mirror of https://github.com/KLayout/klayout.git
Klayout PyCell integration
-added tl::optional as derivate of std::optional for c++17 and above, reduced implementation otherwise -fixed missing include for c++17 and above -added range constraints for PCell parameter Signed-off-by: ThomasZecha <zecha@ihp-microelectronics.com>
This commit is contained in:
parent
ef53700baa
commit
eea4344976
|
|
@ -30,6 +30,7 @@
|
|||
#include "dbLayout.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlObject.h"
|
||||
#include "tlOptional.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -69,7 +70,7 @@ public:
|
|||
* @brief The default constructor
|
||||
*/
|
||||
PCellParameterDeclaration ()
|
||||
: m_hidden (false), m_readonly (false), m_type (t_none)
|
||||
: m_hidden (false), m_readonly (false), m_type (t_none), m_range()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -78,7 +79,7 @@ public:
|
|||
* @brief The constructor with a name
|
||||
*/
|
||||
PCellParameterDeclaration (const std::string &name)
|
||||
: m_hidden (false), m_readonly (false), m_type (t_none), m_name (name)
|
||||
: m_hidden (false), m_readonly (false), m_type (t_none), m_name (name), m_range()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -87,7 +88,7 @@ public:
|
|||
* @brief The constructor with a name, type and description
|
||||
*/
|
||||
PCellParameterDeclaration (const std::string &name, type t, const std::string &description)
|
||||
: m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description)
|
||||
: m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description), m_range()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -96,7 +97,7 @@ public:
|
|||
* @brief The constructor with a name, type, description and default value
|
||||
*/
|
||||
PCellParameterDeclaration (const std::string &name, type t, const std::string &description, const tl::Variant &def)
|
||||
: m_default (def), m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description)
|
||||
: m_default (def), m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description), m_range()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -105,7 +106,7 @@ public:
|
|||
* @brief The constructor with a name, type, description, default value and unit
|
||||
*/
|
||||
PCellParameterDeclaration (const std::string &name, type t, const std::string &description, const tl::Variant &def, const std::string &unit)
|
||||
: m_default (def), m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description), m_unit (unit)
|
||||
: m_default (def), m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description), m_unit (unit), m_range()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -114,7 +115,7 @@ public:
|
|||
* @brief The constructor with a name, type and description and choice values / choice descriptions
|
||||
*/
|
||||
PCellParameterDeclaration (const std::string &name, type t, const std::string &description, const std::vector<tl::Variant> &choices, const std::vector<std::string> &choice_descriptions)
|
||||
: m_choices (choices), m_choice_descriptions (choice_descriptions), m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description)
|
||||
: m_choices (choices), m_choice_descriptions (choice_descriptions), m_hidden (false), m_readonly (false), m_type (t), m_name (name), m_description (description), m_range()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -248,6 +249,53 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief A enum describing the action of range violated
|
||||
*/
|
||||
enum Action {
|
||||
t_Reject = 1, // reject the parameter
|
||||
t_Accept, // accept the parameter
|
||||
t_Use_Default // use a default parameter (currently not supported)
|
||||
};
|
||||
|
||||
void set_range (const tl::Variant& low, const tl::Variant& high, const tl::Variant& resolution, Action action = t_Reject)
|
||||
{
|
||||
m_range = Range(low, high, resolution, action);
|
||||
}
|
||||
|
||||
typedef struct _Range {
|
||||
_Range() :
|
||||
m_low(),
|
||||
m_high(),
|
||||
m_resolution(),
|
||||
m_action(t_Reject) {}
|
||||
|
||||
_Range(const tl::Variant& low, const tl::Variant& high, const tl::Variant& resolution, Action action = t_Reject) :
|
||||
m_low(low),
|
||||
m_high(high),
|
||||
m_resolution(resolution),
|
||||
m_action(action) {}
|
||||
|
||||
bool operator== (const _Range& other) const
|
||||
{
|
||||
return
|
||||
m_low == other.m_low &&
|
||||
m_high == other.m_high &&
|
||||
m_resolution == other.m_resolution &&
|
||||
m_action == other.m_action;
|
||||
}
|
||||
|
||||
tl::Variant m_low;
|
||||
tl::Variant m_high;
|
||||
tl::Variant m_resolution;
|
||||
Action m_action;
|
||||
} Range;
|
||||
|
||||
const tl::optional<Range>& get_range() const
|
||||
{
|
||||
return m_range;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter for the choice descriptions
|
||||
*
|
||||
* The choice descriptions correspond to choice values. The descriptions
|
||||
|
|
@ -280,7 +328,8 @@ public:
|
|||
m_type == d.m_type &&
|
||||
m_name == d.m_name &&
|
||||
m_description == d.m_description &&
|
||||
m_unit == d.m_unit;
|
||||
m_unit == d.m_unit &&
|
||||
m_range == d.m_range;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -291,6 +340,7 @@ private:
|
|||
type m_type;
|
||||
std::string m_name;
|
||||
std::string m_description, m_unit;
|
||||
tl::optional<Range> m_range;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbPCellDeclaration.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "tlLog.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
|
@ -719,12 +720,41 @@ void clear_choices (db::PCellParameterDeclaration *pd)
|
|||
|
||||
void add_choice (db::PCellParameterDeclaration *pd, const std::string &d, const tl::Variant &v)
|
||||
{
|
||||
std::vector<tl::Variant> vv = pd->get_choices ();
|
||||
std::vector<std::string> dd = pd->get_choice_descriptions ();
|
||||
vv.push_back (v);
|
||||
dd.push_back (d);
|
||||
pd->set_choice_descriptions (dd);
|
||||
pd->set_choices (vv);
|
||||
if (!pd->get_range().has_value())
|
||||
{
|
||||
std::vector<tl::Variant> vv = pd->get_choices ();
|
||||
std::vector<std::string> dd = pd->get_choice_descriptions ();
|
||||
vv.push_back (v);
|
||||
dd.push_back (d);
|
||||
pd->set_choice_descriptions (dd);
|
||||
pd->set_choices (vv);
|
||||
}
|
||||
else
|
||||
{
|
||||
tl::warn
|
||||
<< "PCell parameter '" << pd->get_name() << "' has a range constraint, could not add choice '"
|
||||
<< v.to_string() << "'";
|
||||
}
|
||||
}
|
||||
|
||||
void set_range (db::PCellParameterDeclaration *pd, const tl::Variant& low, const tl::Variant& high, const tl::Variant& resolution, unsigned int action)
|
||||
{
|
||||
if (pd->get_choices().empty() && pd->get_choice_descriptions().empty())
|
||||
{
|
||||
if ((pd->get_type() == db::PCellParameterDeclaration::t_int
|
||||
|| pd->get_type() == db::PCellParameterDeclaration::t_double) &&
|
||||
!low.is_nil() && low.can_convert_to_double() &&
|
||||
!high.is_nil() && high.can_convert_to_double())
|
||||
{
|
||||
pd->set_range(low, high, resolution, db::PCellParameterDeclaration::Action(action));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tl::warn
|
||||
<< "PCell parameter '" << pd->get_name() << "' has a choice constraint, could not add range '["
|
||||
<< low.to_string() << ", " << high.to_string() << "]'";
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int pd_type_int ()
|
||||
|
|
@ -772,6 +802,21 @@ static unsigned int pd_type_none ()
|
|||
return (unsigned int) db::PCellParameterDeclaration::t_none;
|
||||
}
|
||||
|
||||
static unsigned int pd_action_reject ()
|
||||
{
|
||||
return (unsigned int) db::PCellParameterDeclaration::t_Reject;
|
||||
}
|
||||
|
||||
static unsigned int pd_action_accept ()
|
||||
{
|
||||
return (unsigned int) db::PCellParameterDeclaration::t_Accept;
|
||||
}
|
||||
|
||||
static unsigned int pd_action_use_default ()
|
||||
{
|
||||
return (unsigned int) db::PCellParameterDeclaration::t_Use_Default;
|
||||
}
|
||||
|
||||
db::PCellParameterDeclaration *ctor_pcell_parameter (const std::string &name, unsigned int type, const std::string &description)
|
||||
{
|
||||
db::PCellParameterDeclaration *pd = new db::PCellParameterDeclaration ();
|
||||
|
|
@ -874,6 +919,19 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
|
|||
"This method will add the given value with the given description to the list of\n"
|
||||
"choices. If choices are defined, KLayout will show a drop-down box instead of an\n"
|
||||
"entry field in the parameter user interface.\n"
|
||||
"If a range is already set for this parameter the choice will not be added and a warning message is showed.\n"
|
||||
) +
|
||||
gsi::method_ext ("set_range", &set_range, gsi::arg ("low"), gsi::arg ("high"), gsi::arg ("resolution"), gsi::arg ("action"),
|
||||
"@brief Set a range constraint\n"
|
||||
"This method will set a range constraint to the parameter with 'low' and 'high' as minimum and maximum value.\n"
|
||||
"This range constraint will only be set if the parameter-, the low- and the high-type are numeric.\n"
|
||||
"If a choice is already set for this parameter the range will not be set and a warning message is showed.\n"
|
||||
"The optional parameter 'resolution' will give a desired resolution value (currently not used).\n"
|
||||
"The optional parameter 'action' determines the action to be invoked.\n"
|
||||
"This action can be one of three values: REJECT, ACCEPT, USE_DEFAULT. If this failure action\n"
|
||||
"parameter is not specified, then it will be REJECT by default.\n"
|
||||
"If a range constraint is violated this parameter is marked wrong with violation hint in the\n"
|
||||
"parameter user interface.\n"
|
||||
) +
|
||||
gsi::method ("choice_values", &db::PCellParameterDeclaration::get_choices,
|
||||
"@brief Returns a list of choice values\n"
|
||||
|
|
@ -897,7 +955,10 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
|
|||
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\n\nThis code has been introduced in version 0.28.") +
|
||||
gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type")
|
||||
gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type") +
|
||||
gsi::method ("REJECT", &pd_action_reject, "@brief Action type: reject violating parameter") +
|
||||
gsi::method ("ACCEPT", &pd_action_accept, "@brief Action type: accept violating parameter") +
|
||||
gsi::method ("USE_DEFAULT", &pd_action_use_default, "@brief Action type: use default instead violating parameter (currently not supported)")
|
||||
,
|
||||
"@brief A PCell parameter declaration\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -398,6 +398,18 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
|
|||
inner_grid->addWidget (icon_label, row, 0);
|
||||
m_icon_widgets.push_back (icon_label);
|
||||
m_all_widgets.back ().push_back (icon_label);
|
||||
std::string range;
|
||||
|
||||
if (p->get_range().has_value())
|
||||
{
|
||||
const tl::Variant& low(p->get_range().value().m_low);
|
||||
const tl::Variant& high(p->get_range().value().m_high);
|
||||
|
||||
range = tl::sprintf(
|
||||
" [%s, %s]" ,
|
||||
low.is_nil() ? "-\u221e" : low.to_string(),
|
||||
high.is_nil() ? "\u221e" : high.to_string());
|
||||
}
|
||||
|
||||
if (p->get_type () != db::PCellParameterDeclaration::t_callback) {
|
||||
|
||||
|
|
@ -406,7 +418,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
|
|||
leader = tl::sprintf ("[%s] ", p->get_name ());
|
||||
}
|
||||
|
||||
QLabel *l = new QLabel (tl::to_qstring (leader + description), inner_frame);
|
||||
QLabel *l = new QLabel (tl::to_qstring (leader + description + range), inner_frame);
|
||||
|
||||
inner_grid->addWidget (l, row, 1);
|
||||
m_all_widgets.back ().push_back (l);
|
||||
|
||||
|
|
@ -762,6 +775,11 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool
|
|||
ps.set_value (tl::Variant (v));
|
||||
lay::indicate_error (le, (tl::Exception *) 0);
|
||||
|
||||
if (p->get_range().has_value())
|
||||
{
|
||||
check_range(tl::Variant(v), p->get_range().value());
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
lay::indicate_error (le, &ex);
|
||||
|
|
@ -786,6 +804,11 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool
|
|||
ps.set_value (tl::Variant (v));
|
||||
lay::indicate_error (le, (tl::Exception *) 0);
|
||||
|
||||
if (p->get_range().has_value())
|
||||
{
|
||||
check_range(tl::Variant(v), p->get_range().value());
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
lay::indicate_error (le, &ex);
|
||||
|
|
@ -1085,6 +1108,23 @@ PCellParametersPage::states_from_parameters (db::ParameterStates &states, const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PCellParametersPage::check_range(const tl::Variant& value, const db::PCellParameterDeclaration::Range& range)
|
||||
{
|
||||
if (db::PCellParameterDeclaration::Action(range.m_action) == db::PCellParameterDeclaration::t_Reject)
|
||||
{
|
||||
if (!range.m_low.is_nil() && value < range.m_low)
|
||||
{
|
||||
throw tl::Exception(tl::to_string (tr("Range violation: value < low")));
|
||||
}
|
||||
|
||||
if (!range.m_high.is_nil() && range.m_high < value)
|
||||
{
|
||||
throw tl::Exception(tl::to_string (tr("Range violation: value > high")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ private:
|
|||
void get_parameters_internal (db::ParameterStates &states, bool &edit_error);
|
||||
std::vector<tl::Variant> parameter_from_states (const db::ParameterStates &states) const;
|
||||
void states_from_parameters (db::ParameterStates &states, const std::vector<tl::Variant> ¶meters);
|
||||
void check_range(const tl::Variant& value, const db::PCellParameterDeclaration::Range& range);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
#include <QString>
|
||||
|
|
|
|||
|
|
@ -36569,6 +36569,18 @@ class PCellParameterDeclaration:
|
|||
r"""
|
||||
@brief Type code: string data
|
||||
"""
|
||||
REJECT: ClassVar[int]
|
||||
r"""
|
||||
@brief Action type: reject violating parameter
|
||||
"""
|
||||
ACCEPT: ClassVar[int]
|
||||
r"""
|
||||
@brief Action type: accept violating parameter
|
||||
"""
|
||||
USE_DEFAULT: ClassVar[int]
|
||||
r"""
|
||||
@brief Action type: use default instead violating parameter (currently not supported)
|
||||
"""
|
||||
default: Any
|
||||
r"""
|
||||
Getter:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ SOURCES = \
|
|||
tlEquivalenceClusters.cc \
|
||||
tlUniqueName.cc \
|
||||
tlRecipe.cc \
|
||||
tlEnv.cc
|
||||
tlEnv.cc \
|
||||
tlOptional.cc
|
||||
|
||||
HEADERS = \
|
||||
tlAlgorithm.h \
|
||||
|
|
@ -121,7 +122,8 @@ HEADERS = \
|
|||
tlUniqueName.h \
|
||||
tlRecipe.h \
|
||||
tlSelect.h \
|
||||
tlEnv.h
|
||||
tlEnv.h \
|
||||
tlOptional.h
|
||||
|
||||
equals(HAVE_GIT2, "1") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "tlOptional.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
extern const nullopt_t nullopt = nullopt_t();
|
||||
#endif
|
||||
|
||||
} // namespace tl
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_tlOptional
|
||||
#define HDR_tlOptional
|
||||
|
||||
#include "tlAssert.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
|
||||
template<typename T>
|
||||
class optional : public std::optional<T> {};
|
||||
|
||||
#else
|
||||
|
||||
struct nullopt_t {};
|
||||
|
||||
extern const nullopt_t nullopt;
|
||||
|
||||
/*
|
||||
* Poor man's partly implementation of C++17's std::optional
|
||||
*/
|
||||
template<typename T>
|
||||
class optional
|
||||
{
|
||||
public:
|
||||
optional() :
|
||||
a_value(),
|
||||
a_isValid(false)
|
||||
{}
|
||||
|
||||
optional(const nullopt_t&) :
|
||||
a_value(),
|
||||
a_isValid(false)
|
||||
{}
|
||||
|
||||
optional(const T &value) :
|
||||
a_value(value),
|
||||
a_isValid(true)
|
||||
{}
|
||||
|
||||
void reset()
|
||||
{
|
||||
a_isValid = false;
|
||||
}
|
||||
|
||||
bool has_value() const { return a_isValid; }
|
||||
|
||||
T &value()
|
||||
{
|
||||
tl_assert(a_isValid);
|
||||
|
||||
return a_value;
|
||||
}
|
||||
|
||||
const T &value() const
|
||||
{
|
||||
tl_assert(a_isValid);
|
||||
|
||||
return a_value;
|
||||
}
|
||||
|
||||
T& operator* ()
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
const T& operator* () const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
T* operator-> ()
|
||||
{
|
||||
return &value();
|
||||
}
|
||||
|
||||
const T* operator-> () const
|
||||
{
|
||||
return &value();
|
||||
}
|
||||
|
||||
private:
|
||||
T a_value;
|
||||
bool a_isValid;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
optional<T> make_optional(const T& value)
|
||||
{
|
||||
return optional<T>(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const optional<T> &lhs, const optional<T> &rhs)
|
||||
{
|
||||
if (lhs.has_value() != rhs.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lhs.has_value())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return lhs.value() == rhs.value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator!=(const optional<T> &lhs, const optional<T> &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream &operator<<(std::ostream &ostr, const optional<T> &rhs)
|
||||
{
|
||||
if (rhs.has_value())
|
||||
{
|
||||
ostr << rhs.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
ostr << "<invalid>";
|
||||
}
|
||||
|
||||
return ostr;
|
||||
}
|
||||
|
||||
#endif /* __cplusplus >= 201703L */
|
||||
|
||||
} // namespace tl
|
||||
|
||||
#endif /* HDR_tlOptional */
|
||||
Loading…
Reference in New Issue