From 879059f8306d8d6546b7dd4bf43536b88907d7cd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 26 Oct 2022 21:28:10 +0200 Subject: [PATCH 01/29] Package manager: show details only when enabling the 'show details' button --- src/lay/lay/SaltManagerDialog.ui | 130 +++++++++++++++++-- src/lay/lay/laySaltGrainDetailsTextWidget.cc | 64 +++++---- src/lay/lay/laySaltGrainDetailsTextWidget.h | 4 + 3 files changed, 161 insertions(+), 37 deletions(-) diff --git a/src/lay/lay/SaltManagerDialog.ui b/src/lay/lay/SaltManagerDialog.ui index de9b8baa4..18a5f2ea2 100644 --- a/src/lay/lay/SaltManagerDialog.ui +++ b/src/lay/lay/SaltManagerDialog.ui @@ -17,7 +17,7 @@ - 0 + 2 @@ -217,6 +217,12 @@ + + + 1 + 0 + + true @@ -227,6 +233,19 @@ + + + + + 0 + 0 + + + + More details + + + @@ -515,6 +534,12 @@ + + + 1 + 0 + + true @@ -525,6 +550,13 @@ + + + + More details + + + @@ -935,8 +967,21 @@ 0 + + + + true + + + + + + 1 + 0 + + true @@ -947,7 +992,7 @@ - + Edit Package Details @@ -964,10 +1009,10 @@ - - - - true + + + + More details @@ -1157,20 +1202,33 @@ lay::SaltGrainDetailsTextWidget QTextBrowser
laySaltGrainDetailsTextWidget.h
+ + show_detailed_view(bool) + mode_tab + mark_new_button + search_new_edit + salt_mine_view_new + detailed_view + toolButton + details_new_text + mark_update_button + search_update_edit + salt_mine_view_update + detailed_view2 + toolButton_2 + details_update_text search_installed_edit salt_view - details_text + detailed_view3 edit_button - search_new_edit - mark_new_button - salt_mine_view_new - details_new_text - toolButton + details_text + create_button apply_new_button + apply_update_button scrollArea @@ -1193,5 +1251,53 @@ + + detailed_view + clicked(bool) + details_new_text + show_detailed_view(bool) + + + 588 + 57 + + + 578 + 121 + + + + + detailed_view2 + clicked(bool) + details_update_text + show_detailed_view(bool) + + + 616 + 58 + + + 615 + 96 + + + + + detailed_view3 + clicked(bool) + details_text + show_detailed_view(bool) + + + 602 + 58 + + + 603 + 91 + + + diff --git a/src/lay/lay/laySaltGrainDetailsTextWidget.cc b/src/lay/lay/laySaltGrainDetailsTextWidget.cc index 3bbda18a2..e09b80e82 100644 --- a/src/lay/lay/laySaltGrainDetailsTextWidget.cc +++ b/src/lay/lay/laySaltGrainDetailsTextWidget.cc @@ -36,14 +36,15 @@ namespace lay { SaltGrainDetailsTextWidget::SaltGrainDetailsTextWidget (QWidget *w) - : QTextBrowser (w), mp_grain () + : QTextBrowser (w), mp_grain (), m_detailed_view (false) { setOpenLinks (false); setOpenExternalLinks (false); connect (this, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (open_link (const QUrl &))); } -void SaltGrainDetailsTextWidget::set_grain (const SaltGrain *g) +void +SaltGrainDetailsTextWidget::set_grain (const SaltGrain *g) { if (g) { mp_grain.reset (new SaltGrain (*g)); @@ -53,6 +54,15 @@ void SaltGrainDetailsTextWidget::set_grain (const SaltGrain *g) setHtml (details_text ()); } +void +SaltGrainDetailsTextWidget::show_detailed_view (bool f) +{ + if (m_detailed_view != f) { + m_detailed_view = f; + setHtml (details_text ()); + } +} + void SaltGrainDetailsTextWidget::open_link (const QUrl &url) { @@ -276,32 +286,36 @@ SaltGrainDetailsTextWidget::details_text () stream << "

" << QObject::tr ("Screenshot") << "

"; } - stream << "
"; - stream << "

" << QObject::tr ("Installation") << "

"; + if (m_detailed_view) { - if (! g->url ().empty ()) { - stream << "

" << QObject::tr ("Download URL: ") << "" << tl::to_qstring (tl::escaped_to_html (g->url ())) << "

"; - } - if (! g->path ().empty () && ! g->installed_time ().isNull ()) { - stream << "

" << QObject::tr ("Installed: ") << "" << g->installed_time ().toString () << "

"; - } - if (! g->dependencies ().empty ()) { - stream << "

" << QObject::tr ("Depends on: ") << "
"; - for (std::vector::const_iterator d = g->dependencies ().begin (); d != g->dependencies ().end (); ++d) { - stream << "    " << tl::to_qstring (tl::escaped_to_html (d->name)) << " "; - stream << tl::to_qstring (tl::escaped_to_html (d->version)); - if (! d->url.empty ()) { - stream << " - "; - stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
"; - } + stream << "
"; + stream << "

" << QObject::tr ("Installation") << "

"; + + if (! g->url ().empty ()) { + stream << "

" << QObject::tr ("Download URL: ") << "" << tl::to_qstring (tl::escaped_to_html (g->url ())) << "

"; + } + if (! g->path ().empty () && ! g->installed_time ().isNull ()) { + stream << "

" << QObject::tr ("Installed: ") << "" << g->installed_time ().toString () << "

"; + } + if (! g->dependencies ().empty ()) { + stream << "

" << QObject::tr ("Depends on: ") << "
"; + for (std::vector::const_iterator d = g->dependencies ().begin (); d != g->dependencies ().end (); ++d) { + stream << "    " << tl::to_qstring (tl::escaped_to_html (d->name)) << " "; + stream << tl::to_qstring (tl::escaped_to_html (d->version)); + if (! d->url.empty ()) { + stream << " - "; + stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
"; + } + } + stream << "

"; + } + + if (! g->path ().empty ()) { + stream << "

" << QObject::tr ("Installed files: ") << "

"; + produce_listing (stream, QDir (tl::to_qstring (g->path ())), 0); + stream << "

"; } - stream << "

"; - } - if (! g->path ().empty ()) { - stream << "

" << QObject::tr ("Installed files: ") << "

"; - produce_listing (stream, QDir (tl::to_qstring (g->path ())), 0); - stream << "

"; } stream << ""; diff --git a/src/lay/lay/laySaltGrainDetailsTextWidget.h b/src/lay/lay/laySaltGrainDetailsTextWidget.h index 1e0221235..47dc485ed 100644 --- a/src/lay/lay/laySaltGrainDetailsTextWidget.h +++ b/src/lay/lay/laySaltGrainDetailsTextWidget.h @@ -55,6 +55,9 @@ public: protected: virtual QVariant loadResource (int type, const QUrl &url); +public slots: + void show_detailed_view (bool f); + private slots: void open_link (const QUrl &url); @@ -62,6 +65,7 @@ private: std::unique_ptr mp_grain; QString details_text (); + bool m_detailed_view; }; } From e6da3fc22c0ece2d57e0df01e25d1383420f7f78 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 27 Oct 2022 00:42:28 +0200 Subject: [PATCH 02/29] WIP: callbacks for PCells --- src/db/db/dbPCellDeclaration.h | 189 ++++++++++- src/db/db/gsiDeclDbLibrary.cc | 8 +- src/edt/edt/edtPCellParametersPage.cc | 438 +++++++++++++++++--------- src/edt/edt/edtPCellParametersPage.h | 11 +- 4 files changed, 498 insertions(+), 148 deletions(-) diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 808a75fe2..aaecb02df 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -61,6 +61,7 @@ public: t_layer, // a layer (value is a db::LayerProperties object) t_shape, // a shape (a db::Point, db::Box, db::Polygon, db::Edge or db::Path) rendering a guiding shape t_list, // a list of strings + t_callback, // callback only (button) t_none // no specific type }; @@ -323,6 +324,174 @@ public: std::string symbolic; }; +/** + * @brief Represents the dynamic state of a single parameter + */ +class DB_PUBLIC ParameterState +{ +public: + /** + * @brief Parameterized constructor + */ + ParameterState () + : m_value (), m_visible (true), m_enabled (true), + m_value_changed (false), m_visible_changed (false), m_enabled_changed (false) + { + // .. nothing yet .. + } + + /** + * @brief Gets the value + */ + const tl::Variant &value () const + { + return m_value; + } + + /** + * @brief Sets the value + */ + void set_value (const tl::Variant &v) + { + if (m_value != v) { + m_value = v; + m_value_changed = true; + } + } + + /** + * @brief Gets a value indicating wheter the value has changed + */ + bool value_changed () const + { + return m_value_changed; + } + + /** + * @brief Gets the visibility state + */ + bool is_visible () const + { + return m_visible; + } + + /** + * @brief Sets the visibility + */ + void set_visible (bool v) + { + if (m_visible != v) { + m_visible = v; + m_visible_changed = true; + } + } + + /** + * @brief Gets a value indicating wheter the visibility has changed + */ + bool visible_changed () const + { + return m_visible_changed; + } + + /** + * @brief Gets the enabled state + */ + bool is_enabled () const + { + return m_enabled; + } + + /** + * @brief Sets the enabled state + */ + void set_enabled (bool v) + { + if (m_enabled != v) { + m_enabled = v; + m_enabled_changed = true; + } + } + + /** + * @brief Gets a value indicating wheter the enabled state has changed + */ + bool enabled_changed () const + { + return m_enabled_changed; + } + + /** + * @brief Resets the modified flags + */ + void reset () + { + m_enabled_changed = m_visible_changed = m_value_changed = false; + } + +private: + tl::Variant m_value; + bool m_visible, m_enabled; + bool m_value_changed, m_visible_changed, m_enabled_changed; +}; + +/** + * @brief Represents the state of call parameters for the callback implementation + */ +class DB_PUBLIC ParameterStates +{ +public: + /** + * @brief Default constructor + */ + ParameterStates () + : m_states () + { + // .. nothing yet .. + } + + /** + * @brief Sets a parameter from a given state + */ + void set_parameter (const std::string &name, const ParameterState &ps) + { + m_states [name] = ps; + } + + /** + * @brief Gets the parameter state for the parameter with the given name + * + * If the name is not a valid parameter name, the behavior is undefined. + */ + ParameterState ¶meter (const std::string &name) + { + return m_states [name]; + } + + /** + * @brief Gets the parameter state for the parameter with the given name + * + * If the name is not a valid parameter name, the behavior is undefined. + */ + const ParameterState ¶meter (const std::string &name) const + { + return const_cast (this)->parameter (name); + } + + /** + * @brief Resets the modified flags + */ + void reset () + { + for (auto p = m_states.begin (); p != m_states.end (); ++p) { + p->second.reset (); + } + } + +public: + std::map m_states; +}; + /** * @brief A declaration for a PCell */ @@ -374,7 +543,25 @@ public: } /** - * @brief Produce a layout for the given parameter set and using the given layers. + * @brief Callback on parameter change + * + * This method allows implementing dynamic behavior on the change of a parameter value. + * A ParameterStatus object is supplied that allows changing parameter enabled status, visibility and value. + * The callback also acts as receiver for t_callback type parameters which only present a button. + * + * The callback function receives the name of the parameter that was changed. + * On some occasions, the callback is called unspecifically, for example for the initialization. + * In that case, the parameter name is empty. + * + * Exceptions from this implementation are ignored. + */ + virtual void callback (const db::Layout & /*layout*/, const std::string & /*name*/, ParameterStates & /*states*/) const + { + // the default implementation does nothing + } + + /** + * @brief Produces a layout for the given parameter set and using the given layers. * * A reimplementation of that method should produce the desired layout for the given parameter set. * The layout shall be put into the given cell. This code may create cell instances to other cells diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index d6537599f..dd306f0cb 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -634,6 +634,11 @@ static unsigned int pd_type_list () return (unsigned int) db::PCellParameterDeclaration::t_list; } +static unsigned int pd_type_callback () +{ + return (unsigned int) db::PCellParameterDeclaration::t_callback; +} + static unsigned int pd_type_none () { return (unsigned int) db::PCellParameterDeclaration::t_none; @@ -763,7 +768,8 @@ Class decl_PCellParameterDeclaration ("db", "PCel gsi::method ("TypeList", &pd_type_list, "@brief Type code: a list of variants") + gsi::method ("TypeLayer", &pd_type_layer, "@brief Type code: a layer (a \\LayerInfo object)") + gsi::method ("TypeShape", &pd_type_shape, "@brief Type code: a guiding shape (Box, Edge, Point, Polygon or Path)") + - gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type") + gsi::method ("TypeCallback", &pd_type_callback, "@brief Type code: a button triggering a callback") + + gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type") , "@brief A PCell parameter declaration\n" "\n" diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index ed28773cf..426c2becf 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -238,13 +238,15 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P mp_pcell_decl.reset (const_cast (pcell_decl)); // no const weak_ptr ... mp_view = view; m_cv_index = cv_index; - m_parameters = parameters; + m_states = db::ParameterStates (); + m_initial_parameters.clear (); if (mp_parameters_area) { delete mp_parameters_area; } m_widgets.clear (); + m_all_widgets.clear (); mp_parameters_area = new QScrollArea (this); mp_parameters_area->setFrameShape (QFrame::NoFrame); @@ -276,7 +278,23 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P const std::vector &pcp = pcell_decl->parameter_declarations (); for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + tl::Variant value; + if (r < int (parameters.size ())) { + value = parameters [r]; + } else { + value = p->get_default (); + } + + m_initial_parameters.push_back (value); + + db::ParameterState &ps = m_states.parameter (p->get_name ()); + ps.set_value (value); + ps.set_enabled (! p->is_readonly ()); + ps.set_visible (! p->is_hidden ()); + + m_all_widgets.push_back (std::vector ()); + + if (p->get_type () == db::PCellParameterDeclaration::t_shape) { m_widgets.push_back (0); continue; } @@ -324,13 +342,10 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P } - inner_grid->addWidget (new QLabel (tl::to_qstring (description), inner_frame), row, 0); - - tl::Variant value; - if (r < int (parameters.size ())) { - value = parameters [r]; - } else { - value = p->get_default (); + if (p->get_type () != db::PCellParameterDeclaration::t_callback) { + QLabel *l = new QLabel (tl::to_qstring (description), inner_frame); + inner_grid->addWidget (l, row, 0); + m_all_widgets.back ().push_back (l); } if (p->get_choices ().empty ()) { @@ -347,7 +362,6 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P f->setFrameShape (QFrame::NoFrame); QLineEdit *le = new QLineEdit (f); - le->setEnabled (! p->is_readonly ()); hb->addWidget (le); le->setMaximumWidth (150); le->setObjectName (tl::to_qstring (p->get_name ())); @@ -358,20 +372,36 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P ul->setText (tl::to_qstring (p->get_unit ())); inner_grid->addWidget (f, row, 1); + m_all_widgets.back ().push_back (f); connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ())); } break; + case db::PCellParameterDeclaration::t_callback: + { + QPushButton *pb = new QPushButton (inner_frame); + pb->setObjectName (tl::to_qstring (p->get_name ())); + pb->setText (tl::to_qstring (description)); + pb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred); + m_widgets.push_back (pb); + + inner_grid->addWidget (pb, row, 1); + m_all_widgets.back ().push_back (pb); + + connect (pb, SIGNAL (clicked ()), this, SLOT (parameter_changed ())); + } + break; + case db::PCellParameterDeclaration::t_string: case db::PCellParameterDeclaration::t_shape: case db::PCellParameterDeclaration::t_list: { QLineEdit *le = new QLineEdit (inner_frame); - le->setEnabled (! p->is_readonly ()); le->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (le); inner_grid->addWidget (le, row, 1); + m_all_widgets.back ().push_back (le); connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ())); } @@ -380,12 +410,12 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P case db::PCellParameterDeclaration::t_layer: { lay::LayerSelectionComboBox *ly = new lay::LayerSelectionComboBox (inner_frame); - ly->setEnabled (! p->is_readonly ()); ly->set_no_layer_available (true); ly->set_view (mp_view, m_cv_index, true /*all layers*/); ly->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (ly); inner_grid->addWidget (ly, row, 1); + m_all_widgets.back ().push_back (ly); connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); } @@ -396,10 +426,10 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P QCheckBox *cbx = new QCheckBox (inner_frame); // this makes the checkbox not stretch over the full width - better when navigating with tab cbx->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred)); - cbx->setEnabled (! p->is_readonly ()); cbx->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (cbx); inner_grid->addWidget (cbx, row, 1); + m_all_widgets.back ().push_back (cbx); connect (cbx, SIGNAL (stateChanged (int)), this, SLOT (parameter_changed ())); } @@ -426,16 +456,14 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P connect (cb, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); - cb->setEnabled (! p->is_readonly ()); cb->setMinimumContentsLength (30); cb->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon); m_widgets.push_back (cb); inner_grid->addWidget (cb, row, 1); + m_all_widgets.back ().push_back (cb); } - set_value (*p, m_widgets.back (), value); - ++row; if (inner_frame == main_frame) { ++main_row; @@ -443,12 +471,64 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P } + // initial callback + + try { + mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), std::string (), m_states); + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + + update_widgets_from_states (m_states); + m_states.reset (); + mp_parameters_area->setWidget (main_frame); main_frame->show (); update_current_parameters (); } +void +PCellParametersPage::update_widgets_from_states (const db::ParameterStates &states) +{ + if (! mp_pcell_decl) { + return; + } + + bool update_needed = false; + + size_t i = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++i) { + + const std::string &name = p->get_name (); + const db::ParameterState &ps = states.parameter (name); + + if (ps.value_changed ()) { + update_needed = true; + set_value (*p, m_widgets [i], ps.value ()); + } + + if (ps.enabled_changed ()) { + m_widgets [i]->setEnabled (ps.is_enabled ()); + } + + if (ps.visible_changed ()) { + for (auto w = m_all_widgets [i].begin (); w != m_all_widgets [i].end (); ++w) { + (*w)->setVisible (ps.is_enabled ()); + } + } + + } + + mp_update_frame->setVisible (update_needed); +} + PCellParametersPage::State PCellParametersPage::get_state () { @@ -483,9 +563,51 @@ PCellParametersPage::set_state (const State &s) } } -void +void PCellParametersPage::parameter_changed () { + if (! mp_pcell_decl) { + return; + } + if (! mp_view->cellview (m_cv_index).is_valid ()) { + return; + } + + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + const db::PCellParameterDeclaration *pd = 0; + for (auto w = m_widgets.begin (); w != m_widgets.end (); ++w) { + if (*w == sender ()) { + pd = &pcp [w - m_widgets.begin ()]; + break; + } + } + + try { + + db::ParameterStates states = m_states; + states.reset (); + + bool edit_error = false; + get_parameters_internal (states, edit_error); + if (! edit_error) { + + mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), pd ? pd->get_name () : std::string (), states); + + update_widgets_from_states (states); + states.reset (); + m_states = states; + + } + + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + dm_parameter_changed (); } @@ -493,9 +615,10 @@ void PCellParametersPage::do_parameter_changed () { // does a coerce and update - bool ok = false; - std::vector parameters = get_parameters (&ok); - if (ok && ! lazy_evaluation ()) { + bool edit_error = false; + db::ParameterStates states = m_states; + get_parameters_internal (states, edit_error); + if (! edit_error && ! lazy_evaluation ()) { emit edited (); } } @@ -521,6 +644,125 @@ PCellParametersPage::update_current_parameters () return ok; } +void +PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool &edit_error) +{ + edit_error = true; + + int r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + + db::ParameterState &ps = states.parameter (p->get_name ()); + + if (! ps.is_visible () || ! ps.is_enabled () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + continue; + } + + if (p->get_choices ().empty ()) { + + switch (p->get_type ()) { + + case db::PCellParameterDeclaration::t_int: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + int v = 0; + tl::from_string_ext (tl::to_string (le->text ()), v); + + ps.set_value (tl::Variant (v)); + lay::indicate_error (le, (tl::Exception *) 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = false; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_double: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + double v = 0; + tl::from_string_ext (tl::to_string (le->text ()), v); + + ps.set_value (tl::Variant (v)); + lay::indicate_error (le, (tl::Exception *) 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = false; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_string: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + ps.set_value (tl::Variant (tl::to_string (le->text ()))); + } + } + break; + + case db::PCellParameterDeclaration::t_list: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + std::vector values = tl::split (tl::to_string (le->text ()), ","); + ps.set_value (tl::Variant (values.begin (), values.end ())); + } + } + break; + + case db::PCellParameterDeclaration::t_layer: + { + lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); + if (ly) { + ps.set_value (tl::Variant (ly->current_layer_props ())); + } + } + break; + case db::PCellParameterDeclaration::t_boolean: + { + QCheckBox *cbx = dynamic_cast (m_widgets [r]); + if (cbx) { + ps.set_value (tl::Variant (cbx->isChecked ())); + } + } + break; + + default: + break; + } + + } else { + + QComboBox *cb = dynamic_cast (m_widgets [r]); + if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { + ps.set_value (p->get_choices () [cb->currentIndex ()]); + } + + } + + } +} + std::vector PCellParametersPage::get_parameters (bool *ok) { @@ -532,130 +774,17 @@ PCellParametersPage::get_parameters (bool *ok) throw tl::Exception (tl::to_string (tr ("PCell no longer valid."))); } - bool edit_error = true; + bool edit_error = false; + + db::ParameterStates states = m_states; + get_parameters_internal (states, edit_error); - int r = 0; const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - - if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { - - if (r < (int) m_parameters.size ()) { - parameters.push_back (m_parameters [r]); - } else { - parameters.push_back (p->get_default ()); - } - - } else { - - parameters.push_back (tl::Variant ()); - - if (p->get_choices ().empty ()) { - - switch (p->get_type ()) { - - case db::PCellParameterDeclaration::t_int: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - int v = 0; - tl::from_string_ext (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, (tl::Exception *) 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_double: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - double v = 0; - tl::from_string_ext (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, (tl::Exception *) 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_string: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - parameters.back () = tl::Variant (tl::to_string (le->text ())); - } - } - break; - - case db::PCellParameterDeclaration::t_list: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - std::vector values = tl::split (tl::to_string (le->text ()), ","); - parameters.back () = tl::Variant (values.begin (), values.end ()); - } - } - break; - - case db::PCellParameterDeclaration::t_layer: - { - lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); - if (ly) { - parameters.back () = tl::Variant (ly->current_layer_props ()); - } - } - break; - case db::PCellParameterDeclaration::t_boolean: - { - QCheckBox *cbx = dynamic_cast (m_widgets [r]); - if (cbx) { - parameters.back () = tl::Variant (cbx->isChecked ()); - } - } - break; - - default: - break; - } - - } else { - - QComboBox *cb = dynamic_cast (m_widgets [r]); - if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { - parameters.back () = p->get_choices () [cb->currentIndex ()]; - } - - } - - } - + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p) { + parameters.push_back (states.parameter (p->get_name ()).value ()); } - if (! edit_error) { + if (edit_error) { throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details."))); } @@ -698,7 +827,34 @@ PCellParametersPage::get_parameters (bool *ok) void PCellParametersPage::set_parameters (const std::vector ¶meters) { - m_parameters = parameters; + if (! mp_pcell_decl) { + return; + } + + size_t r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + db::ParameterState &ps = m_states.parameter (p->get_name ()); + if (r < parameters.size ()) { + ps.set_value (parameters [r]); + } else { + ps.set_value (p->get_default ()); + } + } + + try { + if (mp_view->cellview (m_cv_index).is_valid ()) { + mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), std::string (), m_states); + } + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + set_parameters_internal (parameters, false); } diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 83eadfea1..ea21b1f94 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -103,12 +103,10 @@ public: /** * @brief Gets the initial parameters - * - * The initial parameters are the ones present on "setup". */ const std::vector &initial_parameters () const { - return m_parameters; + return m_initial_parameters; } /** @@ -141,18 +139,21 @@ private: QFrame *mp_error_frame, *mp_update_frame; tl::weak_ptr mp_pcell_decl; std::vector m_widgets; + std::vector > m_all_widgets; lay::LayoutViewBase *mp_view; int m_cv_index; - db::pcell_parameters_type m_parameters; bool m_dense; tl::DeferredMethod dm_parameter_changed; - std::vector m_current_parameters; + std::vector m_current_parameters, m_initial_parameters; + db::ParameterStates m_states; void init (); void do_parameter_changed (); bool lazy_evaluation (); void set_parameters_internal (const std::vector &values, bool tentatively); bool update_current_parameters (); + void update_widgets_from_states (const db::ParameterStates &states); + void get_parameters_internal (db::ParameterStates &states, bool &edit_error); }; } From d82ff4d3f83f5e8c7bf9be75404223200d0b148c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 28 Oct 2022 23:40:48 +0200 Subject: [PATCH 03/29] [consider merging] Fixed a problem with editing guiding shapes --- src/laybasic/laybasic/layObjectInstPath.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laybasic/laybasic/layObjectInstPath.cc b/src/laybasic/laybasic/layObjectInstPath.cc index d22f654e8..2187e9c1d 100644 --- a/src/laybasic/laybasic/layObjectInstPath.cc +++ b/src/laybasic/laybasic/layObjectInstPath.cc @@ -65,7 +65,7 @@ ObjectInstPath::is_valid (lay::LayoutViewBase *view) const } if (! is_cell_inst ()) { - if (! ly.is_valid_layer (layer ())) { + if (! ly.is_valid_layer (layer ()) && layer () != ly.guiding_shape_layer ()) { return false; } if (! ly.cell (ci).shapes (layer ()).is_valid (shape ())) { From eb8c96054c528329eaf2f4c849b9747331022c50 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 28 Oct 2022 23:41:31 +0200 Subject: [PATCH 04/29] WIP: preparations for callbacks in PCell code --- src/db/db/dbPCellDeclaration.cc | 74 ++++++++++ src/db/db/dbPCellDeclaration.h | 101 ++++---------- src/edt/edt/edtInstPropertiesPage.cc | 2 +- src/edt/edt/edtPCellParametersPage.cc | 189 +++++++++++++++----------- src/edt/edt/edtPCellParametersPage.h | 25 +++- 5 files changed, 233 insertions(+), 158 deletions(-) diff --git a/src/db/db/dbPCellDeclaration.cc b/src/db/db/dbPCellDeclaration.cc index 05ad1f4c1..acc1cafde 100644 --- a/src/db/db/dbPCellDeclaration.cc +++ b/src/db/db/dbPCellDeclaration.cc @@ -27,6 +27,80 @@ namespace db { +// ----------------------------------------------------------------------------------------- +// ParameterStates implementation + +ParameterStates::ParameterStates () + : m_states () +{ + // .. nothing yet .. +} + +ParameterStates::ParameterStates (const ParameterStates &other) + : m_states (other.m_states) +{ + // .. nothing yet .. +} + +ParameterStates::ParameterStates (ParameterStates &&other) + : m_states (std::move (other.m_states)) +{ + // .. nothing yet .. +} + +ParameterStates & +ParameterStates::operator= (const ParameterStates &other) +{ + if (this != &other) { + m_states = other.m_states; + } + return *this; +} + +void +ParameterStates::set_parameter (const std::string &name, const ParameterState &ps) +{ + m_states [name] = ps; +} + +ParameterState & +ParameterStates::parameter (const std::string &name) +{ + return m_states [name]; +} + +const ParameterState & +ParameterStates::parameter (const std::string &name) const +{ + auto i = m_states.find (name); + if (i == m_states.end ()) { + static ParameterState empty; + return empty; + } else { + return i->second; + } +} + +bool +ParameterStates::has_parameter (const std::string &name) const +{ + return m_states.find (name) != m_states.end (); +} + +bool +ParameterStates::values_are_equal (const db::ParameterStates &other) const +{ + auto i = m_states.begin (), j = other.m_states.begin (); + while (i != m_states.end () && j != other.m_states.end () && i->first == j->first && i->second.value () == j->second.value ()) { + ++i; ++j; + } + return i == m_states.end () && j == other.m_states.end (); +} + + +// ----------------------------------------------------------------------------------------- +// PCellDeclaration implementation + PCellDeclaration::PCellDeclaration () : m_ref_count (0), m_id (0), mp_layout (0), m_has_parameter_declarations (false) { diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index aaecb02df..f73aa895b 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -334,8 +334,7 @@ public: * @brief Parameterized constructor */ ParameterState () - : m_value (), m_visible (true), m_enabled (true), - m_value_changed (false), m_visible_changed (false), m_enabled_changed (false) + : m_value (), m_visible (true), m_enabled (true) { // .. nothing yet .. } @@ -353,18 +352,7 @@ public: */ void set_value (const tl::Variant &v) { - if (m_value != v) { - m_value = v; - m_value_changed = true; - } - } - - /** - * @brief Gets a value indicating wheter the value has changed - */ - bool value_changed () const - { - return m_value_changed; + m_value = v; } /** @@ -380,18 +368,7 @@ public: */ void set_visible (bool v) { - if (m_visible != v) { - m_visible = v; - m_visible_changed = true; - } - } - - /** - * @brief Gets a value indicating wheter the visibility has changed - */ - bool visible_changed () const - { - return m_visible_changed; + m_visible = v; } /** @@ -407,32 +384,12 @@ public: */ void set_enabled (bool v) { - if (m_enabled != v) { - m_enabled = v; - m_enabled_changed = true; - } - } - - /** - * @brief Gets a value indicating wheter the enabled state has changed - */ - bool enabled_changed () const - { - return m_enabled_changed; - } - - /** - * @brief Resets the modified flags - */ - void reset () - { - m_enabled_changed = m_visible_changed = m_value_changed = false; + m_enabled = v; } private: tl::Variant m_value; bool m_visible, m_enabled; - bool m_value_changed, m_visible_changed, m_enabled_changed; }; /** @@ -444,49 +401,51 @@ public: /** * @brief Default constructor */ - ParameterStates () - : m_states () - { - // .. nothing yet .. - } + ParameterStates (); + + /** + * @brief Copy constructor + */ + ParameterStates (const ParameterStates &other); + + /** + * @brief Move constructor + */ + ParameterStates (ParameterStates &&other); + + /** + * @brief Assignment + */ + ParameterStates &operator= (const ParameterStates &other); /** * @brief Sets a parameter from a given state */ - void set_parameter (const std::string &name, const ParameterState &ps) - { - m_states [name] = ps; - } + void set_parameter (const std::string &name, const ParameterState &ps); /** * @brief Gets the parameter state for the parameter with the given name * * If the name is not a valid parameter name, the behavior is undefined. */ - ParameterState ¶meter (const std::string &name) - { - return m_states [name]; - } + ParameterState ¶meter (const std::string &name); /** * @brief Gets the parameter state for the parameter with the given name * * If the name is not a valid parameter name, the behavior is undefined. */ - const ParameterState ¶meter (const std::string &name) const - { - return const_cast (this)->parameter (name); - } + const ParameterState ¶meter (const std::string &name) const; /** - * @brief Resets the modified flags + * @brief Gets a value indicating whether a parameter with that name is present */ - void reset () - { - for (auto p = m_states.begin (); p != m_states.end (); ++p) { - p->second.reset (); - } - } + bool has_parameter (const std::string &name) const; + + /** + * @brief Returns true, if the values of the parameter states are equal + */ + bool values_are_equal (const db::ParameterStates &other) const; public: std::map m_states; diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index ce5c0d14e..8cfdac462 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -555,7 +555,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & tl_assert (mp_pcell_parameters); std::vector param = mp_pcell_parameters->get_parameters (0); - const std::vector &initial_param = mp_pcell_parameters->initial_parameters (); + std::vector initial_param = mp_pcell_parameters->initial_parameters (); const std::vector &pcp = mp_pcell_parameters->pcell_decl ()->parameter_declarations (); for (std::vector::const_iterator pd = pcp.begin (); pd != pcp.end (); ++pd) { diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 426c2becf..f5687abae 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -239,7 +239,6 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P mp_view = view; m_cv_index = cv_index; m_states = db::ParameterStates (); - m_initial_parameters.clear (); if (mp_parameters_area) { delete mp_parameters_area; @@ -285,8 +284,6 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P value = p->get_default (); } - m_initial_parameters.push_back (value); - db::ParameterState &ps = m_states.parameter (p->get_name ()); ps.set_value (value); ps.set_enabled (! p->is_readonly ()); @@ -484,8 +481,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P // ignore other errors } + m_initial_states = m_states; update_widgets_from_states (m_states); - m_states.reset (); mp_parameters_area->setWidget (main_frame); main_frame->show (); @@ -493,42 +490,6 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P update_current_parameters (); } -void -PCellParametersPage::update_widgets_from_states (const db::ParameterStates &states) -{ - if (! mp_pcell_decl) { - return; - } - - bool update_needed = false; - - size_t i = 0; - const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++i) { - - const std::string &name = p->get_name (); - const db::ParameterState &ps = states.parameter (name); - - if (ps.value_changed ()) { - update_needed = true; - set_value (*p, m_widgets [i], ps.value ()); - } - - if (ps.enabled_changed ()) { - m_widgets [i]->setEnabled (ps.is_enabled ()); - } - - if (ps.visible_changed ()) { - for (auto w = m_all_widgets [i].begin (); w != m_all_widgets [i].end (); ++w) { - (*w)->setVisible (ps.is_enabled ()); - } - } - - } - - mp_update_frame->setVisible (update_needed); -} - PCellParametersPage::State PCellParametersPage::get_state () { @@ -585,16 +546,17 @@ PCellParametersPage::parameter_changed () try { db::ParameterStates states = m_states; - states.reset (); bool edit_error = false; + // Silent and without coerce - this will be done later in do_parameter_changed(). + // This is just about providing the inputs for the callback. get_parameters_internal (states, edit_error); + if (! edit_error) { mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), pd ? pd->get_name () : std::string (), states); update_widgets_from_states (states); - states.reset (); m_states = states; } @@ -614,11 +576,10 @@ PCellParametersPage::parameter_changed () void PCellParametersPage::do_parameter_changed () { - // does a coerce and update - bool edit_error = false; + bool ok = true; db::ParameterStates states = m_states; - get_parameters_internal (states, edit_error); - if (! edit_error && ! lazy_evaluation ()) { + get_parameters (states, &ok); // includes coerce + if (ok && ! lazy_evaluation ()) { emit edited (); } } @@ -634,10 +595,11 @@ PCellParametersPage::update_button_pressed () bool PCellParametersPage::update_current_parameters () { - bool ok = false; - std::vector parameters = get_parameters (&ok); + bool ok = true; + db::ParameterStates states = m_states; + get_parameters (states, &ok); // includes coerce if (ok) { - m_current_parameters = parameters; + m_current_states = states; mp_update_frame->hide (); } @@ -647,7 +609,7 @@ PCellParametersPage::update_current_parameters () void PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool &edit_error) { - edit_error = true; + edit_error = false; int r = 0; const std::vector &pcp = mp_pcell_decl->parameter_declarations (); @@ -679,7 +641,7 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool } catch (tl::Exception &ex) { lay::indicate_error (le, &ex); - edit_error = false; + edit_error = true; } @@ -703,7 +665,7 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool } catch (tl::Exception &ex) { lay::indicate_error (le, &ex); - edit_error = false; + edit_error = true; } @@ -763,11 +725,9 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool } } -std::vector -PCellParametersPage::get_parameters (bool *ok) +void +PCellParametersPage::get_parameters (db::ParameterStates &states, bool *ok) { - std::vector parameters; - try { if (! mp_pcell_decl) { @@ -776,23 +736,25 @@ PCellParametersPage::get_parameters (bool *ok) bool edit_error = false; - db::ParameterStates states = m_states; get_parameters_internal (states, edit_error); - const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p) { - parameters.push_back (states.parameter (p->get_name ()).value ()); - } - if (edit_error) { throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details."))); } - // coerce the parameters + // coerces the parameters and writes the changed values back if (mp_view->cellview (m_cv_index).is_valid ()) { + + auto parameters = parameter_from_states (states); + auto before_coerce = parameters; mp_pcell_decl->coerce_parameters (mp_view->cellview (m_cv_index)->layout (), parameters); + + if (parameters != before_coerce) { + states_from_parameters (states, parameters); + set_parameters_internal (states, lazy_evaluation ()); + } + } - set_parameters_internal (parameters, lazy_evaluation ()); if (ok) { *ok = true; @@ -820,8 +782,15 @@ PCellParametersPage::get_parameters (bool *ok) } } +} - return parameters; +std::vector +PCellParametersPage::get_parameters (bool *ok) +{ + db::ParameterStates states = m_states; + get_parameters (states, ok); + + return parameter_from_states (states); } void @@ -831,16 +800,7 @@ PCellParametersPage::set_parameters (const std::vector ¶meters) return; } - size_t r = 0; - const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - db::ParameterState &ps = m_states.parameter (p->get_name ()); - if (r < parameters.size ()) { - ps.set_value (parameters [r]); - } else { - ps.set_value (p->get_default ()); - } - } + states_from_parameters (m_states, parameters); try { if (mp_view->cellview (m_cv_index).is_valid ()) { @@ -855,11 +815,39 @@ PCellParametersPage::set_parameters (const std::vector ¶meters) // ignore other errors } - set_parameters_internal (parameters, false); + m_initial_states = m_states; + set_parameters_internal (m_states, false); } void -PCellParametersPage::set_parameters_internal (const std::vector ¶meters, bool tentatively) +PCellParametersPage::update_widgets_from_states (const db::ParameterStates &states) +{ + if (! mp_pcell_decl) { + return; + } + + size_t i = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end () && i < m_widgets.size (); ++p, ++i) { + + const std::string &name = p->get_name (); + const db::ParameterState &ps = states.parameter (name); + + if (m_widgets [i]) { + m_widgets [i]->setEnabled (ps.is_enabled ()); + } + + for (auto w = m_all_widgets [i].begin (); w != m_all_widgets [i].end (); ++w) { + (*w)->setVisible (ps.is_visible ()); + } + + } + + set_parameters_internal (states, lazy_evaluation ()); +} + +void +PCellParametersPage::set_parameters_internal (const db::ParameterStates &states, bool tentatively) { if (! mp_pcell_decl) { return; @@ -869,8 +857,8 @@ PCellParametersPage::set_parameters_internal (const std::vector &pa size_t r = 0; const std::vector &pcp = mp_pcell_decl->parameter_declarations (); for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - if (r < parameters.size () && m_widgets [r]) { - set_value (*p, m_widgets [r], parameters [r]); + if (m_widgets [r]) { + set_value (*p, m_widgets [r], states.parameter (p->get_name ()).value ()); } } @@ -879,14 +867,53 @@ PCellParametersPage::set_parameters_internal (const std::vector &pa bool update_needed = false; if (! tentatively) { - m_current_parameters = parameters; + m_current_states = states; } else { - update_needed = (m_current_parameters != parameters); + update_needed = ! m_current_states.values_are_equal (states); } mp_update_frame->setVisible (update_needed); } +std::vector +PCellParametersPage::parameter_from_states (const db::ParameterStates &states) const +{ + std::vector parameters; + if (mp_pcell_decl) { + + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (auto p = pcp.begin (); p != pcp.end (); ++p) { + if (! states.has_parameter (p->get_name ())) { + parameters.push_back (p->get_default ()); + } else { + parameters.push_back (states.parameter (p->get_name ()).value ()); + } + } + + } + + return parameters; +} + +void +PCellParametersPage::states_from_parameters (db::ParameterStates &states, const std::vector ¶meters) +{ + if (! mp_pcell_decl) { + return; + } + + size_t r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + db::ParameterState &ps = states.parameter (p->get_name ()); + if (r < parameters.size ()) { + ps.set_value (parameters [r]); + } else { + ps.set_value (p->get_default ()); + } + } +} + } #endif diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index ea21b1f94..ec44c1578 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -93,7 +93,7 @@ public: void set_state (const State &s); /** - * @brief Get the current parameters + * @brief Gets the current parameters * * *ok is set to true, if there is no error. In case of an error it's set to false. * The error is indicated in the error label in the editor page. @@ -101,12 +101,25 @@ public: */ std::vector get_parameters (bool *ok = 0); + /** + * @brief Gets the current parameters into a ParameterStates object + * + * *ok is set to true, if there is no error. In case of an error it's set to false. + * The error is indicated in the error label in the editor page. + * If ok is null, an exception is thrown. + * + * The value fields of the ParameterState members is set to the parameter value. + * The other attributes are not changed. Parameters not present inside the + * ParameterStates object are created with their corresponding name. + */ + void get_parameters (db::ParameterStates &states, bool *ok = 0); + /** * @brief Gets the initial parameters */ - const std::vector &initial_parameters () const + std::vector initial_parameters () const { - return m_initial_parameters; + return parameter_from_states (m_initial_states); } /** @@ -144,16 +157,18 @@ private: int m_cv_index; bool m_dense; tl::DeferredMethod dm_parameter_changed; - std::vector m_current_parameters, m_initial_parameters; + db::ParameterStates m_current_states, m_initial_states; db::ParameterStates m_states; void init (); void do_parameter_changed (); bool lazy_evaluation (); - void set_parameters_internal (const std::vector &values, bool tentatively); + void set_parameters_internal (const db::ParameterStates &states, bool tentatively); bool update_current_parameters (); void update_widgets_from_states (const db::ParameterStates &states); void get_parameters_internal (db::ParameterStates &states, bool &edit_error); + std::vector parameter_from_states (const db::ParameterStates &states) const; + void states_from_parameters (db::ParameterStates &states, const std::vector ¶meters); }; } From d00c4a94d61c7b42e9d40a01ebb49a800b3852db Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Oct 2022 00:22:54 +0200 Subject: [PATCH 05/29] WIP: first version GSI binding for callbacks --- src/db/db/gsiDeclDbLibrary.cc | 102 +++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 8 deletions(-) diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index dd306f0cb..38a5e0cb2 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -276,15 +276,16 @@ static db::pcell_parameters_type coerce_parameters_native (const db::PCellDeclar // Provide a binding for db::PCellDeclaration for native PCell implementations Class decl_PCellDeclaration_Native ("db", "PCellDeclaration_Native", - gsi::method_ext ("get_layers", &get_layer_declarations_native) + + gsi::method_ext ("get_layers", &get_layer_declarations_native, gsi::arg ("parameters")) + gsi::method ("get_parameters", &db::PCellDeclaration::get_parameter_declarations) + - gsi::method ("produce", &db::PCellDeclaration::produce) + - gsi::method_ext ("coerce_parameters", &coerce_parameters_native) + - gsi::method ("can_create_from_shape", &db::PCellDeclaration::can_create_from_shape) + - gsi::method ("parameters_from_shape", &db::PCellDeclaration::parameters_from_shape) + - gsi::method ("transformation_from_shape", &db::PCellDeclaration::transformation_from_shape) + + gsi::method ("produce", &db::PCellDeclaration::produce, gsi::arg ("layout"), gsi::arg ("layers"), gsi::arg ("parameters"), gsi::arg ("cell")) + + gsi::method ("callback", &db::PCellDeclaration::callback, gsi::arg ("layout"), gsi::arg ("name"), gsi::arg ("states")) + + gsi::method_ext ("coerce_parameters", &coerce_parameters_native, gsi::arg ("layout"), gsi::arg ("parameters")) + + gsi::method ("can_create_from_shape", &db::PCellDeclaration::can_create_from_shape, gsi::arg ("layout"), gsi::arg ("shape"), gsi::arg ("layer")) + + gsi::method ("parameters_from_shape", &db::PCellDeclaration::parameters_from_shape, gsi::arg ("layout"), gsi::arg ("shape"), gsi::arg ("layer")) + + gsi::method ("transformation_from_shape", &db::PCellDeclaration::transformation_from_shape, gsi::arg ("layout"), gsi::arg ("shape"), gsi::arg ("layer")) + gsi::method ("wants_lazy_evaluation", &db::PCellDeclaration::wants_lazy_evaluation) + - gsi::method ("display_text", &db::PCellDeclaration::get_display_name) + + gsi::method ("display_text", &db::PCellDeclaration::get_display_name, gsi::arg ("parameters")) + gsi::method ("layout", &db::PCellDeclaration::layout, "@brief Gets the Layout object the PCell is registered in or nil if it is not registered yet.\n" "This attribute has been added in version 0.27.5." @@ -299,6 +300,56 @@ Class decl_PCellDeclaration_Native ("db", "PCellDeclaratio "@hide\n@alias PCellDeclaration\n" ); +// Provide a binding for db::ParameterState for native PCell implementations +Class decl_PCellParameterState ("db", "PCellParameterState", + gsi::method("value=", &db::ParameterState::set_value, gsi::arg ("v"), + "@brief Sets the value of the parameter\n" + ) + + gsi::method("value", &db::ParameterState::value, + "@brief Gets the value of the parameter\n" + ) + + gsi::method("visible=", &db::ParameterState::set_visible, gsi::arg ("f"), + "@brief Sets a value indicating whether the parameter is visible in the parameter form\n" + ) + + gsi::method("is_visible?", &db::ParameterState::is_visible, + "@brief Gets a value indicating whether the parameter is visible in the parameter form\n" + ) + + gsi::method("enabled=", &db::ParameterState::set_enabled, gsi::arg ("f"), + "@brief Sets a value indicating whether the parameter is enabled in the parameter form\n" + ) + + gsi::method("is_enabled?", &db::ParameterState::is_enabled, + "@brief Gets a value indicating whether the parameter is enabled in the parameter form\n" + ), + "@brief Provides access to the attributes of a single parameter within \\PCellParameterStates.\n" + "\n" + "See \\PCellParameterStates for details about this feature.\n" + "\n" + "This class has been introduced in version 0.28." +); + +// Provide a binding for db::ParameterStates for native PCell implementations +Class decl_PCellParameterStates ("db", "PCellParameterStates", + gsi::method ("has_parameter?", &db::ParameterStates::has_parameter, gsi::arg ("name"), + "@brief Gets a value indicating whether a parameter with that name exists\n" + ) + + gsi::method ("parameter", static_cast (&db::ParameterStates::parameter), gsi::arg ("name"), + "@brief Gets the parameter by name\n" + "\n" + "This will return a \\PCellParameterState object that can be used to manipulate the " + "parameter state." + ), + "@brief Provides access to the parameter states inside a 'callback' implementation of a PCell\n" + "\n" + "Example: enables or disables a parameter 'n' based on the value:\n" + "\n" + "@code\n" + "n_param = states.parameter(\"n\")\n" + "n_param.enabled = n_param.value > 1.0\n" + "@/code\n" + "\n" + "This class has been introduced in version 0.28." +); + class PCellDeclarationImpl : public db::PCellDeclaration { @@ -359,6 +410,20 @@ public: } } + virtual void callback_fb (const db::Layout &layout, const std::string &name, db::ParameterStates &states) const + { + db::PCellDeclaration::callback (layout, name, states); + } + + virtual void callback (const db::Layout &layout, const std::string &name, db::ParameterStates &states) const + { + if (cb_callback.can_issue ()) { + cb_callback.issue (&db::PCellDeclaration::callback, layout, name, states); + } else { + db::PCellDeclaration::callback (layout, name, states); + } + } + void produce_fb (const db::Layout &layout, const std::vector &layer_ids, const db::pcell_parameters_type ¶meters, db::Cell &cell) const { return db::PCellDeclaration::produce (layout, layer_ids, parameters, cell); @@ -451,6 +516,7 @@ public: gsi::Callback cb_transformation_from_shape; gsi::Callback cb_wants_lazy_evaluation; gsi::Callback cb_coerce_parameters; + gsi::Callback cb_callback; gsi::Callback cb_get_display_name; }; @@ -458,6 +524,7 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, // fallback implementations to reroute Ruby calls to the base class: gsi::method ("get_parameters", &PCellDeclarationImpl::get_parameter_declarations_fb, "@hide") + gsi::method ("produce", &PCellDeclarationImpl::produce_fb, "@hide") + + gsi::method ("callback", &PCellDeclarationImpl::callback_fb, "@hide") + gsi::method ("can_create_from_shape", &PCellDeclarationImpl::can_create_from_shape_fb, "@hide") + gsi::method ("parameters_from_shape", &PCellDeclarationImpl::parameters_from_shape_fb, "@hide") + gsi::method ("transformation_from_shape", &PCellDeclarationImpl::transformation_from_shape_fb, "@hide") + @@ -493,6 +560,25 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, "\n" "It can raise an exception to indicate that something is not correct.\n" ) + + gsi::callback ("callback", &PCellDeclarationImpl::callback, &PCellDeclarationImpl::cb_callback, gsi::arg ("layout"), gsi::arg ("name"), gsi::arg ("states"), + "@brief Indicates a parameter change and allows implementing actions based on the parameter value\n" + "@param layout The layout object in which the PCell will be produced\n" + "@param name The name of the parameter which has changed or an empty string if all parameters need to be considered\n" + "@param states A \\PCellParameterStates object which can be used to manipulate the parameter states\n" + "This method may be reimplemented to implement parameter-specific actions upon value change or button callbacks. " + "Whenever the value of a parameter is changed in the PCell parameter form, this method is called with the name of the parameter " + "in 'name'. The implementation can manipulate values or states (enabled, visible) or parameters using the " + "\\PCellParameterStates object passed in 'states'.\n" + "\n" + "Initially, this method will be called with an empty parameter name to indicate a global change. The implementation " + "may then consolidate all states. The initial state is build from the 'readonly' (disabled) or 'hidden' (invisible) parameter " + "declarations.\n" + "\n" + "This method is also called when a button-type parameter is present and the button is pressed. In this case the parameter " + "name is the name of the button.\n" + "\n" + "This feature has been introduced in version 0.28." + ) + gsi::callback ("produce", &PCellDeclarationImpl::produce, &PCellDeclarationImpl::cb_produce, gsi::arg ("layout"), gsi::arg ("layer_ids"), gsi::arg ("parameters"), gsi::arg ("cell"), "@brief The production callback\n" "@param layout The layout object where the cell resides\n" @@ -768,7 +854,7 @@ Class decl_PCellParameterDeclaration ("db", "PCel gsi::method ("TypeList", &pd_type_list, "@brief Type code: a list of variants") + gsi::method ("TypeLayer", &pd_type_layer, "@brief Type code: a layer (a \\LayerInfo object)") + gsi::method ("TypeShape", &pd_type_shape, "@brief Type code: a guiding shape (Box, Edge, Point, Polygon or Path)") + - gsi::method ("TypeCallback", &pd_type_callback, "@brief Type code: a button triggering a callback") + + gsi::method ("TypeCallback", &pd_type_callback, "@brief Type code: a button triggering a callback\n\nThis code has been introduced in version 0.28.") + gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type") , "@brief A PCell parameter declaration\n" From 0e5842d36e6316a0a6883c011375cf1fec11cbb3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Oct 2022 21:19:35 +0200 Subject: [PATCH 06/29] Fixed some qrc files, added more attributes to PCellParameterState (tool tip, readonly, icon), added option to show parameter names --- src/db/db/dbPCellDeclaration.h | 64 +++++++++- src/db/db/gsiDeclDbLibrary.cc | 42 +++++++ src/edt/edt/AlignOptionsDialog.ui | 18 +-- src/edt/edt/DistributeOptionsDialog.ui | 18 +-- src/edt/edt/EditorOptionsInst.ui | 4 +- src/edt/edt/InstPropertiesPage.ui | 5 +- src/edt/edt/MakeCellOptionsDialog.ui | 20 +-- src/edt/edt/edtPCellParametersPage.cc | 114 +++++++++++++++--- src/edt/edt/edtPCellParametersPage.h | 11 +- .../lay_plugin/LEFDEFImportOptionsDialog.ui | 10 +- .../magic/lay_plugin/MAGReaderOptionPage.ui | 10 +- .../oasis/lay_plugin/OASISWriterOptionPage.ui | 6 +- .../streamers/oasis/lay_plugin/lay_plugin.pro | 1 + 13 files changed, 258 insertions(+), 65 deletions(-) diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index f73aa895b..5afa58c35 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -330,11 +330,21 @@ public: class DB_PUBLIC ParameterState { public: + /** + * @brief A enum describing the icon type + */ + enum Icon { + NoIcon = 0, + InfoIcon = 1, + ErrorIcon = 2, + WarningIcon = 3 + }; + /** * @brief Parameterized constructor */ ParameterState () - : m_value (), m_visible (true), m_enabled (true) + : m_value (), m_visible (true), m_enabled (true), m_readonly (false), m_icon (NoIcon) { // .. nothing yet .. } @@ -387,9 +397,59 @@ public: m_enabled = v; } + /** + * @brief Gets a value indicating whether the parameter is read-only + */ + bool is_readonly () const + { + return m_readonly; + } + + /** + * @brief Sets a value indicating whether the parameter is read-only + */ + void set_readonly (bool f) + { + m_readonly = f; + } + + /** + * @brief Gets the tooltip for the parameter + */ + const std::string &tooltip () const + { + return m_tooltip; + } + + /** + * @brief Sets the tooltip + */ + void set_tooltip (const std::string &s) + { + m_tooltip = s; + } + + /** + * @brief Gets the icon + */ + Icon icon () const + { + return m_icon; + } + + /** + * @brief Sets the icon + */ + void set_icon (Icon i) + { + m_icon = i; + } + private: tl::Variant m_value; - bool m_visible, m_enabled; + bool m_visible, m_enabled, m_readonly; + std::string m_tooltip; + Icon m_icon; }; /** diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 38a5e0cb2..e2f89007b 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -23,6 +23,7 @@ #include "gsiDecl.h" +#include "gsiEnums.h" #include "dbLayout.h" #include "dbLibrary.h" #include "dbPCellDeclaration.h" @@ -319,6 +320,26 @@ Class decl_PCellParameterState ("db", "PCellParameterState", ) + gsi::method("is_enabled?", &db::ParameterState::is_enabled, "@brief Gets a value indicating whether the parameter is enabled in the parameter form\n" + ) + + gsi::method("readonly=", &db::ParameterState::set_readonly, gsi::arg ("f"), + "@brief Sets a value indicating whether the parameter is made read-only (not editable) in the parameter form\n" + ) + + gsi::method("is_readonly?", &db::ParameterState::is_readonly, + "@brief Gets a value indicating whether the parameter is read-only (not editable) in the parameter form\n" + ) + + gsi::method("tooltip=", &db::ParameterState::set_tooltip, gsi::arg ("s"), + "@brief Sets the tool tip text\n" + "\n" + "The tool tip is shown when hovering over the parameter label or edit field." + ) + + gsi::method("tooltip", &db::ParameterState::tooltip, + "@brief Gets the tool tip text\n" + ) + + gsi::method("icon=", &db::ParameterState::set_icon, gsi::arg ("i"), + "@brief Sets the icon for the parameter\n" + ) + + gsi::method("tooltip", &db::ParameterState::tooltip, + "@brief Gets the icon for the parameter\n" ), "@brief Provides access to the attributes of a single parameter within \\PCellParameterStates.\n" "\n" @@ -327,6 +348,27 @@ Class decl_PCellParameterState ("db", "PCellParameterState", "This class has been introduced in version 0.28." ); +gsi::EnumIn decl_PCellParameterState_Icon ("db", "ParameterStateIcon", + gsi::enum_const ("NoIcon", db::ParameterState::NoIcon, + "@brief No icon is shown for the parameter\n" + ) + + gsi::enum_const ("InfoIcon", db::ParameterState::InfoIcon, + "@brief A general 'information' icon is shown\n" + ) + + gsi::enum_const ("ErrorIcon", db::ParameterState::ErrorIcon, + "@brief An icon indicating an error is shown\n" + ) + + gsi::enum_const ("WarningIcon", db::ParameterState::WarningIcon, + "@brief An icon indicating a warning is shown\n" + ), + "@brief This enum specifies the icon shown next to the parameter in PCell parameter list.\n" + "\n" + "This enum was introduced in version 0.28.\n" +); + +// Inject the NetlistCrossReference::Status declarations into NetlistCrossReference: +gsi::ClassExt inject_PCellParameterState_Icon_in_parent (decl_PCellParameterState_Icon.defs ()); + // Provide a binding for db::ParameterStates for native PCell implementations Class decl_PCellParameterStates ("db", "PCellParameterStates", gsi::method ("has_parameter?", &db::ParameterStates::has_parameter, gsi::arg ("name"), diff --git a/src/edt/edt/AlignOptionsDialog.ui b/src/edt/edt/AlignOptionsDialog.ui index c6e21d7da..d94795de2 100644 --- a/src/edt/edt/AlignOptionsDialog.ui +++ b/src/edt/edt/AlignOptionsDialog.ui @@ -26,7 +26,7 @@
- + :/align_none_32px.png:/align_none_32px.png @@ -43,7 +43,7 @@ - + :/align_left_32px.png:/align_left_32px.png @@ -60,7 +60,7 @@ - + :/align_hcenter_32px.png:/align_hcenter_32px.png @@ -77,7 +77,7 @@ - + :/align_right_32px.png:/align_right_32px.png @@ -204,7 +204,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -221,7 +221,7 @@ - + :/align_top_32px.png:/align_top_32px.png @@ -238,7 +238,7 @@ - + :/align_vcenter_32px.png:/align_vcenter_32px.png @@ -308,7 +308,7 @@ - + :/align_bottom_32px.png:/align_bottom_32px.png @@ -432,7 +432,7 @@ buttonBox - + diff --git a/src/edt/edt/DistributeOptionsDialog.ui b/src/edt/edt/DistributeOptionsDialog.ui index 900a68f5f..f70b9c04a 100644 --- a/src/edt/edt/DistributeOptionsDialog.ui +++ b/src/edt/edt/DistributeOptionsDialog.ui @@ -278,7 +278,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -311,7 +311,7 @@ - + :/align_left_32px.png:/align_left_32px.png @@ -344,7 +344,7 @@ - + :/align_hcenter_32px.png:/align_hcenter_32px.png @@ -377,7 +377,7 @@ - + :/align_right_32px.png:/align_right_32px.png @@ -456,7 +456,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -489,7 +489,7 @@ - + :/align_top_32px.png:/align_top_32px.png @@ -522,7 +522,7 @@ - + :/align_vcenter_32px.png:/align_vcenter_32px.png @@ -555,7 +555,7 @@ - + :/align_bottom_32px.png:/align_bottom_32px.png @@ -676,7 +676,7 @@ buttonBox - + diff --git a/src/edt/edt/EditorOptionsInst.ui b/src/edt/edt/EditorOptionsInst.ui index bfbe93beb..86b3e2c56 100644 --- a/src/edt/edt/EditorOptionsInst.ui +++ b/src/edt/edt/EditorOptionsInst.ui @@ -158,7 +158,7 @@ ... - + :/find_16px.png:/find_16px.png @@ -549,7 +549,7 @@ - + diff --git a/src/edt/edt/InstPropertiesPage.ui b/src/edt/edt/InstPropertiesPage.ui index e022a1cd4..f389d23f1 100644 --- a/src/edt/edt/InstPropertiesPage.ui +++ b/src/edt/edt/InstPropertiesPage.ui @@ -59,7 +59,6 @@ Sans Serif 12 - 75 false true false @@ -731,7 +730,7 @@ - :/warn_16px@2x.png + :/warn_16px@2x.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -899,7 +898,7 @@ inst_pb - + diff --git a/src/edt/edt/MakeCellOptionsDialog.ui b/src/edt/edt/MakeCellOptionsDialog.ui index 9fae1b2bc..e40f36a75 100644 --- a/src/edt/edt/MakeCellOptionsDialog.ui +++ b/src/edt/edt/MakeCellOptionsDialog.ui @@ -144,7 +144,7 @@ ... - + :/ct_31px.png:/ct_31px.png @@ -164,7 +164,7 @@ ... - + :/lt_31px.png:/lt_31px.png @@ -184,7 +184,7 @@ ... - + :/rt_31px.png:/rt_31px.png @@ -204,7 +204,7 @@ ... - + :/lc_31px.png:/lc_31px.png @@ -224,7 +224,7 @@ ... - + :/cc_31px.png:/cc_31px.png @@ -244,7 +244,7 @@ ... - + :/rc_31px.png:/rc_31px.png @@ -264,7 +264,7 @@ ... - + :/lb_31px.png:/lb_31px.png @@ -284,7 +284,7 @@ ... - + :/cb_31px.png:/cb_31px.png @@ -304,7 +304,7 @@ ... - + :/rb_31px.png:/rb_31px.png @@ -366,7 +366,7 @@
- + diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index f5687abae..0f505113a 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -149,7 +149,7 @@ static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, } PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense) - : QFrame (parent), m_dense (dense), dm_parameter_changed (this, &PCellParametersPage::do_parameter_changed) + : QFrame (parent), m_dense (dense), m_show_parameter_names (false), dm_parameter_changed (this, &PCellParametersPage::do_parameter_changed) { init (); } @@ -170,7 +170,7 @@ PCellParametersPage::init () frame_layout->setContentsMargins (0, 0, 0, 0); setLayout (frame_layout); - mp_update_frame = new QFrame (); + mp_update_frame = new QFrame (this); mp_update_frame->setFrameShape (QFrame::NoFrame); frame_layout->addWidget (mp_update_frame, 0, 0, 1, 1); @@ -197,7 +197,7 @@ PCellParametersPage::init () update_frame_layout->setColumnStretch (2, 1); - mp_error_frame = new QFrame (); + mp_error_frame = new QFrame (this); mp_error_frame->setFrameShape (QFrame::NoFrame); frame_layout->addWidget (mp_error_frame, 1, 0, 1, 1); @@ -224,6 +224,13 @@ PCellParametersPage::init () error_frame_layout->addWidget (mp_error_label, 1, 1, 1, 2); error_frame_layout->setColumnStretch (2, 1); + + mp_show_parameter_names_cb = new QCheckBox (this); + mp_show_parameter_names_cb->setText (tr ("Show parameter names")); + mp_show_parameter_names_cb->setChecked (m_show_parameter_names); + frame_layout->addWidget (mp_show_parameter_names_cb, 3, 0, 1, 1); + + connect (mp_show_parameter_names_cb, SIGNAL (clicked (bool)), this, SLOT (show_parameter_names (bool))); } bool @@ -232,6 +239,18 @@ PCellParametersPage::lazy_evaluation () return mp_pcell_decl.get () && mp_pcell_decl->wants_lazy_evaluation (); } +void +PCellParametersPage::show_parameter_names (bool f) +{ + if (m_show_parameter_names == f) { + return; + } + + m_show_parameter_names = f; + mp_show_parameter_names_cb->setChecked (f); + setup (mp_view, m_cv_index, mp_pcell_decl.get (), get_parameters ()); +} + void PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) { @@ -239,12 +258,14 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P mp_view = view; m_cv_index = cv_index; m_states = db::ParameterStates (); + m_initial_states = db::ParameterStates (); if (mp_parameters_area) { delete mp_parameters_area; } m_widgets.clear (); + m_icon_widgets.clear (); m_all_widgets.clear (); mp_parameters_area = new QScrollArea (this); @@ -269,6 +290,12 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P QWidget *main_frame = inner_frame; QGridLayout *main_grid = inner_grid; + if (! mp_pcell_decl) { + mp_parameters_area->setWidget (main_frame); + update_current_parameters (); + return; + } + int main_row = 0; int row = 0; std::string group_title; @@ -286,13 +313,14 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P db::ParameterState &ps = m_states.parameter (p->get_name ()); ps.set_value (value); - ps.set_enabled (! p->is_readonly ()); + ps.set_readonly (p->is_readonly ()); ps.set_visible (! p->is_hidden ()); m_all_widgets.push_back (std::vector ()); if (p->get_type () == db::PCellParameterDeclaration::t_shape) { m_widgets.push_back (0); + m_icon_widgets.push_back (0); continue; } @@ -312,7 +340,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P // create a new group QGroupBox *gb = new QGroupBox (main_frame); gb->setTitle (tl::to_qstring (gt)); - main_grid->addWidget (gb, main_row, 0, 1, 2); + main_grid->addWidget (gb, main_row, 0, 1, 3); inner_grid = new QGridLayout (gb); if (m_dense) { @@ -339,10 +367,28 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P } + QLabel *icon_label = new QLabel (QString (), inner_frame); + inner_grid->addWidget (icon_label, row, 0); + m_icon_widgets.push_back (icon_label); + m_all_widgets.back ().push_back (icon_label); + if (p->get_type () != db::PCellParameterDeclaration::t_callback) { - QLabel *l = new QLabel (tl::to_qstring (description), inner_frame); - inner_grid->addWidget (l, row, 0); + + std::string leader; + if (m_show_parameter_names) { + leader = tl::sprintf ("[%s] ", p->get_name ()); + } + + QLabel *l = new QLabel (tl::to_qstring (leader + description), inner_frame); + inner_grid->addWidget (l, row, 1); m_all_widgets.back ().push_back (l); + + } else if (m_show_parameter_names) { + + QLabel *l = new QLabel (tl::to_qstring (tl::sprintf ("[%s]", p->get_name ())), inner_frame); + inner_grid->addWidget (l, row, 1); + m_all_widgets.back ().push_back (l); + } if (p->get_choices ().empty ()) { @@ -368,7 +414,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P hb->addWidget (ul, 1); ul->setText (tl::to_qstring (p->get_unit ())); - inner_grid->addWidget (f, row, 1); + inner_grid->addWidget (f, row, 2); m_all_widgets.back ().push_back (f); connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ())); @@ -383,7 +429,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P pb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred); m_widgets.push_back (pb); - inner_grid->addWidget (pb, row, 1); + inner_grid->addWidget (pb, row, 2); m_all_widgets.back ().push_back (pb); connect (pb, SIGNAL (clicked ()), this, SLOT (parameter_changed ())); @@ -397,7 +443,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P QLineEdit *le = new QLineEdit (inner_frame); le->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (le); - inner_grid->addWidget (le, row, 1); + inner_grid->addWidget (le, row, 2); m_all_widgets.back ().push_back (le); connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ())); @@ -411,7 +457,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P ly->set_view (mp_view, m_cv_index, true /*all layers*/); ly->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (ly); - inner_grid->addWidget (ly, row, 1); + inner_grid->addWidget (ly, row, 2); m_all_widgets.back ().push_back (ly); connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); @@ -425,7 +471,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P cbx->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred)); cbx->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (cbx); - inner_grid->addWidget (cbx, row, 1); + inner_grid->addWidget (cbx, row, 2); m_all_widgets.back ().push_back (cbx); connect (cbx, SIGNAL (stateChanged (int)), this, SLOT (parameter_changed ())); @@ -456,7 +502,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P cb->setMinimumContentsLength (30); cb->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon); m_widgets.push_back (cb); - inner_grid->addWidget (cb, row, 1); + inner_grid->addWidget (cb, row, 2); m_all_widgets.back ().push_back (cb); } @@ -499,6 +545,8 @@ PCellParametersPage::get_state () s.vScrollPosition = mp_parameters_area->verticalScrollBar ()->value (); s.hScrollPosition = mp_parameters_area->horizontalScrollBar ()->value (); + s.show_parameter_names = m_show_parameter_names; + if (focusWidget ()) { s.focusWidget = focusWidget ()->objectName (); } @@ -514,6 +562,10 @@ PCellParametersPage::set_state (const State &s) mp_parameters_area->verticalScrollBar ()->setValue (s.vScrollPosition); mp_parameters_area->horizontalScrollBar ()->setValue (s.hScrollPosition); + if (s.show_parameter_names != m_show_parameter_names) { + show_parameter_names (s.show_parameter_names); + } + if (! s.focusWidget.isEmpty ()) { QWidget *c = findChild (s.focusWidget); if (c) { @@ -617,7 +669,7 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool db::ParameterState &ps = states.parameter (p->get_name ()); - if (! ps.is_visible () || ! ps.is_enabled () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + if (! ps.is_visible () || ! ps.is_enabled () || ps.is_readonly () || p->get_type () == db::PCellParameterDeclaration::t_shape) { continue; } @@ -834,11 +886,43 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat const db::ParameterState &ps = states.parameter (name); if (m_widgets [i]) { - m_widgets [i]->setEnabled (ps.is_enabled ()); + m_widgets [i]->setEnabled (ps.is_enabled () && ! ps.is_readonly ()); } for (auto w = m_all_widgets [i].begin (); w != m_all_widgets [i].end (); ++w) { + if (*w != m_widgets [i]) { + (*w)->setEnabled (ps.is_enabled ()); + } (*w)->setVisible (ps.is_visible ()); + (*w)->setToolTip (tl::to_qstring (ps.tooltip ())); + } + + if (m_icon_widgets [i]) { + + static QPixmap error (":/error_16px@2x.png"); + static QPixmap info (":/info_16px@2x.png"); + static QPixmap warning (":/warn_16px@2x.png"); + + switch (ps.icon ()) { + case db::ParameterState::NoIcon: + default: + m_icon_widgets [i]->setPixmap (QPixmap ()); + m_icon_widgets [i]->hide (); + break; + case db::ParameterState::InfoIcon: + m_icon_widgets [i]->setPixmap (info); + m_icon_widgets [i]->show (); + break; + case db::ParameterState::WarningIcon: + m_icon_widgets [i]->setPixmap (warning); + m_icon_widgets [i]->show (); + break; + case db::ParameterState::ErrorIcon: + m_icon_widgets [i]->setPixmap (error); + m_icon_widgets [i]->show (); + break; + } + } } diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index ec44c1578..05462eb02 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace lay { @@ -52,9 +53,10 @@ Q_OBJECT public: struct State { - State () : valid (false), hScrollPosition (0), vScrollPosition (0) { } + State () : valid (false), show_parameter_names (false), hScrollPosition (0), vScrollPosition (0) { } bool valid; + bool show_parameter_names; int hScrollPosition; int vScrollPosition; QString focusWidget; @@ -138,6 +140,9 @@ public: signals: void edited (); +public slots: + void show_parameter_names (bool f); + private slots: void parameter_changed (); void update_button_pressed (); @@ -150,12 +155,14 @@ private: QLabel *mp_changed_icon; QToolButton *mp_update_button; QFrame *mp_error_frame, *mp_update_frame; + QCheckBox *mp_show_parameter_names_cb; tl::weak_ptr mp_pcell_decl; std::vector m_widgets; + std::vector m_icon_widgets; std::vector > m_all_widgets; lay::LayoutViewBase *mp_view; int m_cv_index; - bool m_dense; + bool m_dense, m_show_parameter_names; tl::DeferredMethod dm_parameter_changed; db::ParameterStates m_current_states, m_initial_states; db::ParameterStates m_states; diff --git a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui index dbb3e9401..f14df467b 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui +++ b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui @@ -190,7 +190,7 @@ ...
- + :/clear_16px.png:/clear_16px.png
@@ -204,7 +204,7 @@ ... - + :/add_16px.png:/add_16px.png
@@ -218,7 +218,7 @@ ... - + :/up_16px.png:/up_16px.png
@@ -232,7 +232,7 @@ ... - + :/down_16px.png:/down_16px.png
@@ -298,7 +298,7 @@ buttonBox - + diff --git a/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui b/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui index 4dd76f3b7..107165a8e 100644 --- a/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui +++ b/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui @@ -147,7 +147,7 @@ ... - + :/clear_16px.png:/clear_16px.png @@ -161,7 +161,7 @@ ... - + :/down_16px.png:/down_16px.png @@ -175,7 +175,7 @@ ... - + :/add_16px.png:/add_16px.png @@ -197,7 +197,7 @@ You can use expressions inside the path components for variable paths ... - + :/up_16px.png:/up_16px.png @@ -315,7 +315,7 @@ You can use expressions inside the path components for variable paths read_all_cbx - + diff --git a/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui b/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui index 995fbd702..78110075f 100644 --- a/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui +++ b/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui @@ -284,7 +284,7 @@ - :/warn_16px@2x.png + :/warn_16px@2x.png
@@ -379,7 +379,7 @@ - :/warn_16px@2x.png + :/warn_16px@2x.png @@ -430,7 +430,7 @@ subst_char - + diff --git a/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro b/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro index 666291b59..4ca7fd7d4 100644 --- a/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro +++ b/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro @@ -22,3 +22,4 @@ SOURCES = \ FORMS = \ OASISWriterOptionPage.ui \ + From 194a6f3526514161e1fe4503be7c055bc96a199f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Oct 2022 22:38:33 +0200 Subject: [PATCH 07/29] Added callback helper for Ruby PCellDeclarationHelper --- .../pcell_declaration_helper.lym | 178 +++++++++++++++--- 1 file changed, 151 insertions(+), 27 deletions(-) diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 115f3fdee..3e0d9419a 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -157,6 +157,53 @@ It is supposed to adjust parameters to render a consistent parameter set and to parameter range errors. This method is called for example inside the PCell user interface to compute the actual parameters when "Apply" is pressed. +@method callback_impl(name) + +@brief Provides a callback on a parameter change + +This method applies to user interface changes only. Whenever a parameter is changed +on the parameter page, this method is called with the name of the parameter. + +On some occasions, this method called to establish a configuration unspecifically. +In this case, the name is an empty string - indicating "all parameters may have changed". + +This method can change the state of this or any other parameter. For this, the +state objects are supplied instead of the parameter values. For example to enable +parameter "b" when a boolean parameter "a" is true, use the following code: + +@code +def callback_impl(name) + if name == "a" || name == "" + b.enabled = a.value + end +end +@/code + +The "enabled" attribute of the \\PCellParameterState object indicates whether the +parameter is enabled in the user interface. "a.value" delivers the value of the +(boolean type assumed) parameter "a". + +Note that the above code also checks for empty name to consider the case of a +global refresh. + +Further useful attributes of the parameters are: + +@ul + @li + @b enabled @/b: the parameter entry is grayed out if false + @/li + @li + @b readonly @/b: the parameter cannot be edited (less strict than enabled) + @/li + @li + @b visible @/b: the parameter entry is not visible if false + @/li + @li + @b icon @/b: Sets an icon in front of the parameter indicating an error or a + warning (use \\PCellParameterState#WarningIcon or \\PCellParameterState#ErrorIcon). + @/li +@/ul + @method can_create_from_shape_impl @brief Returns true if the PCell can be created from the given shape @@ -227,12 +274,13 @@ module RBA def initialize @param_decls = [] @param_values = nil + @param_states = nil @layout = nil @shape = nil @layer = nil @cell = nil @layer_param_index = [] - @layers = [] + @layers = nil end # provide accessors for the current layout and cell (for prod) @@ -244,6 +292,43 @@ module RBA def _layout; @layout; end def _cell; @cell; end def _shape; @shape; end + + # A helper method to access the nth parameter + + def _param(nth) + if @param_states + if @param_states.size <= nth + return RBA::PCellParameterState::new + else + return @param_states[nth] + end + else + @param_values || raise("No parameters available.") + while @param_values.size <= nth + @param_values << nil + end + return @param_values[nth] + end + end + + # A helper method to set the nth parameter + + def _set_param(nth, value) + @param_values || raise("Cannot set parameter - inside 'callback_impl' use 'param_name.value = ...' to set the parameter's value.") + if @param_values.size > nth + @param_values[nth] = value + end + end + + # A helper method to access the nth layer + + def _layer(nth) + @layers || raise("No layer index available - layers can be used only inside 'produce_impl'.") + while @param_values.size <= nth + @param_values << nil + end + @param_values[nth] + end # define a parameter # name -> the short name of the parameter @@ -270,11 +355,11 @@ module RBA # create accessor methods for the parameters param_index = @param_decls.length - self.instance_eval("def #{name.to_s}; @param_values[#{param_index}]; end") - self.instance_eval("def set_#{name.to_s}(v); @param_values[#{param_index}] = v; end") - self.instance_eval("def #{name.to_s}=(v); @param_values[#{param_index}] = v; end") + self.instance_eval("def #{name.to_s}; self._param(#{param_index}); end") + self.instance_eval("def set_#{name.to_s}(v); self._set_param(#{param_index}, v); end") + self.instance_eval("def #{name.to_s}=(v); self._set_param(#{param_index}, v); end") if type == TypeLayer - self.instance_eval("def #{name.to_s}_layer; @layers[#{@layer_param_index.length}]; end") + self.instance_eval("def #{name.to_s}_layer; self._layer(#{@layer_param_index.length}); end") @layer_param_index.push(param_index) end @@ -307,8 +392,11 @@ module RBA # implementation of display_text def display_text(parameters) @param_values = parameters - text = display_text_impl - @param_values = nil + begin + text = display_text_impl + ensure + @param_values = nil + end text end @@ -326,9 +414,28 @@ module RBA def coerce_parameters(layout, parameters) @param_values = parameters @layout = layout - coerce_parameters_impl - @layout = nil - @param_values + ret = parameters + begin + coerce_parameters_impl + ensure + @layout = nil + ret = @param_values + @param_values = nil + end + ret + end + + # parameter change callback + def callback(layout, name, states) + @param_values = nil + @param_states = states + @layout = layout + begin + callback_impl(name) + ensure + @param_states = nil + @layout = nil + end end # produce the layout @@ -337,22 +444,29 @@ module RBA @cell = cell @param_values = parameters @layout = layout - produce_impl - @layers = nil - @cell = nil - @param_values = nil - @layout = nil + begin + produce_impl + ensure + @layers = nil + @cell = nil + @param_values = nil + @layout = nil + end end # produce a helper for can_create_from_shape def can_create_from_shape(layout, shape, layer) + ret = false @layout = layout @shape = shape @layer = layer - ret = can_create_from_shape_impl - @layout = nil - @shape = nil - @layer = nil + begin + ret = can_create_from_shape_impl + ensure + @layout = nil + @shape = nil + @layer = nil + end ret end @@ -361,10 +475,13 @@ module RBA @layout = layout @shape = shape @layer = layer - t = transformation_from_shape_impl - @layout = nil - @shape = nil - @layer = nil + begin + t = transformation_from_shape_impl + ensure + @layout = nil + @shape = nil + @layer = nil + end t end @@ -375,10 +492,13 @@ module RBA @layout = layout @shape = shape @layer = layer - parameters_from_shape_impl - @layout = nil - @shape = nil - @layer = nil + begin + parameters_from_shape_impl + ensure + @layout = nil + @shape = nil + @layer = nil + end @param_values end @@ -391,6 +511,10 @@ module RBA def coerce_parameters_impl end + # default implementation + def callback_impl(name) + end + # default implementation def produce_impl end From 1b666e1cc8eb4fe07cf412f31003e9b5bf2f71ed Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Oct 2022 23:43:56 +0200 Subject: [PATCH 08/29] Bug fixes. --- .../db/built-in-macros/pcell_declaration_helper.lym | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 3e0d9419a..229c3b651 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -295,7 +295,7 @@ module RBA # A helper method to access the nth parameter - def _param(nth) + def _get_param(nth) if @param_states if @param_states.size <= nth return RBA::PCellParameterState::new @@ -322,12 +322,9 @@ module RBA # A helper method to access the nth layer - def _layer(nth) + def _get_layer(nth) @layers || raise("No layer index available - layers can be used only inside 'produce_impl'.") - while @param_values.size <= nth - @param_values << nil - end - @param_values[nth] + @layers[nth] end # define a parameter @@ -355,11 +352,11 @@ module RBA # create accessor methods for the parameters param_index = @param_decls.length - self.instance_eval("def #{name.to_s}; self._param(#{param_index}); end") + self.instance_eval("def #{name.to_s}; self._get_param(#{param_index}); end") self.instance_eval("def set_#{name.to_s}(v); self._set_param(#{param_index}, v); end") self.instance_eval("def #{name.to_s}=(v); self._set_param(#{param_index}, v); end") if type == TypeLayer - self.instance_eval("def #{name.to_s}_layer; self._layer(#{@layer_param_index.length}); end") + self.instance_eval("def #{name.to_s}_layer; self._get_layer(#{@layer_param_index.length}); end") @layer_param_index.push(param_index) end From 8aa135b964b1f94dce83c2344b1018b48503b8db Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 30 Oct 2022 00:15:48 +0200 Subject: [PATCH 09/29] Python implementation of PCell helper with callback --- .../pcell_declaration_helper.lym | 136 ++++++++++++++---- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym index 3632806fd..1df6dcb53 100644 --- a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym @@ -162,6 +162,51 @@ It is supposed to adjust parameters to render a consistent parameter set and to parameter range errors. This method is called for example inside the PCell user interface to compute the actual parameters when "Apply" is pressed. +@method callback_impl(name) + +@brief Provides a callback on a parameter change + +This method applies to user interface changes only. Whenever a parameter is changed +on the parameter page, this method is called with the name of the parameter. + +On some occasions, this method called to establish a configuration unspecifically. +In this case, the name is an empty string - indicating "all parameters may have changed". + +This method can change the state of this or any other parameter. For this, the +state objects are supplied instead of the parameter values. For example to enable +parameter "b" when a boolean parameter "a" is true, use the following code: + +@code +def callback_impl(self, name): + if name == "a" or name == "": + b.enabled = a.value +@/code + +The "enabled" attribute of the \\PCellParameterState object indicates whether the +parameter is enabled in the user interface. "a.value" delivers the value of the +(boolean type assumed) parameter "a". + +Note that the above code also checks for empty name to consider the case of a +global refresh. + +Further useful attributes of the parameters are: + +@ul + @li + @b enabled @/b: the parameter entry is grayed out if false + @/li + @li + @b readonly @/b: the parameter cannot be edited (less strict than enabled) + @/li + @li + @b visible @/b: the parameter entry is not visible if false + @/li + @li + @b icon @/b: Sets an icon in front of the parameter indicating an error or a + warning (use \\PCellParameterState#WarningIcon or \\PCellParameterState#ErrorIcon). + @/li +@/ul + @method can_create_from_shape_impl @brief Returns true if the PCell can be created from the given shape @@ -232,13 +277,16 @@ class _PCellDeclarationHelperParameterDescriptor(object): the descriptor acts as a value holder (self.value) """ - def __init__(self, param_index): + def __init__(self, param_index, param_name): self.param_index = param_index + self.param_name = param_name self.value = None def __get__(self, obj, type = None): if obj._param_values: return obj._param_values[self.param_index] + elif obj._param_states: + return obj._param_states.parameter(self.param_name) else: return self.value @@ -261,6 +309,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): # "private" attributes self._param_decls = [] self._param_values = None + self._param_states = None self._layer_param_index = [] self._layers = [] # public attributes @@ -290,7 +339,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): # create accessor methods for the parameters param_index = len(self._param_decls) - setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index)) + setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index, name)) if value_type == type(self).TypeLayer: setattr(type(self), name + "_layer", _PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index))) @@ -323,8 +372,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): implementation of display_text """ self._param_values = parameters - text = self.display_text_impl() - self._param_values = None + try: + text = self.display_text_impl() + finally: + self._param_values = None return text def get_parameters(self): @@ -341,7 +392,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self._param_values = None return v - def init_values(self, values = None, layers = None): + def init_values(self, values = None, layers = None, states = None): """ initializes the temporary parameter values "values" are the original values. If "None" is given, the @@ -349,7 +400,11 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): "layers" are the layer indexes corresponding to the layer parameters. """ - if not values: + self._param_values = None + self._param_states = None + if states: + self._param_states = states + elif not values: self._param_values = [] for pd in self._param_decls: self._param_values.append(pd.default) @@ -359,29 +414,48 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): def finish(self): """ - Needs to be called at the end of produce() after init_values was used + Needs to be called at the end of an implementation """ self._param_values = None + self._param_states = None self._layers = None + self._cell = None + self._layout = None + self._layer = None + self._shape = None def get_layers(self, parameters): """ - get the layer definitions + gets the layer definitions """ layers = [] for i in self._layer_param_index: layers.append(parameters[i]) return layers + def callback(self, layout, name, states): + """ + callback (change state on parameter change) + """ + self.init_values(states = states) + self.layout = layout + try: + self.callback_impl(name) + finally: + self.finish() + def coerce_parameters(self, layout, parameters): """ coerce parameters (make consistent) """ self.init_values(parameters) self.layout = layout - self.coerce_parameters_impl() - self.layout = None - return self.get_values() + try: + self.coerce_parameters_impl() + parameters = self.get_values() + finally: + self.finish() + return parameters def produce(self, layout, layers, parameters, cell): """ @@ -390,10 +464,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.init_values(parameters, layers) self.cell = cell self.layout = layout - self.produce_impl() - self.cell = None - self.layout = None - self.finish() + try: + self.produce_impl() + finally: + self.finish() def can_create_from_shape(self, layout, shape, layer): """ @@ -402,10 +476,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - ret = self.can_create_from_shape_impl() - self.layout = None - self.shape = None - self.layer = None + try: + ret = self.can_create_from_shape_impl() + finally: + self.finish() return ret def transformation_from_shape(self, layout, shape, layer): @@ -415,10 +489,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - t = self.transformation_from_shape_impl() - self.layout = None - self.shape = None - self.layer = None + try: + t = self.transformation_from_shape_impl() + finally: + self.finish() return t def parameters_from_shape(self, layout, shape, layer): @@ -430,11 +504,11 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - self.parameters_from_shape_impl() - param = self.get_values() - self.layout = None - self.shape = None - self.layer = None + try: + self.parameters_from_shape_impl() + param = self.get_values() + finally: + self.finish() return param def display_text_impl(self): @@ -449,6 +523,12 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): """ pass + def callback_impl(self, name): + """ + default implementation + """ + pass + def produce_impl(self): """ default implementation From b1b51d3152acb58c6279b9b7003bc8f70c9c8f46 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 30 Oct 2022 00:23:32 +0200 Subject: [PATCH 10/29] Bug fix Ruby PCell declaration helper - needs testing --- src/db/db/built-in-macros/pcell_declaration_helper.lym | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 229c3b651..f37f64344 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -295,12 +295,12 @@ module RBA # A helper method to access the nth parameter - def _get_param(nth) + def _get_param(nth, name) if @param_states if @param_states.size <= nth return RBA::PCellParameterState::new else - return @param_states[nth] + return @param_states.parameter(name) end else @param_values || raise("No parameters available.") @@ -349,10 +349,14 @@ module RBA # param_{name}_layer def param(name, type, description, args = {}) + + if name !~ /^[_A-Za-z]\w*$/ + raise "Invalid parameter name #{name} (needs to be a word)" + end # create accessor methods for the parameters param_index = @param_decls.length - self.instance_eval("def #{name.to_s}; self._get_param(#{param_index}); end") + self.instance_eval("def #{name.to_s}; self._get_param(#{param_index}, '#{name}'); end") self.instance_eval("def set_#{name.to_s}(v); self._set_param(#{param_index}, v); end") self.instance_eval("def #{name.to_s}=(v); self._set_param(#{param_index}, v); end") if type == TypeLayer From 548db003ed7d97850832b09714ad76b00fead0b2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 30 Oct 2022 10:00:51 +0100 Subject: [PATCH 11/29] Debugged Ruby PCellDeclarationHelper, small enhancements --- src/db/db/built-in-macros/pcell_declaration_helper.lym | 2 +- src/edt/edt/edtPCellParametersPage.cc | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index f37f64344..30023a97a 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -297,7 +297,7 @@ module RBA def _get_param(nth, name) if @param_states - if @param_states.size <= nth + if ! @param_states.has_parameter?(name) return RBA::PCellParameterState::new else return @param_states.parameter(name) diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 0f505113a..043034b75 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -605,12 +605,8 @@ PCellParametersPage::parameter_changed () get_parameters_internal (states, edit_error); if (! edit_error) { - mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), pd ? pd->get_name () : std::string (), states); - - update_widgets_from_states (states); m_states = states; - } } catch (tl::Exception &ex) { @@ -631,6 +627,7 @@ PCellParametersPage::do_parameter_changed () bool ok = true; db::ParameterStates states = m_states; get_parameters (states, &ok); // includes coerce + update_widgets_from_states (states); if (ok && ! lazy_evaluation ()) { emit edited (); } @@ -893,7 +890,9 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat if (*w != m_widgets [i]) { (*w)->setEnabled (ps.is_enabled ()); } - (*w)->setVisible (ps.is_visible ()); + if (*w != m_icon_widgets [i]) { + (*w)->setVisible (ps.is_visible ()); + } (*w)->setToolTip (tl::to_qstring (ps.tooltip ())); } From 2dc5c98416d6907514f4f75355d9ea5c2aec562e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 1 Nov 2022 13:46:36 +0100 Subject: [PATCH 12/29] Implemented readonly for PCell line-edit parameters as QLineEdit::readOnly --- src/edt/edt/edtPCellParametersPage.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 043034b75..e7e72f0c6 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -883,7 +883,13 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat const db::ParameterState &ps = states.parameter (name); if (m_widgets [i]) { - m_widgets [i]->setEnabled (ps.is_enabled () && ! ps.is_readonly ()); + QLineEdit *le = dynamic_cast (m_widgets [i]); + if (le) { + le->setEnabled (ps.is_enabled ()); + le->setReadOnly (ps.is_readonly ()); + } else { + m_widgets [i]->setEnabled (ps.is_enabled () && ! ps.is_readonly ()); + } } for (auto w = m_all_widgets [i].begin (); w != m_all_widgets [i].end (); ++w) { From 54833db00b098cdec696bb2d5bea22c5bee01598 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 1 Nov 2022 13:46:48 +0100 Subject: [PATCH 13/29] Added feature for computing area and perimeter from selection --- src/edt/edt/AreaAndPerimeterDialog.ui | 130 ++++++++++++++++++++++++++ src/edt/edt/edt.pro | 3 +- src/edt/edt/edtDialogs.cc | 23 +++++ src/edt/edt/edtDialogs.h | 17 ++++ src/edt/edt/edtMainService.cc | 78 +++++++++++++++- src/edt/edt/edtMainService.h | 8 ++ src/edt/edt/edtPlugin.cc | 2 + 7 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 src/edt/edt/AreaAndPerimeterDialog.ui diff --git a/src/edt/edt/AreaAndPerimeterDialog.ui b/src/edt/edt/AreaAndPerimeterDialog.ui new file mode 100644 index 000000000..9fd1a263a --- /dev/null +++ b/src/edt/edt/AreaAndPerimeterDialog.ui @@ -0,0 +1,130 @@ + + + AreaAndPerimeterDialog + + + + 0 + 0 + 367 + 205 + + + + Area And Perimeter + + + + + + Qt::Vertical + + + + 10 + 11 + + + + + + + + true + + + + + + + Area + + + + + + + µm + + + + + + + µm² + + + + + + + Perimeter + + + + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + Note: area and perimeter are computed in "merged mode". This means, overlapping shapes are counted once for area calculation. +The perimeter calculation only takes true outside edges into account. Internal edges are ignored. + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + + buttonBox + accepted() + AreaAndPerimeterDialog + accept() + + + 303 + 185 + + + 311 + 201 + + + + + diff --git a/src/edt/edt/edt.pro b/src/edt/edt/edt.pro index 24075ca3b..7680a9946 100644 --- a/src/edt/edt/edt.pro +++ b/src/edt/edt/edt.pro @@ -27,7 +27,8 @@ DEFINES += MAKE_EDT_LIBRARY RoundCornerOptionsDialog.ui \ TextPropertiesPage.ui \ DistributeOptionsDialog.ui \ - EditorOptionsInstPCellParam.ui + EditorOptionsInstPCellParam.ui \ + AreaAndPerimeterDialog.ui } diff --git a/src/edt/edt/edtDialogs.cc b/src/edt/edt/edtDialogs.cc index 1486b2abf..498eb8e47 100644 --- a/src/edt/edt/edtDialogs.cc +++ b/src/edt/edt/edtDialogs.cc @@ -683,6 +683,29 @@ BEGIN_PROTECTED; END_PROTECTED; } +// -------------------------------------------------------------------------------- +// AreaAndPerimeterDialog implementation + +AreaAndPerimeterDialog::AreaAndPerimeterDialog (QWidget *parent) + : QDialog (parent) +{ + setupUi (this); +} + +AreaAndPerimeterDialog::~AreaAndPerimeterDialog () +{ + // .. nothing yet .. +} + +bool +AreaAndPerimeterDialog::exec_dialog (double area, double perimeter) +{ + area_le->setText (tl::to_qstring (tl::sprintf ("%.12g", area))); + perimeter_le->setText (tl::to_qstring (tl::sprintf ("%.12g", perimeter))); + + return exec () != 0; +} + } #endif diff --git a/src/edt/edt/edtDialogs.h b/src/edt/edt/edtDialogs.h index 5864a8d54..a108585b5 100644 --- a/src/edt/edt/edtDialogs.h +++ b/src/edt/edt/edtDialogs.h @@ -43,6 +43,7 @@ #include "ui_MakeCellOptionsDialog.h" #include "ui_MakeArrayOptionsDialog.h" #include "ui_RoundCornerOptionsDialog.h" +#include "ui_AreaAndPerimeterDialog.h" namespace lay { @@ -205,6 +206,22 @@ private: bool m_has_extracted; }; +/** + * @brief Result dialog for "area and perimeter" + */ +class AreaAndPerimeterDialog + : public QDialog, + private Ui::AreaAndPerimeterDialog +{ +Q_OBJECT + +public: + AreaAndPerimeterDialog (QWidget *parent); + ~AreaAndPerimeterDialog (); + + bool exec_dialog (double area, double perimeter); +}; + } // namespace edt #endif diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index 0f97e0166..c7b51e1b9 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -25,6 +25,7 @@ #include "dbPolygonTools.h" #include "dbLibrary.h" #include "dbLibraryManager.h" +#include "dbRegion.h" #include "tlExceptions.h" #include "layLayoutView.h" #include "laySelector.h" @@ -82,6 +83,7 @@ MainService::MainService (db::Manager *manager, lay::LayoutViewBase *view, lay:: { #if defined(HAVE_QT) mp_round_corners_dialog = 0; + mp_area_and_perimeter_dialog = 0; mp_align_options_dialog = 0; mp_distribute_options_dialog = 0; mp_flatten_inst_options_dialog = 0; @@ -106,6 +108,15 @@ MainService::round_corners_dialog () return mp_round_corners_dialog; } +edt::AreaAndPerimeterDialog * +MainService::area_and_perimeter_dialog () +{ + if (! mp_area_and_perimeter_dialog) { + mp_area_and_perimeter_dialog = new edt::AreaAndPerimeterDialog (lay::widget_from_view (view ())); + } + return mp_area_and_perimeter_dialog; +} + edt::AlignOptionsDialog * MainService::align_options_dialog () { @@ -168,6 +179,8 @@ MainService::menu_activated (const std::string &symbol) cm_tap (); } else if (symbol == "edt::sel_round_corners") { cm_round_corners (); + } else if (symbol == "edt::sel_area_perimeter") { + cm_area_perimeter (); } else if (symbol == "edt::sel_convert_to_pcell") { cm_convert_to_pcell (); } else if (symbol == "edt::sel_convert_to_cell") { @@ -1346,6 +1359,67 @@ MainService::cm_convert_to_pcell () } } +void MainService::cm_area_perimeter () +{ +#if ! defined(HAVE_QT) + tl_assert (false); // see TODO +#endif + + double dbu = 0.0; + + std::vector edt_services = view ()->get_plugins (); + + db::Region region; + + // get (common) cellview index of the primary selection + for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { + + for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { + + if (s->is_cell_inst ()) { + continue; + } + + db::Polygon poly; + if (!s->shape ().polygon (poly)) { + continue; + } + + double shape_dbu = view ()->cellview (s->cv_index ())->layout ().dbu (); + + if (dbu == 0.0) { + // first CV is used for reference DBU + dbu = shape_dbu; + } + + if (fabs (shape_dbu - dbu) < db::epsilon) { + region.insert (s->trans () * poly); + } else { + region.insert ((db::ICplxTrans (shape_dbu / dbu) * s->trans ()) * poly); + } + + } + + } + +#if defined(HAVE_QT) + if (region.count () > 100000) { + if (QMessageBox::warning (lay::widget_from_view (view ()), tr ("Warning: Big Selection"), + tr ("The selection contains many shapes. Area and perimeter computation may take a long time.\nContinue anyway?"), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) { + return; + } + } +#endif + + double area = region.area () * dbu * dbu; + double perimeter = region.perimeter () * dbu; + +#if defined(HAVE_QT) + area_and_perimeter_dialog ()->exec_dialog (area, perimeter); +#endif +} + static bool extract_rad (std::vector &poly, double &rinner, double &router, unsigned int &n) { std::vector new_pts; @@ -1356,7 +1430,7 @@ static bool extract_rad (std::vector &poly, double &rinner, double db::Polygon new_poly; new_pts.clear (); - if (! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts) && + if (! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts) && ! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts, true)) { // ultimate fallback: assign original contour new_poly.assign_hull (p->begin_hull (), p->end_hull (), false /*don't compress*/); @@ -1368,7 +1442,7 @@ static bool extract_rad (std::vector &poly, double &rinner, double for (unsigned int h = 0; h < p->holes (); ++h) { new_pts.clear (); - if (! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts) && + if (! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts) && ! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts, true)) { // ultimate fallback: assign original contour new_poly.insert_hole (p->begin_hole (h), p->end_hole (h), false /*don't compress*/); diff --git a/src/edt/edt/edtMainService.h b/src/edt/edt/edtMainService.h index e6b26f98b..cc9fc2426 100644 --- a/src/edt/edt/edtMainService.h +++ b/src/edt/edt/edtMainService.h @@ -48,6 +48,7 @@ class Service; class EditorOptionsPages; class EditorOptionsPage; class RoundCornerOptionsDialog; +class AreaAndPerimeterDialog; class MakeCellOptionsDialog; class MakeArrayOptionsDialog; class AlignOptionsDialog; @@ -104,6 +105,11 @@ public: */ void cm_round_corners (); + /** + * @brief Show area and perimeter of selection + */ + void cm_area_perimeter (); + /** * @brief Convert selection to PCell */ @@ -223,6 +229,7 @@ private: bool m_undo_before_apply; #if defined(HAVE_QT) edt::RoundCornerOptionsDialog *mp_round_corners_dialog; + edt::AreaAndPerimeterDialog *mp_area_and_perimeter_dialog; edt::AlignOptionsDialog *mp_align_options_dialog; edt::DistributeOptionsDialog *mp_distribute_options_dialog; lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog; @@ -234,6 +241,7 @@ private: void check_no_guiding_shapes (); #if defined(HAVE_QT) edt::RoundCornerOptionsDialog *round_corners_dialog (); + edt::AreaAndPerimeterDialog *area_and_perimeter_dialog (); edt::AlignOptionsDialog *align_options_dialog (); edt::DistributeOptionsDialog *distribute_options_dialog (); lay::FlattenInstOptionsDialog *flatten_inst_options_dialog (); diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc index 8df9edfa7..f4aed23d9 100644 --- a/src/edt/edt/edtPlugin.cc +++ b/src/edt/edt/edtPlugin.cc @@ -342,6 +342,8 @@ public: menu_entries.push_back (lay::menu_item ("edt::sel_make_cell_variants", "make_cell_variants:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Make Cell Variants")))); menu_entries.push_back (lay::menu_item ("edt::sel_convert_to_pcell", "convert_to_pcell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Convert To PCell")))); menu_entries.push_back (lay::menu_item ("edt::sel_convert_to_cell", "convert_to_cell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Convert To Static Cell")))); + menu_entries.push_back (lay::separator ("hier_group:edit_info", "edit_menu.selection_menu.end")); + menu_entries.push_back (lay::menu_item ("edt::sel_area_perimeter", "area_perimeter", "edit_menu.selection_menu.end", tl::to_string (tr ("Area and Perimeter")))); menu_entries.push_back (lay::menu_item ("edt::combine_mode", "combine_mode:edit_mode", "@toolbar.end_modes", tl::to_string (tr ("Combine{Select background combination mode}")))); } From 9f2cf7275f12e1b221a6e5f6d7b10984b87872db Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 1 Nov 2022 14:17:37 +0100 Subject: [PATCH 14/29] Fixed display of XOR progress (wasn't properly painting the error bitmaps) --- src/plugins/tools/xor/lay_plugin/layXORProgress.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/tools/xor/lay_plugin/layXORProgress.cc b/src/plugins/tools/xor/lay_plugin/layXORProgress.cc index c5f87c6f0..c0cd49e56 100644 --- a/src/plugins/tools/xor/lay_plugin/layXORProgress.cc +++ b/src/plugins/tools/xor/lay_plugin/layXORProgress.cc @@ -202,13 +202,13 @@ public: } else { - int y2 = m_pixmap_size - 1 - (iy * m_pixmap_size + m_pixmap_size / 2) / ny; - int y1 = m_pixmap_size - 1 - ((iy + 1) * m_pixmap_size + m_pixmap_size / 2) / ny; - int x1 = (ix * m_pixmap_size + m_pixmap_size / 2) / nx; - int x2 = ((ix + 1) * m_pixmap_size + m_pixmap_size / 2) / nx; + int y2 = std::min (m_pixmap_size - 1, m_pixmap_size - 1 - (iy * m_pixmap_size + ny / 2) / ny); + int y1 = std::max (0, m_pixmap_size - 1 - ((iy + 1) * m_pixmap_size + ny / 2) / ny); + int x1 = std::max (0, (ix * m_pixmap_size + nx / 2) / nx); + int x2 = std::min (m_pixmap_size - 1, ((ix + 1) * m_pixmap_size + nx / 2) / nx); // "draw" the field - for (int y = y1; y <= y2 && y >= 0 && y < m_pixmap_size; ++y) { + for (int y = y1; y <= y2; ++y) { *((uint32_t *) img->scanLine (y)) &= (((1 << x1) - 1) | ~((1 << (x2 + 1)) - 1)); } @@ -319,8 +319,8 @@ public: grad.setColorAt (0.0, QColor (248, 248, 248)); grad.setColorAt (1.0, QColor (224, 224, 224)); painter.setBrush (QBrush (grad)); - painter.setPen (QPen (Qt::black)); - painter.drawRect (QRect (QPoint (x, y - 2), QSize (m_pixmap_size + 3, m_pixmap_size + 3))); + painter.setPen (QPen (Qt::black, 1.0, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); + painter.drawRect (QRectF (QPointF (x + 1, y - 1), QSizeF (m_pixmap_size + 2, m_pixmap_size + 2))); painter.setBackgroundMode (Qt::TransparentMode); painter.setPen (QColor (128, 255, 128)); From c8e60d666cb7c5edfdb13995815c0e2a46c6eef2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 1 Nov 2022 14:57:39 +0100 Subject: [PATCH 15/29] Fixed #1167 (delete_cells slow) --- src/db/db/dbLayout.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 067ffc03b..51f249d58 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -795,6 +795,8 @@ Layout::delete_cells (const std::set &cells_to_delete) } } + db::LayoutLocker locker (this); + // Clear all instances for (std::set::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) { From d47cbeb2314847f27dbb80cffad48aa32acb940b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 2 Nov 2022 23:07:29 +0100 Subject: [PATCH 16/29] [consider merging] Bugfix: generation of texts for antenna results --- src/db/db/dbLayoutToNetlist.cc | 2 +- testdata/drc/drcSimpleTests_au5.gds | Bin 9892 -> 9892 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 2f47d395f..8a7255ae8 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1414,7 +1414,7 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); if (! e.at_end ()) { // pick one reference point for the label - if (! any_ref && (*e).p1 () < ref) { + if (! any_ref || (*e).p1 () < ref) { ref = (*e).p1 (); any_ref = true; } diff --git a/testdata/drc/drcSimpleTests_au5.gds b/testdata/drc/drcSimpleTests_au5.gds index e5cca0f9e6baa8df7d3a469ed97cedc92ed1a3a9..3902b4aedf2ea902dec38825a01dc33cd2268320 100644 GIT binary patch delta 184 zcmZ4DyTn(CfsKKQDS|HqLQ*GR*8*Kd5RqW|NnWwz`(R; z@&>s$Hg*FzQ?LQfl)eCGswu#k1_f}Y)d4uuRRGTPPk=KcH-MOvIHWh{tC}(b0Nr3L AGXMYp delta 184 zcmZ4DyTn(CfsKKQDS| Date: Wed, 2 Nov 2022 23:08:47 +0100 Subject: [PATCH 17/29] Avoid an assertion in macro editor when no script support is compiled in --- src/lay/lay/layMacroController.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc index 51b1111ef..41167c001 100644 --- a/src/lay/lay/layMacroController.cc +++ b/src/lay/lay/layMacroController.cc @@ -328,6 +328,10 @@ MacroController::drop_url (const std::string &path_or_url) void MacroController::show_editor (const std::string &cat, bool force_add) { + if (macro_categories ().empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Application has not been compiled with scripting support - no macro IDE available"))); + } + if (mp_macro_editor) { mp_macro_editor->show (cat, force_add); } From a8ea23452287b339c713a037cfebb3d35aaed51f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 2 Nov 2022 23:09:44 +0100 Subject: [PATCH 18/29] Enable Qt6 build from build.sh (gcc needs c++17) and less noisy builds with gcc 11 etc. --- src/db/db/dbPolygonGenerators.h | 10 ++++++++++ src/klayout.pri | 17 +++++++++++++---- src/lym/unit_tests/lymBasicTests.cc | 4 ++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbPolygonGenerators.h b/src/db/db/dbPolygonGenerators.h index e76c3cd87..a4127d59a 100644 --- a/src/db/db/dbPolygonGenerators.h +++ b/src/db/db/dbPolygonGenerators.h @@ -124,6 +124,11 @@ public: */ virtual void put (const db::Edge &e); + /** + * @brief Implementation of the EdgeSink interface + */ + virtual void put (const db::Edge & /*e*/, int /*tag*/) { } + /** * @brief Sets the way how holes are resolved dynamically * @@ -261,6 +266,11 @@ public: */ virtual void put (const db::Edge &e); + /** + * @brief Implementation of the EdgeSink interface + */ + virtual void put (const db::Edge & /*e*/, int /*tag*/) { } + private: db::Coord m_y; PolygonSink *mp_psink; diff --git a/src/klayout.pri b/src/klayout.pri index 042cf972f..f70c810ba 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -162,16 +162,25 @@ msvc { QMAKE_CXXFLAGS_WARN_ON += \ -pedantic \ -Woverloaded-virtual \ - -Wsign-promo \ -Wsynth \ -Wno-deprecated \ -Wno-long-long \ -Wno-strict-aliasing \ -Wno-deprecated-declarations \ - -Wno-reserved-user-defined-literal \ - # because we use unordered_map/unordered_set: - QMAKE_CXXFLAGS += -std=c++11 + # too noisy on Qt: + # QMAKE_CXXFLAGS_WARN_ON += \ + # -Wsign-promo \ + # -Wno-reserved-user-defined-literal \ + # + + lessThan(QT_MAJOR_VERSION, 6) { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++11 + } else { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++17 + } win32 { diff --git a/src/lym/unit_tests/lymBasicTests.cc b/src/lym/unit_tests/lymBasicTests.cc index d0b2eaf14..90fac66bb 100644 --- a/src/lym/unit_tests/lymBasicTests.cc +++ b/src/lym/unit_tests/lymBasicTests.cc @@ -53,13 +53,13 @@ private: std::string m_text; }; +#if defined(HAVE_RUBY) + static std::string np (const std::string &s) { return tl::replaced (s, "\\", "/"); } -#if defined(HAVE_RUBY) - TEST(1_BasicRuby) { tl_assert (rba::RubyInterpreter::instance () != 0); From 9ec7c0ca44f77445338dd6e3a181675a755b7700 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 2 Nov 2022 23:35:06 +0100 Subject: [PATCH 19/29] layout_diff GSI binding: provide interface for edge pair diffs --- src/db/db/gsiDeclDbLayoutDiff.cc | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/db/db/gsiDeclDbLayoutDiff.cc b/src/db/db/gsiDeclDbLayoutDiff.cc index d6e85f00a..cd9431a75 100644 --- a/src/db/db/gsiDeclDbLayoutDiff.cc +++ b/src/db/db/gsiDeclDbLayoutDiff.cc @@ -248,6 +248,26 @@ public: end_edge_differences_event (); } + virtual void begin_edge_pair_differences () + { + begin_edge_pair_differences_event (); + } + + virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > &a, const std::vector > &b) + { + for (std::vector >::const_iterator i = a.begin (); i != a.end (); ++i) { + edge_pair_in_a_only_event (i->first, i->second); + } + for (std::vector >::const_iterator i = b.begin (); i != b.end (); ++i) { + edge_pair_in_b_only_event (i->first, i->second); + } + } + + virtual void end_edge_pair_differences () + { + end_edge_pair_differences_event (); + } + virtual void begin_text_differences () { begin_text_differences_event (); @@ -353,6 +373,10 @@ public: tl::event edge_in_a_only_event; tl::event edge_in_b_only_event; tl::Event end_edge_differences_event; + tl::Event begin_edge_pair_differences_event; + tl::event edge_pair_in_a_only_event; + tl::event edge_pair_in_b_only_event; + tl::Event end_edge_pair_differences_event; tl::Event begin_text_differences_event; tl::event text_in_a_only_event; tl::event text_in_b_only_event; @@ -671,6 +695,29 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", gsi::event ("on_end_edge_differences", &LayoutDiff::end_edge_differences_event, "@brief This signal indicates the end of sequence of edge differences\n" ) + + gsi::event ("on_begin_edge_pair_differences", &LayoutDiff::begin_edge_pair_differences_event, + "@brief This signal indicates differences in the edge pairs on the current layer\n" + "The current layer is indicated by the \\begin_layer_event signal or can be obtained from the diff object " + "through \\LayoutDiff#layer_info_a, \\LayoutDiff#layer_index_a, \\LayoutDiff#layer_info_b and \\LayoutDiff#layer_index_b. " + "In verbose mode (see \\Verbose flag) more signals will be emitted for edge pairs that are different between the two layouts." + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_edge_pair_in_a_only", &LayoutDiff::edge_pair_in_a_only_event, gsi::arg ("anotb"), gsi::arg ("prop_id"), + "@brief This signal indicates an edge pair that is present in the first layout only" + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_edge_pair_in_b_only", &LayoutDiff::edge_pair_in_b_only_event, gsi::arg ("bnota"), gsi::arg ("prop_id"), + "@brief This signal indicates an edge pair that is present in the second layout only" + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_end_edge_pair_differences", &LayoutDiff::end_edge_pair_differences_event, + "@brief This signal indicates the end of sequence of edge pair differences\n" + "\n" + "This event has been introduced in version 0.28." + ) + gsi::event ("on_begin_text_differences", &LayoutDiff::begin_text_differences_event, "@brief This signal indicates differences in the texts on the current layer\n" "The current layer is indicated by the \\begin_layer_event signal or can be obtained from the diff object " From 27e04c61a04d047115cfbb5f139d499062e5102e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 2 Nov 2022 23:35:18 +0100 Subject: [PATCH 20/29] Less compiler warnings --- src/db/db/dbPolygonTools.cc | 1 + src/edt/edt/edtPropertiesPages.h | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 7d49fa7e4..a28cb05e1 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -911,6 +911,7 @@ class ErrorCatchingEdgeSink // TODO: we should not use exceptions to indicate a condition, but right now, there is no good alternative // and this is considered an error anyway. virtual void put (const db::Edge &) { throw OddPolygonException (); } + virtual void put (const db::Edge &, int) { } virtual void crossing_edge (const db::Edge &) { throw OddPolygonException (); } }; diff --git a/src/edt/edt/edtPropertiesPages.h b/src/edt/edt/edtPropertiesPages.h index 834da0fb2..0e933c804 100644 --- a/src/edt/edt/edtPropertiesPages.h +++ b/src/edt/edt/edtPropertiesPages.h @@ -52,8 +52,9 @@ public: virtual size_t count () const; virtual void select_entries (const std::vector &entries); virtual std::string description (size_t entry) const; - virtual QIcon icon (size_t entry, int w, int h) const; virtual std::string description () const; + virtual QIcon icon (size_t entry, int w, int h) const; + virtual QIcon icon (int w, int h) const { return lay::PropertiesPage::icon (w, h); } virtual void leave (); protected: @@ -105,6 +106,7 @@ public: PolygonPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -129,6 +131,7 @@ public: BoxPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -159,6 +162,7 @@ public: TextPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -177,6 +181,7 @@ public: PathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -198,6 +203,7 @@ public: EditablePathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); From 8779e2a4ccef56eea9f0ac9880ffc57cd89db579 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 3 Nov 2022 14:26:17 +0100 Subject: [PATCH 21/29] Enabling build with Qt6 --- src/pymod/bridge_sample/bridge_sample.pro | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pymod/bridge_sample/bridge_sample.pro b/src/pymod/bridge_sample/bridge_sample.pro index 372729f5e..bfff5c5df 100644 --- a/src/pymod/bridge_sample/bridge_sample.pro +++ b/src/pymod/bridge_sample/bridge_sample.pro @@ -79,20 +79,28 @@ LIBS += -L$$LIBDIR -lklayout_db !msvc { - # Some standard compiler warnings on QMAKE_CXXFLAGS_WARN_ON += \ -pedantic \ -Woverloaded-virtual \ - -Wsign-promo \ -Wsynth \ -Wno-deprecated \ -Wno-long-long \ -Wno-strict-aliasing \ -Wno-deprecated-declarations \ - -Wno-reserved-user-defined-literal \ - # because we use unordered_map/unordered_set: - QMAKE_CXXFLAGS += -std=c++11 + # too noisy on Qt: + # QMAKE_CXXFLAGS_WARN_ON += \ + # -Wsign-promo \ + # -Wno-reserved-user-defined-literal \ + # + + lessThan(QT_MAJOR_VERSION, 6) { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++11 + } else { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++17 + } # Python is somewhat sloppy and relies on the compiler initializing fields # of strucs to 0: From 9dac047003c68fe2a99a31a1667bebfc9ea90d00 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 4 Nov 2022 21:25:12 +0100 Subject: [PATCH 22/29] Fixed small doc error --- src/doc/doc/about/basic_lib.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/doc/about/basic_lib.xml b/src/doc/doc/about/basic_lib.xml index a2592561e..3fa5c1715 100644 --- a/src/doc/doc/about/basic_lib.xml +++ b/src/doc/doc/about/basic_lib.xml @@ -83,7 +83,7 @@

Custom fonts are installed by copying the font file to a folder named "fonts" in one of the places in KLayout's path. The standard font can be found in - "src/std_font.gds" in the source package. + "src/db/db/std_font.gds" in the source package.

CIRCLE and ELLIPSE

From 25409a3d337c4bd5b1439078c5408c201d6332d8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 4 Nov 2022 22:08:12 +0100 Subject: [PATCH 23/29] Doc updates --- src/doc/doc/manual/net_tracing.xml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/doc/doc/manual/net_tracing.xml b/src/doc/doc/manual/net_tracing.xml index b903ae388..b775c453e 100644 --- a/src/doc/doc/manual/net_tracing.xml +++ b/src/doc/doc/manual/net_tracing.xml @@ -34,20 +34,35 @@

Before nets can be extracted, a layer stack must be specified. Press "Layer Stack" on the user interface to open the - layer stack dialog. Layers must be specified in the "layer/datatype" notation. The + layer stack dialog or use "Edit Layer Stack" in the "Tools" menu. Layers must be specified in the "layer/datatype" notation. The via specification is optional. If no via layer is specified, both metal layer shapes are required to touch in order to form a connection. If a via layer is specified, a via shape must be present to form the connection.

- KLayout allows specification of symbolic layers and to use boolean expressions. That way it is possible to + The layer stack (also referred to as "Connectivity") is also a technology component. This means + if you select a technology for layout, the technology specific stack is selected. To edit the stack + for all technologies, use the Technology Manager ("Tools/Manage Technologies") and use the + "Connectivity" section from the technologies. +

+ +

+ A connectivity definition can specify multiple stacks, out of which one has to be selected. + This is useful, if your technology setup features multiple routing metal schemes for example. + You do not need to setup different technologies for each scheme. If you have declared multiple + stacks, you can choose one in the "Trace Net" dialog in the drop-down button right of the + "Layer Stack" and the "Configuration" button at the bottom left. +

+ +

+ Within the stack definition, KLayout allows specification of symbolic layers and to use boolean expressions. That way it is possible to assign meaningful names to layers (i.e. "POLY" or "VIA1") and to use derived layers (i.e. "ACTIVE-POLY" for the source and drain regions of a CMOS transistor). Read more about these features in and .

- If a layer stack has been defined, a net can be traced by pressing the "Trace Net" button and clicking on a point in the + Once a layer stack has been defined and selected, a net can be traced by pressing the "Trace Net" button and clicking on a point in the layout. Starting from shapes found under this point, the net is extracted and listed in the net list on the left side of the net tracing dialog. If "Lock" is checked, another net can be traced by clicking at another point without having to press the "Trace Net" button again. From 131745433d9dd684c42fd34e72793edc231e2f15 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 4 Nov 2022 23:16:15 +0100 Subject: [PATCH 24/29] Doc fixes --- src/db/db/gsiDeclDbRegion.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 0cc777b8b..926fa368a 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -2452,7 +2452,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2491,7 +2490,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2535,7 +2533,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2574,7 +2571,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2617,7 +2613,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2667,7 +2662,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2716,7 +2710,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2765,7 +2758,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " From f67b28c52a6f813e8d82878e454fc17d07ef00d9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 4 Nov 2022 23:45:10 +0100 Subject: [PATCH 25/29] Supporting LayerInfo objects in fill pattern generation, doc updates --- src/doc/doc/about/drc_ref_layer.xml | 19 +++++++++++++++++++ src/drc/drc/built-in-macros/_drc_layer.rb | 19 +++++++++++++++++++ src/drc/drc/built-in-macros/_drc_tags.rb | 4 ++++ testdata/drc/drcSimpleTests_46.drc | 4 ++-- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/doc/doc/about/drc_ref_layer.xml b/src/doc/doc/about/drc_ref_layer.xml index 6d105b8ea..4cc344d45 100644 --- a/src/doc/doc/about/drc_ref_layer.xml +++ b/src/doc/doc/about/drc_ref_layer.xml @@ -1125,6 +1125,25 @@ A more compact way of writing this is: p = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0))

+The "shape" method takes several forms: +

+

    +
  • shape(layer, object, object ...) (1)
  • +
  • shape(layer, datatype, object, object ...) (2)
  • +
  • shape(name, object, object ...) (3)
  • +
  • shape(layer_info, object, object ...) (4)
  • +
+

+The first form takes a GDS2 layer number. The datatype is assumed to be 0. +The second form takes a GDS layer and datatype number. +The third form takes a layer name for layout systems with named layers +(like Magic, CIF or DXF). +The forth form takes a LayerInfo object to specify the layer. +All forms take one to many geometry objects which are written to the respective layer. +Geometry objects can either be created using the generator functions +(box, polygon, path). The core classes DBox, DPolygon, DPath or +DText are also accepted as geometry objects. +

The fill pattern can be given a reference point which is used for placing the pattern. The reference point is the one which is aligned with the pattern origin. The following code will assign (-0.5, -0.5) as the reference point for the 1x1 micron rectangle. Hence the reference point is a little below and left of the rectangle which diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 88ab7e0b7..c8e2731a5 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -4712,6 +4712,25 @@ CODE # p = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)) # @/code # + # The "shape" method takes several forms: + # + # @ul + # @li @tt shape(layer, object, object ...) @/tt (1) @/li + # @li @tt shape(layer, datatype, object, object ...) @/tt (2) @/li + # @li @tt shape(name, object, object ...) @/tt (3) @/li + # @li @tt shape(layer_info, object, object ...) @/tt (4) @/li + # @/ul + # + # The first form takes a GDS2 layer number. The datatype is assumed to be 0. + # The second form takes a GDS layer and datatype number. + # The third form takes a layer name for layout systems with named layers + # (like Magic, CIF or DXF). + # The forth form takes a RBA::LayerInfo object to specify the layer. + # All forms take one to many geometry objects which are written to the respective layer. + # Geometry objects can either be created using the generator functions + # (\global#box, \global#polygon, \global#path). The core classes RBA::DBox, RBA::DPolygon, RBA::DPath or + # RBA::DText are also accepted as geometry objects. + # # The fill pattern can be given a reference point which is used for placing the pattern. The reference point # is the one which is aligned with the pattern origin. The following code will assign (-0.5, -0.5) as the reference # point for the 1x1 micron rectangle. Hence the reference point is a little below and left of the rectangle which diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb index dedd797ef..86fd67e8d 100644 --- a/src/drc/drc/built-in-macros/_drc_tags.rb +++ b/src/drc/drc/built-in-macros/_drc_tags.rb @@ -256,6 +256,10 @@ module DRC else raise("Argument ##{ai+1} not understood for FillCell#shape") end + elsif a.is_a?(RBA::LayerInfo) + layer = a.layer + datatype = a.datatype + name = a.name elsif a.is_a?(String) if !name name = a diff --git a/testdata/drc/drcSimpleTests_46.drc b/testdata/drc/drcSimpleTests_46.drc index 1278a4681..493b4aee1 100644 --- a/testdata/drc/drcSimpleTests_46.drc +++ b/testdata/drc/drcSimpleTests_46.drc @@ -14,10 +14,10 @@ to_fill = extent - l1 fp1 = fill_pattern("FP1").shape(10, 0, box(0, 0, 800.nm, 800.nm)).origin(-100.nm, -100.nm) to_fill = to_fill.fill_with_left(fp1, hstep(1.um), vstep(200.nm, 1.um), multi_origin) -fp2 = fill_pattern("FP2").shape(10, 0, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm) +fp2 = fill_pattern("FP2").shape(10, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm) to_fill = to_fill.fill_with_left(fp2, hstep(0.5.um), vstep(100.nm, 0.5.um), multi_origin) -fp3 = fill_pattern("FP3").shape(10, 0, box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm) +fp3 = fill_pattern("FP3").shape(RBA::LayerInfo::new(10, 0), box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm) to_fill = to_fill.fill_with_left(fp3, hstep(0.25.um), vstep(50.nm, 0.25.um), multi_origin) to_fill.output(100, 0) From c25223db361e455a3b37c09d30aae5f97f76dc5d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 4 Nov 2022 23:49:23 +0100 Subject: [PATCH 26/29] Updated golden test data --- testdata/drc/drcSimpleTests_au6.gds | Bin 3494 -> 3494 bytes testdata/drc/drcSimpleTests_au7.gds | Bin 22060 -> 22060 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/testdata/drc/drcSimpleTests_au6.gds b/testdata/drc/drcSimpleTests_au6.gds index 08fada80ba01d0829e0a726ebc62f28d5a0a336e..70ac9f50b12c115c3dfdd22db6342ed66e262482 100644 GIT binary patch delta 273 zcmZ1`y-Zq(fsKKQDS|@UW|YHeMv$kUyZ_`uCgIHnOtaWH{{R2!!N9=gF!>*+)Z{lDE^Ph@3=B+r wfZRAXR{=QF>HwT+PylDDDZrW17vN061~`-50LqL3TJ+}ul;gE|0S_A^05tSHssI20 delta 271 zcmZ1`y-Zq(fsKKQDS|@UW|YHeMv$kUyZ_`uCgIHnOtaWH7@%PCKTfI1Z#Z1oAbcPZ;#6!9nYCuH(J2x86Qp4?=p+mknNpZC0;r+A)H1_r8n03}7$z90uFn1*GTPx4*4 zvOe+$WEtDvt#9uEq%?q1`rjvBuHTiZk#G1r>KoIC!|zQ1X7fU(#TrKdYM;;LT5Mxn zqV*}Ub|JB9N}L@?oM=nbYJ|;D@)OX<8SfP}zf!nK$7NRLQ*MA9RY z9+C8jq(>yZZCu5A+c@=m#rv^rbTvHj@r=pOs}H)k9Ui%vGx_gAR~HK;0#PIph&qWt zlu87mS|Shy6M?8HgHBjYY$c=Ha53iVOZj}fSYRFUOY1mVEU-SJ#Sm#RL|P1y7DJ@P z5NR<)S}d^oavW`A HYqZ%POs_Gb)S3_=W|3~~%S$n1$q%Jx_#7`WKjLV_Iqf*BZC z*cljPSaBM$v1L1>C{{Bz2QY18<6wY-$$Xr3Y!LQjIc{1pvnFqlVBf6F*UgHs*g;Hc z@&(}}nB@*)H8f&oY~CO-iI)rJV}@0e1vnKZ=cp}$xn;#<1#X4O|I`-@5`i9IXt8bP z(Bt8OIf!BM1FP7{l~#$cAbMc6j~2{Ljy4 Date: Sat, 5 Nov 2022 14:28:40 +0100 Subject: [PATCH 27/29] [consider merging] Important bug fix - do not use NDEBUG as ruby.h redefines it and this will lead to crashes in the debugger --- src/gsi/gsi/gsiMethods.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gsi/gsi/gsiMethods.h b/src/gsi/gsi/gsiMethods.h index a2e131587..71cf4ba43 100644 --- a/src/gsi/gsi/gsiMethods.h +++ b/src/gsi/gsi/gsiMethods.h @@ -524,7 +524,7 @@ public: // .. nothing yet .. } -#if !defined(NDEBUG) +#if defined(TRACE_METHOD_CALLS) public: /** From 240281d9ff31727711479baa98c4d9e8102e0c9e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 6 Nov 2022 01:12:03 +0100 Subject: [PATCH 28/29] [consider merging] Important patch: avoids incorrect initialization of Python classes --- src/pya/pya/pyaModule.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index 191adb70d..8f0fb40a3 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -408,19 +408,19 @@ struct PythonClassClientData : public gsi::PerClassClientSpecificData { PythonClassClientData (const gsi::ClassBase *_cls, PyTypeObject *_py_type, PyTypeObject *_py_type_static) - : py_type_object (_py_type), py_type_object_static (_py_type_static), method_table (_cls) + : py_type_object ((PyObject *) _py_type), py_type_object_static ((PyObject *) _py_type_static), method_table (_cls) { // .. nothing yet .. } - PyTypeObject *py_type_object; - PyTypeObject *py_type_object_static; + PythonPtr py_type_object; + PythonPtr py_type_object_static; MethodTable method_table; static PyTypeObject *py_type (const gsi::ClassBase &cls_decl, bool as_static) { PythonClassClientData *cd = dynamic_cast(cls_decl.data (gsi::ClientIndex::Python)); - return cd ? (as_static ? cd->py_type_object_static : cd->py_type_object) : 0; + return (PyTypeObject *) (cd ? (as_static ? cd->py_type_object_static.get () : cd->py_type_object.get ()) : 0); } static void initialize (const gsi::ClassBase &cls_decl, PyTypeObject *py_type, bool as_static) @@ -428,9 +428,9 @@ struct PythonClassClientData PythonClassClientData *cd = dynamic_cast(cls_decl.data (gsi::ClientIndex::Python)); if (cd) { if (as_static) { - cd->py_type_object_static = py_type; + cd->py_type_object_static = (PyObject *) py_type; } else { - cd->py_type_object = py_type; + cd->py_type_object = (PyObject *) py_type; } } else { cls_decl.set_data (gsi::ClientIndex::Python, new PythonClassClientData (&cls_decl, as_static ? NULL : py_type, as_static ? py_type : NULL)); @@ -2475,7 +2475,11 @@ public: PyTypeObject *type = (PyTypeObject *) PyObject_Call ((PyObject *) &PyType_Type, args.get (), NULL); if (type == NULL) { - check_error (); + try { + check_error (); + } catch (tl::Exception &ex) { + tl::error << ex.msg (); + } tl_assert (false); } From cd3ca9e53693cb1815ff144ba68b42225c07de9f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 6 Nov 2022 01:23:39 +0100 Subject: [PATCH 29/29] Do not use zstd compression for Qt6 as there is no built-in decompression --- src/klayout.pri | 5 +++++ src/tl/tl/tlStream.cc | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/klayout.pri b/src/klayout.pri index f70c810ba..0cb25c0ab 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -130,6 +130,11 @@ equals(HAVE_CRONOLOGY, "1") { INCLUDEPATH += $$CRONOLOGY_INCLUDE } +!lessThan(QT_MAJOR_VERSION, 6) { + # internal resource readers to not support zstd so far + QMAKE_RESOURCE_FLAGS += --compress-algo zlib +} + msvc { QMAKE_CXXFLAGS += \ diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 2813a9114..7a9c78df3 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -212,9 +212,9 @@ InputStream::InputStream (const std::string &abstract_path) QByteArray data; #if QT_VERSION >= 0x60000 - if (res.compressionAlgorithm () == QResource::ZlibCompression) { + if (res.compressionAlgorithm () == QResource::ZlibCompression) { #else - if (res.isCompressed ()) { + if (res.isCompressed ()) { #endif data = qUncompress ((const unsigned char *)res.data (), (int)res.size ()); } else {