From 9137919894e011d39103c72a4da3dd54e1305a3d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 Aug 2025 23:51:03 +0200 Subject: [PATCH] WIP: Implementing initial via --- src/edt/edt/edtMainService.cc | 14 ---- src/edt/edt/edtService.cc | 20 ++++- src/edt/edt/edtService.h | 31 +++++++ src/edt/edt/edtServiceImpl.cc | 150 ++++++++++++++++++++++++++++------ src/edt/edt/edtServiceImpl.h | 3 + 5 files changed, 179 insertions(+), 39 deletions(-) diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index 701fe2691..951c7f9d6 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -2484,20 +2484,6 @@ MainService::via_impl (int dir) edt::Service *es = dynamic_cast (view ()->canvas ()->active_service ()); if (es) { es->via (dir); - } else { - -#if 0 // @@@ - db::ShapeIterator::flags_type (db::ShapeIterator::All - db::ShapeIterator::Texts), // do not consider texts - their bounding box may be too large - lay::ShapeFinder finder (true, view ()->is_editable () && m_top_level_sel, m_flags, &m_previous_selection); - - // go through all visible layers of all cellviews - finder.find (view (), search_box); - - // collect the founds from the finder - lay::ShapeFinder::iterator r = finder.begin (); - if (r != finder.end ()) { -#endif - } } diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 69fa801fe..171b7d027 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -67,7 +67,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter db::Object (manager), mp_view (view), mp_transient_marker (0), - m_editing (false), m_immediate (false), + m_mouse_in_view (false), m_editing (false), m_immediate (false), m_selection_maybe_invalid (false), m_cell_inst_service (false), m_flags (flags), @@ -91,7 +91,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view) db::Object (manager), mp_view (view), mp_transient_marker (0), - m_editing (false), m_immediate (false), + m_mouse_in_view (false), m_editing (false), m_immediate (false), m_selection_maybe_invalid (false), m_cell_inst_service (true), m_flags (db::ShapeIterator::Nothing), @@ -882,6 +882,8 @@ Service::move_cancel () bool Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio) { + m_mouse_pos = p; + if (view ()->is_editable () && prio) { if (m_editing || m_immediate) { @@ -948,6 +950,20 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio return false; } +bool +Service::leave_event (bool /*prio*/) +{ + m_mouse_in_view = false; + return false; +} + +bool +Service::enter_event (bool /*prio*/) +{ + m_mouse_in_view = true; + return false; +} + bool Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio) { diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index d20a83f6e..6a081ece2 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -352,6 +352,16 @@ public: */ virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio); + /** + * @brief Mouse leave event handler + */ + virtual bool leave_event (bool prio); + + /** + * @brief Mouse enter event handler + */ + virtual bool enter_event (bool prio); + /** * @brief Implements the key handler */ @@ -623,6 +633,21 @@ protected: return m_editing; } + bool top_level_sel () const + { + return m_top_level_sel; + } + + bool mouse_in_view () const + { + return m_mouse_in_view; + } + + const db::DPoint &mouse_pos () const + { + return m_mouse_pos; + } + /** * @brief Point snapping with detailed return value */ @@ -643,6 +668,12 @@ private: // The marker representing the object to be edited std::vector m_edit_markers; + // The last mouse position + db::DPoint m_mouse_pos; + + // A flag indicating whether the mouse is inside the view + bool m_mouse_in_view; + // True, if editing is in progress. bool m_editing; diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index 5a0914092..e11e87a1f 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -37,6 +37,7 @@ #include "layMarker.h" #include "layLayerProperties.h" #include "layLayoutViewBase.h" +#include "layFinder.h" #if defined(HAVE_QT) # include "layLayoutView.h" @@ -177,22 +178,31 @@ ShapeEditService::change_edit_layer (const db::LayerProperties &lp) void ShapeEditService::set_layer (const db::LayerProperties &lp, unsigned int cv_index) { - if (! mp_layout) { + const lay::CellView &cv = view ()->cellview (cv_index); + if (! cv.is_valid ()) { return; } - int layer = mp_layout->get_layer_maybe (lp); + int layer = cv->layout ().get_layer_maybe (lp); if (layer < 0) { - layer = mp_layout->insert_layer (lp); + layer = cv->layout ().insert_layer (lp); } m_layer = (unsigned int) layer; m_cv_index = cv_index; + mp_layout = &(cv->layout ()); + mp_cell = cv.cell (); m_update_edit_layer_enabled = false; + try { + view ()->set_current_layer (cv_index, lp); + auto cl = view ()->current_layer (); + m_trans = (cl->trans ().front () * db::CplxTrans (cv->layout ().dbu ()) * cv.context_trans ()).inverted (); + m_update_edit_layer_enabled = true; + } catch (...) { m_update_edit_layer_enabled = true; throw; @@ -1489,31 +1499,33 @@ PathService::selection_applies (const lay::ObjectInstPath &sel) const void PathService::via (int dir) { -#if ! defined(HAVE_QT) - tl_assert (false); // see TODO -#endif - - if (! editing ()) { - return; - } - - // not enough points to form a path - if (m_points.size () < 2) { - return; - } - +// see TODO below +#if defined(HAVE_QT) if (combine_mode () != CM_Add) { throw tl::Exception (tl::to_string (tr ("Vias are only available in 'Add' combination mode"))); } - db::LayerProperties lp = layout ().get_properties (layer ()); - std::vector via_defs = db::find_via_definitions_for (layout ().technology_name (), lp, dir); + if (editing ()) { + via_editing (dir); + } else { + via_initial (dir); + } +#endif +} - db::SelectedViaDefinition via_def; +bool +PathService::get_via_for (const db::LayerProperties &lp, unsigned int cv_index, int dir, db::SelectedViaDefinition &via_def) +{ + const lay::CellView &cv = view ()->cellview (cv_index); + if (! cv.is_valid ()) { + return false; + } + + std::vector via_defs = db::find_via_definitions_for (cv->layout ().technology_name (), lp, dir); if (via_defs.size () == 0) { - return; + return false; } else if (via_defs.size () == 1) { @@ -1522,11 +1534,12 @@ PathService::via (int dir) } else if (via_defs.size () > 1) { #if defined(HAVE_QT) - // TODO: what to do here in Qt-less case? Store results in configuration so they can be retrieved externally? + // present a menu with the available vias. + // TODO: what to do here in Qt-less case? QWidget *view_widget = lay::widget_from_view (view ()); if (! view_widget) { - return; + return false; } std::unique_ptr menu (new QMenu (view_widget)); @@ -1542,7 +1555,7 @@ PathService::via (int dir) QAction *action = menu->exec (mp); if (! action) { - return; + return false; } via_def = via_defs [action->data ().toInt ()]; @@ -1550,6 +1563,97 @@ PathService::via (int dir) } + return true; +} + +void +PathService::via_initial (int dir) +{ + if (! mouse_in_view ()) { + return; + } + + // compute search box + double l = catch_distance (); + db::DPoint pos = mouse_pos (); + db::DBox search_box = db::DBox (pos, pos).enlarged (db::DVector (l, l)); + + lay::ShapeFinder finder (true, false, db::ShapeIterator::Regions); + + // go through all visible layers of all cellviews + finder.find (view (), search_box); + + // collect the founds from the finder + lay::ShapeFinder::iterator r = finder.begin (); + if (r == finder.end ()) { + return; + } + + const lay::CellView &cv = view ()->cellview (r->cv_index ()); + if (! cv.is_valid ()) { + return; + } + + db::LayerProperties lp = cv->layout ().get_properties (r->layer ()); + + db::SelectedViaDefinition via_def; + if (! get_via_for (lp, r->cv_index (), dir, via_def)) { + return; + } + + set_layer (lp, r->cv_index ()); + + bool is_bottom = via_def.via_type.bottom.log_equal (lp); + db::LayerProperties lp_new = is_bottom ? via_def.via_type.top : via_def.via_type.bottom; + + { + db::Transaction transaction (manager (), tl::to_string (tr ("Create path segment"))); + + change_edit_layer (lp_new); + begin_edit (pos); + + db::DPoint via_pos = m_last; + + // create the via cell + // (using 0.0 for all dimensions to indicate "place here") + + double w_bottom = 0.0, h_bottom = 0.0, w_top = 0.0, h_top = 0.0; + + std::map params; + params.insert (std::make_pair ("via", tl::Variant (via_def.via_type.name))); + params.insert (std::make_pair ("w_bottom", tl::Variant (w_bottom))); + params.insert (std::make_pair ("w_top", tl::Variant (w_top))); + params.insert (std::make_pair ("h_bottom", tl::Variant (h_bottom))); + params.insert (std::make_pair ("h_top", tl::Variant (h_top))); + + auto via_lib_cell = via_def.lib->layout ().get_pcell_variant_dict (via_def.pcell, params); + auto via_cell = layout ().get_lib_proxy (via_def.lib, via_lib_cell); + + db::Instance via_instance = cell ().insert (db::CellInstArray (db::CellInst (via_cell), db::Trans (trans () * via_pos - db::Point ()))); + push_segment (db::Shape (), via_instance, via_def.via_type, transaction.id ()); + + if (! via_def.via_type.cut.is_null ()) { + edt::set_or_request_current_layer (view (), via_def.via_type.cut, cv_index (), false /*don't make current*/); + } + + } +} + +void +PathService::via_editing (int dir) +{ + // not enough points to form a path + if (m_points.size () < 2) { + return; + } + + db::LayerProperties lp = layout ().get_properties (layer ()); + + db::SelectedViaDefinition via_def; + if (! get_via_for (lp, cv_index (), dir, via_def)) { + return; + } + commit_recent (view ()); // produce the path up to the current point diff --git a/src/edt/edt/edtServiceImpl.h b/src/edt/edt/edtServiceImpl.h index 2c55beb15..3a711bea3 100644 --- a/src/edt/edt/edtServiceImpl.h +++ b/src/edt/edt/edtServiceImpl.h @@ -274,6 +274,9 @@ private: db::Path get_path () const; void set_last_point (const db::DPoint &p); void update_via (); + void via_initial (int dir); + void via_editing (int dir); + bool get_via_for (const db::LayerProperties &lp, unsigned int cv_index, int dir, db::SelectedViaDefinition &via_def); void push_segment (const db::Shape &shape, const db::Instance &instance, const db::ViaType &via_type, db::Manager::transaction_id_t transaction_id); void pop_segment (); };