mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into devel
This commit is contained in:
commit
33b54f3f88
|
|
@ -1,3 +1,12 @@
|
|||
0.29.11 (2025-01-17):
|
||||
* Bug: %GITHUB%/issues/1948 Crash by instantiate a Cell in a Library-Cell
|
||||
* Bug: %GITHUB%/issues/1953 Callback_impl & coerce_parameters_impl parameter display issue
|
||||
* Bug: %GITHUB%/issues/1955 Locked layout after certain operations
|
||||
* Bug: %GITHUB%/issues/1959 Color corrections not working properly for images with color mapping / float values
|
||||
* Enhancement: %GITHUB%/issues/1963 Add lock to Cell
|
||||
* Bug: %GITHUB%/issues/1967 Possible net tracer bug in point-and-click net trace
|
||||
* Enhancement: %GITHUB%/issues/1971 Suppress warnings written with tl::warn from Python
|
||||
|
||||
0.29.10 (2024-12-03):
|
||||
* Bug: %GITHUB%/issues/1941 Crash with the navigator open
|
||||
* Bug: %GITHUB%/issues/1942 Syntax error in pyi stubs
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
klayout (0.29.11-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Fri, 17 Jan 2025 10:20:14 +0100
|
||||
|
||||
klayout (0.29.10-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Cell::box_type Cell::ms_empty_box = Cell::box_type ();
|
|||
Cell::Cell (cell_index_type ci, db::Layout &l)
|
||||
: db::Object (l.manager ()),
|
||||
m_cell_index (ci), mp_layout (&l), m_instances (this), m_prop_id (0), m_hier_levels (0),
|
||||
m_bbox_needs_update (false), m_ghost_cell (false),
|
||||
m_bbox_needs_update (false), m_locked (false), m_ghost_cell (false),
|
||||
mp_last (0), mp_next (0)
|
||||
{
|
||||
// .. nothing yet
|
||||
|
|
@ -125,6 +125,7 @@ Cell::operator= (const Cell &d)
|
|||
}
|
||||
|
||||
m_ghost_cell = d.m_ghost_cell;
|
||||
m_locked = d.m_locked;
|
||||
m_instances = d.m_instances;
|
||||
m_bbox = d.m_bbox;
|
||||
m_bboxes = d.m_bboxes;
|
||||
|
|
@ -138,6 +139,7 @@ Cell::operator= (const Cell &d)
|
|||
|
||||
Cell::~Cell ()
|
||||
{
|
||||
m_locked = false;
|
||||
clear_shapes ();
|
||||
}
|
||||
|
||||
|
|
@ -180,6 +182,8 @@ Cell::empty () const
|
|||
void
|
||||
Cell::clear (unsigned int index)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
shapes_map::iterator s = m_shapes_map.find(index);
|
||||
if (s != m_shapes_map.end() && ! s->second.empty ()) {
|
||||
mp_layout->invalidate_bboxes (index); // HINT: must come before the change is done!
|
||||
|
|
@ -191,6 +195,8 @@ Cell::clear (unsigned int index)
|
|||
void
|
||||
Cell::clear (unsigned int index, unsigned int types)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
shapes_map::iterator s = m_shapes_map.find(index);
|
||||
if (s != m_shapes_map.end() && ! s->second.empty ()) {
|
||||
mp_layout->invalidate_bboxes (index); // HINT: must come before the change is done!
|
||||
|
|
@ -241,6 +247,8 @@ Cell::index_of_shapes (const Cell::shapes_type *shapes) const
|
|||
void
|
||||
Cell::clear_shapes ()
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
mp_layout->invalidate_bboxes (std::numeric_limits<unsigned int>::max ()); // HINT: must come before the change is done!
|
||||
clear_shapes_no_invalidate ();
|
||||
}
|
||||
|
|
@ -345,6 +353,8 @@ Cell::update_bbox (unsigned int layers)
|
|||
void
|
||||
Cell::copy (unsigned int src, unsigned int dest)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
if (src != dest) {
|
||||
shapes (dest).insert (shapes (src));
|
||||
} else {
|
||||
|
|
@ -359,6 +369,8 @@ Cell::copy (unsigned int src, unsigned int dest)
|
|||
void
|
||||
Cell::copy (unsigned int src, unsigned int dest, unsigned int types)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
if (src != dest) {
|
||||
shapes (dest).insert (shapes (src), types);
|
||||
} else {
|
||||
|
|
@ -373,6 +385,8 @@ Cell::copy (unsigned int src, unsigned int dest, unsigned int types)
|
|||
void
|
||||
Cell::move (unsigned int src, unsigned int dest)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
if (src != dest) {
|
||||
copy (src, dest);
|
||||
clear (src);
|
||||
|
|
@ -382,6 +396,8 @@ Cell::move (unsigned int src, unsigned int dest)
|
|||
void
|
||||
Cell::move (unsigned int src, unsigned int dest, unsigned int types)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
if (src != dest) {
|
||||
copy (src, dest, types);
|
||||
clear (src, types);
|
||||
|
|
@ -391,6 +407,8 @@ Cell::move (unsigned int src, unsigned int dest, unsigned int types)
|
|||
void
|
||||
Cell::swap (unsigned int i1, unsigned int i2)
|
||||
{
|
||||
check_locked ();
|
||||
|
||||
if (i1 != i2) {
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
|
|
@ -787,6 +805,14 @@ Cell::set_name (const std::string &name)
|
|||
layout ()->rename_cell (cell_index (), name.c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
Cell::check_locked () const
|
||||
{
|
||||
if (m_locked) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell '%s' cannot be modified as it is locked")), get_basic_name ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::copy_shapes (const db::Cell &source_cell, const db::LayerMapping &layer_mapping)
|
||||
{
|
||||
|
|
@ -803,6 +829,8 @@ Cell::copy_shapes (const db::Cell &source_cell, const db::LayerMapping &layer_ma
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
if (target_layout != source_layout) {
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
|
||||
|
|
@ -826,6 +854,8 @@ Cell::copy_shapes (const db::Cell &source_cell)
|
|||
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
if (target_layout != source_cell.layout ()) {
|
||||
if (! source_cell.layout ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
|
|
@ -850,6 +880,8 @@ Cell::copy_instances (const db::Cell &source_cell)
|
|||
throw tl::Exception (tl::to_string (tr ("Cells do not reside in the same layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
for (db::Cell::const_iterator i = source_cell.begin (); ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
|
|
@ -871,6 +903,8 @@ Cell::copy_tree (const db::Cell &source_cell)
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
|
||||
db::CellMapping cm;
|
||||
|
|
@ -902,6 +936,8 @@ Cell::copy_tree_shapes (const db::Cell &source_cell, const db::CellMapping &cm)
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
|
||||
db::LayerMapping lm;
|
||||
|
|
@ -928,6 +964,8 @@ Cell::copy_tree_shapes (const db::Cell &source_cell, const db::CellMapping &cm,
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
|
||||
std::vector <db::cell_index_type> source_cells;
|
||||
|
|
@ -951,6 +989,8 @@ Cell::move_shapes (db::Cell &source_cell, const db::LayerMapping &layer_mapping)
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
if (target_layout != source_layout) {
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
|
||||
|
|
@ -976,6 +1016,8 @@ Cell::move_shapes (db::Cell &source_cell)
|
|||
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
if (target_layout != source_cell.layout ()) {
|
||||
if (! source_cell.layout ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
|
|
@ -1001,6 +1043,8 @@ Cell::move_instances (db::Cell &source_cell)
|
|||
throw tl::Exception (tl::to_string (tr ("Cells do not reside in the same layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
for (db::Cell::const_iterator i = source_cell.begin (); ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
|
|
@ -1024,6 +1068,8 @@ Cell::move_tree (db::Cell &source_cell)
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
|
||||
db::CellMapping cm;
|
||||
|
|
@ -1057,6 +1103,8 @@ Cell::move_tree_shapes (db::Cell &source_cell, const db::CellMapping &cm)
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
|
||||
db::LayerMapping lm;
|
||||
|
|
@ -1083,6 +1131,8 @@ Cell::move_tree_shapes (db::Cell &source_cell, const db::CellMapping &cm, const
|
|||
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
|
||||
}
|
||||
|
||||
check_locked ();
|
||||
|
||||
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
|
||||
|
||||
std::vector <db::cell_index_type> source_cells;
|
||||
|
|
|
|||
|
|
@ -831,6 +831,13 @@ public:
|
|||
*/
|
||||
virtual void update (ImportLayerMapping * /*layer_mapping*/ = 0) { }
|
||||
|
||||
/**
|
||||
* @brief Checks if the cell is locked
|
||||
*
|
||||
* This method throws an exception if the cell is locked.
|
||||
*/
|
||||
void check_locked () const;
|
||||
|
||||
/**
|
||||
* @brief Tell, if this cell is a proxy cell
|
||||
*
|
||||
|
|
@ -902,6 +909,27 @@ public:
|
|||
m_ghost_cell = g;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the cell is locked
|
||||
*
|
||||
* A locked cell cannot be modified in terms of instances or shapes.
|
||||
* The name of a locked cell can be changed though.
|
||||
*/
|
||||
bool is_locked () const
|
||||
{
|
||||
return m_locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the locked state of the cell
|
||||
*
|
||||
* See \is_locked for details about locked state.
|
||||
*/
|
||||
void set_locked (bool f)
|
||||
{
|
||||
m_locked = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the cell is empty
|
||||
*
|
||||
|
|
@ -1075,8 +1103,9 @@ private:
|
|||
db::properties_id_type m_prop_id;
|
||||
|
||||
// packed fields
|
||||
unsigned int m_hier_levels : 30;
|
||||
unsigned int m_hier_levels : 29;
|
||||
bool m_bbox_needs_update : 1;
|
||||
bool m_locked : 1;
|
||||
bool m_ghost_cell : 1;
|
||||
|
||||
static box_type ms_empty_box;
|
||||
|
|
|
|||
|
|
@ -1035,8 +1035,10 @@ Instances::layout () const
|
|||
void
|
||||
Instances::invalidate_insts ()
|
||||
{
|
||||
if (cell ()) {
|
||||
cell ()->invalidate_insts ();
|
||||
db::Cell *cp = cell ();
|
||||
if (cp) {
|
||||
cp->check_locked ();
|
||||
cp->invalidate_insts ();
|
||||
}
|
||||
|
||||
set_instance_by_cell_index_needs_made (true);
|
||||
|
|
|
|||
|
|
@ -867,6 +867,7 @@ Layout::delete_cells (const std::set<cell_index_type> &cells_to_delete)
|
|||
std::set <cell_index_type> pcs;
|
||||
for (std::set<cell_index_type>::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) {
|
||||
const db::Cell &cref = cell (*c);
|
||||
cref.check_locked ();
|
||||
for (db::Cell::parent_cell_iterator pc = cref.begin_parent_cells (); pc != cref.end_parent_cells (); ++pc) {
|
||||
pcs.insert (*pc);
|
||||
}
|
||||
|
|
@ -944,6 +945,7 @@ void
|
|||
Layout::delete_cell (cell_index_type id)
|
||||
{
|
||||
db::Cell &cref = cell (id);
|
||||
cref.check_locked ();
|
||||
|
||||
std::vector <cell_index_type> pcs;
|
||||
for (db::Cell::parent_cell_iterator pc = cref.begin_parent_cells (); pc != cref.end_parent_cells (); ++pc) {
|
||||
|
|
@ -1134,6 +1136,8 @@ Layout::flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::I
|
|||
void
|
||||
Layout::flatten (db::Cell &cell_to_flatten, int levels, bool prune)
|
||||
{
|
||||
cell_to_flatten.check_locked ();
|
||||
|
||||
std::set<db::cell_index_type> direct_children;
|
||||
if (prune) {
|
||||
// save direct children
|
||||
|
|
|
|||
|
|
@ -297,12 +297,16 @@ Shapes::array_repository () const
|
|||
void
|
||||
Shapes::invalidate_state ()
|
||||
{
|
||||
db::Cell *cp = cell ();
|
||||
if (cp) {
|
||||
cp->check_locked ();
|
||||
}
|
||||
if (! is_dirty ()) {
|
||||
set_dirty (true);
|
||||
if (layout () && cell ()) {
|
||||
unsigned int index = cell ()->index_of_shapes (this);
|
||||
if (cp && cp->layout ()) {
|
||||
unsigned int index = cp->index_of_shapes (this);
|
||||
if (index != std::numeric_limits<unsigned int>::max ()) {
|
||||
layout ()->invalidate_bboxes (index);
|
||||
cp->layout ()->invalidate_bboxes (index);
|
||||
}
|
||||
// property ID change is implied
|
||||
layout ()->invalidate_prop_ids ();
|
||||
|
|
|
|||
|
|
@ -2863,6 +2863,28 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"@return A list of cell indices.\n"
|
||||
) +
|
||||
gsi::method ("is_locked?", &db::Cell::is_locked,
|
||||
"@brief Gets a value indicating whether the cell is locked\n"
|
||||
"\n"
|
||||
"Locked cells cannot be modified in terms of instances (children) and shapes. "
|
||||
"Locked cells can still be renamed, but cannot be deleted or cleared.\n"
|
||||
"Among other things, these features are disabled too: layer operations, copy of instances or shapes, "
|
||||
"flattening or pruning.\n"
|
||||
"\n"
|
||||
"However, wiping the layout entirely with \\Layout#clear is always possible, even if cells are locked.\n"
|
||||
"\n"
|
||||
"Use \\locked= to set the locked state of the cell.\n"
|
||||
"\n"
|
||||
"The lock feature has been introduced in version 0.29.11."
|
||||
) +
|
||||
gsi::method ("locked=", &db::Cell::set_locked, gsi::arg ("l"),
|
||||
"@brief Locks or unlocks the cell\n"
|
||||
"\n"
|
||||
"Set this predicate to 'true' to lock the cell and to 'false' to unlock it.\n"
|
||||
"See \\is_locked? for details about the lock feature.\n"
|
||||
"\n"
|
||||
"The lock feature has been introduced in version 0.29.11."
|
||||
) +
|
||||
gsi::method ("bbox", (const db::Cell::box_type &(db::Cell::*) () const) &db::Cell::bbox,
|
||||
"@brief Gets the bounding box of the cell\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -105,11 +105,14 @@ Class<Logger> decl_Logger ("tl", "Logger",
|
|||
"Level 0 is silent, levels 10, 20, 30 etc. denote levels with increasing verbosity. "
|
||||
"11, 21, 31 .. are sublevels which also enable timing logs in addition to messages."
|
||||
) +
|
||||
gsi::method ("verbosity=", &Logger::set_verbosity, gsi::arg ("v"),
|
||||
gsi::method ("verbosity=|set_verbosity", &Logger::set_verbosity, gsi::arg ("v"),
|
||||
"@brief Sets the verbosity level for the application\n"
|
||||
"\n"
|
||||
"See \\verbosity for a definition of the verbosity levels. Please note that this method "
|
||||
"changes the verbosity level for the whole application.\n"
|
||||
"\n"
|
||||
"The 'set_verbosity' alias has been introduced in version 0.29.11 as class attributes "
|
||||
"are not always available in Python."
|
||||
),
|
||||
"@brief A logger\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -375,6 +375,18 @@ A *A::a20_get ()
|
|||
return a_inst.get ();
|
||||
}
|
||||
|
||||
static int s_sp = 0;
|
||||
|
||||
int A::sp_i_get ()
|
||||
{
|
||||
return s_sp;
|
||||
}
|
||||
|
||||
void A::sp_i_set (int v)
|
||||
{
|
||||
s_sp = v + 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Implementation of B
|
||||
|
||||
|
|
@ -1253,6 +1265,8 @@ static gsi::Class<A> decl_a ("", "A",
|
|||
gsi::method ("a9b", &A::a9b) +
|
||||
gsi::method ("a20", &A::a20) +
|
||||
gsi::method ("a20_get", &A::a20_get) +
|
||||
gsi::method ("sp_i", &A::sp_i_get) +
|
||||
gsi::method ("sp_i=", &A::sp_i_set) +
|
||||
gsi::method ("to_s", &A::to_s) +
|
||||
gsi::iterator ("a6", &A::a6b, &A::a6e) +
|
||||
gsi::iterator ("a7", &A::a7b, &A::a7e) +
|
||||
|
|
|
|||
|
|
@ -415,6 +415,10 @@ struct A
|
|||
|
||||
std::string to_s () const;
|
||||
|
||||
// static (class) properties
|
||||
static int sp_i_get ();
|
||||
static void sp_i_set (int v);
|
||||
|
||||
// members
|
||||
std::vector<double> m_d;
|
||||
int n;
|
||||
|
|
|
|||
|
|
@ -322,9 +322,6 @@ klayout_main (int &argc, char **argv)
|
|||
|
||||
int v = 0;
|
||||
tl::from_string (argv [++i], v);
|
||||
if (v < 0) {
|
||||
v = 0;
|
||||
}
|
||||
tl::verbosity (v);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,16 @@
|
|||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="verbosity_cbx">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>No warnings, no errors</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>No warnings</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Silent</string>
|
||||
|
|
|
|||
|
|
@ -312,9 +312,6 @@ ApplicationBase::parse_cmd (int &argc, char **argv)
|
|||
|
||||
int v = 0;
|
||||
tl::from_string (args [++i], v);
|
||||
if (v < 0) {
|
||||
v = 0;
|
||||
}
|
||||
tl::verbosity (v);
|
||||
|
||||
} else if (a == "-k" && (i + 1) < argc) {
|
||||
|
|
@ -1065,7 +1062,7 @@ ApplicationBase::usage ()
|
|||
r += tl::to_string (QObject::tr (" -b Batch mode (same as -zz -nc -rx)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -c <config file> Use this configuration file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nc Don't use a configuration file (implies -t)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -d <debug level> Set debug level")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -d <log level> Set log level")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -e Editable mode (allow editing of files)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -ne Readonly mode (editing of files is disabled)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gr <file name> Record GUI test file")) + "\n";
|
||||
|
|
|
|||
|
|
@ -107,9 +107,9 @@ LogReceiver::begin ()
|
|||
// LogFile implementation
|
||||
|
||||
LogFile::LogFile (size_t max_entries, bool register_global)
|
||||
: m_error_receiver (this, 0, &LogFile::add_error),
|
||||
: m_error_receiver (this, -10, &LogFile::add_error),
|
||||
m_warn_receiver (this, 0, &LogFile::add_warn),
|
||||
m_log_receiver (this, 0, &LogFile::add_info),
|
||||
m_log_receiver (this, 10, &LogFile::add_info),
|
||||
m_info_receiver (this, 0, &LogFile::add_info),
|
||||
m_max_entries (max_entries),
|
||||
m_generation_id (0),
|
||||
|
|
@ -347,7 +347,7 @@ LogViewerDialog::LogViewerDialog (QWidget *parent, bool register_global, bool in
|
|||
verbosity_cbx->hide ();
|
||||
verbosity_label->hide ();
|
||||
} else {
|
||||
verbosity_cbx->setCurrentIndex (std::min (4, tl::verbosity () / 10));
|
||||
verbosity_cbx->setCurrentIndex (std::max (-2, std::min (4, tl::verbosity () / 10)) + 2);
|
||||
connect (verbosity_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (verbosity_changed (int)));
|
||||
}
|
||||
|
||||
|
|
@ -371,7 +371,7 @@ LogViewerDialog::LogViewerDialog (QWidget *parent, bool register_global, bool in
|
|||
void
|
||||
LogViewerDialog::verbosity_changed (int index)
|
||||
{
|
||||
tl::verbosity (index * 10 + 1);
|
||||
tl::verbosity ((index - 2) * 10 + 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1454,7 +1454,7 @@ NetTracer::determine_interactions (const db::Polygon &seed, const NetTracerShape
|
|||
db::Polygon::area_type poly_area = seed.area_upper_manhattan_bound ();
|
||||
db::Polygon::area_type box_area = seed.box ().area ();
|
||||
|
||||
if (poly_area == box_area && seed.vertices () == 4) {
|
||||
if (seed.is_box ()) {
|
||||
|
||||
// The polygon is a box
|
||||
determine_interactions (seed.box (), shape, layers, delivery);
|
||||
|
|
|
|||
|
|
@ -394,3 +394,15 @@ TEST(9)
|
|||
run_test (_this, file, tc, db::LayerProperties (8, 0), db::Point (3000, 6800), file_au, "A");
|
||||
}
|
||||
|
||||
// issue #1967
|
||||
TEST(10)
|
||||
{
|
||||
std::string file = "t10.oas.gz";
|
||||
std::string file_au = "t10_net.oas.gz";
|
||||
|
||||
db::NetTracerConnectivity tc;
|
||||
tc.add (connection ("1", "2"));
|
||||
|
||||
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (300000, 7000), file_au, "");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1285,7 +1285,14 @@ property_setter_impl (int mid, PyObject *self, PyObject *value)
|
|||
|
||||
meth->call (obj, arglist, retlist);
|
||||
|
||||
return get_return_value (p, retlist, meth, heap);
|
||||
PyObject *ret = get_return_value (p, retlist, meth, heap);
|
||||
|
||||
if (ret == NULL) {
|
||||
Py_INCREF (Py_None);
|
||||
ret = Py_None;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -426,7 +426,11 @@ public:
|
|||
doc += "\n\n";
|
||||
}
|
||||
doc += (*m)->doc ();
|
||||
mp_module->add_python_doc (*m, tl::sprintf (tl::to_string (tr ("The object exposes a readable attribute '%s'. This is the getter")), name));
|
||||
if (! is_static) {
|
||||
mp_module->add_python_doc (*m, tl::sprintf (tl::to_string (tr ("The object exposes a readable attribute '%s'. This is the getter")), name));
|
||||
} else {
|
||||
mp_module->add_python_doc (*m, tl::sprintf (tl::to_string (tr ("The class exposes a readable attribute '%s'. This is the getter")), name));
|
||||
}
|
||||
}
|
||||
|
||||
for (MethodTableEntry::method_iterator m = begin_setters; m != end_setters; ++m) {
|
||||
|
|
@ -434,7 +438,11 @@ public:
|
|||
doc += "\n\n";
|
||||
}
|
||||
doc += (*m)->doc ();
|
||||
mp_module->add_python_doc (*m, tl::sprintf (tl::to_string (tr ("The object exposes a writable attribute '%s'. This is the setter")), name));
|
||||
if (! is_static) {
|
||||
mp_module->add_python_doc (*m, tl::sprintf (tl::to_string (tr ("The object exposes a writable attribute '%s'. This is the setter")), name));
|
||||
} else {
|
||||
mp_module->add_python_doc (*m, tl::sprintf (tl::to_string (tr ("The class exposes a writable attribute '%s'. This setter may not be available in Python")), name));
|
||||
}
|
||||
}
|
||||
|
||||
PythonRef attr;
|
||||
|
|
|
|||
|
|
@ -832,6 +832,27 @@ class Cell:
|
|||
|
||||
This method has been introduced in version 0.20.
|
||||
"""
|
||||
locked: bool
|
||||
r"""
|
||||
Getter:
|
||||
@brief Gets a value indicating whether the cell is locked
|
||||
|
||||
Locked cells cannot be modified in terms of instances (children) and shapes. Locked cells can still be renamed, but cannot be deleted or cleared.
|
||||
Among other things, these features are disabled too: layer operations, copy of instances or shapes, flattening or pruning.
|
||||
|
||||
However, wiping the layout entirely with \Layout#clear is always possible, even if cells are locked.
|
||||
|
||||
Use \locked= to set the locked state of the cell.
|
||||
|
||||
The lock feature has been introduced in version 0.29.11.
|
||||
Setter:
|
||||
@brief Locks or unlocks the cell
|
||||
|
||||
Set this predicate to 'true' to lock the cell and to 'false' to unlock it.
|
||||
See \is_locked? for details about the lock feature.
|
||||
|
||||
The lock feature has been introduced in version 0.29.11.
|
||||
"""
|
||||
name: str
|
||||
r"""
|
||||
Getter:
|
||||
|
|
@ -1912,6 +1933,20 @@ class Cell:
|
|||
This method has been introduced in version 0.22.
|
||||
"""
|
||||
...
|
||||
def is_locked(self) -> bool:
|
||||
r"""
|
||||
@brief Gets a value indicating whether the cell is locked
|
||||
|
||||
Locked cells cannot be modified in terms of instances (children) and shapes. Locked cells can still be renamed, but cannot be deleted or cleared.
|
||||
Among other things, these features are disabled too: layer operations, copy of instances or shapes, flattening or pruning.
|
||||
|
||||
However, wiping the layout entirely with \Layout#clear is always possible, even if cells are locked.
|
||||
|
||||
Use \locked= to set the locked state of the cell.
|
||||
|
||||
The lock feature has been introduced in version 0.29.11.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def is_pcell_variant(self) -> bool:
|
||||
r"""
|
||||
|
|
@ -30230,11 +30265,11 @@ class Instance:
|
|||
|
||||
Starting with version 0.25 the displacement is of vector type.
|
||||
Setter:
|
||||
@brief Sets the displacement vector for the 'b' axis
|
||||
@brief Sets the displacement vector for the 'b' axis in micrometer units
|
||||
|
||||
If the instance was not an array instance before it is made one.
|
||||
Like \b= with an integer displacement, this method will set the displacement vector but it accepts a vector in micrometer units that is of \DVector type. The vector will be translated to database units internally.
|
||||
|
||||
This method has been introduced in version 0.23. Starting with version 0.25 the displacement is of vector type.
|
||||
This method has been introduced in version 0.25.
|
||||
"""
|
||||
cell: Cell
|
||||
r"""
|
||||
|
|
@ -30408,9 +30443,10 @@ class Instance:
|
|||
@brief Gets the transformation of the instance or the first instance in the array
|
||||
The transformation returned is only valid if the array does not represent a complex transformation array
|
||||
Setter:
|
||||
@brief Sets the transformation of the instance or the first instance in the array
|
||||
@brief Sets the transformation of the instance or the first instance in the array (in micrometer units)
|
||||
This method sets the transformation the same way as \cplx_trans=, but the displacement of this transformation is given in micrometer units. It is internally translated into database units.
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
This method has been introduced in version 0.25.
|
||||
"""
|
||||
@classmethod
|
||||
def new(cls) -> Instance:
|
||||
|
|
@ -41367,15 +41403,15 @@ class NetPinRef:
|
|||
@overload
|
||||
def net(self) -> Net:
|
||||
r"""
|
||||
@brief Gets the net this pin reference is attached to.
|
||||
@brief Gets the net this pin reference is attached to (non-const version).
|
||||
|
||||
This constness variant has been introduced in version 0.26.8
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def net(self) -> Net:
|
||||
r"""
|
||||
@brief Gets the net this pin reference is attached to (non-const version).
|
||||
|
||||
This constness variant has been introduced in version 0.26.8
|
||||
@brief Gets the net this pin reference is attached to.
|
||||
"""
|
||||
...
|
||||
def pin(self) -> Pin:
|
||||
|
|
@ -41665,17 +41701,17 @@ class NetTerminalRef:
|
|||
@overload
|
||||
def device(self) -> Device:
|
||||
r"""
|
||||
@brief Gets the device reference (non-const version).
|
||||
@brief Gets the device reference.
|
||||
Gets the device object that this connection is made to.
|
||||
|
||||
This constness variant has been introduced in version 0.26.8
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def device(self) -> Device:
|
||||
r"""
|
||||
@brief Gets the device reference.
|
||||
@brief Gets the device reference (non-const version).
|
||||
Gets the device object that this connection is made to.
|
||||
|
||||
This constness variant has been introduced in version 0.26.8
|
||||
"""
|
||||
...
|
||||
def device_class(self) -> DeviceClass:
|
||||
|
|
@ -42687,17 +42723,26 @@ class Netlist:
|
|||
@overload
|
||||
def circuit_by_name(self, name: str) -> Circuit:
|
||||
r"""
|
||||
@brief Gets the circuit object for a given name.
|
||||
@brief Gets the circuit object for a given name (const version).
|
||||
If the name is not a valid circuit name, nil is returned.
|
||||
|
||||
This constness variant has been introduced in version 0.26.8.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def circuit_by_name(self, name: str) -> Circuit:
|
||||
r"""
|
||||
@brief Gets the circuit object for a given name (const version).
|
||||
@brief Gets the circuit object for a given name.
|
||||
If the name is not a valid circuit name, nil is returned.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def circuits_by_name(self, name_pattern: str) -> List[Circuit]:
|
||||
r"""
|
||||
@brief Gets the circuit objects for a given name filter.
|
||||
The name filter is a glob pattern. This method will return all \Circuit objects matching the glob pattern.
|
||||
|
||||
This constness variant has been introduced in version 0.26.8.
|
||||
This method has been introduced in version 0.26.4.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
|
|
@ -42710,15 +42755,6 @@ class Netlist:
|
|||
This constness variant has been introduced in version 0.26.8.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def circuits_by_name(self, name_pattern: str) -> List[Circuit]:
|
||||
r"""
|
||||
@brief Gets the circuit objects for a given name filter.
|
||||
The name filter is a glob pattern. This method will return all \Circuit objects matching the glob pattern.
|
||||
|
||||
This method has been introduced in version 0.26.4.
|
||||
"""
|
||||
...
|
||||
def combine_devices(self) -> None:
|
||||
r"""
|
||||
@brief Combines devices where possible
|
||||
|
|
@ -60838,17 +60874,17 @@ class SubCircuit(NetlistObject):
|
|||
@overload
|
||||
def circuit(self) -> Circuit:
|
||||
r"""
|
||||
@brief Gets the circuit the subcircuit lives in.
|
||||
@brief Gets the circuit the subcircuit lives in (non-const version).
|
||||
This is NOT the circuit which is referenced. For getting the circuit that the subcircuit references, use \circuit_ref.
|
||||
|
||||
This constness variant has been introduced in version 0.26.8
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def circuit(self) -> Circuit:
|
||||
r"""
|
||||
@brief Gets the circuit the subcircuit lives in (non-const version).
|
||||
@brief Gets the circuit the subcircuit lives in.
|
||||
This is NOT the circuit which is referenced. For getting the circuit that the subcircuit references, use \circuit_ref.
|
||||
|
||||
This constness variant has been introduced in version 0.26.8
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
|
|
|
|||
|
|
@ -1673,6 +1673,16 @@ class Logger:
|
|||
"""
|
||||
...
|
||||
@classmethod
|
||||
def set_verbosity(cls, v: int) -> None:
|
||||
r"""
|
||||
@brief Sets the verbosity level for the application
|
||||
|
||||
See \verbosity for a definition of the verbosity levels. Please note that this method changes the verbosity level for the whole application.
|
||||
|
||||
The 'set_verbosity' alias has been introduced in version 0.29.11 as class attributes are not always available in Python.
|
||||
"""
|
||||
...
|
||||
@classmethod
|
||||
def warn(cls, msg: str) -> None:
|
||||
r"""
|
||||
@brief Writes the given string to the warning channel
|
||||
|
|
|
|||
|
|
@ -392,34 +392,42 @@ WarningChannel::~WarningChannel ()
|
|||
void
|
||||
WarningChannel::puts (const char *s)
|
||||
{
|
||||
fputs (s, stdout);
|
||||
if (verbosity () >= 0) {
|
||||
fputs (s, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WarningChannel::endl ()
|
||||
{
|
||||
fputs ("\n", stdout);
|
||||
m_new_line = true;
|
||||
if (verbosity () >= 0) {
|
||||
fputs ("\n", stdout);
|
||||
m_new_line = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WarningChannel::end ()
|
||||
{
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_RESET, stdout);
|
||||
if (verbosity () >= 0) {
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_RESET, stdout);
|
||||
}
|
||||
fflush (stdout);
|
||||
}
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
void
|
||||
WarningChannel::begin ()
|
||||
{
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_BLUE, stdout);
|
||||
}
|
||||
if (m_new_line) {
|
||||
fputs ("Warning: ", stdout);
|
||||
m_new_line = false;
|
||||
if (verbosity () >= 0) {
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_BLUE, stdout);
|
||||
}
|
||||
if (m_new_line) {
|
||||
fputs ("Warning: ", stdout);
|
||||
m_new_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -463,34 +471,42 @@ ErrorChannel::~ErrorChannel ()
|
|||
void
|
||||
ErrorChannel::puts (const char *s)
|
||||
{
|
||||
fputs (s, stderr);
|
||||
if (verbosity () >= -10) {
|
||||
fputs (s, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ErrorChannel::endl ()
|
||||
{
|
||||
fputs ("\n", stderr);
|
||||
m_new_line = true;
|
||||
if (verbosity () >= -10) {
|
||||
fputs ("\n", stderr);
|
||||
m_new_line = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ErrorChannel::end ()
|
||||
{
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_RESET, stderr);
|
||||
if (verbosity () >= -10) {
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_RESET, stderr);
|
||||
}
|
||||
fflush (stderr);
|
||||
}
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorChannel::begin ()
|
||||
{
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_RED, stderr);
|
||||
}
|
||||
if (m_new_line) {
|
||||
fputs ("ERROR: ", stderr);
|
||||
m_new_line = false;
|
||||
if (verbosity () >= -10) {
|
||||
if (m_colorized) {
|
||||
fputs (ANSI_RED, stderr);
|
||||
}
|
||||
if (m_new_line) {
|
||||
fputs ("ERROR: ", stderr);
|
||||
m_new_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -149,6 +149,15 @@ class BasicTest(unittest.TestCase):
|
|||
|
||||
def test_00(self):
|
||||
|
||||
# does not work with all Python versions
|
||||
# (debugging shows that Python calls the setter on the metaclass,
|
||||
# not on the class itself at least on 3.12)
|
||||
# # static (class) properties
|
||||
# pya.A.sp_i = 17
|
||||
# self.assertEqual(pya.A.sp_i, 18)
|
||||
# pya.A.sp_i = -1
|
||||
# self.assertEqual(pya.A.sp_i, 0)
|
||||
|
||||
# all references of PA are released now:
|
||||
ic0 = pya.A.instance_count()
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ class Basic_TestClass < TestBase
|
|||
# for testing the ut logger:
|
||||
puts "Special chars: <&>"
|
||||
|
||||
# static (class) properties
|
||||
RBA::A.sp_i = 17
|
||||
assert_equal( RBA::A.sp_i, 18 )
|
||||
RBA::A.sp_i = -1
|
||||
assert_equal( RBA::A.sp_i, 0 )
|
||||
|
||||
GC.start
|
||||
|
||||
# all references of A are released now:
|
||||
|
|
|
|||
|
|
@ -124,6 +124,230 @@ class DBCellTests_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# locking
|
||||
def test_4
|
||||
|
||||
ly = RBA::Layout::new
|
||||
top = ly.create_cell("TOP")
|
||||
other = ly.create_cell("OTHER")
|
||||
child = ly.create_cell("CHILD")
|
||||
|
||||
l1 = ly.layer(1, 0)
|
||||
l2 = ly.layer(2, 0)
|
||||
shape = top.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200))
|
||||
inst = top.insert(RBA::CellInstArray::new(child, RBA::Trans::new(RBA::Vector::new(100, 200))))
|
||||
other.insert(RBA::CellInstArray::new(child, RBA::Trans::new(RBA::Vector::new(10, 20))))
|
||||
|
||||
assert_equal(top.is_locked?, false)
|
||||
top.locked = false
|
||||
assert_equal(top.is_locked?, false)
|
||||
top.locked = true
|
||||
assert_equal(top.is_locked?, true)
|
||||
|
||||
# rename is still possible
|
||||
top.name = "TOP2"
|
||||
|
||||
# instances of the cell can still be created
|
||||
toptop = ly.create_cell("TOPTOP")
|
||||
toptop.insert(RBA::CellInstArray::new(top, RBA::Trans::new))
|
||||
assert_equal(top.each_parent_inst.to_a[0].child_inst.to_s, "cell_index=0 r0 0,0")
|
||||
|
||||
begin
|
||||
# forbidden now
|
||||
top.shapes(l2).insert(RBA::Box::new(0, 0, 100, 200))
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Shapes::insert")
|
||||
end
|
||||
|
||||
begin
|
||||
# forbidden now
|
||||
shape.box = RBA::Box::new(1, 2, 101, 202)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Shape::box=")
|
||||
end
|
||||
|
||||
begin
|
||||
# forbidden now
|
||||
shape.prop_id = 1
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Shape::prop_id=")
|
||||
end
|
||||
|
||||
begin
|
||||
# forbidden now
|
||||
shape.polygon = RBA::Polygon::new(RBA::Box::new(0, 0, 200, 100))
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Shape::polygon=")
|
||||
end
|
||||
|
||||
begin
|
||||
# forbidden now
|
||||
inst.cell_index = other.cell_index
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Instance::cell_index=")
|
||||
end
|
||||
|
||||
begin
|
||||
# forbidden now
|
||||
inst.prop_id = 1
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Instance::prop_id=")
|
||||
end
|
||||
|
||||
begin
|
||||
# also forbidden
|
||||
top.insert(RBA::CellInstArray::new(child, RBA::Trans::new))
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::insert")
|
||||
end
|
||||
|
||||
begin
|
||||
# clear is forbidding
|
||||
top.clear
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::clear")
|
||||
end
|
||||
|
||||
begin
|
||||
# clear layer is forbidden
|
||||
top.shapes(l1).clear
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Shapes::clear")
|
||||
end
|
||||
|
||||
begin
|
||||
# clear layer is forbidden
|
||||
top.clear(l1)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::clear")
|
||||
end
|
||||
|
||||
begin
|
||||
# layer copy is forbidden
|
||||
top.copy(l1, l2)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::copy")
|
||||
end
|
||||
|
||||
begin
|
||||
# layer move is forbidden
|
||||
top.move(l1, l2)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::move")
|
||||
end
|
||||
|
||||
begin
|
||||
# layer swap is forbidden
|
||||
top.swap(l1, l2)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::swap")
|
||||
end
|
||||
|
||||
begin
|
||||
# copy_instances is forbidden
|
||||
top.copy_instances(other)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::copy_instances")
|
||||
end
|
||||
|
||||
begin
|
||||
# move_instances is forbidden
|
||||
top.move_instances(other)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::move_instances")
|
||||
end
|
||||
|
||||
begin
|
||||
# copy_tree is forbidden
|
||||
top.copy_tree(other)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::copy_tree")
|
||||
end
|
||||
|
||||
begin
|
||||
# move_tree is forbidden
|
||||
top.move_tree(other)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::move_tree")
|
||||
end
|
||||
|
||||
begin
|
||||
# copy_shapes is forbidden
|
||||
top.copy_shapes(other)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::copy_shapes")
|
||||
end
|
||||
|
||||
begin
|
||||
# move_shapes is forbidden
|
||||
top.move_shapes(other)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::move_shapes")
|
||||
end
|
||||
|
||||
begin
|
||||
# flatten is forbidden
|
||||
top.flatten(true)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::flatten")
|
||||
end
|
||||
|
||||
begin
|
||||
# cell cannot be deleted
|
||||
top.delete
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::delete")
|
||||
end
|
||||
|
||||
# locked attribute is copied
|
||||
ly2 = ly.dup
|
||||
assert_equal(ly2.cell("TOP2").is_locked?, true)
|
||||
|
||||
begin
|
||||
# cell cannot be deleted
|
||||
ly2.cell("TOP2").delete
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "Cell 'TOP2' cannot be modified as it is locked in Cell::delete")
|
||||
end
|
||||
|
||||
# clear and _destroy is always possible
|
||||
ly2.clear
|
||||
|
||||
ly2 = ly.dup
|
||||
ly2._destroy
|
||||
|
||||
# resetting the locked flag enables things again (not all tested here)
|
||||
top.locked = false
|
||||
|
||||
inst.cell_index = other.cell_index
|
||||
top.shapes(l2).insert(RBA::Box::new(0, 0, 100, 200))
|
||||
shape.box = RBA::Box::new(1, 2, 101, 202)
|
||||
top.delete
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue