From a104352a93cae1ef33447fbd69f1e721eebb7c0e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Aug 2019 00:08:39 +0200 Subject: [PATCH] WIP: library browser - cleanup of unused cells in lib browser, some bug fixed, enhancements to parameter editor on drop --- src/db/db/dbLayout.cc | 6 +- src/db/db/dbLayout.h | 6 +- src/db/db/dbLibrary.cc | 29 +++- src/db/db/dbLibrary.h | 27 +++- src/db/db/dbLibraryProxy.cc | 12 ++ src/db/db/dbManager.h | 18 ++- src/db/db/dbPCellDeclaration.cc | 17 ++ src/db/db/dbPCellDeclaration.h | 5 + src/edt/edt/PCellParametersDialog.ui | 73 +++++++++ src/edt/edt/edt.pro | 5 +- src/edt/edt/edtEditorOptionsPages.cc | 11 +- src/edt/edt/edtPCellParametersDialog.cc | 65 ++++++++ src/edt/edt/edtPCellParametersDialog.h | 86 ++++++++++ src/edt/edt/edtPCellParametersPage.cc | 44 +++++- src/edt/edt/edtPCellParametersPage.h | 18 ++- src/edt/edt/edtService.cc | 39 +++++ src/edt/edt/edtService.h | 12 ++ src/edt/edt/edtServiceImpl.cc | 181 ++++++++++++++-------- src/edt/edt/edtServiceImpl.h | 8 + src/laybasic/laybasic/layCellTreeModel.cc | 8 +- src/laybasic/laybasic/layLibrariesView.cc | 1 + 21 files changed, 579 insertions(+), 92 deletions(-) create mode 100644 src/edt/edt/PCellParametersDialog.ui create mode 100644 src/edt/edt/edtPCellParametersDialog.cc create mode 100644 src/edt/edt/edtPCellParametersDialog.h 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 27724cf78..189389030 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -1442,9 +1443,10 @@ public: /** * @brief Cleans up the layout * - * This method removes proxy objects which are no longer used + * This method removes proxy objects which are no longer used. + * It can be given a list of cells which need to be kept. */ - void cleanup (); + void cleanup (const std::set &keep = std::set ()); /** * @brief Implementation of the undo operations diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 7ea6b28ed..feb9160b0 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -76,7 +76,34 @@ Library::unregister_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly) } } -void +void +Library::retire_proxy (db::LibraryProxy *lib_proxy) +{ + m_retired_count.insert (std::make_pair (lib_proxy->library_cell_index (), 0)).first->second += 1; + retired_state_changed_event (); +} + +void +Library::unretire_proxy (db::LibraryProxy *lib_proxy) +{ + std::map::iterator c = m_retired_count.find (lib_proxy->library_cell_index ()); + if (c != m_retired_count.end ()) { + if (! --c->second) { + m_retired_count.erase (c); + } + retired_state_changed_event (); + } +} + +bool +Library::is_retired (const db::cell_index_type library_cell_index) const +{ + std::map::const_iterator i = m_refcount.find (library_cell_index); + std::map::const_iterator j = m_retired_count.find (library_cell_index); + return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second); +} + +void Library::remap_to (db::Library *other) { // Hint: in the loop over the referrers we might unregister (delete from m_referrers) a referrer because no more cells refer to us. diff --git a/src/db/db/dbLibrary.h b/src/db/db/dbLibrary.h index aa5daf4aa..3d1794413 100644 --- a/src/db/db/dbLibrary.h +++ b/src/db/db/dbLibrary.h @@ -163,6 +163,26 @@ public: */ void unregister_proxy (db::LibraryProxy *lib_proxy, db::Layout *layout); + /** + * @brief Retires a LibraryProxy in the given layout + * + * A proxy becomes entirely retired if the refcount is equal to the + * retired count. This feature is used to decide whether a proxy + * is actually used or only present as a shadow object for the transaction + * management. + */ + void retire_proxy (db::LibraryProxy *lib_proxy); + + /** + * @brief Unretires the Library proxy + */ + void unretire_proxy (db::LibraryProxy *lib_proxy); + + /** + * @brief Gets a value indicating whether a proxy is entirely retired + */ + bool is_retired (const cell_index_type library_cell_index) const; + /** * @brief Remap the library proxies to a different library * @@ -170,6 +190,11 @@ public: */ void remap_to (db::Library *other); + /** + * @brief This event is fired if proxies get retired on unretired + */ + tl::Event retired_state_changed_event; + private: std::string m_name; std::string m_description; @@ -177,7 +202,7 @@ private: lib_id_type m_id; db::Layout m_layout; std::map m_referrers; - std::map m_refcount; + std::map m_refcount, m_retired_count; // no copying. Library &operator=(const Library &); diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index 85eaf17f7..14de4c14c 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -59,6 +59,12 @@ LibraryProxy::unregister () if (layout ()) { layout ()->unregister_lib_proxy (this); } + if (db::LibraryManager::initialized ()) { + db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id); + if (lib) { + lib->retire_proxy (this); + } + } } void @@ -67,6 +73,12 @@ LibraryProxy::reregister () if (layout ()) { layout ()->register_lib_proxy (this); } + if (db::LibraryManager::initialized ()) { + db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id); + if (lib) { + lib->unretire_proxy (this); + } + } } void diff --git a/src/db/db/dbManager.h b/src/db/db/dbManager.h index 959720a8b..014fb49c4 100644 --- a/src/db/db/dbManager.h +++ b/src/db/db/dbManager.h @@ -262,10 +262,18 @@ class DB_PUBLIC Transaction { public: Transaction (db::Manager *manager, const std::string &desc) - : mp_manager (manager) + : mp_manager (manager), m_transaction_id (0) { if (mp_manager) { - mp_manager->transaction (desc); + m_transaction_id = mp_manager->transaction (desc); + } + } + + Transaction (db::Manager *manager, const std::string &desc, db::Manager::transaction_id_t join_with) + : mp_manager (manager), m_transaction_id (0) + { + if (mp_manager) { + m_transaction_id = mp_manager->transaction (desc, join_with); } } @@ -277,8 +285,14 @@ public: } } + db::Manager::transaction_id_t id () const + { + return m_transaction_id; + } + private: db::Manager *mp_manager; + db::Manager::transaction_id_t m_transaction_id; // no copying. Transaction (const Transaction &); diff --git a/src/db/db/dbPCellDeclaration.cc b/src/db/db/dbPCellDeclaration.cc index cb579aea0..98c67cc24 100644 --- a/src/db/db/dbPCellDeclaration.cc +++ b/src/db/db/dbPCellDeclaration.cc @@ -111,5 +111,22 @@ PCellDeclaration::map_parameters (const std::map ¶ return new_param; } +std::map +PCellDeclaration::named_parameters (const pcell_parameters_type &pv) const +{ + std::map np; + + const std::vector &pcp = parameter_declarations (); + for (std::vector::const_iterator pd = pcp.begin (); pd != pcp.end (); ++pd) { + size_t index = pd - pcp.begin (); + if (index >= pv.size ()) { + break; + } + np.insert (std::make_pair (pd->get_name (), pv [index])); + } + + return np; +} + } diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 403e7bec6..d5ea922ca 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -496,6 +496,11 @@ public: */ pcell_parameters_type map_parameters (const std::map &named_parameters) const; + /** + * @brief Converts a parameter vector to named parameters + */ + std::map named_parameters (const pcell_parameters_type &pv) const; + protected: /** * @brief Gets a value indicating whether the PCell wants caching of the parameter declarations diff --git a/src/edt/edt/PCellParametersDialog.ui b/src/edt/edt/PCellParametersDialog.ui new file mode 100644 index 000000000..ddfe5ab55 --- /dev/null +++ b/src/edt/edt/PCellParametersDialog.ui @@ -0,0 +1,73 @@ + + + PCellParametersDialog + + + + 0 + 0 + 469 + 429 + + + + Instantiation Path + + + + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + edt::PCellParametersPage + QWidget +
edtPCellParametersPage.h
+ 1 +
+
+ + + + buttons + rejected() + PCellParametersDialog + reject() + + + 321 + 405 + + + 337 + 423 + + + + + buttons + accepted() + PCellParametersDialog + accept() + + + 427 + 405 + + + 443 + 425 + + + + +
diff --git a/src/edt/edt/edt.pro b/src/edt/edt/edt.pro index a88af9d5b..f72811940 100644 --- a/src/edt/edt/edt.pro +++ b/src/edt/edt/edt.pro @@ -20,7 +20,8 @@ HEADERS = \ edtService.h \ edtServiceImpl.h \ edtUtils.h \ - edtCommon.h + edtCommon.h \ + edtPCellParametersDialog.h FORMS = \ AlignOptionsDialog.ui \ @@ -41,6 +42,7 @@ FORMS = \ PolygonPropertiesPage.ui \ RoundCornerOptionsDialog.ui \ TextPropertiesPage.ui \ + PCellParametersDialog.ui SOURCES = \ edtConfig.cc \ @@ -57,6 +59,7 @@ SOURCES = \ edtServiceImpl.cc \ edtUtils.cc \ gsiDeclEdt.cc \ + edtPCellParametersDialog.cc INCLUDEPATH += $$TL_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC DEPENDPATH += $$TL_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index c811b78b5..b47af42b7 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -28,6 +28,7 @@ #include "edtEditorOptionsPages.h" #include "edtPCellParametersPage.h" #include "edtConfig.h" +#include "edtService.h" #include "tlExceptions.h" #include "layPlugin.h" #include "layLayoutView.h" @@ -643,15 +644,7 @@ EditorOptionsInst::apply (lay::Plugin *root) if (pc.first) { const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pc.second); if (pc_decl) { - param += "!"; // flags PCells - std::vector pv = mp_pcell_parameters->get_parameters (); - const std::vector &pcp = pc_decl->parameter_declarations (); - for (size_t i = 0; i < std::min (pv.size (), pcp.size ()); ++i) { - param += tl::to_word_or_quoted_string (pcp [i].get_name ()); - param += ":"; - param += pv [i].to_parsable_string (); - param += ";"; - } + param = pcell_parameters_to_string (pc_decl->named_parameters (mp_pcell_parameters->get_parameters ())); } } } diff --git a/src/edt/edt/edtPCellParametersDialog.cc b/src/edt/edt/edtPCellParametersDialog.cc new file mode 100644 index 000000000..0b74ab42e --- /dev/null +++ b/src/edt/edt/edtPCellParametersDialog.cc @@ -0,0 +1,65 @@ + +/* + + 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 "edtPCellParametersDialog.h" + +#include + +namespace edt +{ + +PCellParametersDialog::PCellParametersDialog (QWidget *parent) + : QDialog (parent) +{ + setupUi (this); + + connect (buttons->button (QDialogButtonBox::Apply), SIGNAL (clicked ()), this, SLOT (apply_pressed ())); +} + +void +PCellParametersDialog::apply_pressed () +{ + emit parameters_changed (); + parameters_changed_event (); +} + +std::vector +PCellParametersDialog::get_parameters () +{ + return parameters->get_parameters (); +} + +void +PCellParametersDialog::set_parameters (const std::vector &p) +{ + parameters->set_parameters (p); +} + +int +PCellParametersDialog::exec (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &p) +{ + parameters->setup (layout, view, cv_index, pcell_decl, p); + return QDialog::exec (); +} + +} diff --git a/src/edt/edt/edtPCellParametersDialog.h b/src/edt/edt/edtPCellParametersDialog.h new file mode 100644 index 000000000..58c162cbb --- /dev/null +++ b/src/edt/edt/edtPCellParametersDialog.h @@ -0,0 +1,86 @@ + +/* + + 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_edtPCellParametersDialog +#define HDR_edtPCellParametersDialog + +#include "dbPCellDeclaration.h" +#include "ui_PCellParametersDialog.h" + +#include + +namespace lay +{ + class LayoutView; +} + +namespace edt +{ + +/** + * @brief A QScrollArea that displays and allows editing PCell parameters + */ +class PCellParametersDialog + : public QDialog, private Ui::PCellParametersDialog +{ +Q_OBJECT + +public: + /** + * @brief Constructor: create a dialog showing the given parameters + * @param parent The parent widget + */ + PCellParametersDialog (QWidget *parent); + + /** + * @brief Executes the parameter dialog + * @param layout The layout in which the PCell instance resides + * @param view The layout view from which to take layers for example + * @param cv_index The index of the cellview in "view" + * @param pcell_decl The PCell declaration + * @param parameters The parameter values to show (if empty, the default values are used) + */ + int exec (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &p); + + /** + * @brief Get the current parameters + */ + std::vector get_parameters (); + + /** + * @brief Sets the given parameters as values + */ + void set_parameters (const std::vector &values); + + tl::Event parameters_changed_event; + +signals: + void parameters_changed (); + +private slots: + void apply_pressed (); +}; + +} + +#endif diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index a851e3508..6c00105e4 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -129,15 +129,30 @@ static void set_value (const db::PCellParameterDeclaration &p, const db::Layout } PCellParametersPage::PCellParametersPage (QWidget *parent, const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) - : QFrame (parent), mp_pcell_decl (pcell_decl), mp_layout (layout), mp_view (view), m_cv_index (cv_index) + : QFrame (parent) { + init (); + setup (layout, view, cv_index, pcell_decl, parameters); +} + +PCellParametersPage::PCellParametersPage (QWidget *parent) + : QFrame (parent) +{ + init (); +} + +void +PCellParametersPage::init () +{ + mp_pcell_decl = 0; + mp_layout = 0; + mp_view = 0; + m_cv_index = 0; + mp_parameters_area = 0; + QGridLayout *frame_layout = new QGridLayout (this); setLayout (frame_layout); - mp_parameters_area = new QScrollArea (this); - frame_layout->addWidget (mp_parameters_area, 0, 0, 1, 2); - frame_layout->setRowStretch (0, 1); - mp_error_icon = new QLabel (this); mp_error_icon->setPixmap (QPixmap (":/warn.png")); mp_error_icon->hide (); @@ -153,9 +168,28 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, const db::Layout *lay mp_error_label->hide (); frame_layout->addWidget (mp_error_label, 1, 1, 1, 1); frame_layout->setColumnStretch (1, 1); +} +void +PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) +{ + mp_pcell_decl = pcell_decl; + mp_layout = layout; + mp_view = view; + m_cv_index = cv_index; m_parameters = parameters; + if (mp_parameters_area) { + delete mp_parameters_area; + } + + m_widgets.clear (); + + mp_parameters_area = new QScrollArea (this); + QGridLayout *frame_layout = dynamic_cast (QFrame::layout ()); + frame_layout->addWidget (mp_parameters_area, 0, 0, 1, 2); + frame_layout->setRowStretch (0, 1); + QFrame *fi = new QFrame (mp_parameters_area); QWidget *inner_frame = fi; fi->setFrameShape (QFrame::NoFrame); diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 5da75cfbf..020dda3b0 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -57,7 +57,7 @@ public: }; /** - * @brief Constructor: create a page showing the given parameters + * @brief Constructor: creates a page showing the given parameters * * @param parent The parent widget * @param layout The layout in which the PCell instance resides @@ -68,6 +68,20 @@ public: */ PCellParametersPage (QWidget *parent, const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters); + /** + * @brief Default constructor + * + * Use "setup" to configure the page. + */ + PCellParametersPage (QWidget *parent); + + /** + * @brief Delayed initialization + * + * Use this method to setup when the arguments are not available in the constructor + */ + void setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters); + /** * @brief Gets the pages current state */ @@ -110,6 +124,8 @@ private: lay::LayoutView *mp_view; int m_cv_index; db::pcell_parameters_type m_parameters; + + void init (); }; } diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index cc1f85f55..5fc6c5062 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -60,6 +60,45 @@ ac_from_buttons (unsigned int buttons) // ------------------------------------------------------------- +std::string pcell_parameters_to_string (const std::map ¶meters) +{ + std::string param; + + param = "!"; // flags PCells + for (std::map::const_iterator p = parameters.begin (); p != parameters.end (); ++p) { + param += tl::to_word_or_quoted_string (p->first); + param += ":"; + param += p->second.to_parsable_string (); + param += ";"; + } + + return param; +} + +std::map pcell_parameters_from_string (const std::string &s) +{ + tl::Extractor ex (s.c_str ()); + std::map pm; + + ex.test ("!"); + + try { + while (! ex.at_end ()) { + std::string n; + ex.read_word_or_quoted (n); + ex.test (":"); + ex.read (pm.insert (std::make_pair (n, tl::Variant ())).first->second); + ex.test (";"); + } + } catch (...) { + // ignore errors + } + + return pm; +} + +// ------------------------------------------------------------- + Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator::flags_type flags) : lay::ViewService (view->view_object_widget ()), lay::Editable (view), diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index dbb27a822..68486cc38 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -57,6 +57,18 @@ extern lay::angle_constraint_type ac_from_buttons (unsigned int buttons); // ------------------------------------------------------------- +/** + * @brief Utility function: serialize PCell parameters into a string + */ +std::string pcell_parameters_to_string (const std::map ¶meters); + +/** + * @brief Utility: deserialize PCell parameters from a string + */ +std::map pcell_parameters_from_string (const std::string &s); + +// ------------------------------------------------------------- + class EDT_PUBLIC Service : public lay::ViewService, public lay::Editable, diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index f79498020..4769ea96c 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -25,6 +25,8 @@ #include "edtServiceImpl.h" #include "edtPropertiesPages.h" #include "edtInstPropertiesPage.h" +#include "edtPCellParametersDialog.h" +#include "edtService.h" #include "dbEdge.h" #include "dbLibrary.h" #include "dbLibraryManager.h" @@ -1112,7 +1114,7 @@ InstService::InstService (db::Manager *manager, lay::LayoutView *view) m_row_x (0.0), m_row_y (0.0), m_column_x (0.0), m_column_y (0.0), m_place_origin (false), m_reference_transaction_id (0), m_needs_update (true), m_has_valid_cell (false), m_in_drag_drop (false), - m_current_cell (0), m_cv_index (-1) + m_current_cell (0), mp_current_layout (0), mp_pcell_decl (0), m_cv_index (-1) { // .. nothing yet .. } @@ -1166,13 +1168,14 @@ InstService::drag_enter_event (const db::DPoint &p, const lay::DragDropDataBase m_in_drag_drop = true; if (cd->library ()) { - m_lib_name = cd->library ()->get_name (); + if (m_lib_name != cd->library ()->get_name ()) { + m_lib_name = cd->library ()->get_name (); + m_pcell_parameters.clear (); + } } else { m_lib_name.clear (); } - m_pcell_parameters.clear (); - m_cell_or_pcell_name.clear (); m_is_pcell = false; if (cd->is_pcell ()) { @@ -1180,12 +1183,17 @@ InstService::drag_enter_event (const db::DPoint &p, const lay::DragDropDataBase const db::PCellDeclaration *pcell_decl = cd->layout ()->pcell_declaration (cd->cell_index ()); if (pcell_decl) { - m_cell_or_pcell_name = pcell_decl->name (); + if (m_cell_or_pcell_name != pcell_decl->name ()) { + m_cell_or_pcell_name = pcell_decl->name (); + m_pcell_parameters.clear (); + } + m_is_pcell = true; + // NOTE: we reuse previous parameters for convenience unless PCell or library has changed const std::vector &pd = pcell_decl->parameter_declarations(); for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { - if (i->get_type () == db::PCellParameterDeclaration::t_layer && i->get_default ().is_nil ()) { + if (i->get_type () == db::PCellParameterDeclaration::t_layer && !i->is_hidden () && !i->is_readonly () && i->get_default ().is_nil ()) { m_pcell_parameters.insert (std::make_pair (i->get_name (), get_default_layer_for_pcell ())); } else { m_pcell_parameters.insert (std::make_pair (i->get_name (), i->get_default ())); @@ -1240,9 +1248,59 @@ bool InstService::drop_event (const db::DPoint & /*p*/, const lay::DragDropDataBase * /*data*/) { if (m_in_drag_drop) { + + const lay::CellView &cv = view ()->cellview (m_cv_index); + if (! cv.is_valid ()) { + return false; + } + + make_cell (cv); + + bool accepted = true; + + if (m_has_valid_cell && mp_pcell_decl) { + + std::vector pv = mp_pcell_decl->map_parameters (m_pcell_parameters); + + // Turn off the drag cursor for the modal dialog + QApplication::restoreOverrideCursor (); + + // for PCells dragged show the parameter dialog for a chance to edit the initial parameters + if (! mp_pcell_parameters_dialog.get ()) { + mp_pcell_parameters_dialog.reset (new edt::PCellParametersDialog (view ())); + mp_pcell_parameters_dialog->parameters_changed_event.add (this, &InstService::apply_edits); + } + + if (! mp_pcell_parameters_dialog->exec (mp_current_layout, view (), m_cv_index, mp_pcell_decl, pv)) { + accepted = false; + } else { + m_has_valid_cell = false; + m_pcell_parameters = mp_pcell_decl->named_parameters (mp_pcell_parameters_dialog->get_parameters ()); + } + + } + set_edit_marker (0); - do_finish_edit (); + + if (accepted) { + do_finish_edit (); + } else { + do_cancel_edit (); + } + + // push the current setup to configuration so the instance dialog will take these as default + // and "apply" of these instance properties doesn't fail because of insistency. + plugin_root ()->config_set (cfg_edit_inst_lib_name, m_lib_name); + plugin_root ()->config_set (cfg_edit_inst_cell_name, m_cell_or_pcell_name); + if (m_is_pcell) { + plugin_root ()->config_set (cfg_edit_inst_pcell_parameters, pcell_parameters_to_string (m_pcell_parameters)); + } else { + plugin_root ()->config_set (cfg_edit_inst_pcell_parameters, std::string ()); + } + plugin_root ()->config_end (); + return true; + } else { return false; } @@ -1307,80 +1365,75 @@ InstService::make_cell (const lay::CellView &cv) return std::make_pair (true, m_current_cell); } + // NOTE: do this at the beginning: creating a transaction might delete transactions behind the + // head transaction, hence releasing (thus: deleting) cells. To prevert interference, create + // the transaction at the beginning. + db::Transaction tr (manager (), tl::to_string (QObject::tr ("Create reference cell")), m_reference_transaction_id); + m_reference_transaction_id = tr.id (); + lay::LayerState layer_state = view ()->layer_snapshot (); - db::Layout *layout; db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected if (lib) { - layout = &lib->layout (); + mp_current_layout = &lib->layout (); } else { - layout = &cv->layout (); + mp_current_layout = &cv->layout (); } std::pair ci (false, db::cell_index_type (0)); std::pair pci (false, db::pcell_id_type (0)); if (! m_is_pcell) { - ci = layout->cell_by_name (m_cell_or_pcell_name.c_str ()); + ci = mp_current_layout->cell_by_name (m_cell_or_pcell_name.c_str ()); } else { - pci = layout->pcell_by_name (m_cell_or_pcell_name.c_str ()); + pci = mp_current_layout->pcell_by_name (m_cell_or_pcell_name.c_str ()); } if (! ci.first && ! pci.first) { return std::pair (false, 0); } - m_reference_transaction_id = manager ()->transaction (tl::to_string (QObject::tr ("Create reference cell")), m_reference_transaction_id); db::cell_index_type inst_cell_index = ci.second; - try { + mp_pcell_decl = 0; - // instantiate the PCell - if (pci.first) { + // instantiate the PCell + if (pci.first) { - std::vector pv; + std::vector pv; - const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pci.second); - if (pc_decl) { + mp_pcell_decl = mp_current_layout->pcell_declaration (pci.second); + if (mp_pcell_decl) { - const std::vector &pcp = pc_decl->parameter_declarations (); - for (std::vector::const_iterator pd = pcp.begin (); pd != pcp.end (); ++pd) { - std::map::const_iterator p = m_pcell_parameters.find (pd->get_name ()); - if (p != m_pcell_parameters.end ()) { - pv.push_back (p->second); - } else { - pv.push_back (pd->get_default ()); - } - } + pv = mp_pcell_decl->map_parameters (m_pcell_parameters); - // make the parameters fit (i.e. PCells may not define consistent default parameters) - pc_decl->coerce_parameters (*layout, pv); - - } - - inst_cell_index = layout->get_pcell_variant (pci.second, pv); + // make the parameters fit (i.e. PCells may not define consistent default parameters) + mp_pcell_decl->coerce_parameters (*mp_current_layout, pv); } - // reference the library - if (lib) { - layout = & cv->layout (); - layout->cleanup (); - inst_cell_index = layout->get_lib_proxy (lib, inst_cell_index); - } + inst_cell_index = mp_current_layout->get_pcell_variant (pci.second, pv); - view ()->add_new_layers (layer_state); - - manager ()->commit (); - - } catch (...) { - manager ()->commit (); - throw; } + // reference the library + if (lib) { + + mp_current_layout = & cv->layout (); + inst_cell_index = mp_current_layout->get_lib_proxy (lib, inst_cell_index); + + // remove unused references + std::set keep; + keep.insert (inst_cell_index); + mp_current_layout->cleanup (keep); + + } + + view ()->add_new_layers (layer_state); + m_has_valid_cell = true; m_current_cell = inst_cell_index; @@ -1487,11 +1540,6 @@ InstService::do_finish_edit () m_has_valid_cell = false; m_in_drag_drop = false; - // on a preconfigured PCell offer to edit the properties now - if (m_is_pcell) { - view ()->show_properties (QApplication::activeWindow ()); - } - } catch (...) { m_has_valid_cell = false; m_in_drag_drop = false; @@ -1535,22 +1583,8 @@ InstService::configure (const std::string &name, const std::string &value) if (name == cfg_edit_inst_pcell_parameters) { - tl::Extractor ex (value.c_str ()); - - m_pcell_parameters.clear (); - m_is_pcell = ex.test ("!") || ! ex.at_end (); - - try { - while (! ex.at_end ()) { - std::string n; - ex.read_word_or_quoted (n); - ex.test (":"); - ex.read (m_pcell_parameters.insert (std::make_pair (n, tl::Variant ())).first->second); - ex.test (";"); - } - } catch (...) { - // ignore errors - } + m_pcell_parameters = pcell_parameters_from_string (value); + m_is_pcell = ! value.empty (); m_needs_update = true; return true; // taken @@ -1638,6 +1672,17 @@ InstService::config_finalize () edt::Service::config_finalize (); } +void +InstService::apply_edits() +{ + if (mp_pcell_decl && mp_pcell_parameters_dialog.get ()) { + m_pcell_parameters = mp_pcell_decl->named_parameters (mp_pcell_parameters_dialog->get_parameters ()); + } + + m_has_valid_cell = false; + update_marker (); +} + void InstService::update_marker () { diff --git a/src/edt/edt/edtServiceImpl.h b/src/edt/edt/edtServiceImpl.h index 348410fcc..024974fea 100644 --- a/src/edt/edt/edtServiceImpl.h +++ b/src/edt/edt/edtServiceImpl.h @@ -27,6 +27,8 @@ #include "edtService.h" #include "edtConfig.h" +#include + namespace lay { class CellView; @@ -35,6 +37,8 @@ namespace lay namespace edt { +class PCellParametersDialog; + /** * @brief Implementation of the edt::Service for generic shape editing */ @@ -235,10 +239,14 @@ private: bool m_has_valid_cell; bool m_in_drag_drop; db::cell_index_type m_current_cell; + db::Layout *mp_current_layout; + const db::PCellDeclaration *mp_pcell_decl; int m_cv_index; db::ICplxTrans m_trans; + std::auto_ptr mp_pcell_parameters_dialog; void update_marker (); + void apply_edits (); bool get_inst (db::CellInstArray &inst); std::pair make_cell (const lay::CellView &cv); tl::Variant get_default_layer_for_pcell (); diff --git a/src/laybasic/laybasic/layCellTreeModel.cc b/src/laybasic/laybasic/layCellTreeModel.cc index 3f351af9b..819dba8a8 100644 --- a/src/laybasic/laybasic/layCellTreeModel.cc +++ b/src/laybasic/laybasic/layCellTreeModel.cc @@ -26,6 +26,7 @@ #include "tlGlobPattern.h" #include "dbPCellHeader.h" #include "dbPCellVariant.h" +#include "dbLibraryProxy.h" #include "dbLibrary.h" #include @@ -559,7 +560,12 @@ CellTreeModel::build_top_level () 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) { - item->add_child (new CellTreeItem (mp_layout, false, v->second->cell_index (), true, m_sorting)); + 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 (); diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index 4b8602927..753483840 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -716,6 +716,7 @@ LibrariesView::do_update_content (int lib_index) 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) {