diff --git a/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc b/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc index fc1ce6ba3..f662339e2 100644 --- a/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc @@ -126,7 +126,7 @@ Class decl_NetlistObjectPath ("lay", "NetlistObjectPath" gsi::method ("is_null?", &lay::NetlistObjectPath::is_null, "@brief Returns a value indicating whether the path is an empty one.\n" ), - "@brief An object describing the instantiation of an object.\n" + "@brief An object describing the instantiation of a netlist object.\n" "This class describes the instantiation of a net or a device or a circuit in terms of " "a root circuit and a subcircuit chain leading to the indicated object.\n" "\n" @@ -135,6 +135,39 @@ Class decl_NetlistObjectPath ("lay", "NetlistObjectPath" "This class has been introduced in version 0.27.\n" ); +static lay::NetlistObjectPath first (const lay::NetlistObjectsPath *pp) +{ + return pp->first (); +} + +static lay::NetlistObjectPath second (const lay::NetlistObjectsPath *pp) +{ + return pp->second (); +} + +Class decl_NetlistObjectsPath ("lay", "NetlistObjectsPath", + gsi::method_ext ("first", &first, + "@brief Gets the first object's path.\n" + "In cases of paired netlists (LVS database), the first path points to the layout netlist object.\n" + "For the single netlist, the first path is the only path supplied." + ) + + gsi::method_ext ("second", &second, + "@brief Gets the second object's path.\n" + "In cases of paired netlists (LVS database), the first path points to the schematic netlist object.\n" + "For the single netlist, the scecond path is always a null path." + ), + "@brief An object describing the instantiation of a single netlist object or a pair of those.\n" + "This class is basically a pair of netlist object paths (see \\NetlistObjectPath). When derived from a single netlist view, " + "only the first path is valid and will point to the selected object (a net, a device or a circuit). The second path is null.\n" + "\n" + "If the path is derived from a paired netlist view (a LVS report view), the first path corresponds to the object in the layout netlist, " + "the second one to the object in the schematic netlist.\n" + "If the selected object isn't a matched one, either the first or second path may be a null or a partial path without a final net or device object " + "or a partial path.\n" + "\n" + "This class has been introduced in version 0.27.\n" +); + static lay::NetlistObjectPath current_path_first (lay::NetlistBrowserDialog *dialog) { return dialog->current_path ().first (); @@ -169,18 +202,12 @@ Class decl_NetlistBrowserDialog ("lay", "NetlistBrows gsi::method_ext ("current_path_second", ¤t_path_second, "@brief Gets the path of the current object on the second (schematic in case of LVS database) side.\n" ) + - // @@@ - gsi::method ("selected_nets", &lay::NetlistBrowserDialog::selected_nets, - "@brief Gets the nets currently selected in the netlist database browser.\n" + gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path, + "@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n" ) + - gsi::method ("selected_devices", &lay::NetlistBrowserDialog::selected_devices, - "@brief Gets the devices currently selected in the netlist database browser.\n" - ) + - gsi::method ("selected_subcircuits", &lay::NetlistBrowserDialog::selected_subcircuits, - "@brief Gets the subcircuits currently selected in the netlist database browser.\n" - ) + - gsi::method ("selected_circuits", &lay::NetlistBrowserDialog::selected_circuits, - "@brief Gets the circuits currently selected in the netlist database browser.\n" + gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths, + "@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n" + "The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs." ), "@brief Represents the netlist browser dialog.\n" "This dialog is a part of the \\LayoutView class and can be obtained through \\LayoutView#netlist_browser.\n" diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 85cc4b4c3..b44db19bc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -146,46 +146,13 @@ NetlistBrowserDialog::current_path () const } } -const std::vector & -NetlistBrowserDialog::selected_nets () const +const std::vector & +NetlistBrowserDialog::selected_paths () const { if (browser_page) { - return browser_page->current_nets (); + return browser_page->selected_paths (); } else { - static std::vector empty; - return empty; - } -} - -const std::vector & -NetlistBrowserDialog::selected_devices () const -{ - if (browser_page) { - return browser_page->current_devices (); - } else { - static std::vector empty; - return empty; - } -} - -const std::vector & -NetlistBrowserDialog::selected_subcircuits () const -{ - if (browser_page) { - return browser_page->current_subcircuits (); - } else { - static std::vector empty; - return empty; - } -} - -const std::vector & -NetlistBrowserDialog::selected_circuits () const -{ - if (browser_page) { - return browser_page->current_circuits (); - } else { - static std::vector empty; + static std::vector empty; return empty; } } diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.h b/src/laybasic/laybasic/layNetlistBrowserDialog.h index 2c3d84bcb..1c350fc78 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.h +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.h @@ -72,22 +72,7 @@ public: /** * @brief Gets the selected nets */ - const std::vector &selected_nets () const; - - /** - * @brief Gets the selected devices - */ - const std::vector &selected_devices () const; - - /** - * @brief Gets the selected subcircuits - */ - const std::vector &selected_subcircuits () const; - - /** - * @brief Gets the selected circuits - */ - const std::vector &selected_circuits () const; + const std::vector &selected_paths () const; /** * @brief An event indicating that the selection has changed diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 15fabc830..cf055fe0c 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -471,8 +471,18 @@ NetlistBrowserPage::selection_changed () NetlistBrowserModel *model = dynamic_cast (directory_tree->model ()); tl_assert (model != 0); + QModelIndexList selected = directory_tree->selectionModel ()->selectedIndexes (); + + std::vector selected_paths; + selected_paths.reserve (selected.size ()); + for (QModelIndexList::const_iterator i = selected.begin (); i != selected.end (); ++i) { + if (i->column () == 0) { + selected_paths.push_back (model->path_from_index (*i)); + } + } + QModelIndex current = directory_tree->selectionModel ()->currentIndex (); - highlight (model->path_from_index (current)); + highlight (model->path_from_index (current), selected_paths); selection_changed_event (); } @@ -792,11 +802,6 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) clear_markers (); - m_current_nets.clear (); - m_current_devices.clear (); - m_current_subcircuits.clear (); - m_current_circuits.clear (); - m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0); setup_trees (); @@ -888,11 +893,12 @@ NetlistBrowserPage::setup_trees () } void -NetlistBrowserPage::highlight (const NetlistObjectsPath &path) +NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths) { - if (path != m_current_path) { + if (current_path != m_current_path && selected_paths != m_selected_paths) { - m_current_path = path; + m_current_path = current_path; + m_selected_paths = selected_paths; clear_markers (); adjust_view (); @@ -961,24 +967,26 @@ NetlistBrowserPage::adjust_view () const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout (); const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ())); - const db::Circuit *circuit = m_current_path.root.first; - if (! circuit) { - return; - } - const db::Layout *layout = mp_database->internal_layout (); const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ()); if (! layout || ! cell) { return; } - db::DCplxTrans trans; + db::DBox bbox; - if (circuit) { + for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { + + const db::Circuit *circuit = path->root.first; + if (! circuit) { + continue; + } + + db::DCplxTrans trans; trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); - for (std::list >::const_iterator p = m_current_path.path.begin (); p != m_current_path.path.end () && circuit; ++p) { + for (std::list >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) { if (p->first) { circuit = p->first->circuit_ref (); trans = trans * p->first->trans (); @@ -987,16 +995,14 @@ NetlistBrowserPage::adjust_view () } } - } - - db::DBox bbox; - - if (circuit) { + if (! circuit) { + continue; + } db::Box ebox; - const db::Device *device = m_current_path.device.first; - const db::Net *net = m_current_path.net.first; + const db::Device *device = path->device.first; + const db::Net *net = path->net.first; if (device) { @@ -1018,7 +1024,7 @@ NetlistBrowserPage::adjust_view () db::Box layer_bbox; db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); while (! shapes.at_end ()) { - layer_bbox += shapes->bbox (); + layer_bbox += shapes->bbox ().transformed (shapes.trans ()); ++shapes; } @@ -1030,7 +1036,7 @@ NetlistBrowserPage::adjust_view () ebox += bbox_for_circuit (layout, circuit); } - bbox = trans * db::CplxTrans (layout->dbu ()) * ebox; + bbox += trans * db::CplxTrans (layout->dbu ()) * ebox; } @@ -1253,38 +1259,12 @@ NetlistBrowserPage::update_highlights () const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout (); const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ())); - const db::Circuit *circuit = m_current_path.root.first; - if (! circuit) { - return; - } - const db::Layout *layout = mp_database->internal_layout (); const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ()); if (! layout || ! cell) { return; } - // computes the transformation supplied by the path - - db::DCplxTrans trans; - - if (circuit) { - - trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); - - for (std::list >::const_iterator p = m_current_path.path.begin (); p != m_current_path.path.end () && circuit; ++p) { - if (p->first) { - circuit = p->first->circuit_ref (); - trans = trans * p->first->trans (); - } else { - circuit = 0; - } - } - - } - - // a map of display properties vs. layer properties - std::map display_by_lp; for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { if (! lp->has_children () && lp->cellview_index () == int (m_cv_index) && lp->layer_index () >= 0 && (unsigned int) lp->layer_index () < original_layout.layers ()) { @@ -1292,22 +1272,55 @@ NetlistBrowserPage::update_highlights () } } - std::vector tv = mp_view->cv_transform_variants (m_cv_index); - - // correct DBU differences between the storage layout and the original layout - for (std::vector::iterator t = tv.begin (); t != tv.end (); ++t) { - *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); - } - size_t n_markers = 0; bool not_all_shapes_are_shown = false; - if (m_current_path.net.first) { - not_all_shapes_are_shown = produce_highlights_for_net (m_current_path.net.first, n_markers, display_by_lp, tv); - } else if (m_current_path.device.first) { - not_all_shapes_are_shown = produce_highlights_for_device (m_current_path.device.first, n_markers, tv); - } else if (circuit) { - not_all_shapes_are_shown = produce_highlights_for_circuit (circuit, n_markers, tv); + for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { + + const db::Circuit *circuit = path->root.first; + if (! circuit) { + continue; + } + + // computes the transformation supplied by the path + + db::DCplxTrans trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); + + for (std::list >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) { + if (p->first) { + circuit = p->first->circuit_ref (); + trans = trans * p->first->trans (); + } else { + circuit = 0; + } + } + + if (! circuit) { + continue; + } + + // a map of display properties vs. layer properties + + // correct DBU differences between the storage layout and the original layout + std::vector tv = mp_view->cv_transform_variants (m_cv_index); + for (std::vector::iterator t = tv.begin (); t != tv.end (); ++t) { + *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); + } + + if (path->net.first) { + if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tv)) { + not_all_shapes_are_shown = true; + } + } else if (path->device.first) { + if (produce_highlights_for_device (path->device.first, n_markers, tv)) { + not_all_shapes_are_shown = true; + } + } else if (circuit) { + if (produce_highlights_for_circuit (circuit, n_markers, tv)) { + not_all_shapes_are_shown = true; + } + } + } if (not_all_shapes_are_shown) { @@ -1318,7 +1331,6 @@ NetlistBrowserPage::update_highlights () } else { info_label->hide (); } - } void diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 88a48acca..11fb8418d 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -179,33 +179,9 @@ public: /** * @brief Gets the selected nets */ - const std::vector ¤t_nets () const + const std::vector &selected_paths () const { - return m_current_nets; - } - - /** - * @brief Gets the selected devices - */ - const std::vector ¤t_devices () const - { - return m_current_devices; - } - - /** - * @brief Gets the selected subcircuits - */ - const std::vector ¤t_subcircuits () const - { - return m_current_subcircuits; - } - - /** - * @brief Gets the selected circuits - */ - const std::vector ¤t_circuits () const - { - return m_current_circuits; + return m_selected_paths; } /** @@ -258,13 +234,8 @@ private: std::vector mp_markers; bool m_enable_updates; bool m_update_needed; - // @@@ TODO: make multiple ... lay::NetlistObjectsPath m_current_path; - // @@@ TODO: remove - std::vector m_current_nets; - std::vector m_current_devices; - std::vector m_current_subcircuits; - std::vector m_current_circuits; + std::vector m_selected_paths; lay::NetInfoDialog *mp_info_dialog; tl::DeferredMethod dm_update_highlights; tl::DeferredMethod dm_rerun_macro; @@ -275,7 +246,7 @@ private: void navigate_to (const QModelIndex &index, bool forward = true); void adjust_view (); void clear_markers (); - void highlight (const lay::NetlistObjectsPath &path); + void highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths); std::vector selected_nets (); std::vector selected_devices (); std::vector selected_subcircuits ();