mirror of
https://github.com/KLayout/klayout.git
synced 2026-08-22 14:07:15 +02:00
Merge pull request #953 from KLayout/lazy-pcell-evaluation
Lazy pcell evaluation
This commit is contained in:
@@ -429,6 +429,17 @@ public:
|
|||||||
return db::Trans ();
|
return db::Trans ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a value indicating that the PCell wants lazy evaluation
|
||||||
|
*
|
||||||
|
* In lazy evaluation mode, the PCell is not immediately updated when a parameter is changed in the UI, but only when it is requested
|
||||||
|
* to be updated.
|
||||||
|
*/
|
||||||
|
virtual bool wants_lazy_evaluation () const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the Layout object the PCell is registered inside or NULL if it is not registered
|
* @brief Gets the Layout object the PCell is registered inside or NULL if it is not registered
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ Class<db::PCellDeclaration> decl_PCellDeclaration_Native ("db", "PCellDeclaratio
|
|||||||
gsi::method ("can_create_from_shape", &db::PCellDeclaration::can_create_from_shape) +
|
gsi::method ("can_create_from_shape", &db::PCellDeclaration::can_create_from_shape) +
|
||||||
gsi::method ("parameters_from_shape", &db::PCellDeclaration::parameters_from_shape) +
|
gsi::method ("parameters_from_shape", &db::PCellDeclaration::parameters_from_shape) +
|
||||||
gsi::method ("transformation_from_shape", &db::PCellDeclaration::transformation_from_shape) +
|
gsi::method ("transformation_from_shape", &db::PCellDeclaration::transformation_from_shape) +
|
||||||
|
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::method ("layout", &db::PCellDeclaration::layout,
|
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"
|
"@brief Gets the Layout object the PCell is registered in or nil if it is not registered yet.\n"
|
||||||
@@ -407,6 +408,20 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wants_lazy_evaluation_fb () const
|
||||||
|
{
|
||||||
|
return db::PCellDeclaration::wants_lazy_evaluation ();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool wants_lazy_evaluation () const
|
||||||
|
{
|
||||||
|
if (cb_wants_lazy_evaluation.can_issue ()) {
|
||||||
|
return cb_wants_lazy_evaluation.issue<db::PCellDeclaration, bool> (&db::PCellDeclaration::wants_lazy_evaluation);
|
||||||
|
} else {
|
||||||
|
return db::PCellDeclaration::wants_lazy_evaluation ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string get_display_name_fb (const db::pcell_parameters_type ¶meters) const
|
std::string get_display_name_fb (const db::pcell_parameters_type ¶meters) const
|
||||||
{
|
{
|
||||||
return db::PCellDeclaration::get_display_name (parameters);
|
return db::PCellDeclaration::get_display_name (parameters);
|
||||||
@@ -427,6 +442,7 @@ public:
|
|||||||
gsi::Callback cb_can_create_from_shape;
|
gsi::Callback cb_can_create_from_shape;
|
||||||
gsi::Callback cb_parameters_from_shape;
|
gsi::Callback cb_parameters_from_shape;
|
||||||
gsi::Callback cb_transformation_from_shape;
|
gsi::Callback cb_transformation_from_shape;
|
||||||
|
gsi::Callback cb_wants_lazy_evaluation;
|
||||||
gsi::Callback cb_coerce_parameters;
|
gsi::Callback cb_coerce_parameters;
|
||||||
gsi::Callback cb_get_display_name;
|
gsi::Callback cb_get_display_name;
|
||||||
};
|
};
|
||||||
@@ -507,6 +523,16 @@ Class<PCellDeclarationImpl> decl_PCellDeclaration (decl_PCellDeclaration_Native,
|
|||||||
"it will use this method to derive the transformation for the PCell instance that will replace the shape. "
|
"it will use this method to derive the transformation for the PCell instance that will replace the shape. "
|
||||||
"See also \\parameters_from_shape and \\can_create_from_shape."
|
"See also \\parameters_from_shape and \\can_create_from_shape."
|
||||||
) +
|
) +
|
||||||
|
gsi::callback ("wants_lazy_evaluation", &PCellDeclarationImpl::wants_lazy_evaluation, &PCellDeclarationImpl::cb_wants_lazy_evaluation,
|
||||||
|
"@brief Gets a value indicating whether the PCell wants lazy evaluation\n"
|
||||||
|
"In lazy evaluation mode, the PCell UI will not immediately update the layout when a parameter is changed. "
|
||||||
|
"Instead, the user has to commit the changes in order to have the parameters updated. This is "
|
||||||
|
"useful for PCells that take a long time to compute.\n"
|
||||||
|
"\n"
|
||||||
|
"The default implementation will return 'false' indicating immediate updates.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been added in version 0.27.6.\n"
|
||||||
|
) +
|
||||||
gsi::callback ("display_text", &PCellDeclarationImpl::get_display_name, &PCellDeclarationImpl::cb_get_display_name, gsi::arg ("parameters"),
|
gsi::callback ("display_text", &PCellDeclarationImpl::get_display_name, &PCellDeclarationImpl::cb_get_display_name, gsi::arg ("parameters"),
|
||||||
"@brief Returns the display text for this PCell given a certain parameter set\n"
|
"@brief Returns the display text for this PCell given a certain parameter set\n"
|
||||||
"Reimplement this method to create a distinct display text for a PCell variant with \n"
|
"Reimplement this method to create a distinct display text for a PCell variant with \n"
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget,
|
|||||||
db::LayerProperties lp;
|
db::LayerProperties lp;
|
||||||
if (value.is_user<db::LayerProperties> ()) {
|
if (value.is_user<db::LayerProperties> ()) {
|
||||||
lp = value.to_user<db::LayerProperties> ();
|
lp = value.to_user<db::LayerProperties> ();
|
||||||
|
} else if (value.is_nil ()) {
|
||||||
|
// empty LayerProperties
|
||||||
} else {
|
} else {
|
||||||
std::string s = value.to_string ();
|
std::string s = value.to_string ();
|
||||||
tl::Extractor ex (s.c_str ());
|
tl::Extractor ex (s.c_str ());
|
||||||
@@ -154,6 +156,9 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense)
|
|||||||
void
|
void
|
||||||
PCellParametersPage::init ()
|
PCellParametersPage::init ()
|
||||||
{
|
{
|
||||||
|
QPalette palette;
|
||||||
|
QFont font;
|
||||||
|
|
||||||
mp_pcell_decl.reset (0);
|
mp_pcell_decl.reset (0);
|
||||||
mp_view = 0;
|
mp_view = 0;
|
||||||
m_cv_index = 0;
|
m_cv_index = 0;
|
||||||
@@ -162,24 +167,69 @@ PCellParametersPage::init ()
|
|||||||
QGridLayout *frame_layout = new QGridLayout (this);
|
QGridLayout *frame_layout = new QGridLayout (this);
|
||||||
// spacing and margin for tool windows
|
// spacing and margin for tool windows
|
||||||
frame_layout->setMargin (0);
|
frame_layout->setMargin (0);
|
||||||
|
frame_layout->setVerticalSpacing (0);
|
||||||
setLayout (frame_layout);
|
setLayout (frame_layout);
|
||||||
|
|
||||||
mp_error_icon = new QLabel (this);
|
mp_update_frame = new QFrame ();
|
||||||
mp_error_icon->setPixmap (QPixmap (":/warn.png"));
|
mp_update_frame->setFrameShape (QFrame::NoFrame);
|
||||||
mp_error_icon->hide ();
|
frame_layout->addWidget (mp_update_frame, 0, 0, 1, 1);
|
||||||
frame_layout->addWidget (mp_error_icon, 1, 0, 1, 1);
|
|
||||||
|
|
||||||
mp_error_label = new QLabel (this);
|
QGridLayout *update_frame_layout = new QGridLayout (mp_update_frame);
|
||||||
|
mp_update_frame->setLayout (update_frame_layout);
|
||||||
|
if (m_dense) {
|
||||||
|
update_frame_layout->setMargin (4);
|
||||||
|
update_frame_layout->setHorizontalSpacing (6);
|
||||||
|
update_frame_layout->setVerticalSpacing (2);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_changed_icon = new QLabel (mp_update_frame);
|
||||||
|
mp_changed_icon->setPixmap (QPixmap (":/warn.png"));
|
||||||
|
update_frame_layout->addWidget (mp_changed_icon, 0, 0, 1, 1);
|
||||||
|
|
||||||
|
mp_update_button = new QToolButton (mp_update_frame);
|
||||||
|
mp_update_button->setText (tr ("Update"));
|
||||||
|
connect (mp_update_button, SIGNAL (clicked()), this, SLOT (update_button_pressed ()));
|
||||||
|
update_frame_layout->addWidget (mp_update_button, 0, 1, 1, 1);
|
||||||
|
|
||||||
|
mp_changed_label = new QLabel (mp_update_frame);
|
||||||
|
mp_changed_label->setText (tr ("Update needed"));
|
||||||
|
update_frame_layout->addWidget (mp_changed_label, 0, 2, 1, 1);
|
||||||
|
|
||||||
|
update_frame_layout->setColumnStretch (2, 1);
|
||||||
|
|
||||||
|
mp_error_frame = new QFrame ();
|
||||||
|
mp_error_frame->setFrameShape (QFrame::NoFrame);
|
||||||
|
frame_layout->addWidget (mp_error_frame, 1, 0, 1, 1);
|
||||||
|
|
||||||
|
QGridLayout *error_frame_layout = new QGridLayout (mp_update_frame);
|
||||||
|
mp_error_frame->setLayout (error_frame_layout);
|
||||||
|
if (m_dense) {
|
||||||
|
error_frame_layout->setMargin (4);
|
||||||
|
error_frame_layout->setHorizontalSpacing (6);
|
||||||
|
error_frame_layout->setVerticalSpacing (2);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_error_icon = new QLabel (mp_update_frame);
|
||||||
|
mp_error_icon->setPixmap (QPixmap (":/warn.png"));
|
||||||
|
error_frame_layout->addWidget (mp_error_icon, 1, 0, 1, 1);
|
||||||
|
|
||||||
|
mp_error_label = new QLabel (mp_update_frame);
|
||||||
mp_error_label->setWordWrap (true);
|
mp_error_label->setWordWrap (true);
|
||||||
QPalette palette = mp_error_label->palette ();
|
palette = mp_error_label->palette ();
|
||||||
palette.setColor (QPalette::Foreground, Qt::red);
|
palette.setColor (QPalette::Foreground, Qt::red);
|
||||||
mp_error_label->setPalette (palette);
|
mp_error_label->setPalette (palette);
|
||||||
QFont font = mp_error_label->font ();
|
font = mp_error_label->font ();
|
||||||
font.setBold (true);
|
font.setBold (true);
|
||||||
mp_error_label->setFont (font);
|
mp_error_label->setFont (font);
|
||||||
mp_error_label->hide ();
|
error_frame_layout->addWidget (mp_error_label, 1, 1, 1, 2);
|
||||||
frame_layout->addWidget (mp_error_label, 1, 1, 1, 1);
|
|
||||||
frame_layout->setColumnStretch (1, 1);
|
error_frame_layout->setColumnStretch (2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PCellParametersPage::lazy_evaluation ()
|
||||||
|
{
|
||||||
|
return mp_pcell_decl.get () && mp_pcell_decl->wants_lazy_evaluation ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -199,8 +249,8 @@ PCellParametersPage::setup (lay::LayoutView *view, int cv_index, const db::PCell
|
|||||||
mp_parameters_area = new QScrollArea (this);
|
mp_parameters_area = new QScrollArea (this);
|
||||||
mp_parameters_area->setFrameShape (QFrame::NoFrame);
|
mp_parameters_area->setFrameShape (QFrame::NoFrame);
|
||||||
QGridLayout *frame_layout = dynamic_cast<QGridLayout *> (QFrame::layout ());
|
QGridLayout *frame_layout = dynamic_cast<QGridLayout *> (QFrame::layout ());
|
||||||
frame_layout->addWidget (mp_parameters_area, 0, 0, 1, 2);
|
frame_layout->addWidget (mp_parameters_area, 2, 0, 1, 1);
|
||||||
frame_layout->setRowStretch (0, 1);
|
frame_layout->setRowStretch (2, 1);
|
||||||
|
|
||||||
QFrame *fi = new QFrame (mp_parameters_area);
|
QFrame *fi = new QFrame (mp_parameters_area);
|
||||||
QWidget *inner_frame = fi;
|
QWidget *inner_frame = fi;
|
||||||
@@ -396,9 +446,7 @@ PCellParametersPage::setup (lay::LayoutView *view, int cv_index, const db::PCell
|
|||||||
mp_parameters_area->setWidget (main_frame);
|
mp_parameters_area->setWidget (main_frame);
|
||||||
main_frame->show ();
|
main_frame->show ();
|
||||||
|
|
||||||
// does a first coerce and update. Ignore errors for now.
|
update_current_parameters ();
|
||||||
bool ok = false;
|
|
||||||
get_parameters (&ok);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PCellParametersPage::State
|
PCellParametersPage::State
|
||||||
@@ -446,12 +494,33 @@ PCellParametersPage::do_parameter_changed ()
|
|||||||
{
|
{
|
||||||
// does a coerce and update
|
// does a coerce and update
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
get_parameters (&ok);
|
std::vector<tl::Variant> parameters = get_parameters (&ok);
|
||||||
if (ok) {
|
if (ok && ! lazy_evaluation ()) {
|
||||||
emit edited ();
|
emit edited ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PCellParametersPage::update_button_pressed ()
|
||||||
|
{
|
||||||
|
if (update_current_parameters ()) {
|
||||||
|
emit edited ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PCellParametersPage::update_current_parameters ()
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
std::vector<tl::Variant> parameters = get_parameters (&ok);
|
||||||
|
if (ok) {
|
||||||
|
m_current_parameters = parameters;
|
||||||
|
mp_update_frame->hide ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<tl::Variant>
|
std::vector<tl::Variant>
|
||||||
PCellParametersPage::get_parameters (bool *ok)
|
PCellParametersPage::get_parameters (bool *ok)
|
||||||
{
|
{
|
||||||
@@ -594,10 +663,7 @@ PCellParametersPage::get_parameters (bool *ok)
|
|||||||
if (mp_view->cellview (m_cv_index).is_valid ()) {
|
if (mp_view->cellview (m_cv_index).is_valid ()) {
|
||||||
mp_pcell_decl->coerce_parameters (mp_view->cellview (m_cv_index)->layout (), parameters);
|
mp_pcell_decl->coerce_parameters (mp_view->cellview (m_cv_index)->layout (), parameters);
|
||||||
}
|
}
|
||||||
set_parameters (parameters);
|
set_parameters_internal (parameters, lazy_evaluation ());
|
||||||
|
|
||||||
mp_error_label->hide ();
|
|
||||||
mp_error_icon->hide ();
|
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
*ok = true;
|
*ok = true;
|
||||||
@@ -608,8 +674,7 @@ PCellParametersPage::get_parameters (bool *ok)
|
|||||||
if (ok) {
|
if (ok) {
|
||||||
mp_error_label->setText (tl::to_qstring (ex.basic_msg ()));
|
mp_error_label->setText (tl::to_qstring (ex.basic_msg ()));
|
||||||
mp_error_label->setToolTip (tl::to_qstring (ex.msg ()));
|
mp_error_label->setToolTip (tl::to_qstring (ex.msg ()));
|
||||||
mp_error_icon->show ();
|
mp_error_frame->show ();
|
||||||
mp_error_label->show ();
|
|
||||||
*ok = false;
|
*ok = false;
|
||||||
} else {
|
} else {
|
||||||
throw;
|
throw;
|
||||||
@@ -619,8 +684,7 @@ PCellParametersPage::get_parameters (bool *ok)
|
|||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
mp_error_label->setText (tl::to_qstring (ex.msg ()));
|
mp_error_label->setText (tl::to_qstring (ex.msg ()));
|
||||||
mp_error_icon->show ();
|
mp_error_frame->show ();
|
||||||
mp_error_label->show ();
|
|
||||||
*ok = false;
|
*ok = false;
|
||||||
} else {
|
} else {
|
||||||
throw;
|
throw;
|
||||||
@@ -633,6 +697,12 @@ PCellParametersPage::get_parameters (bool *ok)
|
|||||||
|
|
||||||
void
|
void
|
||||||
PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
||||||
|
{
|
||||||
|
set_parameters_internal (parameters, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PCellParametersPage::set_parameters_internal (const std::vector<tl::Variant> ¶meters, bool tentatively)
|
||||||
{
|
{
|
||||||
if (! mp_pcell_decl) {
|
if (! mp_pcell_decl) {
|
||||||
return;
|
return;
|
||||||
@@ -646,6 +716,18 @@ PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
|||||||
set_value (*p, m_widgets [r], parameters [r]);
|
set_value (*p, m_widgets [r], parameters [r]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_error_frame->hide ();
|
||||||
|
|
||||||
|
bool update_needed = false;
|
||||||
|
|
||||||
|
if (! tentatively) {
|
||||||
|
m_current_parameters = parameters;
|
||||||
|
} else {
|
||||||
|
update_needed = (m_current_parameters != parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_update_frame->setVisible (update_needed);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
@@ -117,11 +118,16 @@ signals:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void parameter_changed ();
|
void parameter_changed ();
|
||||||
|
void update_button_pressed ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScrollArea *mp_parameters_area;
|
QScrollArea *mp_parameters_area;
|
||||||
QLabel *mp_error_label;
|
QLabel *mp_error_label;
|
||||||
QLabel *mp_error_icon;
|
QLabel *mp_error_icon;
|
||||||
|
QLabel *mp_changed_label;
|
||||||
|
QLabel *mp_changed_icon;
|
||||||
|
QToolButton *mp_update_button;
|
||||||
|
QFrame *mp_error_frame, *mp_update_frame;
|
||||||
tl::weak_ptr<db::PCellDeclaration> mp_pcell_decl;
|
tl::weak_ptr<db::PCellDeclaration> mp_pcell_decl;
|
||||||
std::vector<QWidget *> m_widgets;
|
std::vector<QWidget *> m_widgets;
|
||||||
lay::LayoutView *mp_view;
|
lay::LayoutView *mp_view;
|
||||||
@@ -129,9 +135,13 @@ private:
|
|||||||
db::pcell_parameters_type m_parameters;
|
db::pcell_parameters_type m_parameters;
|
||||||
bool m_dense;
|
bool m_dense;
|
||||||
tl::DeferredMethod<PCellParametersPage> dm_parameter_changed;
|
tl::DeferredMethod<PCellParametersPage> dm_parameter_changed;
|
||||||
|
std::vector<tl::Variant> m_current_parameters;
|
||||||
|
|
||||||
void init ();
|
void init ();
|
||||||
void do_parameter_changed ();
|
void do_parameter_changed ();
|
||||||
|
bool lazy_evaluation ();
|
||||||
|
void set_parameters_internal (const std::vector<tl::Variant> &values, bool tentatively);
|
||||||
|
bool update_current_parameters ();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,13 @@ module PCellLibModule
|
|||||||
# TODO: return a RBA::Trans object for the initial transformation of
|
# TODO: return a RBA::Trans object for the initial transformation of
|
||||||
# the instance
|
# the instance
|
||||||
# end
|
# end
|
||||||
|
#
|
||||||
|
# optional:
|
||||||
|
# def wants_lazy_evaluation
|
||||||
|
# TODO: return "true" here if the PCell takes a long time to compute.
|
||||||
|
# In lazy mode, the user has to acknowledge parameter changes before
|
||||||
|
# they are executed.
|
||||||
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ class PCell(pya.PCellDeclarationHelper):
|
|||||||
# def transformation_from_shape_impl(self):
|
# def transformation_from_shape_impl(self):
|
||||||
# TODO: return a RBA::Trans object for the initial transformation of
|
# TODO: return a RBA::Trans object for the initial transformation of
|
||||||
# the instance
|
# the instance
|
||||||
|
#
|
||||||
|
# optional:
|
||||||
|
# def wants_lazy_evaluation(self):
|
||||||
|
# TODO: return "True" here if the PCell takes a long time to compute.
|
||||||
|
# In lazy mode, the user has to acknowledge parameter changes before
|
||||||
|
# they are executed.
|
||||||
|
|
||||||
# TODO: add more PCell classes ..
|
# TODO: add more PCell classes ..
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user