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); }; }