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