diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc
index 90ba1e748..cdde943f9 100644
--- a/src/db/db/dbLayout.cc
+++ b/src/db/db/dbLayout.cc
@@ -1186,7 +1186,7 @@ Layout::allocate_new_cell ()
}
void
-Layout::cleanup ()
+Layout::cleanup (const std::set &keep)
{
// deleting cells may create new top cells which need to be deleted as well, hence we iterate
// until there are no more cells to delete
@@ -1200,6 +1200,10 @@ Layout::cleanup ()
}
}
+ for (std::set::const_iterator k = keep.begin (); k != keep.end (); ++k) {
+ cells_to_delete.erase (*k);
+ }
+
if (cells_to_delete.empty ()) {
break;
}
diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h
index efce2c173..13bf6cee6 100644
--- a/src/db/db/dbLayout.h
+++ b/src/db/db/dbLayout.h
@@ -45,6 +45,7 @@
#include
#include
-
Left Part - The Hierarchy Browser and Navigator
+
Left Part - The Hierarchy Browser, Library View and Navigator
The left panel is the
@@ -45,6 +45,20 @@
+
+ The sub-panel below the hierarchy browser is the library view. This view
+ shows the libraries registered in the system and their content:
+
+
+
+
+
+
+
+ The library view is used to browse and place library cells, which can
+ be normal cells or PCells. Read more about the library view here: .
+
+
The navigator is invisible by default but can be activated by checking the
"Navigator" menu item in the "View" menu. The navigator shows an overview
diff --git a/src/lay/lay/layConfig.h b/src/lay/lay/layConfig.h
index ade67ad0b..2181893aa 100644
--- a/src/lay/lay/layConfig.h
+++ b/src/lay/lay/layConfig.h
@@ -49,6 +49,7 @@ static const std::string cfg_navigator_all_hier_levels ("navigator-show-all-hier
static const std::string cfg_navigator_show_images ("navigator-show-images");
static const std::string cfg_show_layer_toolbox ("show-layer-toolbox");
static const std::string cfg_show_hierarchy_panel ("show-hierarchy-panel");
+static const std::string cfg_show_libraries_view ("show-libraries-view");
static const std::string cfg_show_layer_panel ("show-layer-panel");
static const std::string cfg_window_state ("window-state");
static const std::string cfg_layout_file_watcher_enabled ("layout-file-watcher-enabled");
diff --git a/src/lay/lay/layHelpResources.qrc b/src/lay/lay/layHelpResources.qrc
index 22848c6aa..34dbc7efd 100644
--- a/src/lay/lay/layHelpResources.qrc
+++ b/src/lay/lay/layHelpResources.qrc
@@ -147,6 +147,8 @@
doc/manual/browse_instances.xmldoc/manual/browse_shapes.xmldoc/manual/cell_list.xml
+ doc/manual/library_view.xml
+ doc/manual/library_view.pngdoc/manual/cell.xmldoc/manual/clip.xmldoc/manual/copypaste_cell.xml
diff --git a/src/lay/lay/layMainConfigPages.cc b/src/lay/lay/layMainConfigPages.cc
index 67a85bacd..5b95b0229 100644
--- a/src/lay/lay/layMainConfigPages.cc
+++ b/src/lay/lay/layMainConfigPages.cc
@@ -68,6 +68,7 @@ public:
options.push_back (std::pair (cfg_show_toolbar, "true"));
options.push_back (std::pair (cfg_show_layer_toolbox, "true"));
options.push_back (std::pair (cfg_show_hierarchy_panel, "true"));
+ options.push_back (std::pair (cfg_show_libraries_view, "true"));
options.push_back (std::pair (cfg_show_layer_panel, "true"));
options.push_back (std::pair (cfg_layout_file_watcher_enabled, "true"));
options.push_back (std::pair (cfg_window_state, ""));
diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc
index 349ad61ec..67475dff5 100644
--- a/src/lay/lay/layMainWindow.cc
+++ b/src/lay/lay/layMainWindow.cc
@@ -506,6 +506,13 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha
connect (mp_hp_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_hp_visible = true;
+ mp_libs_dock_widget = new QDockWidget (QObject::tr ("Libraries"), this);
+ mp_libs_dock_widget->setObjectName (QString::fromUtf8 ("libs_dock_widget"));
+ mp_libs_stack = new ControlWidgetStack (mp_libs_dock_widget, "libs_stack");
+ mp_libs_dock_widget->setWidget (mp_libs_stack);
+ connect (mp_libs_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
+ m_libs_visible = true;
+
mp_view_stack = new ViewWidgetStack (mp_main_frame);
mp_view_stack->setObjectName (QString::fromUtf8 ("view_stack"));
vbl->addWidget (mp_view_stack);
@@ -537,6 +544,7 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha
#endif
addDockWidget(Qt::LeftDockWidgetArea, mp_navigator_dock_widget);
addDockWidget(Qt::LeftDockWidgetArea, mp_hp_dock_widget);
+ addDockWidget(Qt::LeftDockWidgetArea, mp_libs_dock_widget);
addDockWidget(Qt::RightDockWidgetArea, mp_lp_dock_widget);
addDockWidget(Qt::RightDockWidgetArea, mp_layer_toolbox_dock_widget);
@@ -849,6 +857,7 @@ MainWindow::init_menu ()
MenuLayoutEntry ("show_layer_panel", tl::to_string (QObject::tr ("Layers")), std::make_pair (cfg_show_layer_panel, "?")),
MenuLayoutEntry ("show_layer_toolbox", tl::to_string (QObject::tr ("Layer Toolbox")), std::make_pair (cfg_show_layer_toolbox, "?")),
MenuLayoutEntry ("show_hierarchy_panel", tl::to_string (QObject::tr ("Cells")), std::make_pair (cfg_show_hierarchy_panel, "?")),
+ MenuLayoutEntry ("show_libraries_view", tl::to_string (QObject::tr ("Libraries")), std::make_pair (cfg_show_libraries_view, "?")),
MenuLayoutEntry ("reset_window_state", tl::to_string (QObject::tr ("Restore Window")), SLOT (cm_reset_window_state ())),
MenuLayoutEntry::separator ("selection_group"),
MenuLayoutEntry ("transient_selection", tl::to_string (QObject::tr ("Highlight Object Under Mouse")), std::make_pair (cfg_sel_transient_mode, "?")),
@@ -1073,6 +1082,8 @@ MainWindow::dock_widget_visibility_changed (bool /*visible*/)
plugin_root ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ()));
} else if (sender () == mp_hp_dock_widget) {
plugin_root ()->config_set (cfg_show_hierarchy_panel, tl::to_string (!mp_hp_dock_widget->isHidden ()));
+ } else if (sender () == mp_libs_dock_widget) {
+ plugin_root ()->config_set (cfg_show_libraries_view, tl::to_string (!mp_libs_dock_widget->isHidden ()));
} else if (sender () == mp_navigator_dock_widget) {
plugin_root ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ()));
} else if (sender () == mp_layer_toolbox_dock_widget) {
@@ -1237,6 +1248,7 @@ MainWindow::close_all ()
mp_views.pop_back ();
mp_lp_stack->removeWidget (mp_views.size ());
mp_hp_stack->removeWidget (mp_views.size ());
+ mp_libs_stack->removeWidget (mp_views.size ());
mp_view_stack->removeWidget (mp_views.size ());
delete view;
@@ -1685,6 +1697,17 @@ MainWindow::configure (const std::string &name, const std::string &value)
return true;
+ } else if (name == cfg_show_libraries_view) {
+
+ tl::from_string (value, m_libs_visible);
+ if (m_libs_visible) {
+ mp_libs_dock_widget->show ();
+ } else {
+ mp_libs_dock_widget->hide ();
+ }
+
+ return true;
+
} else if (name == cfg_show_layer_panel) {
tl::from_string (value, m_lp_visible);
@@ -1797,6 +1820,7 @@ MainWindow::read_dock_widget_state ()
{
plugin_root ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_hierarchy_panel, tl::to_string (!mp_hp_dock_widget->isHidden ()));
+ plugin_root ()->config_set (cfg_show_libraries_view, tl::to_string (!mp_libs_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_layer_toolbox, tl::to_string (!mp_layer_toolbox_dock_widget->isHidden ()));
}
@@ -1810,6 +1834,12 @@ MainWindow::update_dock_widget_state ()
mp_hp_dock_widget->hide ();
}
+ if (m_libs_visible) {
+ mp_libs_dock_widget->show ();
+ } else {
+ mp_libs_dock_widget->hide ();
+ }
+
if (m_lp_visible) {
mp_lp_dock_widget->show ();
} else {
@@ -3270,6 +3300,7 @@ MainWindow::select_view (int index)
mp_view_stack->raiseWidget (index);
mp_hp_stack->raiseWidget (index);
mp_lp_stack->raiseWidget (index);
+ mp_libs_stack->raiseWidget (index);
mp_setup_form->setup ();
}
@@ -3694,6 +3725,7 @@ MainWindow::clone_current_view ()
mp_view_stack->addWidget (view);
mp_lp_stack->addWidget (view->layer_control_frame ());
mp_hp_stack->addWidget (view->hierarchy_control_frame ());
+ mp_libs_stack->addWidget (view->libraries_frame ());
bool f = m_disable_tab_selected;
m_disable_tab_selected = true;
@@ -3940,6 +3972,7 @@ MainWindow::close_view (int index)
mp_view_stack->removeWidget (index);
mp_lp_stack->removeWidget (index);
mp_hp_stack->removeWidget (index);
+ mp_libs_stack->removeWidget (index);
view_closed_event (int (index));
@@ -4312,6 +4345,7 @@ MainWindow::create_view ()
mp_view_stack->addWidget (mp_views.back ());
mp_lp_stack->addWidget (mp_views.back ()->layer_control_frame ());
mp_hp_stack->addWidget (mp_views.back ()->hierarchy_control_frame ());
+ mp_libs_stack->addWidget (mp_views.back ()->libraries_frame ());
bool f = m_disable_tab_selected;
m_disable_tab_selected = true;
@@ -4373,6 +4407,7 @@ MainWindow::create_or_load_layout (const std::string *filename, const db::LoadLa
mp_view_stack->addWidget (mp_views.back ());
mp_lp_stack->addWidget (mp_views.back ()->layer_control_frame ());
mp_hp_stack->addWidget (mp_views.back ()->hierarchy_control_frame ());
+ mp_libs_stack->addWidget (mp_views.back ()->libraries_frame ());
bool f = m_disable_tab_selected;
m_disable_tab_selected = true;
diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h
index 782dc512e..de4ef64ec 100644
--- a/src/lay/lay/layMainWindow.h
+++ b/src/lay/lay/layMainWindow.h
@@ -872,9 +872,9 @@ private:
QToolBar *mp_tool_bar;
QDockWidget *mp_navigator_dock_widget;
lay::Navigator *mp_navigator;
- QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget;
- ControlWidgetStack *mp_hp_stack, *mp_lp_stack;
- bool m_hp_visible, m_lp_visible, m_navigator_visible, m_layer_toolbox_visible;
+ QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget, *mp_libs_dock_widget;
+ ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_libs_stack;
+ bool m_hp_visible, m_lp_visible, m_libs_visible, m_navigator_visible, m_layer_toolbox_visible;
QDockWidget *mp_layer_toolbox_dock_widget;
lay::LayerToolbox *mp_layer_toolbox;
ViewWidgetStack *mp_view_stack;
diff --git a/src/laybasic/laybasic/layCellSelectionForm.cc b/src/laybasic/laybasic/layCellSelectionForm.cc
index 8ce58c1b8..8122e686c 100644
--- a/src/laybasic/laybasic/layCellSelectionForm.cc
+++ b/src/laybasic/laybasic/layCellSelectionForm.cc
@@ -384,7 +384,7 @@ CellSelectionForm::select_entry (lay::CellView::cell_index_type ci)
QModelIndex mi;
for (int c = 0; c < model->toplevel_items (); ++c) {
lay::CellTreeItem *item = model->toplevel_item (c);
- if (item->cell_index () == ci) {
+ if (item->cell_or_pcell_index () == ci) {
mi = model->model_index (item);
break;
}
@@ -736,7 +736,7 @@ LibraryCellSelectionForm::select_pcell_entry (db::pcell_id_type pci)
QModelIndex mi;
for (int c = 0; c < model->toplevel_items (); ++c) {
lay::CellTreeItem *item = model->toplevel_item (c);
- if (item->is_pcell () && item->cell_index () == pci) {
+ if (item->is_pcell () && item->cell_or_pcell_index () == pci) {
mi = model->model_index (item);
break;
}
@@ -775,7 +775,7 @@ LibraryCellSelectionForm::select_entry (lay::CellView::cell_index_type ci)
QModelIndex mi;
for (int c = 0; c < model->toplevel_items (); ++c) {
lay::CellTreeItem *item = model->toplevel_item (c);
- if (item->cell_index () == ci) {
+ if (item->cell_or_pcell_index () == ci) {
mi = model->model_index (item);
break;
}
diff --git a/src/laybasic/laybasic/layCellTreeModel.cc b/src/laybasic/laybasic/layCellTreeModel.cc
index 09ab23d67..819dba8a8 100644
--- a/src/laybasic/laybasic/layCellTreeModel.cc
+++ b/src/laybasic/laybasic/layCellTreeModel.cc
@@ -25,6 +25,9 @@
#include "layLayoutView.h"
#include "tlGlobPattern.h"
#include "dbPCellHeader.h"
+#include "dbPCellVariant.h"
+#include "dbLibraryProxy.h"
+#include "dbLibrary.h"
#include
#include
@@ -82,11 +85,11 @@ struct cmp_cell_tree_item_vs_name_f
// --------------------------------------------------------------------
// CellTreeItem implementation
-CellTreeItem::CellTreeItem (const db::Layout *layout, CellTreeItem *parent, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting s)
- : mp_layout (layout), mp_parent (parent), m_sorting (s), m_is_pcell (is_pcell), m_index (0), m_children (), m_cell_or_pcell_index (cell_or_pcell_index)
+CellTreeItem::CellTreeItem (const db::Layout *layout, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting s)
+ : mp_layout (layout), mp_parent (0), m_sorting (s), m_is_pcell (is_pcell), m_index (0), m_children (), m_cell_or_pcell_index (cell_or_pcell_index)
{
if (! flat && ! is_pcell) {
- m_child_count = int (mp_layout->cell (cell_index ()).child_cells ());
+ m_child_count = int (mp_layout->cell (cell_or_pcell_index).child_cells ());
} else {
m_child_count = 0;
}
@@ -100,13 +103,19 @@ CellTreeItem::~CellTreeItem ()
m_children.clear ();
}
+bool
+CellTreeItem::is_valid () const
+{
+ return m_is_pcell || mp_layout->is_valid_cell_index (cell_or_pcell_index ());
+}
+
std::string
CellTreeItem::display_text () const
{
if (m_is_pcell) {
return name ();
- } else if (mp_layout->is_valid_cell_index (cell_index ())) {
- return mp_layout->cell (cell_index ()).get_display_name ();
+ } else if (mp_layout->is_valid_cell_index (cell_or_pcell_index ())) {
+ return mp_layout->cell (cell_or_pcell_index ()).get_display_name ();
} else {
return std::string ();
}
@@ -125,28 +134,45 @@ CellTreeItem::child (int index)
// create a list of child sub-item
- const db::Cell *cell = & mp_layout->cell (cell_index ());
+ const db::Cell *cell = & mp_layout->cell (cell_or_pcell_index ());
m_children.reserve (m_child_count);
for (db::Cell::child_cell_iterator child = cell->begin_child_cells (); ! child.at_end (); ++child) {
- CellTreeItem *child_item = new CellTreeItem (mp_layout, this, false, *child, false, m_sorting);
- m_children.push_back (child_item);
+ add_child (new CellTreeItem (mp_layout, false, *child, false, m_sorting));
}
- std::sort (m_children.begin (), m_children.end (), cmp_cell_tree_items_f (m_sorting));
-
- for (size_t i = 0; i < m_children.size (); ++i) {
- m_children [i]->set_index (i);
- }
+ finish_children ();
}
return m_children [index];
}
+void
+CellTreeItem::add_child (CellTreeItem *item)
+{
+ // explicitly added
+ if (size_t (m_child_count) == m_children.size ()) {
+ ++m_child_count;
+ }
+
+ item->mp_parent = this;
+ m_children.push_back (item);
+}
+
+void
+CellTreeItem::finish_children ()
+{
+ std::sort (m_children.begin (), m_children.end (), cmp_cell_tree_items_f (m_sorting));
+
+ for (size_t i = 0; i < m_children.size (); ++i) {
+ m_children [i]->set_index (i);
+ }
+}
+
db::cell_index_type
-CellTreeItem::cell_index () const
+CellTreeItem::cell_or_pcell_index () const
{
return db::cell_index_type (m_cell_or_pcell_index);
}
@@ -161,7 +187,7 @@ const char *
CellTreeItem::name () const
{
if (! m_is_pcell) {
- return mp_layout->cell_name (cell_index ());
+ return mp_layout->cell_name (cell_or_pcell_index ());
} else {
return mp_layout->pcell_header (m_cell_or_pcell_index)->get_name ().c_str ();
}
@@ -214,7 +240,7 @@ CellTreeItem::by_area_less_than (const CellTreeItem *b) const
return m_is_pcell > b->is_pcell ();
}
// Hint: since mp_layout == b.mp_layout, not conversion to um^2 is required because of different DBU
- return mp_layout->cell (cell_index ()).bbox ().area () < b->mp_layout->cell (b->cell_index ()).bbox ().area ();
+ return mp_layout->cell (cell_or_pcell_index ()).bbox ().area () < b->mp_layout->cell (b->cell_or_pcell_index ()).bbox ().area ();
}
bool
@@ -224,7 +250,7 @@ CellTreeItem::by_area_equal_than (const CellTreeItem *b) const
return false;
}
// Hint: since mp_layout == b.mp_layout, not conversion to um^2 is required because of different DBU
- return mp_layout->cell (cell_index ()).bbox ().area () == b->mp_layout->cell (b->cell_index ()).bbox ().area ();
+ return mp_layout->cell (cell_or_pcell_index ()).bbox ().area () == b->mp_layout->cell (b->cell_or_pcell_index ()).bbox ().area ();
}
// --------------------------------------------------------------------
@@ -249,6 +275,7 @@ CellTreeModel::CellTreeModel (QWidget *parent, lay::LayoutView *view, int cv_ind
m_pad = ((flags & NoPadding) == 0);
mp_layout = & view->cellview (cv_index)->layout ();
+ mp_library = 0;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
@@ -269,6 +296,28 @@ CellTreeModel::CellTreeModel (QWidget *parent, db::Layout *layout, unsigned int
m_pad = ((flags & NoPadding) == 0);
mp_layout = layout;
+ mp_library = 0;
+ tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
+
+ build_top_level ();
+
+ m_current_index = m_selected_indexes.begin ();
+}
+
+CellTreeModel::CellTreeModel (QWidget *parent, db::Library *library, unsigned int flags, const db::Cell *base, Sorting sorting)
+ : QAbstractItemModel (parent),
+ m_flags (flags),
+ m_sorting (sorting),
+ mp_parent (parent),
+ mp_view (0),
+ m_cv_index (-1),
+ mp_base (base)
+{
+ m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
+ m_pad = ((flags & NoPadding) == 0);
+
+ mp_layout = &library->layout ();
+ mp_library = library;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
@@ -284,8 +333,26 @@ CellTreeModel::~CellTreeModel ()
void
CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting)
{
- bool flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
db::Layout *layout = & view->cellview (cv_index)->layout ();
+ do_configure (layout, 0, view, cv_index, flags, base, sorting);
+}
+
+void
+CellTreeModel::configure (db::Layout *layout, unsigned int flags, const db::Cell *base, Sorting sorting)
+{
+ do_configure (layout, 0, 0, -1, flags, base, sorting);
+}
+
+void
+CellTreeModel::configure (db::Library *library, unsigned int flags, const db::Cell *base, Sorting sorting)
+{
+ do_configure (& library->layout (), library, 0, -1, flags, base, sorting);
+}
+
+void
+CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting)
+{
+ bool flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
bool need_reset = false;
if (flat != m_flat || layout != mp_layout || view != mp_view) {
@@ -300,13 +367,17 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
if (view != mp_view) {
- mp_view->cell_visibility_changed_event.remove (this, &CellTreeModel::signal_data_changed);
- mp_view->cellview_changed_event.remove (this, &CellTreeModel::signal_data_changed_with_int);
+ if (mp_view) {
+ mp_view->cell_visibility_changed_event.remove (this, &CellTreeModel::signal_data_changed);
+ mp_view->cellview_changed_event.remove (this, &CellTreeModel::signal_data_changed_with_int);
+ }
mp_view = view;
- mp_view->cell_visibility_changed_event.add (this, &CellTreeModel::signal_data_changed);
- mp_view->cellview_changed_event.add (this, &CellTreeModel::signal_data_changed_with_int);
+ if (mp_view) {
+ mp_view->cell_visibility_changed_event.add (this, &CellTreeModel::signal_data_changed);
+ mp_view->cellview_changed_event.add (this, &CellTreeModel::signal_data_changed_with_int);
+ }
}
@@ -321,6 +392,7 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
m_pad = ((flags & NoPadding) == 0);
mp_layout = layout;
+ mp_library = library;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
@@ -339,10 +411,10 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
for (QModelIndexList::const_iterator index = indexes.begin (); index != indexes.end (); ++index) {
- std::vector path;
+ std::vector > path;
CellTreeItem *item = (CellTreeItem *) index->internalPointer ();
while (item) {
- path.push_back (item->cell_index ());
+ path.push_back (std::make_pair (item->is_pcell (), item->cell_or_pcell_index ()));
item = item->parent ();
}
@@ -354,22 +426,22 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
// because we push_back'd on our way up:
std::reverse (path.begin (), path.end ());
- for (std::vector::const_iterator ci = path.begin (); ci != path.end (); ++ci) {
+ for (std::vector >::const_iterator ci = path.begin (); ci != path.end (); ++ci) {
CellTreeItem *new_parent = 0;
- if (! layout->is_valid_cell_index (*ci)) {
+ if ((! ci->first && ! layout->is_valid_cell_index (ci->second)) || (ci->first && ! layout->pcell_declaration (ci->second))) {
// can't translate this index
} else if (parent == 0) {
for (int i = 0; i < int (m_toplevel.size ()) && !new_parent; ++i) {
- if (m_toplevel [i]->cell_index () == *ci) {
+ if (m_toplevel [i]->cell_or_pcell_index () == ci->second && m_toplevel [i]->is_pcell () == ci->first) {
new_parent = m_toplevel [i];
row = i;
}
}
} else {
for (int i = 0; i < parent->children () && !new_parent; ++i) {
- if (parent->child (i)->cell_index () == *ci) {
+ if (parent->child (i)->cell_or_pcell_index () == ci->second && parent->child (i)->is_pcell () == ci->first) {
new_parent = parent->child (i);
row = i;
}
@@ -406,7 +478,7 @@ void
CellTreeModel::set_sorting (Sorting s)
{
if (s != m_sorting) {
- configure (mp_view, m_cv_index, m_flags, mp_base, s);
+ do_configure (mp_layout, mp_library, mp_view, m_cv_index, m_flags, mp_base, s);
}
}
@@ -435,7 +507,7 @@ CellTreeModel::build_top_level ()
if (mp_base) {
m_toplevel.reserve (mp_base->child_cells ());
for (db::Cell::child_cell_iterator child = mp_base->begin_child_cells (); ! child.at_end (); ++child) {
- CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *child, true, m_sorting);
+ CellTreeItem *item = new CellTreeItem (mp_layout, false, *child, true, m_sorting);
m_toplevel.push_back (item);
}
}
@@ -447,7 +519,7 @@ CellTreeModel::build_top_level ()
if (mp_base) {
m_toplevel.reserve (mp_base->parent_cells ());
for (db::Cell::parent_cell_iterator parent = mp_base->begin_parent_cells (); parent != mp_base->end_parent_cells (); ++parent) {
- CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *parent, true, m_sorting);
+ CellTreeItem *item = new CellTreeItem (mp_layout, false, *parent, true, m_sorting);
m_toplevel.push_back (item);
}
}
@@ -462,11 +534,11 @@ CellTreeModel::build_top_level ()
while (top != mp_layout->end_top_down ()) {
if (m_flat) {
- CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *top, true, m_sorting);
+ CellTreeItem *item = new CellTreeItem (mp_layout, false, *top, true, m_sorting);
m_toplevel.push_back (item);
} else if (mp_layout->cell (*top).is_top ()) {
if ((m_flags & BasicCells) == 0 || ! mp_layout->cell (*top).is_proxy ()) {
- CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *top, (m_flags & TopCells) != 0, m_sorting);
+ CellTreeItem *item = new CellTreeItem (mp_layout, false, *top, (m_flags & TopCells) != 0, m_sorting);
m_toplevel.push_back (item);
}
} else {
@@ -478,10 +550,30 @@ CellTreeModel::build_top_level ()
}
if ((m_flags & BasicCells) != 0) {
+
for (db::Layout::pcell_iterator pc = mp_layout->begin_pcells (); pc != mp_layout->end_pcells (); ++pc) {
- CellTreeItem *item = new CellTreeItem (mp_layout, 0, true, pc->second, true, m_sorting);
+
+ CellTreeItem *item = new CellTreeItem (mp_layout, true, pc->second, true, m_sorting);
m_toplevel.push_back (item);
+
+ if ((m_flags & WithVariants) != 0) {
+
+ const db::PCellHeader *pcell_header = mp_layout->pcell_header (pc->second);
+ for (db::PCellHeader::variant_iterator v = pcell_header->begin (); v != pcell_header->end (); ++v) {
+ if (mp_library && mp_library->is_retired (v->second->cell_index ())) {
+ // skip retired cells - this means we won't show variants which are just kept
+ // as shadow variants for the transactions.
+ } else {
+ item->add_child (new CellTreeItem (mp_layout, false, v->second->cell_index (), true, m_sorting));
+ }
+ }
+
+ item->finish_children ();
+
+ }
+
}
+
}
}
@@ -510,19 +602,23 @@ CellTreeModel::mimeTypes () const
QMimeData *
CellTreeModel::mimeData(const QModelIndexList &indexes) const
{
- const db::Cell *c = 0;
- for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end () && !c; ++i) {
+ for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end (); ++i) {
+
if (i->isValid()) {
- c = cell (*i);
+
+ if (is_pcell (*i)) {
+ lay::CellDragDropData data (mp_layout, mp_library, pcell_id (*i), true);
+ return data.to_mime_data ();
+ } else if (cell (*i)) {
+ lay::CellDragDropData data (mp_layout, mp_library, cell_index (*i), false);
+ return data.to_mime_data ();
+ }
+
}
+
}
- if (c) {
- lay::CellDragDropData data (mp_layout, c->cell_index ());
- return data.to_mime_data ();
- } else {
- return 0;
- }
+ return 0;
}
int
@@ -561,7 +657,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
const lay::CellView::specific_cell_path_type &ctx_path = mp_view->cellview (m_cv_index).specific_path ();
if (! path.empty ()) {
- if (item->cell_index () == path.back ()) {
+ if (item->cell_or_pcell_index () == path.back ()) {
if (m_flat) {
f.setBold (true);
} else {
@@ -569,7 +665,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
lay::CellView::unspecific_cell_path_type::const_iterator p = path.end ();
while (it && p != path.begin ()) {
--p;
- if (it->cell_index () != *p) {
+ if (it->cell_or_pcell_index () != *p) {
break;
}
it = it->parent ();
@@ -578,7 +674,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
f.setBold (true);
}
}
- } else if (! ctx_path.empty () && item->cell_index () == ctx_path.back ().inst_ptr.cell_index ()) {
+ } else if (! ctx_path.empty () && item->cell_or_pcell_index () == ctx_path.back ().inst_ptr.cell_index ()) {
if (m_flat) {
f.setUnderline (true);
} else {
@@ -586,7 +682,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
lay::CellView::specific_cell_path_type::const_iterator cp = ctx_path.end ();
while (it && cp != ctx_path.begin ()) {
--cp;
- if (it->cell_index () != cp->inst_ptr.cell_index ()) {
+ if (it->cell_or_pcell_index () != cp->inst_ptr.cell_index ()) {
break;
}
it = it->parent ();
@@ -595,7 +691,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
lay::CellView::unspecific_cell_path_type::const_iterator p = path.end ();
while (it && p != path.begin ()) {
--p;
- if (it->cell_index () != *p) {
+ if (it->cell_or_pcell_index () != *p) {
break;
}
it = it->parent ();
@@ -608,7 +704,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
}
}
- if (mp_view->is_cell_hidden (item->cell_index (), m_cv_index)) {
+ if (mp_view->is_cell_hidden (item->cell_or_pcell_index (), m_cv_index)) {
f.setStrikeOut (true);
}
@@ -647,6 +743,17 @@ CellTreeModel::data (const QModelIndex &index, int role) const
return QVariant ();
#endif
+ } else if (role == Qt::DecorationRole && (m_flags & WithIcons) != 0) {
+
+ // TODO: icons for normal cells too?
+ if (item->is_pcell ()) {
+ QIcon icon (":/setup.png");
+ return QVariant (icon);
+ } else {
+ QIcon icon (":/instance.png");
+ return QVariant (icon);
+ }
+
} else {
return QVariant ();
@@ -660,19 +767,6 @@ CellTreeModel::headerData (int /*section*/, Qt::Orientation /*orientation*/, int
return QVariant ();
}
-bool searchItemPtr(CellTreeItem *parent, CellTreeItem *search)
-{
- if (parent == search) {
- return true;
- }
- for (int i = 0; i < parent->children(); ++i) {
- if (searchItemPtr(parent->child(i), search)) {
- return true;
- }
- }
- return false;
-}
-
int
CellTreeModel::rowCount (const QModelIndex &parent) const
{
@@ -682,7 +776,7 @@ CellTreeModel::rowCount (const QModelIndex &parent) const
CellTreeItem *item = (CellTreeItem *) parent.internalPointer ();
if (! item) {
return 0;
- } else if (! mp_layout->is_valid_cell_index (item->cell_index ())) {
+ } else if (! item->is_valid ()) {
// for safety we return 0 children for invalid cells
return 0;
} else {
@@ -702,7 +796,7 @@ CellTreeModel::index (int row, int column, const QModelIndex &parent) const
CellTreeItem *item = (CellTreeItem *) parent.internalPointer ();
if (! item) {
return QModelIndex ();
- } else if (! mp_layout->is_valid_cell_index (item->cell_index ())) {
+ } else if (! item->is_valid ()) {
// for safety we don't return valid child indexes for invalid cells
return QModelIndex ();
} else {
@@ -784,7 +878,7 @@ CellTreeModel::pcell_id (const QModelIndex &index) const
return 0;
} else {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
- return item->cell_index ();
+ return item->cell_or_pcell_index ();
}
}
@@ -795,7 +889,7 @@ CellTreeModel::cell_index (const QModelIndex &index) const
return 0;
} else {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
- return item->cell_index ();
+ return item->cell_or_pcell_index ();
}
}
@@ -804,7 +898,7 @@ CellTreeModel::cell (const QModelIndex &index) const
{
if (index.isValid () && ! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
- return & mp_layout->cell (item->cell_index ());
+ return & mp_layout->cell (item->cell_or_pcell_index ());
} else {
return 0;
}
@@ -816,9 +910,9 @@ CellTreeModel::cell_name (const QModelIndex &index) const
if (index.isValid () && ! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
if (item->is_pcell ()) {
- return mp_layout->pcell_header (item->cell_index ())->get_name ().c_str ();
+ return mp_layout->pcell_header (item->cell_or_pcell_index ())->get_name ().c_str ();
} else {
- return mp_layout->cell_name (item->cell_index ());
+ return mp_layout->cell_name (item->cell_or_pcell_index ());
}
} else {
return 0;
diff --git a/src/laybasic/laybasic/layCellTreeModel.h b/src/laybasic/laybasic/layCellTreeModel.h
index 721df481b..966693e43 100644
--- a/src/laybasic/laybasic/layCellTreeModel.h
+++ b/src/laybasic/laybasic/layCellTreeModel.h
@@ -37,6 +37,11 @@ namespace tl
class GlobPattern;
}
+namespace db
+{
+ class Library;
+}
+
namespace lay
{
@@ -56,18 +61,20 @@ class CellTreeModel
{
public:
enum Flags {
- Flat = 1, // flat list (rather than hierarchy)
- Children = 2, // direct children of cell "base"
- Parents = 4, // direct parents of cell "base"
- TopCells = 8, // show top cells only
- BasicCells = 16, // show basic cells (PCells included, no proxies)
- NoPadding = 32 // enable padding of display string with a blank at the beginning and end
+ Flat = 1, // flat list (rather than hierarchy)
+ Children = 2, // direct children of cell "base"
+ Parents = 4, // direct parents of cell "base"
+ TopCells = 8, // show top cells only
+ BasicCells = 16, // show basic cells (PCells included, no proxies)
+ WithVariants = 32, // show PCell variants below PCells
+ WithIcons = 64, // show icons for the top level cell type
+ NoPadding = 128 // disable padding of display string with a blank at the beginning and end
};
enum Sorting {
- ByName, // sort by name
- ByArea, // sort by cell area (small to large)
- ByAreaReverse // sort by cell area (large to small)
+ ByName, // sort by name
+ ByArea, // sort by cell area (small to large)
+ ByAreaReverse // sort by cell area (large to small)
};
/**
@@ -87,6 +94,13 @@ public:
*/
CellTreeModel (QWidget *parent, db::Layout *layout, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
+ /**
+ * @brief Constructor
+ *
+ * This constructor does not take a view but rather a layout from a library. It does not display hidden status or similar.
+ */
+ CellTreeModel (QWidget *parent, db::Library *library, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
+
/**
* @brief Dtor
*/
@@ -104,10 +118,20 @@ public:
virtual QMimeData *mimeData (const QModelIndexList &indexes) const;
/**
- * @brief Reconfigures the model
+ * @brief Reconfigures the model with a LayoutView
*/
void configure (lay::LayoutView *view, int cv_index, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
+ /**
+ * @brief Reconfigures the model with a pure Layout
+ */
+ void configure (db::Layout *layout, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
+
+ /**
+ * @brief Reconfigures the model with a pure Layout from a library
+ */
+ void configure (db::Library *library, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
+
/**
* @brief Gets the layout this model is connected to
*/
@@ -219,7 +243,8 @@ private:
Sorting m_sorting;
QWidget *mp_parent;
lay::LayoutView *mp_view;
- const db::Layout *mp_layout;
+ db::Layout *mp_layout;
+ db::Library *mp_library;
int m_cv_index;
const db::Cell *mp_base;
std::vector m_toplevel;
@@ -230,6 +255,7 @@ private:
void build_top_level ();
void clear_top_level ();
void search_children (const tl::GlobPattern &pattern, CellTreeItem *item);
+ void do_configure (db::Layout *layout, db::Library *library, lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting);
};
/**
@@ -241,12 +267,12 @@ private:
class CellTreeItem
{
public:
- CellTreeItem (const db::Layout *layout, CellTreeItem *parent, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting sorting);
+ CellTreeItem (const db::Layout *layout, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting sorting);
~CellTreeItem ();
int children () const;
CellTreeItem *child (int index);
- db::cell_index_type cell_index () const;
+ db::cell_index_type cell_or_pcell_index () const;
CellTreeItem *parent () const;
bool by_name_less_than (const CellTreeItem *b) const;
bool by_area_less_than (const CellTreeItem *b) const;
@@ -255,6 +281,9 @@ public:
bool name_equals (const char *name) const;
bool name_matches (const tl::GlobPattern &p) const;
std::string display_text () const;
+ void add_child (CellTreeItem *item);
+ void finish_children ();
+ bool is_valid () const;
bool is_pcell () const
{
diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc
index f8e391e7e..83a8a47ae 100644
--- a/src/laybasic/laybasic/layHierarchyControlPanel.cc
+++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc
@@ -526,6 +526,10 @@ HierarchyControlPanel::search_prev ()
void
HierarchyControlPanel::search_editing_finished ()
{
+ if (! mp_search_frame->isVisible ()) {
+ return;
+ }
+
for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
CellTreeModel *m = dynamic_cast ((*v)->model ());
if (m) {
@@ -572,13 +576,13 @@ HierarchyControlPanel::path_from_index (const QModelIndex &index, int cv_index,
// construct a path in the flat case
lay::CellView cv (m_cellviews [cv_index]);
- cv.set_cell (item->cell_index ());
+ cv.set_cell (item->cell_or_pcell_index ());
path = cv.unspecific_path ();
} else {
while (item) {
- path.push_back (item->cell_index ());
+ path.push_back (item->cell_or_pcell_index ());
item = item->parent ();
}
@@ -630,10 +634,10 @@ HierarchyControlPanel::double_clicked (const QModelIndex &index)
set_active_celltree_from_sender ();
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Show or hide cell")));
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
- if (mp_view->is_cell_hidden (item->cell_index (), m_active_index)) {
- mp_view->show_cell (item->cell_index (), m_active_index);
+ if (mp_view->is_cell_hidden (item->cell_or_pcell_index (), m_active_index)) {
+ mp_view->show_cell (item->cell_or_pcell_index (), m_active_index);
} else {
- mp_view->hide_cell (item->cell_index (), m_active_index);
+ mp_view->hide_cell (item->cell_or_pcell_index (), m_active_index);
}
mp_view->manager ()->commit ();
}
@@ -733,6 +737,8 @@ HierarchyControlPanel::selection_changed (int index)
{
if (index != m_active_index) {
+ search_editing_finished ();
+
m_active_index = index;
bool split_mode = m_split_mode;
@@ -744,6 +750,9 @@ HierarchyControlPanel::selection_changed (int index)
int i = 0;
for (std::vector ::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) {
(*f)->setVisible (i == index || split_mode);
+ if (i == index) {
+ mp_cell_lists [i]->setFocus ();
+ }
}
i = 0;
@@ -771,7 +780,7 @@ HierarchyControlPanel::index_from_path (const cell_path_type &path, int cv_index
// TODO: linear search might not be effective enough ..
for (int c = 0; c < model->toplevel_items (); ++c) {
CellTreeItem *item = model->toplevel_item (c);
- if (item->cell_index () == path.back ()) {
+ if (item->cell_or_pcell_index () == path.back ()) {
return model->model_index (item);
}
}
@@ -780,7 +789,7 @@ HierarchyControlPanel::index_from_path (const cell_path_type &path, int cv_index
for (int c = 0; c < model->toplevel_items (); ++c) {
CellTreeItem *item = model->toplevel_item (c);
- if (item->cell_index () == path.front ()) {
+ if (item->cell_or_pcell_index () == path.front ()) {
item = find_child_item (path.begin () + 1, path.end (), item);
if (item) {
return model->model_index (item);
@@ -804,7 +813,7 @@ HierarchyControlPanel::find_child_item (cell_path_type::const_iterator start, ce
for (int n = 0; n < p->children (); ++n) {
CellTreeItem *item = p->child (n);
- if (item && item->cell_index () == *start) {
+ if (item && item->cell_or_pcell_index () == *start) {
return find_child_item (start + 1, end, item);
}
}
diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc
index 54b498936..3930c678c 100644
--- a/src/laybasic/laybasic/layLayoutView.cc
+++ b/src/laybasic/laybasic/layLayoutView.cc
@@ -61,6 +61,7 @@
#include "layLayoutCanvas.h"
#include "layLayerControlPanel.h"
#include "layHierarchyControlPanel.h"
+#include "layLibrariesView.h"
#include "layBrowser.h"
#include "layRedrawThread.h"
#include "layRedrawThreadWorker.h"
@@ -72,6 +73,7 @@
#include "dbRecursiveShapeIterator.h"
#include "dbManager.h"
#include "dbEdgeProcessor.h"
+#include "dbLibrary.h"
#include "rdb.h"
#include "rdbMarkerBrowserDialog.h"
#include "dbLayoutToNetlist.h"
@@ -356,6 +358,8 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
mp_control_frame = 0;
mp_hierarchy_panel = 0;
mp_hierarchy_frame = 0;
+ mp_libraries_view = 0;
+ mp_libraries_frame = 0;
mp_min_hier_spbx = 0;
mp_max_hier_spbx = 0;
m_from_level = 0;
@@ -445,6 +449,17 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
vbl->setMargin (0);
vbl->setSpacing (0);
+ mp_canvas = new lay::LayoutCanvas (this, this);
+ vbl->addWidget (mp_canvas);
+ connect (mp_canvas, SIGNAL (left_arrow_key_pressed ()), this, SLOT (pan_left ()));
+ connect (mp_canvas, SIGNAL (up_arrow_key_pressed ()), this, SLOT (pan_up ()));
+ connect (mp_canvas, SIGNAL (right_arrow_key_pressed ()), this, SLOT (pan_right ()));
+ connect (mp_canvas, SIGNAL (down_arrow_key_pressed ()), this, SLOT (pan_down ()));
+ connect (mp_canvas, SIGNAL (left_arrow_key_pressed_with_shift ()), this, SLOT (pan_left_fast ()));
+ connect (mp_canvas, SIGNAL (up_arrow_key_pressed_with_shift ()), this, SLOT (pan_up_fast ()));
+ connect (mp_canvas, SIGNAL (right_arrow_key_pressed_with_shift ()), this, SLOT (pan_right_fast ()));
+ connect (mp_canvas, SIGNAL (down_arrow_key_pressed_with_shift ()), this, SLOT (pan_down_fast ()));
+
if ((m_options & LV_NoHierarchyPanel) == 0 && (m_options & LV_Naked) == 0) {
QFrame *hierarchy_frame = new QFrame (0);
@@ -491,16 +506,21 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
}
- mp_canvas = new lay::LayoutCanvas (this, this);
- vbl->addWidget (mp_canvas);
- connect (mp_canvas, SIGNAL (left_arrow_key_pressed ()), this, SLOT (pan_left ()));
- connect (mp_canvas, SIGNAL (up_arrow_key_pressed ()), this, SLOT (pan_up ()));
- connect (mp_canvas, SIGNAL (right_arrow_key_pressed ()), this, SLOT (pan_right ()));
- connect (mp_canvas, SIGNAL (down_arrow_key_pressed ()), this, SLOT (pan_down ()));
- connect (mp_canvas, SIGNAL (left_arrow_key_pressed_with_shift ()), this, SLOT (pan_left_fast ()));
- connect (mp_canvas, SIGNAL (up_arrow_key_pressed_with_shift ()), this, SLOT (pan_up_fast ()));
- connect (mp_canvas, SIGNAL (right_arrow_key_pressed_with_shift ()), this, SLOT (pan_right_fast ()));
- connect (mp_canvas, SIGNAL (down_arrow_key_pressed_with_shift ()), this, SLOT (pan_down_fast ()));
+ if ((m_options & LV_NoLibrariesView) == 0 && (m_options & LV_Naked) == 0) {
+
+ QFrame *libraries_frame = new QFrame (0);
+ libraries_frame->setObjectName (QString::fromUtf8 ("libs_frame"));
+ mp_libraries_frame = libraries_frame;
+ QVBoxLayout *left_frame_ly = new QVBoxLayout (libraries_frame);
+ left_frame_ly->setMargin (0);
+ left_frame_ly->setSpacing (0);
+
+ mp_libraries_view = new lay::LibrariesView (this, libraries_frame, "libs");
+ left_frame_ly->addWidget (mp_libraries_view, 1 /*stretch*/);
+
+ connect (mp_libraries_view, SIGNAL (active_library_changed (int)), this, SLOT (active_library_changed (int)));
+
+ }
// occupy services and editables:
// these services get deleted by the canvas destructor automatically:
@@ -628,6 +648,12 @@ LayoutView::~LayoutView ()
}
mp_hierarchy_frame = 0;
mp_hierarchy_panel = 0;
+
+ if (mp_libraries_frame) {
+ delete mp_libraries_frame;
+ }
+ mp_libraries_frame = 0;
+ mp_libraries_view = 0;
}
void LayoutView::hideEvent (QHideEvent *)
@@ -790,6 +816,7 @@ LayoutView::init_menu (lay::AbstractMenu &menu)
{
lay::LayerControlPanel::init_menu (menu);
lay::HierarchyControlPanel::init_menu (menu);
+ lay::LibrariesView::init_menu (menu);
}
void
@@ -951,6 +978,22 @@ LayoutView::configure (const std::string &name, const std::string &value)
}
return true;
+ } else if (name == cfg_split_lib_views) {
+
+ bool f;
+ tl::from_string (value, f);
+ if (mp_libraries_view) {
+ mp_libraries_view->set_split_mode (f);
+ }
+ return true;
+
+ } else if (name == cfg_current_lib_view) {
+
+ if (mp_libraries_view) {
+ mp_libraries_view->select_active_lib_by_name (value);
+ }
+ return true;
+
} else if (name == cfg_cell_list_sorting) {
if (mp_hierarchy_panel) {
@@ -4472,6 +4515,11 @@ LayoutView::background_color (QColor c)
mp_hierarchy_panel->set_text_color (contrast);
}
+ if (mp_libraries_view) {
+ mp_libraries_view->set_background_color (c);
+ mp_libraries_view->set_text_color (contrast);
+ }
+
if (mp_selection_service) {
mp_selection_service->set_colors (c, contrast);
}
@@ -4550,6 +4598,19 @@ LayoutView::active_cellview_changed (int index)
}
}
+void
+LayoutView::active_library_changed (int /*index*/)
+{
+ std::string lib_name;
+ if (mp_libraries_view->active_lib ()) {
+ lib_name = mp_libraries_view->active_lib ()->get_name ();
+ }
+
+ // commit the new active library to the other views and persist this state
+ // TODO: could be passed through the LibraryController (like through some LibraryController::active_library)
+ plugin_root ()->config_set (cfg_current_lib_view, lib_name);
+}
+
void
LayoutView::cellview_changed (unsigned int index)
{
@@ -7243,7 +7304,7 @@ LayoutView::sizeHint () const
{
if ((m_options & LV_Naked) != 0) {
return QSize (200, 200);
- } else if ((m_options & LV_NoLayers) != 0 || (m_options & LV_NoHierarchyPanel) != 0) {
+ } else if ((m_options & LV_NoLayers) != 0 || (m_options & LV_NoHierarchyPanel) != 0 || (m_options & LV_NoLibrariesView) != 0) {
return QSize (400, 200);
} else {
return QSize (600, 200);
diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h
index 5b871e7a4..cf5cbc8b9 100644
--- a/src/laybasic/laybasic/layLayoutView.h
+++ b/src/laybasic/laybasic/layLayoutView.h
@@ -70,6 +70,7 @@ namespace lay {
class AbstractMenu;
class LayerControlPanel;
class HierarchyControlPanel;
+class LibrariesView;
class MouseTracker;
class ZoomService;
class SelectionService;
@@ -168,13 +169,14 @@ public:
LV_Normal = 0,
LV_NoLayers = 1,
LV_NoHierarchyPanel = 2,
- LV_Naked = 4,
- LV_NoZoom = 8,
- LV_NoGrid = 16,
- LV_NoMove = 32,
- LV_NoTracker = 64,
- LV_NoSelection = 128,
- LV_NoPlugins = 256,
+ LV_NoLibrariesView = 4,
+ LV_Naked = 8,
+ LV_NoZoom = 16,
+ LV_NoGrid = 32,
+ LV_NoMove = 64,
+ LV_NoTracker = 128,
+ LV_NoSelection = 256,
+ LV_NoPlugins = 512,
LV_NoServices = LV_NoMove + LV_NoTracker + LV_NoSelection + LV_NoPlugins
};
@@ -221,7 +223,7 @@ public:
bool has_selection ();
/**
- * @brief Get the container with the layer control panel
+ * @brief Gets the container with the layer control panel
*/
QWidget *layer_control_frame ()
{
@@ -229,7 +231,7 @@ public:
}
/**
- * @brief Get the container with the hierarchy control panel
+ * @brief Gets the container with the hierarchy control panel
*/
QWidget *hierarchy_control_frame ()
{
@@ -237,7 +239,15 @@ public:
}
/**
- * @brief Paste from clipboard
+ * @brief Gets the container with the libraries view
+ */
+ QWidget *libraries_frame ()
+ {
+ return mp_libraries_frame;
+ }
+
+ /**
+ * @brief Pastes from clipboard
*
* This reimplementation of the lay::Editables interface additionally
* looks for paste receivers in the tree views for example.
@@ -245,7 +255,7 @@ public:
void paste ();
/**
- * @brief Copy to clipboard
+ * @brief Copies to clipboard
*
* This reimplementation of the lay::Editables interface additionally
* looks for copy providers in the tree views for example.
@@ -253,7 +263,7 @@ public:
void copy ();
/**
- * @brief Cut to clipboard
+ * @brief Cuts to clipboard
*
* This reimplementation of the lay::Editables interface additionally
* looks for cut & copy providers in the tree views for example.
@@ -261,7 +271,7 @@ public:
void cut ();
/**
- * @brief Get the explicit title string of the view
+ * @brief Gets the explicit title string of the view
*
* This is the one explicitly set, not the one displayed. The displayed text is composed of internal information
* if no title string is set.
@@ -272,17 +282,17 @@ public:
}
/**
- * @brief Get the window title of the view
+ * @brief Gets the window title of the view
*/
std::string title () const;
/**
- * @brief Set the window title to an explicit string
+ * @brief Sets the window title to an explicit string
*/
void set_title (const std::string &t);
/**
- * @brief Reset the explicit title and enable the automatic naming
+ * @brief Resets the explicit title and enable the automatic naming
*/
void reset_title ();
@@ -2627,6 +2637,7 @@ public slots:
private slots:
void active_cellview_changed (int index);
+ void active_library_changed (int index);
void goto_bookmark ();
signals:
@@ -2695,7 +2706,8 @@ private:
QFrame *mp_left_frame;
lay::LayerControlPanel *mp_control_panel;
lay::HierarchyControlPanel *mp_hierarchy_panel;
- QWidget *mp_control_frame, *mp_hierarchy_frame;
+ lay::LibrariesView *mp_libraries_view;
+ QWidget *mp_control_frame, *mp_hierarchy_frame, *mp_libraries_frame;
QSpinBox *mp_min_hier_spbx;
QSpinBox *mp_max_hier_spbx;
std::list m_cellviews;
diff --git a/src/laybasic/laybasic/layLayoutViewConfigPages.cc b/src/laybasic/laybasic/layLayoutViewConfigPages.cc
index 2fcb6ebf6..3c0ca93b4 100644
--- a/src/laybasic/laybasic/layLayoutViewConfigPages.cc
+++ b/src/laybasic/laybasic/layLayoutViewConfigPages.cc
@@ -1486,6 +1486,8 @@ public:
options.push_back (std::pair (cfg_flat_cell_list, "false"));
options.push_back (std::pair (cfg_split_cell_list, "false"));
options.push_back (std::pair (cfg_cell_list_sorting, "by-name"));
+ options.push_back (std::pair (cfg_split_lib_views, "false"));
+ options.push_back (std::pair (cfg_current_lib_view, ""));
options.push_back (std::pair (cfg_hide_empty_layers, "false"));
options.push_back (std::pair (cfg_min_inst_label_size, "16"));
options.push_back (std::pair (cfg_cell_box_text_font, "0"));
diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc
new file mode 100644
index 000000000..d0bc69894
--- /dev/null
+++ b/src/laybasic/laybasic/layLibrariesView.cc
@@ -0,0 +1,820 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2019 Matthias Koefferlein
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "dbClipboard.h"
+#include "dbClipboardData.h"
+#include "dbLibraryManager.h"
+#include "dbLibrary.h"
+#include "layLibrariesView.h"
+#include "layCellTreeModel.h"
+#include "layLayoutView.h"
+#include "layAbstractMenu.h"
+#include "layAbstractMenuProvider.h"
+#include "layDialogs.h"
+#include "tlExceptions.h"
+#include "laybasicConfig.h"
+#include "tlInternational.h"
+#include "tlString.h"
+#include "gtf.h"
+
+namespace lay
+{
+
+// --------------------------------------------------------------------
+// A helper class the identifies clipboard data
+
+class CellClipboardData
+ : public db::ClipboardData
+{
+public:
+ CellClipboardData () { }
+};
+
+// --------------------------------------------------------------------
+// LibraryTreeWidget implementation
+
+LibraryTreeWidget::LibraryTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver)
+ : QTreeView (parent), mp_key_event_receiver (key_event_receiver)
+{
+ // Allow dragging from here to
+ setDragDropMode (QAbstractItemView::DragOnly);
+
+ setObjectName (QString::fromUtf8 (name));
+}
+
+
+bool
+LibraryTreeWidget::event (QEvent *event)
+{
+#if 0
+ // Handling this event makes the widget receive all keystrokes.
+ // Without this code, shortcuts override the search function.
+ if (event->type () == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast (event);
+ QString t = ke->text ();
+ if (!t.isEmpty () && t[0].isPrint ()) {
+ ke->accept ();
+ }
+ }
+#endif
+ return QTreeView::event (event);
+}
+
+bool
+LibraryTreeWidget::focusNextPrevChild (bool /*next*/)
+{
+ return false;
+}
+
+void
+LibraryTreeWidget::keyPressEvent (QKeyEvent *event)
+{
+ QString t = event->text ();
+ if (! t.isEmpty () && t[0].isPrint ()) {
+ // "/" is a search initiator
+ if (t == QString::fromUtf8 ("/")) {
+ t.clear ();
+ }
+ emit search_triggered (t);
+ } else if (mp_key_event_receiver) {
+ // send other key events to the alternative receiver - this way we can make the
+ // view receive arrow keys for panning.
+ QCoreApplication::sendEvent (mp_key_event_receiver, event);
+ } else {
+ return QTreeView::keyPressEvent (event);
+ }
+}
+
+void
+LibraryTreeWidget::startDrag (Qt::DropActions supportedActions)
+{
+ QModelIndex index = selectionModel ()->currentIndex ();
+ if (index.isValid ()) {
+
+ QModelIndexList indexes;
+ indexes << index;
+ QMimeData *data = model ()->mimeData (indexes);
+ if (!data) {
+ return;
+ }
+
+ QDrag *drag = new QDrag (this);
+ drag->setMimeData(data);
+ QPixmap px (1, 1);
+ px.fill (QColor (0, 0, 0));
+ px.createMaskFromColor (QColor (0, 0, 0), Qt::MaskOutColor);
+ drag->setPixmap (px);
+
+ Qt::DropAction defaultDropAction = Qt::IgnoreAction;
+ if (supportedActions & Qt::CopyAction) {
+ defaultDropAction = Qt::CopyAction;
+ }
+
+ drag->exec(supportedActions, defaultDropAction);
+
+ }
+}
+
+void
+LibraryTreeWidget::mouseDoubleClickEvent (QMouseEvent *event)
+{
+ QModelIndex index (indexAt (event->pos ()));
+ if (index.isValid ()) {
+ emit cell_double_clicked (index);
+ }
+}
+
+void
+LibraryTreeWidget::mousePressEvent (QMouseEvent *event)
+{
+ if (event->button () == Qt::MidButton) {
+ // eat this event.
+ } else {
+ QModelIndex index (indexAt (event->pos ()));
+ if (index.isValid ()) {
+ emit cell_clicked (index);
+ }
+ QTreeView::mousePressEvent (event);
+ }
+}
+
+void
+LibraryTreeWidget::mouseReleaseEvent (QMouseEvent *event)
+{
+ if (event->button () == Qt::MidButton) {
+ QModelIndex index (indexAt (event->pos ()));
+ if (index.isValid ()) {
+ emit cell_middle_clicked (index);
+ }
+ } else {
+ QTreeView::mouseReleaseEvent (event);
+ }
+}
+
+
+// --------------------------------------------------------------------
+// LibrariesView implementation
+
+const int max_cellviews_in_split_mode = 5;
+
+void
+LibrariesView::init_menu (lay::AbstractMenu &menu)
+{
+ MenuLayoutEntry context_menu [] = {
+#if 0
+ // doesn't make sense for many libs
+ MenuLayoutEntry ("split_mode", tl::to_string (QObject::tr ("Split Mode")), std::make_pair (cfg_split_lib_views, "?")),
+#endif
+ MenuLayoutEntry::last ()
+ };
+
+ MenuLayoutEntry main_menu [] = {
+ MenuLayoutEntry ("@lib_context_menu", "", context_menu),
+ MenuLayoutEntry::last ()
+ };
+
+ menu.init (main_menu);
+}
+
+LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char *name)
+ : QFrame (parent),
+ m_enable_cb (true),
+ mp_view (view),
+ m_split_mode (false),
+ m_do_update_content_dm (this, &LibrariesView::do_update_content),
+ m_do_full_update_content_dm (this, &LibrariesView::do_full_update_content)
+{
+ setObjectName (QString::fromUtf8 (name));
+
+ QVBoxLayout *ly = new QVBoxLayout (this);
+ ly->setSpacing (0);
+ ly->setContentsMargins (0, 0, 0, 0);
+
+ mp_selector = new QComboBox (this);
+ mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
+ ly->addWidget (mp_selector);
+
+ mp_search_frame = new QFrame (this);
+ ly->addWidget (mp_search_frame);
+ mp_search_frame->hide ();
+ mp_search_frame->setAutoFillBackground (true);
+ mp_search_frame->setObjectName (QString::fromUtf8 ("panel"));
+ mp_search_frame->setFrameStyle (QFrame::Panel | QFrame::Raised);
+ mp_search_frame->setLineWidth (1);
+ mp_search_frame->setBackgroundRole (QPalette::Highlight);
+
+ QHBoxLayout *sf_ly = new QHBoxLayout (mp_search_frame);
+ sf_ly->setMargin (0);
+ sf_ly->setContentsMargins (0, 0, 0, 0);
+ sf_ly->setSpacing (0);
+
+ mp_search_close_cb = new QCheckBox (mp_search_frame);
+ sf_ly->addWidget (mp_search_close_cb);
+
+ mp_search_close_cb->setFocusPolicy (Qt::NoFocus);
+ mp_search_close_cb->setBackgroundRole (QPalette::Highlight);
+ mp_search_close_cb->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred));
+ QPalette pl (mp_search_close_cb->palette ());
+ pl.setColor (QPalette::Foreground, pl.color (QPalette::Active, QPalette::HighlightedText));
+ mp_search_close_cb->setPalette (pl);
+ mp_search_close_cb->setMaximumSize (QSize (mp_search_close_cb->maximumSize ().width (), mp_search_close_cb->sizeHint ().height () - 4));
+ connect (mp_search_close_cb, SIGNAL (clicked ()), this, SLOT (search_editing_finished ()));
+
+ mp_search_model = 0;
+ mp_search_edit_box = new lay::DecoratedLineEdit (mp_search_frame);
+ mp_search_edit_box->setObjectName (QString::fromUtf8 ("cellview_search_edit_box"));
+ mp_search_edit_box->set_escape_signal_enabled (true);
+ mp_search_edit_box->set_tab_signal_enabled (true);
+ connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
+ connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited ()));
+ connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
+ connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
+ connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
+ sf_ly->addWidget (mp_search_edit_box);
+
+ mp_use_regular_expressions = new QAction (this);
+ mp_use_regular_expressions->setCheckable (true);
+ mp_use_regular_expressions->setChecked (true);
+ mp_use_regular_expressions->setText (tr ("Use expressions (use * and ? for any character)"));
+
+ mp_case_sensitive = new QAction (this);
+ mp_case_sensitive->setCheckable (true);
+ mp_case_sensitive->setChecked (true);
+ mp_case_sensitive->setText (tr ("Case sensitive search"));
+
+ QMenu *m = new QMenu (mp_search_edit_box);
+ m->addAction (mp_use_regular_expressions);
+ m->addAction (mp_case_sensitive);
+ connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
+ connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
+
+ mp_search_edit_box->set_clear_button_enabled (true);
+ mp_search_edit_box->set_options_button_enabled (true);
+ mp_search_edit_box->set_options_menu (m);
+
+ QToolButton *sf_next = new QToolButton (mp_search_frame);
+ sf_next->setAutoRaise (true);
+ sf_next->setToolTip (tr ("Find next"));
+ sf_next->setIcon (QIcon (QString::fromUtf8 (":/find.png")));
+ connect (sf_next, SIGNAL (clicked ()), this, SLOT (search_next ()));
+ sf_ly->addWidget (sf_next);
+
+ mp_splitter = new QSplitter (Qt::Vertical, this);
+ ly->addWidget (mp_splitter);
+
+ connect (mp_selector, SIGNAL (activated (int)), this, SLOT (selection_changed (int)));
+
+ QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Preferred);
+ sp.setHorizontalStretch (0);
+ sp.setVerticalStretch (0);
+ setSizePolicy (sp);
+
+ do_update_content ();
+}
+
+LibrariesView::~LibrariesView ()
+{
+ // .. nothing yet ..
+}
+
+QSize
+LibrariesView::sizeHint () const
+{
+ int w = 120; // TODO: better(?): mp_cell_list->sizeHint ().width ();
+ return QSize (w, 0);
+}
+
+bool
+LibrariesView::event (QEvent *e)
+{
+ if (e->type () == QEvent::MaxUser) {
+ // GTF probe event
+ e->accept ();
+ return true;
+ } else {
+ return QFrame::event (e);
+ }
+}
+
+void
+LibrariesView::context_menu (const QPoint &p)
+{
+ tl_assert (lay::AbstractMenuProvider::instance () != 0);
+
+ QTreeView *cell_list = dynamic_cast (sender ());
+ if (cell_list) {
+ QMenu *ctx_menu = lay::AbstractMenuProvider::instance ()->menu ()->detached_menu ("lib_context_menu");
+ ctx_menu->exec (cell_list->mapToGlobal (p));
+ }
+}
+
+void
+LibrariesView::set_split_mode (bool f)
+{
+ if (f != m_split_mode) {
+ m_split_mode = f;
+ m_do_update_content_dm ();
+ }
+}
+
+void
+LibrariesView::clear_all ()
+{
+ m_libraries.clear ();
+ m_needs_update.clear ();
+ m_force_close.clear ();
+
+ for (size_t i = 0; i < mp_cell_list_frames.size (); ++i) {
+ delete mp_cell_list_frames [i];
+ }
+ mp_cell_list_frames.clear ();
+ mp_cell_list_headers.clear ();
+ mp_cell_lists.clear ();
+}
+
+void
+LibrariesView::search_triggered (const QString &t)
+{
+ mp_search_model = 0;
+ lay::LibraryTreeWidget *w = dynamic_cast (sender ());
+ if (w) {
+ for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
+ if (mp_cell_lists [i] == w) {
+ // Switch the active list for split mode -> CAUTION: this may trigger a search_editing_finished call
+ select_active (int (i));
+ mp_search_model = dynamic_cast (w->model ());
+ break;
+ }
+ }
+ }
+
+ if (mp_search_model) {
+ mp_search_close_cb->setChecked (true);
+ mp_search_frame->show ();
+ mp_search_edit_box->setText (t);
+ mp_search_edit_box->setFocus ();
+ search_edited ();
+ }
+}
+
+void
+LibrariesView::search_edited ()
+{
+ QString t = mp_search_edit_box->text ();
+
+ for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
+ if ((*v)->model () == mp_search_model) {
+ if (t.isEmpty ()) {
+ mp_search_model->clear_locate ();
+ (*v)->setCurrentIndex (QModelIndex ());
+ } else {
+ QModelIndex found = mp_search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false);
+ (*v)->setCurrentIndex (found);
+ if (found.isValid ()) {
+ (*v)->scrollTo (found);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void
+LibrariesView::search_next ()
+{
+ for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
+ if ((*v)->model () == mp_search_model) {
+ QModelIndex found = mp_search_model->locate_next ();
+ if (found.isValid ()) {
+ (*v)->setCurrentIndex (found);
+ (*v)->scrollTo (found);
+ }
+ break;
+ }
+ }
+}
+
+void
+LibrariesView::search_prev ()
+{
+ for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
+ if ((*v)->model () == mp_search_model) {
+ QModelIndex found = mp_search_model->locate_prev ();
+ if (found.isValid ()) {
+ (*v)->setCurrentIndex (found);
+ (*v)->scrollTo (found);
+ }
+ break;
+ }
+ }
+}
+
+void
+LibrariesView::search_editing_finished ()
+{
+ if (! mp_search_frame->isVisible ()) {
+ return;
+ }
+
+ for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
+ CellTreeModel *m = dynamic_cast ((*v)->model ());
+ if (m) {
+ m->clear_locate ();
+ }
+ }
+
+ // give back the focus to the cell list
+ for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
+ if (mp_cell_lists [i]->model () == mp_search_model) {
+ mp_cell_lists [i]->setFocus ();
+ break;
+ }
+ }
+
+ mp_search_frame->hide ();
+ mp_search_model = 0;
+}
+
+void
+LibrariesView::middle_clicked (const QModelIndex &index)
+{
+ // ... nothing yet ..
+}
+
+void
+LibrariesView::header_clicked ()
+{
+ // ... nothing yet ..
+}
+
+void
+LibrariesView::clicked (const QModelIndex & /*index*/)
+{
+ // ... nothing yet ..
+}
+
+void
+LibrariesView::double_clicked (const QModelIndex &index)
+{
+ // ... nothing yet ..
+}
+
+void
+LibrariesView::set_background_color (QColor c)
+{
+ m_background_color = c;
+ for (std::vector ::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) {
+ QPalette pl ((*f)->palette ());
+ pl.setColor (QPalette::Base, c);
+ (*f)->setPalette (pl);
+ }
+}
+
+void
+LibrariesView::set_text_color (QColor c)
+{
+ m_text_color = c;
+ for (std::vector ::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) {
+ QPalette pl ((*f)->palette ());
+ pl.setColor (QPalette::Text, c);
+ (*f)->setPalette (pl);
+ }
+}
+
+void
+LibrariesView::update_required ()
+{
+ m_do_full_update_content_dm ();
+}
+
+void
+LibrariesView::do_full_update_content ()
+{
+ size_t i = 0;
+ for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib, ++i) {
+ if (m_needs_update.size () > i) {
+ m_needs_update [i] = true;
+ }
+ if (m_force_close.size () > i) {
+ m_force_close [i] = true;
+ }
+ }
+
+ do_update_content ();
+}
+
+void
+LibrariesView::do_update_content (int lib_index)
+{
+ // close the search box since we will modify the model
+ mp_search_frame->hide ();
+ mp_search_model = 0;
+
+ size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index);
+ size_t imax = (lib_index < 0 ? std::numeric_limits ::max () : (size_t) lib_index);
+
+ // rebuild all events
+ detach_from_all_events ();
+ db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required);
+
+ std::vector libraries;
+ for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
+ libraries.push_back (db::LibraryManager::instance ().lib (lib->second));
+ libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
+ libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
+ }
+
+ for (size_t i = imin; i < libraries.size () && i <= imax; ++i) {
+ if (i < m_libraries.size () && ! m_libraries[i].get ()) {
+ tl_assert (i < m_force_close.size ());
+ m_force_close [i] = true;
+ }
+ if (i >= m_force_close.size ()) {
+ m_force_close.push_back (true);
+ }
+ if (i >= m_needs_update.size ()) {
+ m_needs_update.push_back (true);
+ }
+ if (i >= libraries.size ()) {
+ m_force_close [i] = true;
+ m_needs_update [i] = true;
+ }
+ }
+
+ size_t n = std::min (m_libraries.size (), libraries.size ());
+ for (size_t i = imin; i < n && i <= imax; ++i) {
+
+ if (m_libraries [i].get () != libraries [i]) {
+ m_needs_update [i] = true;
+ m_force_close [i] = true;
+ }
+
+ if (m_needs_update [i]) {
+ mp_cell_lists [i]->doItemsLayout (); // triggers a redraw
+ }
+
+ m_libraries [i].reset (libraries [i]);
+
+ }
+
+ if (m_libraries.size () < libraries.size ()) {
+ for (size_t i = n; i < libraries.size (); ++i) {
+ m_libraries.push_back (tl::weak_ptr (libraries [i]));
+ }
+ } else if (m_libraries.size () > libraries.size ()) {
+ m_libraries.erase (m_libraries.begin () + libraries.size (), m_libraries.end ());
+ }
+
+ bool split_mode = m_split_mode;
+ // for more than max_cellviews_in_split_mode cellviews, switch to overlay mode
+ if (int (m_libraries.size ()) > max_cellviews_in_split_mode) {
+ split_mode = false;
+ }
+
+ while (mp_cell_lists.size () < m_libraries.size ()) {
+
+ size_t i = mp_cell_lists.size ();
+
+ QPalette pl;
+
+ QFrame *cl_frame = new QFrame (this);
+ cl_frame->setFrameShape (QFrame::NoFrame);
+ QVBoxLayout *cl_ly = new QVBoxLayout (cl_frame);
+ cl_ly->setSpacing (0);
+ cl_ly->setContentsMargins (0, 0, 0, 0);
+
+ QToolButton *header = new QToolButton (cl_frame);
+ connect (header, SIGNAL (clicked ()), this, SLOT (header_clicked ()));
+ header->setText (tl::to_qstring (display_string (int (i))));
+ header->setFocusPolicy (Qt::NoFocus);
+ header->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred);
+ header->setCheckable (true);
+ header->setAutoRaise (true);
+ header->setAutoFillBackground (true);
+ header->setVisible (split_mode);
+ cl_ly->addWidget (header);
+
+ LibraryTreeWidget *cell_list = new LibraryTreeWidget (cl_frame, "tree", mp_view->view_object_widget ());
+ cl_ly->addWidget (cell_list);
+ cell_list->setModel (new CellTreeModel (cell_list, m_libraries [i].get (), CellTreeModel::Flat | CellTreeModel::TopCells | CellTreeModel::BasicCells | CellTreeModel::WithVariants | CellTreeModel::WithIcons, 0));
+ cell_list->setUniformRowHeights (true);
+
+ pl = cell_list->palette ();
+ if (m_text_color.isValid ()) {
+ pl.setColor (QPalette::Text, m_text_color);
+ }
+ if (m_background_color.isValid ()) {
+ pl.setColor (QPalette::Base, m_background_color);
+ }
+ cell_list->setPalette (pl);
+
+ cell_list->header ()->hide ();
+ cell_list->setSelectionMode (QTreeView::ExtendedSelection);
+ cell_list->setRootIsDecorated (true);
+ cell_list->setContextMenuPolicy (Qt::CustomContextMenu);
+
+ connect (cell_list, SIGNAL (customContextMenuRequested (const QPoint &)), this, SLOT (context_menu (const QPoint &)));
+ connect (cell_list, SIGNAL (cell_clicked (const QModelIndex &)), this, SLOT (clicked (const QModelIndex &)));
+ connect (cell_list, SIGNAL (cell_double_clicked (const QModelIndex &)), this, SLOT (double_clicked (const QModelIndex &)));
+ connect (cell_list, SIGNAL (cell_middle_clicked (const QModelIndex &)), this, SLOT (middle_clicked (const QModelIndex &)));
+ connect (cell_list, SIGNAL (search_triggered (const QString &)), this, SLOT (search_triggered (const QString &)));
+
+ mp_cell_lists.push_back (cell_list);
+ mp_cell_list_frames.push_back (cl_frame);
+ mp_cell_list_headers.push_back (header);
+
+ mp_splitter->addWidget (cl_frame);
+
+ }
+
+ while (mp_cell_lists.size () > m_libraries.size ()) {
+ delete mp_cell_list_frames.back ();
+ mp_cell_list_frames.pop_back ();
+ mp_cell_list_headers.pop_back ();
+ mp_cell_lists.pop_back ();
+ }
+
+ for (unsigned int i = imin; i < m_libraries.size () && i < (unsigned int) mp_selector->count () && i <= imax; ++i) {
+ mp_selector->setItemText (i, tl::to_qstring (display_string (i)));
+ }
+ while (mp_selector->count () < int (m_libraries.size ())) {
+ mp_selector->addItem (tl::to_qstring (display_string (mp_selector->count ())));
+ }
+ while (mp_selector->count () > int (m_libraries.size ())) {
+ mp_selector->removeItem (mp_selector->count () - 1);
+ }
+
+ if (m_active_index >= int (m_libraries.size ())) {
+ m_active_index = int (m_libraries.size ()) - 1;
+ } else if (m_active_index < 0 && ! m_libraries.empty ()) {
+ m_active_index = 0;
+ }
+ mp_selector->setCurrentIndex (m_active_index);
+ mp_selector->setVisible (mp_cell_lists.size () > 1 && ! split_mode);
+
+ for (unsigned int i = imin; i < m_libraries.size () && i <= imax; ++i) {
+
+ if (m_needs_update [i]) {
+
+ mp_cell_list_headers [i]->setText (tl::to_qstring (display_string (i)));
+
+ // draw the cells in the level of the current cell,
+ // add an "above" entry if there is a level above.
+ // highlight the current entry. If the index is
+ // invalid, just clear the list.
+
+ if (m_force_close [i]) {
+
+ m_force_close [i] = false;
+
+ CellTreeModel *model = dynamic_cast (mp_cell_lists [i]->model ());
+ if (model) {
+ model->configure (m_libraries [i].get (), CellTreeModel::Flat | CellTreeModel::TopCells | CellTreeModel::BasicCells | CellTreeModel::WithVariants | CellTreeModel::WithIcons, 0);
+ }
+
+ }
+
+ m_needs_update [i] = false;
+
+ }
+
+ mp_cell_list_headers [i]->setVisible (split_mode && m_libraries.size () > 1);
+ mp_cell_list_headers [i]->setChecked (int (i) == m_active_index);
+
+ mp_cell_list_frames [i]->setVisible (int (i) == m_active_index || split_mode);
+
+ }
+}
+
+void
+LibrariesView::select_active_lib_by_name (const std::string &name)
+{
+ for (std::vector >::const_iterator i = m_libraries.begin (); i != m_libraries.end (); ++i) {
+ if (i->get () && (*i)->get_name () == name) {
+ select_active (int (i - m_libraries.begin ()));
+ break;
+ }
+ }
+}
+
+void
+LibrariesView::select_active (int lib_index)
+{
+ if (lib_index != m_active_index) {
+ mp_selector->setCurrentIndex (lib_index);
+ selection_changed (lib_index);
+ }
+}
+
+db::Library *
+LibrariesView::active_lib ()
+{
+ if (m_active_index >= 0 && m_active_index < int (m_libraries.size ())) {
+ return m_libraries [m_active_index].get ();
+ }
+ return 0;
+}
+
+void
+LibrariesView::selection_changed (int index)
+{
+ if (index != m_active_index) {
+
+ search_editing_finished ();
+
+ m_active_index = index;
+
+ bool split_mode = m_split_mode;
+ // for more than max_cellviews_in_split_mode cellviews, switch to overlay mode
+ if (int (m_libraries.size ()) > max_cellviews_in_split_mode) {
+ split_mode = false;
+ }
+
+ int i = 0;
+ for (std::vector ::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) {
+ (*f)->setVisible (i == index || split_mode);
+ if (i == index) {
+ mp_cell_lists [i]->setFocus ();
+ }
+ }
+
+ i = 0;
+ for (std::vector ::const_iterator f = mp_cell_list_headers.begin (); f != mp_cell_list_headers.end (); ++f, ++i) {
+ (*f)->setChecked (i == index);
+ }
+
+ emit active_library_changed (index);
+
+ }
+}
+
+std::string
+LibrariesView::display_string (int n) const
+{
+ const db::Library *lib = m_libraries [n].get ();
+ std::string text = lib->get_name ();
+ if (! lib->get_description ().empty ()) {
+ text += " - " + lib->get_description ();
+ }
+ return text;
+}
+
+CellTreeItem *
+LibrariesView::current_item () const
+{
+ if (m_active_index < 0 || m_active_index >= int (mp_cell_lists.size ())) {
+ return 0;
+ }
+ if (mp_cell_lists [m_active_index]->currentIndex ().isValid ()) {
+ return (CellTreeItem *) mp_cell_lists [m_active_index]->currentIndex ().internalPointer ();
+ } else {
+ return 0;
+ }
+}
+
+bool
+LibrariesView::has_focus () const
+{
+ return m_active_index >= 0 && m_active_index < int (mp_cell_lists.size ()) && mp_cell_lists [m_active_index]->hasFocus ();
+}
+
+} // namespace lay
diff --git a/src/laybasic/laybasic/layLibrariesView.h b/src/laybasic/laybasic/layLibrariesView.h
new file mode 100644
index 000000000..7960d7985
--- /dev/null
+++ b/src/laybasic/laybasic/layLibrariesView.h
@@ -0,0 +1,280 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2019 Matthias Koefferlein
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+
+#ifndef HDR_layLibrariesView
+#define HDR_layLibrariesView
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include "dbLayout.h"
+#include "layCanvasPlane.h"
+#include "layViewOp.h"
+#include "layLayoutView.h"
+#include "layCellTreeModel.h"
+#include "layWidgets.h"
+#include "tlDeferredExecution.h"
+
+class QModelIndex;
+class QComboBox;
+class QMenu;
+class QSplitter;
+class QFrame;
+class QToolButton;
+class QLineEdit;
+class QAction;
+class QCheckBox;
+
+namespace lay
+{
+
+/**
+ * @brief A special QTreeView customization
+ *
+ * A customized QTreeView that is used to receive middle-mouse-button
+ * events and processes double clicks by bypassing the standard implementation
+ * that closes and opens branches.
+ */
+class LibraryTreeWidget
+ : public QTreeView
+{
+Q_OBJECT
+
+public:
+ LibraryTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver);
+
+signals:
+ void cell_clicked (const QModelIndex &);
+ void cell_double_clicked (const QModelIndex &);
+ void cell_middle_clicked (const QModelIndex &);
+ void search_triggered (const QString &t);
+
+protected:
+ virtual void mouseDoubleClickEvent (QMouseEvent *event);
+ virtual void mousePressEvent (QMouseEvent *event);
+ virtual void mouseReleaseEvent (QMouseEvent *event);
+ virtual void startDrag (Qt::DropActions supportedActions);
+ virtual bool focusNextPrevChild (bool next);
+ virtual void keyPressEvent (QKeyEvent *event);
+ virtual bool event (QEvent *event);
+
+ QWidget *mp_key_event_receiver;
+};
+
+/**
+ * @brief The hierarchy control panel
+ *
+ * The hierarchy control panel allows changing the cell shown, to
+ * browse the hierarchy and disable/enable cells
+ *
+ * The class communicates with a Layout interface for
+ * retrieval of the cell hierarchy
+ */
+class LibrariesView
+ : public QFrame,
+ public tl::Object
+{
+Q_OBJECT
+
+public:
+ /**
+ * @brief Constructor
+ *
+ * @param parent The Qt parent widget
+ * @param name The layer control panel's widget name
+ */
+ LibrariesView (lay::LayoutView *view, QWidget *parent = 0, const char *name = "libraries_view");
+
+ /**
+ * @brief Destructor
+ */
+ ~LibrariesView ();
+
+ /**
+ * @brief Perform the cell control panel's initialisations on the main menu
+ */
+ static void init_menu (lay::AbstractMenu &menu);
+
+ /**
+ * @brief The sizeHint implementation for Qt layout management
+ */
+ virtual QSize sizeHint () const;
+
+ /**
+ * @brief Changing of the background color
+ */
+ void set_background_color (QColor c);
+
+ /**
+ * @brief Changing of the text color
+ */
+ void set_text_color (QColor c);
+
+ /**
+ * @brief Sets the active library by name
+ */
+ void select_active_lib_by_name (const std::string &name);
+
+ /**
+ * @brief Select the active cellview
+ *
+ * selects the active cellview by index. The index must be
+ * a valid index within the context of the layout view.
+ */
+ void select_active (int lib_index);
+
+ /**
+ * @brief Get the active cellview
+ *
+ * get the active cellview index.
+ */
+ int active ()
+ {
+ return m_active_index;
+ }
+
+ /**
+ * @brief Gets the active library or 0 if there is no active library
+ */
+ db::Library *active_lib ();
+
+ /**
+ * @brief Update the contents if necessary
+ *
+ * Update the cell trees according to the hierarchy found in
+ * the layouts. This version includes a hint which cellview has changed.
+ */
+ void do_update_content (int cv_index);
+
+ /**
+ * @brief Update the contents if necessary
+ *
+ * Update the cell trees according to the hierarchy found in
+ * the layouts.
+ */
+ void do_update_content ()
+ {
+ do_update_content (-1);
+ }
+
+ /**
+ * @brief Event handler
+ *
+ * The object subclasses the event handler in order to intercept
+ * the GTF probe events (Qt::MaxUser).
+ */
+ virtual bool event (QEvent *e);
+
+ /**
+ * @brief Return true, if the tree view has the focus
+ */
+ bool has_focus () const;
+
+ /**
+ * @brief Select split mode
+ * In split mode all cell trees are shown stacked
+ */
+ void set_split_mode (bool sbs);
+
+ /**
+ * @brief Returns true if side-by-side mode is set
+ */
+ bool split_mode () const
+ {
+ return m_split_mode;
+ }
+
+ /**
+ * @brief Gets the layout view this panel is attached to
+ */
+ lay::LayoutView *view ()
+ {
+ return mp_view;
+ }
+
+signals:
+ void active_library_changed (int cellview_index);
+
+public slots:
+ void clicked (const QModelIndex &index);
+ void header_clicked ();
+ void double_clicked (const QModelIndex &index);
+ void middle_clicked (const QModelIndex &index);
+ void selection_changed (int index);
+ void context_menu (const QPoint &pt);
+ void search_triggered (const QString &t);
+ void search_edited ();
+ void search_editing_finished ();
+ void search_next ();
+ void search_prev ();
+
+private:
+ db::Layout *mp_layout;
+ bool m_enable_cb;
+ lay::LayoutView *mp_view;
+ std::vector mp_cell_lists;
+ std::vector mp_cell_list_headers;
+ std::vector mp_cell_list_frames;
+ std::vector m_force_close;
+ std::vector m_needs_update;
+ int m_active_index;
+ bool m_split_mode;
+ QComboBox *mp_selector;
+ lay::DecoratedLineEdit *mp_search_edit_box;
+ QAction *mp_case_sensitive;
+ QAction *mp_use_regular_expressions;
+ CellTreeModel *mp_search_model;
+ QFrame *mp_search_frame;
+ QCheckBox *mp_search_close_cb;
+ QSplitter *mp_splitter;
+ QColor m_background_color;
+ QColor m_text_color;
+ tl::DeferredMethod m_do_update_content_dm;
+ tl::DeferredMethod m_do_full_update_content_dm;
+ std::auto_ptr mp_tree_style;
+ std::vector > m_libraries;
+
+ // event listener for changes in the cellview and layout
+ void update_required ();
+
+ // get the current item
+ CellTreeItem *current_item () const;
+
+ // clears all widgets of the cell lists
+ void clear_all ();
+
+ // display string of nth cellview
+ std::string display_string (int n) const;
+
+ // forces a complete update
+ void do_full_update_content ();
+};
+
+} // namespace lay
+
+#endif
+
diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc
index affdb81d2..37162137c 100644
--- a/src/laybasic/laybasic/layViewObject.cc
+++ b/src/laybasic/laybasic/layViewObject.cc
@@ -70,7 +70,9 @@ CellDragDropData::serialized () const
stream << QString::fromUtf8 ("CellDragDropData");
stream << (quintptr) mp_layout;
+ stream << (quintptr) mp_library;
stream << m_cell_index;
+ stream << m_is_pcell;
return data;
}
@@ -88,7 +90,10 @@ CellDragDropData::deserialize (const QByteArray &ba)
quintptr p = 0;
stream >> p;
mp_layout = reinterpret_cast (p);
+ stream >> p;
+ mp_library = reinterpret_cast (p);
stream >> m_cell_index;
+ stream >> m_is_pcell;
return true;
} else {
diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h
index 432eb585d..5b9185412 100644
--- a/src/laybasic/laybasic/layViewObject.h
+++ b/src/laybasic/laybasic/layViewObject.h
@@ -53,6 +53,12 @@ class QDragLeaveEvent;
class QDropEvent;
class QMimeData;
+namespace db
+{
+ class Library;
+ class Layout;
+}
+
namespace lay {
class Viewport;
@@ -113,7 +119,7 @@ public:
* @brief Default ctor
*/
CellDragDropData ()
- : mp_layout (0), m_cell_index (0)
+ : mp_layout (0), mp_library (0), m_cell_index (0), m_is_pcell (false)
{
// .. nothing yet ..
}
@@ -124,8 +130,8 @@ public:
* @param layout the layout where the cell lives in
* @param cell_index The index of the cell
*/
- CellDragDropData (const db::Layout *layout, db::cell_index_type cell_index)
- : mp_layout (layout), m_cell_index (cell_index)
+ CellDragDropData (const db::Layout *layout, const db::Library *library, db::cell_index_type cell_or_pcell_index, bool is_pcell)
+ : mp_layout (layout), mp_library (library), m_cell_index (cell_or_pcell_index), m_is_pcell (is_pcell)
{
// .. nothing yet ..
}
@@ -138,6 +144,14 @@ public:
return mp_layout;
}
+ /**
+ * @brief Gets the layout object where the cell lives in
+ */
+ const db::Library *library () const
+ {
+ return mp_library;
+ }
+
/**
* @brief Gets the index of the cell
*/
@@ -146,6 +160,14 @@ public:
return m_cell_index;
}
+ /**
+ * @brief Gets a value indicating whether the cell is a pcell
+ */
+ bool is_pcell () const
+ {
+ return m_is_pcell;
+ }
+
/**
* @brief Serializes itself to an QByteArray
*/
@@ -160,7 +182,9 @@ public:
private:
const db::Layout *mp_layout;
+ const db::Library *mp_library;
db::cell_index_type m_cell_index;
+ bool m_is_pcell;
};
/**
diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro
index b285677ca..5d59bd3af 100644
--- a/src/laybasic/laybasic/laybasic.pro
+++ b/src/laybasic/laybasic/laybasic.pro
@@ -175,7 +175,8 @@ SOURCES = \
layNetlistBrowserModel.cc \
layIndexedNetlistModel.cc \
layNetlistCrossReferenceModel.cc \
- layNetlistBrowserTreeModel.cc
+ layNetlistBrowserTreeModel.cc \
+ layLibrariesView.cc
HEADERS = \
gtf.h \
@@ -271,7 +272,8 @@ HEADERS = \
layNetlistBrowserModel.h \
layIndexedNetlistModel.h \
layNetlistCrossReferenceModel.h \
- layNetlistBrowserTreeModel.h
+ layNetlistBrowserTreeModel.h \
+ layLibrariesView.h
INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC
diff --git a/src/laybasic/laybasic/laybasicConfig.h b/src/laybasic/laybasic/laybasicConfig.h
index 4953c3edb..ecdcabb1f 100644
--- a/src/laybasic/laybasic/laybasicConfig.h
+++ b/src/laybasic/laybasic/laybasicConfig.h
@@ -124,6 +124,9 @@ static const std::string cfg_flat_cell_list ("flat-cell-list");
static const std::string cfg_split_cell_list ("split-cell-list");
static const std::string cfg_cell_list_sorting ("cell-list-sorting");
+static const std::string cfg_split_lib_views ("split-lib-views");
+static const std::string cfg_current_lib_view ("current-lib-view");
+
static const std::string cfg_pan_distance ("pan-distance");
static const std::string cfg_paste_display_mode ("paste-display-mode");
diff --git a/src/lib/lib/libBasicArc.cc b/src/lib/lib/libBasicArc.cc
index 27112d4d3..0ad950218 100644
--- a/src/lib/lib/libBasicArc.cc
+++ b/src/lib/lib/libBasicArc.cc
@@ -204,7 +204,13 @@ BasicArc::produce (const db::Layout &layout, const std::vector &la
std::string
BasicArc::get_display_name (const db::pcell_parameters_type ¶meters) const
{
- return std::string("ARC(r=") + tl::micron_to_string (parameters [p_actual_radius1].to_double ()) + ".." + tl::micron_to_string (parameters [p_actual_radius2].to_double ()) + ",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) + ".." + tl::to_string (parameters [p_end_angle].to_double (), 6) + ")";
+ return "ARC(l=" + std::string (parameters [p_layer].to_string ()) +
+ ",r=" + tl::to_string (parameters [p_actual_radius1].to_double ()) +
+ ".." + tl::to_string (parameters [p_actual_radius2].to_double ()) +
+ ",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) +
+ ".." + tl::to_string (parameters [p_end_angle].to_double (), 6) +
+ ",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
+ ")";
}
std::vector
diff --git a/src/lib/lib/libBasicCircle.cc b/src/lib/lib/libBasicCircle.cc
index bcc29411c..049387f1c 100644
--- a/src/lib/lib/libBasicCircle.cc
+++ b/src/lib/lib/libBasicCircle.cc
@@ -142,7 +142,10 @@ BasicCircle::produce (const db::Layout &layout, const std::vector
std::string
BasicCircle::get_display_name (const db::pcell_parameters_type ¶meters) const
{
- return std::string("CIRCLE(r=") + tl::micron_to_string (parameters [p_actual_radius].to_double ()) + ")";
+ return "CIRCLE(l=" + std::string (parameters [p_layer].to_string ()) +
+ ",r=" + tl::to_string (parameters [p_actual_radius].to_double ()) +
+ ",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
+ ")";
}
std::vector
diff --git a/src/lib/lib/libBasicDonut.cc b/src/lib/lib/libBasicDonut.cc
index 9b1a53ad2..504534288 100644
--- a/src/lib/lib/libBasicDonut.cc
+++ b/src/lib/lib/libBasicDonut.cc
@@ -169,7 +169,11 @@ BasicDonut::produce (const db::Layout &layout, const std::vector &
std::string
BasicDonut::get_display_name (const db::pcell_parameters_type ¶meters) const
{
- return std::string("DONUT(r=") + tl::micron_to_string (parameters [p_actual_radius1].to_double ()) + ".." + tl::micron_to_string (parameters [p_actual_radius2].to_double ()) + ")";
+ return "DONUT(l=" + std::string (parameters [p_layer].to_string ()) +
+ ",r=" + tl::to_string (parameters [p_actual_radius1].to_double ()) +
+ ".." + tl::to_string (parameters [p_actual_radius2].to_double ()) +
+ ",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
+ ")";
}
std::vector
diff --git a/src/lib/lib/libBasicEllipse.cc b/src/lib/lib/libBasicEllipse.cc
index 1d213452e..d0eb147ef 100644
--- a/src/lib/lib/libBasicEllipse.cc
+++ b/src/lib/lib/libBasicEllipse.cc
@@ -173,7 +173,11 @@ BasicEllipse::produce (const db::Layout &layout, const std::vector
std::string
BasicEllipse::get_display_name (const db::pcell_parameters_type ¶meters) const
{
- return std::string("ELLIPSE(rx=") + tl::micron_to_string (parameters [p_actual_radius_x].to_double ()) + ",ry=" + tl::micron_to_string (parameters [p_actual_radius_y].to_double ()) + ")";
+ return "ELLIPSE(l=" + std::string (parameters [p_layer].to_string ()) +
+ ",rx=" + tl::to_string (parameters [p_actual_radius_x].to_double ()) +
+ ",ry=" + tl::to_string (parameters [p_actual_radius_y].to_double ()) +
+ ",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
+ ")";
}
std::vector
diff --git a/src/lib/lib/libBasicPie.cc b/src/lib/lib/libBasicPie.cc
index bd3bc6d12..46e8b766b 100644
--- a/src/lib/lib/libBasicPie.cc
+++ b/src/lib/lib/libBasicPie.cc
@@ -186,7 +186,12 @@ BasicPie::produce (const db::Layout &layout, const std::vector &la
std::string
BasicPie::get_display_name (const db::pcell_parameters_type ¶meters) const
{
- return std::string("PIE(r=") + tl::micron_to_string (parameters [p_actual_radius].to_double ()) + ",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) + ".." + tl::to_string (parameters [p_end_angle].to_double (), 6) + ")";
+ return "PIE(l=" + std::string (parameters [p_layer].to_string ()) +
+ ",r=" + tl::to_string (parameters [p_actual_radius].to_double ()) +
+ ",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) +
+ ".." + tl::to_string (parameters [p_end_angle].to_double (), 6) +
+ ",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
+ ")";
}
std::vector
diff --git a/src/lib/lib/libBasicRoundPath.cc b/src/lib/lib/libBasicRoundPath.cc
index 20931f27b..11844284d 100644
--- a/src/lib/lib/libBasicRoundPath.cc
+++ b/src/lib/lib/libBasicRoundPath.cc
@@ -108,7 +108,10 @@ BasicRoundPath::produce (const db::Layout &layout, const std::vector
diff --git a/src/lib/lib/libBasicRoundPolygon.cc b/src/lib/lib/libBasicRoundPolygon.cc
index 110679a1b..da14fc4ea 100644
--- a/src/lib/lib/libBasicRoundPolygon.cc
+++ b/src/lib/lib/libBasicRoundPolygon.cc
@@ -112,7 +112,10 @@ BasicRoundPolygon::produce (const db::Layout &layout, const std::vector
diff --git a/src/lib/lib/libBasicStrokedPolygon.cc b/src/lib/lib/libBasicStrokedPolygon.cc
index fb910acbb..94b834163 100644
--- a/src/lib/lib/libBasicStrokedPolygon.cc
+++ b/src/lib/lib/libBasicStrokedPolygon.cc
@@ -134,7 +134,12 @@ BasicStrokedPolygon::produce (const db::Layout &layout, const std::vector
diff --git a/src/lib/lib/libBasicText.cc b/src/lib/lib/libBasicText.cc
index 84d95a761..b20683c7f 100644
--- a/src/lib/lib/libBasicText.cc
+++ b/src/lib/lib/libBasicText.cc
@@ -177,7 +177,8 @@ BasicText::get_display_name (const db::pcell_parameters_type ¶meters) const
if (! parameters.empty ()) {
t = parameters [p_text].to_string ();
}
- return std::string("TEXT('") + t + "')";
+ return "TEXT(l=" + std::string (parameters [p_layer].to_string ()) +
+ ",'" + t + "')";
}
std::vector