diff --git a/COPYRIGHT b/COPYRIGHT index 61f6751f7..d65254a01 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,12 +1,12 @@ klayout is packaged by Peter C.S. Scholtens and Matthias Köfferlein -and was obtained from http://klayout.de/klayout-0.25.tar.gz +and was obtained from https://www.klayout.org/downloads/source/klayout-0.25.1.tar.gz Authors: Matthias Köfferlein Copyright: - Copyright (C) 2006-2017 by Matthias Köfferlein. + Copyright (C) 2006-2018 by Matthias Köfferlein. 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 diff --git a/Changelog b/Changelog index acd51aef4..21f41d8f0 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,47 @@ +0.25.1 (2018-02-23): +* Enhancements: build compatibility with MacOS, Qt 5.9. + Qt 4.6+4.7 supported as well with restrictions: + the package installation feature is not working. +* Bugfix: Package manager + - Remove button wasn't enabled if multiple packages were selected + - A potential crash ob removing packages was fixed +* Enhancement: 64 bit coordinate support enabled on Windows builds +* Further bugfixes: See links + - https://github.com/klayoutmatthias/klayout/issues/21 (Autorun(-early) doesn't seem to run when lym files are inside a package) + - https://github.com/klayoutmatthias/klayout/issues/24 (Text insert dialog possible) + - https://github.com/klayoutmatthias/klayout/issues/26 (Exceptions are reported every time they propagate up in the call chain in the ruby debugger) + - https://github.com/klayoutmatthias/klayout/issues/28 (CIF format detection failed) + - https://github.com/klayoutmatthias/klayout/issues/30 (Writer options dialog non-functional on a fresh configuration) + - https://github.com/klayoutmatthias/klayout/issues/32 (rounding issue with instance properties) + - https://github.com/klayoutmatthias/klayout/issues/33 (Plugin factory not working when using with Python) + - https://github.com/klayoutmatthias/klayout/issues/36 (hardening against destruction of object inside event handler) + - https://github.com/klayoutmatthias/klayout/issues/39 (Action cannot be reassigned) + - https://github.com/klayoutmatthias/klayout/issues/40 (Crash in Python binding) + - https://github.com/klayoutmatthias/klayout/issues/41 (Polygon#touches? issue) + - https://github.com/klayoutmatthias/klayout/issues/42 (headless mode support with Qt5/-zz) + - https://github.com/klayoutmatthias/klayout/issues/43 (crash when using Qt specific command line options) + - https://github.com/klayoutmatthias/klayout/issues/44 (Transformation constructor with x,y not working) + - https://github.com/klayoutmatthias/klayout/issues/45 (Partial selection does not capture instance) + - https://github.com/klayoutmatthias/klayout/issues/48 (Cancel does not reset current tool) + - https://github.com/klayoutmatthias/klayout/issues/51 (Segmentation fault on return to main window and other opportunities) + - https://github.com/klayoutmatthias/klayout/issues/53 (unreadable 'about' text) + - https://github.com/klayoutmatthias/klayout/issues/59 (async download of package index and details) + - https://github.com/klayoutmatthias/klayout/issues/62 (QXmlSimpleReader#parse cannot be called) + - https://github.com/klayoutmatthias/klayout/issues/63 (wrong output on DRC non_interacting with empty second input) + - https://github.com/klayoutmatthias/klayout/issues/64 (crash on exit) + - https://github.com/klayoutmatthias/klayout/issues/68 (OASIS reader issue with degenerated shapes) + - https://github.com/klayoutmatthias/klayout/issues/69 (DRC: 'inside' does not merge shapes of second input) + - https://github.com/klayoutmatthias/klayout/issues/71 (target cell argument is required) + - https://github.com/klayoutmatthias/klayout/issues/72 (Edges/Region NOT issue) + - https://github.com/klayoutmatthias/klayout/issues/73 (allow 'change layers' on PCells which support a single layer parameter) + - https://github.com/klayoutmatthias/klayout/issues/74 (small-corner boolean issue) + - https://github.com/klayoutmatthias/klayout/issues/75 (Python PCell issue when parameters are called 'layer') + - https://github.com/klayoutmatthias/klayout/issues/79 (Replace function enabled also for read-only macros) +* Further enhancements: see links + - https://github.com/klayoutmatthias/klayout/issues/29 (permissive mode for OASIS writer on odd-width paths) + - https://github.com/klayoutmatthias/klayout/issues/66 (Authentication dialog indicates retry) + - https://github.com/klayoutmatthias/klayout/issues/77 (copy_tree works in non-editable mode too) + 0.25 (2017-11-04): * Enhancement: Menu customization Menu items can be disabled or enabled now. The former diff --git a/Changelog.Debian b/Changelog.Debian index eb924c70b..15c67929f 100644 --- a/Changelog.Debian +++ b/Changelog.Debian @@ -1,3 +1,10 @@ +klayout (0.25.1-1) unstable; urgency=low + + * New features and bugfixes + - See changelog + + -- Matthias Köfferlein Thu, 22 Feb 2018 22:52:56 +0100 + klayout (0.25-1) unstable; urgency=low * New features and bugfixes diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc index a67b54a14..686224fc9 100644 --- a/src/ant/ant/antObject.cc +++ b/src/ant/ant/antObject.cc @@ -343,7 +343,6 @@ Object::class_name () const void Object::from_string (const char *s) { -printf("@@@ %s\n", s); fflush(stdout); tl::Extractor ex (s); while (! ex.at_end ()) { diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc index 61e407f06..65298eceb 100644 --- a/src/ant/ant/gsiDeclAnt.cc +++ b/src/ant/ant/gsiDeclAnt.cc @@ -1035,7 +1035,7 @@ public: value_type operator* () const { - return value_type (*(dynamic_cast (m_iter->first->ptr ())), m_services[m_service]->view ()); + return value_type (*(static_cast (m_iter->first->ptr ())), m_services[m_service]->view ()); } private: diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 0c8497f0b..b0674e5b2 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -183,6 +183,13 @@ to create the \\LayerInfo object, i.e. like this: The default implementation does nothing. All parameters not set in this method will receive their default value. +If you use a parameter called "layer" for example, the parameter getter will hide the +"layer" argument. Use "_layer" for the argument in this case (same for "layout", "shape" or "cell): + +@code + set_layer layout.get_info(_layer) +@/code + @method transformation_from_shape_impl @brief Gets the initial PCell instance transformation when creating from a shape @@ -230,6 +237,13 @@ module RBA # provide accessors for the current layout and cell (for prod) attr_reader :layout, :cell, :shape, :layer + + # provide fallback accessors in case of a name clash with a + # parameter + def _layer; @layer; end + def _layout; @layout; end + def _cell; @cell; end + def _shape; @shape; end # define a parameter # name -> the short name of the parameter @@ -246,6 +260,12 @@ module RBA # set_{name} -> write accessor ({name}= does not work because the # Ruby confuses that method with variables) # {name}_layer -> read accessor for the layer index for TypeLayer parameters + # in addition, fallback accessors are defined which can be used if + # the parameter's name clashes with another name: + # param_{name} + # set_param_{name} + # param_{name}_layer + def param(name, type, description, args = {}) # create accessor methods for the parameters diff --git a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym index 13abeb6c5..f867865dc 100644 --- a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym @@ -26,7 +26,7 @@ class MyPCell(pya.PCellDeclarationHelper): def __init__(self): # Important: initialize the super class - super(Circle, self).__init__() + super(MyPCell, self).__init__() # your initialization: add parameters with name, type, description and # optional other values @@ -226,16 +226,27 @@ class _PCellDeclarationHelperLayerDescriptor(object): class _PCellDeclarationHelperParameterDescriptor(object): """ A descriptor object which translates the PCell parameters into class attributes + + In some cases (i.e. can_convert_from_shape), these placeholders are not + connected to real parameters (obj._param_values is None). In this case, + the descriptor acts as a value holder (self.value) """ def __init__(self, param_index): self.param_index = param_index + self.value = None def __get__(self, obj, type = None): - return obj._param_values[self.param_index] + if obj._param_values: + return obj._param_values[self.param_index] + else: + return self.value def __set__(self, obj, value): - obj._param_values[self.param_index] = value + if obj._param_values: + obj._param_values[self.param_index] = value + else: + self.value = value class _PCellDeclarationHelper(pya.PCellDeclaration): """ @@ -321,7 +332,38 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): gets the parameters """ return self._param_decls + + def get_values(self): + """ + gets the temporary parameter values + """ + v = self._param_values + self._param_values = None + return v + def init_values(self, values = None, layers = None): + """ + initializes the temporary parameter values + "values" are the original values. If "None" is given, the + default values will be used. + "layers" are the layer indexes corresponding to the layer + parameters. + """ + if not values: + self._param_values = [] + for pd in self._param_decls: + self._param_values.append(pd.default) + else: + self._param_values = values + self._layers = layers + + def finish(self): + """ + Needs to be called at the end of produce() after init_values was used + """ + self._param_values = None + self._layers = None + def get_layers(self, parameters): """ get the layer definitions @@ -335,25 +377,23 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): """ coerce parameters (make consistent) """ - self._param_values = parameters + self.init_values(parameters) self.layout = layout self.coerce_parameters_impl() self.layout = None - return self._param_values + return self.get_values() def produce(self, layout, layers, parameters, cell): """ coerce parameters (make consistent) """ - self._layers = layers + self.init_values(parameters, layers) self.cell = cell - self._param_values = parameters self.layout = layout self.produce_impl() - self._layers = None self.cell = None - self._param_values = None self.layout = None + self.finish() def can_create_from_shape(self, layout, shape, layer): """ @@ -386,17 +426,16 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): produce a helper for parameters_from_shape with this helper, the implementation can use the parameter setters """ - self._param_values = [] - for pd in self._param_decls: - self._param_values.append(pd.default) + self.init_values() self.layout = layout self.shape = shape self.layer = layer self.parameters_from_shape_impl() + param = self.get_values() self.layout = None self.shape = None self.layer = None - return self._param_values + return param def display_text_impl(self): """ @@ -432,7 +471,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): """ default implementation """ - return pya.Trans.new + return pya.Trans() # import the Type... constants from PCellParameterDeclaration for k in dir(pya.PCellParameterDeclaration): diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index 60c449a13..60889271b 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -1349,13 +1349,17 @@ get_intersections_per_band_any (std::vector &cutpoints, std::vector // the cutpoint will be a weak attractor - that is an optional cutpoint. // In that case we can skip the cutpoint because no related edge will move. ip_weak.clear (); + size_t n_off_edge = on_edge1 ? 0 : 1; for (std::vector ::iterator cc = c; cc != f; ++cc) { if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) { ip_weak.push_back (&*cc); + if (!is_point_on_exact (*cc, cp.second)) { + ++n_off_edge; + } } } for (std::vector ::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) { - if (ip_weak.size () > 1 || !on_edge1) { + if (n_off_edge > 1) { (*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true); #ifdef DEBUG_EDGE_PROCESSOR printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ()); @@ -1435,13 +1439,23 @@ get_intersections_per_band_any (std::vector &cutpoints, std::vector // the cutpoint will be a weak attractor - that is an optional cutpoint. // In that case we can skip the cutpoint because no related edge will move. ip_weak.clear (); + size_t n_off_edge = 0; + if (!on_edge1) { + n_off_edge += 1; + } + if (!on_edge2) { + n_off_edge += 1; + } for (std::vector ::iterator cc = c; cc != f; ++cc) { if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) { ip_weak.push_back (&*cc); + if (!is_point_on_exact (*cc, cp.second)) { + ++n_off_edge; + } } } for (std::vector ::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) { - if (ip_weak.size () > 1 || !on_edge1 || !on_edge2) { + if (n_off_edge > 1) { (*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true); #ifdef DEBUG_EDGE_PROCESSOR printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ()); diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 021b9058e..8f09cf238 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1884,6 +1884,26 @@ Layout::is_pcell_instance (cell_index_type cell_index) const } } +const Layout::pcell_declaration_type * +Layout::pcell_declaration_for_pcell_variant (cell_index_type variant_cell_index) const +{ + const Cell *variant_cell = &cell (variant_cell_index); + + const LibraryProxy *lib_proxy = dynamic_cast (variant_cell); + if (lib_proxy) { + Library *lib = LibraryManager::instance ().lib (lib_proxy->lib_id ()); + tl_assert (lib != 0); + return lib->layout ().pcell_declaration_for_pcell_variant (lib_proxy->library_cell_index ()); + } + + const PCellVariant *pcell_variant = dynamic_cast (variant_cell); + if (pcell_variant) { + return pcell_declaration (pcell_variant->pcell_id ()); + } else { + return 0; + } +} + std::pair Layout::defining_library (cell_index_type cell_index) const { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 4a8a4222e..2506b0558 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -881,11 +881,22 @@ public: */ std::pair defining_library (cell_index_type cell_index) const; + /** + * @brief Gets the PCell declaration object for a PCell instance + * + * This method determines the PCell declaration object for a given PCell variant cell. + * Note, that the declaration may originate from a different layout than this, if the PCell + * is imported from a library. + * + * The cell given cell is not a PCell variant cell, 0 is returned. + */ + const Layout::pcell_declaration_type *pcell_declaration_for_pcell_variant (cell_index_type cell_index) const; + /** * @brief Get the PCell parameters of a PCell instance * * For the order of the parameters, ask the PCell declaration (available trough Layout::pcell_declaration - * from the PCell id). + * from the PCell id or from Layout::pcell_declaration_for_pcell_variant from the cell_index). * * @return A list of parameters in the order they are declared. */ diff --git a/src/db/db/dbOASISReader.cc b/src/db/db/dbOASISReader.cc index 1edcec995..844a0024b 100644 --- a/src/db/db/dbOASISReader.cc +++ b/src/db/db/dbOASISReader.cc @@ -110,6 +110,18 @@ OASISReader::OASISReader (tl::InputStream &s) { m_progress.set_format (tl::to_string (QObject::tr ("%.0f MB"))); m_progress.set_unit (1024 * 1024); + m_first_cellname = 0; + m_first_propname = 0; + m_first_propstring = 0; + m_first_textstring = 0; + m_first_layername = 0; + m_in_table = NotInTable; + m_table_cellname = 0; + m_table_propname = 0; + m_table_propstring = 0; + m_table_textstring = 0; + m_table_layername = 0; + m_table_start = 0; } OASISReader::~OASISReader () @@ -197,6 +209,16 @@ OASISReader::get_long () } } +inline unsigned long +OASISReader::get_ulong_for_divider () +{ + unsigned long l = get_ulong (); + if (l == 0) { + error (tl::to_string (QObject::tr ("Divider must not be zero"))); + } + return l; +} + inline unsigned long OASISReader::get_ulong () { @@ -295,21 +317,21 @@ OASISReader::get_real () } else if (t == 2) { - return 1.0 / double (get_ulong ()); + return 1.0 / double (get_ulong_for_divider ()); } else if (t == 3) { - return -1.0 / double (get_ulong ()); + return -1.0 / double (get_ulong_for_divider ()); } else if (t == 4) { double d = double (get_ulong ()); - return d / double (get_ulong ()); + return d / double (get_ulong_for_divider ()); } else if (t == 5) { double d = double (get_ulong ()); - return -d / double (get_ulong ()); + return -d / double (get_ulong_for_divider ()); } else if (t == 6) { diff --git a/src/db/db/dbOASISReader.h b/src/db/db/dbOASISReader.h index 60f04aeda..26487ef68 100644 --- a/src/db/db/dbOASISReader.h +++ b/src/db/db/dbOASISReader.h @@ -318,6 +318,7 @@ private: unsigned long long get_ulong_long (); long get_long (); unsigned long get_ulong (); + unsigned long get_ulong_for_divider (); int get_int (); unsigned int get_uint (); diff --git a/src/db/db/dbPCellVariant.cc b/src/db/db/dbPCellVariant.cc index 0430996f0..55f67a840 100644 --- a/src/db/db/dbPCellVariant.cc +++ b/src/db/db/dbPCellVariant.cc @@ -186,15 +186,28 @@ PCellVariant::update (ImportLayerMapping *layer_mapping) shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (m_parameters[i].to_user () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { + + shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(m_parameters[i].to_user (), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(db::Edge (m_parameters[i].to_user () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { + + shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(m_parameters[i].to_user (), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { db::DPoint p = m_parameters[i].to_user (); shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (db::DBox (p, p) * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { + + db::Point p = m_parameters[i].to_user (); + shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (p, p), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { db::complex_trans dbu_trans (1.0 / layout ()->dbu ()); @@ -202,11 +215,21 @@ PCellVariant::update (ImportLayerMapping *layer_mapping) // Hint: we don't compress the polygon since we don't want to loose information shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { + + db::Polygon poly = m_parameters[i].to_user (); + // Hint: we don't compress the polygon since we don't want to loose information + shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { db::complex_trans dbu_trans (1.0 / layout ()->dbu ()); shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(dbu_trans * m_parameters[i].to_user (), layout ()->properties_repository ().properties_id (props))); + } else if (m_parameters[i].is_user ()) { + + shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(m_parameters[i].to_user (), layout ()->properties_repository ().properties_id (props))); + } } diff --git a/src/db/db/dbReader.cc b/src/db/db/dbReader.cc index 2ce1efe86..bd8326c9f 100644 --- a/src/db/db/dbReader.cc +++ b/src/db/db/dbReader.cc @@ -62,7 +62,7 @@ Reader::Reader (tl::InputStream &stream) } if (! mp_actual_reader) { - throw db::ReaderException (tl::to_string (QObject::tr ("Stream has unknown format"))); + throw db::ReaderException (tl::to_string (QObject::tr ("Stream has unknown format: ")) + stream.source ()); } } diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index bd6718522..7281b9861 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -276,6 +276,8 @@ RecursiveShapeIterator::init () m_shape_inv_prop_sel = false; m_inst_quad_id = 0; m_shape_quad_id = 0; + mp_cell = 0; + m_current_layer = 0; } void diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 31433cfb0..bdc97c797 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -883,8 +883,6 @@ static bool cell_has_prop_id (const db::Cell *c) static void delete_cell_property (db::Cell *c, const tl::Variant &key) { - check_is_editable (c); - db::properties_id_type id = c->prop_id (); if (id == 0) { return; @@ -911,8 +909,6 @@ static void delete_cell_property (db::Cell *c, const tl::Variant &key) static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Variant &value) { - check_is_editable (c); - db::properties_id_type id = c->prop_id (); db::Layout *layout = c->layout (); @@ -1110,13 +1106,11 @@ static void move_or_copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, un static void move_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer) { - check_is_editable (cell); move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, true); } static void copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer) { - check_is_editable (cell); move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, false); } @@ -1158,7 +1152,6 @@ write_options (const db::Cell *cell, const std::string &filename, const db::Save static void clear_all (db::Cell *cell) { - check_is_editable (cell); cell->clear_shapes (); cell->clear_insts (); } @@ -1166,7 +1159,6 @@ clear_all (db::Cell *cell) static void delete_cell (db::Cell *cell) { - check_is_editable (cell); db::Layout *layout = cell->layout (); if (layout) { layout->delete_cell (cell->cell_index ()); @@ -1176,7 +1168,6 @@ delete_cell (db::Cell *cell) static void prune_subcells (db::Cell *cell, int levels) { - check_is_editable (cell); db::Layout *layout = cell->layout (); if (layout) { layout->prune_subcells (cell->cell_index (), levels); @@ -1192,7 +1183,6 @@ prune_subcells0 (db::Cell *cell) static void prune_cell (db::Cell *cell, int levels) { - check_is_editable (cell); db::Layout *layout = cell->layout (); if (layout) { layout->prune_cell (cell->cell_index (), levels); @@ -1208,7 +1198,6 @@ prune_cell0 (db::Cell *cell) static void flatten (db::Cell *cell, int levels, bool prune) { - check_is_editable (cell); db::Layout *layout = cell->layout (); if (layout) { layout->flatten (*cell, levels, prune); @@ -1288,8 +1277,6 @@ begin_shapes_rec_overlapping_um (const db::Cell *cell, unsigned int layer, db::D static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::LayerMapping &layer_mapping) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); } @@ -1318,8 +1305,6 @@ static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db: static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); } @@ -1344,8 +1329,6 @@ static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell) static void copy_instances (db::Cell *cell, const db::Cell &source_cell) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy instances within the same cell"))); } @@ -1360,8 +1343,6 @@ static void copy_instances (db::Cell *cell, const db::Cell &source_cell) static std::vector copy_tree (db::Cell *cell, const db::Cell &source_cell) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); } @@ -1393,8 +1374,6 @@ static std::vector copy_tree (db::Cell *cell, const db::Cel static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); } @@ -1421,8 +1400,6 @@ static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, cons static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); } @@ -1446,8 +1423,6 @@ static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, cons static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::LayerMapping &layer_mapping) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); } @@ -1478,8 +1453,6 @@ static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::Layer static void move_shapes1 (db::Cell *cell, db::Cell &source_cell) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); } @@ -1505,8 +1478,6 @@ static void move_shapes1 (db::Cell *cell, db::Cell &source_cell) static void move_instances (db::Cell *cell, db::Cell &source_cell) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot move instances within the same cell"))); } @@ -1523,8 +1494,6 @@ static void move_instances (db::Cell *cell, db::Cell &source_cell) static std::vector move_tree (db::Cell *cell, db::Cell &source_cell) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); } @@ -1558,8 +1527,6 @@ static std::vector move_tree (db::Cell *cell, db::Cell &sou static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); } @@ -1586,8 +1553,6 @@ static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db:: static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm) { - check_is_editable (cell); - if (cell == &source_cell) { throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); } @@ -1612,8 +1577,6 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db:: static void fill_region1 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin) { - check_is_editable (cell); - if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) { throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)"))); } @@ -1624,8 +1587,6 @@ static void fill_region2 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin, db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) { - check_is_editable (cell); - if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) { throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)"))); } diff --git a/src/db/unit_tests/dbEdgeProcessor.cc b/src/db/unit_tests/dbEdgeProcessor.cc index 72e29671a..623defb7e 100644 --- a/src/db/unit_tests/dbEdgeProcessor.cc +++ b/src/db/unit_tests/dbEdgeProcessor.cc @@ -2244,3 +2244,54 @@ TEST(100) db::compare_layouts (_this, lr, au_fn); } +// #74 (GitHub) +TEST(101) +{ + db::EdgeProcessor ep; + + { + db::Point pts[] = { + db::Point (0, 0), + db::Point (0, 10), + db::Point (10, 10), + db::Point (10, 0) + }; + db::Polygon p; + p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]); + ep.insert (p, 0); + } + + { + db::Point pts[] = { + db::Point (-1, -1), + db::Point (-1, 8), + db::Point (2, 11), + db::Point (2, -1) + }; + db::Polygon p; + p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]); + ep.insert (p, 1); + } + + { + db::Point pts[] = { + db::Point (2, -1), + db::Point (2, 11), + db::Point (11, 11), + db::Point (11, -1) + }; + db::Polygon p; + p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]); + ep.insert (p, 1); + } + + std::vector out; + db::PolygonContainer pc (out); + db::PolygonGenerator pg (pc, false, true); + db::BooleanOp op (db::BooleanOp::And); + + ep.process (pg, op); + + EXPECT_EQ (out.size (), size_t (1)); + EXPECT_EQ (out[0].to_string (), "(0,0;0,9;1,10;10,10;10,0)"); +} diff --git a/src/db/unit_tests/dbObject.cc b/src/db/unit_tests/dbObject.cc index 0ecf9195b..a8d03d968 100644 --- a/src/db/unit_tests/dbObject.cc +++ b/src/db/unit_tests/dbObject.cc @@ -58,6 +58,7 @@ struct A : public db::Object void redo (db::Op *op) throw () { AO *aop = dynamic_cast (op); + tl_assert (aop != 0); x += aop->d; } @@ -162,6 +163,7 @@ struct B : public db::Object void redo (db::Op *op) throw () { BO *bop = dynamic_cast (op); + tl_assert (bop != 0); x += bop->d; } diff --git a/src/drc/drc/built-in-macros/drc.lym b/src/drc/drc/built-in-macros/drc.lym index 3f103f38c..514b59a4d 100644 --- a/src/drc/drc/built-in-macros/drc.lym +++ b/src/drc/drc/built-in-macros/drc.lym @@ -3922,9 +3922,9 @@ CODE n = $1.to_i - 1 view = RBA::LayoutView::current view || raise("No view open") - (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n}") + (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}") cv = view.cellview(n) - cv.is_valid? || raise("Invalid layout @#{n}") + cv.is_valid? || raise("Invalid layout @#{n + 1}") @def_source = make_source(cv.layout, cv.cell) else layout = RBA::Layout::new @@ -4016,9 +4016,9 @@ CODE n = $1.to_i - 1 view = RBA::LayoutView::current view || raise("No view open") - (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n}") + (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}") cv = view.cellview(n) - cv.is_valid? || raise("Invalid layout @#{n}") + cv.is_valid? || raise("Invalid layout @#{n + 1}") return make_source(cv.layout, cv.cell) else layout = RBA::Layout::new @@ -4173,9 +4173,9 @@ CODE n = $1.to_i - 1 view = RBA::LayoutView::current view || raise("No view open") - (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n}") + (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}") cv = view.cellview(n) - cv.is_valid? || raise("Invalid layout @#{n}") + cv.is_valid? || raise("Invalid layout @#{n + 1}") @output_layout = cv.layout @output_cell = cellname ? (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)) : cv.cell @output_layout_file = nil @@ -4694,11 +4694,20 @@ CODE else - output = @output_layout || @def_layout - output || raise("No output layout specified") - - output_cell = @output_cell || @def_cell - output_cell || raise("No output cell specified") + if @output_layout + output = @output_layout + if @output_cell + output_cell = @output_cell + elsif @def_cell + output_cell = @output_layout.cell(@def_cell.name) || @output_layout.create_cell(@def_cell.name) + end + output_cell || raise("No output cell specified (see 'target' instruction)") + else + output = @def_layout + output || raise("No output layout specified") + output_cell = @output_cell || @def_cell + output_cell || raise("No output cell specified") + end info = nil if args.size == 1 diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index deb4f88cb..0d98f3872 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -1084,23 +1084,29 @@ MainService::cm_convert_to_pcell () db::Library *lib = db::LibraryManager::instance ().lib (l->second); for (db::Layout::pcell_iterator pc = lib->layout ().begin_pcells (); pc != lib->layout ().end_pcells (); ++pc) { - const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second); - size_t n = 1000; // 1000 tries max. - for (std::vector::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) { - for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) { - const lay::CellView &cv = view ()->cellview (s->cv_index ()); - if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) { - --n; - } else { - pc_decl = 0; // stop + try { + + const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second); + size_t n = 1000; // 1000 tries max. + for (std::vector::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) { + for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) { + const lay::CellView &cv = view ()->cellview (s->cv_index ()); + if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) { + --n; + } else { + pc_decl = 0; // stop + } } } - } - // We have positive hit - if (pc_decl) { - pcells.push_back (std::make_pair (lib, pc->second)); - items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ())); + // We have positive hit + if (pc_decl) { + pcells.push_back (std::make_pair (lib, pc->second)); + items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ())); + } + + } catch (...) { + // ignore errors in can_create_from_shape } } @@ -1906,12 +1912,10 @@ MainService::cm_change_layer () // get (common) cellview index of the selected shapes for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { - if (! s->is_cell_inst ()) { - if (cv_index >= 0 && cv_index != int (s->cv_index ())) { - throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case."))); - } - cv_index = int (s->cv_index ()); + if (cv_index >= 0 && cv_index != int (s->cv_index ())) { + throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case."))); } + cv_index = int (s->cv_index ()); } } @@ -1975,17 +1979,58 @@ MainService::cm_change_layer () // Insert and delete the shape. This exploits the fact, that a shape can be erased multiple times - // this is important since the selection potentially contains the same shape multiple times. for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { + for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { + if (!s->is_cell_inst () && int (s->layer ()) != layer) { + db::Cell &cell = layout.cell (s->cell_index ()); if (cell.shapes (s->layer ()).is_valid (s->shape ())) { cell.shapes (layer).insert (s->shape ()); cell.shapes (s->layer ()).erase_shape (s->shape ()); } + + } else if (s->is_cell_inst ()) { + + // If the selected object is a PCell instance, and there is exactly one visible, writable layer type parameter, change this one + + db::Instance inst = s->back ().inst_ptr; + db::Cell &cell = layout.cell (s->cell_index ()); + + if (cell.is_valid (inst)) { + + const db::PCellDeclaration *pcell_decl = layout.pcell_declaration_for_pcell_variant (inst.cell_index ()); + if (pcell_decl) { + + size_t layer_par_index = 0; + int n_layer_par = 0; + for (std::vector::const_iterator d = pcell_decl->parameter_declarations ().begin (); d != pcell_decl->parameter_declarations ().end () && n_layer_par < 2; ++d) { + if (d->get_type () == db::PCellParameterDeclaration::t_layer && !d->is_hidden () && !d->is_readonly ()) { + ++n_layer_par; + layer_par_index = size_t (d - pcell_decl->parameter_declarations ().begin ()); + } + } + + if (n_layer_par == 1) { + std::vector parameters = cell.get_pcell_parameters (inst); + tl_assert (layer_par_index < parameters.size ()); + parameters [layer_par_index] = layout.get_properties (layer); + cell.change_pcell_parameters (inst, parameters); + } + + } + + } + } + } + } + // remove superfluous proxies + layout.cleanup (); + // The selection is no longer valid view ()->clear_selection (); diff --git a/src/ext/ext/extNetTracerIO.cc b/src/ext/ext/extNetTracerIO.cc index 761271dd2..22d9ef3fb 100644 --- a/src/ext/ext/extNetTracerIO.cc +++ b/src/ext/ext/extNetTracerIO.cc @@ -1092,7 +1092,7 @@ Net::Net () } Net::Net (const NetTracer &tracer, const db::ICplxTrans &trans, const db::Layout &layout, db::cell_index_type cell_index, const std::string &layout_filename, const std::string &layout_name, const NetTracerData &data) - : m_name (tracer.name ()), m_incomplete (tracer.incomplete ()) + : m_name (tracer.name ()), m_incomplete (tracer.incomplete ()), m_trace_path (false) { m_dbu = layout.dbu (); m_top_cell_name = layout.cell_name (cell_index); diff --git a/src/ext/ext/extRS274XApertures.cc b/src/ext/ext/extRS274XApertures.cc index 0a42d40ea..d232293c9 100644 --- a/src/ext/ext/extRS274XApertures.cc +++ b/src/ext/ext/extRS274XApertures.cc @@ -607,11 +607,30 @@ RS274XMacroAperture::do_produce_flash () } } +void +RS274XMacroAperture::read_exposure (tl::Extractor &ex, bool &clear, bool &clear_set) +{ + int pol = int (floor (read_expr (ex) + 0.5)); + + if (pol == 0) { + clear = true; + } else if (pol == 1) { + clear = false; + } else if (pol == 2) { + clear = !clear_set || !clear; + } else { + throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol); + } + + clear_set = true; +} + void RS274XMacroAperture::do_produce_flash_internal () { tl::Extractor ex (m_def.c_str ()); bool clear = false; + bool clear_set = false; while (! ex.at_end ()) { @@ -640,18 +659,7 @@ RS274XMacroAperture::do_produce_flash_internal () if (code == 1) { ex.expect (","); - int pol = (read_expr (ex) > 0.5); - - if (pol == 0) { - clear = true; - } else if (pol == 1) { - clear = false; - } else if (pol == 2) { - clear = !clear; - } else { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol); - } - + read_exposure (ex, clear, clear_set); ex.expect (","); double d = read_expr (ex, true); ex.expect (","); @@ -670,18 +678,7 @@ RS274XMacroAperture::do_produce_flash_internal () } else if (code == 2 || code == 20) { ex.expect (","); - int pol = (read_expr (ex) > 0.5); - - if (pol == 0) { - clear = true; - } else if (pol == 1) { - clear = false; - } else if (pol == 2) { - clear = !clear; - } else { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol); - } - + read_exposure (ex, clear, clear_set); ex.expect (","); double w = read_expr (ex, true); ex.expect (","); @@ -723,18 +720,7 @@ RS274XMacroAperture::do_produce_flash_internal () } else if (code == 21 || code == 22) { ex.expect (","); - int pol = (read_expr (ex) > 0.5); - - if (pol == 0) { - clear = true; - } else if (pol == 1) { - clear = false; - } else if (pol == 2) { - clear = !clear; - } else { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol); - } - + read_exposure (ex, clear, clear_set); ex.expect (","); double w = read_expr (ex, true); ex.expect (","); @@ -766,18 +752,7 @@ RS274XMacroAperture::do_produce_flash_internal () } else if (code == 4) { ex.expect (","); - int pol = (read_expr (ex) > 0.5); - - if (pol == 0) { - clear = true; - } else if (pol == 1) { - clear = false; - } else if (pol == 2) { - clear = !clear; - } else { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol); - } - + read_exposure (ex, clear, clear_set); ex.expect (","); int n = int (read_expr (ex) + 0.5); if (n < 1) { @@ -854,18 +829,7 @@ RS274XMacroAperture::do_produce_flash_internal () } else if (code == 5) { ex.expect (","); - int pol = (read_expr (ex) > 0.5); - - if (pol == 0) { - clear = true; - } else if (pol == 1) { - clear = false; - } else if (pol == 2) { - clear = !clear; - } else { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol); - } - + read_exposure (ex, clear, clear_set); ex.expect (","); int n = int (read_expr (ex) + 0.5); if (n < 3) { diff --git a/src/ext/ext/extRS274XApertures.h b/src/ext/ext/extRS274XApertures.h index 969a1d710..78fa02ac6 100644 --- a/src/ext/ext/extRS274XApertures.h +++ b/src/ext/ext/extRS274XApertures.h @@ -168,6 +168,7 @@ private: double read_atom (tl::Extractor &ex); double read_dot_expr (tl::Extractor &ex); double read_expr (tl::Extractor &ex, bool length = false); + void read_exposure (tl::Extractor &ex, bool &clear, bool &clear_set); void do_produce_flash_internal (); }; diff --git a/src/gsi/gsi/gsiMethods.h b/src/gsi/gsi/gsiMethods.h index c0deceef9..d4bb408bd 100644 --- a/src/gsi/gsi/gsiMethods.h +++ b/src/gsi/gsi/gsiMethods.h @@ -524,7 +524,6 @@ private: ArgType m_ret_type; bool m_const : 1; bool m_static : 1; - bool m_is_predicate : 1; bool m_protected : 1; unsigned int m_argsize; std::vector m_method_synonyms; diff --git a/src/img/img/imgObject.cc b/src/img/img/imgObject.cc index c4c1e9b2f..eb45a1668 100644 --- a/src/img/img/imgObject.cc +++ b/src/img/img/imgObject.cc @@ -697,12 +697,14 @@ static size_t make_id () Object::Object () : m_trans (1.0), mp_data (0), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0) { + m_updates_enabled = false; mp_pixel_data = 0; } Object::Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color) : m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0) { + m_updates_enabled = false; mp_pixel_data = 0; mp_data = new DataHeader (w, h, color, false); diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 8087008c2..ac4f3dea4 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1380,6 +1380,17 @@ GuiApplication::notify (QObject *receiver, QEvent *e) return ret; } +void +GuiApplication::force_update_app_menu () +{ +#if defined(__APPLE__) + // This is a workaround for a bug in the MacOS native menu integration: + // this signal forces the menu to become updated. Without this, any + // new menu items stay disabled. + emit focusWindowChanged (focusWindow ()); +#endif +} + int GuiApplication::exec () { diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 95eba57de..7eceea849 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -432,6 +432,12 @@ public: return mp_mw; } + /** + * @brief Forces update of the application menu + * This function is used for work around a MacOS issue. + */ + void force_update_app_menu (); + protected: virtual void setup (); virtual void shutdown (); diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index 9f0f408c6..a866660f0 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -1621,6 +1621,8 @@ MacroEditorDialog::current_tab_changed (int index) // clear the search searchEditBox->clear (); + replaceFrame->setEnabled (page && page->macro () && !page->macro ()->is_readonly ()); + apply_search (); do_update_ui_to_run_mode (); diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index 804c98741..f82350c44 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -971,6 +971,10 @@ static QString interpolate_string (const QString &replace, const QRegExp &re) void MacroEditorPage::replace_and_find_next (const QString &replace) { + if (! mp_macro || mp_macro->is_readonly ()) { + return; + } + QTextCursor c = mp_text->textCursor (); if (c.hasSelection ()) { c.insertText (interpolate_string (replace, m_current_search)); @@ -982,6 +986,10 @@ MacroEditorPage::replace_and_find_next (const QString &replace) void MacroEditorPage::replace_all (const QString &replace) { + if (! mp_macro || mp_macro->is_readonly ()) { + return; + } + const QTextDocument *doc = mp_text->document (); QTextCursor c = mp_text->textCursor (); diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 4fce4d8e7..37be91928 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -450,6 +450,7 @@ MainWindow::MainWindow (QApplication *app, const char *name) m_disable_tab_selected (false), m_exited (false), dm_do_update_menu (this, &MainWindow::do_update_menu), + dm_do_update_file_menu (this, &MainWindow::do_update_file_menu), dm_exit (this, &MainWindow::exit), m_grid_micron (0.001), m_default_grids_updated (true), @@ -608,15 +609,6 @@ MainWindow::MainWindow (QApplication *app, const char *name) cp_frame_ly->addWidget (mp_cpy_label); cp_frame_ly->insertSpacing (-1, 6); - // connect to the menus to provide the dynamic parts - QMenu *bookmark_menu = mp_menu->menu ("bookmark_menu"); - tl_assert (bookmark_menu != 0); - connect (bookmark_menu, SIGNAL (aboutToShow ()), this, SLOT (bookmark_menu_show ())); - - QMenu *file_menu = mp_menu->menu ("file_menu"); - tl_assert (file_menu != 0); - connect (file_menu, SIGNAL (aboutToShow ()), this, SLOT (file_menu_show ())); - // select the default mode select_mode (lay::LayoutView::default_mode ()); @@ -1595,6 +1587,8 @@ MainWindow::configure (const std::string &name, const std::string &value) } } + dm_do_update_file_menu (); + return true; } else if (name == cfg_micron_digits) { @@ -1799,6 +1793,12 @@ MainWindow::edits_enabled_changed () } } +void +MainWindow::menu_needs_update () +{ + lay::LayoutView::update_menu (current_view (), *mp_menu); +} + void MainWindow::libraries_changed () { @@ -2427,57 +2427,6 @@ MainWindow::cm_redo () END_PROTECTED } -void -MainWindow::bookmark_menu_show () -{ - if (mp_menu->is_valid ("bookmark_menu.goto_bookmark_menu")) { - - Action goto_bookmark_action = mp_menu->action ("bookmark_menu.goto_bookmark_menu"); - bool has_bookmarks = current_view () && current_view ()->bookmarks ().size () > 0; - - if (has_bookmarks && edits_enabled ()) { - - goto_bookmark_action.set_enabled (true); - - QMenu *goto_bookmark_menu = goto_bookmark_action.qaction ()->menu (); - if (goto_bookmark_menu) { - - goto_bookmark_menu->clear (); - - if (current_view ()) { - const lay::BookmarkList &bookmarks = current_view ()->bookmarks (); - for (size_t i = 0; i < bookmarks.size (); ++i) { - QAction *action = goto_bookmark_menu->addAction (tl::to_qstring (bookmarks.name (i))); - action->setObjectName (tl::to_qstring (tl::sprintf ("bookmark_%d", i + 1))); - gtf::action_connect (action, SIGNAL (triggered ()), this, SLOT (goto_bookmark ())); - action->setData (QVariant (int (i))); - } - } - - } - - } else { - goto_bookmark_action.set_enabled (false); - } - - } -} - -void -MainWindow::goto_bookmark () -{ - BEGIN_PROTECTED - - QAction *action = dynamic_cast (sender ()); - tl_assert (action); - size_t id = size_t (action->data ().toInt ()); - if (current_view () && current_view ()->bookmarks ().size () > id) { - current_view ()->goto_view (current_view ()->bookmarks ().state (id)); - } - - END_PROTECTED -} - void MainWindow::cm_goto_position () { @@ -2581,19 +2530,7 @@ MainWindow::cm_bookmark_view () BEGIN_PROTECTED if (current_view ()) { - while (true) { - bool ok = false; - QString text = QInputDialog::getText (this, QObject::tr ("Enter Bookmark Name"), QObject::tr ("Bookmark name"), - QLineEdit::Normal, QString::null, &ok); - if (! ok) { - break; - } else if (text.isEmpty ()) { - QMessageBox::critical (this, QObject::tr ("Error"), QObject::tr ("Enter a name for the bookmark")); - } else { - current_view ()->bookmark_view (tl::to_string (text)); - break; - } - } + current_view ()->bookmark_current_view (); } END_PROTECTED @@ -3360,6 +3297,7 @@ MainWindow::select_view (int index) clear_current_pos (); edits_enabled_changed (); clear_message (); + menu_needs_update (); m_disable_tab_selected = dis; @@ -3739,6 +3677,7 @@ MainWindow::clone_current_view () connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); + connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); @@ -4042,6 +3981,7 @@ MainWindow::close_view (int index) clear_current_pos (); edits_enabled_changed (); + menu_needs_update (); clear_message (); update_dock_widget_state (); @@ -4173,30 +4113,28 @@ MainWindow::add_mru (const std::string &fn_rel, const std::string &tech) } void -MainWindow::file_menu_show () +MainWindow::do_update_file_menu () { - if (mp_menu->is_valid ("file_menu.open_recent_menu")) { + std::string mru_menu = "file_menu.open_recent_menu"; - Action open_recent_action = mp_menu->action ("file_menu.open_recent_menu"); + if (mp_menu->is_valid (mru_menu)) { + + Action open_recent_action = mp_menu->action (mru_menu); + open_recent_action.set_enabled (true); if (m_mru.size () > 0 && edits_enabled ()) { - open_recent_action.set_enabled (true); - - QMenu *open_recent_menu = open_recent_action.qaction ()->menu (); - if (open_recent_menu) { - - open_recent_menu->clear (); - - for (std::vector >::iterator mru = m_mru.end (); mru != m_mru.begin (); ) { - --mru; - unsigned int i = std::distance (m_mru.begin (), mru); - QAction *action = open_recent_menu->addAction (tl::to_qstring (mru->first)); - action->setObjectName (tl::to_qstring (tl::sprintf ("open_recent_%d", i + 1))); - gtf::action_connect (action, SIGNAL (triggered ()), this, SLOT (open_recent ())); - action->setData (QVariant (int (i))); - } + // rebuild MRU menu + mp_menu->clear_menu (mru_menu); + for (std::vector >::iterator mru = m_mru.end (); mru != m_mru.begin (); ) { + --mru; + unsigned int i = std::distance (m_mru.begin (), mru); + Action action; + gtf::action_connect (action.qaction (), SIGNAL (triggered ()), this, SLOT (open_recent ())); + action.set_title (mru->first); + action.qaction ()->setData (QVariant (int (i))); + mp_menu->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action); } } else { @@ -4349,6 +4287,7 @@ MainWindow::do_create_view () connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); + connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); @@ -5016,6 +4955,10 @@ void MainWindow::do_update_menu () { mp_menu->build (menuBar (), mp_tool_bar); + lay::GuiApplication *app = dynamic_cast (qApp); + if (app) { + app->force_update_app_menu (); + } } void diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h index 478e5b685..092ac57a4 100644 --- a/src/lay/lay/layMainWindow.h +++ b/src/lay/lay/layMainWindow.h @@ -689,7 +689,6 @@ public slots: void tab_close_requested (int); void enable_all (); void disable_all (); - void goto_bookmark (); void open_recent (); void view_selected (int index); void view_title_changed (); @@ -858,9 +857,9 @@ public slots: protected slots: void menu_changed (); void message_timer (); - void bookmark_menu_show (); - void file_menu_show (); void edits_enabled_changed (); + void menu_needs_update (); + void file_changed_timer (); void file_changed (const QString &path); void file_removed (const QString &path); @@ -868,13 +867,13 @@ protected slots: protected: void update_content (); void do_update_menu (); + void do_update_file_menu (); private: TextProgressDelegate m_text_progress; // Main menu AbstractMenu *mp_menu; - QMenu *mp_goto_bookmark_menu; QTabBar *mp_tab_bar; QToolBar *mp_tool_bar; QDockWidget *mp_navigator_dock_widget; @@ -911,6 +910,7 @@ private: bool m_disable_tab_selected; bool m_exited; tl::DeferredMethod dm_do_update_menu; + tl::DeferredMethod dm_do_update_file_menu; tl::DeferredMethod dm_exit; QTimer m_message_timer; QTimer m_file_changed_timer; diff --git a/src/lay/lay/layProgress.cc b/src/lay/lay/layProgress.cc index 219473fa5..daefbaff1 100644 --- a/src/lay/lay/layProgress.cc +++ b/src/lay/lay/layProgress.cc @@ -211,10 +211,12 @@ ProgressReporter::set_visible (bool vis) // actual operation tl::DeferredMethodScheduler::enable (!vis); - if (!vis) { - mp_pb->progress_remove_widget (); - } else if (mp_pb->progress_wants_widget () && mp_objects.front ()) { - mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ()); + if (mp_pb) { + if (!vis) { + mp_pb->progress_remove_widget (); + } else if (mp_pb->progress_wants_widget () && mp_objects.front ()) { + mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ()); + } } m_pw_visible = vis; diff --git a/src/lay/lay/laySaltGrainPropertiesDialog.cc b/src/lay/lay/laySaltGrainPropertiesDialog.cc index 809d953e4..336f041c4 100644 --- a/src/lay/lay/laySaltGrainPropertiesDialog.cc +++ b/src/lay/lay/laySaltGrainPropertiesDialog.cc @@ -259,7 +259,7 @@ SaltGrainPropertiesDialog::dependency_changed (QTreeWidgetItem *item, int column m_update_enabled = false; std::string name = tl::to_string (item->data (0, Qt::UserRole).toString ().simplified ()); - SaltGrain *g = mp_salt->grain_by_name (name); + SaltGrain *g = mp_salt ? mp_salt->grain_by_name (name) : 0; if (column == 0 && mp_salt) { diff --git a/src/laybasic/laybasic/gsiDeclLayTechnologies.cc b/src/laybasic/laybasic/gsiDeclLayTechnologies.cc index acd9b6964..9ed316979 100644 --- a/src/laybasic/laybasic/gsiDeclLayTechnologies.cc +++ b/src/laybasic/laybasic/gsiDeclLayTechnologies.cc @@ -45,7 +45,7 @@ static lay::Technology *create_technology (const std::string &name) { lay::Technology *tech = new lay::Technology (); tech->set_name (name); - lay::Technologies::instance ()->add (tech); + lay::Technologies::instance ()->add_new (tech); return tech; } diff --git a/src/laybasic/laybasic/layAbstractMenu.cc b/src/laybasic/laybasic/layAbstractMenu.cc index 8ad69fabc..dccd1ea33 100644 --- a/src/laybasic/laybasic/layAbstractMenu.cc +++ b/src/laybasic/laybasic/layAbstractMenu.cc @@ -66,7 +66,7 @@ static const bool s_can_move_menu = true; #endif // --------------------------------------------------------------- -// Helper function to parse a title with potential shortcut and +// Helper function to parse a title with potential shortcut and // icon specification static void @@ -122,19 +122,19 @@ parse_menu_title (const std::string &s, std::string &title, std::string &shortcu // --------------------------------------------------------------- // AbstractMenuItem implementation -AbstractMenuItem::AbstractMenuItem () +AbstractMenuItem::AbstractMenuItem () : m_has_submenu (false), m_remove_on_empty (false) { // ... nothing yet .. } -AbstractMenuItem::AbstractMenuItem (const AbstractMenuItem &) +AbstractMenuItem::AbstractMenuItem (const AbstractMenuItem &) : m_has_submenu (false), m_remove_on_empty (false) -{ +{ // ... nothing yet .. } -void +void AbstractMenuItem::setup_item (const std::string &pn, const std::string &s, const Action &a) { m_basename.clear (); @@ -162,7 +162,7 @@ AbstractMenuItem::setup_item (const std::string &pn, const std::string &s, const set_action (a, false); } -void +void AbstractMenuItem::set_action (const Action &a, bool copy_properties) { Action acopy = a; @@ -187,13 +187,13 @@ AbstractMenuItem::set_action (const Action &a, bool copy_properties) } } -void +void AbstractMenuItem::set_action_title (const std::string &s) { m_action.set_title (s); } -void +void AbstractMenuItem::set_has_submenu () { m_has_submenu = true; @@ -214,10 +214,20 @@ static std::set *sp_actionHandles = 0; * @brief A specialization that provides a way to catch ambiguous key shortcuts */ class ActionObject - : public QAction + : public QAction { public: - ActionObject (QObject *parent) : QAction (parent) { } + ActionObject (QObject *parent) + : QAction (parent) + { + static size_t s_id = 0; + m_id = ++s_id; + } + + size_t id () const + { + return m_id; + } bool event(QEvent *e) { @@ -251,8 +261,18 @@ public: return QAction::event(e); } + +private: + size_t m_id; }; +static size_t +id_from_action (QAction *action) +{ + ActionObject *ao = dynamic_cast (action); + return ao ? ao->id () : 0; +} + ActionHandle::ActionHandle (QWidget *parent) : mp_menu (0), mp_action (new ActionObject (parent)), @@ -260,7 +280,7 @@ ActionHandle::ActionHandle (QWidget *parent) m_owned (true), m_visible (true), m_hidden (false) -{ +{ if (! sp_actionHandles) { sp_actionHandles = new std::set (); } @@ -273,11 +293,11 @@ ActionHandle::ActionHandle (QWidget *parent) ActionHandle::ActionHandle (QAction *action, bool owned) : mp_menu (0), mp_action (action), - m_ref_count (0), + m_ref_count (0), m_owned (owned), m_visible (true), m_hidden (false) -{ +{ if (! sp_actionHandles) { sp_actionHandles = new std::set (); } @@ -330,13 +350,13 @@ ActionHandle::~ActionHandle () } } -void -ActionHandle::add_ref () +void +ActionHandle::add_ref () { ++m_ref_count; } -void +void ActionHandle::remove_ref () { if (--m_ref_count == 0) { @@ -356,7 +376,7 @@ ActionHandle::menu () const return mp_menu; } -void +void ActionHandle::destroyed (QObject * /*obj*/) { mp_action = 0; @@ -548,7 +568,7 @@ Action::triggered_slot () END_PROTECTED } -void +void Action::set_title (const std::string &t) { if (qaction ()) { @@ -556,7 +576,7 @@ Action::set_title (const std::string &t) } } -std::string +std::string Action::get_title () const { if (qaction ()) { @@ -566,7 +586,7 @@ Action::get_title () const } } -void +void Action::set_shortcut (const QKeySequence &s) { if (mp_handle) { @@ -732,7 +752,7 @@ Action::set_separator (bool s) } } -void +void Action::set_icon (const std::string &filename) { if (qaction ()) { @@ -744,7 +764,7 @@ Action::set_icon (const std::string &filename) } } -std::string +std::string Action::get_tool_tip () const { if (qaction ()) { @@ -754,7 +774,7 @@ Action::get_tool_tip () const } } -void +void Action::set_tool_tip (const std::string &text) { if (qaction ()) { @@ -766,7 +786,7 @@ Action::set_tool_tip (const std::string &text) } } -std::string +std::string Action::get_icon_text () const { if (qaction ()) { @@ -776,7 +796,7 @@ Action::get_icon_text () const } } -void +void Action::set_icon_text (const std::string &icon_text) { if (qaction ()) { @@ -788,7 +808,7 @@ Action::set_icon_text (const std::string &icon_text) } } -void +void Action::set_object_name (const std::string &name) { if (qaction ()) { @@ -814,7 +834,7 @@ ConfigureAction::ConfigureAction (lay::PluginRoot *pr, const std::string &cname, } reg (); -} +} ConfigureAction::ConfigureAction (lay::PluginRoot *pr, const std::string &title, const std::string &cname, const std::string &cvalue) : Action (title), m_pr (pr), m_cname (cname), m_cvalue (cvalue), m_type (ConfigureAction::setter_type) @@ -831,19 +851,19 @@ ConfigureAction::ConfigureAction (lay::PluginRoot *pr, const std::string &title, } reg (); -} +} ConfigureAction::~ConfigureAction () { unreg (); } -void +void ConfigureAction::triggered () { if (m_type == boolean_type) { m_cvalue = tl::to_string (is_checked ()); - } + } m_pr->config_set (m_cname, m_cvalue); } @@ -880,7 +900,7 @@ ConfigureAction::configure (const std::string &value) set_checkable (true); set_checked (m_cvalue == value); - } + } } // --------------------------------------------------------------- @@ -897,7 +917,7 @@ AbstractMenu::create_action (const std::string &s) std::string tool_tip; parse_menu_title (s, title, shortcut, res, tool_tip); - + ActionHandle *ah = new ActionHandle (lay::AbstractMenuProvider::instance ()->menu_parent_widget ()); ah->ptr ()->setText (tl::to_qstring (title)); @@ -927,7 +947,7 @@ AbstractMenu::~AbstractMenu () // .. nothing yet .. } -void +void AbstractMenu::init (const MenuLayoutEntry *layout) { m_root.set_has_submenu (); @@ -943,12 +963,12 @@ AbstractMenu::make_exclusive_group (const std::string &name) QActionGroup *ag = new QActionGroup (this); ag->setExclusive (true); a = m_action_groups.insert (std::make_pair (name, ag)).first; - } + } return a->second; } -void +void AbstractMenu::build_detached (const std::string &name, QFrame *mbar) { // Clean up the menu bar before rebuilding @@ -1005,7 +1025,7 @@ AbstractMenu::build_detached (const std::string &name, QFrame *mbar) menu_layout->addStretch (1); } -void +void AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) { tl_assert (mp_provider != 0); @@ -1013,9 +1033,11 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) m_helper_menu_items.clear (); tbar->clear (); - std::set present_actions; + std::set > present_actions; QList a = mbar->actions (); - present_actions.insert (a.begin (), a.end ()); + for (QList::const_iterator i = a.begin (); i != a.end (); ++i) { + present_actions.insert (std::make_pair (id_from_action (*i), *i)); + } for (std::list::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) { @@ -1027,7 +1049,7 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } else if (c->name ().find ("@@") == 0) { - // nothing: let build_detached build the menu + // nothing: let build_detached build the menu } else if (c->name ().find ("@") == 0) { @@ -1035,9 +1057,9 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) QMenu *menu = new QMenu (tl::to_qstring (c->action ().get_title ())); // HINT: it is necessary to add the menu action to a widget below the main window. // Otherwise, the keyboard shortcuts do not work for menu items inside such a - // popup menu. It seems not to have a negative effect to add the menu to the + // popup menu. It seems not to have a negative effect to add the menu to the // main widget. - mp_provider->menu_parent_widget ()->addAction (menu->menuAction ()); + mp_provider->menu_parent_widget ()->addAction (menu->menuAction ()); c->set_action (Action (new ActionHandle (menu)), true); } @@ -1053,10 +1075,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) c->set_action (Action (new ActionHandle (menu)), true); } else { // Move the action to the end if present in the menu already - std::set::iterator a = present_actions.find (c->menu ()->menuAction ()); + std::set >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ())); if (a != present_actions.end ()) { if (s_can_move_menu) { - mbar->removeAction (*a); + mbar->removeAction (a->second); mbar->addMenu (c->menu ()); } present_actions.erase (*a); @@ -1071,10 +1093,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } else { // Move the action to the end if present in the menu already - std::set::iterator a = present_actions.find (c->action ().qaction ()); + std::set >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ().qaction ()), c->action ().qaction ())); if (a != present_actions.end ()) { if (s_can_move_menu) { - mbar->removeAction (*a); + mbar->removeAction (a->second); mbar->addAction (c->action ().qaction ()); } present_actions.erase (*a); @@ -1086,17 +1108,19 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } // Remove all actions that have vanished - for (std::set::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { - mbar->removeAction (*a); + for (std::set >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { + mbar->removeAction (a->second); } } -void +void AbstractMenu::build (QMenu *m, std::list &items) { - std::set present_actions; + std::set > present_actions; QList a = m->actions (); - present_actions.insert (a.begin (), a.end ()); + for (QList::const_iterator i = a.begin (); i != a.end (); ++i) { + present_actions.insert (std::make_pair (id_from_action (*i), *i)); + } for (std::list::iterator c = items.begin (); c != items.end (); ++c) { @@ -1111,10 +1135,10 @@ AbstractMenu::build (QMenu *m, std::list &items) c->set_action (Action (new ActionHandle (menu)), true); } else { // Move the action to the end if present in the menu already - std::set::iterator a = present_actions.find (c->menu ()->menuAction ()); + std::set >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ())); if (a != present_actions.end ()) { if (s_can_move_menu) { - m->removeAction (*a); + m->removeAction (a->second); m->addMenu (c->menu ()); } present_actions.erase (*a); @@ -1128,10 +1152,10 @@ AbstractMenu::build (QMenu *m, std::list &items) } else { // Move the action to the end if present in the menu already - std::set::iterator a = present_actions.find (c->action ().qaction ()); + std::set >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ().qaction ()), c->action ().qaction ())); if (a != present_actions.end ()) { if (s_can_move_menu) { - m->removeAction (*a); + m->removeAction (a->second); m->addAction (c->action ().qaction ()); } present_actions.erase (*a); @@ -1143,26 +1167,26 @@ AbstractMenu::build (QMenu *m, std::list &items) } // Remove all actions that have vanished - for (std::set::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { - m->removeAction (*a); + for (std::set >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { + m->removeAction (a->second); } } -void +void AbstractMenu::build (QToolBar *t, std::list &items) { for (std::list::iterator c = items.begin (); c != items.end (); ++c) { if (! c->children.empty ()) { - // To support tool buttons with menu we have to attach a helper menu - // item to the QAction object. + // To support tool buttons with menu we have to attach a helper menu + // item to the QAction object. // TODO: this hurts if we use this QAction otherwise. In this case, this // QAction would get a menu too. However, hopefully this usage is constrained // to special toolbar buttons only. // In order to be able to manage the QMenu ourselves, we must not give it a parent. QMenu *menu = new QMenu (0); - m_helper_menu_items.push_back (menu); // will be owned by the stable vector + m_helper_menu_items.push_back (menu); // will be owned by the stable vector c->action ().qaction ()->setMenu (menu); t->addAction (c->action ().qaction ()); build (menu, c->children); @@ -1183,7 +1207,7 @@ AbstractMenu::detached_menu (const std::string &name) } QMenu * -AbstractMenu::menu (const std::string &path) +AbstractMenu::menu (const std::string &path) { AbstractMenuItem *item = find_item_exact (path); if (item) { @@ -1214,7 +1238,7 @@ AbstractMenu::is_separator (const std::string &path) const return item != 0 && item->action ().is_separator (); } -Action +Action AbstractMenu::action (const std::string &path) const { const AbstractMenuItem *item = find_item_exact (path); @@ -1224,7 +1248,7 @@ AbstractMenu::action (const std::string &path) const return item->action (); } -std::vector +std::vector AbstractMenu::items (const std::string &path) const { std::vector res; @@ -1240,7 +1264,7 @@ AbstractMenu::items (const std::string &path) const return res; } -void +void AbstractMenu::insert_item (const std::string &p, const std::string &name, const Action &action) { typedef std::vector::iterator > > path_type; @@ -1271,7 +1295,7 @@ AbstractMenu::insert_item (const std::string &p, const std::string &name, const emit changed (); } -void +void AbstractMenu::insert_separator (const std::string &p, const std::string &name) { tl_assert (mp_provider != 0); // required to get the parent for the new QAction (via ActionHandle) @@ -1294,7 +1318,7 @@ AbstractMenu::insert_separator (const std::string &p, const std::string &name) emit changed (); } -void +void AbstractMenu::insert_menu (const std::string &p, const std::string &name, const Action &action) { typedef std::vector::iterator > > path_type; @@ -1324,13 +1348,24 @@ AbstractMenu::insert_menu (const std::string &p, const std::string &name, const emit changed (); } -void +void AbstractMenu::insert_menu (const std::string &path, const std::string &name, const std::string &title) { insert_menu (path, name, create_action (title)); } -void +void +AbstractMenu::clear_menu (const std::string &p) +{ + typedef std::vector::iterator > > path_type; + path_type path = find_item (p); + if (! path.empty () && ! path.back ().second->children.empty ()) { + path.back ().second->children.clear (); + emit changed (); + } +} + +void AbstractMenu::delete_item (const std::string &p) { typedef std::vector::iterator > > path_type; @@ -1387,7 +1422,7 @@ AbstractMenu::find_item_exact (const std::string &path) const } AbstractMenuItem * -AbstractMenu::find_item_exact (const std::string &path) +AbstractMenu::find_item_exact (const std::string &path) { tl::Extractor extr (path.c_str ()); AbstractMenuItem *item = &m_root; @@ -1406,7 +1441,7 @@ AbstractMenu::find_item_exact (const std::string &path) } if (n > 0) { return 0; - } + } item = &*c; @@ -1576,7 +1611,7 @@ AbstractMenu::find_item (const std::string &p) return path; } -void +void AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item) { tl_assert (mp_provider != 0); @@ -1609,7 +1644,7 @@ AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item) std::string tool_tip; parse_menu_title (layout->title, title, shortcut, res, tool_tip); - + a.set_separator (false); a.set_title (title); @@ -1641,7 +1676,7 @@ AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item) } } -std::vector +std::vector AbstractMenu::group (const std::string &name) const { std::vector grp; @@ -1649,7 +1684,7 @@ AbstractMenu::group (const std::string &name) const return grp; } -void +void AbstractMenu::collect_group (std::vector &grp, const std::string &name, const AbstractMenuItem &item) const { for (std::list::const_iterator c = item.children.begin (); c != item.children.end (); ++c) { diff --git a/src/laybasic/laybasic/layAbstractMenu.h b/src/laybasic/laybasic/layAbstractMenu.h index f86c3a674..c5a6ade53 100644 --- a/src/laybasic/laybasic/layAbstractMenu.h +++ b/src/laybasic/laybasic/layAbstractMenu.h @@ -784,6 +784,13 @@ public: */ void insert_menu (const std::string &path, const std::string &name, const std::string &title); + /** + * @brief Deletes the children of the item with the given path + * + * If the item does not exist or is not a menu, this method does nothing. + */ + void clear_menu (const std::string &path); + /** * @brief Delete the item given by the path * diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index d4f291c5a..7a4c2b5c6 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -42,6 +42,7 @@ #include "tlString.h" #include "tlLog.h" #include "tlAssert.h" +#include "tlExceptions.h" #include "layLayoutView.h" #include "layViewOp.h" #include "layViewObject.h" @@ -74,6 +75,7 @@ #include "rdbMarkerBrowserDialog.h" #include "tlXMLParser.h" #include "gsi.h" +#include "gtf.h" #include @@ -772,6 +774,37 @@ LayoutView::init_menu (lay::AbstractMenu &menu) lay::HierarchyControlPanel::init_menu (menu); } +void +LayoutView::update_menu (lay::LayoutView *view, lay::AbstractMenu &menu) +{ + std::string bm_menu = "bookmark_menu.goto_bookmark_menu"; + + if (menu.is_valid (bm_menu)) { + + menu.clear_menu (bm_menu); + + Action goto_bookmark_action = menu.action (bm_menu); + + if (view && view->bookmarks ().size () > 0) { + + goto_bookmark_action.set_enabled (true); + + const lay::BookmarkList &bookmarks = view->bookmarks (); + for (size_t i = 0; i < bookmarks.size (); ++i) { + Action action; + gtf::action_connect (action.qaction (), SIGNAL (triggered ()), view, SLOT (goto_bookmark ())); + action.set_title (bookmarks.name (i)); + action.qaction ()->setData (QVariant (int (i))); + menu.insert_item (bm_menu + ".end", tl::sprintf ("bookmark_%d", i + 1), action); + } + + } else { + goto_bookmark_action.set_enabled (false); + } + + } +} + void LayoutView::set_drawing_workers (int workers) { @@ -3650,6 +3683,24 @@ LayoutView::cancel () clear_selection (); } +void +LayoutView::bookmark_current_view () +{ + while (true) { + bool ok = false; + QString text = QInputDialog::getText (this, QObject::tr ("Enter Bookmark Name"), QObject::tr ("Bookmark name"), + QLineEdit::Normal, QString::null, &ok); + if (! ok) { + break; + } else if (text.isEmpty ()) { + QMessageBox::critical (this, QObject::tr ("Error"), QObject::tr ("Enter a name for the bookmark")); + } else { + bookmark_view (tl::to_string (text)); + break; + } + } +} + void LayoutView::manage_bookmarks () { @@ -3663,6 +3714,7 @@ void LayoutView::bookmarks (const BookmarkList &b) { m_bookmarks = b; + emit menu_needs_update (); } void @@ -3670,6 +3722,22 @@ LayoutView::bookmark_view (const std::string &name) { DisplayState state (box (), get_min_hier_levels (), get_max_hier_levels (), m_cellviews); m_bookmarks.add (name, state); + emit menu_needs_update (); +} + +void +LayoutView::goto_bookmark () +{ + BEGIN_PROTECTED + + QAction *action = dynamic_cast (sender ()); + tl_assert (action); + size_t id = size_t (action->data ().toInt ()); + if (bookmarks ().size () > id) { + goto_view (bookmarks ().state (id)); + } + + END_PROTECTED } void diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index 0cc3d63ff..5d5d2e4c3 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -1557,6 +1557,11 @@ public: */ void bookmark_view (const std::string &name); + /** + * @brief Asks for a bookmark name and bookmark the current view under this name + */ + void bookmark_current_view (); + /** * @brief Show the bookmark management form */ @@ -1603,6 +1608,12 @@ public: */ static void init_menu (lay::AbstractMenu &menu); + /** + * @brief Updates the menu for the given view + * If the view is 0, the menu shall be updated to reflect "no view active" + */ + static void update_menu (lay::LayoutView *view, lay::AbstractMenu &menu); + /** * @brief Query the default mode */ @@ -2530,6 +2541,7 @@ public slots: private slots: void active_cellview_changed (int index); + void goto_bookmark (); signals: /** @@ -2562,6 +2574,11 @@ signals: */ void edits_enabled_changed (); + /** + * @brief This signal is sent when the view wants to update the menu + */ + void menu_needs_update (); + protected: /** * @brief Establish the view operations diff --git a/src/laybasic/laybasic/layQtTools.cc b/src/laybasic/laybasic/layQtTools.cc index d9d0751a9..f7642e8d7 100644 --- a/src/laybasic/laybasic/layQtTools.cc +++ b/src/laybasic/laybasic/layQtTools.cc @@ -88,11 +88,13 @@ save_dialog_state (QWidget *w) } - for (QList::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) { - if (dynamic_cast (*c)) { - std::string cs = save_dialog_state (dynamic_cast (*c)); - if (! cs.empty ()) { - s += cs; + if (w) { + for (QList::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) { + if (dynamic_cast (*c)) { + std::string cs = save_dialog_state (dynamic_cast (*c)); + if (! cs.empty ()) { + s += cs; + } } } } diff --git a/src/laybasic/laybasic/layTechnology.cc b/src/laybasic/laybasic/layTechnology.cc index 0ff8b044d..8934cb547 100644 --- a/src/laybasic/laybasic/layTechnology.cc +++ b/src/laybasic/laybasic/layTechnology.cc @@ -45,6 +45,8 @@ Technologies::Technologies () Technologies::Technologies (const Technologies &other) : tl::Object () { + m_changed = false; + m_in_update = false; operator= (other); } @@ -115,19 +117,30 @@ Technologies::load_from_xml (const std::string &s) } void -Technologies::add (Technology *technology) +Technologies::add_tech (Technology *tech, bool replace_same) { - for (tl::stable_vector::iterator t = m_technologies.begin (); technology && t != m_technologies.end (); ++t) { - if (t->name () == technology->name ()) { - *t = *technology; - delete technology; - technology = 0; + if (! tech) { + return; + } + + std::auto_ptr tech_ptr (tech); + + Technology *t = 0; + for (tl::stable_vector::iterator i = m_technologies.begin (); !t && i != m_technologies.end (); ++i) { + if (i->name () == tech->name ()) { + t = i.operator-> (); } } - if (technology) { - m_technologies.push_back (technology); - technology->technology_changed_with_sender_event.add (this, &Technologies::technology_changed); + if (t) { + if (replace_same) { + *t = *tech; + } else { + throw tl::Exception (tl::to_string (QObject::tr ("A technology with this name already exists: %1").arg (tl::to_qstring (tech->name ())))); + } + } else { + m_technologies.push_back (tech_ptr.release ()); + tech->technology_changed_with_sender_event.add (this, &Technologies::technology_changed); } technologies_changed (); @@ -218,6 +231,7 @@ Technologies::technology_by_name (const std::string &name) } } + tl_assert (! m_technologies.empty ()); return &*m_technologies.begin (); } diff --git a/src/laybasic/laybasic/layTechnology.h b/src/laybasic/laybasic/layTechnology.h index 03f2ddc55..a7d130c7d 100644 --- a/src/laybasic/laybasic/layTechnology.h +++ b/src/laybasic/laybasic/layTechnology.h @@ -126,7 +126,22 @@ public: * The container becomes owner of the technology object. * Replaces a technology with the name of the given technology. */ - void add (Technology *technology); + void add (Technology *technology) + { + add_tech (technology, true /*replace*/); + } + + /** + * @brief Adds a technology with a new name + * + * Like \add, but throws an exception if a technology with this name + * already exists. Takes over ownership over the technology object. + * The technology object is discarded if an exception is thrown. + */ + void add_new (Technology *technology) + { + add_tech (technology, false /*throws exception on same name*/); + } /** * @brief Remove a technology with the given name from the setup @@ -233,6 +248,8 @@ private: tl::stable_vector m_technologies; bool m_changed; bool m_in_update; + + void add_tech (Technology *technology, bool replace_same); }; /** diff --git a/src/laybasic/unit_tests/layAbstractMenu.cc b/src/laybasic/unit_tests/layAbstractMenu.cc index 5edf78f8f..46bd3b3ff 100644 --- a/src/laybasic/unit_tests/layAbstractMenu.cc +++ b/src/laybasic/unit_tests/layAbstractMenu.cc @@ -124,5 +124,14 @@ TEST(1) menu.delete_item ("n1.c2"); EXPECT_EQ (menu_to_string (menu), "(n2)"); -} + menu.clear_menu ("n1"); + EXPECT_EQ (menu_to_string (menu), "(n2)"); + + menu.insert_menu ("end", "n1", lay::Action ("title:n1")); + menu.insert_item ("n1.begin", "c1", lay::Action ("title:c1")); + menu.insert_item ("n1.end", "c2", lay::Action ("title:c2")); + EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1,n1.c2))"); + menu.clear_menu ("n1"); + EXPECT_EQ (menu_to_string (menu), "(n2,n1)"); +} diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index 4f76d32e2..e6c64c658 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -915,26 +915,28 @@ void Macro::install_doc () const if (cls == 0) { tl::error << tl::to_string (QObject::tr ("Reading class doc from ")) << path () << ": " << tl::to_string (QObject::tr ("@method without preceeding @class")); - } + } else { - std::string n; - ex.read_word_or_quoted (n); + std::string n; + ex.read_word_or_quoted (n); - std::string doc; - while (++i < lines.size ()) { - std::string l = tl::trim (lines [i]); - if (l.find ("@method") == 0 || l.find ("@static_method") == 0) { - break; + std::string doc; + while (++i < lines.size ()) { + std::string l = tl::trim (lines [i]); + if (l.find ("@method") == 0 || l.find ("@static_method") == 0) { + break; + } + if (! doc.empty ()) { + doc += "\n"; + } + doc += lines [i]; } - if (! doc.empty ()) { - doc += "\n"; - } - doc += lines [i]; - } - --i; + --i; - ExternalMethod *meth = new ExternalMethod (n, doc, false, st); - cls->add_method (meth); + ExternalMethod *meth = new ExternalMethod (n, doc, false, st); + cls->add_method (meth); + + } } diff --git a/src/pya/pya/pya.cc b/src/pya/pya/pya.cc index c2d3ebac4..755d1a2bc 100644 --- a/src/pya/pya/pya.cc +++ b/src/pya/pya/pya.cc @@ -82,6 +82,27 @@ class PYAObjectBase; */ PythonInterpreter *sp_interpreter = 0; +// ------------------------------------------------------------------- + +/** + * @brief Normalizes the file path + * This function normalizes the file path so it only contains one + * kind of slashes on Windows. + */ +static +std::string normalize_path (const std::string &p) +{ +#if defined(__WIN32) + std::string np; + np.reserve (p.size ()); + for (const char *c = p.c_str (); *c; ++c) { + np += (*c == '\\' ? '/' : *c); + } + return np; +#else + return p; +#endif +} // ------------------------------------------------------------------- // The lookup table for the method overload resolution @@ -438,7 +459,7 @@ public: int line = frame->f_lineno; std::string fn; if (test_type (frame->f_code->co_filename, true)) { - fn = python2c (frame->f_code->co_filename); + fn = normalize_path (python2c (frame->f_code->co_filename)); } m_stack_trace.push_back (tl::BacktraceElement (fn, line)); @@ -1945,7 +1966,11 @@ property_setter_impl (int mid, PyObject *self, PyObject *value) if (meth->is_signal ()) { - if (PyObject_IsInstance (value, (PyObject *) PYASignal::cls)) { + if (!p) { + + // TODO: Static signals? + + } else if (PyObject_IsInstance (value, (PyObject *) PYASignal::cls)) { // assigning a signal to a signal works if it applies to the same handler - // this simplifies the implementation of += and -=. @@ -3221,7 +3246,7 @@ PythonInterpreter::prepare_trace (PyObject *fn_object) { std::map::const_iterator f = m_file_id_map.find (fn_object); if (f == m_file_id_map.end ()) { - f = m_file_id_map.insert (std::make_pair (fn_object, mp_current_exec_handler->id_for_path (this, python2c (fn_object)))).first; + f = m_file_id_map.insert (std::make_pair (fn_object, mp_current_exec_handler->id_for_path (this, normalize_path (python2c (fn_object))))).first; } return f->second; @@ -3511,4 +3536,3 @@ PythonInterpreter *PythonInterpreter::instance () } } - diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index 44029f3f0..ae401399f 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -495,7 +495,7 @@ public: bool compare (const ValueBase *other) const { - return m_value < dynamic_cast *> (other)->m_value; + return m_value < static_cast *> (other)->m_value; } std::string to_string () const; diff --git a/src/tl/tl/tlIntervalMap.h b/src/tl/tl/tlIntervalMap.h index ed477748a..194d0e5ce 100644 --- a/src/tl/tl/tlIntervalMap.h +++ b/src/tl/tl/tlIntervalMap.h @@ -213,7 +213,7 @@ public: ++lb0; } --lb; - if (lb != m_index_map.end () && i2 < lb->first.second) { + if (i2 < lb->first.second) { // the last one is overlapping above i2: cut it lb->first.first = i2; } else { diff --git a/src/tl/tl/tlThreadedWorkers.cc b/src/tl/tl/tlThreadedWorkers.cc index 648afcfb6..16a3e7c5a 100644 --- a/src/tl/tl/tlThreadedWorkers.cc +++ b/src/tl/tl/tlThreadedWorkers.cc @@ -424,17 +424,20 @@ JobBase::schedule (Task *task) { m_lock.lock (); - // Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition) if (m_stopping) { - m_lock.unlock (); - throw TaskTerminatedException (); - } - // Add the task to the task queue - m_task_list.put (task); + // Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition) + delete task; + + } else { + + // Add the task to the task queue + m_task_list.put (task); + + if (m_running) { + m_task_available_condition.wakeAll (); + } - if (m_running) { - m_task_available_condition.wakeAll (); } m_lock.unlock (); diff --git a/src/tl/tl/tlVariant.cc b/src/tl/tl/tlVariant.cc index b1b73dff0..d223ab537 100644 --- a/src/tl/tl/tlVariant.cc +++ b/src/tl/tl/tlVariant.cc @@ -1298,7 +1298,7 @@ Variant::can_convert_to_long () const case t_double: return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: - return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); + return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); diff --git a/testdata/bool/special2_au1.oas b/testdata/bool/special2_au1.oas index 471528b62..edc8aff89 100644 Binary files a/testdata/bool/special2_au1.oas and b/testdata/bool/special2_au1.oas differ diff --git a/testdata/bool/special2_au1_tz.oas b/testdata/bool/special2_au1_tz.oas index 57478e97f..b677cc72d 100644 Binary files a/testdata/bool/special2_au1_tz.oas and b/testdata/bool/special2_au1_tz.oas differ diff --git a/testdata/bool/special2_au2.oas b/testdata/bool/special2_au2.oas index dd1d49e6c..56d1c79e7 100644 Binary files a/testdata/bool/special2_au2.oas and b/testdata/bool/special2_au2.oas differ diff --git a/testdata/bool/special2_au2_tz.oas b/testdata/bool/special2_au2_tz.oas index 0deca4d3a..76d37a8c9 100644 Binary files a/testdata/bool/special2_au2_tz.oas and b/testdata/bool/special2_au2_tz.oas differ diff --git a/testdata/bool/special2_au4.oas b/testdata/bool/special2_au4.oas index 81ed86c90..6e698ef05 100644 Binary files a/testdata/bool/special2_au4.oas and b/testdata/bool/special2_au4.oas differ diff --git a/testdata/bool/special2_au4_tz.oas b/testdata/bool/special2_au4_tz.oas index a763ba8f9..1528b10ea 100644 Binary files a/testdata/bool/special2_au4_tz.oas and b/testdata/bool/special2_au4_tz.oas differ diff --git a/testdata/python/dbPCells.py b/testdata/python/dbPCells.py index 686df2e88..27a80057b 100644 --- a/testdata/python/dbPCells.py +++ b/testdata/python/dbPCells.py @@ -52,20 +52,25 @@ class BoxPCell(pya.PCellDeclaration): # create the shape cell.shapes(layers[0]).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2)) + + def can_create_from_shape(self, layout, shape, layer): + return shape.is_box() + + def transformation_from_shape(self, layout, shape, layer): + return pya.Trans(shape.box.center() - pya.Point()) + + def parameters_from_shape(self, layout, shape, layer): + return [ layout.get_info(layer), shape.box.width() * layout.dbu, shape.box.height() * layout.dbu ] - class PCellTestLib(pya.Library): - boxpcell = None - def __init__(self): # set the description self.description = "PCell test lib" # create the PCell declarations - boxpcell = BoxPCell() - self.layout().register_pcell("Box", boxpcell) + self.layout().register_pcell("Box", BoxPCell()) sb_index = self.layout().add_cell("StaticBox") l10 = self.layout().insert_layer(pya.LayerInfo(10, 0)) @@ -75,6 +80,60 @@ class PCellTestLib(pya.Library): # register us with the name "MyLib" self.register("PCellTestLib") + +# A PCell based on the declaration helper + +class BoxPCell2(pya.PCellDeclarationHelper): + + def __init__(self): + + super(BoxPCell2, self).__init__() + + self.param("layer", self.TypeLayer, "Layer", default = pya.LayerInfo(0, 0)) + self.param("width", self.TypeDouble, "Width", default = 1.0) + self.param("height", self.TypeDouble, "Height", default = 1.0) + + def display_text_impl(self): + # provide a descriptive text for the cell + return "Box2(L=" + str(self.layer) + ",W=" + ('%.3f' % self.width) + ",H=" + ('%.3f' % self.height) + ")" + + def produce_impl(self): + + dbu = self.layout.dbu + + # fetch the parameters + l = self.layer_layer + w = self.width / self.layout.dbu + h = self.height / self.layout.dbu + + # create the shape + self.cell.shapes(l).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2)) + + def can_create_from_shape_impl(self): + return self.shape.is_box() + + def transformation_from_shape_impl(self): + return pya.Trans(self.shape.box.center() - pya.Point()) + + def parameters_from_shape_impl(self): + self.layer = self.layout.get_info(self.layer) + self.width = self.shape.box.width() * self.layout.dbu + self.height = self.shape.box.height() * self.layout.dbu + +class PCellTestLib2(pya.Library): + + def __init__(self): + + # set the description + self.description = "PCell test lib2" + + # create the PCell declarations + self.layout().register_pcell("Box2", BoxPCell2()) + + # register us with the name "MyLib" + self.register("PCellTestLib2") + + def inspect_LayerInfo(self): return "<" + str(self) + ">" @@ -233,6 +292,75 @@ class DBPCellTests(unittest.TestCase): pcell_inst.cell_index = new_id self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-500,-100;500,100)") + l10 = ly.layer(10, 0) + c1.shapes(l10).insert(pya.Box(0, 10, 100, 210)) + l11 = ly.layer(11, 0) + c1.shapes(l11).insert(pya.Text("hello", pya.Trans())) + self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False) + self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True) + self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]") + self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110") + + + def test_1a(self): + + # instantiate and register the library + tl = PCellTestLib2() + + ly = pya.Layout(True) + ly.dbu = 0.01 + + li1 = find_layer(ly, "1/0") + self.assertEqual(li1 == None, True) + + ci1 = ly.add_cell("c1") + c1 = ly.cell(ci1) + + lib = pya.Library.library_by_name("PCellTestLib2") + self.assertEqual(lib != None, True) + pcell_decl = lib.layout().pcell_declaration("Box2") + + param = [ pya.LayerInfo(1, 0) ] # rest is filled with defaults + pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param) + pcell_var = ly.cell(pcell_var_id) + pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans())) + self.assertEqual(pcell_var.basic_name(), "Box2") + self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]") + self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") + self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") + self.assertEqual(pcell_var.pcell_parameter("height").__repr__(), "1.0") + self.assertEqual(c1.pcell_parameters(pcell_inst).__repr__(), "[<1/0>, 1.0, 1.0]") + self.assertEqual(nh(c1.pcell_parameters_by_name(pcell_inst)), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") + self.assertEqual(c1.pcell_parameter(pcell_inst, "height").__repr__(), "1.0") + self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") + self.assertEqual(pcell_inst["height"].__repr__(), "1.0") + self.assertEqual(pcell_inst.pcell_parameter("height").__repr__(), "1.0") + self.assertEqual(pcell_var.pcell_declaration().__repr__(), pcell_decl.__repr__()) + self.assertEqual(c1.pcell_declaration(pcell_inst).__repr__(), pcell_decl.__repr__()) + self.assertEqual(pcell_inst.pcell_declaration().__repr__(), pcell_decl.__repr__()) + + li1 = find_layer(ly, "1/0") + self.assertEqual(li1 == None, False) + pcell_inst.change_pcell_parameter("height", 2.0) + self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 2.0, 'layer': <1/0>, 'width': 1.0}") + + self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-50,-100;50,100)") + + param = { "layer": pya.LayerInfo(2, 0), "width": 2, "height": 1 } + li2 = ly.layer(2, 0) + c1.change_pcell_parameters(pcell_inst, param) + self.assertEqual(ly.begin_shapes(c1.cell_index(), li2).shape().__str__(), "box (-100,-50;100,50)") + + l10 = ly.layer(10, 0) + c1.shapes(l10).insert(pya.Box(0, 10, 100, 210)) + l11 = ly.layer(11, 0) + c1.shapes(l11).insert(pya.Text("hello", pya.Trans())) + self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False) + self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True) + self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]") + self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110") + + def test_2(self): # instantiate and register the library diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index 3bd511982..7a49fe621 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -488,443 +488,415 @@ END def test_5a - if RBA::Application::instance.is_editable? + # delete_cell + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) + assert_equal(c0.is_empty?, true) - # delete_cell - - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) - assert_equal(c0.is_empty?, true) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(c0.is_empty?, false) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - assert_equal(c0.is_empty?, false) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + assert_equal(l.is_valid_cell_index?(c0_index), true) + l.delete_cell(c0.cell_index) + assert_equal(l.is_valid_cell_index?(c0_index), false) - c0_index = c0.cell_index - assert_equal(l.is_valid_cell_index?(c0_index), true) - l.delete_cell(c0.cell_index) - assert_equal(l.is_valid_cell_index?(c0_index), false) + assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); + assert_equal(c3.is_empty?, true) - assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); - assert_equal(c3.is_empty?, true) + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) + assert_equal(c0.is_empty?, true) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) - assert_equal(c0.is_empty?, true) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(c0.is_empty?, false) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - assert_equal(c0.is_empty?, false) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + assert_equal(l.is_valid_cell_index?(c0_index), true) + l.cell(c0_index).delete + assert_equal(l.is_valid_cell_index?(c0_index), false) - c0_index = c0.cell_index - assert_equal(l.is_valid_cell_index?(c0_index), true) - l.cell(c0_index).delete - assert_equal(l.is_valid_cell_index?(c0_index), false) - - assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); - assert_equal(c3.is_empty?, true) - - end + assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); + assert_equal(c3.is_empty?, true) end def test_5b - if RBA::Application::instance.is_editable? + # delete_cells + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - # delete_cells - - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + assert_equal(c0.is_empty?, false) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - assert_equal(c0.is_empty?, false) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ll = l.dup - ll = l.dup + l.delete_cells([c0_index, c2_index]) + assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); - l.delete_cells([c0_index, c2_index]) - assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); - - l = ll - # Hint: even though we deleted c0 and c2, their indices are still valid - l.delete_cells([c2_index, c0_index]) - assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); - - end + l = ll + # Hint: even though we deleted c0 and c2, their indices are still valid + l.delete_cells([c2_index, c0_index]) + assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); end def test_5d - # TODO: undo tests crashes in non-editable mode! Should be checked properly. - if RBA::Application::instance.is_editable? + # prune_cell + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - # prune_cell - - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ll = l.dup - ll = l.dup + l.prune_cell(c0_index, -1) + assert_equal(collect_hier(l), ""); - l.prune_cell(c0_index, -1) - assert_equal(collect_hier(l), ""); + l = ll + ll = l.dup + # Hint: even though we deleted c0 and c2, their indices are still valid + l.prune_cell(c2_index, -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); - l = ll - ll = l.dup - # Hint: even though we deleted c0 and c2, their indices are still valid - l.prune_cell(c2_index, -1) - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ll = l.dup - ll = l.dup + l.cell(c0_index).prune_cell + assert_equal(collect_hier(l), ""); - l.cell(c0_index).prune_cell - assert_equal(collect_hier(l), ""); - - l = ll - ll = l.dup - # Hint: even though we deleted c0 and c2, their indices are still valid - l.cell(c2_index).prune_cell(-1) - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); - - end + l = ll + ll = l.dup + # Hint: even though we deleted c0 and c2, their indices are still valid + l.cell(c2_index).prune_cell(-1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); end def test_5e - # TODO: undo tests crashes in non-editable mode! Should be checked properly. - if RBA::Application::instance.is_editable? + # delete_cell_rec + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - # delete_cell_rec - - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ll = l.dup - ll = l.dup + l.delete_cell_rec(c0_index) + assert_equal(collect_hier(l), ""); - l.delete_cell_rec(c0_index) - assert_equal(collect_hier(l), ""); - - l = ll - ll = l.dup - # Hint: even though we deleted c0 and c2, their indices are still valid - l.delete_cell_rec(c2_index) - assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)"); - - end + l = ll + ll = l.dup + # Hint: even though we deleted c0 and c2, their indices are still valid + l.delete_cell_rec(c2_index) + assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)"); end def test_5f - # TODO: undo tests crashes in non-editable mode! Should be checked properly. - if RBA::Application::instance.is_editable? + # delete_cell_rec + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - # delete_cell_rec - - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)"); + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + ll = l.dup - ll = l.dup + l.flatten(c0_index, -1, false) + assert_equal(collect_hier(l), "[c0](P=)(C=)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); - l.flatten(c0_index, -1, false) - assert_equal(collect_hier(l), "[c0](P=)(C=)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); + l = ll + ll = l.dup + l.flatten(c0_index, -1, true) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); - l = ll - ll = l.dup - l.flatten(c0_index, -1, true) - assert_equal(collect_hier(l), "[c0](P=)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); + l = ll + ll = l.dup + l.flatten(c0_index, 0, false) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - l = ll - ll = l.dup - l.flatten(c0_index, 0, false) - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)"); + l = ll + ll = l.dup + l.flatten(c0_index, 1, false) + assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c0,c2)(C=)"); - l = ll - ll = l.dup - l.flatten(c0_index, 1, false) - assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c0,c2)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); + l = ll + ll = l.dup + l.flatten(c0_index, 1, true) + assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c3](P=c0)(C=)"); - l = ll - ll = l.dup - l.flatten(c0_index, 1, true) - assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c3](P=c0)(C=)"); + l = ll + ll = l.dup - l = ll - ll = l.dup + l.cell(c0_index).flatten(false) + assert_equal(collect_hier(l), "[c0](P=)(C=)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); - l.cell(c0_index).flatten(false) - assert_equal(collect_hier(l), "[c0](P=)(C=)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); + l = ll + ll = l.dup + l.cell(c0_index).flatten(true) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); - l = ll - ll = l.dup - l.cell(c0_index).flatten(true) - assert_equal(collect_hier(l), "[c0](P=)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); + l = ll + ll = l.dup + l.cell(c0_index).flatten(0, false) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - l = ll - ll = l.dup - l.cell(c0_index).flatten(0, false) - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)"); + l = ll + ll = l.dup + l.cell(c0_index).flatten(1, false) + assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c0,c2)(C=)"); - l = ll - ll = l.dup - l.cell(c0_index).flatten(1, false) - assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c0,c2)(C=)"); + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); - ii = l.begin_shapes(c0_index, 0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); + l = ll + ll = l.dup + l.cell(c0_index).flatten(1, true) + assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c3](P=c0)(C=)"); - l = ll - ll = l.dup - l.cell(c0_index).flatten(1, true) - assert_equal(collect_hier(l), "[c0](P=)(C=c3)/[c3](P=c0)(C=)"); + ii = l.cell(c0_index).begin_shapes_rec(0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); - ii = l.cell(c0_index).begin_shapes_rec(0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); - - ii = l.cell(c0_index).begin_shapes_rec(0); - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); - - end + ii = l.cell(c0_index).begin_shapes_rec(0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c3](1200,0;2200,1100)"); end def test_5g - # TODO: undo tests crashes in non-editable mode! Should be checked properly. - if RBA::Application::instance.is_editable? + # prune_subcells + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - # prune_subcells - - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ll = l.dup - ll = l.dup + l.prune_subcells(c0_index, -1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); - l.prune_subcells(c0_index, -1) - assert_equal(collect_hier(l), "[c0](P=)(C=)"); + l = ll + ll = l.dup + # Hint: even though we deleted c0 and c2, their indices are still valid + l.prune_subcells(c2_index, -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=)/[c3](P=c0)(C=)"); - l = ll - ll = l.dup - # Hint: even though we deleted c0 and c2, their indices are still valid - l.prune_subcells(c2_index, -1) - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=)/[c3](P=c0)(C=)"); + l = ll + # Hint: even though we deleted c0 and c2, their indices are still valid + l.prune_subcells(c0_index, 1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); - l = ll - # Hint: even though we deleted c0 and c2, their indices are still valid - l.prune_subcells(c0_index, 1) - assert_equal(collect_hier(l), "[c0](P=)(C=)"); + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); + c0_index = c0.cell_index + c2_index = c2.cell_index - c0_index = c0.cell_index - c2_index = c2.cell_index + ll = l.dup - ll = l.dup + l.cell(c0_index).prune_subcells + assert_equal(collect_hier(l), "[c0](P=)(C=)"); - l.cell(c0_index).prune_subcells - assert_equal(collect_hier(l), "[c0](P=)(C=)"); + l = ll + ll = l.dup + # Hint: even though we deleted c0 and c2, their indices are still valid + l.cell(c2_index).prune_subcells + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=)/[c3](P=c0)(C=)"); - l = ll - ll = l.dup - # Hint: even though we deleted c0 and c2, their indices are still valid - l.cell(c2_index).prune_subcells - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=)/[c3](P=c0)(C=)"); - - l = ll - # Hint: even though we deleted c0 and c2, their indices are still valid - l.cell(c0_index).prune_subcells(1) - assert_equal(collect_hier(l), "[c0](P=)(C=)"); - - end + l = ll + # Hint: even though we deleted c0 and c2, their indices are still valid + l.cell(c0_index).prune_subcells(1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); end @@ -1218,84 +1190,80 @@ END # copy shapes between cells - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - s = c0.shapes(1).insert(b) - s.set_property("p", 17) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + c0c.copy_shapes(c0) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) + + c0c.clear + lm = RBA::LayerMapping::new + lm.map(1, 0) + c0c.copy_shapes(c0, lm) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) - c0c = l.cell(l.add_cell("c0")) - c0c.copy_shapes(c0) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) - - c0c.clear - lm = RBA::LayerMapping::new - lm.map(1, 0) - c0c.copy_shapes(c0, lm) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) + c0c.copy_shapes(c0) + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") + assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") + assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - c0c.copy_shapes(c0) - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") - assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") - assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) + lm = RBA::LayerMapping::new + lm.create(l2, l) + layer1 = l2.find_layer(1, 0) + assert_equal(layer1, nil) + layer2 = l2.find_layer(2, 0) + assert_equal(layer2, nil) - lm = RBA::LayerMapping::new - lm.create(l2, l) - layer1 = l2.find_layer(1, 0) - assert_equal(layer1, nil) - layer2 = l2.find_layer(2, 0) - assert_equal(layer2, nil) + lm.create_full(l2, l) - lm.create_full(l2, l) - - c0c.copy_shapes(c0, lm) - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") - assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") - assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - - end + c0c.copy_shapes(c0, lm) + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") + assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") + assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) end @@ -1303,104 +1271,100 @@ END # move shapes between cells - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - s = c0.shapes(1).insert(b) - s.set_property("p", 17) + tt = RBA::Trans.new + c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + ll = l.dup - ll = l.dup + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + c0c.move_shapes(c0) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) + c0.move_shapes(c0c) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "") + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") + + lm = RBA::LayerMapping::new + lm.map(1, 0) + c0c.move_shapes(c0, lm) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) - c0c = l.cell(l.add_cell("c0")) - c0c.move_shapes(c0) - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) - c0.move_shapes(c0c) - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "") - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - - lm = RBA::LayerMapping::new - lm.map(1, 0) - c0c.move_shapes(c0, lm) - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) + l = ll.dup + c0 = l.cell("c0") - l = ll.dup - c0 = l.cell("c0") + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) + c0c.move_shapes(c0) + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") + assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") + assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - c0c.move_shapes(c0) - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") - assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") - assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) + l = ll.dup + c0 = l.cell("c0") - l = ll.dup - c0 = l.cell("c0") + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) + lm = RBA::LayerMapping::new + lm.create(l2, l) + layer1 = l2.find_layer(1, 0) + assert_equal(layer1, nil) + layer2 = l2.find_layer(2, 0) + assert_equal(layer2, nil) - lm = RBA::LayerMapping::new - lm.create(l2, l) - layer1 = l2.find_layer(1, 0) - assert_equal(layer1, nil) - layer2 = l2.find_layer(2, 0) - assert_equal(layer2, nil) + lm.create_full(l2, l) - lm.create_full(l2, l) - - c0c.move_shapes(c0, lm) - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") - assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") - assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - - end + c0c.move_shapes(c0, lm) + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)") + assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") + assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) end @@ -1408,55 +1372,51 @@ END # copy instances between cells - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - s = c0.shapes(1).insert(b) - s.set_property("p", 17) + tt = RBA::Trans.new + i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + i0.set_property("p", 17) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - i0.set_property("p", 17) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + c0c.copy_instances(c0) + i0 = nil + c0c.each_inst { |i| i.cell_index == c1.cell_index && i0 = i } + assert_equal(i0.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - c0c = l.cell(l.add_cell("c0")) + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) + err = false + begin c0c.copy_instances(c0) - i0 = nil - c0c.each_inst { |i| i.cell_index == c1.cell_index && i0 = i } - assert_equal(i0.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) - err = false - begin - c0c.copy_instances(c0) - rescue => ex - err = true - end - assert_equal(err, true) - - end + rescue => ex + err = true + end + assert_equal(err, true) end @@ -1464,57 +1424,53 @@ END # move instances between cells - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - s = c0.shapes(1).insert(b) - s.set_property("p", 17) + tt = RBA::Trans.new + i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + i0.set_property("p", 17) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - i0.set_property("p", 17) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + c0c.move_instances(c0) + i0 = nil + c0c.each_inst { |i| i.cell_index == c1.cell_index && i0 = i } + assert_equal(i0.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - c0c = l.cell(l.add_cell("c0")) - c0c.move_instances(c0) - i0 = nil - c0c.each_inst { |i| i.cell_index == c1.cell_index && i0 = i } - assert_equal(i0.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) - err = false - begin - c0c.copy_instances(c0) - rescue => ex - err = true - end - assert_equal(err, true) - - end + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) + err = false + begin + c0c.copy_instances(c0) + rescue => ex + err = true + end + assert_equal(err, true) end @@ -1522,62 +1478,58 @@ END # copy cell tree - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + s = c1.shapes(0).insert(b) + s.set_property("p", 17) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + c0.shapes(1).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - s = c1.shapes(0).insert(b) - s.set_property("p", 17) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - c0.shapes(1).insert(b) + tt = RBA::Trans.new + i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + i0.set_property("p", 18) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - i0.set_property("p", 18) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + c0c.copy_tree(c0) - c0c = l.cell(l.add_cell("c0")) - c0c.copy_tree(c0) + i0 = nil + c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) + assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17) - i0 = nil - c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) - assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) + c0c.copy_tree(c0) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) - c0c.copy_tree(c0) + i0 = nil + c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) - i0 = nil - c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) - - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(l2.cell("c1").begin_shapes_rec(layer1).shape.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(layer1), l2), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") - assert_equal(collect(c0c.begin_shapes_rec(layer2), l2), "[c0](2,202;2002,2402)") - - end + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(l2.cell("c1").begin_shapes_rec(layer1).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(layer1), l2), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") + assert_equal(collect(c0c.begin_shapes_rec(layer2), l2), "[c0](2,202;2002,2402)") end @@ -1585,80 +1537,76 @@ END # move cell tree - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + s = c1.shapes(0).insert(b) + s.set_property("p", 17) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + c0.shapes(1).insert(b) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - s = c1.shapes(0).insert(b) - s.set_property("p", 17) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - c0.shapes(1).insert(b) + tt = RBA::Trans.new + i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + i0.set_property("p", 18) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - i0.set_property("p", 18) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + ll = l.dup - ll = l.dup + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + c0c.move_tree(c0) + assert_equal(l.has_cell?("c0"), true) + assert_equal(l.has_cell?("c1"), false) + assert_equal(l.has_cell?("c2"), false) + assert_equal(l.has_cell?("c3"), false) - c0c = l.cell(l.add_cell("c0")) - c0c.move_tree(c0) - assert_equal(l.has_cell?("c0"), true) - assert_equal(l.has_cell?("c1"), false) - assert_equal(l.has_cell?("c2"), false) - assert_equal(l.has_cell?("c3"), false) + i0 = nil + c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) + assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17) - i0 = nil - c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) - assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17) + assert_equal(collect(c0.begin_shapes_rec(0), l), "") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + l = ll.dup + c0 = l.cell("c0") - l = ll.dup - c0 = l.cell("c0") + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) + c0c.move_tree(c0) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) - c0c.move_tree(c0) + assert_equal(collect(c0.begin_shapes_rec(0), l), "") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(l.has_cell?("c0"), true) + assert_equal(l.has_cell?("c1"), false) + assert_equal(l.has_cell?("c2"), false) + assert_equal(l.has_cell?("c3"), false) - assert_equal(collect(c0.begin_shapes_rec(0), l), "") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(l.has_cell?("c0"), true) - assert_equal(l.has_cell?("c1"), false) - assert_equal(l.has_cell?("c2"), false) - assert_equal(l.has_cell?("c3"), false) + i0 = nil + c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) - i0 = nil - c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) - - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(l2.cell("c1").begin_shapes_rec(layer1).shape.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(layer1), l2), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") - assert_equal(collect(c0c.begin_shapes_rec(layer2), l2), "[c0](2,202;2002,2402)") - - end + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(l2.cell("c1").begin_shapes_rec(layer1).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(layer1), l2), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") + assert_equal(collect(c0c.begin_shapes_rec(layer2), l2), "[c0](2,202;2002,2402)") end @@ -1666,83 +1614,79 @@ END # copy shapes between cell trees - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - s = c0.shapes(1).insert(b) - s.set_property("p", 17) + tt = RBA::Trans.new + s = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + s.set_property("p", 18) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - s = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - s.set_property("p", 18) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + cm = RBA::CellMapping::new + cm.for_single_cell(l, c0c.cell_index, l, c0.cell_index) + c0c.copy_tree_shapes(c0, cm) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c0$1](0,100;1000,1200)/[c0$1](100,0;1100,1100)/[c0$1](-1200,0;-100,1000)/[c0$1](1200,0;2200,1100)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) + + c0c.clear + lm = RBA::LayerMapping::new + lm.map(1, 0) + c0c.copy_tree_shapes(c0, cm, lm) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) - c0c = l.cell(l.add_cell("c0")) - cm = RBA::CellMapping::new - cm.for_single_cell(l, c0c.cell_index, l, c0.cell_index) - c0c.copy_tree_shapes(c0, cm) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c0$1](0,100;1000,1200)/[c0$1](100,0;1100,1100)/[c0$1](-1200,0;-100,1000)/[c0$1](1200,0;2200,1100)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) - - c0c.clear - lm = RBA::LayerMapping::new - lm.map(1, 0) - c0c.copy_tree_shapes(c0, cm, lm) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) + c0c.clear + cm.for_single_cell_full(l, c0c.cell_index, l, c0.cell_index) + c0c.copy_tree_shapes(c0, cm) + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) - c0c.clear - cm.for_single_cell_full(l, c0c.cell_index, l, c0.cell_index) - c0c.copy_tree_shapes(c0, cm) - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) + i0 = nil + c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) - i0 = nil - c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) + cm.for_single_cell_full(l2, c0c.cell_index, l, c0.cell_index) + c0c.copy_tree_shapes(c0, cm) + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") + assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") + assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - cm.for_single_cell_full(l2, c0c.cell_index, l, c0.cell_index) - c0c.copy_tree_shapes(c0, cm) - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") - assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") - assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - - i0 = nil - c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) - - end + i0 = nil + c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) end @@ -1750,115 +1694,107 @@ END # move shapes between cell trees - if RBA::Application::instance.is_editable? + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) - b = RBA::Box.new(0, 100, 1000, 1200) - c0.shapes(0).insert(b) - c1.shapes(0).insert(b) - c2.shapes(0).insert(b) - c3.shapes(0).insert(b) - b = RBA::Box.new(1, 101, 1001, 1201) - s = c0.shapes(1).insert(b) - s.set_property("p", 17) + tt = RBA::Trans.new + s = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + assert_equal(s.is_pcell?, false) + assert_equal(s.pcell_declaration, nil) + assert_equal(s.pcell_parameters, []) + assert_equal(s.pcell_parameters_by_name, {}) + s.set_property("p", 18) + c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) + c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - tt = RBA::Trans.new - s = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - assert_equal(s.is_pcell?, false) - assert_equal(s.pcell_declaration, nil) - assert_equal(s.pcell_parameters, []) - assert_equal(s.pcell_parameters_by_name, {}) - s.set_property("p", 18) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + ll = l.dup - ll = l.dup + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + c0c = l.cell(l.add_cell("c0")) + cm = RBA::CellMapping::new + cm.for_single_cell(l, c0c.cell_index, l, c0.cell_index) + c0c.move_tree_shapes(c0, cm) + assert_equal(collect(c0.begin_shapes_rec(0), l), "") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c0$1](0,100;1000,1200)/[c0$1](100,0;1100,1100)/[c0$1](-1200,0;-100,1000)/[c0$1](1200,0;2200,1100)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) - c0c = l.cell(l.add_cell("c0")) - cm = RBA::CellMapping::new - cm.for_single_cell(l, c0c.cell_index, l, c0.cell_index) - c0c.move_tree_shapes(c0, cm) - assert_equal(collect(c0.begin_shapes_rec(0), l), "") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c0$1](0,100;1000,1200)/[c0$1](100,0;1100,1100)/[c0$1](-1200,0;-100,1000)/[c0$1](1200,0;2200,1100)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) + l = ll.dup + c0 = l.cell("c0") + c0c = l.cell(l.add_cell("c0")) + + lm = RBA::LayerMapping::new + lm.map(1, 0) + c0c.move_tree_shapes(c0, cm, lm) + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) - l = ll.dup - c0 = l.cell("c0") - c0c = l.cell(l.add_cell("c0")) - - lm = RBA::LayerMapping::new - lm.map(1, 0) - c0c.move_tree_shapes(c0, cm, lm) - assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil) + l = ll.dup + c0 = l.cell("c0") + c0c = l.cell(l.add_cell("c0")) + + cm.for_single_cell_full(l, c0c.cell_index, l, c0.cell_index) + c0c.move_tree_shapes(c0, cm) + assert_equal(collect(c0.begin_shapes_rec(0), l), "") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") + assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") + assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) - l = ll.dup - c0 = l.cell("c0") - c0c = l.cell(l.add_cell("c0")) - - cm.for_single_cell_full(l, c0c.cell_index, l, c0.cell_index) - c0c.move_tree_shapes(c0, cm) - assert_equal(collect(c0.begin_shapes_rec(0), l), "") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") - assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)") - assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17) + i0 = nil + c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) - i0 = nil - c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) + l = ll.dup + c0 = l.cell("c0") + + l2 = RBA::Layout::new + l2.dbu = 0.0005 + c0c = l2.cell(l2.add_cell("c0")) - l = ll.dup - c0 = l.cell("c0") - - l2 = RBA::Layout::new - l2.dbu = 0.0005 - c0c = l2.cell(l2.add_cell("c0")) + cm.for_single_cell_full(l2, c0c.cell_index, l, c0.cell_index) + c0c.move_tree_shapes(c0, cm) + assert_equal(collect(c0.begin_shapes_rec(0), l), "") + assert_equal(collect(c0.begin_shapes_rec(1), l), "") + layer1 = l2.find_layer(1, 0) + layer2 = l2.find_layer(2, 0) + assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") + assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) + assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") + assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - cm.for_single_cell_full(l2, c0c.cell_index, l, c0.cell_index) - c0c.move_tree_shapes(c0, cm) - assert_equal(collect(c0.begin_shapes_rec(0), l), "") - assert_equal(collect(c0.begin_shapes_rec(1), l), "") - layer1 = l2.find_layer(1, 0) - layer2 = l2.find_layer(2, 0) - assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)") - assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil) - assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)") - assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17) - - i0 = nil - c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } - assert_equal(i0.property("p"), 18) - - end + i0 = nil + c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i } + assert_equal(i0.property("p"), 18) end def test_16 - if !RBA::Application::instance.is_editable? - return - end - # fill tool l = nil @@ -1980,9 +1916,6 @@ END def test_18 ly = RBA::Layout::new - if !ly.is_editable? - return - end cell = ly.create_cell("X") diff --git a/testdata/ruby/dbPCells.rb b/testdata/ruby/dbPCells.rb index 938c0d1f6..1f3e30950 100644 --- a/testdata/ruby/dbPCells.rb +++ b/testdata/ruby/dbPCells.rb @@ -61,6 +61,18 @@ class BoxPCell < RBA::PCellDeclaration end + def can_create_from_shape(layout, shape, layer) + return shape.is_box? + end + + def transformation_from_shape(layout, shape, layer) + return RBA::Trans::new(shape.box.center - RBA::Point::new) + end + + def parameters_from_shape(layout, shape, layer) + return [ layout.get_info(layer), shape.box.width * layout.dbu, shape.box.height * layout.dbu ] + end + end class PCellTestLib < RBA::Library @@ -85,6 +97,72 @@ class PCellTestLib < RBA::Library end +# A PCell based on the declaration helper + +class BoxPCell2 < RBA::PCellDeclarationHelper + + def initialize + + super() + + param("layer", BoxPCell2::TypeLayer, "Layer", :default => RBA::LayerInfo::new(0, 0)) + param("width", BoxPCell2::TypeDouble, "Width", :default => 1.0) + param("height", BoxPCell2::TypeDouble, "Height", :default => 1.0) + + end + + def display_text_impl + # provide a descriptive text for the cell + return "Box2(L=" + layer.to_s + ",W=" + ('%.3f' % width) + ",H=" + ('%.3f' % height) + ")" + end + + def produce_impl + + # fetch the parameters + l = layer_layer + w = width / layout.dbu + h = height / layout.dbu + + # create the shape + cell.shapes(l).insert(RBA::Box::new(-w / 2, -h / 2, w / 2, h / 2)) + + end + + def can_create_from_shape_impl + return self.shape.is_box? + end + + def transformation_from_shape_impl + return RBA::Trans::new(shape.box.center - RBA::Point::new) + end + + def parameters_from_shape_impl + # NOTE: because there is one parameter called "layer" already, we need to use + # the "_layer" fallback to access the argument to this method + set_layer(_layout.get_info(_layer)) + set_width(shape.box.width * _layout.dbu) + set_height(shape.box.height * _layout.dbu) + end + +end + +class PCellTestLib2 < RBA::Library + + def initialize + + # set the description + description = "PCell test lib2" + + # create the PCell declarations + layout.register_pcell("Box2", BoxPCell2::new) + + # register us with the name "MyLib" + self.register("PCellTestLib2") + + end + +end + # A helper for testing: provide an inspect method class RBA::LayerInfo def inspect @@ -115,8 +193,7 @@ class DBPCell_TestClass < TestBase ly = RBA::Layout::new(true) ly.dbu = 0.01 - li1 = ly.layer_indices.find { |li| ly.get_info(li).to_s == "1/0" } - assert_equal(li1 == nil, true) + li1 = ly.layer(1, 0) ci1 = ly.add_cell("c1") c1 = ly.cell(ci1) @@ -241,10 +318,84 @@ class DBPCell_TestClass < TestBase pcell_inst.cell_index = new_id assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-500,-100;500,100)") -#ly.destroy + l10 = ly.layer(10, 0) + c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210)) + l11 = ly.layer(11, 0) + c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new)) + assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false) + assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true) + assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]") + assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110") + + ly.destroy ensure -#tl.delete + tl.delete + end + + end + + def test_1a + + # instantiate and register the library + tl = PCellTestLib2::new + + begin + + ly = RBA::Layout::new(true) + ly.dbu = 0.01 + + ci1 = ly.add_cell("c1") + c1 = ly.cell(ci1) + + lib = RBA::Library.library_by_name("PCellTestLib2") + assert_equal(lib != nil, true) + pcell_decl = lib.layout().pcell_declaration("Box2") + + param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults + pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param) + pcell_var = ly.cell(pcell_var_id) + pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new)) + assert_equal(pcell_var.basic_name, "Box2") + assert_equal(pcell_var.pcell_parameters().inspect, "[<1/0>, 1.0, 1.0]") + assert_equal(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") + assert_equal(norm_hash(pcell_var.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}") + assert_equal(pcell_var.pcell_parameter("height").inspect(), "1.0") + assert_equal(c1.pcell_parameters(pcell_inst).inspect(), "[<1/0>, 1.0, 1.0]") + assert_equal(norm_hash(c1.pcell_parameters_by_name(pcell_inst)), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}") + assert_equal(c1.pcell_parameter(pcell_inst, "height").inspect(), "1.0") + assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}") + assert_equal(pcell_inst["height"].inspect(), "1.0") + assert_equal(pcell_inst.pcell_parameter("height").inspect(), "1.0") + assert_equal(pcell_var.pcell_declaration().inspect(), pcell_decl.inspect) + assert_equal(c1.pcell_declaration(pcell_inst).inspect(), pcell_decl.inspect) + assert_equal(pcell_inst.pcell_declaration().inspect(), pcell_decl.inspect) + + li1 = ly.layer(1, 0) + assert_equal(li1 == nil, false) + pcell_inst.change_pcell_parameter("height", 2.0) + assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>2.0, \"layer\"=><1/0>, \"width\"=>1.0}") + + assert_equal(ly.begin_shapes(c1.cell_index(), li1).shape().to_s, "box (-50,-100;50,100)") + + param = { "layer" => RBA::LayerInfo::new(2, 0), "width" => 2, "height" => 1 } + li2 = ly.layer(2, 0) + c1.change_pcell_parameters(pcell_inst, param) + assert_equal(ly.begin_shapes(c1.cell_index(), li2).shape().to_s, "box (-100,-50;100,50)") + + l10 = ly.layer(10, 0) + c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210)) + l11 = ly.layer(11, 0) + c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new)) + assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false) + assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true) + assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]") + assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110") + + ly.destroy + + ensure + tl.delete end end