diff --git a/src/db/db/dbCell.cc b/src/db/db/dbCell.cc index 64efb2aaf..83acc1182 100644 --- a/src/db/db/dbCell.cc +++ b/src/db/db/dbCell.cc @@ -187,6 +187,17 @@ Cell::clear (unsigned int index) } } +void +Cell::clear (unsigned int index, unsigned int types) +{ + shapes_map::iterator s = m_shapes_map.find(index); + if (s != m_shapes_map.end() && ! s->second.empty ()) { + mp_layout->invalidate_bboxes (index); // HINT: must come before the change is done! + s->second.clear (types); + m_bbox_needs_update = true; + } +} + Cell::shapes_type & Cell::shapes (unsigned int index) { @@ -344,6 +355,20 @@ Cell::copy (unsigned int src, unsigned int dest) } } +void +Cell::copy (unsigned int src, unsigned int dest, unsigned int types) +{ + if (src != dest) { + shapes (dest).insert (shapes (src), types); + } else { + // When duplicating the layer, first create a copy to avoid problems with non-stable containers + // Hint: using the assignment and not the copy ctor does not copy the db::Manager association. + db::Shapes shape_copy; + shape_copy.insert (shapes (src), types); + shapes (dest).insert (shape_copy); + } +} + void Cell::move (unsigned int src, unsigned int dest) { @@ -353,6 +378,15 @@ Cell::move (unsigned int src, unsigned int dest) } } +void +Cell::move (unsigned int src, unsigned int dest, unsigned int types) +{ + if (src != dest) { + copy (src, dest, types); + clear (src, types); + } +} + void Cell::swap (unsigned int i1, unsigned int i2) { diff --git a/src/db/db/dbCell.h b/src/db/db/dbCell.h index 00319ee08..2d04bc0ba 100644 --- a/src/db/db/dbCell.h +++ b/src/db/db/dbCell.h @@ -182,6 +182,13 @@ public: */ void copy (unsigned int src, unsigned int dest); + /** + * @brief Copy the shapes from layer src to dest (only shapes from given classes) + * + * The target layer is not overwritten. Instead, the shapes are added to the target layer's shapes. + */ + void copy (unsigned int src, unsigned int dest, unsigned int types); + /** * @brief Move the shapes from layer src to dest * @@ -189,6 +196,13 @@ public: */ void move (unsigned int src, unsigned int dest); + /** + * @brief Move the shapes from layer src to dest (only shapes from given classes) + * + * The target layer is not overwritten. Instead, the shapes are added to the target layer's shapes. + */ + void move (unsigned int src, unsigned int dest, unsigned int types); + /** * @brief Swap the layers given */ @@ -199,7 +213,12 @@ public: */ void clear (unsigned int index); - /** + /** + * @brief Clear the shapes on the given layer (only the shapes from the given classes) + */ + void clear (unsigned int index, unsigned int types); + + /** * @brief Erase a cell instance given by a instance proxy * * Erasing a cell instance will destroy the sorting order and invalidate diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 0b53b70a1..32bba3042 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1971,7 +1971,19 @@ Layout::move_layer (unsigned int src, unsigned int dest) } } -void +void +Layout::move_layer (unsigned int src, unsigned int dest, unsigned int flags) +{ + tl_assert (m_layers.layer_state (src) != LayoutLayers::Free); + tl_assert (m_layers.layer_state (dest) != LayoutLayers::Free); + + // move the shapes + for (iterator c = begin (); c != end (); ++c) { + c->move (src, dest, flags); + } +} + +void Layout::copy_layer (unsigned int src, unsigned int dest) { tl_assert (m_layers.layer_state (src) != LayoutLayers::Free); @@ -1983,7 +1995,19 @@ Layout::copy_layer (unsigned int src, unsigned int dest) } } -void +void +Layout::copy_layer (unsigned int src, unsigned int dest, unsigned int flags) +{ + tl_assert (m_layers.layer_state (src) != LayoutLayers::Free); + tl_assert (m_layers.layer_state (dest) != LayoutLayers::Free); + + // copy the shapes + for (iterator c = begin (); c != end (); ++c) { + c->copy (src, dest, flags); + } +} + +void Layout::clear_layer (unsigned int n) { tl_assert (m_layers.layer_state (n) != LayoutLayers::Free); @@ -1994,7 +2018,18 @@ Layout::clear_layer (unsigned int n) } } -void +void +Layout::clear_layer (unsigned int n, unsigned int flags) +{ + tl_assert (m_layers.layer_state (n) != LayoutLayers::Free); + + // clear the shapes + for (iterator c = begin (); c != end (); ++c) { + c->clear (n, flags); + } +} + +void Layout::delete_layer (unsigned int n) { tl_assert (m_layers.layer_state (n) != LayoutLayers::Free); diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index cb79d2a8a..353ad2ad9 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1377,7 +1377,15 @@ public: */ void move_layer (unsigned int src, unsigned int dest); - /** + /** + * @brief Move a layer (selected shape types only) + * + * Move a layer from the source to the target. The target is not cleared before, so that this method + * merges shapes from the source with the target layer. The source layer is empty after that operation. + */ + void move_layer (unsigned int src, unsigned int dest, unsigned int flags); + + /** * @brief Copy a layer * * Copy a layer from the source to the target. The target is not cleared before, so that this method @@ -1385,14 +1393,29 @@ public: */ void copy_layer (unsigned int src, unsigned int dest); - /** + /** + * @brief Copy a layer (selected shape types only) + * + * Copy a layer from the source to the target. The target is not cleared before, so that this method + * merges shapes from the source with the target layer. + */ + void copy_layer (unsigned int src, unsigned int dest, unsigned int flags); + + /** * @brief Clear a layer * * Clears the layer: removes all shapes. */ void clear_layer (unsigned int n); - /** + /** + * @brief Clear a layer (selected shapes only) + * + * Clears the layer: removes the shapes of the type given the flags (ShapeIterator::shapes_type) + */ + void clear_layer (unsigned int n, unsigned int flags); + + /** * @brief Delete a layer * * This does free the shapes of the cells and remembers the diff --git a/src/db/db/dbShapes.cc b/src/db/db/dbShapes.cc index d8b439404..48736115d 100644 --- a/src/db/db/dbShapes.cc +++ b/src/db/db/dbShapes.cc @@ -81,6 +81,12 @@ inline bool needs_translate (object_tag /*tag*/) return tl::is_equal_type::can_deref, tl::True> () || tl::is_equal_type::is_array, tl::True> (); } +inline bool type_mask_applies (const db::LayerBase *layer, unsigned int flags) +{ + unsigned int tm = layer->type_mask (); + return (((flags & db::ShapeIterator::Properties) == 0 || (tm & db::ShapeIterator::Properties) != 0) && (flags & tm) != 0); +} + // --------------------------------------------------------------------------------------- // layer_op implementation @@ -214,7 +220,13 @@ Shapes::insert (const Shapes &d) } void -Shapes::do_insert (const Shapes &d) +Shapes::insert (const Shapes &d, unsigned int flags) +{ + do_insert (d, flags); +} + +void +Shapes::do_insert (const Shapes &d, unsigned int flags) { // shortcut for "nothing to do" if (d.empty ()) { @@ -228,10 +240,12 @@ Shapes::do_insert (const Shapes &d) m_layers.reserve (d.m_layers.size ()); for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { - m_layers.push_back ((*l)->clone ()); - if (manager () && manager ()->transacting ()) { - check_is_editable_for_undo_redo (); - manager ()->queue (this, new FullLayerOp (true, m_layers.back ())); + if (type_mask_applies (*l, flags)) { + m_layers.push_back ((*l)->clone ()); + if (manager () && manager ()->transacting ()) { + check_is_editable_for_undo_redo (); + manager ()->queue (this, new FullLayerOp (true, m_layers.back ())); + } } } @@ -239,7 +253,9 @@ Shapes::do_insert (const Shapes &d) } else { for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { - (*l)->insert_into (this); + if (type_mask_applies (*l, flags)) { + (*l)->insert_into (this); + } } } @@ -247,14 +263,18 @@ Shapes::do_insert (const Shapes &d) // the target is standalone - dereference for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { - (*l)->deref_into (this); + if (type_mask_applies (*l, flags)) { + (*l)->deref_into (this); + } } } else { // both shape containers are in separate spaces - translate for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { - (*l)->translate_into (this, shape_repository (), array_repository ()); + if (type_mask_applies (*l, flags)) { + (*l)->translate_into (this, shape_repository (), array_repository ()); + } } } @@ -1046,6 +1066,41 @@ Shapes::clear () } } +void +Shapes::clear (unsigned int flags) +{ + if (!m_layers.empty ()) { + + invalidate_state (); // HINT: must come before the change is done! + + tl::vector new_layers; + + for (tl::vector::const_iterator l = m_layers.end (); l != m_layers.begin (); ) { + + // because the undo stack will do a push, we need to remove layers from the back (this is the last undo + // element to be executed) + --l; + + if (type_mask_applies (*l, flags)) { + + if (manager () && manager ()->transacting ()) { + check_is_editable_for_undo_redo (); + manager ()->queue (this, new FullLayerOp (false, (*l))); + } else { + delete *l; + } + + } else { + new_layers.push_back (*l); + } + + } + + m_layers.swap (new_layers); + + } +} + void Shapes::reset_bbox_dirty () { set_dirty (false); diff --git a/src/db/db/dbShapes.h b/src/db/db/dbShapes.h index b8114e360..bffb08315 100644 --- a/src/db/db/dbShapes.h +++ b/src/db/db/dbShapes.h @@ -628,6 +628,18 @@ public: */ void insert (const Shapes &d); + /** + * @brief Insert all shapes from another container using the given shape types only + * + * This method insert all shapes from the given shape container. + * + * HINT: This method can duplicate shape containers from one layout to another. + * The current implementation does not translate property Id's. + * It is mainly intended for 1-to-1 copies of layouts where the whole + * property repository is copied. + */ + void insert (const Shapes &d, unsigned int types); + /** * @brief Assignment operator with transformation * @@ -1219,6 +1231,11 @@ public: */ void clear (); + /** + * @brief Clears the collection (given shape types only) + */ + void clear (unsigned int types); + /** * @brief Report the type mask of the objects stored herein * @@ -1515,7 +1532,7 @@ private: db::Cell *mp_cell; // HINT: contains "dirty" in bit 0 and "editable" in bit 1 void invalidate_state (); - void do_insert (const Shapes &d); + void do_insert (const Shapes &d, unsigned int flags = db::ShapeIterator::All); void check_is_editable_for_undo_redo () const; // gets the layers array diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 8285bc5fa..9da66889d 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -1682,29 +1682,53 @@ Class decl_Layout ("db", "Layout", "@param a The first of the layers to swap.\n" "@param b The second of the layers to swap.\n" ) + - gsi::method ("move_layer", &db::Layout::move_layer, gsi::arg ("src"), gsi::arg ("dest"), + gsi::method ("move_layer", static_cast (&db::Layout::move_layer), gsi::arg ("src"), gsi::arg ("dest"), "@brief Moves a layer\n" "\n" - "This method was introduced in version 0.19.\n" - "\n" - "Move a layer from the source to the target. The target is not cleared before, so that this method \n" - "merges shapes from the source with the target layer. The source layer is empty after that operation.\n" + "Moves a layer from the source to the destination layer. The target is not cleared before, so that this method \n" + "merges shapes from the source with the destination layer. The source layer is empty after that operation.\n" "\n" "@param src The layer index of the source layer.\n" "@param dest The layer index of the destination layer.\n" + "\n" + "This method was introduced in version 0.19.\n" ) + - gsi::method ("copy_layer", &db::Layout::copy_layer, gsi::arg ("src"), gsi::arg ("dest"), + gsi::method ("move_layer", static_cast (&db::Layout::move_layer), gsi::arg ("src"), gsi::arg ("dest"), gsi::arg ("flags"), + "@brief Moves a layer (selected shape types only)\n" + "\n" + "Moves a layer from the source to the destination layer. The target is not cleared before, so that this method \n" + "merges shapes from the source with the destination layer. The copied shapes are removed from the source layer.\n" + "\n" + "@param src The layer index of the source layer.\n" + "@param dest The layer index of the destination layer.\n" + "@param flags A combination of the shape type flags from \\Shapes, S... constants\n" + "\n" + "This method variant has been introduced in version 0.28.9.\n" + ) + + gsi::method ("copy_layer", static_cast (&db::Layout::copy_layer), gsi::arg ("src"), gsi::arg ("dest"), "@brief Copies a layer\n" "\n" - "This method was introduced in version 0.19.\n" - "\n" - "Copy a layer from the source to the target. The target is not cleared before, so that this method \n" - "merges shapes from the source with the target layer.\n" + "Copies a layer from the source to the destination layer. The destination layer is not cleared before, so that this method \n" + "merges shapes from the source with the destination layer.\n" "\n" "@param src The layer index of the source layer.\n" "@param dest The layer index of the destination layer.\n" + "\n" + "This method was introduced in version 0.19.\n" ) + - gsi::method ("clear_layer", &db::Layout::clear_layer, gsi::arg ("layer_index"), + gsi::method ("copy_layer", static_cast (&db::Layout::copy_layer), gsi::arg ("src"), gsi::arg ("dest"), gsi::arg ("flags"), + "@brief Copies a layer (selected shape types only)\n" + "\n" + "Copies a layer from the source to the destination layer. The destination layer is not cleared before, so that this method \n" + "merges shapes from the source with the destination layer.\n" + "\n" + "@param src The layer index of the source layer.\n" + "@param dest The layer index of the destination layer.\n" + "@param flags A combination of the shape type flags from \\Shapes, S... constants\n" + "\n" + "This method variant has been introduced in version 0.28.9.\n" + ) + + gsi::method ("clear_layer", static_cast (&db::Layout::clear_layer), gsi::arg ("layer_index"), "@brief Clears a layer\n" "\n" "Clears the layer: removes all shapes.\n" @@ -1712,6 +1736,16 @@ Class decl_Layout ("db", "Layout", "This method was introduced in version 0.19.\n" "\n" "@param layer_index The index of the layer to delete.\n" + ) + + gsi::method ("clear_layer", static_cast (&db::Layout::clear_layer), gsi::arg ("layer_index"), gsi::arg ("flags"), + "@brief Clears a layer (given shape types only)\n" + "\n" + "Clears the layer: removes all shapes for the given shape types.\n" + "\n" + "This method was introduced in version 0.28.9.\n" + "\n" + "@param layer_index The index of the layer to delete.\n" + "@param flags The type selector for the shapes to delete (see \\Shapes class, S... constants).\n" ) + gsi::method ("delete_layer", &db::Layout::delete_layer, gsi::arg ("layer_index"), "@brief Deletes a layer\n" diff --git a/src/db/db/gsiDeclDbShapes.cc b/src/db/db/gsiDeclDbShapes.cc index e711fe0c6..33f1a90c5 100644 --- a/src/db/db/gsiDeclDbShapes.cc +++ b/src/db/db/gsiDeclDbShapes.cc @@ -108,47 +108,47 @@ static gsi::layout_locking_iterator1 begin (const db return gsi::layout_locking_iterator1 (s->layout (), s->begin (flags)); } -static gsi::layout_locking_iterator1begin_all (const db::Shapes *s) +static gsi::layout_locking_iterator1 begin_all (const db::Shapes *s) { return gsi::layout_locking_iterator1 (s->layout (), s->begin (db::ShapeIterator::All)); } -static gsi::layout_locking_iterator1begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion) +static gsi::layout_locking_iterator1 begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (region, flags)); } -static gsi::layout_locking_iterator1begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) +static gsi::layout_locking_iterator1 begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags)); } -static gsi::layout_locking_iterator1begin_overlapping_all (const db::Shapes *s, const db::Box ®ion) +static gsi::layout_locking_iterator1 begin_overlapping_all (const db::Shapes *s, const db::Box ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (region, db::ShapeIterator::All)); } -static gsi::layout_locking_iterator1begin_doverlapping_all (const db::Shapes *s, const db::DBox ®ion) +static gsi::layout_locking_iterator1 begin_doverlapping_all (const db::Shapes *s, const db::DBox ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All)); } -static gsi::layout_locking_iterator1begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion) +static gsi::layout_locking_iterator1 begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (region, flags)); } -static gsi::layout_locking_iterator1begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) +static gsi::layout_locking_iterator1 begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags)); } -static gsi::layout_locking_iterator1begin_touching_all (const db::Shapes *s, const db::Box ®ion) +static gsi::layout_locking_iterator1 begin_touching_all (const db::Shapes *s, const db::Box ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (region, db::ShapeIterator::All)); } -static gsi::layout_locking_iterator1begin_dtouching_all (const db::Shapes *s, const db::DBox ®ion) +static gsi::layout_locking_iterator1 begin_dtouching_all (const db::Shapes *s, const db::DBox ®ion) { return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All)); } @@ -251,12 +251,7 @@ static void insert_shapes (db::Shapes *sh, const db::Shapes &s) static void insert_shapes_with_flags (db::Shapes *sh, const db::Shapes &s, unsigned int flags) { - // NOTE: if the source (r) is from the same layout than the shapes live in, we better - // lock the layout against updates while inserting - db::LayoutLocker locker (sh->layout ()); - for (db::Shapes::shape_iterator i = s.begin (flags); !i.at_end(); ++i) { - sh->insert (*i); - } + sh->insert (s, flags); } static void insert_shapes_with_trans (db::Shapes *sh, const db::Shapes &s, const db::ICplxTrans &trans) @@ -1264,9 +1259,15 @@ Class decl_Shapes ("db", "Shapes", "@brief Returns a value indicating whether the shapes container is empty\n" "This method has been introduced in version 0.20.\n" ) + - gsi::method ("clear", &db::Shapes::clear, + gsi::method ("clear", static_cast (&db::Shapes::clear), "@brief Clears the shape container\n" - "This method has been introduced in version 0.16. It can only be used in editable mode." + "This method has been introduced in version 0.16." + ) + + gsi::method ("clear", static_cast (&db::Shapes::clear), gsi::arg ("flags"), + "@brief Clears certain shape types from the shape container\n" + "Only shapes matching the shape types from 'flags' are removed. 'flags' is a combination of the S... constants.\n" + "\n" + "This method has been introduced in version 0.28.9." ) + gsi::method_ext ("size", &shapes_size, "@brief Gets the number of shapes in this container\n" @@ -1296,10 +1297,19 @@ Class decl_Shapes ("db", "Shapes", "returned for future references." ) + gsi::method ("SAll|#s_all", &s_all, - "@brief Indicates that all shapes shall be retrieved" + "@brief Indicates that all shapes shall be retrieved\n" + "You can use this constant to construct 'except' classes - e.g. " + "to specify 'all shape types except boxes' use\n" + "\n" + "@code SAll - SBoxes @/code\n" ) + gsi::method ("SAllWithProperties|#s_all_with_properties", &s_all_with_properties, - "@brief Indicates that all shapes with properties shall be retrieved" + "@brief Indicates that all shapes with properties shall be retrieved\n" + "Using this selector means to retrieve only shapes with properties." + "You can use this constant to construct 'except' classes - e.g. " + "to specify 'all shape types with properties except boxes' use\n" + "\n" + "@code SAllWithProperties - SBoxes @/code\n" ) + gsi::method ("SPolygons|#s_polygons", &s_polygons, "@brief Indicates that polygons shall be retrieved" @@ -1333,7 +1343,10 @@ Class decl_Shapes ("db", "Shapes", "@brief Indicates that user objects shall be retrieved" ) + gsi::method ("SProperties|#s_properties", &s_properties, - "@brief Indicates that only shapes with properties shall be retrieved" + "@brief Indicates that only shapes with properties shall be retrieved\n" + "You can or-combine this flag with the plain shape types to select a " + "certain shape type, but only those shapes with properties. For example to " + "select boxes with properties, use 'SProperties | SBoxes'." ) + gsi::method_ext ("dump_mem_statistics", &dump_mem_statistics, gsi::arg ("detailed", false), "@hide" diff --git a/src/db/unit_tests/dbShapesTests.cc b/src/db/unit_tests/dbShapesTests.cc index b2fce8945..1648f0885 100644 --- a/src/db/unit_tests/dbShapesTests.cc +++ b/src/db/unit_tests/dbShapesTests.cc @@ -1925,6 +1925,51 @@ TEST(7) } } +// copy, move, clear with shape types +TEST(8) +{ + db::Manager m (true); + + db::Layout layout (&m); + unsigned int lindex1 = layout.insert_layer (); + unsigned int lindex2 = layout.insert_layer (); + + db::Cell &topcell = layout.cell (layout.add_cell ("TOP")); + + topcell.shapes (lindex1).insert (db::Box (1, 2, 3, 4)); + topcell.shapes (lindex1).insert (db::Polygon (db::Box (1, 2, 3, 4))); + + { + db::Transaction trans (&m, "T1"); + topcell.shapes (lindex2).insert (topcell.shapes (lindex1)); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "polygon (1,2;1,4;3,4;3,2) #0\nbox (1,2;3,4) #0\n"); + } + + m.undo (); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), ""); + + { + db::Transaction trans (&m, "T1"); + topcell.shapes (lindex2).insert (topcell.shapes (lindex1), db::ShapeIterator::Boxes); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "box (1,2;3,4) #0\n"); + } + + m.undo (); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), ""); + + topcell.shapes (lindex2).insert (topcell.shapes (lindex1)); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "polygon (1,2;1,4;3,4;3,2) #0\nbox (1,2;3,4) #0\n"); + + { + db::Transaction trans (&m, "T1"); + topcell.shapes (lindex2).clear (db::ShapeIterator::Polygons); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "box (1,2;3,4) #0\n"); + } + + m.undo (); + EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), shapes_to_string (_this, topcell.shapes (lindex1))); +} + TEST(10A) { if (db::default_editable_mode ()) { diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc index eda190c67..c79df181f 100644 --- a/src/lay/lay/layGSIHelpProvider.cc +++ b/src/lay/lay/layGSIHelpProvider.cc @@ -118,6 +118,10 @@ std::string escape_xml_with_formatting (const std::string &s, bool &in_code) r += ""; } else if (sc.test ("@/u")) { r += ""; + } else if (sc.test ("@tt")) { + r += ""; + } else if (sc.test ("@/tt")) { + r += ""; } else if (sc.test ("@i")) { r += ""; } else if (sc.test ("@/i")) { diff --git a/testdata/ruby/dbLayoutTests1.rb b/testdata/ruby/dbLayoutTests1.rb index dca1b4b8b..c6734efb3 100644 --- a/testdata/ruby/dbLayoutTests1.rb +++ b/testdata/ruby/dbLayoutTests1.rb @@ -1971,6 +1971,66 @@ class DBLayoutTests1_TestClass < TestBase end + def test_23 + + # layer operations with shape types + + m = RBA::Manager::new + + l = RBA::Layout.new(m) + l1 = l.insert_layer(RBA::LayerInfo.new(1, 0)) + l2 = l.insert_layer(RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c1 = l.cell(l.add_cell("c1")) + + c0.shapes(l1).insert(RBA::Box::new(1, 2, 3, 4)) + c1.shapes(l1).insert(RBA::Polygon::new(RBA::Box::new(1, 2, 3, 4))) + + str1 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l1).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str1, "c0:box (1,2;3,4)\nc1:polygon (1,2;1,4;3,4;3,2)") + + m.transaction("T") + l.clear_layer(l1, RBA::Shapes::SPolygons) + m.commit + + str1 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l1).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str1, "c0:box (1,2;3,4)\nc1:") + + m.undo + + str1 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l1).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str1, "c0:box (1,2;3,4)\nc1:polygon (1,2;1,4;3,4;3,2)") + + m.transaction("T") + l.move_layer(l1, l2, RBA::Shapes::SPolygons) + m.commit + + str1 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l1).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str1, "c0:box (1,2;3,4)\nc1:") + + str2 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l2).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str2, "c0:\nc1:polygon (1,2;1,4;3,4;3,2)") + + m.undo + + str1 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l1).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str1, "c0:box (1,2;3,4)\nc1:polygon (1,2;1,4;3,4;3,2)") + + str2 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l2).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str2, "c0:\nc1:") + + m.transaction("T") + l.copy_layer(l1, l2, RBA::Shapes::SPolygons) + m.commit + + str1 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l1).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str1, "c0:box (1,2;3,4)\nc1:polygon (1,2;1,4;3,4;3,2)") + + str2 = l.each_cell.collect { |c| c.name + ":" + c.shapes(l2).each.collect { |sh| sh.to_s }.join(";") }.join("\n") + assert_equal(str2, "c0:\nc1:polygon (1,2;1,4;3,4;3,2)") + + end + # Iterating while flatten def test_issue200 diff --git a/testdata/ruby/dbShapesTest.rb b/testdata/ruby/dbShapesTest.rb index 76bb1df85..a55ffa4f8 100644 --- a/testdata/ruby/dbShapesTest.rb +++ b/testdata/ruby/dbShapesTest.rb @@ -1595,6 +1595,34 @@ class DBShapes_TestClass < TestBase end + # Shapes with shape-type specific insert and clear + def test_11 + + s = RBA::Shapes::new + s.insert(RBA::Box::new(1, 2, 3, 4)) + s.insert(RBA::Polygon::new(RBA::Box::new(1, 2, 3, 4))) + + assert_equal(s.each.collect { |sh| sh.to_s }.join("; "), "polygon (1,2;1,4;3,4;3,2); box (1,2;3,4)") + + s2 = RBA::Shapes::new + s2.insert(s) + + assert_equal(s2.each.collect { |sh| sh.to_s }.join("; "), "polygon (1,2;1,4;3,4;3,2); box (1,2;3,4)") + + s2.clear(RBA::Shapes::SPolygons) + + assert_equal(s2.each.collect { |sh| sh.to_s }.join("; "), "box (1,2;3,4)") + + s2.clear + + assert_equal(s2.each.collect { |sh| sh.to_s }.join("; "), "") + + s2.insert(s, RBA::Shapes::SPolygons) + + assert_equal(s2.each.collect { |sh| sh.to_s }.join("; "), "polygon (1,2;1,4;3,4;3,2)") + + end + end load("test_epilogue.rb")