From a54ea1f273bd16a464df91cf04d954e5828fdc21 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 15 Feb 2023 00:28:41 +0100 Subject: [PATCH 1/9] DEF reader bug fixes, turned some errors into warnings temporarily. --- .../lefdef/db_plugin/dbDEFImporter.cc | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 5ba6c5e0b..117d88b20 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -782,7 +782,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool } } - while (test ("+")) { + while ((in_subnet && ! at_end ()) || test ("+")) { bool was_shield = false; unsigned int mask = 0; @@ -820,6 +820,8 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool } else { + bool any = false; + bool prefixed = false; bool can_have_rect_polygon_or_via = true; @@ -831,8 +833,6 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool can_have_rect_polygon_or_via = test ("+"); } - bool any = false; - if (can_have_rect_polygon_or_via) { if (test ("SHAPE")) { take (); @@ -882,22 +882,29 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool } else if (can_have_rect_polygon_or_via && test ("VIA")) { + // For the via, the masks are encoded in a three-digit number ( ) + unsigned int mask_top = (mask / 100) % 10; + unsigned int mask_cut = (mask / 10) % 10; + unsigned int mask_bottom = mask % 10; + std::string vn = get (); db::FTrans ft = get_orient (true /*optional*/); - test ("("); - db::Vector pt = get_vector (scale); - test (")"); + while (test ("(")) { - std::map::const_iterator vd = m_via_desc.find (vn); - if (vd != m_via_desc.end ()) { - // TODO: no mask specification here? - db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, 0, 0, 0, &m_lef_importer); - if (cell) { - design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt))); + db::Vector pt = get_vector (scale); + test (")"); + + std::map::const_iterator vd = m_via_desc.find (vn); + if (vd != m_via_desc.end ()) { + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + if (cell) { + design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt))); + } + } else { + warn (tl::to_string (tr ("Invalid via name: ")) + vn); } - } else { - error (tl::to_string (tr ("Invalid via name: ")) + vn); + } any = true; @@ -1204,7 +1211,7 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) double x = 0.0, y = 0.0; - while (! at_end () && ! test ("+") && ! test (";")) { + while (! at_end () && ! peek ("+") && ! peek (";")) { test ("("); if (! test ("*")) { @@ -1238,7 +1245,17 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) } else if (test ("VIA")) { // TODO: implement - error (tl::to_string (tr ("VIA not supported on pins currently"))); + warn (tl::to_string (tr ("VIA not supported on pins currently"))); + + get (); + + if (test ("MASK")) { + get_mask (get_long ()); + } + + test ("("); + db::Vector d = get_vector (scale); + test (")"); } else { while (! peek ("+") && ! peek ("-") && ! peek (";")) { @@ -1432,7 +1449,7 @@ DEFImporter::read_styles (double scale) } - m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end ()); + m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end (), false /*don't compress*/); } } From 93d9298b5101cb88fcdf15c84f0a3dd49ecb0d45 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 15 Feb 2023 00:29:26 +0100 Subject: [PATCH 2/9] Formally minkowsky sum now is allowed with empty polygon arguments --- src/db/db/dbPolygonTools.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 2032eeb36..0202ee908 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -2143,6 +2143,10 @@ ms_extraction (db::EdgeProcessor &ep, bool resolve_holes) static db::Polygon do_minkowski_sum (const db::Polygon &a, const db::Edge &b, bool resolve_holes) { + if (a.begin_hull () == a.end_hull ()) { + return db::Polygon (); + } + db::EdgeProcessor ep; db::ms_production (a, b.p1 (), b.p2 (), ep); return db::ms_extraction (ep, resolve_holes); @@ -2161,7 +2165,9 @@ minkowski_sum (const db::Polygon &a, const db::Edge &b, bool rh) static db::Polygon do_minkowski_sum (const db::Polygon &a, const db::Polygon &b, bool resolve_holes) { - tl_assert (a.begin_hull () != a.end_hull ()); + if (a.begin_hull () == a.end_hull () || b.begin_hull () == b.end_hull ()) { + return db::Polygon (); + } db::Vector p0 = *a.begin_hull () - db::Point (); From f73b2290241a840467c3eba05aa2435b3dfc8c4c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 15 Feb 2023 00:29:43 +0100 Subject: [PATCH 3/9] WIP --- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 00797bdda..c97677899 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -277,81 +277,81 @@ static void run_test2 (tl::TestBase *_this, const char *lef_dir, const char *fil } } -TEST(1) +TEST(lef1) { run_test (_this, "lef1", "lef:in.lef", 0, default_options ()); } -TEST(2) +TEST(lef2) { // Also tests ability of plugin to properly read LEF run_test (_this, "lef2", "read:in.lef", "au.oas.gz", default_options ()); } -TEST(3) +TEST(lef3) { db::LEFDEFReaderOptions options = default_options (); options.set_cell_outline_layer ("OUTLINE (2/0)"); run_test (_this, "lef3", "lef:in.lef", "au.oas.gz", options); } -TEST(4) +TEST(lef4) { run_test (_this, "lef4", "lef:in.lef", 0, default_options ()); } -TEST(5) +TEST(lef5) { run_test (_this, "lef5", "lef:in.lef", 0, default_options ()); } -TEST(6) +TEST(lef6) { run_test (_this, "lef6", "lef:in.lef", 0, default_options ()); } -TEST(7) +TEST(lef7) { db::LEFDEFReaderOptions options = default_options (); options.set_cell_outline_layer ("OUTLINE (8/0)"); run_test (_this, "lef7", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", options); } -TEST(10) +TEST(def1) { run_test (_this, "def1", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ()); } -TEST(11) +TEST(def2) { db::LEFDEFReaderOptions options = default_options (); options.set_cell_outline_layer ("OUTLINE (10/0)"); run_test (_this, "def2", "lef:0.lef+lef:1.lef+def:in.def.gz", "au.oas.gz", options); } -TEST(12) +TEST(def3) { db::LEFDEFReaderOptions options = default_options (); options.set_cell_outline_layer ("OUTLINE (13/0)"); run_test (_this, "def3", "lef:in.lef+def:in.def", "au.oas.gz", options); } -TEST(13) +TEST(def4) { run_test (_this, "def4", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ()); } -TEST(14) +TEST(def5) { run_test (_this, "def5", "lef:in.lef+def:in.def", "au.oas.gz", default_options ()); } -TEST(15) +TEST(def6) { run_test (_this, "def6", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au-new.oas.gz", default_options ()); } -TEST(16) +TEST(def7) { db::LEFDEFReaderOptions options = default_options (); options.set_placement_blockage_layer ("PLACEMENT_BLK (11/0)"); @@ -361,12 +361,12 @@ TEST(16) run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au2_with_map_file-new.oas.gz", options); } -TEST(17) +TEST(def8) { run_test (_this, "def8", "lef:tech.lef+def:in.def", "au.oas.gz", default_options ()); } -TEST(18) +TEST(def9) { db::LEFDEFReaderOptions options = default_options (); options.set_separate_groups (true); @@ -375,47 +375,54 @@ TEST(18) run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au_nogroups-new.oas.gz", default_options ()); } -TEST(19) +TEST(def10) { db::LEFDEFReaderOptions opt = default_options (); opt.set_cell_outline_layer ("OUTLINE (2/0)"); run_test (_this, "def10", "def:in.def", "au.oas.gz", opt); } -TEST(20) +TEST(def11) { db::LEFDEFReaderOptions opt = default_options (); opt.set_cell_outline_layer ("OUTLINE (12/0)"); run_test (_this, "def11", "lef:test.lef+def:test.def", "au.oas.gz", opt); } -TEST(21) +TEST(def12) { db::LEFDEFReaderOptions opt = default_options (); opt.set_cell_outline_layer ("OUTLINE (20/0)"); run_test (_this, "def12", "lef:test.lef+def:test.def", "au-new.oas.gz", opt); } -TEST(22) +TEST(def13) { db::LEFDEFReaderOptions opt = default_options (); run_test (_this, "def13", "map:test.map+lef:test.lef_5.8+def:top.def.gz", "au2.oas.gz", opt); } -TEST(23) +TEST(def14) { db::LEFDEFReaderOptions opt = default_options (); opt.set_macro_resolution_mode (1); run_test (_this, "def14", "map:test.map+lef:tech.lef+lef:stdlib.lef+def:test.def", "au.oas.gz", opt); } -TEST(24) +TEST(def15) { db::LEFDEFReaderOptions opt = default_options (); opt.set_macro_resolution_mode (1); run_test (_this, "def15", "map:test.map+lef:tech.lef+def:test.def", "au2.oas.gz", opt); } +TEST(def16) +{ + db::LEFDEFReaderOptions opt = default_options (); + opt.set_macro_resolution_mode (1); + run_test (_this, "def16", "lef:a.lef+def:a.def", "au.oas.gz", opt); +} + TEST(100) { run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false); From 66a683259416f54e2245e8089f890c1b10057c0a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 15 Feb 2023 22:11:12 +0100 Subject: [PATCH 4/9] Some enhancements to DEF reader based on the 'complete' example. VIAs in FILL und PIN, a variety of syntax fixes. --- .../lefdef/db_plugin/dbDEFImporter.cc | 82 +++++++++++++++--- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 2 +- testdata/lefdef/specialnets_geo/au.oas.gz | Bin 682 -> 478 bytes .../lefdef/specialnets_geo/au_no_spnet.oas.gz | Bin 529 -> 350 bytes .../specialnets_geo/au_spnet_mapped.oas.gz | Bin 765 -> 510 bytes testdata/lefdef/viasize/au.oas.gz | Bin 863 -> 519 bytes testdata/lefdef/viasize2/au.oas.gz | Bin 424 -> 542 bytes 7 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 117d88b20..989081b88 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -1127,9 +1127,9 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) if (vd.m1.empty () && vd.m2.empty ()) { // analyze the layers to find the metals - if (routing_layers.size () == 2) { - vd.m1 = routing_layers[0]; - vd.m2 = routing_layers[1]; + if (routing_layers.size () == 2 || routing_layers.size () == 1) { + vd.m1 = routing_layers.front (); + vd.m2 = routing_layers.back (); } else { warn (tl::to_string (tr ("Cannot determine routing layers for via: ")) + n); } @@ -1244,18 +1244,36 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) } else if (test ("VIA")) { - // TODO: implement - warn (tl::to_string (tr ("VIA not supported on pins currently"))); + // TODO: clarify - VIA on pins is regarded VIA purpose, not PIN and gives a separate cell - get (); + std::string vn = get (); + unsigned int mask = 0; if (test ("MASK")) { - get_mask (get_long ()); + mask = get_mask (get_long ()); } - test ("("); - db::Vector d = get_vector (scale); - test (")"); + while (test ("(")) { + + db::Vector pt = get_vector (scale); + test (")"); + + unsigned int mask_top = (mask / 100) % 10; + unsigned int mask_cut = (mask / 10) % 10; + unsigned int mask_bottom = mask % 10; + + std::map::const_iterator vd = m_via_desc.find (vn); + if (vd != m_via_desc.end ()) { + std::string nondefaultrule; + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + if (cell) { + design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt))); + } + } else { + warn (tl::to_string (tr ("Invalid via name: ")) + vn); + } + + } } else { while (! peek ("+") && ! peek ("-") && ! peek (";")) { @@ -1408,13 +1426,49 @@ DEFImporter::read_fills (db::Layout &layout, db::Cell &design, double scale) } else if (test ("VIA")) { - // TODO: implement - warn (tl::to_string (tr ("VIA not supported on fills currently"))); + // TODO: clarify - VIA on fill is regarded VIA purpose, not PIN and gives a separate cell - while (! at_end () && ! test (";")) { - take (); + std::string vn = get (); + + unsigned int mask = 0; + while (test ("+")) { + if (test ("MASK")) { + mask = get_mask (get_long ()); + } else if (test ("OPC")) { + // ignore + } else { + error (tl::to_string (tr ("Expected 'MASK' or 'OPC' inside fill/VIA definition"))); + } } + if (peek ("+") && test ("MASK")) { + mask = get_mask (get_long ()); + } + + unsigned int mask_top = (mask / 100) % 10; + unsigned int mask_cut = (mask / 10) % 10; + unsigned int mask_bottom = mask % 10; + + while (test ("(")) { + + db::Vector pt = get_vector (scale); + test (")"); + + std::map::const_iterator vd = m_via_desc.find (vn); + if (vd != m_via_desc.end ()) { + std::string nondefaultrule; + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + if (cell) { + design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt))); + } + } else { + warn (tl::to_string (tr ("Invalid via name: ")) + vn); + } + + } + + test (";"); + } else { error (tl::to_string (tr ("'LAYER' or 'VIA' keyword expected"))); } diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index c97677899..328feedcc 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -420,7 +420,7 @@ TEST(def16) { db::LEFDEFReaderOptions opt = default_options (); opt.set_macro_resolution_mode (1); - run_test (_this, "def16", "lef:a.lef+def:a.def", "au.oas.gz", opt); + run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au.oas.gz", opt); } TEST(100) diff --git a/testdata/lefdef/specialnets_geo/au.oas.gz b/testdata/lefdef/specialnets_geo/au.oas.gz index dced1c01d169597f188d940a11aa1f5310af4dcf..72437372a7be92691aa6a0fe39523b295dcde6f4 100644 GIT binary patch literal 478 zcmV<40U`b$iwFovN$q0*19WY0UomB7Wid86VJ>fBa{yBfcJ=kt^>+;R4CduxWH!_@ zV0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F;;|1o9>4KX(8~>b$4qRRSKbqrK z6n{_8gJqfS+Zf>O#gP;E6wD0`9A3uI6PEAWpd*Jx2!1$+>p)oV-LX!#kC(dv@ zYtGD@X5jDcoTj#bV-70=FO#S>GXo=2N{X?us3jvKlTCo8yr?A;Ba?=Ps3*|KU|3+hgyTe4ZpxDshMVfzs}68%`NwiWgE?h!3ZoK(lTq?Bk8>w45e=gz4L7gzV3QChL+W7|izk8BD%-}W#tG5%&^WMEWgEM{zB UWMpU+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>a3p7B7Q~n27qIgM$Gf`(#|H%Y2e<}> zL~^pGl;-AEGQ$-x^M!dj#sjfoJXnUC-9I$M$J5W1nT45w2bsgo%m2W_A%qpgNG01q=HrrbA38m>T%cF&$$%!?cC*3KLwogZ}^%NVtbzvf7c3 diff --git a/testdata/lefdef/specialnets_geo/au_no_spnet.oas.gz b/testdata/lefdef/specialnets_geo/au_no_spnet.oas.gz index 021f51106a270a0e6eaf02b9087957147f539168..dfb6a9b0b28952912fd91ea8f4295eb9d3b36701 100644 GIT binary patch literal 350 zcmV-k0ipgMiwFovN$q0*19WY0Uo+;R4CduxWH!_@ zV0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F;;|1o9>4KX(8~>b$4qRRSKbqrK z6n{_8gJqfq3(W`A5$1JZsL(n`Yqe z?wqE!fMX6T122=PH6sHflTCo8yr?BJBU4I>v9YKn6C;y`hNvhnBVJhs!Ea0xm?tm` zeqcPo$RKiu_{16UXD=oAkF+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>a3p7B7Q~n27ce7Od|{rB@jz@CpHiBe zTglDt9~$E0>F3JK!py*f%;9G8HDqQ43PNch--wwR%m>rlEFe>unSdg27B8cyH6sHf zlTCo8yr?BJBU4I>v9YKn6C;y`hNvhngWxyD3Ct6i1q)6vGKd^zVOYb&)G(3(0|NjH CakUo! diff --git a/testdata/lefdef/specialnets_geo/au_spnet_mapped.oas.gz b/testdata/lefdef/specialnets_geo/au_spnet_mapped.oas.gz index 70d7ce49400a914d3c7979334c442de450e5c290..244696cf00d99bf7087d90cd8a466f89c2eab4b9 100644 GIT binary patch literal 510 zcmVQlGcIpoa{yBfcJ=kt^>+;R4CduxWH!_@ zV0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F;;|1o9>4KX(8~>b$4qRRSKbqrK z6n{_8gJqfS+Zf>O#!#qZx$7$dBc|U&qQk_h_wXpS zM@n2X=&Vh9_9$IEk)>-+!j!=DCkao|MYbj++8-_HSlRra;j-njWFOlA&5pi}fXl_+4ly|The2$;_^ zW|Q1I^l6{wxfBa{yBfcJ=kt^>+;R4CduxWH!_@ zV0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F;;|1o9>4KX(8~>b$4qRRSKbqrK z6n{_8gJqfS+Zf>O#!zads$7$dBc|U&qQkyyS;6NYQm=mQY0D literal 863 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>a3p7B7Q~n27qIgM$Gf`(#|H%Y2e<}> zL~^pGl;-AEGQ$-x^M!dj#sjfod~t4KP7V@3C$T6!m7Co^G{nc#&y|^xnSlqH!_DJs zsORSzq8}UpB$?TP(ikE@HAYBkIKgVrM7TLXw(9{2W)7e{3XfY1CTA7w8RcrAXJ8Zo zB7iCxdGN?_OJL|T0c$h?>SW@e|ASubqh%Cs+$fThm zD$2_s_>E}-^8{wW4~!=m8AJ{gk$e}L&6(=nzVe$gJVD3XpfOmJlT#&%FZxt XVY~toW@G{x^M#o~mZ@PR0|o{F;1vXa diff --git a/testdata/lefdef/viasize2/au.oas.gz b/testdata/lefdef/viasize2/au.oas.gz index 5da4dd619c09b1b68a4422c59bb31f10d52a30e7..c1ab0c221a0f64ddf30e46b875986f89f7a0c222 100644 GIT binary patch literal 542 zcmV+(0^$81iwFoYN9|((19WY0UomB7Wid86VJ>fBa{yBfcJ=kt^>+;R4CduxWH!_@ zV0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F;;|1o9>4KX(8~>b$4qRRSKbqrK z6n{_8gJqfS+Zf>O#!y2ZH$7$dBc|U&qQkyyS;6NYQm=mQY*47|*u)*Q@?Oa=y$lDtenHX|dGhK8spFC&o6 z1Y{dXit+;e+{aih{O6brBL}O!!Q6xtfj!488Y7<=C?A$m3v?}WTgG`tT_W|0q@~19 zNmt&82(gX23DF13dY-d&uesswS63$Jc1+koLp$r>p}MY@0>SM68J89N9G_A3!?pUr zA`h!;1_!6kO~`t{u4#REOY282j~Np=Q_hH|u|)#y4s%L==5g+XPKW+U{Rx8U4`!S? zaz^;sO9}oXZ67^5T@^O^sioQNh$zfU^5gUPqOZJ}BgRC1qlT^NJ%f7+_ZU>ZPZVTe gVw}v($iS$~Sj^bM$jHzzvH$}E02kfczu5u+07+I9IRF3v literal 424 zcmV;Z0ayMXiwFoh6Jufk17US8Z((x)<&C>a13?sqXU?qIjl1g-aH5e-VIkTWH^D-* z3TB84$tGmhYcs?PDkLag3cHjR7I_4*vas|4L_vaxm57gEsUX(QDu(q!Ucfob;r##i z&zvF7itcDB%Uy1EW0Foe=t)K4W77dHirEFh-Mq(g!u5QXXB9E;=KL8=u}%9E&w76a zY}(C*Un+}fRwx+S%Esol*xTAxd$`EwxF}ajWmfSQqg|`}_4)y62Z%A}W`(?Iv0U9D zJ#DpHuhwcIU90Y_ujy)O)-SjoBbXo~EOeuoPI=59<7L^2D)BEzW-=is`jPqJ=vuHX zB^%Ks|EBc#mzw165_3{cW+7;jVWR`n`~GI*5`xhQ>ixgqc$*TVBQ*(~lFPwy5(yLJ zj4_OiP- Date: Thu, 16 Feb 2023 23:49:24 +0100 Subject: [PATCH 5/9] Some LEF reader fixes based on the complete sample --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 18 +- .../lefdef/db_plugin/dbLEFDEFImporter.h | 23 ++ .../lefdef/db_plugin/dbLEFImporter.cc | 250 +++++++++++++----- .../lefdef/db_plugin/dbLEFImporter.h | 1 + .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 7 + 5 files changed, 225 insertions(+), 74 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index bc9fac2c7..031b34726 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1990,7 +1990,11 @@ LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderS void LEFDEFImporter::error (const std::string &msg) { - throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn); + if (m_sections.empty ()) { + throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn); + } else { + throw LEFDEFReaderException (msg + tl::sprintf (tl::to_string (tr (" (inside %s)")), tl::join (m_sections, "/")), int (mp_stream->line_number ()), m_cellname, m_fn); + } } void @@ -2140,6 +2144,18 @@ LEFDEFImporter::get () return r; } +void +LEFDEFImporter::enter_section (const std::string &name) +{ + m_sections.push_back (name); +} + +void +LEFDEFImporter::leave_section () +{ + m_sections.pop_back (); +} + const std::string & LEFDEFImporter::next () { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index beb161fb3..84fdc7525 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -1706,8 +1706,31 @@ private: db::property_names_id_type m_pin_prop_name_id; db::LEFDEFReaderOptions m_options; int m_warn_level; + std::vector m_sections; + + friend class LEFDEFSection; const std::string &next (); + void enter_section (const std::string &name); + void leave_section (); +}; + +class DB_PLUGIN_PUBLIC LEFDEFSection +{ +public: + LEFDEFSection (LEFDEFImporter *importer, const std::string &name) + : mp_importer (importer) + { + mp_importer->enter_section (name); + } + + ~LEFDEFSection () + { + mp_importer->leave_section (); + } + +private: + LEFDEFImporter *mp_importer; }; class DB_PLUGIN_PUBLIC LEFDEFReader diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index 12f7cb6b4..4b136bb7e 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -388,9 +388,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye } else if (test ("PROPERTY")) { // skip properties - while (! at_end () && ! test (";")) { - take (); - } + skip_entry (); } else { // stop at unknown token @@ -406,7 +404,7 @@ LEFImporter::read_nondefaultrule (db::Layout &layout) // read NONDEFAULTRULE sections std::string n = get (); - while (! test ("END") || ! test (n)) { + while (! test ("END")) { if (test ("LAYER")) { @@ -419,9 +417,7 @@ LEFImporter::read_nondefaultrule (db::Layout &layout) test (";"); m_nondefault_widths[n][l] = std::make_pair (w, w); } else { - while (! at_end () && ! test (";")) { - take (); - } + skip_entry (); } } @@ -432,12 +428,25 @@ LEFImporter::read_nondefaultrule (db::Layout &layout) read_viadef (layout, n); } else { - while (! at_end () && ! test (";")) { - take (); + + std::string token = get (); + + if (token == "SPACING") { + // read over sections we do not need + while (! at_end () && ! test ("END")) { + skip_entry (); + } + test (token); + } else if (token != ";") { + // read over lines we do not need + skip_entry (); } + } } + + test (n); } void @@ -557,6 +566,13 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc get_double (); test (";"); + } else if (test ("FOREIGN")) { + + // undocumented + while (! at_end () && ! test (";")) { + take (); + } + } else if (test ("LAYER")) { layer_name = get (); @@ -631,9 +647,7 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc } else if (test ("PROPERTY")) { // skip properties - while (! at_end () && ! test (";")) { - take (); - } + skip_entry (); } else { // stop at unknown token @@ -663,7 +677,7 @@ LEFImporter::read_viadef (Layout &layout, const std::string &nondefaultrule) ViaDesc &via_desc = m_vias[n]; - while (test ("DEFAULT") || test ("TOPOFSTACKONLY")) + while (test ("DEFAULT") || test ("TOPOFSTACKONLY") || test("GENERATED")) ; test (";"); @@ -746,55 +760,51 @@ LEFImporter::read_layer (Layout & /*layout*/) // blocks following a semicolon take (); if (test ("FREQUENCY")) { - while (! test ("TABLEENTRIES")) { + while (! at_end () && ! test ("TABLEENTRIES")) { take (); } } - while (! at_end () && ! test (";")) { - take (); - } + skip_entry (); } else if (test ("PROPERTY")) { - std::string name = get (); - tl::Variant value = get (); + while (! test (";") && ! at_end ()) { - if (name == "LEF58_MINWIDTH") { + std::string name = get (); + tl::Variant value = get (); - // Cadence extension - tl::Extractor ex (value.to_string ()); - double v = 0.0; - if (ex.test ("MINWIDTH") && ex.try_read (v)) { - if (ex.test ("WRONGDIRECTION")) { - wmin_wrongdir = v; - } else { - wmin = v; + if (name == "LEF58_MINWIDTH") { + + // Cadence extension + tl::Extractor ex (value.to_string ()); + double v = 0.0; + if (ex.test ("MINWIDTH") && ex.try_read (v)) { + if (ex.test ("WRONGDIRECTION")) { + wmin_wrongdir = v; + } else { + wmin = v; + } } - } - } else if (name == "LEF58_WIDTH") { + } else if (name == "LEF58_WIDTH") { - // Cadence extension - tl::Extractor ex (value.to_string ()); - double v = 0.0; - if (ex.test ("WIDTH") && ex.try_read (v)) { - if (ex.test ("WRONGDIRECTION")) { - w_wrongdir = v; - } else { - w = v; + // Cadence extension + tl::Extractor ex (value.to_string ()); + double v = 0.0; + if (ex.test ("WIDTH") && ex.try_read (v)) { + if (ex.test ("WRONGDIRECTION")) { + w_wrongdir = v; + } else { + w = v; + } } + } } - expect (";"); - } else { - - while (! at_end () && ! test (";")) { - take (); - } - + skip_entry (); } } @@ -865,6 +875,8 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("PIN")) { + LEFDEFSection section (this, "PIN"); + std::string pn = get (); std::string dir; @@ -881,6 +893,8 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("PORT")) { + LEFDEFSection section (this, "PORT"); + // produce pin labels // TODO: put a label on every single object? std::string label = pn; @@ -916,9 +930,7 @@ LEFImporter::read_macro (Layout &layout) expect ("END"); } else { - while (! at_end () && ! test (";")) { - take (); - } + skip_entry (); } } @@ -926,12 +938,19 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("FOREIGN")) { + LEFDEFSection section (this, "FOREIGN"); + std::string cn = get (); db::Point vec; db::FTrans ft; if (! peek (";")) { - vec = get_point (1.0 / layout.dbu ()); + if (test ("(")) { + vec = get_point (1.0 / layout.dbu ()); + expect (")"); + } else { + vec = get_point (1.0 / layout.dbu ()); + } ft = get_orient (true); } @@ -940,7 +959,7 @@ LEFImporter::read_macro (Layout &layout) if (options ().macro_resolution_mode () != 1) { if (! foreign_name.empty ()) { - error (tl::to_string (tr ("Duplicate FOREIGN definition"))); + warn (tl::to_string (tr ("Duplicate FOREIGN definition"))); } // What is the definition of the FOREIGN transformation? @@ -956,6 +975,8 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("OBS")) { + LEFDEFSection section (this, "OBS"); + if (reader_state ()->tech_comp ()->produce_obstructions ()) { read_geometries (mg, layout.dbu (), Obstructions); } else { @@ -966,8 +987,10 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("DENSITY")) { + LEFDEFSection section (this, "DENSITY"); + // read over DENSITY statements - while (! test ("END")) { + while (! at_end () && ! test ("END")) { if (test ("LAYER")) { get (); expect (";"); @@ -980,17 +1003,27 @@ LEFImporter::read_macro (Layout &layout) } } - expect ("END"); - } else if (test ("FIXEDMASK")) { mg->set_fixedmask (true); expect (";"); } else { - while (! at_end () && ! test (";")) { - take (); + + std::string token = get (); + LEFDEFSection section (this, token); + + if (token == "TIMING") { + // read over sections we do not need + while (! at_end () && ! test ("END")) { + skip_entry (); + } + test (token); + } else if (token != ";") { + // read over lines we do not need + skip_entry (); } + } } @@ -1031,17 +1064,16 @@ LEFImporter::do_read (db::Layout &layout) } else if (test ("UNITS")) { - // read over SPACING sections - while (! test ("END")) { + LEFDEFSection section (this, "UNITS"); + + while (! at_end () && ! test ("END")) { if (test ("DATABASE")) { expect ("MICRONS"); // TODO: what to do with that value /* dbu_mic = */ get_double (); expect (";"); } else { - while (! at_end () && ! test (";")) { - take (); - } + skip_entry (); } } @@ -1049,44 +1081,105 @@ LEFImporter::do_read (db::Layout &layout) } else if (test ("SPACING")) { + LEFDEFSection section (this, "SPACING"); + // read over SPACING sections - while (! test ("END") || ! test ("SPACING")) { - take (); + while (! at_end () && ! test ("END")) { + skip_entry (); } + test ("SPACING"); + } else if (test ("PROPERTYDEFINITIONS")) { + LEFDEFSection section (this, "PROPERTYDEFINITIONS"); + // read over PROPERTYDEFINITIONS sections - while (! test ("END") || ! test ("PROPERTYDEFINITIONS")) { - take (); + while (! at_end () && ! test ("END")) { + skip_entry (); } + test ("PROPERTYDEFINITIONS"); + } else if (test ("NONDEFAULTRULE")) { + LEFDEFSection section (this, "NONDEFAULTRULE"); + read_nondefaultrule (layout); } else if (test ("SITE")) { - // read over SITE sections + LEFDEFSection section (this, "NONDEFAULTRULE"); + + // read over SITE or VIARULE sections std::string n = get (); - while (! test ("END") || ! test (n)) { - take (); + while (! at_end () && ! test ("END")) { + skip_entry (); } + test (n); + } else if (test ("VIARULE")) { - // read over VIARULE sections + LEFDEFSection section (this, "VIARULE"); + + // read over SITE or VIARULE sections std::string n = get (); - while (! test ("END") || ! test (n)) { - take (); + while (! at_end () && ! test ("END")) { + skip_entry (); } + test (n); + + } else if (test ("NOISETABLE")) { + + LEFDEFSection section (this, "NOISETABLE"); + + // read over NOISETABLE sections + while (! at_end () && ! test ("END")) { + skip_entry (); + } + + test ("NOISETABLE"); + + } else if (test ("IRDROP")) { + + LEFDEFSection section (this, "IRDROP"); + + // read over IRDROP sections + while (! at_end () && ! test ("END")) { + skip_entry (); + } + + test ("IRDROP"); + + } else if (test ("ARRAY")) { + + LEFDEFSection section (this, "ARRAY"); + + // read over ARRAY sections + std::string n = get (); + while (! at_end () && ! test ("END")) { + if (test ("FLOORPLAN")) { + while (! at_end () && ! test ("END")) { + skip_entry (); + } + } else { + skip_entry (); + } + } + + test (n); + } else if (test ("VIA")) { + LEFDEFSection section (this, "VIA"); read_viadef (layout, std::string ()); } else if (test ("BEGINEXT")) { + LEFDEFSection section (this, "BEGINEXT"); + // read over BEGINEXT sections while (! test ("ENDEXT")) { take (); @@ -1094,21 +1187,32 @@ LEFImporter::do_read (db::Layout &layout) } else if (test ("LAYER")) { + LEFDEFSection section (this, "LAYER"); read_layer (layout); } else if (test ("MACRO")) { + LEFDEFSection section (this, "MACRO"); read_macro (layout); } else { - while (! at_end () && ! test (";")) { - take (); - } + + // read over entries we do not need + skip_entry (); + } } } +void +LEFImporter::skip_entry () +{ + while (! at_end () && ! test (";")) { + take (); + } +} + void LEFImporter::finish_lef (db::Layout &layout) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 266b887aa..5c6402af4 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -152,6 +152,7 @@ private: void read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc &desc, const std::string &n, double dbu); void read_layer (Layout &layout); void read_macro (Layout &layout); + void skip_entry (); }; } diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 328feedcc..09b435dfb 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -317,6 +317,12 @@ TEST(lef7) run_test (_this, "lef7", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", options); } +TEST(lef8) +{ + // this is rather a smoke test and throws a number of warnings + run_test (_this, "lef8", "lef:tech.lef+lef:a.lef", "au.oas.gz", default_options ()); +} + TEST(def1) { run_test (_this, "def1", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ()); @@ -418,6 +424,7 @@ TEST(def15) TEST(def16) { + // this is rather a smoke test db::LEFDEFReaderOptions opt = default_options (); opt.set_macro_resolution_mode (1); run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au.oas.gz", opt); From 4eb48738e47b4dd7a6543a746f29eb1b33b79691 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Feb 2023 00:02:59 +0100 Subject: [PATCH 6/9] Confirming that issue #1282 is fixed --- src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc | 8 ++++---- .../streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index 4b136bb7e..92a8046ff 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -404,14 +404,14 @@ LEFImporter::read_nondefaultrule (db::Layout &layout) // read NONDEFAULTRULE sections std::string n = get (); - while (! test ("END")) { + while (! at_end () && ! test ("END")) { if (test ("LAYER")) { std::string l = get (); // read the width for the layer - while (! test ("END")) { + while (! at_end () && ! test ("END")) { if (test ("WIDTH")) { double w = get_double (); test (";"); @@ -452,7 +452,7 @@ LEFImporter::read_nondefaultrule (db::Layout &layout) void LEFImporter::read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &via_desc, const std::string & /*n*/, double dbu) { - while (! test ("END")) { + while (! at_end () && ! test ("END")) { double x, y; @@ -1181,7 +1181,7 @@ LEFImporter::do_read (db::Layout &layout) LEFDEFSection section (this, "BEGINEXT"); // read over BEGINEXT sections - while (! test ("ENDEXT")) { + while (! at_end () && ! test ("ENDEXT")) { take (); } diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 09b435dfb..0dcc0c646 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -320,6 +320,7 @@ TEST(lef7) TEST(lef8) { // this is rather a smoke test and throws a number of warnings + // (complete example) run_test (_this, "lef8", "lef:tech.lef+lef:a.lef", "au.oas.gz", default_options ()); } @@ -425,6 +426,7 @@ TEST(def15) TEST(def16) { // this is rather a smoke test + // (complete example) db::LEFDEFReaderOptions opt = default_options (); opt.set_macro_resolution_mode (1); run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au.oas.gz", opt); @@ -968,3 +970,9 @@ TEST(205_lef_resistance) run_test (_this, "issue-1214", "read:merged.nom.lef", "au.oas.gz", lefdef_opt, false); } +// issue 1282 +TEST(206_lef_spacing) +{ + run_test (_this, "issue-1282", "read:a.lef", 0, default_options (), false); +} + From 68db8fc867e21318bf903cd8a6612211f5dd9b1a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Feb 2023 21:42:59 +0100 Subject: [PATCH 7/9] Added missing files --- testdata/lefdef/issue-1282/a.lef | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 testdata/lefdef/issue-1282/a.lef diff --git a/testdata/lefdef/issue-1282/a.lef b/testdata/lefdef/issue-1282/a.lef new file mode 100644 index 000000000..bb736ef5f --- /dev/null +++ b/testdata/lefdef/issue-1282/a.lef @@ -0,0 +1,25 @@ +VERSION 5.4 ; + +NAMESCASESENSITIVE ON ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; +NOWIREEXTENSIONATPIN OFF ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +NONDEFAULTRULE DOUBLESPACE + LAYER M1 + WIDTH 0.16 ; + SPACING 0.36 ; + END M1 + +# klayout 0.28.5 lef reader get's confused by the SPACING in NONDEFAULTRULE + SPACING + SAMENET M1 M1 0.36 ; + END SPACING + +END DOUBLESPACE +END LIBRARY + From f6edc9c802ca705b863792dd9b64f0f58e9d5ae2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Feb 2023 23:41:36 +0100 Subject: [PATCH 8/9] Implemented solution for issue #1249 (persist layer properties in session) --- src/laybasic/laybasic/gsiDeclLayLayers.cc | 10 +++++ src/laybasic/laybasic/layLayerProperties.cc | 44 ++++++++++++++++--- src/laybasic/laybasic/layLayerProperties.h | 31 ++++++++++++- src/laybasic/laybasic/layLayoutViewBase.cc | 15 +++++++ src/laybasic/laybasic/layLayoutViewBase.h | 20 +++++++++ src/layui/layui/layLayerControlPanel.cc | 48 +++++++++------------ src/layui/layui/layLayerControlPanel.h | 2 +- src/layui/layui/layLayerTreeModel.cc | 15 ++++++- src/layui/layui/layLayerTreeModel.h | 16 +++++++ testdata/ruby/layLayers.rb | 6 +++ 10 files changed, 170 insertions(+), 37 deletions(-) diff --git a/src/laybasic/laybasic/gsiDeclLayLayers.cc b/src/laybasic/laybasic/gsiDeclLayLayers.cc index 7647b79bb..787eab65d 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayers.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayers.cc @@ -1189,6 +1189,16 @@ Class decl_LayerPropertiesNode ( "Unlike the name suggests, this node will still contain a hierarchy of nodes below if the original " "node did so." ) + + method ("is_expanded?", &lay::LayerPropertiesNode::expanded, + "@brief Gets a value indicating whether the layer tree node is expanded.\n" + "This predicate has been introduced in version 0.28.6." + ) + + method ("expanded=", &lay::LayerPropertiesNode::set_expanded, gsi::arg ("ex"), + "@brief Set a value indicating whether the layer tree node is expanded.\n" + "Setting this value to 'true' will expand (open) the tree node. Setting it to 'false' will collapse the node.\n" + "\n" + "This predicate has been introduced in version 0.28.6." + ) + method_ext ("add_child", &add_child0, "@brief Add a child entry\n" "@return A reference to the node created\n" diff --git a/src/laybasic/laybasic/layLayerProperties.cc b/src/laybasic/laybasic/layLayerProperties.cc index 8d009643b..3175306f5 100644 --- a/src/laybasic/laybasic/layLayerProperties.cc +++ b/src/laybasic/laybasic/layLayerProperties.cc @@ -591,6 +591,12 @@ LayerProperties::need_realize (unsigned int flags, bool /*force*/) } } +void +LayerProperties::expanded_state_changed () +{ + // .. no effect .. +} + void LayerProperties::do_realize (const LayoutViewBase *view) const { @@ -651,7 +657,7 @@ static unsigned int s_unique_id = 0; LayerPropertiesNode::LayerPropertiesNode () : LayerProperties (), - m_list_index (0) + m_list_index (0), m_expanded (false) { m_id = ++s_unique_id; } @@ -663,7 +669,7 @@ LayerPropertiesNode::~LayerPropertiesNode () LayerPropertiesNode::LayerPropertiesNode (const LayerProperties &d) : LayerProperties (d), - m_list_index (0) + m_list_index (0), m_expanded (false) { m_id = ++s_unique_id; } @@ -671,6 +677,7 @@ LayerPropertiesNode::LayerPropertiesNode (const LayerProperties &d) LayerPropertiesNode::LayerPropertiesNode (const LayerPropertiesNode &d) : LayerProperties (d), tl::Object (), m_list_index (0), + m_expanded (d.m_expanded), m_children (d.m_children), m_id (d.m_id) { @@ -687,6 +694,7 @@ LayerPropertiesNode::operator= (const LayerPropertiesNode &d) LayerProperties::operator= (d); m_children = d.m_children; + m_expanded = d.m_expanded; m_id = d.m_id; for (iterator c = m_children.begin (); c != m_children.end (); ++c) { @@ -705,7 +713,7 @@ LayerPropertiesNode::operator== (const LayerPropertiesNode &d) const if (! LayerProperties::operator== (d)) { return false; } - return m_children == d.m_children; + return m_children == d.m_children && m_expanded == d.m_expanded; } LayoutViewBase *LayerPropertiesNode::view() const @@ -713,6 +721,15 @@ LayoutViewBase *LayerPropertiesNode::view() const return const_cast (mp_view.get ()); } +void +LayerPropertiesNode::set_expanded (bool ex) +{ + if (expanded () != ex) { + m_expanded = ex; + expanded_state_changed (); + } +} + unsigned int LayerPropertiesNode::list_index () const { @@ -740,6 +757,12 @@ LayerPropertiesNode::realize_source () const do_realize (mp_view.get ()); } +void +LayerPropertiesNode::expanded_state_changed () +{ + touch (); +} + void LayerPropertiesNode::need_realize (unsigned int flags, bool force) { @@ -1763,8 +1786,9 @@ struct LineStyleIndexConverter static const tl::XMLElementList layer_element = tl::XMLElementList ( // HINT: these make_member calls want to be qualified: otherwise an internal error // was observed .. - tl::make_member (&LayerPropertiesNode::frame_color_loc, &LayerPropertiesNode::set_frame_color_code, "frame-color", UIntColorConverter ()) + - tl::make_member (&LayerPropertiesNode::fill_color_loc, &LayerPropertiesNode::set_fill_color_code, "fill-color", UIntColorConverter ()) + + tl::make_member (&LayerPropertiesNode::expanded, &LayerPropertiesNode::set_expanded, "expanded") + + tl::make_member (&LayerPropertiesNode::frame_color_loc, &LayerPropertiesNode::set_frame_color_code, "frame-color", UIntColorConverter ()) + + tl::make_member (&LayerPropertiesNode::fill_color_loc, &LayerPropertiesNode::set_fill_color_code, "fill-color", UIntColorConverter ()) + tl::make_member (&LayerPropertiesNode::frame_brightness_loc, &LayerPropertiesNode::set_frame_brightness, "frame-brightness") + tl::make_member (&LayerPropertiesNode::fill_brightness_loc, &LayerPropertiesNode::set_fill_brightness, "fill-brightness") + tl::make_member (&LayerPropertiesNode::dither_pattern_loc, &LayerPropertiesNode::set_dither_pattern, "dither-pattern", DitherPatternIndexConverter ()) + @@ -2061,6 +2085,16 @@ LayerPropertiesNodeRef::need_realize (unsigned int flags, bool force) } } +void +LayerPropertiesNodeRef::expanded_state_changed () +{ + LayerPropertiesNode::expanded_state_changed (); + + if (is_valid ()) { + view ()->set_layer_node_expanded (m_iter, expanded ()); + } +} + void LayerPropertiesNodeRef::refresh () const { diff --git a/src/laybasic/laybasic/layLayerProperties.h b/src/laybasic/laybasic/layLayerProperties.h index 60c7f79f1..4318dbab1 100644 --- a/src/laybasic/laybasic/layLayerProperties.h +++ b/src/laybasic/laybasic/layLayerProperties.h @@ -919,6 +919,11 @@ protected: */ virtual void need_realize (unsigned int flags, bool force = false); + /** + * @brief indicates a change of the collapsed/expanded state + */ + virtual void expanded_state_changed (); + /** * @brief Fetches the current status from the original properties for the LayerPropertiesNodeRef implementation */ @@ -1069,6 +1074,20 @@ public: return r; } + /** + * @brief Sets the expanded state of the layer properties tree node + */ + void set_expanded (bool ex); + + /** + * @brief Gets the expanded state of the layer properties node + */ + bool expanded () const + { + refresh (); + return m_expanded; + } + /** * @brief Child layers: begin iterator */ @@ -1207,14 +1226,21 @@ public: virtual void realize_source () const; virtual void realize_visual () const; + void set_expanded_silent (bool ex) + { + m_expanded = ex; + } + protected: virtual void need_realize (unsigned int flags, bool force); + virtual void expanded_state_changed (); void set_parent (const LayerPropertiesNode *); private: // A reference to the view tl::weak_ptr mp_view; unsigned int m_list_index; + bool m_expanded; // the parent node tl::weak_ptr mp_parent; // the list of children @@ -2009,8 +2035,9 @@ private: tl::weak_ptr mp_node; size_t m_synched_gen_id; - void need_realize (unsigned int flags, bool force); - void refresh () const; + virtual void need_realize (unsigned int flags, bool force); + virtual void expanded_state_changed (); + virtual void refresh () const; }; } diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index bf711a53d..908ef1ff1 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -1880,6 +1880,21 @@ LayoutViewBase::replace_layer_node (unsigned int index, const LayerPropertiesCon } } +void +LayoutViewBase::set_layer_node_expanded (unsigned int index, const LayerPropertiesConstIterator &iter, bool ex) +{ + if (ex != iter->expanded ()) { + + LayerPropertiesIterator non_const_iter (get_properties (index), iter.uint ()); + non_const_iter->set_expanded (ex); + + if (index == current_layer_list ()) { + layer_list_changed_event (8 /*expanded state needs update*/); + } + + } +} + void LayoutViewBase::set_properties (unsigned int index, const LayerPropertiesConstIterator &iter, const LayerProperties &props) { diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index 7d6257c19..0263a208a 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -335,6 +335,17 @@ public: set_properties (current_layer_list (), iter, props); } + /** + * @brief Sets a value indicating whether the given node is expanded in the layer tree + * + * @param iter Points to the layer node to be modified + * @param ex True if the layer node shall be expanded, false if it shall be collapsed + */ + void set_layer_node_expanded (const LayerPropertiesConstIterator &iter, bool ex) + { + set_layer_node_expanded (current_layer_list (), iter, ex); + } + /** * @brief Set the layer properties of a layer with the given position (by iterator) for the layer list with the given index * @@ -344,6 +355,15 @@ public: */ void set_properties (unsigned int index, const LayerPropertiesConstIterator &iter, const LayerProperties &props); + /** + * @brief Sets a value indicating whether the given node is expanded in the layer tree + * + * @param index The layer list's index + * @param iter Points to the layer node to be modified + * @param ex True if the layer node shall be expanded, false if it shall be collapsed + */ + void set_layer_node_expanded (unsigned int index, const LayerPropertiesConstIterator &iter, bool ex); + /** * @brief Expand the layer properties of all tabs * diff --git a/src/layui/layui/layLayerControlPanel.cc b/src/layui/layui/layLayerControlPanel.cc index 4234bc4ae..31b3bacf2 100644 --- a/src/layui/layui/layLayerControlPanel.cc +++ b/src/layui/layui/layLayerControlPanel.cc @@ -205,6 +205,7 @@ LayerControlPanel::LayerControlPanel (lay::LayoutViewBase *view, db::Manager *ma db::Object (manager), mp_view (view), m_needs_update (true), + m_expanded_state_needs_update (false), m_tabs_need_update (true), m_hidden_flags_need_update (true), m_in_update (false), @@ -1696,6 +1697,7 @@ LayerControlPanel::cancel_updates () { m_in_update = false; m_needs_update = false; + m_expanded_state_needs_update = false; m_hidden_flags_need_update = false; m_tabs_need_update = false; } @@ -1874,11 +1876,13 @@ LayerControlPanel::do_update_content () } if (m_hidden_flags_need_update) { - do_update_hidden_flags (); - m_hidden_flags_need_update = false; + } + if (m_expanded_state_needs_update) { + restore_expanded (); + m_expanded_state_needs_update = false; } } @@ -1993,6 +1997,11 @@ LayerControlPanel::signal_li_changed (int) void LayerControlPanel::update_required (int f) { + // the name of a layer list has changed + if ((f & 8) != 0) { + m_expanded_state_needs_update = true; + } + // the name of a layer list has changed if ((f & 4) != 0) { m_tabs_need_update = true; @@ -2032,18 +2041,18 @@ LayerControlPanel::current_index_changed (const QModelIndex &index) void LayerControlPanel::group_collapsed (const QModelIndex &index) { - lay::LayerPropertiesConstIterator iter = mp_model->iterator (index); + auto iter = mp_model->iterator_nc (index); if (! iter.is_null () && ! iter.at_end ()) { - m_expanded.erase (iter->id ()); + iter->set_expanded_silent (false); } } void LayerControlPanel::group_expanded (const QModelIndex &index) { - lay::LayerPropertiesConstIterator iter = mp_model->iterator (index); + auto iter = mp_model->iterator_nc (index); if (! iter.is_null () && ! iter.at_end ()) { - m_expanded.insert (iter->id ()); + iter->set_expanded_silent (true); } } @@ -2052,33 +2061,16 @@ LayerControlPanel::restore_expanded () { mp_layer_list->blockSignals (true); -#if 1 - // By keeping m_expanded, we can preserve the expansion state of different tabs. - // However we will always continue filling m_expanded. lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); while (! l.at_end ()) { - if (m_expanded.find (l->id ()) != m_expanded.end ()) { - QModelIndex index = mp_model->index (l, 0); + QModelIndex index = mp_model->index (l, 0); + if (l->expanded ()) { mp_layer_list->expand (index); + } else { + mp_layer_list->collapse (index); } ++l; } -#else - // this solution will forget the other tab's expansion flags. - std::set new_expanded; - - lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); - while (! l.at_end ()) { - if (m_expanded.find (l->id ()) != m_expanded.end ()) { - new_expanded.insert (l->id ()); - QModelIndex index = mp_model->index (l, 0); - mp_layer_list->expand (index); - } - ++l; - } - - m_expanded.swap (new_expanded); -#endif mp_layer_list->blockSignals (false); } @@ -2287,7 +2279,7 @@ public: menu_entries.push_back (lay::menu_item ("cm_lv_select_all", "select_all", at, tl::to_string (QObject::tr ("Select All")))); // It is not sure, whether "expandAll" destabilizes the tree widget: - // menu_entries.push_back (lay::menu_item ("cm_lv_expand_all", "expand_all", at, tl::to_string (QObject::tr ("Expand All"))); + // menu_entries.push_back (lay::menu_item ("cm_lv_expand_all", "expand_all", at, tl::to_string (QObject::tr ("Expand All")))); menu_entries.push_back (lay::separator ("tab_group", at)); menu_entries.push_back (lay::submenu ("tab_menu", at, tl::to_string (QObject::tr ("Tabs")))); diff --git a/src/layui/layui/layLayerControlPanel.h b/src/layui/layui/layLayerControlPanel.h index 9e38da689..40134c9e5 100644 --- a/src/layui/layui/layLayerControlPanel.h +++ b/src/layui/layui/layLayerControlPanel.h @@ -352,6 +352,7 @@ private: LayerTreeModel *mp_model; lay::LayoutViewBase *mp_view; bool m_needs_update; + bool m_expanded_state_needs_update; bool m_tabs_need_update; bool m_hidden_flags_need_update; bool m_in_update; @@ -360,7 +361,6 @@ private: int m_oversampling; bool m_hrm; tl::DeferredMethod m_do_update_content_dm; - std::set m_expanded; bool m_no_stipples; QLabel *m_no_stipples_label; lay::DecoratedLineEdit *mp_search_edit_box; diff --git a/src/layui/layui/layLayerTreeModel.cc b/src/layui/layui/layLayerTreeModel.cc index 36e3a3be8..a8f733c61 100644 --- a/src/layui/layui/layLayerTreeModel.cc +++ b/src/layui/layui/layLayerTreeModel.cc @@ -756,7 +756,20 @@ LayerTreeModel::iterator (const QModelIndex &index) const return lay::LayerPropertiesConstIterator (); } -QModelIndex +lay::LayerPropertiesIterator +LayerTreeModel::iterator_nc (const QModelIndex &index) +{ + if (index.isValid ()) { + size_t iter_index = size_t (index.internalPointer ()); + if (mp_view->layer_lists () > 0 && iter_index >= m_id_start && iter_index < m_id_end) { + return lay::LayerPropertiesIterator (mp_view->get_properties (), iter_index - m_id_start); + } + } + + return lay::LayerPropertiesIterator (); +} + +QModelIndex LayerTreeModel::index (lay::LayerPropertiesConstIterator iter, int column) const { try { diff --git a/src/layui/layui/layLayerTreeModel.h b/src/layui/layui/layLayerTreeModel.h index 94c5af84e..7071a2438 100644 --- a/src/layui/layui/layLayerTreeModel.h +++ b/src/layui/layui/layLayerTreeModel.h @@ -51,6 +51,7 @@ namespace lay class LayoutViewBase; class LayerPropertiesConstIterator; +class LayerPropertiesIterator; /** * @brief A helper class implementing a cache for the "test shapes in view" feature @@ -107,6 +108,16 @@ public: virtual QModelIndex index (int row, int column, const QModelIndex &parent) const; virtual QModelIndex parent (const QModelIndex &index) const; + /** + * @brief Sets the expanded state for a given model index + */ + void set_expanded (const QModelIndex &index, bool ex); + + /** + * @brief Gets the expanded state for a given model index + */ + bool expanded (const QModelIndex &index) const; + /** * @brief Provides an icon for a given layer style */ @@ -127,6 +138,11 @@ public: */ lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const; + /** + * @brief Converts a QModelIndex to an iterator (non-const) + */ + lay::LayerPropertiesIterator iterator_nc (const QModelIndex &index); + /** * @brief Gets a flag indicating that an entry is hidden */ diff --git a/testdata/ruby/layLayers.rb b/testdata/ruby/layLayers.rb index 8bf617f78..1f08758a9 100644 --- a/testdata/ruby/layLayers.rb +++ b/testdata/ruby/layLayers.rb @@ -667,12 +667,18 @@ class LAYLayers_TestClass < TestBase p.clear_line_style assert_equal( p.has_line_style?, false ) + assert_equal( p.is_expanded?, false ) + p.expanded = true + assert_equal( p.is_expanded?, true ) + pp = RBA::LayerPropertiesNode::new assert_equal( pp == p, false ) assert_equal( pp != p, true ) + assert_equal( pp.is_expanded?, false ) pp = p.dup assert_equal( pp == p, true ) assert_equal( pp != p, false ) + assert_equal( pp.is_expanded?, true ) end From 8038acc23630e7e22c1527891374c3f6aae9373d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Feb 2023 09:50:34 +0100 Subject: [PATCH 9/9] Updated test data --- src/laybasic/unit_tests/layLayerProperties.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/laybasic/unit_tests/layLayerProperties.cc b/src/laybasic/unit_tests/layLayerProperties.cc index f6175a348..26e7ecb20 100644 --- a/src/laybasic/unit_tests/layLayerProperties.cc +++ b/src/laybasic/unit_tests/layLayerProperties.cc @@ -135,6 +135,7 @@ TEST (1) "\n" "\n" " \n" + " false\n" " \n" " \n" " 0\n"