diff --git a/src/laybasic/laybasic/NetlistBrowserDialog.ui b/src/laybasic/laybasic/NetlistBrowserDialog.ui index 7cde819e6..e74ef4cd7 100644 --- a/src/laybasic/laybasic/NetlistBrowserDialog.ui +++ b/src/laybasic/laybasic/NetlistBrowserDialog.ui @@ -285,6 +285,23 @@ to load a netlist or a netlist/LVS database + + + + Select a new by clicking on a shape + + + Probe Net + + + + + + + Lock + + + diff --git a/src/laybasic/laybasic/NetlistBrowserPage.ui b/src/laybasic/laybasic/NetlistBrowserPage.ui index 030339e09..e6a06b5be 100644 --- a/src/laybasic/laybasic/NetlistBrowserPage.ui +++ b/src/laybasic/laybasic/NetlistBrowserPage.ui @@ -200,13 +200,6 @@ - - - - Probe - - - @@ -243,7 +236,7 @@ true - false + true diff --git a/src/laybasic/laybasic/layNetInfoDialog.cc b/src/laybasic/laybasic/layNetInfoDialog.cc index 36e8b4396..4362ae170 100644 --- a/src/laybasic/laybasic/layNetInfoDialog.cc +++ b/src/laybasic/laybasic/layNetInfoDialog.cc @@ -154,6 +154,9 @@ void NetInfoDialog::update_info_text () info.cdata (tl::to_string (tr ("Net"))); info.end_element ("th"); info.start_element ("th"); + info.cdata (tl::to_string (tr ("Circuit"))); + info.end_element ("th"); + info.start_element ("th"); info.cdata (tl::to_string (tr ("Shapes"))); info.end_element ("th"); info.start_element ("th"); @@ -177,6 +180,12 @@ void NetInfoDialog::update_info_text () info.cdata (net->expanded_name ()); info.end_element ("td"); + info.start_element ("td"); + if (net->circuit ()) { + info.cdata (net->circuit ()->name ()); + } + info.end_element ("td"); + size_t n; info.start_element ("td"); @@ -253,23 +262,6 @@ void NetInfoDialog::update_info_text () info.start_element ("hr"); info.end_element ("hr"); - info.start_element ("h3"); - info.cdata (tl::to_string (QObject::tr ("Details:"))); - info.end_element ("h3"); - - info.start_element ("p"); - info.start_element ("b"); - info.cdata (tl::to_string (QObject::tr ("Net name: "))); - info.end_element ("b"); - info.cdata (net->expanded_name ()); - info.start_element ("br"); - info.end_element ("br"); - info.start_element ("b"); - info.cdata (tl::to_string (QObject::tr ("Circuit: "))); - info.end_element ("b"); - info.cdata (net->circuit () ? net->circuit ()->name () : "(null)"); - info.end_element ("p"); - std::map > shapes; // map as (layernumber, group of shapes by layer): diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 7d0c21c15..8a72b5280 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -23,8 +23,9 @@ #include "layNetlistBrowserDialog.h" #include "tlProgress.h" -#include "layLayoutView.h" #include "tlExceptions.h" +#include "layLayoutView.h" +#include "layFinder.h" #include "layFileDialog.h" #include "layConverters.h" #include "layQtTools.h" @@ -56,6 +57,7 @@ extern const std::string cfg_l2ndb_window_state; NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutView *vw) : lay::Browser (root, vw), + lay::ViewService (vw->view_object_widget ()), Ui::NetlistBrowserDialog (), m_window (lay::NetlistBrowserConfig::FitNet), m_window_dim (0.0), @@ -67,7 +69,8 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutVi m_marker_dither_pattern (-1), m_marker_intensity (0), m_cv_index (-1), - m_l2n_index (-1) + m_l2n_index (-1), + m_mouse_state (0) { Ui::NetlistBrowserDialog::setupUi (this); @@ -111,6 +114,8 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutVi connect (layout_cb, SIGNAL (activated (int)), this, SLOT (cv_index_changed (int))); connect (l2ndb_cb, SIGNAL (activated (int)), this, SLOT (l2ndb_index_changed (int))); connect (configure_pb, SIGNAL (clicked ()), this, SLOT (configure_clicked ())); + connect (probe_pb, SIGNAL (clicked ()), this, SLOT (probe_button_pressed ())); + connect (sticky_cbx, SIGNAL (clicked ()), this, SLOT (sticky_mode_clicked ())); cellviews_changed (); } @@ -123,10 +128,188 @@ NetlistBrowserDialog::~NetlistBrowserDialog () void NetlistBrowserDialog::configure_clicked () { + release_mouse (); + lay::ConfigurationDialog config_dialog (this, lay::PluginRoot::instance (), "NetlistBrowserPlugin"); config_dialog.exec (); } +bool +NetlistBrowserDialog::mouse_move_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool prio) +{ + if (prio && m_mouse_state != 0) { + set_cursor (lay::Cursor::cross); + } + + return false; +} + +void +NetlistBrowserDialog::sticky_mode_clicked () +{ +BEGIN_PROTECTED + if (! sticky_cbx->isChecked ()) { + release_mouse (); + } else { + probe_button_pressed (); + } +END_PROTECTED +} + +bool +NetlistBrowserDialog::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio) +{ + if (prio && (buttons & lay::LeftButton) != 0 && m_mouse_state != 0) { + + // TODO: not used yet, borrowed from net tracer ... TODO: implement short locator! + if (m_mouse_state == 2) { + + m_mouse_first_point = p; + m_mouse_state = 3; + + view ()->message (tl::to_string (QObject::tr ("Click on the second point in the net"))); + + } else { + + bool trace_path = (m_mouse_state == 3); + + if (trace_path || ! sticky_cbx->isChecked ()) { + release_mouse (); + } + + probe_net (p, trace_path); + + } + + } + + return true; +} + +void +NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path) +{ + // prepare for the net tracing + double l = double (lay::search_range) / widget ()->mouse_event_trans ().mag (); + + db::DBox start_search_box = db::DBox (p, p).enlarged (db::DVector (l, l)); + + // @@@ not used yet .. + db::DBox stop_search_box; + if (trace_path) { + stop_search_box = db::DBox (m_mouse_first_point, m_mouse_first_point).enlarged (db::DVector (l, l)); + } + + unsigned int start_layer = 0; + db::Point start_point; + unsigned int cv_index; + + // locate the seed shape to figure out the cv index and layer + { + + lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All); + + // go through all visible layers of all cellviews and find a seed shape + for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) { + if (lprop->is_visual ()) { + finder.find (view (), *lprop, start_search_box); + } + } + + // return, if no shape was found + lay::ShapeFinder::iterator r = finder.begin (); + if (r == finder.end ()) { + return; + } + + cv_index = r->cv_index (); + start_layer = r->layer (); + + } + + // if the cv index is not corresponding to the one of the current netlist, ignore this event + if (int (cv_index) != m_cv_index) { + return; + } + + // determine the cellview + lay::CellView cv = view ()->cellview (cv_index); + if (! cv.is_valid ()) { + return; + } + + // determine the start point + { + + std::vector tv = view ()->cv_transform_variants (m_cv_index, start_layer); + if (tv.empty ()) { + return; + } + + db::CplxTrans tt = tv.front () * db::CplxTrans (cv->layout ().dbu ()) * cv.context_trans (); + + start_point = tt.inverted ().trans (start_search_box.center ()); + + } + + const db::Net *net = 0; + + db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index); + if (l2ndb) { + + // determines the corresponding layer inside the database and probe the net from this region and the + // start point. + + db::Region *region = 0; + + const db::Connectivity &conn = l2ndb->connectivity (); + for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer); + if (! lp.is_null () && lp == cv->layout ().get_properties (start_layer)) { + region = l2ndb->layer_by_index (*layer); + break; + } + } + + // probe the net + + if (region) { + net = l2ndb->probe_net (*region, start_point); + } + + } + + // select the net if one was found + browser_frame->select_net (net); +} + +void +NetlistBrowserDialog::release_mouse () +{ + m_mouse_state = 0; + view ()->message (); + widget ()->ungrab_mouse (this); +} + +lay::ViewService * +NetlistBrowserDialog::view_service_interface () +{ + return this; +} + +void +NetlistBrowserDialog::probe_button_pressed () +{ +BEGIN_PROTECTED + + m_mouse_state = 1; + + view ()->message (tl::to_string (QObject::tr ("Click on a point in the net"))); + widget ()->grab_mouse (this, false); + +END_PROTECTED +} + void NetlistBrowserDialog::unload_all_clicked () { @@ -510,8 +693,13 @@ NetlistBrowserDialog::activated () void NetlistBrowserDialog::update_content () { + release_mouse (); + db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index); + probe_pb->setEnabled (l2ndb != 0); + release_mouse (); + if (! l2ndb) { central_stack->setCurrentIndex (1); } @@ -554,6 +742,8 @@ NetlistBrowserDialog::update_content () void NetlistBrowserDialog::deactivated () { + release_mouse (); + if (lay::PluginRoot::instance ()) { lay::PluginRoot::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this).c_str ()); } diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.h b/src/laybasic/laybasic/layNetlistBrowserDialog.h index b686caf40..429eb2827 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.h +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.h @@ -27,6 +27,7 @@ #include "ui_NetlistBrowserDialog.h" #include "layBrowser.h" #include "layNetlistBrowser.h" +#include "layViewObject.h" #include "layColorPalette.h" namespace lay @@ -34,6 +35,7 @@ namespace lay class NetlistBrowserDialog : public lay::Browser, + public lay::ViewService, private Ui::NetlistBrowserDialog { Q_OBJECT @@ -49,7 +51,11 @@ private: virtual void activated (); virtual void deactivated (); - bool configure (const std::string &name, const std::string &value); + virtual bool configure (const std::string &name, const std::string &value); + + 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 lay::ViewService *view_service_interface (); // implementation of the lay::Plugin interface virtual void menu_activated (const std::string &symbol); @@ -68,6 +74,8 @@ public slots: void unload_clicked (); void unload_all_clicked (); void configure_clicked (); + void probe_button_pressed (); + void sticky_mode_clicked (); private: lay::NetlistBrowserConfig::net_window_type m_window; @@ -86,6 +94,8 @@ private: std::string m_l2ndb_name; int m_l2n_index; std::string m_open_filename; + db::DPoint m_mouse_first_point; + int m_mouse_state; QAction *m_open_action; QAction *m_saveas_action; QAction *m_export_action; @@ -94,8 +104,8 @@ private: QAction *m_reload_action; void update_content (); - void scan_layer (); - void scan_layer_flat (); + void release_mouse (); + void probe_net (const db::DPoint &p, bool trace_path); }; } diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 6c114b8a2..f59681ddc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -27,6 +27,7 @@ #include "layLayoutView.h" #include "layMarker.h" #include "layNetInfoDialog.h" +#include "tlProgress.h" #include "dbLayoutToNetlist.h" #include "dbNetlistDeviceClasses.h" @@ -1203,8 +1204,16 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const } QVariant -NetlistBrowserModel::headerData (int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const +NetlistBrowserModel::headerData (int section, Qt::Orientation /*orientation*/, int role) const { + if (role == Qt::DisplayRole) { + if (section == 0) { + return tr ("Object"); + } else if (section == 1) { + return tr ("Attribute"); + } + } + return QVariant (); } @@ -1295,6 +1304,13 @@ NetlistBrowserModel::colors_changed () emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex()) - 1, 0, QModelIndex ())); } +QModelIndex +NetlistBrowserModel::index_from_net (const db::Net *net) const +{ + void *id = make_id_circuit_net (circuit_index (net->circuit ()), net_index (net)); + return index_from_id (id, 0); +} + const db::Net * NetlistBrowserModel::net_from_index (const QModelIndex &index) const { @@ -1818,6 +1834,18 @@ NetlistBrowserPage::current_index_changed (const QModelIndex &index) } } +void +NetlistBrowserPage::select_net (const db::Net *net) +{ + if (! net || ! net->circuit ()) { + directory_tree->clearSelection (); + } else { + NetlistBrowserModel *model = dynamic_cast (directory_tree->model ()); + tl_assert (model != 0); + directory_tree->setCurrentIndex (model->index_from_net (net)); + } +} + std::vector NetlistBrowserPage::selected_nets () { @@ -1962,15 +1990,21 @@ NetlistBrowserPage::info_button_pressed () static QModelIndex find_next (QAbstractItemModel *model, const QRegExp &to_find, const QModelIndex &from) { - if (! from.isValid ()) { - return from; + QModelIndex index = from; + + if (! index.isValid () && model->hasChildren (index)) { + index = model->index (0, 0, index); } + if (! index.isValid ()) { + return index; + } + + QModelIndex current = index; + std::vector parent_stack; std::vector > rows_stack; - QModelIndex index = from; - while (index.isValid ()) { parent_stack.push_back (model->parent (index)); @@ -1983,13 +2017,15 @@ static QModelIndex find_next (QAbstractItemModel *model, const QRegExp &to_find, std::reverse (parent_stack.begin (), parent_stack.end ()); std::reverse (rows_stack.begin (), rows_stack.end ()); - QModelIndex current = from; + tl::AbsoluteProgress progress (tl::to_string (tr ("Searching ..."))); do { + ++progress; + bool has_next = false; - if (model->hasChildren (current)) { + if (model->hasChildren (current) && rows_stack.size () < 2) { int row_count = model->rowCount (current); if (row_count > 0) { @@ -2008,7 +2044,7 @@ static QModelIndex find_next (QAbstractItemModel *model, const QRegExp &to_find, ++rows_stack.back ().first; - if (rows_stack.back ().first == rows_stack.back ().second) { + if (rows_stack.back ().first >= rows_stack.back ().second) { // up current = parent_stack.back (); @@ -2033,7 +2069,7 @@ static QModelIndex find_next (QAbstractItemModel *model, const QRegExp &to_find, } - } while (current != from); + } while (current.internalPointer () != from.internalPointer () || current.row () != from.row ()); return QModelIndex (); } @@ -2098,6 +2134,7 @@ NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database) // NOTE: with the tree as the parent, the tree will take over ownership of the model NetlistBrowserModel *new_model = new NetlistBrowserModel (directory_tree, database, &m_colorizer); + delete directory_tree->model (); directory_tree->setModel (new_model); connect (directory_tree->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (current_index_changed (const QModelIndex &))); connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (net_selection_changed ())); diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 1bd372d92..707a66039 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -123,6 +123,7 @@ public: QModelIndex index_from_id (void *id, int column) const; const db::Net *net_from_index (const QModelIndex &index) const; + QModelIndex index_from_net (const db::Net *net) const; private slots: void colors_changed (); @@ -252,6 +253,10 @@ public: */ void set_l2ndb (db::LayoutToNetlist *database); + /** + * @brief Selects a net or clears the selection if net == 0 + */ + void select_net (const db::Net *net); /** * @brief Set the window type and window dimensions