mirror of https://github.com/KLayout/klayout.git
WIP: callbacks for PCells
This commit is contained in:
parent
879059f830
commit
e6da3fc22c
|
|
@ -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<ParameterStates *> (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<std::string, ParameterState> 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
|
||||
|
|
|
|||
|
|
@ -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<db::PCellParameterDeclaration> 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"
|
||||
|
|
|
|||
|
|
@ -238,13 +238,15 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
|
|||
mp_pcell_decl.reset (const_cast<db::PCellDeclaration *> (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<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::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<QWidget *> ());
|
||||
|
||||
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<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::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<db::PCellParameterDeclaration> &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<tl::Variant> 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<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::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<QLineEdit *> (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<QLineEdit *> (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<QLineEdit *> (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<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
std::vector<std::string> 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<lay::LayerSelectionComboBox *> (m_widgets [r]);
|
||||
if (ly) {
|
||||
ps.set_value (tl::Variant (ly->current_layer_props ()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case db::PCellParameterDeclaration::t_boolean:
|
||||
{
|
||||
QCheckBox *cbx = dynamic_cast<QCheckBox *> (m_widgets [r]);
|
||||
if (cbx) {
|
||||
ps.set_value (tl::Variant (cbx->isChecked ()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
QComboBox *cb = dynamic_cast<QComboBox*> (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<tl::Variant>
|
||||
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<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::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<QLineEdit *> (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<QLineEdit *> (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<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
parameters.back () = tl::Variant (tl::to_string (le->text ()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_list:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
std::vector<std::string> 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<lay::LayerSelectionComboBox *> (m_widgets [r]);
|
||||
if (ly) {
|
||||
parameters.back () = tl::Variant (ly->current_layer_props ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case db::PCellParameterDeclaration::t_boolean:
|
||||
{
|
||||
QCheckBox *cbx = dynamic_cast<QCheckBox *> (m_widgets [r]);
|
||||
if (cbx) {
|
||||
parameters.back () = tl::Variant (cbx->isChecked ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
QComboBox *cb = dynamic_cast<QComboBox*> (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<db::PCellParameterDeclaration>::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<tl::Variant> ¶meters)
|
||||
{
|
||||
m_parameters = parameters;
|
||||
if (! mp_pcell_decl) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t r = 0;
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,12 +103,10 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Gets the initial parameters
|
||||
*
|
||||
* The initial parameters are the ones present on "setup".
|
||||
*/
|
||||
const std::vector<tl::Variant> &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<db::PCellDeclaration> mp_pcell_decl;
|
||||
std::vector<QWidget *> m_widgets;
|
||||
std::vector<std::vector<QWidget *> > m_all_widgets;
|
||||
lay::LayoutViewBase *mp_view;
|
||||
int m_cv_index;
|
||||
db::pcell_parameters_type m_parameters;
|
||||
bool m_dense;
|
||||
tl::DeferredMethod<PCellParametersPage> dm_parameter_changed;
|
||||
std::vector<tl::Variant> m_current_parameters;
|
||||
std::vector<tl::Variant> 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<tl::Variant> &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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue