From b2afb55fe3800d59231fa17f1a6de1785b7f3d68 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 11 Jul 2026 21:56:02 +0200 Subject: [PATCH] Convenience constructor for Layout from a cell (hierarchical copy) --- src/db/db/gsiDeclDbLayout.cc | 51 ++++++++++++++++++++++++++------- testdata/ruby/dbLayoutTests1.rb | 34 ++++++++++++++++++++++ 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 46329ec13..088254f79 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -892,14 +892,38 @@ static db::Layout *layout_default_ctor() return new db::Layout (true); } -static db::Layout *editable_layout_ctor_with_manager(bool editable, db::Manager &manager) +static db::Layout *editable_layout_ctor_with_manager(bool editable, db::Manager *manager) { - return new db::Layout (editable, &manager); + return new db::Layout (editable, manager); } -static db::Layout *editable_layout_default_ctor(bool editable) +static db::Layout *layout_ctor_from_cell(const db::Cell &source_cell, tl::Variant editable, db::Manager *manager) { - return new db::Layout (editable); + const db::Layout *source_layout = source_cell.layout (); + if (! source_layout) { + throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); + } + + bool editable_flag = source_layout->is_editable (); + if (! editable.is_nil ()) { + editable_flag = editable.to_bool (); + } + + std::unique_ptr target_layout (new db::Layout (editable_flag, manager)); + db::cell_index_type target_cell_index = target_layout->add_cell (source_layout->cell_name (source_cell.cell_index ())); + target_layout->dbu (source_layout->dbu ()); + + db::CellMapping cm; + cm.create_single_mapping_full (*target_layout, target_cell_index, *source_layout, source_cell.cell_index ()); + + db::LayerMapping lm; + lm.create_full (*target_layout, *source_cell.layout ()); + + std::vector source_cells; + source_cells.push_back (source_cell.cell_index ()); + db::copy_shapes (*target_layout, *source_layout, db::ICplxTrans (), source_cells, cm.table (), lm.table ()); + + return target_layout.release (); } static db::cell_index_type add_lib_pcell_variant (db::Layout *layout, db::Library *lib, db::pcell_id_type pcell_id, const std::vector ¶meters) @@ -1286,7 +1310,7 @@ Class decl_Layout ("db", "Layout", "always editable. Before that version, they inherited the editable flag from " "the application." ) + - gsi::constructor ("new", &editable_layout_ctor_with_manager, gsi::arg ("editable"), gsi::arg ("manager"), + gsi::constructor ("new", &editable_layout_ctor_with_manager, gsi::arg ("editable"), gsi::arg ("manager", (db::Manager *) 0, "nil"), "@brief Creates a layout object attached to a manager\n" "\n" "This constructor specifies a manager object which is used to " @@ -1294,16 +1318,21 @@ Class decl_Layout ("db", "Layout", "the layout is editable. In editable mode, some optimizations are disabled " "and the layout can be manipulated through a variety of methods.\n" "\n" + "The manager object can be nil - in that case, undo/redo is not supported.\n" + "\n" "This method was introduced in version 0.22.\n" ) + - gsi::constructor ("new", &editable_layout_default_ctor, gsi::arg ("editable"), - "@brief Creates a layout object\n" + gsi::constructor ("new", &layout_ctor_from_cell, gsi::arg ("source_cell"), gsi::arg ("editable", tl::Variant (), "nil"), gsi::arg ("manager", (db::Manager *) 0, "nil"), + "@brief Creates a layout object as a copy of another cell\n" "\n" - "This constructor specifies whether " - "the layout is editable. In editable mode, some optimizations are disabled " - "and the layout can be manipulated through a variety of methods.\n" + "This convenience constructor creates a new layout object as a hierarchical copy of the source cell including all " + "child cells and shapes.\n" "\n" - "This method was introduced in version 0.22.\n" + "If 'editable' is a boolean value, the new layout object will be made editable depending on that value. " + "If 'nil' is used for 'editable', the editable attribute is copied from the layout the source cell lives in.\n" + "'manager' can be a \\Manager object to which the new layout will be attached.\n" + "\n" + "This method was introduced in version 0.30.10.\n" ) + gsi::method ("library", &db::Layout::library, "@brief Gets the library this layout lives in or nil if the layout is not part of a library\n" diff --git a/testdata/ruby/dbLayoutTests1.rb b/testdata/ruby/dbLayoutTests1.rb index 97c903762..fd52659de 100644 --- a/testdata/ruby/dbLayoutTests1.rb +++ b/testdata/ruby/dbLayoutTests1.rb @@ -2518,6 +2518,40 @@ class DBLayoutTests1_TestClass < TestBase end + # Create layout from a cell + def test_newLayoutFromCell + + [ true, false ].each do |editable| + + ly = RBA::Layout::new(editable) + top = ly.create_cell("TOP") + a = ly.create_cell("A") + b = ly.create_cell("B") + l1 = ly.layer(1, 0) + a.shapes(l1).insert(RBA::Box::new(0, 0, 1000, 2000)) + b.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200)) + top.insert(RBA::CellInstArray::new(a, RBA::Trans::new)) + a.insert(RBA::CellInstArray::new(b, RBA::Trans::new(1, 2))) + + ly2 = RBA::Layout::new(a) + assert_equal(ly2.is_editable?, ly.is_editable?) + assert_equal(ly2.top_cell.name, "A") + assert_equal(collect(ly2.top_cell.begin_shapes_rec(ly2.layer(1, 0)), ly2), "[A](0,0;1000,2000)/[B](1,2;101,202)") + + ly2 = RBA::Layout::new(a, false) + assert_equal(ly2.is_editable?, false) + assert_equal(ly2.top_cell.name, "A") + assert_equal(collect(ly2.top_cell.begin_shapes_rec(ly2.layer(1, 0)), ly2), "[A](0,0;1000,2000)/[B](1,2;101,202)") + + ly2 = RBA::Layout::new(a, true) + assert_equal(ly2.is_editable?, true) + assert_equal(ly2.top_cell.name, "A") + assert_equal(collect(ly2.top_cell.begin_shapes_rec(ly2.layer(1, 0)), ly2), "[A](0,0;1000,2000)/[B](1,2;101,202)") + + end + + end + end load("test_epilogue.rb")