Merge pull request #2202 from KLayout/bugfix/issue-2201

Fixed issue #2201 (trace path)
This commit is contained in:
Matthias Köfferlein 2025-10-26 16:35:43 +01:00 committed by GitHub
commit 3a069427cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 101 additions and 21 deletions

View File

@ -1327,6 +1327,13 @@ static std::string path_to_string (const db::Layout &layout, const lay::ObjectIn
void void
Service::display_status (bool transient) Service::display_status (bool transient)
{ {
if (transient && view ()->canvas ()->begin_mouse_receivers () != view ()->canvas ()->end_mouse_receivers ()
&& (*view ()->canvas ()->begin_mouse_receivers ())->claims_message_bar ()) {
// do not display transient if there is a plugin active that has captured the mouse and claims the message bar -
// this way we can use messages in active plugins and still get visual feedback by the transient selection.
return;
}
EditableSelectionIterator r = transient ? begin_transient_selection () : begin_selection (); EditableSelectionIterator r = transient ? begin_transient_selection () : begin_selection ();
EditableSelectionIterator rr = r; EditableSelectionIterator rr = r;

View File

@ -63,7 +63,7 @@ static int inst_point_sel_tests = 10000;
Finder::Finder (bool point_mode, bool top_level_sel) Finder::Finder (bool point_mode, bool top_level_sel)
: m_min_level (0), m_max_level (0), : m_min_level (0), m_max_level (0),
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_catch_all (false), m_top_level_sel (top_level_sel) mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_catch_all (false), m_consider_viewport (true), m_top_level_sel (top_level_sel)
{ {
m_distance = std::numeric_limits<double>::max (); m_distance = std::numeric_limits<double>::max ();
} }
@ -482,7 +482,10 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
checkpoint (); checkpoint ();
// Viewport in current cell coordinate space (DBU) // Viewport in current cell coordinate space (DBU)
db::Box viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ()); db::Box viewport_box;
if (consider_viewport ()) {
viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ());
}
if (! m_context_layers.empty ()) { if (! m_context_layers.empty ()) {
@ -583,7 +586,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
bool any_valid_edge = m_capture_all_shapes; bool any_valid_edge = m_capture_all_shapes;
for (db::Shape::polygon_edge_iterator e = shape->begin_edge (); ! e.at_end (); ++e) { for (db::Shape::polygon_edge_iterator e = shape->begin_edge (); ! e.at_end (); ++e) {
if ((*e).clipped (viewport_box).first) { if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
any_valid_edge = true; any_valid_edge = true;
test_edge (t, *e, d, match); test_edge (t, *e, d, match);
} }
@ -606,7 +609,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
++pt; ++pt;
for (; pt != shape->end_point (); ++pt) { for (; pt != shape->end_point (); ++pt) {
db::Edge e (p, *pt); db::Edge e (p, *pt);
if (e.clipped (viewport_box).first) { if (viewport_box.empty () || e.clipped (viewport_box).first) {
any_valid_edge = true; any_valid_edge = true;
test_edge (t, e, d, match); test_edge (t, e, d, match);
} }
@ -618,7 +621,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
db::Polygon poly; db::Polygon poly;
shape->polygon (poly); shape->polygon (poly);
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if ((*e).clipped (viewport_box).first) { if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
any_valid_edge = true; any_valid_edge = true;
test_edge (t, *e, d, match); test_edge (t, *e, d, match);
} }
@ -651,7 +654,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
// convert to polygon and test those edges // convert to polygon and test those edges
db::Polygon poly (box); db::Polygon poly (box);
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if ((*e).clipped (viewport_box).first) { if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
any_valid_edge = true; any_valid_edge = true;
test_edge (t, *e, d, match); test_edge (t, *e, d, match);
} }
@ -819,7 +822,10 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
checkpoint (); checkpoint ();
// Viewport in current cell coordinate space (DBU) // Viewport in current cell coordinate space (DBU)
db::Box viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ()); db::Box viewport_box;
if (consider_viewport ()) {
viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ());
}
if (! point_mode ()) { if (! point_mode ()) {
@ -952,7 +958,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
bool any_valid_edge = false; bool any_valid_edge = false;
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
// only consider edges that cut through the viewport // only consider edges that cut through the viewport
if ((*e).clipped (viewport_box).first) { if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
any_valid_edge = true; any_valid_edge = true;
test_edge (t, *e, d, match); test_edge (t, *e, d, match);
} }

View File

@ -96,6 +96,25 @@ public:
m_catch_all = f; m_catch_all = f;
} }
/**
* @brief Gets a flag indicating that the viewport will be considered
*/
bool consider_viewport () const
{
return m_consider_viewport;
}
/**
* @brief Sets a flag indicating that the viewport will be considered
* If this flag is true (the default), only shapes and instances will be considered
* if edges (or polygons) or boundary edges (for instances) are visible in the
* viewport. If this flag is false, shapes or instances are considered always.
*/
void set_consider_viewport (bool f)
{
m_consider_viewport = f;
}
/** /**
* @brief Destructor (just provided to please the compiler) * @brief Destructor (just provided to please the compiler)
*/ */
@ -217,6 +236,7 @@ private:
double m_distance; double m_distance;
bool m_point_mode; bool m_point_mode;
bool m_catch_all; bool m_catch_all;
bool m_consider_viewport;
bool m_top_level_sel; bool m_top_level_sel;
db::box_convert <db::CellInst, false> m_box_convert; db::box_convert <db::CellInst, false> m_box_convert;
db::box_convert <db::Cell, false> m_cell_box_convert; db::box_convert <db::Cell, false> m_cell_box_convert;

View File

@ -621,7 +621,10 @@ END_PROTECTED
void void
ViewObjectUI::set_cursor (lay::Cursor::cursor_shape cursor) ViewObjectUI::set_cursor (lay::Cursor::cursor_shape cursor)
{ {
if (m_cursor != cursor) {
m_cursor = cursor; m_cursor = cursor;
realize_cursor ();
}
} }
void void
@ -629,15 +632,7 @@ ViewObjectUI::set_default_cursor (lay::Cursor::cursor_shape cursor)
{ {
if (cursor != m_default_cursor) { if (cursor != m_default_cursor) {
m_default_cursor = cursor; m_default_cursor = cursor;
#if defined(HAVE_QT) realize_cursor ();
if (m_cursor == lay::Cursor::none && mp_widget) {
if (m_default_cursor == lay::Cursor::none) {
mp_widget->unsetCursor ();
} else {
mp_widget->setCursor (lay::Cursor::qcursor (m_default_cursor));
}
}
#endif
} }
} }
@ -652,11 +647,17 @@ ViewObjectUI::ensure_entered ()
void void
ViewObjectUI::begin_mouse_event (lay::Cursor::cursor_shape cursor) ViewObjectUI::begin_mouse_event (lay::Cursor::cursor_shape cursor)
{ {
m_cursor = cursor; set_cursor (cursor);
} }
void void
ViewObjectUI::end_mouse_event () ViewObjectUI::end_mouse_event ()
{
realize_cursor ();
}
void
ViewObjectUI::realize_cursor ()
{ {
#if defined(HAVE_QT) #if defined(HAVE_QT)
if (mp_widget) { if (mp_widget) {

View File

@ -285,6 +285,14 @@ public:
*/ */
virtual void drag_cancel () { } virtual void drag_cancel () { }
/**
* @brief Gets a value indicating whether the mouse receiver claims the view message bar
*
* If this method returns true, other services are not supposed to emit transient
* messages.
*/
virtual bool claims_message_bar () const { return false; }
/** /**
* @brief Gets a value indicating whether a cursor position it set * @brief Gets a value indicating whether a cursor position it set
*/ */
@ -1121,6 +1129,7 @@ private:
void objects_changed (); void objects_changed ();
int widget_height () const; int widget_height () const;
int widget_width () const; int widget_width () const;
void realize_cursor ();
/** /**
* @brief Register a service * @brief Register a service

View File

@ -202,13 +202,32 @@ NetTracerDialog::item_double_clicked (QListWidgetItem *item)
} }
} }
void
NetTracerDialog::drag_cancel ()
{
if (m_mouse_state > 0) {
view ()->message ();
ui ()->ungrab_mouse (this);
set_cursor (lay::Cursor::none);
m_mouse_state = 0;
}
}
bool
NetTracerDialog::claims_message_bar () const
{
return true;
}
bool bool
NetTracerDialog::mouse_move_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool prio) NetTracerDialog::mouse_move_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool prio)
{ {
if (prio && m_mouse_state != 0) { if (prio && m_mouse_state != 0) {
set_cursor (lay::Cursor::cross); set_cursor (lay::Cursor::cross);
} }
return false; return false;
} }
@ -397,11 +416,13 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
{ {
unsigned int start_layer = 0; unsigned int start_layer = 0;
db::Point start_point; db::Point start_point;
db::Shape start_shape;
// locate the seed // locate the seed
{ {
lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All); lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All);
finder.set_consider_viewport (false);
// go through all visible layers of all cellviews and find a seed shape // go through all visible layers of all cellviews and find a seed shape
for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) { for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) {
@ -417,7 +438,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
} }
m_cv_index = r->cv_index (); m_cv_index = r->cv_index ();
start_shape = r->shape ();
start_layer = r->layer (); start_layer = r->layer ();
} }
@ -440,6 +461,12 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
start_point = tt.inverted ().trans (start_search_box.center ()); start_point = tt.inverted ().trans (start_search_box.center ());
// stop if the center start point is not inside the start polygon
db::Polygon poly;
if (start_shape.polygon (poly) && db::inside_poly (poly.begin_edge (), start_point) < 0) {
return 0;
}
} }
// Set up the net tracer environment // Set up the net tracer environment
@ -455,6 +482,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
if (trace_path) { if (trace_path) {
lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All); lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All);
finder.set_consider_viewport (false);
// go through all visible layers of all cellviews and find a seed shape // go through all visible layers of all cellviews and find a seed shape
for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) { for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) {
@ -483,6 +511,12 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
stop_point = tt.inverted ().trans (stop_search_box.center ()); stop_point = tt.inverted ().trans (stop_search_box.center ());
stop_layer = r->layer (); stop_layer = r->layer ();
// stop if the center stop point is not inside the stop polygon
db::Polygon poly;
if (r->shape ().polygon (poly) && db::inside_poly (poly.begin_edge (), stop_point) < 0) {
return 0;
}
} }
db::NetTracer net_tracer; db::NetTracer net_tracer;
@ -1261,6 +1295,7 @@ NetTracerDialog::release_mouse ()
m_mouse_state = 0; m_mouse_state = 0;
view ()->message (); view ()->message ();
ui ()->ungrab_mouse (this); ui ()->ungrab_mouse (this);
set_cursor (lay::Cursor::none);
} }
void void

View File

@ -60,6 +60,8 @@ public:
NetTracerDialog (lay::Dispatcher *root, lay::LayoutViewBase *view); NetTracerDialog (lay::Dispatcher *root, lay::LayoutViewBase *view);
virtual ~NetTracerDialog (); virtual ~NetTracerDialog ();
virtual void drag_cancel ();
virtual bool claims_message_bar () const;
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio); virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio); virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual void menu_activated (const std::string &symbol); virtual void menu_activated (const std::string &symbol);