Merge pull request #2242 from KLayout/bugfix/issue-2234

Bugfix/issue 2234
This commit is contained in:
Matthias Köfferlein 2025-12-07 22:28:51 +01:00 committed by GitHub
commit 4f30ad36db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 164 additions and 72 deletions

View File

@ -762,9 +762,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
{ {
if (! point_mode ()) { if (! point_mode ()) {
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) { for (std::vector<unsigned int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (scan_box))) { if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (scan_box))) {
checkpoint (); checkpoint ();
@ -897,9 +897,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
} else { } else {
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) { for (std::vector<unsigned int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (hit_box))) { if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (hit_box))) {
checkpoint (); checkpoint ();

View File

@ -328,6 +328,12 @@ set_menu_items_hidden (lay::MainWindow *mw, const std::map<std::string, bool> &h
mw->dispatcher ()->config_set (lay::cfg_menu_items_hidden, lay::pack_menu_items_hidden (hv)); mw->dispatcher ()->config_set (lay::cfg_menu_items_hidden, lay::pack_menu_items_hidden (hv));
} }
static void
clear_message (lay::MainWindow *mw, int priority)
{
mw->message (std::string (), 0, priority);
}
Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "MainWindow", Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "MainWindow",
// Dispatcher interface and convenience functions // Dispatcher interface and convenience functions
@ -475,15 +481,36 @@ Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M
"\n" "\n"
"This method has been added in version 0.24." "This method has been added in version 0.24."
) + ) +
gsi::method ("message", &lay::MainWindow::message, gsi::arg ("message"), gsi::arg ("time", -1, "infinite"), gsi::method_ext ("clear_message", &clear_message, gsi::arg ("priority", -1, "all priorities"),
"@brief Clears the message\n"
"When calling this method with a priority, it will clear the message in the given priority slot, thus "
"unhiding the messages with lower priority. This is equivalent to calling \\message with an empty string.\n"
"\n"
"When calling without a priority, all messages in all priority slots will be cleared.\n"
"\n"
"This method has been added in version 0.30.6."
) +
gsi::method ("message", &lay::MainWindow::message, gsi::arg ("message"), gsi::arg ("time", -1, "infinite"), gsi::arg ("priority", 0),
"@brief Displays a message in the status bar\n" "@brief Displays a message in the status bar\n"
"\n" "\n"
"@param message The message to display\n" "@param message The message to display\n"
"@param time The time how long to display the message in ms. A negative value means 'infinitely'.\n" "@param time The time how long to display the message in ms. A negative value means 'infinitely'.\n"
"@param priority The priority of the message. Higher-priority messages have precendence over lower-priority ones.\n"
"\n" "\n"
"This given message is shown in the status bar for the given time.\n" "This given message is shown in the status bar for the given time.\n"
"If a priority is given, higher-priority messages have precedence over lower-priority ones.\n"
"Placing an empty message clears a message with a given priority and unhides messages with lower "
"priority. Standard messages like selection descriptions have priority 0, which is the lowest priority.\n"
"\n" "\n"
"This method has been added in version 0.18. The 'time' parameter was made optional in version 0.28.10." "Messages generated during modal actions (e.g. 'Click on first point') by convention should have priority 10 "
"and should be tied to the active state of a plugin. This ensures there is only one such message.\n"
"Higher-priority messages must be cleared (set to empty string) explicitly to unhide lower-priority messages "
"when the indicated action is finished.\n"
"\n"
"\\clear_message is a convenience method that will clear messages.\n"
"\n"
"This method has been added in version 0.18. The 'time' parameter was made optional in version 0.28.10.\n"
"The 'priority' argument has been added in version 0.30.6."
) + ) +
gsi::method ("resize", (void (lay::MainWindow::*)(int, int)) &lay::MainWindow::resize, gsi::arg ("width"), gsi::arg ("height"), gsi::method ("resize", (void (lay::MainWindow::*)(int, int)) &lay::MainWindow::resize, gsi::arg ("width"), gsi::arg ("height"),
"@brief Resizes the window\n" "@brief Resizes the window\n"

View File

@ -186,6 +186,7 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
m_synchronous (false), m_synchronous (false),
m_busy (false), m_busy (false),
mp_app (app), mp_app (app),
m_message_timer_priority (-1),
m_manager (undo_enabled) m_manager (undo_enabled)
{ {
setAnimated (false); setAnimated (false);
@ -823,10 +824,15 @@ static int fm_width (const QFontMetrics &fm, const QString &s)
void void
MainWindow::format_message () MainWindow::format_message ()
{ {
std::string msg;
if (! m_messages.empty ()) {
msg = (--m_messages.end ())->second;
}
QFontMetrics fm (mp_msg_label->font ()); QFontMetrics fm (mp_msg_label->font ());
std::string full_message; std::string full_message;
for (const char *c = m_message.c_str (); *c; ++c) { for (const char *c = msg.c_str (); *c; ++c) {
if (*c == '\\' && (c[1] == '(' || c[1] == ')')) { if (*c == '\\' && (c[1] == '(' || c[1] == ')')) {
++c; ++c;
} else { } else {
@ -847,7 +853,7 @@ MainWindow::format_message ()
short_message.clear (); short_message.clear ();
for (const char *c = m_message.c_str (); *c; ++c) { for (const char *c = msg.c_str (); *c; ++c) {
if (*c == '\\' && c[1] == '(') { if (*c == '\\' && c[1] == '(') {
if (nsection++ < ndrop) { if (nsection++ < ndrop) {
in_drop = true; in_drop = true;
@ -875,24 +881,53 @@ MainWindow::format_message ()
} }
void void
MainWindow::message (const std::string &s, int ms) MainWindow::message (const std::string &s, int ms, int priority)
{ {
m_message = s; if (s.empty () && priority < 0) {
m_messages.clear ();
} else if (s.empty ()) {
m_messages.erase (priority);
} else {
// simulate timeout of previous message timer
if (m_message_timer_priority >= 0) {
m_messages.erase (m_message_timer_priority);
}
m_messages[priority] = s;
if (ms >= 0) {
m_message_timer_priority = priority;
m_message_timer.start (ms);
} else {
m_message_timer_priority = -1;
}
}
format_message (); format_message ();
m_message_timer.start (ms);
} }
void void
MainWindow::clear_message () MainWindow::clear_messages ()
{ {
m_message.clear (); m_message_timer.stop ();
m_message_timer.start (0); m_message_timer_priority = -1;
m_messages.clear ();
format_message ();
} }
void void
MainWindow::message_timer () MainWindow::message_timer ()
{ {
m_message.clear (); if (m_message_timer_priority >= 0) {
m_messages.erase (m_message_timer_priority);
}
m_message_timer_priority = -1;
format_message (); format_message ();
} }
@ -2467,7 +2502,7 @@ MainWindow::select_view (int index)
update_editor_options_dock (); update_editor_options_dock ();
clear_current_pos (); clear_current_pos ();
edits_enabled_changed (); edits_enabled_changed ();
clear_message (); clear_messages ();
menu_needs_update (); menu_needs_update ();
m_disable_tab_selected = dis; m_disable_tab_selected = dis;
@ -2994,7 +3029,7 @@ MainWindow::close_view (int index)
clear_current_pos (); clear_current_pos ();
edits_enabled_changed (); edits_enabled_changed ();
menu_needs_update (); menu_needs_update ();
clear_message (); clear_messages ();
update_dock_widget_state (); update_dock_widget_state ();
@ -3479,7 +3514,7 @@ MainWindow::add_view (lay::LayoutViewWidget *view)
connect (view, SIGNAL (dirty_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *))); connect (view, SIGNAL (dirty_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *)));
connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ()));
connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ()));
connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (show_message (const std::string &, int, int)), this, SLOT (message (const std::string &, int, int)));
connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int))); connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int)));

View File

@ -649,12 +649,12 @@ public slots:
/** /**
* @brief Displays a status message next to the coordinates * @brief Displays a status message next to the coordinates
*/ */
void message (const std::string &s, int ms); void message (const std::string &s, int ms, int);
/** /**
* @brief Clears the current message * @brief Clears the current message
*/ */
void clear_message (); void clear_messages ();
/** /**
* @brief Selects the given mode * @brief Selects the given mode
@ -789,7 +789,8 @@ private:
QApplication *mp_app; QApplication *mp_app;
lay::HelpDialog *mp_assistant; lay::HelpDialog *mp_assistant;
std::string m_current_session; std::string m_current_session;
std::string m_message; int m_message_timer_priority;
std::map<int, std::string> m_messages;
std::unique_ptr<QPrinter> mp_printer; std::unique_ptr<QPrinter> mp_printer;
std::vector<QString> m_changed_files; std::vector<QString> m_changed_files;
std::string m_title; std::string m_title;

View File

@ -87,7 +87,7 @@ Finder::closer (double d)
} }
void void
Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox &region, const db::DBox &scan_region, int min_level, int max_level, const std::vector<int> &layers) Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox &region, const db::DBox &scan_region, int min_level, int max_level, const std::vector<unsigned int> &layers)
{ {
const lay::CellView &cv = view->cellview (cv_index); const lay::CellView &cv = view->cellview (cv_index);
@ -100,8 +100,8 @@ Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vect
if (layers.size () == 1) { if (layers.size () == 1) {
m_box_convert = db::box_convert <db::CellInst, false> (*mp_layout, (unsigned int) layers [0]); m_box_convert = db::box_convert <db::CellInst, false> (*mp_layout, layers [0]);
m_cell_box_convert = db::box_convert <db::Cell, false> ((unsigned int) layers [0]); m_cell_box_convert = db::box_convert <db::Cell, false> (layers [0]);
} else { } else {
@ -202,7 +202,7 @@ Finder::do_find (const db::Cell &cell, int level, const db::DCplxTrans &vp, cons
if (level <= m_max_level /*take level of cell itself*/ if (level <= m_max_level /*take level of cell itself*/
&& cell.is_proxy () && cell.is_proxy ()
&& m_layers.size () == 1 && m_layers.size () == 1
&& (unsigned int) m_layers [0] == mp_layout->guiding_shape_layer ()) { && m_layers [0] == mp_layout->guiding_shape_layer ()) {
// when looking at the guiding shape layer, we can visit this cell as well allowing to find the guiding shapes // when looking at the guiding shape layer, we can visit this cell as well allowing to find the guiding shapes
@ -339,7 +339,7 @@ ShapeFinder::find (LayoutViewBase *view, const db::DBox &region_mu)
std::sort (lprops.begin (), lprops.end (), LPContextCompareOp ()); std::sort (lprops.begin (), lprops.end (), LPContextCompareOp ());
std::vector<int> layers; std::vector<unsigned int> layers;
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator llp = lprops.begin (); llp != lprops.end (); ) { for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator llp = lprops.begin (); llp != lprops.end (); ) {
layers.clear (); layers.clear ();
@ -347,7 +347,10 @@ ShapeFinder::find (LayoutViewBase *view, const db::DBox &region_mu)
lay::LayerPropertiesConstIterator lp0 = *llp; lay::LayerPropertiesConstIterator lp0 = *llp;
LPContextEqualOp eq; LPContextEqualOp eq;
do { do {
layers.push_back ((*llp)->layer_index ()); int li = (*llp)->layer_index ();
if (li >= 0) {
layers.push_back ((unsigned int) li);
}
++llp; ++llp;
} while (llp != lprops.end () && eq(lp0, *llp)); } while (llp != lprops.end () && eq(lp0, *llp));
@ -398,16 +401,19 @@ ShapeFinder::find (lay::LayoutViewBase *view, const lay::LayerProperties &lprops
lay::TextInfo text_info (view); lay::TextInfo text_info (view);
mp_text_info = (m_flags & db::ShapeIterator::Texts) != 0 ? &text_info : 0; mp_text_info = (m_flags & db::ShapeIterator::Texts) != 0 ? &text_info : 0;
std::vector<int> layers; std::vector<unsigned int> layers;
layers.push_back (lprops.layer_index ()); int li = lprops.layer_index ();
if (li >= 0) {
layers.push_back ((unsigned int) li);
}
bool result = find_internal (view, lprops.cellview_index (), &lprops.prop_sel (), lprops.inverse_prop_sel (), lprops.hier_levels (), lprops.trans (), layers, region_mu); bool result = find_internal (view, lprops.cellview_index (), &lprops.prop_sel (), lprops.inverse_prop_sel (), lprops.hier_levels (), lprops.trans (), layers, region_mu);
mp_progress = 0; mp_progress = 0;
return result; return result;
} }
bool bool
ShapeFinder::find_internal (lay::LayoutViewBase *view, unsigned int cv_index, const std::set<db::properties_id_type> *prop_sel, bool inv_prop_sel, const lay::HierarchyLevelSelection &hier_sel, const std::vector<db::DCplxTrans> &trans_mu, const std::vector<int> &layers, const db::DBox &region_mu) ShapeFinder::find_internal (lay::LayoutViewBase *view, unsigned int cv_index, const std::set<db::properties_id_type> *prop_sel, bool inv_prop_sel, const lay::HierarchyLevelSelection &hier_sel, const std::vector<db::DCplxTrans> &trans_mu, const std::vector<unsigned int> &layers, const db::DBox &region_mu)
{ {
m_cv_index = cv_index; m_cv_index = cv_index;
@ -511,13 +517,13 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
if (! point_mode ()) { if (! point_mode ()) {
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) { for (std::vector<unsigned int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (scan_box))) { if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (scan_box))) {
checkpoint (); checkpoint ();
const db::Shapes &shapes = cell.shapes ((unsigned int) *l); const db::Shapes &shapes = cell.shapes (*l);
db::ShapeIterator shape = shapes.begin_touching (scan_box, m_flags, mp_prop_sel, m_inv_prop_sel); db::ShapeIterator shape = shapes.begin_touching (scan_box, m_flags, mp_prop_sel, m_inv_prop_sel);
while (! shape.at_end ()) { while (! shape.at_end ()) {
@ -563,9 +569,9 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
} else { } else {
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) { for (std::vector<unsigned int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (scan_box))) { if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (scan_box))) {
checkpoint (); checkpoint ();
@ -793,7 +799,7 @@ InstFinder::find_internal (LayoutViewBase *view, unsigned int cv_index, const db
try { try {
std::vector<db::DCplxTrans> tv; std::vector<db::DCplxTrans> tv;
tv.push_back (trans_mu); tv.push_back (trans_mu);
start (view, cv_index, tv, region_mu, region_mu, view->get_min_hier_levels (), view->get_max_hier_levels (), std::vector<int> ()); start (view, cv_index, tv, region_mu, region_mu, view->get_min_hier_levels (), view->get_max_hier_levels (), std::vector<unsigned int> ());
} catch (StopException) { } catch (StopException) {
// .. // ..
} }

View File

@ -132,7 +132,7 @@ public:
} }
protected: protected:
const std::vector<int> &layers () const const std::vector<unsigned int> &layers () const
{ {
return m_layers; return m_layers;
} }
@ -183,7 +183,7 @@ protected:
* @param max_level The maximum hierarchy level to check * @param max_level The maximum hierarchy level to check
* @param layers A set of layers to check * @param layers A set of layers to check
*/ */
void start (LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox &region, const db::DBox &scan_region, int min_level, int max_level, const std::vector<int> &layers = std::vector<int> ()); void start (LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox &region, const db::DBox &scan_region, int min_level, int max_level, const std::vector<unsigned int> &layers = std::vector<unsigned int> ());
/** /**
* @brief Provide a basic edge test facility * @brief Provide a basic edge test facility
@ -232,7 +232,7 @@ private:
unsigned int m_cv_index; unsigned int m_cv_index;
db::Box m_region; db::Box m_region;
db::Box m_scan_region; db::Box m_scan_region;
std::vector<int> m_layers; std::vector<unsigned int> m_layers;
double m_distance; double m_distance;
bool m_point_mode; bool m_point_mode;
bool m_catch_all; bool m_catch_all;
@ -267,8 +267,8 @@ public:
*/ */
ShapeFinder (bool point_mode, bool top_level_sel, db::ShapeIterator::flags_type flags, const std::set<lay::ObjectInstPath> *excludes = 0, bool capture_all_shapes = false); ShapeFinder (bool point_mode, bool top_level_sel, db::ShapeIterator::flags_type flags, const std::set<lay::ObjectInstPath> *excludes = 0, bool capture_all_shapes = false);
bool find (LayoutViewBase *view, const lay::LayerProperties &lprops, const db::DBox &region_mu); bool find (lay::LayoutViewBase *view, const lay::LayerProperties &lprops, const db::DBox &region_mu);
bool find (LayoutViewBase *view, const db::DBox &region_mu); bool find (lay::LayoutViewBase *view, const db::DBox &region_mu);
iterator begin () const iterator begin () const
{ {
@ -327,7 +327,7 @@ private:
bool inv_prop_sel, bool inv_prop_sel,
const lay::HierarchyLevelSelection &hier_sel, const lay::HierarchyLevelSelection &hier_sel,
const std::vector<db::DCplxTrans> &trans_mu, const std::vector<db::DCplxTrans> &trans_mu,
const std::vector<int> &layers, const std::vector<unsigned int> &layers,
const db::DBox &region_mu); const db::DBox &region_mu);
const std::set<lay::ObjectInstPath> *mp_excludes; const std::set<lay::ObjectInstPath> *mp_excludes;

View File

@ -694,7 +694,7 @@ LayoutViewBase::set_synchronous (bool s)
} }
void void
LayoutViewBase::message (const std::string & /*s*/, int /*timeout*/) LayoutViewBase::message (const std::string & /*s*/, int /*timeout*/, int /*priority*/)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -4164,7 +4164,7 @@ void
LayoutViewBase::cancel_edits () LayoutViewBase::cancel_edits ()
{ {
// clear any messages // clear any messages
message (); message (std::string (), 0, -1);
// the move service takes a special role here as it manages the // the move service takes a special role here as it manages the
// transaction for the collective move operation. // transaction for the collective move operation.

View File

@ -365,7 +365,7 @@ public:
/** /**
* @brief Display a status message * @brief Display a status message
*/ */
virtual void message (const std::string &s = "", int timeout = 10); virtual void message (const std::string &s = "", int timeout = 10, int priority = 0);
/** /**
* @brief Sets the keyboard focus to the view * @brief Sets the keyboard focus to the view

View File

@ -1585,10 +1585,10 @@ LayoutView::signal_selection_changed ()
} }
void void
LayoutView::message (const std::string &s, int timeout) LayoutView::message (const std::string &s, int timeout, int priority)
{ {
if (mp_widget) { if (mp_widget) {
mp_widget->emit_show_message (s, timeout * 1000); mp_widget->emit_show_message (s, timeout * 1000, priority);
} }
} }

View File

@ -187,7 +187,7 @@ public:
/** /**
* @brief Displays a status message * @brief Displays a status message
*/ */
void message (const std::string &s = "", int timeout = 10); virtual void message (const std::string &s = "", int timeout = 10, int priority = 0);
/** /**
* @brief Sets the keyboard focus to the view * @brief Sets the keyboard focus to the view
@ -773,7 +773,7 @@ public:
void emit_title_changed (lay::LayoutView *view) { emit title_changed (view); } void emit_title_changed (lay::LayoutView *view) { emit title_changed (view); }
void emit_dirty_changed (lay::LayoutView *view) { emit dirty_changed (view); } void emit_dirty_changed (lay::LayoutView *view) { emit dirty_changed (view); }
void emit_show_message (const std::string &s, int ms) { emit show_message (s, ms); } void emit_show_message (const std::string &s, int ms, int priority) { emit show_message (s, ms, priority); }
void emit_current_pos_changed (double x, double y, bool dbu_units) { emit current_pos_changed (x, y, dbu_units); } void emit_current_pos_changed (double x, double y, bool dbu_units) { emit current_pos_changed (x, y, dbu_units); }
void emit_clear_current_pos () { emit clear_current_pos (); } void emit_clear_current_pos () { emit clear_current_pos (); }
void emit_edits_enabled_changed () { emit edits_enabled_changed (); } void emit_edits_enabled_changed () { emit edits_enabled_changed (); }
@ -826,7 +826,7 @@ signals:
/** /**
* @brief This signal is emitted when the view wants to show a message for the given time (of infinitely for ms == 0) * @brief This signal is emitted when the view wants to show a message for the given time (of infinitely for ms == 0)
*/ */
void show_message (const std::string &s, int ms); void show_message (const std::string &s, int ms, int priority);
/** /**
* @brief This signal is emitted when the view wants to indicate a mouse position change * @brief This signal is emitted when the view wants to indicate a mouse position change

View File

@ -337,6 +337,16 @@ NetTracerData::requires_booleans (unsigned int from_layer) const
return r->second; return r->second;
} }
std::set<unsigned int>
NetTracerData::original_layers () const
{
std::set<unsigned int> ol;
for (std::map <unsigned int, std::set <unsigned int> >::const_iterator g = m_original_layers.begin (); g != m_original_layers.end (); ++g) {
ol.insert (g->second.begin (), g->second.end ());
}
return ol;
}
void void
NetTracerData::clean_l2n_regions () NetTracerData::clean_l2n_regions ()
{ {

View File

@ -626,6 +626,13 @@ public:
*/ */
void configure_l2n (db::LayoutToNetlist &l2n); void configure_l2n (db::LayoutToNetlist &l2n);
/**
* @brief Gets the original layers
*
* These are the layer indexes used for computing the net tracer functions
*/
std::set<unsigned int> original_layers () const;
private: private:
unsigned int m_next_log_layer; unsigned int m_next_log_layer;
std::vector <NetTracerConnection> m_connections; std::vector <NetTracerConnection> m_connections;

View File

@ -207,7 +207,7 @@ NetTracerDialog::drag_cancel ()
{ {
if (m_mouse_state > 0) { if (m_mouse_state > 0) {
view ()->message (); view ()->message (std::string (), 0, 10);
ui ()->ungrab_mouse (this); ui ()->ungrab_mouse (this);
set_cursor (lay::Cursor::none); set_cursor (lay::Cursor::none);
@ -241,7 +241,7 @@ NetTracerDialog::mouse_click_event (const db::DPoint &p, unsigned int buttons, b
m_mouse_first_point = p; m_mouse_first_point = p;
m_mouse_state = 3; m_mouse_state = 3;
view ()->message (tl::to_string (QObject::tr ("Click on the second point in the net"))); view ()->message (tl::to_string (QObject::tr ("Click on the second point in the net")), -1 /*infinitely*/, 10);
} else { } else {
@ -414,9 +414,24 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat
db::NetTracerNet * db::NetTracerNet *
NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path) NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path)
{ {
// determine the cellview
lay::CellView cv = view ()->cellview (m_cv_index);
if (! cv.is_valid ()) {
return 0;
}
// Set up the net tracer environment
db::NetTracerData tracer_data;
if (! get_net_tracer_setup (cv, tracer_data)) {
return 0;
}
std::set<unsigned int> original_layers = tracer_data.original_layers ();
unsigned int start_layer = 0; unsigned int start_layer = 0;
db::Point start_point; db::Point start_point;
db::Shape start_shape; db::Shape start_shape;
db::ICplxTrans start_trans;
// locate the seed // locate the seed
{ {
@ -426,7 +441,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
// 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) {
if (lprop->is_visual ()) { if (lprop->is_visual () && lprop->cellview_index () == m_cv_index && original_layers.find ((unsigned int) lprop->layer_index ()) != original_layers.end ()) {
finder.find (view (), *lprop, start_search_box); finder.find (view (), *lprop, start_search_box);
} }
} }
@ -440,15 +455,10 @@ 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_shape = r->shape ();
start_layer = r->layer (); start_layer = r->layer ();
start_trans = r->trans ();
} }
// determine the cellview
lay::CellView cv = view ()->cellview (m_cv_index);
if (! cv.is_valid ()) {
return 0;
}
// determine the start point // determine the start point
{ {
@ -463,20 +473,15 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
// stop if the center start point is not inside the start polygon // stop if the center start point is not inside the start polygon
db::Polygon poly; db::Polygon poly;
if (start_shape.polygon (poly) && db::inside_poly (poly.begin_edge (), start_point) < 0) { if (start_shape.polygon (poly) && db::inside_poly (poly.begin_edge (), start_trans.inverted () * start_point) < 0) {
return 0; return 0;
} }
} }
// Set up the net tracer environment
db::NetTracerData tracer_data;
if (! get_net_tracer_setup (cv, tracer_data)) {
return 0;
}
unsigned int stop_layer = 0; unsigned int stop_layer = 0;
db::Point stop_point; db::Point stop_point;
db::ICplxTrans stop_trans;
// locate the stop shape (the second mouse click) // locate the stop shape (the second mouse click)
if (trace_path) { if (trace_path) {
@ -486,7 +491,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
// 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) {
if (lprop->is_visual ()) { if (lprop->is_visual () && lprop->cellview_index () == m_cv_index && original_layers.find ((unsigned int) lprop->layer_index ()) != original_layers.end ()) {
finder.find (view (), *lprop, stop_search_box); finder.find (view (), *lprop, stop_search_box);
} }
} }
@ -510,10 +515,11 @@ 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_trans = r->trans ();
// stop if the center stop point is not inside the stop polygon // stop if the center stop point is not inside the stop polygon
db::Polygon poly; db::Polygon poly;
if (r->shape ().polygon (poly) && db::inside_poly (poly.begin_edge (), stop_point) < 0) { if (r->shape ().polygon (poly) && db::inside_poly (poly.begin_edge (), stop_trans.inverted () * stop_point) < 0) {
return 0; return 0;
} }
@ -1258,7 +1264,7 @@ BEGIN_PROTECTED
commit (); commit ();
net_list->setCurrentItem (0); net_list->setCurrentItem (0);
m_mouse_state = 2; m_mouse_state = 2;
view ()->message (tl::to_string (QObject::tr ("Click on the first point in the net"))); view ()->message (tl::to_string (QObject::tr ("Click on the first point in the net")), -1 /*infinitely*/, 10);
ui ()->grab_mouse (this, false); ui ()->grab_mouse (this, false);
END_PROTECTED END_PROTECTED
} }
@ -1270,7 +1276,7 @@ BEGIN_PROTECTED
commit (); commit ();
net_list->setCurrentItem (0); net_list->setCurrentItem (0);
m_mouse_state = 1; m_mouse_state = 1;
view ()->message (tl::to_string (QObject::tr ("Click on a point in the net"))); view ()->message (tl::to_string (QObject::tr ("Click on a point in the net")), -1 /*infinitely*/, 10);
ui ()->grab_mouse (this, false); ui ()->grab_mouse (this, false);
END_PROTECTED END_PROTECTED
} }
@ -1293,7 +1299,7 @@ NetTracerDialog::release_mouse ()
add_pb->setChecked (false); add_pb->setChecked (false);
add2_pb->setChecked (false); add2_pb->setChecked (false);
m_mouse_state = 0; m_mouse_state = 0;
view ()->message (); view ()->message (std::string (), 0, 10);
ui ()->ungrab_mouse (this); ui ()->ungrab_mouse (this);
set_cursor (lay::Cursor::none); set_cursor (lay::Cursor::none);
} }