diff --git a/.gitignore b/.gitignore index c53e2de59..93210c161 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ build-* bin-* mkqtdecl.tmp +mkqtdecl5.tmp testtmp *build.macos* *bin.macos* diff --git a/build.sh b/build.sh index c2f1d6bfe..79555a24f 100755 --- a/build.sh +++ b/build.sh @@ -26,6 +26,14 @@ IS_WINDOWS="no" IS_LINUX="no" HAVE_QTBINDINGS=1 +HAVE_QT_UITOOLS=1 +HAVE_QT_NETWORK=1 +HAVE_QT_SQL=1 +HAVE_QT_SVG=1 +HAVE_QT_PRINTSUPPORT=1 +HAVE_QT_MULTIMEDIA=1 +HAVE_QT_DESIGNER=1 +HAVE_QT_XML=1 HAVE_64BIT_COORD=0 HAVE_QT=1 HAVE_QT5="" # not set @@ -83,15 +91,39 @@ while [ "$*" != "" ]; do shift case $a in - -with-qtbinding) - HAVE_QTBINDINGS=1 - ;; -without-qt) HAVE_QT=0 ;; + -with-qtbinding) + HAVE_QTBINDINGS=1 + ;; -without-qtbinding) HAVE_QTBINDINGS=0 ;; + -without-qt-uitools) + HAVE_QT_UITOOLS=0 + ;; + -without-qt-network) + HAVE_QT_NETWORK=0 + ;; + -without-qt-sql) + HAVE_QT_SQL=0 + ;; + -without-qt-svg) + HAVE_QT_SVG=0 + ;; + -without-qt-printsupport) + HAVE_QT_PRINTSUPPORT=0 + ;; + -without-qt-multimedia) + HAVE_QT_MULTIMEDIA=0 + ;; + -without-qt-designer) + HAVE_QT_DESIGNER=0 + ;; + -without-qt-xml) + HAVE_QT_XML=0 + ;; -with-64bit-coord) HAVE_64BIT_COORD=1 ;; @@ -207,6 +239,7 @@ while [ "$*" != "" ]; do echo "" echo " -with-qtbinding Create Qt bindings for ruby scripts [default]" echo " -without-qtbinding Don't create Qt bindings for ruby scripts" + echo " -without-qt-uitools Don't include uitools in Qt binding" echo " -with-64bit-coord Use long (64bit) coordinates - EXPERIMENTAL FEATURE" echo " (only available for gcc>=4.4 for 64bit build)" echo " -without-64bit-coord Don't use long (64bit) coordinates [default]" @@ -604,6 +637,14 @@ qmake_options=( PYTHONEXTSUFFIX="$PYTHONEXTSUFFIX" HAVE_PYTHON="$HAVE_PYTHON" HAVE_QTBINDINGS="$HAVE_QTBINDINGS" + HAVE_QT_UITOOLS="$HAVE_QT_UITOOLS" + HAVE_QT_NETWORK="$HAVE_QT_NETWORK" + HAVE_QT_SQL="$HAVE_QT_SQL" + HAVE_QT_SVG="$HAVE_QT_SVG" + HAVE_QT_PRINTSUPPORT="$HAVE_QT_PRINTSUPPORT" + HAVE_QT_MULTIMEDIA="$HAVE_QT_MULTIMEDIA" + HAVE_QT_DESIGNER="$HAVE_QT_DESIGNER" + HAVE_QT_XML="$HAVE_QT_XML" HAVE_64BIT_COORD="$HAVE_64BIT_COORD" HAVE_QT="$HAVE_QT" HAVE_QT5="$HAVE_QT5" diff --git a/scripts/mkqtdecl.sh b/scripts/mkqtdecl.sh index bd240bb85..8a0f462e6 100755 --- a/scripts/mkqtdecl.sh +++ b/scripts/mkqtdecl.sh @@ -49,8 +49,8 @@ inst_dir5=`pwd`/scripts/mkqtdecl5 src_dir=`pwd`/src src_name4=gsiqt/qt4 src_name5=gsiqt/qt5 -qt_mods4="QtCore QtGui QtDesigner QtNetwork QtSql QtXml" -qt_mods5="QtCore QtGui QtWidgets QtDesigner QtNetwork QtPrintSupport QtSql QtSvg QtXml QtXmlPatterns QtMultimedia" +qt_mods4="QtCore QtGui QtDesigner QtNetwork QtSql QtXml QtUiTools" +qt_mods5="QtCore QtGui QtWidgets QtDesigner QtNetwork QtPrintSupport QtSql QtSvg QtXml QtXmlPatterns QtMultimedia QtUiTools" src_name=$src_name4 inst_dir=$inst_dir4 diff --git a/scripts/mkqtdecl4/QtUiTools/allofqt.cpp b/scripts/mkqtdecl4/QtUiTools/allofqt.cpp new file mode 100644 index 000000000..efa38a675 --- /dev/null +++ b/scripts/mkqtdecl4/QtUiTools/allofqt.cpp @@ -0,0 +1 @@ +#include "QtUiTools/QUiLoader" diff --git a/scripts/mkqtdecl4/mkqtdecl.conf b/scripts/mkqtdecl4/mkqtdecl.conf index b6bc2f11d..92973c77b 100644 --- a/scripts/mkqtdecl4/mkqtdecl.conf +++ b/scripts/mkqtdecl4/mkqtdecl.conf @@ -302,6 +302,13 @@ rename "QProcess", /QProcess::finished\(int[\s\w]*\)/, "finished_int" # disambig drop_method "QCoreApplication", /QCoreApplication::QCoreApplication/ add_native_qapp_ctor_impl("QCoreApplication") +# Reasoning: "notify" is hardly needed (use postEvent or sendEvent instead). Reimplementing remains as a use case. +# Reimplementing this method however is questionable: providing an reimplementation hook has severe consequences as even +# Qt object constructors will route over this slot and invoke interpreter calls. This will for example lead to preliminary +# binding of Qt objects to Python objects, hence spoil their object identity. +drop_method "QCoreApplication", /QCoreApplication::notify/ +drop_method "QApplication", /QApplication::notify/ + # alternative implementation for QObject::findChild add_native_impl_QObject_findChild @@ -886,6 +893,11 @@ no_copy_ctor "QFormLayout" no_copy_ctor "QXmlParseException" no_copy_ctor "QNetworkAccessManager" +# -------------------------------------------------------------- +# QtUiTools + +include "QUiLoader", [ "", "", "", "", "", "", "", "", "" ] + # -------------------------------------------------------------- # events and properties # NOTE: to generate these files use scripts/mkqtdecl/mkqtdecl_extract_props.rb diff --git a/scripts/mkqtdecl5/QtUiTools/allofqt.cpp b/scripts/mkqtdecl5/QtUiTools/allofqt.cpp new file mode 100644 index 000000000..efa38a675 --- /dev/null +++ b/scripts/mkqtdecl5/QtUiTools/allofqt.cpp @@ -0,0 +1 @@ +#include "QtUiTools/QUiLoader" diff --git a/scripts/mkqtdecl5/mkqtdecl.conf b/scripts/mkqtdecl5/mkqtdecl.conf index 4d5b23f09..2a9f3a688 100644 --- a/scripts/mkqtdecl5/mkqtdecl.conf +++ b/scripts/mkqtdecl5/mkqtdecl.conf @@ -375,6 +375,14 @@ rename "QProcess", /QProcess::finished\(int[\s\w]*\)/, "finished_int" # disambig drop_method "QCoreApplication", /QCoreApplication::QCoreApplication/ add_native_qapp_ctor_impl("QCoreApplication") +# Reasoning: "notify" is hardly needed (use postEvent or sendEvent instead). Reimplementing remains as a use case. +# Reimplementing this method however is questionable: providing an reimplementation hook has severe consequences as even +# Qt object constructors will route over this slot and invoke interpreter calls. This will for example lead to preliminary +# binding of Qt objects to Python objects, hence spoil their object identity. +drop_method "QCoreApplication", /QCoreApplication::notify/ +drop_method "QApplication", /QApplication::notify/ +drop_method "QGuiApplication", /QGuiApplication::notify/ + # alternative implementation for QObject::findChild add_native_impl_QObject_findChild @@ -1210,6 +1218,11 @@ rename "QNetworkSession", /QNetworkSession::error\(QNetworkSession::/, "error_si rename "QSqlDriver", /QSqlDriver::notification\(const\s+QString\s*\&\s*\w*\s*\)/, "notification" # disambiguator rename "QSqlDriver", /QSqlDriver::notification\(const\s+QString\s*\&\s*\w*\s*,/, "notification_withData" # disambiguator +# -------------------------------------------------------------- +# QtUiTools + +include "QUiLoader", [ "", "", "", "", "", "", "", "", "" ] + # -------------------------------------------------------------- # events and properties # NOTE: to generate these files use scripts/mkqtdecl/mkqtdecl_extract_props.rb diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc index 773fb8338..721cd8c24 100644 --- a/src/ant/ant/antPropertiesPage.cc +++ b/src/ant/ant/antPropertiesPage.cc @@ -134,7 +134,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2) try { tl::from_string (tl::to_string (x1->text ()), dx1); - lay::indicate_error (x1, 0); + lay::indicate_error (x1, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (x1, &ex); has_error = true; @@ -142,7 +142,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2) try { tl::from_string (tl::to_string (x2->text ()), dx2); - lay::indicate_error (x2, 0); + lay::indicate_error (x2, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (x2, &ex); has_error = true; @@ -150,7 +150,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2) try { tl::from_string (tl::to_string (y1->text ()), dy1); - lay::indicate_error (y1, 0); + lay::indicate_error (y1, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (y1, &ex); has_error = true; @@ -158,7 +158,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2) try { tl::from_string (tl::to_string (y2->text ()), dy2); - lay::indicate_error (y2, 0); + lay::indicate_error (y2, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (y2, &ex); has_error = true; diff --git a/src/buddies/src/bd/bdInit.cc b/src/buddies/src/bd/bdInit.cc index 261ab0c1a..0d3160ccc 100644 --- a/src/buddies/src/bd/bdInit.cc +++ b/src/buddies/src/bd/bdInit.cc @@ -71,13 +71,10 @@ public: ProgressAdaptor (int verbosity); virtual ~ProgressAdaptor (); - virtual void register_object (tl::Progress *progress); - virtual void unregister_object (tl::Progress *progress); virtual void trigger (tl::Progress *progress); virtual void yield (tl::Progress *progress); private: - std::list mp_objects; int m_verbosity; std::string m_progress_text, m_progress_value; }; @@ -93,36 +90,19 @@ ProgressAdaptor::~ProgressAdaptor () // .. nothing yet .. } -void -ProgressAdaptor::register_object (tl::Progress *progress) -{ - mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible. -} - -void -ProgressAdaptor::unregister_object (tl::Progress *progress) -{ - for (std::list::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) { - if (*k == progress) { - mp_objects.erase (k); - return; - } - } -} - void ProgressAdaptor::trigger (tl::Progress *progress) { - if (! mp_objects.empty () && mp_objects.front () == progress && tl::verbosity () >= m_verbosity) { + if (progress && first () == progress && tl::verbosity () >= m_verbosity) { - std::string text = mp_objects.front ()->desc (); + std::string text = progress->desc (); if (m_progress_text != text) { tl::info << text << " .."; m_progress_text = text; } - std::string value = mp_objects.front ()->formatted_value (); + std::string value = progress->formatted_value (); if (m_progress_value != value) { tl::info << ".. " << value; m_progress_value = value; diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 925212796..57c31cd95 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -97,6 +97,9 @@ GenericReaderOptions::GenericReaderOptions () m_lefdef_produce_lef_pins = load_options.get_option_by_name ("lefdef_config.produce_lef_pins").to_bool (); m_lefdef_lef_pins_suffix = load_options.get_option_by_name ("lefdef_config.lef_pins_suffix_str").to_string (); m_lefdef_lef_pins_datatype = load_options.get_option_by_name ("lefdef_config.lef_pins_datatype_str").to_string (); + m_lefdef_produce_fills = load_options.get_option_by_name ("lefdef_config.produce_fills").to_bool (); + m_lefdef_fills_suffix = load_options.get_option_by_name ("lefdef_config.fills_suffix_str").to_string (); + m_lefdef_fills_datatype = load_options.get_option_by_name ("lefdef_config.fills_datatype_str").to_string (); m_lefdef_produce_obstructions = load_options.get_option_by_name ("lefdef_config.produce_obstructions").to_bool (); m_lefdef_obstruction_suffix = load_options.get_option_by_name ("lefdef_config.obstructions_suffix").to_string (); m_lefdef_obstruction_datatype = load_options.get_option_by_name ("lefdef_config.obstructions_datatype").to_int (); @@ -500,6 +503,20 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "The LEF pin geometry generation and layer mapping is designed in the same way than via geometry mapping. " "See '--" + m_long_prefix + "lefdef-produce-via-geometry' for a description of the mapping scheme.\n" ) + << tl::arg (group + + "#!--" + m_long_prefix + "lefdef-dont-produce-fills", &m_lefdef_produce_fills, "Skips fills when producing geometry", + "If this option is given, no fill geometry will be produced." + ) + << tl::arg (group + + "#--" + m_long_prefix + "lefdef-fills-suffix", &m_lefdef_fills_suffix, "Specifies the fill geometry layer suffix in pattern-based mode", + "The fill geometry generation and layer mapfillg is designed in the same way than via geometry mapfillg. " + "See '--" + m_long_prefix + "lefdef-via-geometry-suffix' for a description of the mapfillg scheme.\n" + ) + << tl::arg (group + + "#--" + m_long_prefix + "lefdef-fills-datatype", &m_lefdef_fills_datatype, "Specifies the fill geometry layer datatype in pattern-based mode", + "The fill geometry generation and layer mapfillg is designed in the same way than via geometry mapfillg. " + "See '--" + m_long_prefix + "lefdef-produce-via-geometry' for a description of the mapfillg scheme.\n" + ) << tl::arg (group + "#!--" + m_long_prefix + "lefdef-dont-produce-routing", &m_lefdef_produce_routing, "Skips routing when producing geometry", "If this option is given, no routing geometry will be produced." @@ -724,6 +741,9 @@ GenericReaderOptions::configure (db::LoadLayoutOptions &load_options) const load_options.set_option_by_name ("lefdef_config.produce_lef_pins", m_lefdef_produce_lef_pins); load_options.set_option_by_name ("lefdef_config.lef_pins_suffix_str", m_lefdef_lef_pins_suffix); load_options.set_option_by_name ("lefdef_config.lef_pins_datatype_str", m_lefdef_lef_pins_datatype); + load_options.set_option_by_name ("lefdef_config.produce_fills", m_lefdef_produce_fills); + load_options.set_option_by_name ("lefdef_config.fills_suffix_str", m_lefdef_fills_suffix); + load_options.set_option_by_name ("lefdef_config.fills_datatype_str", m_lefdef_fills_datatype); load_options.set_option_by_name ("lefdef_config.produce_obstructions", m_lefdef_produce_obstructions); load_options.set_option_by_name ("lefdef_config.obstructions_suffix", m_lefdef_obstruction_suffix); load_options.set_option_by_name ("lefdef_config.obstructions_datatype", m_lefdef_obstruction_datatype); diff --git a/src/buddies/src/bd/bdReaderOptions.h b/src/buddies/src/bd/bdReaderOptions.h index ac4cf2acf..2f877dc00 100644 --- a/src/buddies/src/bd/bdReaderOptions.h +++ b/src/buddies/src/bd/bdReaderOptions.h @@ -161,6 +161,9 @@ private: bool m_lefdef_produce_lef_pins; std::string m_lefdef_lef_pins_suffix; std::string m_lefdef_lef_pins_datatype; + bool m_lefdef_produce_fills; + std::string m_lefdef_fills_suffix; + std::string m_lefdef_fills_datatype; bool m_lefdef_produce_obstructions; std::string m_lefdef_obstruction_suffix; int m_lefdef_obstruction_datatype; diff --git a/src/buddies/unit_tests/bdStrmrunTests.cc b/src/buddies/unit_tests/bdStrmrunTests.cc index 4daa5a7e1..21bd27368 100644 --- a/src/buddies/unit_tests/bdStrmrunTests.cc +++ b/src/buddies/unit_tests/bdStrmrunTests.cc @@ -27,6 +27,7 @@ // Testing the converter main implementation (CIF) TEST(1) { +#if defined(HAVE_PYTHON) std::string fp (tl::testsrc ()); fp += "/testdata/bd/strmrun.py"; @@ -51,5 +52,6 @@ TEST(1) tl::info << data; EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n"); +#endif } diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 16f9df099..bd6371526 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -61,6 +61,7 @@ SOURCES = \ dbPolygonGenerators.cc \ dbPropertiesRepository.cc \ dbReader.cc \ + dbRecursiveInstanceIterator.cc \ dbRecursiveShapeIterator.cc \ dbRegion.cc \ dbRegionLocalOperations.cc \ @@ -114,6 +115,7 @@ SOURCES = \ gsiDeclDbPoint.cc \ gsiDeclDbPolygon.cc \ gsiDeclDbReader.cc \ + gsiDeclDbRecursiveInstanceIterator.cc \ gsiDeclDbRecursiveShapeIterator.cc \ gsiDeclDbRegion.cc \ gsiDeclDbShape.cc \ @@ -269,6 +271,7 @@ HEADERS = \ dbPolygonGenerators.h \ dbPropertiesRepository.h \ dbReader.h \ + dbRecursiveInstanceIterator.h \ dbRecursiveShapeIterator.h \ dbRegion.h \ dbRegionLocalOperations.h \ diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 8881e454f..9547a71cf 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -403,6 +403,8 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; others.push_back (counting ? other.begin_merged () : other.begin ()); @@ -479,6 +481,8 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; others.push_back (other.begin ()); @@ -564,6 +568,8 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ()); @@ -702,6 +708,8 @@ AsIfFlatRegion::pull_generic (const Edges &other) const db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; others.push_back (other.begin_merged ()); @@ -752,6 +760,8 @@ AsIfFlatRegion::pull_generic (const Texts &other) const db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; others.push_back (other.begin ()); @@ -807,6 +817,8 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; others.push_back (other.begin_merged ()); @@ -1170,6 +1182,8 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); std::vector > others; std::vector foreign; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index ee3fb5892..bc49410e9 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -601,6 +601,8 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_threads (deep_layer ().store ()->threads ()); proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); @@ -620,6 +622,8 @@ DeepRegion::and_and_not_with (const DeepRegion *other) const db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_threads (deep_layer ().store ()->threads ()); proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); @@ -1359,6 +1363,8 @@ Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &no const_cast (®ion->deep_layer ().initial_cell ()), region->deep_layer ().breakout_cells ()); + proc.set_description (region->progress_desc ()); + proc.set_report_progress (region->report_progress ()); proc.set_base_verbosity (region->base_verbosity ()); proc.set_threads (region->deep_layer ().store ()->threads ()); @@ -1464,6 +1470,8 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons deep_layer ().breakout_cells (), other_deep ? other_deep->deep_layer ().breakout_cells () : 0); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); @@ -1536,6 +1544,8 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count, true); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); if (split_after) { @@ -1575,6 +1585,8 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count, true); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); if (split_after) { @@ -1614,6 +1626,8 @@ DeepRegion::pull_generic (const Region &other, int mode, bool touching) const db::PullLocalOperation op (mode, touching); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); if (split_after) { @@ -1650,6 +1664,8 @@ DeepRegion::pull_generic (const Edges &other) const db::PullWithEdgeLocalOperation op; db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell (), polygons.breakout_cells (), other_edges.breakout_cells ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); proc.run (&op, polygons.layer (), other_edges.layer (), dl_out.layer ()); @@ -1679,6 +1695,8 @@ DeepRegion::pull_generic (const Texts &other) const db::PullWithTextLocalOperation op; db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ()); @@ -1709,6 +1727,8 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size db::InteractingWithTextLocalOperation op (inverse, min_count, max_count); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); if (split_after) { diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 9f42043ca..e5f1da83b 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -395,7 +395,7 @@ void NetlistSpiceReader::push_stream (const std::string &path) istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path)); } } else { - istream = new tl::InputStream (current_uri.resolved (new_uri).to_string ()); + istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ()); } m_streams.push_back (std::make_pair (istream, mp_stream.release ())); diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 1895d69b9..0aa4839d1 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -725,7 +725,7 @@ template DB_PUBLIC void split_polygon<> (const db::DSimplePolygon &polygon, std: // Smoothing tools void -smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector &points, db::Coord d) +smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector &points, db::Coord d, bool keep_hv) { points.clear (); points.reserve (std::distance (from, to)); @@ -781,7 +781,9 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon bool can_drop = false; - if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) { + if (keep_hv && (p1.x () == p0.x () || p1.y () == p0.y () || p2.x () == p1.x () || p2.y () == p1.y ())) { + // keep points which participate in either a vertical or horizontal edge + } else if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) { // jog configurations with small edges are candidates can_drop = true; } else if (db::vprod_sign (p2 - p1, p1 - p0) < 0) { @@ -839,19 +841,19 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon } db::Polygon -smooth (const db::Polygon &polygon, db::Coord d) +smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv) { db::Polygon new_poly; std::vector new_pts; - smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d); + smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d, keep_hv); if (new_pts.size () >= 3) { new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/); for (unsigned int h = 0; h < polygon.holes (); ++h) { new_pts.clear (); - smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d); + smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d, keep_hv); if (new_pts.size () >= 3) { new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/); } diff --git a/src/db/db/dbPolygonTools.h b/src/db/db/dbPolygonTools.h index 26f963039..d59188163 100644 --- a/src/db/db/dbPolygonTools.h +++ b/src/db/db/dbPolygonTools.h @@ -449,6 +449,8 @@ db::Polygon DB_PUBLIC compute_rounded (const db::Polygon &poly, double rinner, d */ db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner, double router, unsigned int n); +#define KLAYOUT_SMOOTH_HAS_KEEP_HV 1 + /** * @brief Smooth a contour * @@ -458,13 +460,14 @@ db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner, * @param to The end of the contour * @param new_pts The points that make up the new contour * @param d The distance that determines the smoothing "roughness" + * @param keep_hv If true, vertical and horizontal edges are maintained */ -void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector &new_pts, db::Coord d); +void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector &new_pts, db::Coord d, bool keep_hv); /** * @brief Smooth a polygon (apply smoothing to the whole polygon) */ -db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d); +db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d, bool keep_hv); /** * @brief Returns a value indicating whether the polygon is an "strange polygon" diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc new file mode 100644 index 000000000..c4782ad8d --- /dev/null +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -0,0 +1,755 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbRecursiveInstanceIterator.h" +#include "dbRegion.h" +#include "dbEdgeProcessor.h" +#include "tlProgress.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------ +// Recursive shape iterator implementation + +RecursiveInstanceIterator::RecursiveInstanceIterator (const RecursiveInstanceIterator &d) +{ + operator= (d); +} + +RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const RecursiveInstanceIterator &d) +{ + if (&d != this) { + + m_all_targets = d.m_all_targets; + m_targets = d.m_targets; + + m_max_depth = d.m_max_depth; + m_min_depth = d.m_min_depth; + m_overlapping = d.m_overlapping; + m_start = d.m_start; + m_stop = d.m_stop; + + mp_layout = d.mp_layout; + mp_top_cell = d.mp_top_cell; + + m_region = d.m_region; + if (d.mp_complex_region.get () != 0) { + mp_complex_region.reset (new region_type (*d.mp_complex_region.get ())); + } else { + mp_complex_region.reset (0); + } + + m_box_convert = d.m_box_convert; + + m_inst = d.m_inst; + m_inst_array = d.m_inst_array; + m_empty_cells_cache = d.m_empty_cells_cache; + mp_cell = d.mp_cell; + m_trans = d.m_trans; + m_trans_stack = d.m_trans_stack; + m_inst_iterators = d.m_inst_iterators; + m_inst_array_iterators = d.m_inst_array_iterators; + m_cells = d.m_cells; + m_local_complex_region_stack = d.m_local_complex_region_stack; + m_local_region_stack = d.m_local_region_stack; + m_needs_reinit = d.m_needs_reinit; + m_inst_quad_id = d.m_inst_quad_id; + m_inst_quad_id_stack = d.m_inst_quad_id_stack; + + } + return *this; +} + +RecursiveInstanceIterator::RecursiveInstanceIterator () +{ + // anything. Not necessary reasonable. + mp_layout = 0; + mp_top_cell = 0; + mp_cell = 0; + m_overlapping = false; + m_max_depth = std::numeric_limits::max (); // all + m_min_depth = 0; + m_needs_reinit = false; + m_inst_quad_id = 0; + m_all_targets = true; +} + +RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type ®ion, bool overlapping) + : m_box_convert (layout) +{ + mp_layout = &layout; + mp_top_cell = &cell; + m_overlapping = overlapping; + init (); + init_region (region); +} + +RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type ®ion, bool overlapping) + : m_box_convert (layout) +{ + mp_layout = &layout; + mp_top_cell = &cell; + m_overlapping = overlapping; + init (); + init_region (region); +} + +RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell) + : m_box_convert (layout) +{ + mp_layout = &layout; + mp_top_cell = &cell; + m_overlapping = false; + init (); + init_region (box_type::world ()); +} + +RecursiveInstanceIterator::~RecursiveInstanceIterator () +{ + // .. nothing yet .. +} + + +void +RecursiveInstanceIterator::init () +{ + m_needs_reinit = true; + m_max_depth = std::numeric_limits::max (); // all + m_min_depth = 0; // from the beginning + m_inst_quad_id = 0; + mp_cell = 0; + m_all_targets = true; +} + +void +RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::box_type ®ion) +{ + m_region = region; + mp_complex_region.reset (0); +} + +void +RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::region_type ®ion) +{ + if (region.empty ()) { + + m_region = box_type (); + mp_complex_region.reset (0); + + } else if (region.is_box ()) { + + m_region = region.bbox (); + mp_complex_region.reset (0); + + } else { + + mp_complex_region.reset (new region_type (region)); + m_region = region.bbox (); + // A small optimization. We can do this since we merge and translate to trapezoids anyway. + mp_complex_region->set_strict_handling (false); + + } +} + +void +RecursiveInstanceIterator::set_region (const box_type ®ion) +{ + if (m_region != region || mp_complex_region.get () != 0) { + init_region (region); + m_needs_reinit = true; + } +} + +void +RecursiveInstanceIterator::set_region (const region_type ®ion) +{ + init_region (region); + m_needs_reinit = true; +} + +void +RecursiveInstanceIterator::confine_region (const box_type ®ion) +{ + if (m_region.empty ()) { + // no more confinement + } else if (mp_complex_region.get ()) { + init_region (*mp_complex_region & region_type (region)); + } else { + init_region (m_region & region); + } + m_needs_reinit = true; +} + +void +RecursiveInstanceIterator::confine_region (const region_type ®ion) +{ + if (m_region.empty ()) { + // no more confinement + } else if (mp_complex_region.get ()) { + init_region (*mp_complex_region & region); + } else { + init_region (region & region_type (m_region)); + } + m_needs_reinit = true; +} + +void +RecursiveInstanceIterator::enable_all_targets () +{ + if (! m_all_targets) { + m_all_targets = true; + m_targets.clear (); + m_needs_reinit = true; + } +} + +void +RecursiveInstanceIterator::set_targets (const std::set &tgt) +{ + if (m_all_targets || m_targets != tgt) { + m_targets = tgt; + m_all_targets = false; + m_needs_reinit = true; + } +} + +namespace { + +struct BoxTreePusher + : public db::SimplePolygonSink +{ + BoxTreePusher (RecursiveInstanceIterator::box_tree_type *bt) + : mp_bt (bt) + { + // .. nothing yet .. + } + + void put (const db::SimplePolygon &sp) + { + mp_bt->insert (sp.box ()); + } + +private: + RecursiveInstanceIterator::box_tree_type *mp_bt; +}; + +} + +void +RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const +{ + if (! m_needs_reinit) { + return; + } + + m_needs_reinit = false; + + // re-initialize + mp_cell = mp_top_cell; + m_trans_stack.clear (); + m_inst_iterators.clear (); + m_inst_quad_id_stack.clear (); + m_inst_array_iterators.clear (); + m_cells.clear (); + m_trans = cplx_trans_type (); + + m_local_region_stack.clear (); + m_local_region_stack.push_back (m_region); + + m_local_complex_region_stack.clear (); + if (mp_complex_region.get ()) { + + // prepare a local complex region + m_local_complex_region_stack.push_back (box_tree_type ()); + + // Use a merge and the trapezoid generator to produce a decomposition that goes into the complex region + + db::EdgeProcessor ep; + size_t n = 0; + for (region_type::const_iterator p = mp_complex_region->begin (); !p.at_end (); ++p, ++n) { + ep.insert (*p, n); + } + + BoxTreePusher btp (&m_local_complex_region_stack.back ()); + db::TrapezoidGenerator tg (btp); + + db::MergeOp op (0); + ep.process (tg, op); + + m_local_complex_region_stack.back ().sort (db::box_convert ()); + + } + + if (mp_top_cell) { + + if (! m_all_targets) { + m_target_tree.clear (); + mp_top_cell->collect_called_cells (m_target_tree); + } + + new_cell (receiver); + next_instance (receiver); + + } +} + +void +RecursiveInstanceIterator::reset_selection () +{ + if (mp_layout) { + + m_start.clear (); + m_stop.clear (); + + m_needs_reinit = true; + + } +} + +void +RecursiveInstanceIterator::unselect_cells (const std::set &cells) +{ + if (mp_layout) { + + for (std::set::const_iterator c = cells.begin (); c != cells.end (); ++c) { + m_stop.insert (*c); + m_start.erase (*c); + } + + m_needs_reinit = true; + + } +} + +void +RecursiveInstanceIterator::unselect_all_cells () +{ + if (mp_layout) { + + m_start.clear (); + for (db::Layout::const_iterator c = mp_layout->begin (); c != mp_layout->end (); ++c) { + m_stop.insert (c->cell_index ()); + } + + m_needs_reinit = true; + + } +} + +void +RecursiveInstanceIterator::select_cells (const std::set &cells) +{ + if (mp_layout) { + + for (std::set::const_iterator c = cells.begin (); c != cells.end (); ++c) { + m_start.insert (*c); + m_stop.erase (*c); + } + + m_needs_reinit = true; + + } +} + +void +RecursiveInstanceIterator::select_all_cells () +{ + if (mp_layout) { + + m_stop.clear (); + for (db::Layout::const_iterator c = mp_layout->begin (); c != mp_layout->end (); ++c) { + m_start.insert (c->cell_index ()); + } + + m_needs_reinit = true; + + } +} + +const RecursiveInstanceIterator::instance_element_type * +RecursiveInstanceIterator::operator-> () const +{ + validate (0); + m_combined_instance = db::InstElement (*m_inst, m_inst_array); + return &m_combined_instance; +} + +bool +RecursiveInstanceIterator::at_end () const +{ + validate (0); + return m_inst.at_end (); +} + +std::vector +RecursiveInstanceIterator::path () const +{ + std::vector elements; + for (size_t i = 0; i < m_inst_array_iterators.size () && i < m_inst_iterators.size (); ++i) { + elements.push_back (db::InstElement (*m_inst_iterators [i], m_inst_array_iterators [i])); + } + return elements; +} + +void +RecursiveInstanceIterator::skip_inst_iter_for_complex_region () const +{ + while (! m_inst.at_end ()) { + + // skip inst quad if possible + while (! m_inst.at_end ()) { + if (is_outside_complex_region (m_inst.quad_box ())) { + m_inst.skip_quad (); + } else { + m_inst_quad_id = m_inst.quad_id (); + break; + } + } + + // skip insts outside the complex region + if (! m_inst.at_end ()) { + if (! is_outside_complex_region (m_inst->bbox ())) { + break; + } else { + ++m_inst; + } + } + + } +} + +void +RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver) +{ + if (! at_end ()) { + ++m_inst_array; + if (! m_inst_array.at_end ()) { + new_inst_member (receiver); + } else { + ++m_inst; + new_inst (receiver); + next_instance (receiver); + } + } +} + +bool +RecursiveInstanceIterator::needs_visit () const +{ + return int (m_inst_iterators.size ()) >= m_min_depth && ! is_inactive () && (m_all_targets || m_targets.find (m_inst->cell_index ()) != m_targets.end ()); +} + +void +RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) const +{ + while (true) { + + if (! m_inst.at_end ()) { + + if (int (m_inst_iterators.size ()) < m_max_depth && (m_all_targets || m_target_tree.find (m_inst->cell_index ()) != m_target_tree.end ())) { + down (receiver); + } + + } else { + + if (! m_inst_iterators.empty ()) { + // no more instances: up and next instance + up (receiver); + } else { + break; + } + + } + + if (! m_inst.at_end ()) { + if (! needs_visit ()) { + ++m_inst_array; + if (! m_inst_array.at_end ()) { + new_inst_member (receiver); + } else { + ++m_inst; + new_inst (receiver); + } + } else { + break; + } + } + + } +} + +void +RecursiveInstanceIterator::down (RecursiveInstanceReceiver *receiver) const +{ + m_trans_stack.push_back (m_trans); + m_cells.push_back (mp_cell); + + m_inst_iterators.push_back (m_inst); + m_inst_array_iterators.push_back (m_inst_array); + m_inst_quad_id_stack.push_back (m_inst_quad_id); + + bool ia = is_inactive (); + bool aoi = is_all_of_instance (); + mp_cell = &mp_layout->cell (m_inst->cell_index ()); + set_inactive (ia); + set_all_of_instance (aoi); + + m_trans = m_trans * m_inst->complex_trans (*m_inst_array); + + // don't transform the world region, since transformation of that region might not work properly + box_type new_region = box_type::world (); + + // compute the region inside the new cell + if (new_region != m_local_region_stack.front ()) { + new_region = m_trans.inverted () * m_local_region_stack.front (); + new_region &= cell ()->bbox (); + } + m_local_region_stack.push_back (new_region); + + if (! m_local_complex_region_stack.empty ()) { + + m_local_complex_region_stack.push_back (box_tree_type ()); + const box_tree_type &pcl = m_local_complex_region_stack.end ()[-2]; + + if (! new_region.empty ()) { + + // compute a new, reduced complex region for use inside the new cell + + db::CellInstArray::complex_trans_type tinst = m_inst->complex_trans (*m_inst_array); + db::CellInstArray::complex_trans_type tinst_inv = tinst.inverted (); + + db::Box bb; + + for (box_tree_type::touching_iterator b = pcl.begin_touching (correct_box_overlapping (new_region.transformed (tinst)), db::box_convert ()); ! b.at_end (); ++b) { + db::Box lb = (b->transformed (tinst_inv) & new_region); + if (! lb.empty ()) { + m_local_complex_region_stack.back ().insert (lb); + bb += lb; + } + } + + m_local_complex_region_stack.back ().sort (db::box_convert ()); + + // re-adjust the new local region, so we take into account additional clipping by the complex region. + // in the extreme case, this box is empty: + m_local_region_stack.back () = bb; + + } + + } + + if (receiver) { + receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ()); + } + + new_cell (receiver); +} + +void +RecursiveInstanceIterator::up (RecursiveInstanceReceiver *receiver) const +{ + if (receiver) { + receiver->leave_cell (this, cell ()); + } + + m_inst = m_inst_iterators.back (); + m_inst_array = m_inst_array_iterators.back (); + m_inst_quad_id = m_inst_quad_id_stack.back (); + m_inst_iterators.pop_back (); + m_inst_array_iterators.pop_back (); + m_inst_quad_id_stack.pop_back (); + + m_trans = m_trans_stack.back (); + m_trans_stack.pop_back (); + mp_cell = m_cells.back (); + m_cells.pop_back (); + m_local_region_stack.pop_back (); + if (! m_local_complex_region_stack.empty ()) { + m_local_complex_region_stack.pop_back (); + } +} + +void +RecursiveInstanceIterator::new_cell (RecursiveInstanceReceiver *receiver) const +{ + bool new_cell_inactive = is_child_inactive (cell_index ()); + if (is_inactive () != new_cell_inactive) { + set_inactive (new_cell_inactive); + } + + m_inst = cell ()->begin_touching (correct_box_overlapping (m_local_region_stack.back ())); + + m_inst_quad_id = 0; + + // skip instance quad if possible + if (! m_local_complex_region_stack.empty ()) { + skip_inst_iter_for_complex_region (); + } + + new_inst (receiver); +} + +void +RecursiveInstanceIterator::new_inst (RecursiveInstanceReceiver *receiver) const +{ + // look for the next instance with a non-empty array iterator. The array iterator can be empty because we + // use a lookup region. + while (! m_inst.at_end ()) { + + // skip instance quad if possible + if (! m_local_complex_region_stack.empty ()) { + skip_inst_iter_for_complex_region (); + if (m_inst.at_end ()) { + break; + } + } + + bool all_of_instance = false; + bool with_region = false; + + if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) { + with_region = true; + } else { + // TODO: optimization potential: only report all_of_instance == false, if not entirely within the complex region + all_of_instance = m_local_complex_region_stack.empty (); + } + + RecursiveInstanceReceiver::new_inst_mode ni = RecursiveInstanceReceiver::NI_all; + if (receiver) { + ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance); + } + + if (ni == RecursiveInstanceReceiver::NI_skip) { + m_inst_array = inst_array_iterator (); + } else if (ni == RecursiveInstanceReceiver::NI_single) { + // a singular iterator + m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false); + } else if (with_region) { + m_inst_array = m_inst->cell_inst ().begin_touching (correct_box_overlapping (m_local_region_stack.back ()), m_box_convert); + } else { + m_inst_array = m_inst->cell_inst ().begin (); + } + + set_all_of_instance (all_of_instance); + + new_inst_member (receiver); + + if (! m_inst_array.at_end ()) { + break; + } else { + ++m_inst; + } + + } +} + +void +RecursiveInstanceIterator::new_inst_member (RecursiveInstanceReceiver *receiver) const +{ + if (! m_local_complex_region_stack.empty ()) { + + // skip instance array members not part of the complex region + while (! m_inst_array.at_end ()) { + db::Box ia_box = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ()); + if (! is_outside_complex_region (ia_box)) { + break; + } else { + ++m_inst_array; + } + } + + } + + while (! m_inst_array.at_end () && receiver) { + if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) { + break; + } else { + ++m_inst_array; + } + } +} + +RecursiveInstanceIterator::box_type +RecursiveInstanceIterator::correct_box_overlapping (const box_type &box) const +{ + if (! m_overlapping) { + return box; + } else if (box.empty () || box == box_type::world ()) { + return box; + } else if (box.width () < 2 || box.height () < 2) { + return box; + } else { + return box.enlarged (box_type::vector_type (-1, -1)); + } +} + +bool +RecursiveInstanceIterator::is_outside_complex_region (const box_type &box) const +{ + if (m_overlapping) { + return m_local_complex_region_stack.back ().begin_overlapping (box, db::box_convert ()).at_end (); + } else { + return m_local_complex_region_stack.back ().begin_touching (box, db::box_convert ()).at_end (); + } +} + +bool +RecursiveInstanceIterator::is_child_inactive (db::cell_index_type new_child) const +{ + bool inactive = is_inactive (); + if (! m_start.empty () && m_start.find (new_child) != m_start.end ()) { + inactive = false; + } else if (! m_stop.empty () && m_stop.find (new_child) != m_stop.end ()) { + inactive = true; + } + return inactive; +} + +void +RecursiveInstanceIterator::push (RecursiveInstanceReceiver *receiver) +{ + // force reset so we can validate with a receiver + reset (); + + receiver->begin (this); + + try { + + validate (receiver); + + while (! at_end ()) { + next (receiver); + } + + receiver->end (this); + + } catch (...) { + + receiver->end (this); + throw; + + } +} + +} + diff --git a/src/db/db/dbRecursiveInstanceIterator.h b/src/db/db/dbRecursiveInstanceIterator.h new file mode 100644 index 000000000..8b2eabc50 --- /dev/null +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -0,0 +1,713 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbRecursiveInstanceIterator +#define HDR_dbRecursiveInstanceIterator + +#include "dbCommon.h" + +#include "dbLayout.h" +#include "dbInstElement.h" +#include "tlAssert.h" + +#include +#include +#include + +namespace db +{ + +class Region; +class RecursiveInstanceReceiver; + +/** + * @brief An iterator delivering shapes that touch or overlap the given region recursively + * + * The iterator can be constructed from a layout, a cell and a region. + * It simplifies retrieval of instances from a geometrical region while considering + * subcells as well. + * Some options can be specified, i.e. the level to which to look into or which cells + * to select. + * + * The general iteration scheme is iterating is depth-first and child instances before parent instances. + */ +class DB_PUBLIC RecursiveInstanceIterator +{ +public: + typedef db::Layout layout_type; + typedef db::Box box_type; + typedef db::Region region_type; + typedef db::Cell cell_type; + typedef db::Cell::touching_iterator inst_iterator; + typedef db::CellInstArray::iterator inst_array_iterator; + typedef db::Instances::overlapping_iterator overlapping_instance_iterator; + typedef db::Instances::touching_iterator touching_instance_iterator; + typedef db::Instance instance_type; + typedef db::InstElement instance_element_type; + typedef db::ICplxTrans cplx_trans_type; + typedef instance_element_type value_type; + typedef db::box_tree, 20, 20> box_tree_type; + + /** + * @brief Default constructor + */ + RecursiveInstanceIterator (); + + /** + * @brief Copy constructor + */ + RecursiveInstanceIterator (const RecursiveInstanceIterator &d); + + /** + * @brief Assignment + */ + RecursiveInstanceIterator &operator= (const RecursiveInstanceIterator &d); + + /** + * @brief Standard constructor + * + * @param layout The layout from which to get the cell hierarchy + * @param cell The starting cell + * @param region The region from which to select the instances + * @param overlapping Specify overlapping mode + * + * By default the iterator operates in touching mode - i.e. instances that touch the given region + * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers instances that + * overlap the given region by at least one database unit. + * The cell instances are selected according to their overall bounding box. + */ + RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type ®ion, bool overlapping = false); + + /** + * @brief Standard constructor + * + * @param layout The layout from which to get the cell hierarchy + * @param cell The starting cell + * @param region The complex region from which to select the shapes + * @param overlapping Specify overlapping mode + * + * By default the iterator operates in touching mode - i.e. instances that touch the given region + * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers instances that + * overlap the given region by at least one database unit. + * The cell instances are selected according to their overall bounding box. + * This version offers a complex search region instead of a simple box. + */ + RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type ®ion, bool overlapping = false); + + /** + * @brief Standard constructor for "overall" iteration + * + * This iterator delivers all instances recursively. + * + * @param layout The layout from which to get the cell hierarchy + * @param cell The starting cell + */ + RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell); + + /** + * @brief Destructor + */ + ~RecursiveInstanceIterator (); + + /** + * @brief Specify the maximum hierarchy depth to look into + * + * A depth of 0 instructs the iterator to deliver only instances from the initial cell. + * A higher depth instructs the iterator to look deeper. + * The depth must be specified before the instances are being retrieved. + */ + void max_depth (int depth) + { + if (m_max_depth != depth) { + m_max_depth = depth; + m_needs_reinit = true; + } + } + + /** + * @brief Gets the maximum hierarchy depth to search for + */ + int max_depth () const + { + return m_max_depth; + } + + /** + * @brief Specify the minimum hierarchy depth to look into + * + * A depth of 0 instructs the iterator to deliver instance from the top level and below. + * 1 instructs to deliver instance from the first child level. + * The minimum depth must be specified before the instances are being retrieved. + */ + void min_depth (int depth) + { + if (m_min_depth != depth) { + m_min_depth = depth; + m_needs_reinit = true; + } + } + + /** + * @brief Gets the minimum hierarchy depth to search for + */ + int min_depth () const + { + return m_min_depth; + } + + /** + * @brief Gets the layout + */ + const layout_type *layout () const + { + return mp_layout; + } + + /** + * @brief Gets the top cell + * + * The top cell is the cell with which the iterator was started + */ + const cell_type *top_cell () const + { + return mp_top_cell; + } + + /** + * @brief Gets the basic region the iterator is using (will be world if none is set) + * In addition to the basic region, a complex region may be defined that is further confining the + * search to a subregion of the basic region. + */ + const box_type ®ion () const + { + return m_region; + } + + /** + * @brief Returns true if a complex region is given + */ + bool has_complex_region () const + { + return mp_complex_region.get () != 0; + } + + /** + * @brief Gets the complex region the iterator is using + */ + const region_type &complex_region () const + { + tl_assert (mp_complex_region.get ()); + return *mp_complex_region; + } + + /** + * @brief Sets the region to a basic rectangle + * This will reset the iterator. + */ + void set_region (const box_type ®ion); + + /** + * @brief Sets a complex search region + * This will reset the iterator to the beginning. + */ + void set_region (const region_type ®ion); + + /** + * @brief Confines the search further to the given rectangle. + * This will reset the iterator and confine the search to the given rectangle + * in addition to any region or complex region already defined. + */ + void confine_region (const box_type ®ion); + + /** + * @brief Confines the search further to the given complex region. + * This will reset the iterator and confine the search to the given region + * in addition to any simple region or complex region already defined. + */ + void confine_region (const region_type ®ion); + + /** + * @brief Gets a flag indicating whether overlapping instances are selected when a region is used + */ + bool overlapping () const + { + return m_overlapping; + } + + /** + * @brief Sets a flag indicating whether overlapping instances are selected when a region is used + */ + void set_overlapping (bool f) + { + if (m_overlapping != f) { + m_overlapping = f; + m_needs_reinit = true; + } + } + + /** + * @brief Reset the iterator + */ + void reset () + { + m_needs_reinit = true; + } + + /** + * @brief Gets the selected target cells + * + * Only instances of cells in the targets set are reported. + * By default the iterator is configured to deliver all instances. + * By using "set_targets" with a set of cell indexes, the reporting + * can be confined to certain cells only. To enable all-cell reporting + * use "enable_all_targets". + * + * "all_targets_enabled" can be used to check which mode is used. + */ + const std::set &targets () const + { + return m_targets; + } + + /** + * @brief Gets a flags indicating whether all targets are selected + * See \targets for more details. + */ + bool all_targets_enabled () const + { + return m_all_targets; + } + + /** + * @brief Selects all target cells + * See \targets for more details. + */ + void enable_all_targets (); + + /** + * @brief Selects the given targets + * + * This will reset the "all_targets" flag to false. + * See \targets for more details. + */ + void set_targets (const std::set &set_targets); + + /** + * @brief Select cells + * + * Cell selection allows confining the hierarchy traversal to subtrees of the + * hierarchy tree. This happens by "selecting" and "unselecting" cells in the traversal path. + * "selected" cells will make iterator traverse the tree below this cell while + * "unselected" cells make the iterator ignore this cell. + * Cells which are neither selected nor unselected will be traversed depending + * on their parent's state. They are traversed if their parents are and are not traversed + * if their parents are not. + * + * If no specific cells have been selected before, this method will confine the selection + * to the given cells (plus their sub-hierarchy). + * If cells have been selected before, this will add the given cells to the selection. + */ + void select_cells (const std::set &cells); + + /** + * @brief Select all cells + * + * Makes all cells selected. After doing so, all unselect_cells calls + * will unselect only that specific cell without children. + * + * See \select_cells for more details. + */ + void select_all_cells (); + + /** + * @brief Unselect cells + * + * This method will remove the given cells (plus their sub-hierarchy) from the selection. + * + * See \select_cells for more details. + */ + void unselect_cells (const std::set &cells); + + /** + * @brief Unselect all cells + * + * Makes all cells unselected. After doing so, select_cells calls + * will select only that specific cell without children. + * + * See \select_cells for more details. + */ + void unselect_all_cells (); + + /** + * @brief Resets the selection + * + * This will reset all selections and unselections. + * After calling this methods, all select_cells will again select the cells + * including their children. + * + * See \select_cells for more details. + */ + void reset_selection (); + + /** + * @brief Returns the cells in the "enable" selection + * + * Cells in this set make the iterator become active, while cells in the + * disable selection make the iterator inactive. Only when active, the + * iterator will deliver shapes. + */ + const std::set &enables () const + { + return m_start; + } + + /** + * @brief Returns the cells in the "disable" selection + */ + const std::set &disables () const + { + return m_stop; + } + + /** + * @brief Get the current transformation by which the instances must be transformed into the initial cell + * + * The instances delivered are not transformed. Instead, this transformation must be applied to + * get the instance in the coordinate system of the top cell. + */ + const cplx_trans_type &trans () const + { + validate (0); + return m_trans; + } + + /** + * @brief Gets the current depth + * + * Returns the number of hierarchy levels we are below top level currently. + */ + unsigned int depth () const + { + validate (0); + return (unsigned int) m_trans_stack.size (); + } + + /** + * @brief Gets the current instance + * + * Returns the instance currently referred to by the recursive iterator. + * This instance is not transformed yet and is located in the current cell. + */ + instance_element_type instance () const + { + return *operator-> (); + } + + /** + * @brief Access operator + * + * The access operator is identical to the instance method. + */ + instance_element_type operator* () const + { + return *operator-> (); + } + + /** + * @brief Access (arrow) operator + * + * The access operator is identical to the instance method. + */ + const instance_element_type *operator-> () const; + + /** + * @brief End of iterator predicate + * + * Returns true, if the iterator is at the end of the sequence + */ + bool at_end () const; + + /** + * @brief Gets the current cell's index + */ + db::cell_index_type cell_index () const + { + return cell ()->cell_index (); + } + + /** + * @brief Gets the current cell's reference + */ + const cell_type *cell () const + { + validate (0); + size_t c = reinterpret_cast (mp_cell); + return reinterpret_cast (c - (c & size_t (3))); + } + + /** + * @brief Increments the iterator (operator version) + */ + RecursiveInstanceIterator &operator++() + { + next (0); + return *this; + } + + /** + * @brief Increments the iterator + */ + void next () + { + next (0); + } + + /** + * @brief Comparison of iterators - equality + */ + bool operator==(const RecursiveInstanceIterator &d) const + { + if (at_end () != d.at_end ()) { + return false; + } else if (at_end ()) { + return true; + } else { + return (*m_inst == *d.m_inst); + } + } + + /** + * @brief Comparison of iterators - inequality + */ + bool operator!=(const RecursiveInstanceIterator &d) const + { + return !operator==(d); + } + + /** + * @brief The instance path + */ + std::vector path () const; + + /** + * @brief Push-mode delivery + * + * This method will deliver all instances to the given receiver. + * In contrast to pull mode, this method allows tailoring the + * traversal of the hierarchy tree during iteration. + * For this purpose, the receiver has methods that receive + * events and to some extend may modify the traversal (e.g. + * return value of enter_cell). + * + * See RecursiveInstanceReceiver class for more details. + */ + void push (RecursiveInstanceReceiver *receiver); + + /** + * @brief Returns a value indicating whether the current cell is inactive (disabled) + */ + bool is_inactive () const + { + return (reinterpret_cast (mp_cell) & size_t (1)) != 0; + } + + /** + * @brief Returns a value indicating whether a new child cell of the current cell will be inactive + */ + bool is_child_inactive (db::cell_index_type new_child) const; + +private: + int m_max_depth; + int m_min_depth; + bool m_overlapping; + std::set m_start, m_stop; + std::set m_targets; + bool m_all_targets; + + const layout_type *mp_layout; + const cell_type *mp_top_cell; + + box_type m_region; + std::unique_ptr mp_complex_region; + db::box_convert m_box_convert; + + mutable inst_iterator m_inst; + mutable inst_array_iterator m_inst_array; + mutable instance_element_type m_combined_instance; + mutable std::map m_empty_cells_cache; + mutable const cell_type *mp_cell; + mutable cplx_trans_type m_trans; + mutable std::vector m_trans_stack; + mutable std::vector m_inst_iterators; + mutable std::vector m_inst_array_iterators; + mutable std::vector m_cells; + mutable std::vector m_local_complex_region_stack; + mutable std::vector m_local_region_stack; + mutable bool m_needs_reinit; + mutable size_t m_inst_quad_id; + mutable std::vector m_inst_quad_id_stack; + mutable std::set m_target_tree; + + void init (); + void init_region (const region_type ®ion); + void init_region (const box_type ®ion); + void skip_inst_iter_for_complex_region () const; + void validate (RecursiveInstanceReceiver *receiver) const; + void next (RecursiveInstanceReceiver *receiver); + bool needs_visit () const; + void next_instance (RecursiveInstanceReceiver *receiver) const; + void new_inst (RecursiveInstanceReceiver *receiver) const; + void new_inst_member (RecursiveInstanceReceiver *receiver) const; + void new_cell (RecursiveInstanceReceiver *receiver) const; + void up (RecursiveInstanceReceiver *receiver) const; + void down (RecursiveInstanceReceiver *receiver) const; + + bool is_outside_complex_region (const box_type &box) const; + box_type correct_box_overlapping (const box_type &box) const; + + void set_inactive (bool a) const + { + size_t c = reinterpret_cast (mp_cell); + c -= (c & size_t (1)); + mp_cell = reinterpret_cast (c + (a ? 1 : 0)); + } + + bool is_all_of_instance () const + { + return (reinterpret_cast (mp_cell) & size_t (2)) != 0; + } + + void set_all_of_instance (bool a) const + { + size_t c = reinterpret_cast (mp_cell); + c -= (c & size_t (2)); + mp_cell = reinterpret_cast (c + (a ? 2 : 0)); + } +}; + +/** + * @brief A receiver interface for "push" mode + * + * In push mode, the iterator will deliver the instances and hierarchy transitions + * to this interface. See "RecursiveInstanceIterator::push" for details about this + * mode. + * + * The receiver receives events for the start of the delivery, on each cell + * entry and on each instance (followed by a cell entry). + */ +class DB_PUBLIC RecursiveInstanceReceiver +{ +public: + typedef RecursiveInstanceIterator::box_tree_type box_tree_type; + + /** + * @brief See new_inst for details. + */ + enum new_inst_mode { NI_all = 0, NI_single = 1, NI_skip = 2 }; + + /** + * @brief Constructor + */ + RecursiveInstanceReceiver () { } + + /** + * @brief Destructor + */ + virtual ~RecursiveInstanceReceiver () { } + + /** + * @brief Called once when the iterator begins pushing + */ + virtual void begin (const RecursiveInstanceIterator * /*iter*/) { } + + /** + * @brief Called once after the iterator pushed everything + */ + virtual void end (const RecursiveInstanceIterator * /*iter*/) { } + + /** + * @brief Enters a cell + * + * This method is called when the recursive shape iterator + * enters a new cell. It is not called for the top cell. When it is called, "iter->trans()" + * will already be updated. + * + * @param iter The iterator + * @param cell The cell which is entered + * @param region The clip box as seen from "cell" or db::Box::world if there is no clip box + * @param complex_region A complex clip region if one is supplied together with "region" + */ + virtual void enter_cell (const RecursiveInstanceIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { } + + /** + * @brief Leaves the current cell + * + * This method is the counterpart for "enter_cell". It is called when traversal of "cell" ended. + */ + virtual void leave_cell (const RecursiveInstanceIterator * /*iter*/, const db::Cell * /*cell*/) { } + + /** + * @brief Enters a new instance + * + * This method is called before "enter_cell" and "new_inst_member" is called and will indicate the instance to follow. + * The sequence of events is + * + * new_inst(A) + * new_inst_member(A[0,0]) + * enter_cell(A) + * ... + * leave_cell(A) + * new_inst_member(A[1,0]) + * enter_cell(A) + * ... + * leave_cell(A) + * ... + * new_inst(B) + * ... + * + * The "all" parameter is true, if all instances of the array will be addressed. + * + * This method can return the following values: + * - NI_all: iterate all members through "new_inst_member" + * - NI_single: iterate a single member (the first one) + * - NI_skip: skips the whole array (not a single instance is iterated) + */ + virtual new_inst_mode new_inst (const RecursiveInstanceIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; } + + /** + * @brief Enters a new array member of the instance + * + * See "new_inst" for a description. This method adds the "trans" parameter + * which holds the complex transformation for this particular instance of + * the array. + * + * "all" is true, if an instance array is iterated in "all" mode (see new_inst). + * + * If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered. + */ + virtual bool new_inst_member (const RecursiveInstanceIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; } +}; + +} // namespace db + +#endif diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index 72f8742c7..605fb1671 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -263,15 +263,15 @@ Region::rounded_corners (double rinner, double router, unsigned int n) const } void -Region::smooth (coord_type d) +Region::smooth (coord_type d, bool keep_hv) { - process (SmoothingProcessor (d)); + process (SmoothingProcessor (d, keep_hv)); } Region -Region::smoothed (coord_type d) const +Region::smoothed (coord_type d, bool keep_hv) const { - return processed (SmoothingProcessor (d)); + return processed (SmoothingProcessor (d, keep_hv)); } void diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 3ee137c7c..b05e04184 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1518,14 +1518,14 @@ public: /** * @brief Smoothes the region (in-place) */ - void smooth (coord_type d); + void smooth (coord_type d, bool keep_hv); /** * @brief Returns the smoothed region * * @param d The smoothing accuracy */ - Region smoothed (coord_type d) const; + Region smoothed (coord_type d, bool keep_hv) const; /** * @brief Returns the nth polygon diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index a1eacf9f7..9f0e6f513 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -614,6 +614,34 @@ RectilinearFilter::vars () const return 0; } +// ------------------------------------------------------------------------------------- +// HoleCountFilter implementation + +HoleCountFilter::HoleCountFilter (size_t min_count, size_t max_count, bool inverse) + : m_min_count (min_count), m_max_count (max_count), m_inverse (inverse) +{ + // .. nothing yet .. +} + +bool +HoleCountFilter::selected (const db::Polygon &poly) const +{ + bool ok = poly.holes () < m_max_count && poly.holes () >= m_min_count; + return ok != m_inverse; +} + +bool +HoleCountFilter::selected (const db::PolygonRef &poly) const +{ + bool ok = poly.obj ().holes () < m_max_count && poly.obj ().holes () >= m_min_count; + return ok != m_inverse; +} + +const TransformationReducer *HoleCountFilter::vars () const +{ + return 0; +} + // ------------------------------------------------------------------------------------- // RectilinearFilter implementation @@ -840,14 +868,14 @@ StrangePolygonCheckProcessor::process (const db::Polygon &poly, std::vector &res) const { - res.push_back (db::smooth (poly, m_d)); + res.push_back (db::smooth (poly, m_d, m_keep_hv)); } // ------------------------------------------------------------------------------------------------------------- diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 28ce19f67..f1da9196d 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -286,6 +286,51 @@ private: bool m_inverse; }; +/** + * @brief Filters by number of holes + * + * This filter will select all polygons with a hole count between min_holes and max_holes (exclusively) + */ + +struct DB_PUBLIC HoleCountFilter + : public AllMustMatchFilter +{ + /** + * @brief Constructor + * @param inverse If set to true, only polygons not matching this criterion will be filtered + */ + HoleCountFilter (size_t min_count, size_t max_count, bool inverse); + + /** + * @brief Returns true if the polygon is a rectangle + */ + virtual bool selected (const db::Polygon &poly) const; + + /** + * @brief Returns true if the polygon is a rectangle + */ + virtual bool selected (const db::PolygonRef &poly) const; + + /** + * @brief This filter does not need variants + */ + virtual const TransformationReducer *vars () const; + + /** + * @brief This filter prefers producing variants + */ + virtual bool wants_variants () const { return true; } + + /** + * @brief This filter wants merged input + */ + virtual bool requires_raw_input () const { return false; } + +private: + size_t m_min_count, m_max_count; + bool m_inverse; +}; + /** * @brief A bounding box filter for use with Region::filter or Region::filtered * @@ -459,7 +504,7 @@ class DB_PUBLIC SmoothingProcessor : public PolygonProcessorBase { public: - SmoothingProcessor (db::Coord d); + SmoothingProcessor (db::Coord d, bool keep_hv); ~SmoothingProcessor (); virtual void process (const db::Polygon &poly, std::vector &res) const; @@ -472,6 +517,7 @@ public: private: db::Coord m_d; + bool m_keep_hv; db::MagnificationReducer m_vars; }; diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index e11e5c2b8..de891d776 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -38,6 +38,8 @@ #include "dbCellMapping.h" #include "dbPCellDeclaration.h" #include "dbSaveLayoutOptions.h" +#include "dbRecursiveShapeIterator.h" +#include "dbRecursiveInstanceIterator.h" #include "dbWriter.h" #include "dbHash.h" #include "tlStream.h" @@ -1204,6 +1206,56 @@ begin_shapes_rec_overlapping_um (const db::Cell *cell, unsigned int layer, db::D return db::RecursiveShapeIterator (*layout, *cell, layer, db::CplxTrans (layout->dbu ()).inverted () * region, true); } +static db::RecursiveInstanceIterator +begin_instances_rec (const db::Cell *cell) +{ + const db::Layout *layout = cell->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell is not inside layout"))); + } + return db::RecursiveInstanceIterator (*layout, *cell); +} + +static db::RecursiveInstanceIterator +begin_instances_rec_touching (const db::Cell *cell, db::Box region) +{ + const db::Layout *layout = cell->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell is not inside layout"))); + } + return db::RecursiveInstanceIterator (*layout, *cell, region, false); +} + +static db::RecursiveInstanceIterator +begin_instances_rec_touching_um (const db::Cell *cell, db::DBox region) +{ + const db::Layout *layout = cell->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell is not inside layout"))); + } + return db::RecursiveInstanceIterator (*layout, *cell, db::CplxTrans (layout->dbu ()).inverted () * region, false); +} + +static db::RecursiveInstanceIterator +begin_instances_rec_overlapping (const db::Cell *cell, db::Box region) +{ + const db::Layout *layout = cell->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell is not inside layout"))); + } + return db::RecursiveInstanceIterator (*layout, *cell, region, true); +} + +static db::RecursiveInstanceIterator +begin_instances_rec_overlapping_um (const db::Cell *cell, db::DBox region) +{ + const db::Layout *layout = cell->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell is not inside layout"))); + } + return db::RecursiveInstanceIterator (*layout, *cell, db::CplxTrans (layout->dbu ()).inverted () * region, true); +} + static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::LayerMapping &layer_mapping) { cell->copy_shapes (source_cell, layer_mapping); @@ -1833,6 +1885,54 @@ Class decl_Cell ("db", "Cell", "\n" "This variant has been added in version 0.25.\n" ) + + gsi::method_ext ("begin_instances_rec", &begin_instances_rec, + "@brief Delivers a recursive instance iterator for the instances below the cell\n" + "@return A suitable iterator\n" + "\n" + "For details see the description of the \\RecursiveInstanceIterator class.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + + gsi::method_ext ("begin_instances_rec_touching", &begin_instances_rec_touching, gsi::arg ("region"), + "@brief Delivers a recursive instance iterator for the instances below the cell\n" + "@param region The search region\n" + "@return A suitable iterator\n" + "\n" + "For details see the description of the \\RecursiveInstanceIterator class.\n" + "This version gives an iterator delivering instances whose bounding box touches the given region.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + + gsi::method_ext ("begin_instances_rec_touching", &begin_instances_rec_touching_um, gsi::arg ("region"), + "@brief Delivers a recursive instance iterator for the instances below the cell using a region search, with the region given in micrometer units\n" + "@param region The search region as \\DBox object in micrometer units\n" + "@return A suitable iterator\n" + "\n" + "For details see the description of the \\RecursiveInstanceIterator class.\n" + "This version gives an iterator delivering instances whose bounding box touches the given region.\n" + "\n" + "This variant has been added in version 0.27.\n" + ) + + gsi::method_ext ("begin_instances_rec_overlapping", &begin_instances_rec_overlapping, gsi::arg ("region"), + "@brief Delivers a recursive instance iterator for the instances below the cell using a region search\n" + "@param region The search region\n" + "@return A suitable iterator\n" + "\n" + "For details see the description of the \\RecursiveInstanceIterator class.\n" + "This version gives an iterator delivering instances whose bounding box overlaps the given region.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + + gsi::method_ext ("begin_instances_rec_overlapping", &begin_instances_rec_overlapping_um, gsi::arg ("region"), + "@brief Delivers a recursive instance iterator for the instances below the cell using a region search, with the region given in micrometer units\n" + "@param region The search region as \\DBox object in micrometer units\n" + "@return A suitable iterator\n" + "\n" + "For details see the description of the \\RecursiveInstanceIterator class.\n" + "This version gives an iterator delivering instances whose bounding box overlaps the given region.\n" + "\n" + "This variant has been added in version 0.27.\n" + ) + gsi::method_ext ("copy_shapes", ©_shapes1, gsi::arg ("source_cell"), "@brief Copies the shapes from the given cell into this cell\n" "@param source_cell The cell from where to copy shapes\n" diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index 90ad2447b..e9699eed7 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -185,10 +185,10 @@ static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::Compoun return new db::CompoundRegionProcessingOperationNode (new db::StrangePolygonCheckProcessor (), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d) +static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d, bool keep_hv) { check_non_null (input, "input"); - return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/, d); + return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d, keep_hv), input, true /*processor is owned*/, d); } static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n) @@ -466,6 +466,12 @@ static db::CompoundRegionOperationNode *new_perimeter_sum_filter (db::CompoundRe return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true, true /*sum of set*/); } +static db::CompoundRegionOperationNode *new_hole_count_filter (db::CompoundRegionOperationNode *input, bool inverse, size_t hmin, size_t hmax) +{ + check_non_null (input, "input"); + return new db::CompoundRegionFilterOperationNode (new db::HoleCountFilter (hmin, hmax, inverse), input, true); +} + static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits::area_type amin, db::coord_traits::area_type amax) { check_non_null (input, "input"); @@ -566,9 +572,10 @@ Class decl_CompoundRegionOperationNode ("db", " "@brief Creates a node extracting strange polygons.\n" "'strange polygons' are ones which cannot be oriented - e.g. '8' shape polygons." ) + - gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"), + gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("keep_hv", false), "@brief Creates a node smoothing the polygons.\n" - "@param d The tolerance to be applied for the smoothing." + "@param d The tolerance to be applied for the smoothing.\n" + "@param keep_hv If true, horizontal and vertical edges are maintained.\n" ) + gsi::constructor ("new_rounded_corners", &new_rounded_corners, gsi::arg ("input"), gsi::arg ("rinner"), gsi::arg ("router"), gsi::arg ("n"), "@brief Creates a node generating rounded corners.\n" @@ -672,6 +679,11 @@ Class decl_CompoundRegionOperationNode ("db", " "@brief Creates a node filtering the input by area sum.\n" "Like \\new_area_filter, but applies to the sum of all shapes in the current set.\n" ) + + gsi::constructor ("new_hole_count_filter", &new_hole_count_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("hmin", 0), gsi::arg ("hmax", std::numeric_limits::max (), "max"), + "@brief Creates a node filtering the input by number of holes per polygon.\n" + "This node renders the input if the hole count is between hmin and hmax (exclusively). If 'inverse' is set to true, the " + "input shape is returned if the hole count is less than hmin (exclusively) or larger than hmax (inclusively)." + ) + gsi::constructor ("new_bbox_filter", &new_bbox_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits::area_type>::max (), "max"), "@brief Creates a node filtering the input by bounding box parameters.\n" "This node renders the input if the specified bounding box parameter of the input shape is between pmin and pmax (exclusively). If 'inverse' is set to true, the " diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index d08a06a2d..b950970b5 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -1716,9 +1716,11 @@ Class decl_Layout ("db", "Layout", "For details see the description of the \\RecursiveShapeIterator class.\n" "This version is convenience overload which takes a cell object instead of a cell index.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec instead.\n" + "\n" "This method has been added in version 0.24.\n" ) + - gsi::method_ext ("begin_shapes", &begin_shapes, gsi::arg ("cell_index"), gsi::arg ("layer"), + gsi::method_ext ("#begin_shapes", &begin_shapes, gsi::arg ("cell_index"), gsi::arg ("layer"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer\n" "@param cell_index The index of the initial (top) cell\n" "@param layer The layer from which to get the shapes\n" @@ -1726,9 +1728,11 @@ Class decl_Layout ("db", "Layout", "\n" "For details see the description of the \\RecursiveShapeIterator class.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec instead.\n" + "\n" "This method has been added in version 0.18.\n" ) + - gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n" "@param cell_index The index of the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1738,9 +1742,11 @@ Class decl_Layout ("db", "Layout", "For details see the description of the \\RecursiveShapeIterator class.\n" "This version gives an iterator delivering shapes whose bounding box touches the given region.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n" + "\n" "This method has been added in version 0.18.\n" ) + - gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching2, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching2, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n" "@param cell The cell object for the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1751,9 +1757,11 @@ Class decl_Layout ("db", "Layout", "This version gives an iterator delivering shapes whose bounding box touches the given region.\n" "It is convenience overload which takes a cell object instead of a cell index.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n" + "\n" "This method has been added in version 0.24.\n" ) + - gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n" "@param cell_index The index of the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1763,9 +1771,11 @@ Class decl_Layout ("db", "Layout", "For details see the description of the \\RecursiveShapeIterator class.\n" "This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n" + "\n" "This method has been added in version 0.18.\n" ) + - gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping2, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping2, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n" "@param cell The cell object for the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1776,9 +1786,11 @@ Class decl_Layout ("db", "Layout", "This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n" "It is convenience overload which takes a cell object instead of a cell index.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n" + "\n" "This method has been added in version 0.24.\n" ) + - gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n" "@param cell_index The index of the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1788,9 +1800,11 @@ Class decl_Layout ("db", "Layout", "For details see the description of the \\RecursiveShapeIterator class.\n" "This version gives an iterator delivering shapes whose bounding box touches the given region.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n" + "\n" "This variant has been added in version 0.25.\n" ) + - gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n" "@param cell The cell object for the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1801,9 +1815,11 @@ Class decl_Layout ("db", "Layout", "This version gives an iterator delivering shapes whose bounding box touches the given region.\n" "It is convenience overload which takes a cell object instead of a cell index.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n" + "\n" "This variant has been added in version 0.25.\n" ) + - gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n" "@param cell_index The index of the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1813,9 +1829,11 @@ Class decl_Layout ("db", "Layout", "For details see the description of the \\RecursiveShapeIterator class.\n" "This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n" + "\n" "This variant has been added in version 0.25.\n" ) + - gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), + gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n" "@param cell The cell object for the starting cell\n" "@param layer The layer from which to get the shapes\n" @@ -1826,6 +1844,8 @@ Class decl_Layout ("db", "Layout", "This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n" "It is convenience overload which takes a cell object instead of a cell index.\n" "\n" + "This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n" + "\n" "This variant has been added in version 0.25.\n" ) + gsi::method_ext ("#write", &write_options2, gsi::arg ("filename"), gsi::arg ("gzip"), gsi::arg ("options"), diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index 76f3315c9..c597112f5 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -1602,9 +1602,9 @@ static db::Polygon transformed_icplx_dp (const db::Polygon *p, const db::ICplxTr return p->transformed (t, false /*don't compress*/); } -static db::Polygon smooth (const db::Polygon *p, db::Coord d) +static db::Polygon smooth (const db::Polygon *p, db::Coord d, bool keep_hv) { - return db::smooth (*p, d); + return db::smooth (*p, d, keep_hv); } static db::Polygon minkowsky_sum_pe (const db::Polygon *p, const db::Edge &e, bool rh) @@ -1787,17 +1787,18 @@ Class decl_Polygon ("db", "Polygon", "\n" "This method was introduced in version 0.22.\n" ) + - method_ext ("smooth", &smooth, gsi::arg ("d"), + method_ext ("smooth", &smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false), "@brief Smoothes a polygon\n" "\n" "Remove vertices that deviate by more than the distance d from the average contour.\n" "The value d is basically the roughness which is removed.\n" "\n" "@param d The smoothing \"roughness\".\n" + "@param keep_hv If true, horizontal and vertical edges will be preserved always.\n" "\n" "@return The smoothed polygon.\n" "\n" - "This method was introduced in version 0.23.\n" + "This method was introduced in version 0.23. The 'keep_hv' optional parameter was added in version 0.27.\n" ) + method_ext ("minkowsky_sum", &minkowsky_sum_pe, gsi::arg ("e"), gsi::arg ("resolve_holes"), "@brief Computes the Minkowsky sum of the polygon and an edge\n" diff --git a/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc b/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc new file mode 100644 index 000000000..3a2fdf2df --- /dev/null +++ b/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc @@ -0,0 +1,558 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "gsiDecl.h" +#include "dbRecursiveInstanceIterator.h" +#include "dbRegion.h" + +#include "tlGlobPattern.h" + +namespace gsi +{ + +// --------------------------------------------------------------- +// db::RecursiveInstanceIterator binding + +static db::RecursiveInstanceIterator *new_si1 (const db::Layout &layout, const db::Cell &cell) +{ + return new db::RecursiveInstanceIterator (layout, cell); +} + +static db::RecursiveInstanceIterator *new_si2 (const db::Layout &layout, const db::Cell &cell, const db::Box &box, bool overlapping) +{ + return new db::RecursiveInstanceIterator (layout, cell, box, overlapping); +} + +static db::RecursiveInstanceIterator *new_si2a (const db::Layout &layout, const db::Cell &cell, const db::Region ®ion, bool overlapping) +{ + return new db::RecursiveInstanceIterator (layout, cell, region, overlapping); +} + +static db::DCplxTrans si_dtrans (const db::RecursiveInstanceIterator *r) +{ + const db::Layout *ly = r->layout (); + tl_assert (ly != 0); + return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ()); +} + +static void set_targets1 (db::RecursiveInstanceIterator *r, const std::vector &cells) +{ + std::set cc; + cc.insert (cells.begin (), cells.end ()); + r->set_targets (cc); +} + +static db::DCplxTrans inst_dtrans (const db::RecursiveInstanceIterator *r) +{ + const db::Layout *ly = r->layout (); + tl_assert (ly != 0); + return db::CplxTrans (ly->dbu ()) * (*r)->complex_trans () * db::VCplxTrans (1.0 / ly->dbu ()); +} + +static db::ICplxTrans inst_trans (const db::RecursiveInstanceIterator *r) +{ + return (*r)->complex_trans (); +} + +static db::Cell *inst_cell (const db::RecursiveInstanceIterator *r) +{ + const db::Layout *ly = r->layout (); + tl_assert (ly != 0); + return const_cast (&ly->cell ((*r)->inst_ptr.cell_index ())); +} + +static void set_targets2 (db::RecursiveInstanceIterator *r, const std::string &pattern) +{ + tl::GlobPattern p (pattern); + std::set cc; + for (db::Layout::const_iterator ci = r->layout ()->begin (); ci != r->layout ()->end (); ++ci) { + if (p.match (r->layout ()->cell_name (ci->cell_index ()))) { + cc.insert (ci->cell_index ()); + } + } + + r->set_targets (cc); +} + +static void select_cells1 (db::RecursiveInstanceIterator *r, const std::vector &cells) +{ + std::set cc; + cc.insert (cells.begin (), cells.end ()); + r->select_cells (cc); +} + +static void select_cells2 (db::RecursiveInstanceIterator *r, const std::string &pattern) +{ + tl::GlobPattern p (pattern); + std::set cc; + for (db::Layout::const_iterator ci = r->layout ()->begin (); ci != r->layout ()->end (); ++ci) { + if (p.match (r->layout ()->cell_name (ci->cell_index ()))) { + cc.insert (ci->cell_index ()); + } + } + + r->select_cells (cc); +} + +static void unselect_cells1 (db::RecursiveInstanceIterator *r, const std::vector &cells) +{ + std::set cc; + cc.insert (cells.begin (), cells.end ()); + r->unselect_cells (cc); +} + +static void unselect_cells2 (db::RecursiveInstanceIterator *r, const std::string &pattern) +{ + tl::GlobPattern p (pattern); + std::set cc; + for (db::Layout::const_iterator ci = r->layout ()->begin (); ci != r->layout ()->end (); ++ci) { + if (p.match (r->layout ()->cell_name (ci->cell_index ()))) { + cc.insert (ci->cell_index ()); + } + } + + r->unselect_cells (cc); +} + +static db::Region complex_region (const db::RecursiveInstanceIterator *iter) +{ + if (iter->has_complex_region ()) { + return iter->complex_region (); + } else { + return db::Region (iter->region ()); + } +} + +Class decl_RecursiveInstanceIterator ("db", "RecursiveInstanceIterator", + gsi::constructor ("new", &new_si1, gsi::arg ("layout"), gsi::arg ("cell"), + "@brief Creates a recursive instance iterator.\n" + "@param layout The layout which shall be iterated\n" + "@param cell The initial cell which shall be iterated (including its children)\n" + "@param layer The layer (index) from which the shapes are taken\n" + "\n" + "This constructor creates a new recursive instance iterator which delivers the instances of " + "the given cell plus its children.\n" + ) + + gsi::constructor ("new", &new_si2, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("box"), gsi::arg ("overlapping", false), + "@brief Creates a recursive instance iterator with a search region.\n" + "@param layout The layout which shall be iterated\n" + "@param cell The initial cell which shall be iterated (including its children)\n" + "@param box The search region\n" + "@param overlapping If set to true, instances overlapping the search region are reported, otherwise touching is sufficient\n" + "\n" + "This constructor creates a new recursive instance iterator which delivers the instances of " + "the given cell plus its children.\n" + "\n" + "The search is confined to the region given by the \"box\" parameter. If \"overlapping\" is true, instances whose " + "bounding box is overlapping the search region are reported. If \"overlapping\" is false, instances whose " + "bounding box touches the search region are reported. The bounding box of instances is measured taking all layers " + "of the target cell into account.\n" + ) + + gsi::constructor ("new", &new_si2a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("region"), gsi::arg ("overlapping"), + "@brief Creates a recursive instance iterator with a search region.\n" + "@param layout The layout which shall be iterated\n" + "@param cell The initial cell which shall be iterated (including its children)\n" + "@param region The search region\n" + "@param overlapping If set to true, instances overlapping the search region are reported, otherwise touching is sufficient\n" + "\n" + "This constructor creates a new recursive instance iterator which delivers the instances of " + "the given cell plus its children.\n" + "\n" + "The search is confined to the region given by the \"region\" parameter. The region needs to be a rectilinear region.\n" + "If \"overlapping\" is true, instances whose " + "bounding box is overlapping the search region are reported. If \"overlapping\" is false, instances whose " + "bounding box touches the search region are reported. The bounding box of instances is measured taking all layers " + "of the target cell into account.\n" + ) + + gsi::method ("max_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::max_depth, gsi::arg ("depth"), + "@brief Specifies the maximum hierarchy depth to look into\n" + "\n" + "A depth of 0 instructs the iterator to deliver only instances from the initial cell.\n" + "A higher depth instructs the iterator to look deeper.\n" + "The depth must be specified before the instances are being retrieved.\n" + ) + + gsi::method ("max_depth", (int (db::RecursiveInstanceIterator::*) () const) &db::RecursiveInstanceIterator::max_depth, + "@brief Gets the maximum hierarchy depth\n" + "\n" + "See \\max_depth= for a description of that attribute.\n" + ) + + gsi::method ("min_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::min_depth, gsi::arg ("depth"), + "@brief Specifies the minimum hierarchy depth to look into\n" + "\n" + "A depth of 0 instructs the iterator to deliver instances from the top level.\n" + "1 instructs to deliver instances from the first child level.\n" + "The minimum depth must be specified before the instances are being retrieved.\n" + ) + + gsi::method ("min_depth", (int (db::RecursiveInstanceIterator::*) () const) &db::RecursiveInstanceIterator::min_depth, + "@brief Gets the minimum hierarchy depth\n" + "\n" + "See \\min_depth= for a description of that attribute.\n" + ) + + gsi::method ("reset", &db::RecursiveInstanceIterator::reset, + "@brief Resets the iterator to the initial state\n" + ) + + gsi::method ("reset_selection", &db::RecursiveInstanceIterator::reset_selection, + "@brief Resets the selection to the default state\n" + "\n" + "In the initial state, the top cell and its children are selected. Child cells can be switched on and off " + "together with their sub-hierarchy using \\select_cells and \\unselect_cells.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method ("layout", &db::RecursiveInstanceIterator::layout, + "@brief Gets the layout this iterator is connected to\n" + ) + + gsi::method ("top_cell", &db::RecursiveInstanceIterator::top_cell, + "@brief Gets the top cell this iterator is connected to\n" + ) + + gsi::method ("region", &db::RecursiveInstanceIterator::region, + "@brief Gets the basic region that is iterator is using\n" + "The basic region is the overall box the region iterator iterates over. " + "There may be an additional complex region that confines the region iterator. " + "See \\complex_region for this attribute.\n" + ) + + gsi::method_ext ("complex_region", &complex_region, + "@brief Gets the complex region that is iterator is using\n" + "The complex region is the effective region (a \\Region object) that the " + "iterator is selecting from the layout. This region can be a single box " + "or a complex region.\n" + ) + + gsi::method ("region=", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::box_type &)) &db::RecursiveInstanceIterator::set_region, gsi::arg ("box_region"), + "@brief Sets the rectangular region that is iterator is iterating over\n" + "See \\region for a description of this attribute.\n" + "Setting a simple region will reset the complex region to a rectangle and reset the iterator to " + "the beginning of the sequence." + ) + + gsi::method ("region=", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::region_type &)) &db::RecursiveInstanceIterator::set_region, gsi::arg ("complex_region"), + "@brief Sets the complex region that is iterator is using\n" + "See \\complex_region for a description of this attribute. Setting the complex region will " + "reset the basic region (see \\region) to the bounding box of the complex region and " + "reset the iterator to the beginning of the sequence.\n" + ) + + gsi::method ("confine_region", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::box_type &)) &db::RecursiveInstanceIterator::confine_region, gsi::arg ("box_region"), + "@brief Confines the region that is iterator is iterating over\n" + "This method is similar to setting the region (see \\region=), but will confine any region (complex or simple) already set. " + "Essentially it does a logical AND operation between the existing and given region. " + "Hence this method can only reduce a region, not extend it.\n" + ) + + gsi::method ("confine_region", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::region_type &)) &db::RecursiveInstanceIterator::confine_region, gsi::arg ("complex_region"), + "@brief Confines the region that is iterator is iterating over\n" + "This method is similar to setting the region (see \\region=), but will confine any region (complex or simple) already set. " + "Essentially it does a logical AND operation between the existing and given region. " + "Hence this method can only reduce a region, not extend it.\n" + ) + + gsi::method ("overlapping?", &db::RecursiveInstanceIterator::overlapping, + "@brief Gets a flag indicating whether overlapping instances are selected when a region is used\n" + ) + + gsi::method ("overlapping=", &db::RecursiveInstanceIterator::set_overlapping, gsi::arg ("region"), + "@brief Sets a flag indicating whether overlapping instances are selected when a region is used\n" + "\n" + "If this flag is false, instances touching the search region are returned.\n" + ) + + gsi::method ("unselect_all_cells", &db::RecursiveInstanceIterator::unselect_all_cells, + "@brief Unselects all cells.\n" + "\n" + "This method will set the \"unselected\" mark on all cells. The effect is " + "that subsequent calls of \\select_cells will select only the specified cells, not " + "their children, because they are still unselected.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method ("select_all_cells", &db::RecursiveInstanceIterator::select_all_cells, + "@brief Selects all cells.\n" + "\n" + "This method will set the \"selected\" mark on all cells. The effect is " + "that subsequent calls of \\unselect_cells will unselect only the specified cells, not " + "their children, because they are still unselected.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method_ext ("unselect_cells", &unselect_cells1, gsi::arg ("cells"), + "@brief Unselects the given cells.\n" + "\n" + "This method will sets the \"unselected\" mark on the given cells. " + "That means that these cells or their child cells will not be visited, unless " + "they are marked as \"selected\" again with the \\select_cells method.\n" + "\n" + "The cells are given as a list of cell indexes.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method_ext ("unselect_cells", &unselect_cells2, gsi::arg ("cells"), + "@brief Unselects the given cells.\n" + "\n" + "This method will sets the \"unselected\" mark on the given cells. " + "That means that these cells or their child cells will not be visited, unless " + "they are marked as \"selected\" again with the \\select_cells method.\n" + "\n" + "The cells are given as a glob pattern.\n" + "A glob pattern follows the syntax of " + "file names on the shell (i.e. \"A*\" are all cells starting with a letter \"A\").\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method_ext ("select_cells", &select_cells1, gsi::arg ("cells"), + "@brief Unselects the given cells.\n" + "\n" + "This method will sets the \"selected\" mark on the given cells. " + "That means that these cells or their child cells are visited, unless " + "they are marked as \"unselected\" again with the \\unselect_cells method.\n" + "\n" + "The cells are given as a list of cell indexes.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method_ext ("select_cells", &select_cells2, gsi::arg ("cells"), + "@brief Unselects the given cells.\n" + "\n" + "This method will sets the \"selected\" mark on the given cells. " + "That means that these cells or their child cells are visited, unless " + "they are marked as \"unselected\" again with the \\unselect_cells method.\n" + "\n" + "The cells are given as a glob pattern.\n" + "A glob pattern follows the syntax of " + "file names on the shell (i.e. \"A*\" are all cells starting with a letter \"A\").\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method_ext ("targets=", &set_targets1, gsi::arg ("cells"), + "@brief Specifies the target cells.\n" + "\n" + "If target cells are specified, only instances of these cells are delivered. " + "This version takes a list of cell indexes for the targets. " + "By default, no target cell list is present and the instances of all cells " + "are delivered by the iterator. See \\all_targets_enabled? and \\enable_all_targets for " + "a description of this mode. Once a target list is specified, the iteration is " + "confined to the cells from this list." + "\n" + "The cells are given as a list of cell indexes.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method_ext ("targets=", &set_targets2, gsi::arg ("cells"), + "@brief Specifies the target cells.\n" + "\n" + "If target cells are specified, only instances of these cells are delivered. " + "This version takes a cell list as a glob pattern. " + "A glob pattern follows the syntax of " + "file names on the shell (i.e. \"A*\" are all cells starting with a letter \"A\").\n" + "Use the curly-bracket notation to list different cells, e.g \"{A,B,C}\" for cells A, B and C.\n" + "\n" + "By default, no target cell list is present and the instances of all cells " + "are delivered by the iterator. See \\all_targets_enabled? and \\enable_all_targets for " + "a description of this mode. Once a target list is specified, the iteration is " + "confined to the cells from this list." + "\n" + "The cells are given as a list of cell indexes.\n" + "\n" + "This method will also reset the iterator.\n" + ) + + gsi::method ("targets", &db::RecursiveInstanceIterator::targets, + "@brief Gets the list of target cells\n" + "See \\targets= for a description of the target cell concept. " + "This method returns a list of cell indexes of the selected target cells." + ) + + gsi::method ("all_targets_enabled?", &db::RecursiveInstanceIterator::all_targets_enabled, + "@brief Gets a value indicating whether instances of all cells are reported\n" + "See \\targets= for a description of the target cell concept. " + ) + + gsi::method ("enable_all_targets", &db::RecursiveInstanceIterator::enable_all_targets, + "@brief Enables 'all targets' mode in which instances of all cells are reported\n" + "See \\targets= for a description of the target cell concept. " + ) + + gsi::method ("trans", &db::RecursiveInstanceIterator::trans, + "@brief Gets the accumulated transformation of the current instance parent cell to the top cell\n" + "\n" + "This transformation represents how the current instance is seen in the top cell.\n" + ) + + gsi::method_ext ("dtrans", &gsi::si_dtrans, + "@brief Gets the accumulated transformation of the current instance parent cell to the top cell\n" + "\n" + "This transformation represents how the current instance is seen in the top cell.\n" + "This version returns the micon-unit transformation.\n" + ) + + gsi::method ("at_end?", &db::RecursiveInstanceIterator::at_end, + "@brief End of iterator predicate\n" + "\n" + "Returns true, if the iterator is at the end of the sequence\n" + ) + + gsi::method ("cell", &db::RecursiveInstanceIterator::cell, + "@brief Gets the cell the current instance sits in\n" + ) + + gsi::method ("cell_index", &db::RecursiveInstanceIterator::cell_index, + "@brief Gets the index of the cell the current instance sits in\n" + "This is equivalent to 'cell.cell_index'." + ) + + gsi::method_ext ("inst_trans", &inst_trans, + "@brief Gets the integer-unit transformation of the current instance\n" + "This is the transformation of the current instance inside its parent.\n" + "'trans * inst_trans' gives the full transformation how the current cell is seen in the top cell.\n" + "See also \\inst_dtrans and \\inst_cell.\n" + ) + + gsi::method_ext ("inst_dtrans", &inst_dtrans, + "@brief Gets the micron-unit transformation of the current instance\n" + "This is the transformation of the current instance inside its parent.\n" + "'dtrans * inst_dtrans' gives the full micron-unit transformation how the current cell is seen in the top cell.\n" + "See also \\inst_trans and \\inst_cell.\n" + ) + + gsi::method_ext ("inst_cell", &inst_cell, + "@brief Gets the target cell of the current instance\n" + "This is the cell the current instance refers to. It is one of the \\targets if a target list is given.\n" + ) + + gsi::method ("current_inst_element", &db::RecursiveInstanceIterator::instance, + "@brief Gets the current instance\n" + "\n" + "This is the instance/array element the iterator currently refers to.\n" + "This is a \\InstElement object representing the current instance and the array element the iterator currently points at.\n" + "\n" + "See \\inst_trans, \\inst_dtrans and \\inst_cell for convenience methods to access the details of the current element.\n" + ) + + gsi::method ("next", (void (db::RecursiveInstanceIterator::*) ()) &db::RecursiveInstanceIterator::next, + "@brief Increments the iterator\n" + "This moves the iterator to the next instance inside the search scope." + ) + + gsi::method ("path", &db::RecursiveInstanceIterator::path, + "@brief Gets the instantatiation path of the instance addressed currently\n" + "\n" + "This attribute is a sequence of \\InstElement objects describing the cell instance path from the initial " + "cell to the current instance. The path is empty if the current instance is in the top cell.\n" + ) + + gsi::method ("==", &db::RecursiveInstanceIterator::operator==, gsi::arg ("other"), + "@brief Comparison of iterators - equality\n" + "\n" + "Two iterators are equal if they point to the same instance.\n" + ) + + gsi::method ("!=", &db::RecursiveInstanceIterator::operator!=, gsi::arg ("other"), + "@brief Comparison of iterators - inequality\n" + "\n" + "Two iterators are not equal if they do not point to the same instance.\n" + ), + "@brief An iterator delivering instances recursively\n" + "\n" + "The iterator can be obtained from a cell and optionally a region.\n" + "It simplifies retrieval of instances while considering\n" + "subcells as well.\n" + "Some options can be specified in addition, i.e. the hierarchy level to which to look into.\n" + "The search can be confined to instances of certain cells (see \\targets=) or to certain regions. " + "Subtrees can be selected for traversal or excluded from it (see \\select_cells).\n" + "\n" + "This is some sample code:\n" + "\n" + "@code\n" + "# prints the effective instances of cell \"A\" as seen from the initial cell \"cell\"\n" + "iter = cell.begin_instances_rec\n" + "iter.targets = \"A\"\n" + "while !iter.at_end?\n" + " puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n" + " iter.next\n" + "end\n" + "@/code\n" + "\n" + "Here, a target cell is specified which confines the search to instances of this particular cell.\n" + "'iter.dtrans' gives us the accumulated transformation of all parents up to the top cell. " + "'iter.inst_dtrans' gives us the transformation from the current instance. " + "'iter.inst_cell' finally gives us the target cell of the current instance (which is always 'A' in our case).\n" + "\n" + "\\Cell offers three methods to get these iterators: begin_instances_rec, begin_instances_rec_touching and begin_instances_rec_overlapping.\n" + "\\Cell#begin_instances_rec will deliver a standard recursive instance iterator which starts from the given cell and iterates " + "over all child cells. \\Cell#begin_instances_rec_touching creates a RecursiveInstanceIterator which delivers the instances " + "whose bounding boxed touch the given search box. \\Layout#begin_instances_rec_overlapping gives an iterator which delivers all instances whose bounding box " + "overlaps the search box.\n" + "\n" + "A RecursiveInstanceIterator object can also be created directly, like this:\n" + "\n" + "@code\n" + "iter = RBA::RecursiveInstanceIterator::new(layout, cell [, options ])\n" + "@/code\n" + "\n" + "\"layout\" is the layout object, \"cell\" the \\Cell object of the initial cell.\n" + "\n" + "The recursive instance iterator can be confined to a maximum hierarchy depth. By using \\max_depth=, the " + "iterator will restrict the search depth to the given depth in the cell tree.\n" + "In the same way, the iterator can be configured to start from a certain hierarchy depth using \\min_depth=. " + "The hierarchy depth always applies to the parent of the instances iterated.\n" + "\n" + "In addition, the recursive instance iterator supports selection and exclusion of subtrees. For that purpose " + "it keeps flags per cell telling it for which cells to turn instance delivery on and off. The \\select_cells method " + "sets the \"start delivery\" flag while \\unselect_cells sets the \"stop delivery\" flag. In effect, using " + "\\unselect_cells will exclude that cell plus the subtree from delivery. Parts of that subtree can be " + "turned on again using \\select_cells. For the cells selected that way, the instances of these cells and their " + "child cells are delivered, even if their parent was unselected.\n" + "\n" + "To get instances from a specific cell, i.e. \"MACRO\" plus its child cells, unselect the top cell first " + "and the select the desired cell again:\n" + "\n" + "@code\n" + "# deliver all instances inside \"MACRO\" and the sub-hierarchy:\n" + "iter = RBA::RecursiveInstanceIterator::new(layout, cell)\n" + "iter.unselect_cells(cell.cell_index)\n" + "iter.select_cells(\"MACRO\")\n" + "...\n" + "@/code\n" + "\n" + "The \\unselect_all_cells and \\select_all_cells methods turn on the \"stop\" and \"start\" flag " + "for all cells respectively. If you use \\unselect_all_cells and use \\select_cells for a specific cell, " + "the iterator will deliver only the instances of the selected cell, not its children. Those are still " + "unselected by \\unselect_all_cells:\n" + "\n" + "@code\n" + "# deliver all instance inside \"MACRO\" but not of child cells:\n" + "iter = RBA::RecursiveInstanceIterator::new(layout, cell)\n" + "iter.unselect_all_cells\n" + "iter.select_cells(\"MACRO\")\n" + "...\n" + "@/code\n" + "\n" + "Cell selection is done using cell indexes or glob pattern. Glob pattern are equivalent to the usual " + "file name wildcards used on various command line shells. For example \"A*\" matches all cells starting with " + "an \"A\". The curly brace notation and character classes are supported as well. For example \"C{125,512}\" matches " + "\"C125\" and \"C512\" and \"[ABC]*\" matches all cells starting with an \"A\", a \"B\" or \"C\". \"[^ABC]*\" matches " + "all cells not starting with one of that letters.\n" + "\n" + "To confine instance iteration to instances of certain cells, use the \\targets feature:\n" + "\n" + "@code\n" + "# deliver all instance of \"INV1\":\n" + "iter = RBA::RecursiveInstanceIterator::new(layout, cell)\n" + "iter.targets = \"INV1\"\n" + "...\n" + "@/code\n" + "\n" + "Targets can be specified either as lists of cell indexes or through a glob pattern.\n" + "\n" + "Instances are always delivered depth-first with child instances before their parents. A default recursive instance " + "iterator will first deliver leaf cells, followed by the parent of these cells.\n" + "\n" + "When a search region is used, instances whose bounding box touch or overlap (depending on 'overlapping' flag) will " + "be reported. The instance bounding box taken as reference is computed using all layers of the layout.\n" + "\n" + "The iterator will deliver the individual elements of instance arrays, confined to the search region if one is given. " + "Consequently the return value (\\current_inst_element) is an \\InstElement " + "object which is basically a combination of an \\Instance object and information about the current array element.\n" + "\\inst_cell, \\inst_trans and \\inst_dtrans are methods provided for convenience to access the current array member's transformation " + "and the target cell of the current instance.\n" + "\n" + "The RecursiveInstanceIterator class has been introduced in version 0.27.\n" +); + +} diff --git a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc index be01b271f..72070d1e7 100644 --- a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc @@ -123,89 +123,89 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS gsi::constructor ("new", &new_si1, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), "@brief Creates a recursive, single-layer shape iterator.\n" "@param layout The layout which shall be iterated\n" - "@param cell The initial cell which shall be iterated (including it's children)\n" + "@param cell The initial cell which shall be iterated (including its children)\n" "@param layer The layer (index) from which the shapes are taken\n" "\n" "This constructor creates a new recursive shape iterator which delivers the shapes of " - "the given cell plus it's children from the layer given by the layer index in the \"layer\" parameter.\n" + "the given cell plus its children from the layer given by the layer index in the \"layer\" parameter.\n" "\n" "This constructor has been introduced in version 0.23.\n" ) + gsi::constructor ("new", &new_si2, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), "@brief Creates a recursive, multi-layer shape iterator.\n" "@param layout The layout which shall be iterated\n" - "@param cell The initial cell which shall be iterated (including it's children)\n" + "@param cell The initial cell which shall be iterated (including its children)\n" "@param layers The layer indexes from which the shapes are taken\n" "\n" "This constructor creates a new recursive shape iterator which delivers the shapes of " - "the given cell plus it's children from the layers given by the layer indexes in the \"layers\" parameter.\n" + "the given cell plus its children from the layers given by the layer indexes in the \"layers\" parameter.\n" "While iterating use the \\layer method to retrieve the layer of the current shape.\n" "\n" "This constructor has been introduced in version 0.23.\n" ) + - gsi::constructor ("new", &new_si3, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("box"), gsi::arg ("overlapping"), + gsi::constructor ("new", &new_si3, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("box"), gsi::arg ("overlapping", false), "@brief Creates a recursive, single-layer shape iterator with a region.\n" "@param layout The layout which shall be iterated\n" - "@param cell The initial cell which shall be iterated (including it's children)\n" + "@param cell The initial cell which shall be iterated (including its children)\n" "@param layer The layer (index) from which the shapes are taken\n" "@param box The search region\n" "@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n" "\n" "This constructor creates a new recursive shape iterator which delivers the shapes of " - "the given cell plus it's children from the layer given by the layer index in the \"layer\" parameter.\n" + "the given cell plus its children from the layer given by the layer index in the \"layer\" parameter.\n" "\n" "The search is confined to the region given by the \"box\" parameter. If \"overlapping\" is true, shapes whose " "bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose " "bounding box touches the search region are reported.\n" "\n" - "This constructor has been introduced in version 0.23.\n" + "This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n" ) + - gsi::constructor ("new", &new_si3a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), gsi::arg ("overlapping"), + gsi::constructor ("new", &new_si3a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), gsi::arg ("overlapping", false), "@brief Creates a recursive, single-layer shape iterator with a region.\n" "@param layout The layout which shall be iterated\n" - "@param cell The initial cell which shall be iterated (including it's children)\n" + "@param cell The initial cell which shall be iterated (including its children)\n" "@param layer The layer (index) from which the shapes are taken\n" "@param region The search region\n" "@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n" "\n" "This constructor creates a new recursive shape iterator which delivers the shapes of " - "the given cell plus it's children from the layer given by the layer index in the \"layer\" parameter.\n" + "the given cell plus its children from the layer given by the layer index in the \"layer\" parameter.\n" "\n" "The search is confined to the region given by the \"region\" parameter. The region needs to be a rectilinear region.\n" "If \"overlapping\" is true, shapes whose " "bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose " "bounding box touches the search region are reported.\n" "\n" - "This constructor has been introduced in version 0.25.\n" + "This constructor has been introduced in version 0.25. The 'overlapping' parameter has been made optional in version 0.27.\n" ) + - gsi::constructor ("new", &new_si4, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("box"), gsi::arg ("overlapping"), + gsi::constructor ("new", &new_si4, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("box"), gsi::arg ("overlapping", false), "@brief Creates a recursive, multi-layer shape iterator with a region.\n" "@param layout The layout which shall be iterated\n" - "@param cell The initial cell which shall be iterated (including it's children)\n" + "@param cell The initial cell which shall be iterated (including its children)\n" "@param layers The layer indexes from which the shapes are taken\n" "@param box The search region\n" "@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n" "\n" "This constructor creates a new recursive shape iterator which delivers the shapes of " - "the given cell plus it's children from the layers given by the layer indexes in the \"layers\" parameter.\n" + "the given cell plus its children from the layers given by the layer indexes in the \"layers\" parameter.\n" "While iterating use the \\layer method to retrieve the layer of the current shape.\n" "\n" "The search is confined to the region given by the \"box\" parameter. If \"overlapping\" is true, shapes whose " "bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose " "bounding box touches the search region are reported.\n" "\n" - "This constructor has been introduced in version 0.23.\n" + "This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n" ) + - gsi::constructor ("new", &new_si4a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("region"), gsi::arg ("overlapping"), + gsi::constructor ("new", &new_si4a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("region"), gsi::arg ("overlapping", false), "@brief Creates a recursive, multi-layer shape iterator with a region.\n" "@param layout The layout which shall be iterated\n" - "@param cell The initial cell which shall be iterated (including it's children)\n" + "@param cell The initial cell which shall be iterated (including its children)\n" "@param layers The layer indexes from which the shapes are taken\n" "@param region The search region\n" "@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n" "\n" "This constructor creates a new recursive shape iterator which delivers the shapes of " - "the given cell plus it's children from the layers given by the layer indexes in the \"layers\" parameter.\n" + "the given cell plus its children from the layers given by the layer indexes in the \"layers\" parameter.\n" "While iterating use the \\layer method to retrieve the layer of the current shape.\n" "\n" "The search is confined to the region given by the \"region\" parameter. The region needs to be a rectilinear region.\n" @@ -213,10 +213,10 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose " "bounding box touches the search region are reported.\n" "\n" - "This constructor has been introduced in version 0.23.\n" + "This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n" ) + gsi::method ("max_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::max_depth, gsi::arg ("depth"), - "@brief Specify the maximum hierarchy depth to look into\n" + "@brief Specifies the maximum hierarchy depth to look into\n" "\n" "A depth of 0 instructs the iterator to deliver only shapes from the initial cell.\n" "The depth must be specified before the shapes are being retrieved.\n" @@ -229,7 +229,23 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "\n" "This method has been introduced in version 0.23.\n" ) + - gsi::method ("reset", &db::RecursiveShapeIterator::reset, + gsi::method ("min_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::min_depth, gsi::arg ("depth"), + "@brief Specifies the minimum hierarchy depth to look into\n" + "\n" + "A depth of 0 instructs the iterator to deliver shapes from the top level.\n" + "1 instructs to deliver shapes from the first child level.\n" + "The minimum depth must be specified before the shapes are being retrieved.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method ("min_depth", (int (db::RecursiveShapeIterator::*) () const) &db::RecursiveShapeIterator::min_depth, + "@brief Gets the minimum hierarchy depth\n" + "\n" + "See \\min_depth= for a description of that attribute.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method ("reset", &db::RecursiveShapeIterator::reset, "@brief Resets the iterator to the initial state\n" "\n" "This method has been introduced in version 0.23.\n" @@ -237,7 +253,7 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS gsi::method ("reset_selection", &db::RecursiveShapeIterator::reset_selection, "@brief Resets the selection to the default state\n" "\n" - "In the initial state, the top cell and it's children are selected. Child cells can be switched on and off " + "In the initial state, the top cell and its children are selected. Child cells can be switched on and off " "together with their sub-hierarchy using \\select_cells and \\unselect_cells.\n" "\n" "This method will also reset the iterator.\n" @@ -436,7 +452,7 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "@brief Gets the current cell's index \n" ) + gsi::method ("next", (void (db::RecursiveShapeIterator::*) ()) &db::RecursiveShapeIterator::next, - "@brief Increment the iterator\n" + "@brief Increments the iterator\n" "This moves the iterator to the next shape inside the search scope." ) + gsi::method ("layer", &db::RecursiveShapeIterator::layer, @@ -462,12 +478,12 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "\n" "Two iterators are not equal if they do not point to the same shape.\n" ), - "@brief An iterator delivering shapes that touch or overlap the given region recursively\n" + "@brief An iterator delivering shapes recursively\n" "\n" - "The iterator can be obtained from a layout, specifying a starting cell, a layer and optionally a region.\n" + "The iterator can be obtained from a cell, a layer and optionally a region.\n" "It simplifies retrieval of shapes from a geometrical region while considering\n" "subcells as well.\n" - "Some options can be specified, i.e. the level to which to look into or\n" + "Some options can be specified in addition, i.e. the level to which to look into or\n" "shape classes and shape properties. The shapes are retrieved by using the \\shape method,\n" "\\next moves to the next shape and \\at_end tells, if the iterator has move shapes to deliver.\n" "\n" @@ -475,7 +491,7 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "\n" "@code\n" "# print the polygon-like objects as seen from the initial cell \"cell\"\n" - "iter = layout.begin_shapes(cell_index, layer)\n" + "iter = cell.begin_shapes_rec(layer)\n" "while !iter.at_end?\n" " if iter.shape.renders_polygon?\n" " polygon = iter.shape.polygon.transformed(iter.itrans)\n" @@ -485,10 +501,10 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "end\n" "@/code\n" "\n" - "\\Layout offers three methods to get these iterators: begin_shapes, begin_shapes_touching and begin_shapes_overlapping.\n" - "\\Layout#begin_shapes will deliver a standard recursive shape iterator which starts from the given cell and iterates " - "over all child cells. \\Layout#begin_shapes_touching delivers a RecursiveShapeIterator which delivers the shapes " - "whose bounding boxed touch the given search box. \\Layout#begin_shapes_overlapping delivers all shapes whose bounding box " + "\\Cell offers three methods to get these iterators: begin_shapes_rec, begin_shapes_rec_touching and begin_shapes_rec_overlapping.\n" + "\\Cell#begin_shapes_rec will deliver a standard recursive shape iterator which starts from the given cell and iterates " + "over all child cells. \\Cell#begin_shapes_rec_touching delivers a RecursiveShapeIterator which delivers the shapes " + "whose bounding boxed touch the given search box. \\Cell#begin_shapes_rec_overlapping delivers all shapes whose bounding box " "overlaps the search box.\n" "\n" "A RecursiveShapeIterator object can also be created explicitly. This allows some more options, i.e. using " @@ -510,7 +526,7 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "sets the \"start delivery\" flag while \\unselect_cells sets the \"stop delivery\" flag. In effect, using " "\\unselect_cells will exclude that cell plus the subtree from delivery. Parts of that subtree can be " "turned on again using \\select_cells. For the cells selected that way, the shapes of these cells and their " - "child cells are delivered, even if their parents was unselected.\n" + "child cells are delivered, even if their parent was unselected.\n" "\n" "To get shapes from a specific cell, i.e. \"MACRO\" plus its child cells, unselect the top cell first " "and the select the desired cell again:\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index a52ca5717..6614be324 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -308,6 +308,18 @@ static db::Region with_area2 (const db::Region *r, const tl::Variant &min, const return r->filtered (f); } +static db::Region with_holes1 (const db::Region *r, size_t n, bool inverse) +{ + db::HoleCountFilter f (n, n + 1, inverse); + return r->filtered (f); +} + +static db::Region with_holes2 (const db::Region *r, const tl::Variant &min, const tl::Variant &max, bool inverse) +{ + db::HoleCountFilter f (min.is_nil () ? size_t (0) : min.to (), max.is_nil () ? std::numeric_limits ::max () : max.to (), inverse); + return r->filtered (f); +} + static db::Region with_bbox_width1 (const db::Region *r, db::Region::distance_type bbox_width, bool inverse) { db::RegionBBoxFilter f (bbox_width, bbox_width + 1, inverse, db::RegionBBoxFilter::BoxWidth); @@ -925,6 +937,30 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" ) + + method_ext ("with_holes", with_holes1, gsi::arg ("nholes"), gsi::arg ("inverse"), + "@brief Filters the polygons by their number of holes\n" + "Filters the polygons of the region by number of holes. If \"inverse\" is false, only " + "polygons which have the given number of holes are returned. If \"inverse\" is true, " + "polygons not having the given of holes are returned.\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + + method_ext ("with_holes", with_holes2, gsi::arg ("min_bholes"), gsi::arg ("max_nholes"), gsi::arg ("inverse"), + "@brief Filter the polygons by their number of holes\n" + "Filters the polygons of the region by number of holes. If \"inverse\" is false, only " + "polygons which have a hole count larger or equal to \"min_nholes\" and less than \"max_nholes\" are " + "returned. If \"inverse\" is true, " + "polygons having a hole count less than \"min_nholes\" or larger or equal than \"max_nholes\" are " + "returned.\n" + "\n" + "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + method_ext ("with_bbox_width", with_bbox_width1, gsi::arg ("width"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box width\n" "Filters the polygons of the region by the width of their bounding box. If \"inverse\" is false, only " @@ -1376,9 +1412,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "See \\round_corners for a description of this method. This version returns a new region instead of " "modifying self (out-of-place)." ) + - method ("smooth", &db::Region::smooth, gsi::arg ("d"), + method ("smooth", &db::Region::smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false), "@brief Smoothing\n" "@param d The smoothing tolerance (in database units)\n" + "@param keep_hv If true, horizontal and vertical edges are maintained\n" "\n" "This method will simplify the merged polygons of the region by removing vertexes if the " "resulting polygon stays equivalent with the original polygon. Equivalence is measured " @@ -1387,9 +1424,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method modifies the region. \\smoothed is a method that does the same but returns a new " "region without modifying self. Merged semantics applies for this method.\n" ) + - method ("smoothed", &db::Region::smoothed, gsi::arg ("d"), + method ("smoothed", &db::Region::smoothed, gsi::arg ("d"), gsi::arg ("keep_hv", false), "@brief Smoothing\n" "@param d The smoothing tolerance (in database units)\n" + "@param keep_hv If true, horizontal and vertical edges are maintained\n" "\n" "See \\smooth for a description of this method. This version returns a new region instead of " "modifying self (out-of-place). It has been introduced in version 0.25." diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 02391876b..46b57bf22 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -733,7 +733,8 @@ TEST(11_RoundAndSmoothed) r1_sized -= r1; db::Region rounded = r1_sized.rounded_corners (3000, 5000, 100); - db::Region smoothed = rounded.smoothed (100); + db::Region smoothed = rounded.smoothed (100, false); + db::Region smoothed_keep_hv = rounded.smoothed (100, true); db::Layout target; unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); @@ -741,6 +742,7 @@ TEST(11_RoundAndSmoothed) target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1_sized); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), rounded); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), smoothed); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), smoothed_keep_hv); CHECKPOINT(); db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au11.gds"); diff --git a/src/db/unit_tests/dbPolygonToolsTests.cc b/src/db/unit_tests/dbPolygonToolsTests.cc index 156aa6a8d..1764fd4e7 100644 --- a/src/db/unit_tests/dbPolygonToolsTests.cc +++ b/src/db/unit_tests/dbPolygonToolsTests.cc @@ -1188,8 +1188,8 @@ TEST(100) db::Polygon p; p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); - EXPECT_EQ (smooth (p, 5).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)"); - EXPECT_EQ (smooth (p, 20).to_string (), "(0,-100;0,0;150,0;150,-100)"); + EXPECT_EQ (smooth (p, 5, true).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)"); + EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,-100;0,0;150,0;150,-100)"); } // smoothing @@ -1207,8 +1207,8 @@ TEST(101) db::Polygon p; p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); - EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)"); - EXPECT_EQ (smooth (p, 20).to_string (), "(0,0;0,100;150,100;150,0)"); + EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)"); + EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,0;0,100;150,100;150,0)"); } // smoothing @@ -1224,8 +1224,8 @@ TEST(102) db::Polygon p; p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); - EXPECT_EQ (smooth (p, 20).to_string (), "()"); - EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;150,0;0,0;50,10)"); + EXPECT_EQ (smooth (p, 20, true).to_string (), "()"); + EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;150,0;0,0;50,10)"); } // smoothing @@ -1251,9 +1251,9 @@ TEST(103) db::Polygon p; p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); - EXPECT_EQ (smooth (p, 0).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)"); - EXPECT_EQ (smooth (p, 50).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)"); - EXPECT_EQ (smooth (p, 5000).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)"); + EXPECT_EQ (smooth (p, 0, true).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)"); + EXPECT_EQ (smooth (p, 50, true).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)"); + EXPECT_EQ (smooth (p, 5000, true).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)"); } // smoothing @@ -1272,7 +1272,8 @@ TEST(104) db::Polygon p; p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); - EXPECT_EQ (smooth (p, 12).to_string (), "(-244,-942;-942,-246;248,943;943,246)"); + EXPECT_EQ (smooth (p, 12, false).to_string (), "(-244,-942;-942,-246;248,943;943,246)"); + EXPECT_EQ (smooth (p, 12, true).to_string (), "(-245,-942;-942,-247;-942,-246;247,943;248,943;943,246;-244,-942)"); } // smoothing @@ -1292,11 +1293,46 @@ TEST(105) db::Polygon p; p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); - EXPECT_EQ (smooth (p, 0).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); - EXPECT_EQ (smooth (p, 50).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); - EXPECT_EQ (smooth (p, 80).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); - EXPECT_EQ (smooth (p, 90).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)"); - EXPECT_EQ (smooth (p, 100).to_string (), "(0,0;0,1000;2000,1000;2000,0)"); + EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); + EXPECT_EQ (smooth (p, 50, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); + EXPECT_EQ (smooth (p, 80, false).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); + EXPECT_EQ (smooth (p, 90, false).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)"); + EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;0,1000;2000,1000;2000,0)"); + EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)"); +} + +// smoothing +TEST(106) +{ + db::Point pattern [] = { + db::Point (0, 0), + db::Point (0, 73235), + db::Point (100, 74568), + db::Point (700, 82468), + db::Point (1200, 90468), + db::Point (2000, 106468), + db::Point (2300, 114468), + db::Point (2700, 130468), + db::Point (2800, 138468), + db::Point (2800, 154468), + db::Point (2700, 162468), + db::Point (2300, 178468), + db::Point (2000, 186468), + db::Point (1200, 202468), + db::Point (700, 210468), + db::Point (100, 218368), + db::Point (0, 219701), + db::Point (0, 272971), + db::Point (126450, 272971), + db::Point (126450, 0), + }; + + db::Polygon p; + p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); + + EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,73235;100,74568;700,82468;1200,90468;2000,106468;2300,114468;2700,130468;2800,138468;2800,154468;2700,162468;2300,178468;2000,186468;1200,202468;700,210468;100,218368;0,219701;0,272971;126450,272971;126450,0)"); + EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;100,74568;1200,90468;2300,114468;2800,138468;2700,162468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)"); + EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,73235;1200,90468;2300,114468;2800,138468;2800,154468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)"); } // rounding @@ -1501,7 +1537,7 @@ TEST(203) in.push_back (pp); ep.simple_merge (in, out, false /*no cut line*/); pp = out.front (); - pp = smooth (pp, 1); + pp = smooth (pp, 1, true); EXPECT_EQ (pp.hull ().size (), size_t (300)); EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); @@ -1547,7 +1583,7 @@ TEST(204) in.push_back (pp); ep.simple_merge (in, out, false /*no cut line*/); pp = out.front (); - pp = smooth (pp, 1); + pp = smooth (pp, 1, true); EXPECT_EQ (pp.hull ().size (), size_t (200)); EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); diff --git a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc new file mode 100644 index 000000000..a13dad263 --- /dev/null +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -0,0 +1,621 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbRecursiveInstanceIterator.h" +#include "dbRegion.h" +#include "dbLayoutDiff.h" +#include "tlString.h" +#include "tlUnitTest.h" + +#include + +std::string collect(db::RecursiveInstanceIterator &s, const db::Layout &layout) +{ + std::string res; + while (! s.at_end ()) { + if (! res.empty ()) { + res += "/"; + } + if (s.cell ()) { + res += std::string ("[") + layout.cell_name (s.cell ()->cell_index ()) + "]"; + } else { + res += "[]"; + } + res += s->inst_ptr.to_string (true); + ++s; + } + return res; +} + +std::string collect_with_copy(db::RecursiveInstanceIterator s, const db::Layout &layout) +{ + s.reset (); + return collect (s, layout); +} + +TEST(1) +{ + db::Manager m (true); + db::Layout g (&m); + g.insert_layer (0); + g.insert_layer (1); + g.insert_layer (2); + + db::Cell &c0 (g.cell (g.add_cell ())); + + db::RecursiveInstanceIterator idef; + EXPECT_EQ (idef.at_end (), true); + EXPECT_EQ (collect (idef, g), ""); + EXPECT_EQ (collect_with_copy (idef, g), ""); + + db::RecursiveInstanceIterator i00 (g, c0, db::Box (0, 0, 100, 100)); + EXPECT_EQ (collect (i00, g), ""); + EXPECT_EQ (collect_with_copy (i00, g), ""); + + db::Cell &c1 (g.cell (g.add_cell ())); + db::Cell &c2 (g.cell (g.add_cell ())); + db::Cell &c3 (g.cell (g.add_cell ())); + + db::RecursiveInstanceIterator i0 (g, c0, db::Box (0, 0, 100, 100)); + EXPECT_EQ (collect (i0, g), ""); + EXPECT_EQ (collect_with_copy (i0, g), ""); + + db::Box b (0, 100, 1000, 1200); + c0.shapes (0).insert (b); + c1.shapes (0).insert (b); + c2.shapes (0).insert (b); + c3.shapes (0).insert (b); + + c0.shapes (2).insert (b); + c0.shapes (2).insert (b.moved (db::Vector (50, 50))); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100)))); + c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1))); + c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0)))); + + std::string x; + + db::RecursiveInstanceIterator i1 (g, c0, db::Box (0, 0, 100, 100)); + x = collect(i1, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i1, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i1_1inf (g, c0, db::Box (0, 0, 100, 100)); + i1_1inf.min_depth(0); + x = collect(i1_1inf, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i1_1inf, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i1_11 (g, c0, db::Box (0, 0, 2000, 100)); + i1_11.min_depth(0); + i1_11.max_depth(0); + x = collect(i1_11, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i1_11, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i1_12 (g, c0, db::Box (0, 0, 2000, 100)); + i1_12.min_depth(0); + i1_12.max_depth(1); + x = collect(i1_12, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i1_12, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i1_22 (g, c0, db::Box (0, 0, 2000, 100)); + i1_22.min_depth(1); + i1_22.max_depth(1); + x = collect(i1_22, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + x = collect_with_copy(i1_22, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + + db::RecursiveInstanceIterator i1o (g, c0, db::Box (0, 0, 100, 100), true); + x = collect(i1o, g); + EXPECT_EQ (x, ""); + x = collect_with_copy(i1o, g); + EXPECT_EQ (x, ""); + i1o = db::RecursiveInstanceIterator (g, c0, db::Box (0, 0, 100, 101), true); + x = collect(i1o, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0"); + x = collect_with_copy(i1o, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0"); + i1o = db::RecursiveInstanceIterator (g, c0, db::Box (0, 0, 101, 101), true); + x = collect(i1o, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i1o, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i2 (g, c0, db::Box (-100, 0, 100, 100)); + db::RecursiveInstanceIterator i2c = i2; + x = collect(i2, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i2, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect(i2c, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i2c, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + db::RecursiveInstanceIterator i2o (g, c0, db::Box (-100, 0, 100, 100), true); + x = collect(i2o, g); + EXPECT_EQ (x, ""); + x = collect_with_copy(i2o, g); + EXPECT_EQ (x, ""); + i2o = db::RecursiveInstanceIterator (g, c0, db::Box (-101, 0, 101, 101), true); + x = collect(i2o, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i2o, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + db::Region r; + r.insert (db::Box (-600, -100, -500, 0)); + r.insert (db::Box (1600, 0, 1700, 100)); + db::RecursiveInstanceIterator i2r (g, c0, r); + db::RecursiveInstanceIterator i2rc = i2r; + x = collect(i2r, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i2r, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect(i2rc, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i2rc, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + db::RecursiveInstanceIterator i2ro (g, c0, r, true); + x = collect(i2ro, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i2ro, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i4 (g, c0, db::Box (-100, 0, 2000, 100)); + db::RecursiveInstanceIterator i4_copy (g, c0, db::Box (-100, 0, 2000, 100)); + i4.max_depth (0); + x = collect(i4, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i4, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + EXPECT_EQ (i4 == i4, true); + EXPECT_EQ (i4 != i4, false); + EXPECT_EQ (i4 == i4_copy, false); + EXPECT_EQ (i4 != i4_copy, true); + i4 = i4_copy; + EXPECT_EQ (i4 == i4_copy, true); + EXPECT_EQ (i4 != i4_copy, false); + i4.max_depth (1); + x = collect(i4, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i4, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + i4 = i4_copy; + x = collect(i4, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i4, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + db::RecursiveInstanceIterator i5 (g, c0, db::Box::world ()); + x = collect(i5, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(i5, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + std::set cc; + db::RecursiveInstanceIterator ii; + + ii = db::RecursiveInstanceIterator (g, c0, db::Box::world ()); + cc.clear (); + cc.insert (c2.cell_index ()); + ii.unselect_all_cells (); + ii.select_cells (cc); + x = collect(ii, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + x = collect_with_copy(ii, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + ii.reset (); + x = collect(ii, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + x = collect_with_copy(ii, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + + ii.reset_selection (); + x = collect(ii, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(ii, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + ii.reset_selection (); + cc.clear (); + cc.insert (c0.cell_index ()); + cc.insert (c2.cell_index ()); + ii.unselect_cells (cc); + cc.clear (); + cc.insert (c2.cell_index ()); + ii.select_cells (cc); + x = collect(ii, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + x = collect_with_copy(ii, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); + + ii = db::RecursiveInstanceIterator (g, c0, db::Box::world ()); + ii.unselect_all_cells (); + cc.clear (); + cc.insert (c0.cell_index ()); + ii.select_cells (cc); + x = collect(ii, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + x = collect_with_copy(ii, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0"); + + db::RecursiveInstanceIterator i1z (g, c0); + EXPECT_EQ (i1z.all_targets_enabled (), true); + std::set ct; + ct.insert (c3.cell_index ()); + i1z.set_targets (ct); + EXPECT_EQ (i1z.all_targets_enabled (), false); + EXPECT_EQ (i1z.targets () == ct, true); + i1z.enable_all_targets (); + EXPECT_EQ (i1z.all_targets_enabled (), true); + + i1z.set_targets (ct); + EXPECT_EQ (i1z.all_targets_enabled (), false); + + x = collect(i1z, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$4 r90 0,0"); + x = collect_with_copy(i1z, g); + EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$4 r90 0,0"); +} + +static db::Layout boxes2layout (const std::set &boxes) +{ + db::Layout l; + l.insert_layer(0, db::LayerProperties (1, 0)); + db::Cell &top (l.cell (l.add_cell ())); + + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + top.shapes (0).insert (*b); + } + + return l; +} + +namespace { + + class FlatPusher + : public db::RecursiveInstanceReceiver + { + public: + FlatPusher (std::set *boxes) : mp_boxes (boxes) { } + + void enter_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + { + mp_boxes->insert (iter->trans () * cell->bbox ()); + } + + private: + std::set *mp_boxes; + }; + +} + +TEST(2) +{ + // Big fun with cells + + db::Manager m (true); + db::Layout g (&m); + g.insert_layer(0); + + db::Cell &c0 (g.cell (g.add_cell ())); + db::Cell &c1 (g.cell (g.add_cell ())); + + db::Box basic_box (0, 0, 10, 10); + c1.shapes (0).insert (basic_box); + + std::set boxes; + + for (int i = 0; i < 100000; ++i) { + + int x = rand () % 10000; + int y = rand () % 10000; + + boxes.insert (basic_box.moved (db::Vector (x, y))); + + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y)))); + + } + + db::Box search_box (2500, 2500, 7500, 7500); + + std::set selected_boxes; + std::set selected_boxes2; + + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter.trans () * iter->inst_ptr.bbox ()); + } + + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + if (search_box.overlaps (*b)) { + selected_boxes2.insert (*b); + } + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + // push mode + { + selected_boxes.clear (); + FlatPusher pusher (&selected_boxes); + db::RecursiveInstanceIterator (g, c0, search_box, true).push (&pusher); + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + db::Box search_box2 (500, 500, 1000, 1000); + + selected_boxes.clear (); + selected_boxes2.clear (); + + db::Region reg; + reg.insert (search_box); + reg.insert (search_box2); + + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); + } + + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + if (search_box.overlaps (*b) || search_box2.overlaps (*b)) { + selected_boxes2.insert (*b); + } + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + // push mode + { + selected_boxes.clear (); + FlatPusher pusher (&selected_boxes); + db::RecursiveInstanceIterator (g, c0, reg, true).push (&pusher); + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); +} + +TEST(3) +{ + // Big fun with cells - 2 hierarchy levels + + db::Manager m (true); + db::Layout g (&m); + g.insert_layer(0); + + db::Cell &c0 (g.cell (g.add_cell ())); + db::Cell &c1 (g.cell (g.add_cell ())); + db::Cell &c2 (g.cell (g.add_cell ())); + + db::Box basic_box (0, 0, 10, 10); + c2.shapes (0).insert (basic_box); + c1.insert (db::CellInstArray (c2.cell_index (), db::Trans (db::Vector (1, -1)))); + + std::set boxes; + + int nboxes = 100000; + for (int i = 0; i < nboxes; ++i) { + + int x, y; + + do { + x = rand () % 10000; + y = rand () % 10000; + } while (boxes.find (basic_box.moved (db::Vector (x + 1, y - 1))) != boxes.end ()); + + boxes.insert (basic_box.moved (db::Vector (x + 1, y - 1))); + + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y)))); + + } + + db::Box search_box (2500, 2500, 7500, 7500); + + std::set selected_boxes; + std::set selected_boxes2; + + db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box, true); + std::set tc; + tc.insert (c2.cell_index ()); + iter.set_targets (tc); + int n = 0; + for ( ; !iter.at_end (); ++iter) { + ++n; + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); + } + + int nn = 0; + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + if (search_box.overlaps (*b)) { + ++nn; + selected_boxes2.insert (*b); + } + } + + EXPECT_EQ (n, nn); + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + // push mode + { + selected_boxes.clear (); + FlatPusher pusher (&selected_boxes); + db::RecursiveInstanceIterator (g, c0, search_box, true).push (&pusher); + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + db::Box search_box2 (500, 500, 1000, 1000); + + selected_boxes.clear (); + selected_boxes2.clear (); + + db::Region reg; + reg.insert (search_box); + reg.insert (search_box2); + + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); + } + + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + if (search_box.overlaps (*b) || search_box2.overlaps (*b)) { + selected_boxes2.insert (*b); + } + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + // push mode + { + selected_boxes.clear (); + FlatPusher pusher (&selected_boxes); + db::RecursiveInstanceIterator (g, c0, reg, true).push (&pusher); + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); +} + +TEST(4) +{ + // Big fun with cells - 2 hierarchy levels + touching mode + + db::Manager m (true); + db::Layout g (&m); + g.insert_layer(0); + + db::Cell &c0 (g.cell (g.add_cell ())); + db::Cell &c1 (g.cell (g.add_cell ())); + db::Cell &c2 (g.cell (g.add_cell ())); + + db::Box basic_box (0, 0, 10, 10); + c2.shapes (0).insert (basic_box); + c1.insert (db::CellInstArray (c2.cell_index (), db::Trans (db::Vector (1, -1)))); + + std::set boxes; + + int nboxes = 100000; + for (int i = 0; i < nboxes; ++i) { + + int x, y; + + do { + x = rand () % 10000; + y = rand () % 10000; + } while (boxes.find (basic_box.moved (db::Vector (x + 1, y - 1))) != boxes.end ()); + + boxes.insert (basic_box.moved (db::Vector (x + 1, y - 1))); + + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y)))); + + } + + db::Box search_box (2500, 2500, 7500, 7500); + + std::set selected_boxes; + std::set selected_boxes2; + + db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box); + std::set tc; + tc.insert (c2.cell_index ()); + iter.set_targets (tc); + int n = 0; + for ( ; !iter.at_end (); ++iter) { + ++n; + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); + } + + int nn = 0; + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + if (search_box.touches (*b)) { + ++nn; + selected_boxes2.insert (*b); + } + } + + EXPECT_EQ (n, nn); + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + // push mode + { + selected_boxes.clear (); + FlatPusher pusher (&selected_boxes); + db::RecursiveInstanceIterator (g, c0, search_box).push (&pusher); + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + db::Box search_box2 (500, 500, 1000, 1000); + + selected_boxes.clear (); + selected_boxes2.clear (); + + db::Region reg; + reg.insert (search_box); + reg.insert (search_box2); + + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg); !iter.at_end (); ++iter) { + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); + } + + for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { + if (search_box.touches (*b) || search_box2.touches (*b)) { + selected_boxes2.insert (*b); + } + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); + + // push mode + { + selected_boxes.clear (); + FlatPusher pusher (&selected_boxes); + db::RecursiveInstanceIterator (g, c0, reg).push (&pusher); + } + + EXPECT_EQ (selected_boxes.size () > 100, true); + EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); +} + diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index bfef1084f..cf559bb1f 100644 --- a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc @@ -723,20 +723,24 @@ static db::Layout boxes2layout (const std::set &boxes) return l; } -class FlatPusher - : public db::RecursiveShapeReceiver -{ -public: - FlatPusher (std::set *boxes) : mp_boxes (boxes) { } +namespace { - void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + class FlatPusher + : public db::RecursiveShapeReceiver { - mp_boxes->insert (trans * shape.bbox ()); - } + public: + FlatPusher (std::set *boxes) : mp_boxes (boxes) { } -private: - std::set *mp_boxes; -}; + void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + { + mp_boxes->insert (trans * shape.bbox ()); + } + + private: + std::set *mp_boxes; + }; + +} TEST(4) { @@ -1023,6 +1027,8 @@ TEST(10) db::Box b (1000, -500, 2000, 500); c2.shapes (0).insert (b); + c0.shapes (0).insert (b.moved (db::Vector (-1000, 500))); + c0.shapes (0).insert (b.moved (db::Vector (-2000, 500))); db::Trans tt; c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); @@ -1036,6 +1042,9 @@ TEST(10) "begin\n" "new_inst($2,all)\n" "new_inst_member($2,r0 *1 0,0,all)\n" + // It's a bit weird to have shape events after new_inst_member, but remember, new_inst_member is a query callback, not an event. + "shape(box (0,0;1000,1000),r0 *1 0,0)\n" + "shape(box (-1000,0;0,1000),r0 *1 0,0)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "new_inst_member($3,r0 *1 0,0,all)\n" @@ -1126,6 +1135,8 @@ TEST(10) "begin\n" "new_inst($2,all)\n" "new_inst_member($2,r0 *1 0,0,all)\n" + "shape(box (0,0;1000,1000),r0 *1 0,0)\n" + "shape(box (-1000,0;0,1000),r0 *1 0,0)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "leave_cell($2)\n" @@ -1152,6 +1163,8 @@ TEST(10) "begin\n" "new_inst($2,all)\n" "new_inst_member($2,r0 *1 0,0,all)\n" + "shape(box (0,0;1000,1000),r0 *1 0,0)\n" + "shape(box (-1000,0;0,1000),r0 *1 0,0)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "new_inst_member($3,r0 *1 0,0,all)\n" @@ -1194,6 +1207,8 @@ TEST(10) "begin\n" "new_inst($2,all)\n" "new_inst_member($2,r0 *1 0,0,all)\n" + "shape(box (0,0;1000,1000),r0 *1 0,0)\n" + "shape(box (-1000,0;0,1000),r0 *1 0,0)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "new_inst_member($3,r0 *1 0,0,all)\n" // -> skipped @@ -1271,6 +1286,8 @@ TEST(10) EXPECT_EQ (rr2.text (), "begin\n" "new_inst($2,all)\n" + "shape(box (0,0;1000,1000),r0 *1 0,0)\n" + "shape(box (-1000,0;0,1000),r0 *1 0,0)\n" "end\n" ); @@ -1282,6 +1299,8 @@ TEST(10) "begin\n" "new_inst($2)\n" "new_inst_member($2,r0 *1 0,0)\n" + "shape(box (0,0;1000,1000),r0 *1 0,0)\n" + "shape(box (-1000,0;0,1000),r0 *1 0,0)\n" "enter_cell($2)\n" "new_inst($3)\n" "new_inst_member($3,r0 *1 0,0)\n" diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index db2d9d296..c8b2334fa 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -1973,6 +1973,27 @@ TEST(35c_interact_with_count_text) EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)"); } +TEST(40_with_holes) +{ + db::Region r; + r.insert (db::Box (db::Point (0, 0), db::Point (100, 200))); + db::Region rr; + rr.insert (db::Box (db::Point (10, 10), db::Point (20, 20))); + rr.insert (db::Box (db::Point (30, 30), db::Point (40, 40))); + r.set_merged_semantics (true); + r.set_min_coherence (false); + + r -= rr; + + EXPECT_EQ (rr.filtered (db::HoleCountFilter (0, 1, false)).to_string (), "(10,10;10,20;20,20;20,10);(30,30;30,40;40,40;40,30)"); + EXPECT_EQ (r.filtered (db::HoleCountFilter (2, 3, false)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)"); + EXPECT_EQ (r.filtered (db::HoleCountFilter (1, 2, false)).to_string (), ""); + EXPECT_EQ (r.filtered (db::HoleCountFilter (1, 3, false)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)"); + EXPECT_EQ (r.filtered (db::HoleCountFilter (0, 2, false)).to_string (), ""); + EXPECT_EQ (r.filtered (db::HoleCountFilter (2, 5, false)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)"); + EXPECT_EQ (r.filtered (db::HoleCountFilter (3, 5, true)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)"); +} + TEST(100_Processors) { db::Region r; diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index ee48d7549..3af34f474 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ dbCompoundOperationTests.cc \ + dbRecursiveInstanceIteratorTests.cc \ dbRegionUtilsTests.cc \ dbUtilsTests.cc \ dbWriterTools.cc \ diff --git a/src/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index 1c8419bbe..6e24ce748 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -71,6 +71,7 @@ module DRC # @li \global#space @/li # @li \global#squares @/li # @li \global#width @/li +# @li \global#with_holes @/li # @/ul # # The following documentation will list the methods available for DRC expression objects. @@ -434,7 +435,7 @@ CODE # result. Without "if_any" three corners are returned for each triangle. def count - DRCOpNodeCountFilter::new(@engine, self) + DRCOpNodeCountFilter::new(@engine, self, :new_count_filter, "count") end # %DRC% @@ -738,16 +739,18 @@ CODE # %DRC% # @name smoothed # @brief Applies smoothing - # @synopsis expression.smoothed(d) + # @synopsis expression.smoothed(d [, keep_hv ]) # - # This operation acts on polygons and applies polygon smoothing with the tolerance d. See \Layer#smoothed for more details. + # This operation acts on polygons and applies polygon smoothing with the tolerance d. 'keep_hv' indicates + # whether horizontal and vertical edges are maintained. Default is 'no' which means such edges may be distorted. + # See \Layer#smoothed for more details. # # The "smoothed" method is available as a plain function or as a method on \DRC# expressions. # The plain function is equivalent to "primary.smoothed". - def smoothed(d) + def smoothed(d, keep_hv = false) @engine._context("smoothed") do - DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d)) + DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d), keep_hv) end end @@ -1003,6 +1006,24 @@ CODE return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges") end + # %DRC% + # @name with_holes + # @brief Selects all input polygons with the specified number of holes + # @synopsis expression.with_holes (in condition) + # + # This operation can be used as a plain function in which case it acts on primary + # shapes or can be used as method on another DRC expression. + # The following example selects all polygons with more than 2 holes: + # + # @code + # out = in.drc(with_holes > 2) + # out = in.drc(primary.with_holes > 2) # equivalent + # @/code + + def with_holes + return DRCOpNodeCountFilter::new(@engine, self, :new_hole_count_filter, "with_holes") + end + # %DRC% # @name merged # @brief Returns the merged input polygons, optionally selecting multi-overlap @@ -1552,16 +1573,19 @@ class DRCOpNodeCountFilter < DRCOpNodeWithCompare attr_accessor :input attr_accessor :inverse + attr_accessor :method + attr_accessor :name - def initialize(engine, input) + def initialize(engine, input, method, name) super(engine) self.input = input self.inverse = false - self.description = "count" + self.description = name + self.method = method end def _description_for_dump - self.inverse ? "count" : "not_count" + self.inverse ? name : "not_" + name end def do_create_node(cache) @@ -1570,7 +1594,7 @@ class DRCOpNodeCountFilter < DRCOpNodeWithCompare if self.lt || self.le args << (self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) + 1) end - RBA::CompoundRegionOperationNode::new_count_filter(*args) + RBA::CompoundRegionOperationNode::send(self.method, *args) end def inverted diff --git a/src/drc/drc/built-in-macros/_drc_cop_integration.rb b/src/drc/drc/built-in-macros/_drc_cop_integration.rb index 0b17df957..2a7566ff9 100644 --- a/src/drc/drc/built-in-macros/_drc_cop_integration.rb +++ b/src/drc/drc/built-in-macros/_drc_cop_integration.rb @@ -953,6 +953,19 @@ CODE CODE end + # %DRC% + # @name with_holes + # @brief Selects all input polygons according to their number of holes in DRC expressions + # @synopsis with_holes (in condition) + # + # "with_holes" represents a polygon selector for + # \DRC# expressions selecting polygons of the primary by their number of holes + # (see \Layer#drc and \DRC#with_holes for more details). + + def with_holes + primary.with_holes + end + # %DRC% # @name enclosing # @brief Performs an enclosing check diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 2d449e49f..8cb066c0b 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -498,6 +498,20 @@ module DRC end end + # %DRC% + # @name warn + # @brief Prints a warning + # @synopsis warn(message) + # Similar to \log, but the message is printed formatted as a warning + + def warn(arg) + if @log_file + @log_file.puts("WARNING: " + arg) + else + RBA::Logger::warn(arg) + end + end + # %DRC% # @name log_file # @brief Specify the log file where to send to log to @@ -1840,7 +1854,7 @@ CODE def run_timed(desc, obj) - info(desc) + log(desc) # enable progress if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts) diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 0f1363f61..b5fa7a3df 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -488,7 +488,7 @@ CODE # # This method is available for polygon layers only. - %w(bbox_height bbox_max bbox_min bbox_width perimeter).each do |f| + %w(bbox_height bbox_max bbox_min bbox_width perimeter holes).each do |f| [true, false].each do |inv| mn = (inv ? "without" : "with") + "_" + f eval <<"CODE" @@ -517,6 +517,61 @@ CODE end end + # %DRC% + # @name with_holes + # @brief Selects all polygons with the specified number of holes + # @synopsis layer.with_holes(count) + # @synopsis layer.with_holes(min_count, max_count) + # @synopsis layer.with_holes(min_count .. max_count) + # + # This method is available for polygon layers. It will select all polygons from the input layer + # which have the specified number of holes. + + # %DRC% + # @name without_holes + # @brief Selects all polygons with the specified number of holes + # @synopsis layer.without_holes(count) + # @synopsis layer.without_holes(min_count, max_count) + # @synopsis layer.without_holes(min_count .. max_count) + # + # This method is available for polygon layers. It will select all polygons from the input layer + # which do not have the specified number of holes. + + %w(holes).each do |f| + [true, false].each do |inv| + mn = (inv ? "without" : "with") + "_" + f + eval <<"CODE" + def #{mn}(*args) + + @engine._context("#{mn}") do + + requires_region + if args.size == 1 + a = args[0] + if a.is_a?(Range) + min = @engine._make_numeric_value_with_nil(a.begin) + max = @engine._make_numeric_value_with_nil(a.end) + max && (max += 1) + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, min, max, #{inv.inspect})) + else + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, @engine._make_value(a), #{inv.inspect})) + end + elsif args.size == 2 + min = @engine._make_numeric_value_with_nil(args[0]) + max = @engine._make_numeric_value_with_nil(args[1]) + max && (max += 1) + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, min, max, #{inv.inspect})) + else + raise("Invalid number of arguments (1 or 2 expected)") + end + + end + + end +CODE + end + end + # %DRC% # @name with_bbox_aspect_ratio # @brief Selects polygons by the aspect ratio of their bounding box diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index 6ada00b60..f1affc3d7 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -25,6 +25,8 @@ module DRC drc._rdb_index = rdb_index drc._generator = generator + drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path) + begin # Set a debugger scope so that our errors end up with the debugger set to the DRC's line @@ -46,6 +48,9 @@ module DRC # cleans up and creates layout and report views drc._finish + # unlocks the UI + drc_progress._destroy + end timer.stop diff --git a/src/drc/unit_tests/drcGenericTests.cc b/src/drc/unit_tests/drcGenericTests.cc index a175c6b7b..ea4de5476 100644 --- a/src/drc/unit_tests/drcGenericTests.cc +++ b/src/drc/unit_tests/drcGenericTests.cc @@ -238,3 +238,13 @@ TEST(17d) { run_test (_this, "17", true); } + +TEST(18) +{ + run_test (_this, "18", false); +} + +TEST(18d) +{ + run_test (_this, "18", true); +} diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 9f0d45e6a..b3215743f 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1152,3 +1152,14 @@ TEST(28_inputFragmentation) { run_test (_this, "28", true); } + +TEST(29_holes) +{ + run_test (_this, "29", false); +} + +TEST(29d_holes) +{ + run_test (_this, "29", true); +} + diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index 84e1602fb..7681eb396 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -60,7 +60,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le Value value = Value (0); tl::from_string (tl::to_string (le->text ()), value); dispatcher->config_set (cfg_name, tl::to_string (value)); - lay::indicate_error (le, 0); + lay::indicate_error (le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (le, &ex); } @@ -114,7 +114,7 @@ EditorOptionsGeneric::apply (lay::Dispatcher *root) try { db::DVector eg; egc.from_string_picky (tl::to_string (mp_ui->edit_grid_le->text ()), eg); - lay::indicate_error (mp_ui->edit_grid_le, 0); + lay::indicate_error (mp_ui->edit_grid_le, (tl::Exception *) 0); root->config_set (cfg_edit_grid, egc.to_string (eg)); } catch (tl::Exception &ex) { lay::indicate_error (mp_ui->edit_grid_le, &ex); @@ -166,7 +166,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root) mp_ui->edit_grid_le->setText (tl::to_qstring (egc.to_string (eg))); } grid_changed (mp_ui->grid_cb->currentIndex ()); - lay::indicate_error (mp_ui->edit_grid_le, 0); + lay::indicate_error (mp_ui->edit_grid_le, (tl::Exception *) 0); // edit & move angle @@ -196,7 +196,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root) unsigned int max_shapes = 1000; root->config_get (cfg_edit_max_shapes_of_instances, max_shapes); mp_ui->max_shapes_le->setText (tl::to_qstring (tl::to_string (max_shapes))); - lay::indicate_error (mp_ui->max_shapes_le, 0); + lay::indicate_error (mp_ui->max_shapes_le, (tl::Exception *) 0); bool show_shapes = true; root->config_get (cfg_edit_show_shapes_of_instances, show_shapes); @@ -356,7 +356,7 @@ EditorOptionsPath::setup (lay::Dispatcher *root) double w = 0.0; root->config_get (cfg_edit_path_width, w); mp_ui->width_le->setText (tl::to_qstring (tl::to_string (w))); - lay::indicate_error (mp_ui->width_le, 0); + lay::indicate_error (mp_ui->width_le, (tl::Exception *) 0); // path type and extensions @@ -377,9 +377,9 @@ EditorOptionsPath::setup (lay::Dispatcher *root) root->config_get (cfg_edit_path_ext_var_begin, bgnext); root->config_get (cfg_edit_path_ext_var_end, endext); mp_ui->start_ext_le->setText (tl::to_qstring (tl::to_string (bgnext))); - lay::indicate_error (mp_ui->start_ext_le, 0); + lay::indicate_error (mp_ui->start_ext_le, (tl::Exception *) 0); mp_ui->end_ext_le->setText (tl::to_qstring (tl::to_string (endext))); - lay::indicate_error (mp_ui->end_ext_le, 0); + lay::indicate_error (mp_ui->end_ext_le, (tl::Exception *) 0); } // ------------------------------------------------------------------ @@ -631,7 +631,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root) double angle = 0.0; root->config_get (cfg_edit_inst_angle, angle); mp_ui->angle_le->setText (tl::to_qstring (tl::to_string (angle))); - lay::indicate_error (mp_ui->angle_le, 0); + lay::indicate_error (mp_ui->angle_le, (tl::Exception *) 0); bool mirror = false; root->config_get (cfg_edit_inst_mirror, mirror); @@ -640,7 +640,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root) double scale = 1.0; root->config_get (cfg_edit_inst_scale, scale); mp_ui->scale_le->setText (tl::to_qstring (tl::to_string (scale))); - lay::indicate_error (mp_ui->scale_le, 0); + lay::indicate_error (mp_ui->scale_le, (tl::Exception *) 0); // array bool array = false; @@ -657,17 +657,17 @@ EditorOptionsInst::setup (lay::Dispatcher *root) root->config_get (cfg_edit_inst_column_y, column_y); mp_ui->rows_le->setText (tl::to_qstring (tl::to_string (rows))); - lay::indicate_error (mp_ui->rows_le, 0); + lay::indicate_error (mp_ui->rows_le, (tl::Exception *) 0); mp_ui->row_x_le->setText (tl::to_qstring (tl::to_string (row_x))); - lay::indicate_error (mp_ui->row_x_le, 0); + lay::indicate_error (mp_ui->row_x_le, (tl::Exception *) 0); mp_ui->row_y_le->setText (tl::to_qstring (tl::to_string (row_y))); - lay::indicate_error (mp_ui->row_y_le, 0); + lay::indicate_error (mp_ui->row_y_le, (tl::Exception *) 0); mp_ui->columns_le->setText (tl::to_qstring (tl::to_string (columns))); - lay::indicate_error (mp_ui->columns_le, 0); + lay::indicate_error (mp_ui->columns_le, (tl::Exception *) 0); mp_ui->column_x_le->setText (tl::to_qstring (tl::to_string (column_x))); - lay::indicate_error (mp_ui->column_x_le, 0); + lay::indicate_error (mp_ui->column_x_le, (tl::Exception *) 0); mp_ui->column_y_le->setText (tl::to_qstring (tl::to_string (column_y))); - lay::indicate_error (mp_ui->column_y_le, 0); + lay::indicate_error (mp_ui->column_y_le, (tl::Exception *) 0); // place origin of cell flag bool place_origin = false; diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index 23d6a509e..2360211db 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -405,7 +405,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ()); } - lay::indicate_error (cell_name_le, 0); + lay::indicate_error (cell_name_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (cell_name_le, &ex); @@ -447,7 +447,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (pos_x_le->text ()), x); - lay::indicate_error (pos_x_le, 0); + lay::indicate_error (pos_x_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (pos_x_le, &ex); has_error = true; @@ -455,7 +455,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (pos_y_le->text ()), y); - lay::indicate_error (pos_y_le, 0); + lay::indicate_error (pos_y_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (pos_y_le, &ex); has_error = true; @@ -472,7 +472,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & double angle = 0.0; try { tl::from_string (tl::to_string (angle_le->text ()), angle); - lay::indicate_error (angle_le, 0); + lay::indicate_error (angle_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (angle_le, &ex); has_error = true; @@ -481,7 +481,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & double mag = 0.0; try { tl::from_string (tl::to_string (mag_le->text ()), mag); - lay::indicate_error (mag_le, 0); + lay::indicate_error (mag_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (mag_le, &ex); has_error = true; @@ -510,7 +510,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (column_x_le->text ()), cx); - lay::indicate_error (column_x_le, 0); + lay::indicate_error (column_x_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (column_x_le, &ex); has_error = true; @@ -518,7 +518,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (column_y_le->text ()), cy); - lay::indicate_error (column_y_le, 0); + lay::indicate_error (column_y_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (column_y_le, &ex); has_error = true; @@ -526,7 +526,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (row_x_le->text ()), rx); - lay::indicate_error (row_x_le, 0); + lay::indicate_error (row_x_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (row_x_le, &ex); has_error = true; @@ -534,7 +534,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (row_y_le->text ()), ry); - lay::indicate_error (row_y_le, 0); + lay::indicate_error (row_y_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (row_y_le, &ex); has_error = true; @@ -542,7 +542,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (rows_le->text ()), rows); - lay::indicate_error (rows_le, 0); + lay::indicate_error (rows_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (rows_le, &ex); has_error = true; @@ -550,7 +550,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (columns_le->text ()), cols); - lay::indicate_error (columns_le, 0); + lay::indicate_error (columns_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (columns_le, &ex); has_error = true; @@ -766,7 +766,7 @@ InstPropertiesPage::update_pcell_parameters () tl::Exception ex (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ()); lay::indicate_error (cell_name_le, &ex); } else { - lay::indicate_error (cell_name_le, 0); + lay::indicate_error (cell_name_le, (tl::Exception *) 0); } if (pc.first && layout->pcell_declaration (pc.second)) { diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index 50a5ba131..5d44adb74 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -1387,7 +1387,7 @@ MainService::cm_round_corners () std::vector in; ep.merge (primary, in, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/); for (std::vector ::iterator p = in.begin (); p != in.end (); ++p) { - *p = smooth (*p, 1); + *p = smooth (*p, 1, true); } std::vector out = in; diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index c8d1be652..17c2bdada 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -496,7 +496,7 @@ PCellParametersPage::get_parameters (bool *ok) tl::from_string (tl::to_string (le->text ()), v); parameters.back () = tl::Variant (v); - lay::indicate_error (le, 0); + lay::indicate_error (le, (tl::Exception *) 0); } catch (tl::Exception &ex) { @@ -520,7 +520,7 @@ PCellParametersPage::get_parameters (bool *ok) tl::from_string (tl::to_string (le->text ()), v); parameters.back () = tl::Variant (v); - lay::indicate_error (le, 0); + lay::indicate_error (le, (tl::Exception *) 0); } catch (tl::Exception &ex) { diff --git a/src/edt/edt/edtPropertiesPages.cc b/src/edt/edt/edtPropertiesPages.cc index 09912ce74..b8a038291 100644 --- a/src/edt/edt/edtPropertiesPages.cc +++ b/src/edt/edt/edtPropertiesPages.cc @@ -509,7 +509,7 @@ PolygonPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Sha } - lay::indicate_error (pointListEdit, 0); + lay::indicate_error (pointListEdit, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (pointListEdit, &ex); @@ -609,7 +609,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (x1_le_1->text ()), x1); - lay::indicate_error (x1_le_1, 0); + lay::indicate_error (x1_le_1, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (x1_le_1, &ex); has_error = true; @@ -617,7 +617,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (y1_le_1->text ()), y1); - lay::indicate_error (y1_le_1, 0); + lay::indicate_error (y1_le_1, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (y1_le_1, &ex); has_error = true; @@ -625,7 +625,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (x2_le_1->text ()), x2); - lay::indicate_error (x2_le_1, 0); + lay::indicate_error (x2_le_1, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (x2_le_1, &ex); has_error = true; @@ -633,7 +633,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (y2_le_1->text ()), y2); - lay::indicate_error (y2_le_1, 0); + lay::indicate_error (y2_le_1, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (y2_le_1, &ex); has_error = true; @@ -669,7 +669,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (cx_le_2->text ()), cx); - lay::indicate_error (cx_le_2, 0); + lay::indicate_error (cx_le_2, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (cx_le_2, &ex); has_error = true; @@ -677,7 +677,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (cy_le_2->text ()), cy); - lay::indicate_error (cy_le_2, 0); + lay::indicate_error (cy_le_2, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (cy_le_2, &ex); has_error = true; @@ -685,7 +685,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (w_le_2->text ()), w); - lay::indicate_error (w_le_2, 0); + lay::indicate_error (w_le_2, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (w_le_2, &ex); has_error = true; @@ -693,7 +693,7 @@ BoxPropertiesPage::get_box (int mode) const try { tl::from_string (tl::to_string (h_le_2->text ()), h); - lay::indicate_error (h_le_2, 0); + lay::indicate_error (h_le_2, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (h_le_2, &ex); has_error = true; @@ -834,7 +834,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape try { tl::from_string (tl::to_string (x_le->text ()), x); - lay::indicate_error (x_le, 0); + lay::indicate_error (x_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (x_le, &ex); has_error = true; @@ -842,7 +842,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape try { tl::from_string (tl::to_string (y_le->text ()), y); - lay::indicate_error (y_le, 0); + lay::indicate_error (y_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (y_le, &ex); has_error = true; @@ -875,7 +875,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape if (! size_le->text ().isEmpty ()) { try { size = coord_from_string (tl::to_string (size_le->text ()).c_str (), dbu, du, t); - lay::indicate_error (size_le, 0); + lay::indicate_error (size_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (size_le, &ex); has_error = true; @@ -1084,7 +1084,7 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db throw tl::Exception (tl::to_string (QObject::tr ("The path must have at least one point"))); } - lay::indicate_error (ptlist_le, 0); + lay::indicate_error (ptlist_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (ptlist_le, &ex); @@ -1094,7 +1094,7 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db db::Coord w = 0; try { w = coord_from_string (tl::to_string (width_le->text ()).c_str (), dbu, du, t); - lay::indicate_error (width_le, 0); + lay::indicate_error (width_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (width_le, &ex); has_error = true; @@ -1111,14 +1111,14 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db case 2: // variable try { se = coord_from_string (tl::to_string (start_ext_le->text ()).c_str (), dbu, du, t); - lay::indicate_error (start_ext_le, 0); + lay::indicate_error (start_ext_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (start_ext_le, &ex); has_error = true; } try { ee = coord_from_string (tl::to_string (end_ext_le->text ()).c_str (), dbu, du, t); - lay::indicate_error (end_ext_le, 0); + lay::indicate_error (end_ext_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (end_ext_le, &ex); has_error = true; diff --git a/src/gsi/gsi/gsiDeclTl.cc b/src/gsi/gsi/gsiDeclTl.cc index ef05a59e3..ccb800826 100644 --- a/src/gsi/gsi/gsiDeclTl.cc +++ b/src/gsi/gsi/gsiDeclTl.cc @@ -201,25 +201,6 @@ Class decl_Timer ("tl", "Timer", // ---------------------------------------------------------------- // Progress reporter objects -namespace tl { - - template <> struct type_traits : public type_traits { - typedef tl::false_tag has_copy_constructor; - typedef tl::false_tag has_default_constructor; - }; - - template <> struct type_traits : public type_traits { - typedef tl::false_tag has_copy_constructor; - typedef tl::false_tag has_default_constructor; - }; - - template <> struct type_traits : public type_traits { - typedef tl::false_tag has_copy_constructor; - typedef tl::false_tag has_default_constructor; - }; - -} - namespace gsi { @@ -247,6 +228,27 @@ Class decl_Progress ("tl", "Progress", "This class has been introduced in version 0.23.\n" ); +static tl::AbstractProgress *abstract_progress (const std::string &desc) +{ + return new tl::AbstractProgress (desc); +} + +Class decl_AbstractProgress (decl_Progress, "tl", "AbstractProgress", + gsi::constructor ("new", &abstract_progress, gsi::arg ("desc"), + "@brief Creates an abstract progress reporter with the given description\n" + ), + "@brief The abstract progress reporter\n" + "\n" + "The abstract progress reporter acts as a 'bracket' for a sequence of operations which are connected " + "logically. For example, a DRC script consists of multiple operations. An abstract progress reportert " + "is instantiated during the run time of the DRC script. This way, the application leaves the UI open while " + "the DRC executes and log messages can be collected.\n" + "\n" + "The abstract progress does not have a value.\n" + "\n" + "This class has been introduced in version 0.27.\n" +); + static tl::RelativeProgress *rel_progress_2 (const std::string &desc, size_t max) { return new tl::RelativeProgress (desc, max); diff --git a/src/gsiqt/qt4/QtCore/gsiDeclQCoreApplication.cc b/src/gsiqt/qt4/QtCore/gsiDeclQCoreApplication.cc index 0241de6be..236cad6bb 100644 --- a/src/gsiqt/qt4/QtCore/gsiDeclQCoreApplication.cc +++ b/src/gsiqt/qt4/QtCore/gsiDeclQCoreApplication.cc @@ -77,28 +77,6 @@ static void _call_f_filterEvent_2477 (const qt_gsi::GenericMethod * /*decl*/, vo } -// bool QCoreApplication::notify(QObject *, QEvent *) - - -static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = gsi::arg_reader() (args, heap); - QEvent *arg2 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QCoreApplication *)cls)->notify (arg1, arg2)); -} - - // static void QCoreApplication::addLibraryPath(const QString &) @@ -941,7 +919,6 @@ static gsi::Methods methods_QCoreApplication () { gsi::Methods methods; methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo); methods += new qt_gsi::GenericMethod ("filterEvent", "@brief Method bool QCoreApplication::filterEvent(void *message, long int *result)\n", false, &_init_f_filterEvent_2477, &_call_f_filterEvent_2477); - methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QCoreApplication::notify(QObject *, QEvent *)\n", false, &_init_f_notify_2411, &_call_f_notify_2411); methods += gsi::qt_signal ("aboutToQuit()", "aboutToQuit", "@brief Signal declaration for QCoreApplication::aboutToQuit()\nYou can bind a procedure to this signal."); methods += gsi::qt_signal ("destroyed(QObject *)", "destroyed", gsi::arg("arg1"), "@brief Signal declaration for QCoreApplication::destroyed(QObject *)\nYou can bind a procedure to this signal."); methods += gsi::qt_signal ("unixSignal(int)", "unixSignal", gsi::arg("arg1"), "@brief Signal declaration for QCoreApplication::unixSignal(int)\nYou can bind a procedure to this signal."); @@ -1054,21 +1031,6 @@ public: } } - // [adaptor impl] bool QCoreApplication::notify(QObject *, QEvent *) - bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2) - { - return QCoreApplication::notify(arg1, arg2); - } - - virtual bool notify(QObject *arg1, QEvent *arg2) - { - if (cb_notify_2411_0.can_issue()) { - return cb_notify_2411_0.issue(&QCoreApplication_Adaptor::cbs_notify_2411_0, arg1, arg2); - } else { - return QCoreApplication::notify(arg1, arg2); - } - } - // [emitter impl] void QCoreApplication::aboutToQuit() void emitter_QCoreApplication_aboutToQuit_0() { @@ -1163,7 +1125,6 @@ public: } gsi::Callback cb_eventFilter_2411_0; - gsi::Callback cb_notify_2411_0; gsi::Callback cb_childEvent_1701_0; gsi::Callback cb_customEvent_1217_0; gsi::Callback cb_disconnectNotify_1731_0; @@ -1326,32 +1287,6 @@ static void _set_callback_cbs_eventFilter_2411_0 (void *cls, const gsi::Callback } -// bool QCoreApplication::notify(QObject *, QEvent *) - -static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = args.read (heap); - QEvent *arg2 = args.read (heap); - ret.write ((bool)((QCoreApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2)); -} - -static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb) -{ - ((QCoreApplication_Adaptor *)cls)->cb_notify_2411_0 = cb; -} - - // exposed int QCoreApplication::receivers(const char *signal) static void _init_fp_receivers_c1731 (qt_gsi::GenericMethod *decl) @@ -1445,8 +1380,6 @@ static gsi::Methods methods_QCoreApplication_Adaptor () { methods += new qt_gsi::GenericMethod ("*event", "@hide", false, &_init_cbs_event_1217_0, &_call_cbs_event_1217_0, &_set_callback_cbs_event_1217_0); methods += new qt_gsi::GenericMethod ("eventFilter", "@brief Virtual method bool QCoreApplication::eventFilter(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0); methods += new qt_gsi::GenericMethod ("eventFilter", "@hide", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0, &_set_callback_cbs_eventFilter_2411_0); - methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QCoreApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0); - methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0); methods += new qt_gsi::GenericMethod ("*receivers", "@brief Method int QCoreApplication::receivers(const char *signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_receivers_c1731, &_call_fp_receivers_c1731); methods += new qt_gsi::GenericMethod ("*sender", "@brief Method QObject *QCoreApplication::sender()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_sender_c0, &_call_fp_sender_c0); methods += new qt_gsi::GenericMethod ("*timerEvent", "@brief Virtual method void QCoreApplication::timerEvent(QTimerEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0); diff --git a/src/gsiqt/qt4/QtGui/gsiDeclQApplication.cc b/src/gsiqt/qt4/QtGui/gsiDeclQApplication.cc index 8f7b30aea..4fed3d98c 100644 --- a/src/gsiqt/qt4/QtGui/gsiDeclQApplication.cc +++ b/src/gsiqt/qt4/QtGui/gsiDeclQApplication.cc @@ -101,28 +101,6 @@ static void _call_f_isSessionRestored_c0 (const qt_gsi::GenericMethod * /*decl*/ } -// bool QApplication::notify(QObject *, QEvent *) - - -static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = gsi::arg_reader() (args, heap); - QEvent *arg2 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QApplication *)cls)->notify (arg1, arg2)); -} - - // QString QApplication::sessionId() @@ -1534,7 +1512,6 @@ static gsi::Methods methods_QApplication () { methods += new qt_gsi::GenericMethod (":autoSipEnabled", "@brief Method bool QApplication::autoSipEnabled()\n", true, &_init_f_autoSipEnabled_c0, &_call_f_autoSipEnabled_c0); methods += new qt_gsi::GenericMethod (":inputContext", "@brief Method QInputContext *QApplication::inputContext()\n", true, &_init_f_inputContext_c0, &_call_f_inputContext_c0); methods += new qt_gsi::GenericMethod ("isSessionRestored?", "@brief Method bool QApplication::isSessionRestored()\n", true, &_init_f_isSessionRestored_c0, &_call_f_isSessionRestored_c0); - methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QApplication::notify(QObject *, QEvent *)\nThis is a reimplementation of QCoreApplication::notify", false, &_init_f_notify_2411, &_call_f_notify_2411); methods += new qt_gsi::GenericMethod ("sessionId", "@brief Method QString QApplication::sessionId()\n", true, &_init_f_sessionId_c0, &_call_f_sessionId_c0); methods += new qt_gsi::GenericMethod ("sessionKey", "@brief Method QString QApplication::sessionKey()\n", true, &_init_f_sessionKey_c0, &_call_f_sessionKey_c0); methods += new qt_gsi::GenericMethod ("setAutoSipEnabled|autoSipEnabled=", "@brief Method void QApplication::setAutoSipEnabled(const bool enabled)\n", false, &_init_f_setAutoSipEnabled_1559, &_call_f_setAutoSipEnabled_1559); @@ -1686,21 +1663,6 @@ public: } } - // [adaptor impl] bool QApplication::notify(QObject *, QEvent *) - bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2) - { - return QApplication::notify(arg1, arg2); - } - - virtual bool notify(QObject *arg1, QEvent *arg2) - { - if (cb_notify_2411_0.can_issue()) { - return cb_notify_2411_0.issue(&QApplication_Adaptor::cbs_notify_2411_0, arg1, arg2); - } else { - return QApplication::notify(arg1, arg2); - } - } - // [emitter impl] void QApplication::aboutToQuit() void emitter_QApplication_aboutToQuit_0() { @@ -1813,7 +1775,6 @@ public: } gsi::Callback cb_eventFilter_2411_0; - gsi::Callback cb_notify_2411_0; gsi::Callback cb_childEvent_1701_0; gsi::Callback cb_customEvent_1217_0; gsi::Callback cb_disconnectNotify_1731_0; @@ -2025,32 +1986,6 @@ static void _call_emitter_lastWindowClosed_0 (const qt_gsi::GenericMethod * /*de } -// bool QApplication::notify(QObject *, QEvent *) - -static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = args.read (heap); - QEvent *arg2 = args.read (heap); - ret.write ((bool)((QApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2)); -} - -static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb) -{ - ((QApplication_Adaptor *)cls)->cb_notify_2411_0 = cb; -} - - // exposed int QApplication::receivers(const char *signal) static void _init_fp_receivers_c1731 (qt_gsi::GenericMethod *decl) @@ -2147,8 +2082,6 @@ static gsi::Methods methods_QApplication_Adaptor () { methods += new qt_gsi::GenericMethod ("emit_focusChanged", "@brief Emitter for signal void QApplication::focusChanged(QWidget *old, QWidget *now)\nCall this method to emit this signal.", false, &_init_emitter_focusChanged_2522, &_call_emitter_focusChanged_2522); methods += new qt_gsi::GenericMethod ("emit_fontDatabaseChanged", "@brief Emitter for signal void QApplication::fontDatabaseChanged()\nCall this method to emit this signal.", false, &_init_emitter_fontDatabaseChanged_0, &_call_emitter_fontDatabaseChanged_0); methods += new qt_gsi::GenericMethod ("emit_lastWindowClosed", "@brief Emitter for signal void QApplication::lastWindowClosed()\nCall this method to emit this signal.", false, &_init_emitter_lastWindowClosed_0, &_call_emitter_lastWindowClosed_0); - methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0); - methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0); methods += new qt_gsi::GenericMethod ("*receivers", "@brief Method int QApplication::receivers(const char *signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_receivers_c1731, &_call_fp_receivers_c1731); methods += new qt_gsi::GenericMethod ("*sender", "@brief Method QObject *QApplication::sender()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_sender_c0, &_call_fp_sender_c0); methods += new qt_gsi::GenericMethod ("*timerEvent", "@brief Virtual method void QApplication::timerEvent(QTimerEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0); diff --git a/src/gsiqt/qt4/QtUiTools/QtUiTools.pri b/src/gsiqt/qt4/QtUiTools/QtUiTools.pri new file mode 100644 index 000000000..616643bc8 --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/QtUiTools.pri @@ -0,0 +1,13 @@ +# +# Partial QMAKE project file for Qt bindings +# +# DO NOT EDIT THIS FILE. +# This file has been created automatically +# + +SOURCES += \ + gsiQtUiToolsMain.cc \ + $$PWD/gsiDeclQUiLoader.cc + +HEADERS += gsiQtUiToolsCommon.h + diff --git a/src/gsiqt/qt4/QtUiTools/QtUiTools.pro b/src/gsiqt/qt4/QtUiTools/QtUiTools.pro new file mode 100644 index 000000000..58b1f6c0c --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/QtUiTools.pro @@ -0,0 +1,20 @@ + + +DESTDIR = $$OUT_PWD/../../.. +TARGET = klayout_QtUiTools + +include($$PWD/../../../lib.pri) + +DEFINES += MAKE_GSI_QTUITOOLS_LIBRARY + +INCLUDEPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC +DEPENDPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC + +LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_qtbasic + +SOURCES += \ + +HEADERS += \ + +include(QtUiTools.pri) + diff --git a/src/gsiqt/qt4/QtUiTools/gsiDeclQUiLoader.cc b/src/gsiqt/qt4/QtUiTools/gsiDeclQUiLoader.cc new file mode 100644 index 000000000..5cb3472f3 --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/gsiDeclQUiLoader.cc @@ -0,0 +1,1093 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** +* @file gsiDeclQUiLoader.cc +* +* DO NOT EDIT THIS FILE. +* This file has been created automatically +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gsiQt.h" +#include "gsiQtUiToolsCommon.h" +#include "gsiDeclQtUiToolsTypeTraits.h" +#include + +// ----------------------------------------------------------------------- +// class QUiLoader + +// get static meta object + +static void _init_smo (qt_gsi::GenericStaticMethod *decl) +{ + decl->set_return (); +} + +static void _call_smo (const qt_gsi::GenericStaticMethod *, gsi::SerialArgs &, gsi::SerialArgs &ret) +{ + ret.write (QUiLoader::staticMetaObject); +} + + +// void QUiLoader::addPluginPath(const QString &path) + + +static void _init_f_addPluginPath_2025 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("path"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_addPluginPath_2025 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->addPluginPath (arg1); +} + + +// QStringList QUiLoader::availableLayouts() + + +static void _init_f_availableLayouts_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_availableLayouts_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QStringList)((QUiLoader *)cls)->availableLayouts ()); +} + + +// QStringList QUiLoader::availableWidgets() + + +static void _init_f_availableWidgets_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_availableWidgets_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QStringList)((QUiLoader *)cls)->availableWidgets ()); +} + + +// void QUiLoader::clearPluginPaths() + + +static void _init_f_clearPluginPaths_0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_clearPluginPaths_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->clearPluginPaths (); +} + + +// QAction *QUiLoader::createAction(QObject *parent, const QString &name) + + +static void _init_f_createAction_3219 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent", true, "0"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name", true, "QString()"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_createAction_3219 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QAction *)((QUiLoader *)cls)->createAction (arg1, arg2)); +} + + +// QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) + + +static void _init_f_createActionGroup_3219 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent", true, "0"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name", true, "QString()"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_createActionGroup_3219 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QActionGroup *)((QUiLoader *)cls)->createActionGroup (arg1, arg2)); +} + + +// QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) + + +static void _init_f_createLayout_5136 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent", true, "0"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name", true, "QString()"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_createLayout_5136 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = gsi::arg_reader() (args, heap); + QObject *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg3 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QLayout *)((QUiLoader *)cls)->createLayout (arg1, arg2, arg3)); +} + + +// QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) + + +static void _init_f_createWidget_5149 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent", true, "0"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name", true, "QString()"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_createWidget_5149 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = gsi::arg_reader() (args, heap); + QWidget *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg3 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QWidget *)((QUiLoader *)cls)->createWidget (arg1, arg2, arg3)); +} + + +// bool QUiLoader::isLanguageChangeEnabled() + + +static void _init_f_isLanguageChangeEnabled_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_isLanguageChangeEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((bool)((QUiLoader *)cls)->isLanguageChangeEnabled ()); +} + + +// bool QUiLoader::isScriptingEnabled() + + +static void _init_f_isScriptingEnabled_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_isScriptingEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((bool)((QUiLoader *)cls)->isScriptingEnabled ()); +} + + +// bool QUiLoader::isTranslationEnabled() + + +static void _init_f_isTranslationEnabled_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_isTranslationEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((bool)((QUiLoader *)cls)->isTranslationEnabled ()); +} + + +// QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) + + +static void _init_f_load_2654 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("device"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parentWidget", true, "0"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_load_2654 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QIODevice *arg1 = gsi::arg_reader() (args, heap); + QWidget *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + ret.write ((QWidget *)((QUiLoader *)cls)->load (arg1, arg2)); +} + + +// QStringList QUiLoader::pluginPaths() + + +static void _init_f_pluginPaths_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_pluginPaths_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QStringList)((QUiLoader *)cls)->pluginPaths ()); +} + + +// void QUiLoader::setLanguageChangeEnabled(bool enabled) + + +static void _init_f_setLanguageChangeEnabled_864 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("enabled"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setLanguageChangeEnabled_864 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + bool arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setLanguageChangeEnabled (arg1); +} + + +// void QUiLoader::setScriptingEnabled(bool enabled) + + +static void _init_f_setScriptingEnabled_864 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("enabled"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setScriptingEnabled_864 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + bool arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setScriptingEnabled (arg1); +} + + +// void QUiLoader::setTranslationEnabled(bool enabled) + + +static void _init_f_setTranslationEnabled_864 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("enabled"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setTranslationEnabled_864 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + bool arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setTranslationEnabled (arg1); +} + + +// void QUiLoader::setWorkingDirectory(const QDir &dir) + + +static void _init_f_setWorkingDirectory_1681 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("dir"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setWorkingDirectory_1681 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QDir &arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setWorkingDirectory (arg1); +} + + +// QDir QUiLoader::workingDirectory() + + +static void _init_f_workingDirectory_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_workingDirectory_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QDir)((QUiLoader *)cls)->workingDirectory ()); +} + + +// static QString QUiLoader::tr(const char *s, const char *c) + + +static void _init_f_tr_3354 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("s"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("c", true, "0"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_tr_3354 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + const char *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + ret.write ((QString)QUiLoader::tr (arg1, arg2)); +} + + +// static QString QUiLoader::tr(const char *s, const char *c, int n) + + +static void _init_f_tr_4013 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("s"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("c"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("n"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_tr_4013 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + const char *arg2 = gsi::arg_reader() (args, heap); + int arg3 = gsi::arg_reader() (args, heap); + ret.write ((QString)QUiLoader::tr (arg1, arg2, arg3)); +} + + +// static QString QUiLoader::trUtf8(const char *s, const char *c) + + +static void _init_f_trUtf8_3354 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("s"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("c", true, "0"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_trUtf8_3354 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + const char *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + ret.write ((QString)QUiLoader::trUtf8 (arg1, arg2)); +} + + +// static QString QUiLoader::trUtf8(const char *s, const char *c, int n) + + +static void _init_f_trUtf8_4013 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("s"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("c"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("n"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_trUtf8_4013 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + const char *arg2 = gsi::arg_reader() (args, heap); + int arg3 = gsi::arg_reader() (args, heap); + ret.write ((QString)QUiLoader::trUtf8 (arg1, arg2, arg3)); +} + + +namespace gsi +{ + +static gsi::Methods methods_QUiLoader () { + gsi::Methods methods; + methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo); + methods += new qt_gsi::GenericMethod ("addPluginPath", "@brief Method void QUiLoader::addPluginPath(const QString &path)\n", false, &_init_f_addPluginPath_2025, &_call_f_addPluginPath_2025); + methods += new qt_gsi::GenericMethod ("availableLayouts", "@brief Method QStringList QUiLoader::availableLayouts()\n", true, &_init_f_availableLayouts_c0, &_call_f_availableLayouts_c0); + methods += new qt_gsi::GenericMethod ("availableWidgets", "@brief Method QStringList QUiLoader::availableWidgets()\n", true, &_init_f_availableWidgets_c0, &_call_f_availableWidgets_c0); + methods += new qt_gsi::GenericMethod ("clearPluginPaths", "@brief Method void QUiLoader::clearPluginPaths()\n", false, &_init_f_clearPluginPaths_0, &_call_f_clearPluginPaths_0); + methods += new qt_gsi::GenericMethod ("createAction", "@brief Method QAction *QUiLoader::createAction(QObject *parent, const QString &name)\n", false, &_init_f_createAction_3219, &_call_f_createAction_3219); + methods += new qt_gsi::GenericMethod ("createActionGroup", "@brief Method QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)\n", false, &_init_f_createActionGroup_3219, &_call_f_createActionGroup_3219); + methods += new qt_gsi::GenericMethod ("createLayout", "@brief Method QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)\n", false, &_init_f_createLayout_5136, &_call_f_createLayout_5136); + methods += new qt_gsi::GenericMethod ("createWidget", "@brief Method QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)\n", false, &_init_f_createWidget_5149, &_call_f_createWidget_5149); + methods += new qt_gsi::GenericMethod ("isLanguageChangeEnabled?", "@brief Method bool QUiLoader::isLanguageChangeEnabled()\n", true, &_init_f_isLanguageChangeEnabled_c0, &_call_f_isLanguageChangeEnabled_c0); + methods += new qt_gsi::GenericMethod ("isScriptingEnabled?", "@brief Method bool QUiLoader::isScriptingEnabled()\n", true, &_init_f_isScriptingEnabled_c0, &_call_f_isScriptingEnabled_c0); + methods += new qt_gsi::GenericMethod ("isTranslationEnabled?", "@brief Method bool QUiLoader::isTranslationEnabled()\n", true, &_init_f_isTranslationEnabled_c0, &_call_f_isTranslationEnabled_c0); + methods += new qt_gsi::GenericMethod ("load", "@brief Method QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)\n", false, &_init_f_load_2654, &_call_f_load_2654); + methods += new qt_gsi::GenericMethod ("pluginPaths", "@brief Method QStringList QUiLoader::pluginPaths()\n", true, &_init_f_pluginPaths_c0, &_call_f_pluginPaths_c0); + methods += new qt_gsi::GenericMethod ("setLanguageChangeEnabled", "@brief Method void QUiLoader::setLanguageChangeEnabled(bool enabled)\n", false, &_init_f_setLanguageChangeEnabled_864, &_call_f_setLanguageChangeEnabled_864); + methods += new qt_gsi::GenericMethod ("setScriptingEnabled", "@brief Method void QUiLoader::setScriptingEnabled(bool enabled)\n", false, &_init_f_setScriptingEnabled_864, &_call_f_setScriptingEnabled_864); + methods += new qt_gsi::GenericMethod ("setTranslationEnabled", "@brief Method void QUiLoader::setTranslationEnabled(bool enabled)\n", false, &_init_f_setTranslationEnabled_864, &_call_f_setTranslationEnabled_864); + methods += new qt_gsi::GenericMethod ("setWorkingDirectory", "@brief Method void QUiLoader::setWorkingDirectory(const QDir &dir)\n", false, &_init_f_setWorkingDirectory_1681, &_call_f_setWorkingDirectory_1681); + methods += new qt_gsi::GenericMethod ("workingDirectory", "@brief Method QDir QUiLoader::workingDirectory()\n", true, &_init_f_workingDirectory_c0, &_call_f_workingDirectory_c0); + methods += new qt_gsi::GenericStaticMethod ("tr", "@brief Static method QString QUiLoader::tr(const char *s, const char *c)\nThis method is static and can be called without an instance.", &_init_f_tr_3354, &_call_f_tr_3354); + methods += new qt_gsi::GenericStaticMethod ("tr", "@brief Static method QString QUiLoader::tr(const char *s, const char *c, int n)\nThis method is static and can be called without an instance.", &_init_f_tr_4013, &_call_f_tr_4013); + methods += new qt_gsi::GenericStaticMethod ("trUtf8", "@brief Static method QString QUiLoader::trUtf8(const char *s, const char *c)\nThis method is static and can be called without an instance.", &_init_f_trUtf8_3354, &_call_f_trUtf8_3354); + methods += new qt_gsi::GenericStaticMethod ("trUtf8", "@brief Static method QString QUiLoader::trUtf8(const char *s, const char *c, int n)\nThis method is static and can be called without an instance.", &_init_f_trUtf8_4013, &_call_f_trUtf8_4013); + return methods; +} + +gsi::Class &qtdecl_QObject (); + +qt_gsi::QtNativeClass decl_QUiLoader (qtdecl_QObject (), "QtUiTools", "QUiLoader_Native", + methods_QUiLoader (), + "@hide\n@alias QUiLoader"); + +GSI_QTUITOOLS_PUBLIC gsi::Class &qtdecl_QUiLoader () { return decl_QUiLoader; } + +} + + +class QUiLoader_Adaptor : public QUiLoader, public qt_gsi::QtObjectBase +{ +public: + + virtual ~QUiLoader_Adaptor(); + + // [adaptor ctor] QUiLoader::QUiLoader(QObject *parent) + QUiLoader_Adaptor() : QUiLoader() + { + qt_gsi::QtObjectBase::init (this); + } + + // [adaptor ctor] QUiLoader::QUiLoader(QObject *parent) + QUiLoader_Adaptor(QObject *parent) : QUiLoader(parent) + { + qt_gsi::QtObjectBase::init (this); + } + + // [expose] void QUiLoader::destroyed(QObject *) + void fp_QUiLoader_destroyed_1302 (QObject *arg1) { + QUiLoader::destroyed(arg1); + } + + // [expose] int QUiLoader::receivers(const char *signal) + int fp_QUiLoader_receivers_c1731 (const char *signal) const { + return QUiLoader::receivers(signal); + } + + // [expose] QObject *QUiLoader::sender() + QObject * fp_QUiLoader_sender_c0 () const { + return QUiLoader::sender(); + } + + // [adaptor impl] QAction *QUiLoader::createAction(QObject *parent, const QString &name) + QAction * cbs_createAction_3219_2(QObject *parent, const QString &name) + { + return QUiLoader::createAction(parent, name); + } + + virtual QAction * createAction(QObject *parent, const QString &name) + { + if (cb_createAction_3219_2.can_issue()) { + return cb_createAction_3219_2.issue(&QUiLoader_Adaptor::cbs_createAction_3219_2, parent, name); + } else { + return QUiLoader::createAction(parent, name); + } + } + + // [adaptor impl] QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) + QActionGroup * cbs_createActionGroup_3219_2(QObject *parent, const QString &name) + { + return QUiLoader::createActionGroup(parent, name); + } + + virtual QActionGroup * createActionGroup(QObject *parent, const QString &name) + { + if (cb_createActionGroup_3219_2.can_issue()) { + return cb_createActionGroup_3219_2.issue(&QUiLoader_Adaptor::cbs_createActionGroup_3219_2, parent, name); + } else { + return QUiLoader::createActionGroup(parent, name); + } + } + + // [adaptor impl] QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) + QLayout * cbs_createLayout_5136_2(const QString &className, QObject *parent, const QString &name) + { + return QUiLoader::createLayout(className, parent, name); + } + + virtual QLayout * createLayout(const QString &className, QObject *parent, const QString &name) + { + if (cb_createLayout_5136_2.can_issue()) { + return cb_createLayout_5136_2.issue(&QUiLoader_Adaptor::cbs_createLayout_5136_2, className, parent, name); + } else { + return QUiLoader::createLayout(className, parent, name); + } + } + + // [adaptor impl] QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) + QWidget * cbs_createWidget_5149_2(const QString &className, QWidget *parent, const QString &name) + { + return QUiLoader::createWidget(className, parent, name); + } + + virtual QWidget * createWidget(const QString &className, QWidget *parent, const QString &name) + { + if (cb_createWidget_5149_2.can_issue()) { + return cb_createWidget_5149_2.issue(&QUiLoader_Adaptor::cbs_createWidget_5149_2, className, parent, name); + } else { + return QUiLoader::createWidget(className, parent, name); + } + } + + // [adaptor impl] bool QUiLoader::event(QEvent *) + bool cbs_event_1217_0(QEvent *arg1) + { + return QUiLoader::event(arg1); + } + + virtual bool event(QEvent *arg1) + { + if (cb_event_1217_0.can_issue()) { + return cb_event_1217_0.issue(&QUiLoader_Adaptor::cbs_event_1217_0, arg1); + } else { + return QUiLoader::event(arg1); + } + } + + // [adaptor impl] bool QUiLoader::eventFilter(QObject *, QEvent *) + bool cbs_eventFilter_2411_0(QObject *arg1, QEvent *arg2) + { + return QUiLoader::eventFilter(arg1, arg2); + } + + virtual bool eventFilter(QObject *arg1, QEvent *arg2) + { + if (cb_eventFilter_2411_0.can_issue()) { + return cb_eventFilter_2411_0.issue(&QUiLoader_Adaptor::cbs_eventFilter_2411_0, arg1, arg2); + } else { + return QUiLoader::eventFilter(arg1, arg2); + } + } + + // [adaptor impl] void QUiLoader::childEvent(QChildEvent *) + void cbs_childEvent_1701_0(QChildEvent *arg1) + { + QUiLoader::childEvent(arg1); + } + + virtual void childEvent(QChildEvent *arg1) + { + if (cb_childEvent_1701_0.can_issue()) { + cb_childEvent_1701_0.issue(&QUiLoader_Adaptor::cbs_childEvent_1701_0, arg1); + } else { + QUiLoader::childEvent(arg1); + } + } + + // [adaptor impl] void QUiLoader::customEvent(QEvent *) + void cbs_customEvent_1217_0(QEvent *arg1) + { + QUiLoader::customEvent(arg1); + } + + virtual void customEvent(QEvent *arg1) + { + if (cb_customEvent_1217_0.can_issue()) { + cb_customEvent_1217_0.issue(&QUiLoader_Adaptor::cbs_customEvent_1217_0, arg1); + } else { + QUiLoader::customEvent(arg1); + } + } + + // [adaptor impl] void QUiLoader::disconnectNotify(const char *signal) + void cbs_disconnectNotify_1731_0(const char *signal) + { + QUiLoader::disconnectNotify(signal); + } + + virtual void disconnectNotify(const char *signal) + { + if (cb_disconnectNotify_1731_0.can_issue()) { + cb_disconnectNotify_1731_0.issue(&QUiLoader_Adaptor::cbs_disconnectNotify_1731_0, signal); + } else { + QUiLoader::disconnectNotify(signal); + } + } + + // [adaptor impl] void QUiLoader::timerEvent(QTimerEvent *) + void cbs_timerEvent_1730_0(QTimerEvent *arg1) + { + QUiLoader::timerEvent(arg1); + } + + virtual void timerEvent(QTimerEvent *arg1) + { + if (cb_timerEvent_1730_0.can_issue()) { + cb_timerEvent_1730_0.issue(&QUiLoader_Adaptor::cbs_timerEvent_1730_0, arg1); + } else { + QUiLoader::timerEvent(arg1); + } + } + + gsi::Callback cb_createAction_3219_2; + gsi::Callback cb_createActionGroup_3219_2; + gsi::Callback cb_createLayout_5136_2; + gsi::Callback cb_createWidget_5149_2; + gsi::Callback cb_event_1217_0; + gsi::Callback cb_eventFilter_2411_0; + gsi::Callback cb_childEvent_1701_0; + gsi::Callback cb_customEvent_1217_0; + gsi::Callback cb_disconnectNotify_1731_0; + gsi::Callback cb_timerEvent_1730_0; +}; + +QUiLoader_Adaptor::~QUiLoader_Adaptor() { } + +// Constructor QUiLoader::QUiLoader(QObject *parent) (adaptor class) + +static void _init_ctor_QUiLoader_Adaptor_1302 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent", true, "0"); + decl->add_arg (argspec_0); + decl->set_return_new (); +} + +static void _call_ctor_QUiLoader_Adaptor_1302 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + ret.write (new QUiLoader_Adaptor (arg1)); +} + + +// void QUiLoader::childEvent(QChildEvent *) + +static void _init_cbs_childEvent_1701_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_childEvent_1701_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QChildEvent *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_childEvent_1701_0 (arg1); +} + +static void _set_callback_cbs_childEvent_1701_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_childEvent_1701_0 = cb; +} + + +// QAction *QUiLoader::createAction(QObject *parent, const QString &name) + +static void _init_cbs_createAction_3219_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_cbs_createAction_3219_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args.read (heap); + const QString &arg2 = args.read (heap); + ret.write ((QAction *)((QUiLoader_Adaptor *)cls)->cbs_createAction_3219_2 (arg1, arg2)); +} + +static void _set_callback_cbs_createAction_3219_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createAction_3219_2 = cb; +} + + +// QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) + +static void _init_cbs_createActionGroup_3219_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_cbs_createActionGroup_3219_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args.read (heap); + const QString &arg2 = args.read (heap); + ret.write ((QActionGroup *)((QUiLoader_Adaptor *)cls)->cbs_createActionGroup_3219_2 (arg1, arg2)); +} + +static void _set_callback_cbs_createActionGroup_3219_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createActionGroup_3219_2 = cb; +} + + +// QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) + +static void _init_cbs_createLayout_5136_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_cbs_createLayout_5136_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = args.read (heap); + QObject *arg2 = args.read (heap); + const QString &arg3 = args.read (heap); + ret.write ((QLayout *)((QUiLoader_Adaptor *)cls)->cbs_createLayout_5136_2 (arg1, arg2, arg3)); +} + +static void _set_callback_cbs_createLayout_5136_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createLayout_5136_2 = cb; +} + + +// QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) + +static void _init_cbs_createWidget_5149_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_cbs_createWidget_5149_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = args.read (heap); + QWidget *arg2 = args.read (heap); + const QString &arg3 = args.read (heap); + ret.write ((QWidget *)((QUiLoader_Adaptor *)cls)->cbs_createWidget_5149_2 (arg1, arg2, arg3)); +} + +static void _set_callback_cbs_createWidget_5149_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createWidget_5149_2 = cb; +} + + +// void QUiLoader::customEvent(QEvent *) + +static void _init_cbs_customEvent_1217_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_customEvent_1217_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QEvent *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_customEvent_1217_0 (arg1); +} + +static void _set_callback_cbs_customEvent_1217_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_customEvent_1217_0 = cb; +} + + +// exposed void QUiLoader::destroyed(QObject *) + +static void _init_fp_destroyed_1302 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1", true, "0"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_fp_destroyed_1302 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->fp_QUiLoader_destroyed_1302 (arg1); +} + + +// void QUiLoader::disconnectNotify(const char *signal) + +static void _init_cbs_disconnectNotify_1731_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("signal"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_disconnectNotify_1731_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_disconnectNotify_1731_0 (arg1); +} + +static void _set_callback_cbs_disconnectNotify_1731_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_disconnectNotify_1731_0 = cb; +} + + +// bool QUiLoader::event(QEvent *) + +static void _init_cbs_event_1217_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_event_1217_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QEvent *arg1 = args.read (heap); + ret.write ((bool)((QUiLoader_Adaptor *)cls)->cbs_event_1217_0 (arg1)); +} + +static void _set_callback_cbs_event_1217_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_event_1217_0 = cb; +} + + +// bool QUiLoader::eventFilter(QObject *, QEvent *) + +static void _init_cbs_eventFilter_2411_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("arg2"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_cbs_eventFilter_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args.read (heap); + QEvent *arg2 = args.read (heap); + ret.write ((bool)((QUiLoader_Adaptor *)cls)->cbs_eventFilter_2411_0 (arg1, arg2)); +} + +static void _set_callback_cbs_eventFilter_2411_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_eventFilter_2411_0 = cb; +} + + +// exposed int QUiLoader::receivers(const char *signal) + +static void _init_fp_receivers_c1731 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("signal"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_fp_receivers_c1731 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + ret.write ((int)((QUiLoader_Adaptor *)cls)->fp_QUiLoader_receivers_c1731 (arg1)); +} + + +// exposed QObject *QUiLoader::sender() + +static void _init_fp_sender_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_fp_sender_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QObject *)((QUiLoader_Adaptor *)cls)->fp_QUiLoader_sender_c0 ()); +} + + +// void QUiLoader::timerEvent(QTimerEvent *) + +static void _init_cbs_timerEvent_1730_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_timerEvent_1730_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QTimerEvent *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_timerEvent_1730_0 (arg1); +} + +static void _set_callback_cbs_timerEvent_1730_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_timerEvent_1730_0 = cb; +} + + +namespace gsi +{ + +gsi::Class &qtdecl_QUiLoader (); + +static gsi::Methods methods_QUiLoader_Adaptor () { + gsi::Methods methods; + methods += new qt_gsi::GenericStaticMethod ("new", "@brief Constructor QUiLoader::QUiLoader(QObject *parent)\nThis method creates an object of class QUiLoader.", &_init_ctor_QUiLoader_Adaptor_1302, &_call_ctor_QUiLoader_Adaptor_1302); + methods += new qt_gsi::GenericMethod ("*childEvent", "@brief Virtual method void QUiLoader::childEvent(QChildEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_childEvent_1701_0, &_call_cbs_childEvent_1701_0); + methods += new qt_gsi::GenericMethod ("*childEvent", "@hide", false, &_init_cbs_childEvent_1701_0, &_call_cbs_childEvent_1701_0, &_set_callback_cbs_childEvent_1701_0); + methods += new qt_gsi::GenericMethod ("createAction", "@brief Virtual method QAction *QUiLoader::createAction(QObject *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createAction_3219_2, &_call_cbs_createAction_3219_2); + methods += new qt_gsi::GenericMethod ("createAction", "@hide", false, &_init_cbs_createAction_3219_2, &_call_cbs_createAction_3219_2, &_set_callback_cbs_createAction_3219_2); + methods += new qt_gsi::GenericMethod ("createActionGroup", "@brief Virtual method QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createActionGroup_3219_2, &_call_cbs_createActionGroup_3219_2); + methods += new qt_gsi::GenericMethod ("createActionGroup", "@hide", false, &_init_cbs_createActionGroup_3219_2, &_call_cbs_createActionGroup_3219_2, &_set_callback_cbs_createActionGroup_3219_2); + methods += new qt_gsi::GenericMethod ("createLayout", "@brief Virtual method QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createLayout_5136_2, &_call_cbs_createLayout_5136_2); + methods += new qt_gsi::GenericMethod ("createLayout", "@hide", false, &_init_cbs_createLayout_5136_2, &_call_cbs_createLayout_5136_2, &_set_callback_cbs_createLayout_5136_2); + methods += new qt_gsi::GenericMethod ("createWidget", "@brief Virtual method QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createWidget_5149_2, &_call_cbs_createWidget_5149_2); + methods += new qt_gsi::GenericMethod ("createWidget", "@hide", false, &_init_cbs_createWidget_5149_2, &_call_cbs_createWidget_5149_2, &_set_callback_cbs_createWidget_5149_2); + methods += new qt_gsi::GenericMethod ("*customEvent", "@brief Virtual method void QUiLoader::customEvent(QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_customEvent_1217_0, &_call_cbs_customEvent_1217_0); + methods += new qt_gsi::GenericMethod ("*customEvent", "@hide", false, &_init_cbs_customEvent_1217_0, &_call_cbs_customEvent_1217_0, &_set_callback_cbs_customEvent_1217_0); + methods += new qt_gsi::GenericMethod ("*destroyed", "@brief Method void QUiLoader::destroyed(QObject *)\nThis method is protected and can only be called from inside a derived class.", false, &_init_fp_destroyed_1302, &_call_fp_destroyed_1302); + methods += new qt_gsi::GenericMethod ("*disconnectNotify", "@brief Virtual method void QUiLoader::disconnectNotify(const char *signal)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_disconnectNotify_1731_0, &_call_cbs_disconnectNotify_1731_0); + methods += new qt_gsi::GenericMethod ("*disconnectNotify", "@hide", false, &_init_cbs_disconnectNotify_1731_0, &_call_cbs_disconnectNotify_1731_0, &_set_callback_cbs_disconnectNotify_1731_0); + methods += new qt_gsi::GenericMethod ("event", "@brief Virtual method bool QUiLoader::event(QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_event_1217_0, &_call_cbs_event_1217_0); + methods += new qt_gsi::GenericMethod ("event", "@hide", false, &_init_cbs_event_1217_0, &_call_cbs_event_1217_0, &_set_callback_cbs_event_1217_0); + methods += new qt_gsi::GenericMethod ("eventFilter", "@brief Virtual method bool QUiLoader::eventFilter(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0); + methods += new qt_gsi::GenericMethod ("eventFilter", "@hide", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0, &_set_callback_cbs_eventFilter_2411_0); + methods += new qt_gsi::GenericMethod ("*receivers", "@brief Method int QUiLoader::receivers(const char *signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_receivers_c1731, &_call_fp_receivers_c1731); + methods += new qt_gsi::GenericMethod ("*sender", "@brief Method QObject *QUiLoader::sender()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_sender_c0, &_call_fp_sender_c0); + methods += new qt_gsi::GenericMethod ("*timerEvent", "@brief Virtual method void QUiLoader::timerEvent(QTimerEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0); + methods += new qt_gsi::GenericMethod ("*timerEvent", "@hide", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0, &_set_callback_cbs_timerEvent_1730_0); + return methods; +} + +gsi::Class decl_QUiLoader_Adaptor (qtdecl_QUiLoader (), "QtUiTools", "QUiLoader", + methods_QUiLoader_Adaptor (), + "@qt\n@brief Binding of QUiLoader"); + +} + diff --git a/src/gsiqt/qt4/QtUiTools/gsiDeclQtUiToolsTypeTraits.h b/src/gsiqt/qt4/QtUiTools/gsiDeclQtUiToolsTypeTraits.h new file mode 100644 index 000000000..1f14fe99e --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/gsiDeclQtUiToolsTypeTraits.h @@ -0,0 +1,86 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** +* @file generated/gsiDeclQtUiToolsTypeTraits.h +* @brief Type traits for the Qt binding classes +* +* DO NOT EDIT THIS FILE. +* This file has been created automatically +*/ + +#ifndef _HDR_gsiDeclQtUiToolsTypeTraits +#define _HDR_gsiDeclQtUiToolsTypeTraits + +#include "gsiTypes.h" + + +struct QMetaObject; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QObject; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QObject_Adaptor; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QSysInfo; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QUiLoader; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QUiLoader_Adaptor; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class Qt_Namespace; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; +} + + +#endif diff --git a/src/gsiqt/qt4/QtUiTools/gsiQtExternals.h b/src/gsiqt/qt4/QtUiTools/gsiQtExternals.h new file mode 100644 index 000000000..789b4e182 --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/gsiQtExternals.h @@ -0,0 +1,48 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/* + External declarations for for Qt bindings + + DO NOT EDIT THIS FILE. + This file has been created automatically +*/ + +#if !defined(HDR_gsiQtUiToolsExternals) +#define HDR_gsiQtUiToolsExternals + +#include "gsiClass.h" +#include "gsiQtUiToolsCommon.h" + +class QUiLoader; + +namespace tl { template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; } + +namespace gsi { GSI_QTUITOOLS_PUBLIC gsi::Class &qtdecl_QUiLoader (); } + + +#define QT_EXTERNAL_BASE(X) gsi::qtdecl_##X(), + +#endif + diff --git a/src/gsiqt/qt4/QtUiTools/gsiQtUiToolsCommon.h b/src/gsiqt/qt4/QtUiTools/gsiQtUiToolsCommon.h new file mode 100644 index 000000000..49782546e --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/gsiQtUiToolsCommon.h @@ -0,0 +1,25 @@ +/** + * Common header for Qt binding definition library + * + * DO NOT EDIT THIS FILE. + * This file has been created automatically + */ + +#include "tlDefs.h" + +#if !defined(HDR_gsiQtUiToolsCommon_h) +# define HDR_gsiQtUiToolsCommon_h + +# ifdef MAKE_GSI_QTUITOOLS_LIBRARY +# define GSI_QTUITOOLS_PUBLIC DEF_INSIDE_PUBLIC +# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_INSIDE_PUBLIC_TEMPLATE +# define GSI_QTUITOOLS_LOCAL DEF_INSIDE_LOCAL +# else +# define GSI_QTUITOOLS_PUBLIC DEF_OUTSIDE_PUBLIC +# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_OUTSIDE_PUBLIC_TEMPLATE +# define GSI_QTUITOOLS_LOCAL DEF_OUTSIDE_LOCAL +# endif + +#define FORCE_LINK_GSI_QTUITOOLS GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f (); int _force_link_gsiQtUiTools = _force_link_gsiQtUiTools_f (); + +#endif diff --git a/src/gsiqt/qt4/QtUiTools/gsiQtUiToolsMain.cc b/src/gsiqt/qt4/QtUiTools/gsiQtUiToolsMain.cc new file mode 100644 index 000000000..fce03b11f --- /dev/null +++ b/src/gsiqt/qt4/QtUiTools/gsiQtUiToolsMain.cc @@ -0,0 +1,11 @@ +/** + * Main source file for Qt binding definition library + * + * DO NOT EDIT THIS FILE. + * This file has been created automatically + */ + +#include "gsiQtUiToolsCommon.h" + +GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f () { return 0; } + diff --git a/src/gsiqt/qt4/qt4.pro b/src/gsiqt/qt4/qt4.pro index 36c09917d..5aeee7dfd 100644 --- a/src/gsiqt/qt4/qt4.pro +++ b/src/gsiqt/qt4/qt4.pro @@ -1,16 +1,36 @@ +include($$PWD/../../klayout.pri) + TEMPLATE = subdirs SUBDIRS = \ QtCore \ - QtGui \ - QtXml \ - QtSql \ - QtNetwork \ - QtDesigner + QtGui QtGui.depends += QtCore -QtNetwork.depends += QtCore -QtSql.depends += QtCore -QtDesigner.depends += QtCore -QtXml.depends += QtCore + +equals(HAVE_QT_NETWORK, "1") { + SUBDIRS += QtNetwork + QtNetwork.depends += QtCore +} + +equals(HAVE_QT_SQL, "1") { + SUBDIRS += QtSql + QtSql.depends += QtCore +} + +equals(HAVE_QT_DESIGNER, "1") { + SUBDIRS += QtDesigner + QtDesigner.depends += QtCore +} + +equals(HAVE_QT_XML, "1") { + SUBDIRS += QtXml + QtXml.depends += QtCore +} + +equals(HAVE_QT_UITOOLS, "1") { + SUBDIRS += QtUiTools + QtUiTools.depends += QtCore +} + diff --git a/src/gsiqt/qt5/QtCore/gsiDeclQCoreApplication.cc b/src/gsiqt/qt5/QtCore/gsiDeclQCoreApplication.cc index 5d239046a..c47df8fb5 100644 --- a/src/gsiqt/qt5/QtCore/gsiDeclQCoreApplication.cc +++ b/src/gsiqt/qt5/QtCore/gsiDeclQCoreApplication.cc @@ -72,28 +72,6 @@ static void _call_f_installNativeEventFilter_3266 (const qt_gsi::GenericMethod * } -// bool QCoreApplication::notify(QObject *, QEvent *) - - -static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = gsi::arg_reader() (args, heap); - QEvent *arg2 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QCoreApplication *)cls)->notify (arg1, arg2)); -} - - // void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj) @@ -924,7 +902,6 @@ static gsi::Methods methods_QCoreApplication () { gsi::Methods methods; methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo); methods += new qt_gsi::GenericMethod ("installNativeEventFilter", "@brief Method void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)\n", false, &_init_f_installNativeEventFilter_3266, &_call_f_installNativeEventFilter_3266); - methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QCoreApplication::notify(QObject *, QEvent *)\n", false, &_init_f_notify_2411, &_call_f_notify_2411); methods += new qt_gsi::GenericMethod ("removeNativeEventFilter", "@brief Method void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj)\n", false, &_init_f_removeNativeEventFilter_3266, &_call_f_removeNativeEventFilter_3266); methods += gsi::qt_signal ("aboutToQuit()", "aboutToQuit", "@brief Signal declaration for QCoreApplication::aboutToQuit()\nYou can bind a procedure to this signal."); methods += gsi::qt_signal ("applicationNameChanged()", "applicationNameChanged", "@brief Signal declaration for QCoreApplication::applicationNameChanged()\nYou can bind a procedure to this signal."); @@ -1076,21 +1053,6 @@ public: } } - // [adaptor impl] bool QCoreApplication::notify(QObject *, QEvent *) - bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2) - { - return QCoreApplication::notify(arg1, arg2); - } - - virtual bool notify(QObject *arg1, QEvent *arg2) - { - if (cb_notify_2411_0.can_issue()) { - return cb_notify_2411_0.issue(&QCoreApplication_Adaptor::cbs_notify_2411_0, arg1, arg2); - } else { - return QCoreApplication::notify(arg1, arg2); - } - } - // [emitter impl] void QCoreApplication::objectNameChanged(const QString &objectName) void emitter_QCoreApplication_objectNameChanged_4567(const QString &objectName) { @@ -1186,7 +1148,6 @@ public: } gsi::Callback cb_eventFilter_2411_0; - gsi::Callback cb_notify_2411_0; gsi::Callback cb_childEvent_1701_0; gsi::Callback cb_customEvent_1217_0; gsi::Callback cb_disconnectNotify_2394_0; @@ -1395,32 +1356,6 @@ static void _call_fp_isSignalConnected_c2394 (const qt_gsi::GenericMethod * /*de } -// bool QCoreApplication::notify(QObject *, QEvent *) - -static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = args.read (heap); - QEvent *arg2 = args.read (heap); - ret.write ((bool)((QCoreApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2)); -} - -static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb) -{ - ((QCoreApplication_Adaptor *)cls)->cb_notify_2411_0 = cb; -} - - // emitter void QCoreApplication::objectNameChanged(const QString &objectName) static void _init_emitter_objectNameChanged_4567 (qt_gsi::GenericMethod *decl) @@ -1559,8 +1494,6 @@ static gsi::Methods methods_QCoreApplication_Adaptor () { methods += new qt_gsi::GenericMethod ("eventFilter", "@brief Virtual method bool QCoreApplication::eventFilter(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0); methods += new qt_gsi::GenericMethod ("eventFilter", "@hide", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0, &_set_callback_cbs_eventFilter_2411_0); methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QCoreApplication::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394); - methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QCoreApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0); - methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0); methods += new qt_gsi::GenericMethod ("emit_objectNameChanged", "@brief Emitter for signal void QCoreApplication::objectNameChanged(const QString &objectName)\nCall this method to emit this signal.", false, &_init_emitter_objectNameChanged_4567, &_call_emitter_objectNameChanged_4567); methods += new qt_gsi::GenericMethod ("emit_organizationDomainChanged", "@brief Emitter for signal void QCoreApplication::organizationDomainChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationDomainChanged_0, &_call_emitter_organizationDomainChanged_0); methods += new qt_gsi::GenericMethod ("emit_organizationNameChanged", "@brief Emitter for signal void QCoreApplication::organizationNameChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationNameChanged_0, &_call_emitter_organizationNameChanged_0); diff --git a/src/gsiqt/qt5/QtGui/gsiDeclQGuiApplication.cc b/src/gsiqt/qt5/QtGui/gsiDeclQGuiApplication.cc index 1bbefdc67..a8d1d07c8 100644 --- a/src/gsiqt/qt5/QtGui/gsiDeclQGuiApplication.cc +++ b/src/gsiqt/qt5/QtGui/gsiDeclQGuiApplication.cc @@ -99,28 +99,6 @@ static void _call_f_isSessionRestored_c0 (const qt_gsi::GenericMethod * /*decl*/ } -// bool QGuiApplication::notify(QObject *, QEvent *) - - -static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = gsi::arg_reader() (args, heap); - QEvent *arg2 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QGuiApplication *)cls)->notify (arg1, arg2)); -} - - // QString QGuiApplication::sessionId() @@ -831,7 +809,6 @@ static gsi::Methods methods_QGuiApplication () { methods += new qt_gsi::GenericMethod ("devicePixelRatio", "@brief Method double QGuiApplication::devicePixelRatio()\n", true, &_init_f_devicePixelRatio_c0, &_call_f_devicePixelRatio_c0); methods += new qt_gsi::GenericMethod ("isSavingSession?", "@brief Method bool QGuiApplication::isSavingSession()\n", true, &_init_f_isSavingSession_c0, &_call_f_isSavingSession_c0); methods += new qt_gsi::GenericMethod ("isSessionRestored?", "@brief Method bool QGuiApplication::isSessionRestored()\n", true, &_init_f_isSessionRestored_c0, &_call_f_isSessionRestored_c0); - methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QGuiApplication::notify(QObject *, QEvent *)\nThis is a reimplementation of QCoreApplication::notify", false, &_init_f_notify_2411, &_call_f_notify_2411); methods += new qt_gsi::GenericMethod ("sessionId", "@brief Method QString QGuiApplication::sessionId()\n", true, &_init_f_sessionId_c0, &_call_f_sessionId_c0); methods += new qt_gsi::GenericMethod ("sessionKey", "@brief Method QString QGuiApplication::sessionKey()\n", true, &_init_f_sessionKey_c0, &_call_f_sessionKey_c0); methods += gsi::qt_signal ("aboutToQuit()", "aboutToQuit", "@brief Signal declaration for QGuiApplication::aboutToQuit()\nYou can bind a procedure to this signal."); @@ -1034,21 +1011,6 @@ public: emit QGuiApplication::layoutDirectionChanged(direction); } - // [adaptor impl] bool QGuiApplication::notify(QObject *, QEvent *) - bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2) - { - return QGuiApplication::notify(arg1, arg2); - } - - virtual bool notify(QObject *arg1, QEvent *arg2) - { - if (cb_notify_2411_0.can_issue()) { - return cb_notify_2411_0.issue(&QGuiApplication_Adaptor::cbs_notify_2411_0, arg1, arg2); - } else { - return QGuiApplication::notify(arg1, arg2); - } - } - // [emitter impl] void QGuiApplication::objectNameChanged(const QString &objectName) void emitter_QGuiApplication_objectNameChanged_4567(const QString &objectName) { @@ -1168,7 +1130,6 @@ public: } gsi::Callback cb_eventFilter_2411_0; - gsi::Callback cb_notify_2411_0; gsi::Callback cb_childEvent_1701_0; gsi::Callback cb_customEvent_1217_0; gsi::Callback cb_disconnectNotify_2394_0; @@ -1495,32 +1456,6 @@ static void _call_emitter_layoutDirectionChanged_2316 (const qt_gsi::GenericMeth } -// bool QGuiApplication::notify(QObject *, QEvent *) - -static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = args.read (heap); - QEvent *arg2 = args.read (heap); - ret.write ((bool)((QGuiApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2)); -} - -static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb) -{ - ((QGuiApplication_Adaptor *)cls)->cb_notify_2411_0 = cb; -} - - // emitter void QGuiApplication::objectNameChanged(const QString &objectName) static void _init_emitter_objectNameChanged_4567 (qt_gsi::GenericMethod *decl) @@ -1738,8 +1673,6 @@ static gsi::Methods methods_QGuiApplication_Adaptor () { methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QGuiApplication::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394); methods += new qt_gsi::GenericMethod ("emit_lastWindowClosed", "@brief Emitter for signal void QGuiApplication::lastWindowClosed()\nCall this method to emit this signal.", false, &_init_emitter_lastWindowClosed_0, &_call_emitter_lastWindowClosed_0); methods += new qt_gsi::GenericMethod ("emit_layoutDirectionChanged", "@brief Emitter for signal void QGuiApplication::layoutDirectionChanged(Qt::LayoutDirection direction)\nCall this method to emit this signal.", false, &_init_emitter_layoutDirectionChanged_2316, &_call_emitter_layoutDirectionChanged_2316); - methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QGuiApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0); - methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0); methods += new qt_gsi::GenericMethod ("emit_objectNameChanged", "@brief Emitter for signal void QGuiApplication::objectNameChanged(const QString &objectName)\nCall this method to emit this signal.", false, &_init_emitter_objectNameChanged_4567, &_call_emitter_objectNameChanged_4567); methods += new qt_gsi::GenericMethod ("emit_organizationDomainChanged", "@brief Emitter for signal void QGuiApplication::organizationDomainChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationDomainChanged_0, &_call_emitter_organizationDomainChanged_0); methods += new qt_gsi::GenericMethod ("emit_organizationNameChanged", "@brief Emitter for signal void QGuiApplication::organizationNameChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationNameChanged_0, &_call_emitter_organizationNameChanged_0); diff --git a/src/gsiqt/qt5/QtUiTools/QtUiTools.pri b/src/gsiqt/qt5/QtUiTools/QtUiTools.pri new file mode 100644 index 000000000..616643bc8 --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/QtUiTools.pri @@ -0,0 +1,13 @@ +# +# Partial QMAKE project file for Qt bindings +# +# DO NOT EDIT THIS FILE. +# This file has been created automatically +# + +SOURCES += \ + gsiQtUiToolsMain.cc \ + $$PWD/gsiDeclQUiLoader.cc + +HEADERS += gsiQtUiToolsCommon.h + diff --git a/src/gsiqt/qt5/QtUiTools/QtUiTools.pro b/src/gsiqt/qt5/QtUiTools/QtUiTools.pro new file mode 100644 index 000000000..eec9abbec --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/QtUiTools.pro @@ -0,0 +1,20 @@ + + +DESTDIR = $$OUT_PWD/../../.. +TARGET = klayout_QtUiTools + +include($$PWD/../../../lib.pri) + +DEFINES += MAKE_GSI_QTUITOOLS_LIBRARY + +INCLUDEPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC +DEPENDPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC + +LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_qtbasic -lklayout_QtCore + +SOURCES += \ + +HEADERS += \ + +include(QtUiTools.pri) + diff --git a/src/gsiqt/qt5/QtUiTools/gsiDeclQUiLoader.cc b/src/gsiqt/qt5/QtUiTools/gsiDeclQUiLoader.cc new file mode 100644 index 000000000..90698b958 --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/gsiDeclQUiLoader.cc @@ -0,0 +1,1045 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** +* @file gsiDeclQUiLoader.cc +* +* DO NOT EDIT THIS FILE. +* This file has been created automatically +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gsiQt.h" +#include "gsiQtUiToolsCommon.h" +#include "gsiDeclQtUiToolsTypeTraits.h" +#include + +// ----------------------------------------------------------------------- +// class QUiLoader + +// get static meta object + +static void _init_smo (qt_gsi::GenericStaticMethod *decl) +{ + decl->set_return (); +} + +static void _call_smo (const qt_gsi::GenericStaticMethod *, gsi::SerialArgs &, gsi::SerialArgs &ret) +{ + ret.write (QUiLoader::staticMetaObject); +} + + +// void QUiLoader::addPluginPath(const QString &path) + + +static void _init_f_addPluginPath_2025 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("path"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_addPluginPath_2025 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->addPluginPath (arg1); +} + + +// QStringList QUiLoader::availableLayouts() + + +static void _init_f_availableLayouts_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_availableLayouts_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QStringList)((QUiLoader *)cls)->availableLayouts ()); +} + + +// QStringList QUiLoader::availableWidgets() + + +static void _init_f_availableWidgets_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_availableWidgets_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QStringList)((QUiLoader *)cls)->availableWidgets ()); +} + + +// void QUiLoader::clearPluginPaths() + + +static void _init_f_clearPluginPaths_0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_clearPluginPaths_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->clearPluginPaths (); +} + + +// QAction *QUiLoader::createAction(QObject *parent, const QString &name) + + +static void _init_f_createAction_3219 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent", true, "0"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name", true, "QString()"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_createAction_3219 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QAction *)((QUiLoader *)cls)->createAction (arg1, arg2)); +} + + +// QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) + + +static void _init_f_createActionGroup_3219 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent", true, "0"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name", true, "QString()"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_createActionGroup_3219 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QActionGroup *)((QUiLoader *)cls)->createActionGroup (arg1, arg2)); +} + + +// QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) + + +static void _init_f_createLayout_5136 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent", true, "0"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name", true, "QString()"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_createLayout_5136 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = gsi::arg_reader() (args, heap); + QObject *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg3 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QLayout *)((QUiLoader *)cls)->createLayout (arg1, arg2, arg3)); +} + + +// QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) + + +static void _init_f_createWidget_5149 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent", true, "0"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name", true, "QString()"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_createWidget_5149 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = gsi::arg_reader() (args, heap); + QWidget *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + const QString &arg3 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (QString(), heap); + ret.write ((QWidget *)((QUiLoader *)cls)->createWidget (arg1, arg2, arg3)); +} + + +// QString QUiLoader::errorString() + + +static void _init_f_errorString_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_errorString_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QString)((QUiLoader *)cls)->errorString ()); +} + + +// bool QUiLoader::isLanguageChangeEnabled() + + +static void _init_f_isLanguageChangeEnabled_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_isLanguageChangeEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((bool)((QUiLoader *)cls)->isLanguageChangeEnabled ()); +} + + +// bool QUiLoader::isTranslationEnabled() + + +static void _init_f_isTranslationEnabled_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_isTranslationEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((bool)((QUiLoader *)cls)->isTranslationEnabled ()); +} + + +// QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) + + +static void _init_f_load_2654 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("device"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parentWidget", true, "0"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_f_load_2654 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QIODevice *arg1 = gsi::arg_reader() (args, heap); + QWidget *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + ret.write ((QWidget *)((QUiLoader *)cls)->load (arg1, arg2)); +} + + +// QStringList QUiLoader::pluginPaths() + + +static void _init_f_pluginPaths_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_pluginPaths_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QStringList)((QUiLoader *)cls)->pluginPaths ()); +} + + +// void QUiLoader::setLanguageChangeEnabled(bool enabled) + + +static void _init_f_setLanguageChangeEnabled_864 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("enabled"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setLanguageChangeEnabled_864 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + bool arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setLanguageChangeEnabled (arg1); +} + + +// void QUiLoader::setTranslationEnabled(bool enabled) + + +static void _init_f_setTranslationEnabled_864 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("enabled"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setTranslationEnabled_864 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + bool arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setTranslationEnabled (arg1); +} + + +// void QUiLoader::setWorkingDirectory(const QDir &dir) + + +static void _init_f_setWorkingDirectory_1681 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("dir"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_f_setWorkingDirectory_1681 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QDir &arg1 = gsi::arg_reader() (args, heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader *)cls)->setWorkingDirectory (arg1); +} + + +// QDir QUiLoader::workingDirectory() + + +static void _init_f_workingDirectory_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_f_workingDirectory_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QDir)((QUiLoader *)cls)->workingDirectory ()); +} + + +// static QString QUiLoader::tr(const char *s, const char *c, int n) + + +static void _init_f_tr_4013 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("s"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("c", true, "__null"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("n", true, "-1"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_tr_4013 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + const char *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (__null, heap); + int arg3 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (-1, heap); + ret.write ((QString)QUiLoader::tr (arg1, arg2, arg3)); +} + + +// static QString QUiLoader::trUtf8(const char *s, const char *c, int n) + + +static void _init_f_trUtf8_4013 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("s"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("c", true, "__null"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("n", true, "-1"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_f_trUtf8_4013 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + const char *arg2 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (__null, heap); + int arg3 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (-1, heap); + ret.write ((QString)QUiLoader::trUtf8 (arg1, arg2, arg3)); +} + + +namespace gsi +{ + +static gsi::Methods methods_QUiLoader () { + gsi::Methods methods; + methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo); + methods += new qt_gsi::GenericMethod ("addPluginPath", "@brief Method void QUiLoader::addPluginPath(const QString &path)\n", false, &_init_f_addPluginPath_2025, &_call_f_addPluginPath_2025); + methods += new qt_gsi::GenericMethod ("availableLayouts", "@brief Method QStringList QUiLoader::availableLayouts()\n", true, &_init_f_availableLayouts_c0, &_call_f_availableLayouts_c0); + methods += new qt_gsi::GenericMethod ("availableWidgets", "@brief Method QStringList QUiLoader::availableWidgets()\n", true, &_init_f_availableWidgets_c0, &_call_f_availableWidgets_c0); + methods += new qt_gsi::GenericMethod ("clearPluginPaths", "@brief Method void QUiLoader::clearPluginPaths()\n", false, &_init_f_clearPluginPaths_0, &_call_f_clearPluginPaths_0); + methods += new qt_gsi::GenericMethod ("createAction", "@brief Method QAction *QUiLoader::createAction(QObject *parent, const QString &name)\n", false, &_init_f_createAction_3219, &_call_f_createAction_3219); + methods += new qt_gsi::GenericMethod ("createActionGroup", "@brief Method QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)\n", false, &_init_f_createActionGroup_3219, &_call_f_createActionGroup_3219); + methods += new qt_gsi::GenericMethod ("createLayout", "@brief Method QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)\n", false, &_init_f_createLayout_5136, &_call_f_createLayout_5136); + methods += new qt_gsi::GenericMethod ("createWidget", "@brief Method QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)\n", false, &_init_f_createWidget_5149, &_call_f_createWidget_5149); + methods += new qt_gsi::GenericMethod ("errorString", "@brief Method QString QUiLoader::errorString()\n", true, &_init_f_errorString_c0, &_call_f_errorString_c0); + methods += new qt_gsi::GenericMethod ("isLanguageChangeEnabled?", "@brief Method bool QUiLoader::isLanguageChangeEnabled()\n", true, &_init_f_isLanguageChangeEnabled_c0, &_call_f_isLanguageChangeEnabled_c0); + methods += new qt_gsi::GenericMethod ("isTranslationEnabled?", "@brief Method bool QUiLoader::isTranslationEnabled()\n", true, &_init_f_isTranslationEnabled_c0, &_call_f_isTranslationEnabled_c0); + methods += new qt_gsi::GenericMethod ("load", "@brief Method QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)\n", false, &_init_f_load_2654, &_call_f_load_2654); + methods += new qt_gsi::GenericMethod ("pluginPaths", "@brief Method QStringList QUiLoader::pluginPaths()\n", true, &_init_f_pluginPaths_c0, &_call_f_pluginPaths_c0); + methods += new qt_gsi::GenericMethod ("setLanguageChangeEnabled", "@brief Method void QUiLoader::setLanguageChangeEnabled(bool enabled)\n", false, &_init_f_setLanguageChangeEnabled_864, &_call_f_setLanguageChangeEnabled_864); + methods += new qt_gsi::GenericMethod ("setTranslationEnabled", "@brief Method void QUiLoader::setTranslationEnabled(bool enabled)\n", false, &_init_f_setTranslationEnabled_864, &_call_f_setTranslationEnabled_864); + methods += new qt_gsi::GenericMethod ("setWorkingDirectory", "@brief Method void QUiLoader::setWorkingDirectory(const QDir &dir)\n", false, &_init_f_setWorkingDirectory_1681, &_call_f_setWorkingDirectory_1681); + methods += new qt_gsi::GenericMethod ("workingDirectory", "@brief Method QDir QUiLoader::workingDirectory()\n", true, &_init_f_workingDirectory_c0, &_call_f_workingDirectory_c0); + methods += new qt_gsi::GenericStaticMethod ("tr", "@brief Static method QString QUiLoader::tr(const char *s, const char *c, int n)\nThis method is static and can be called without an instance.", &_init_f_tr_4013, &_call_f_tr_4013); + methods += new qt_gsi::GenericStaticMethod ("trUtf8", "@brief Static method QString QUiLoader::trUtf8(const char *s, const char *c, int n)\nThis method is static and can be called without an instance.", &_init_f_trUtf8_4013, &_call_f_trUtf8_4013); + return methods; +} + +gsi::Class &qtdecl_QObject (); + +qt_gsi::QtNativeClass decl_QUiLoader (qtdecl_QObject (), "QtUiTools", "QUiLoader_Native", + methods_QUiLoader (), + "@hide\n@alias QUiLoader"); + +GSI_QTUITOOLS_PUBLIC gsi::Class &qtdecl_QUiLoader () { return decl_QUiLoader; } + +} + + +class QUiLoader_Adaptor : public QUiLoader, public qt_gsi::QtObjectBase +{ +public: + + virtual ~QUiLoader_Adaptor(); + + // [adaptor ctor] QUiLoader::QUiLoader(QObject *parent) + QUiLoader_Adaptor() : QUiLoader() + { + qt_gsi::QtObjectBase::init (this); + } + + // [adaptor ctor] QUiLoader::QUiLoader(QObject *parent) + QUiLoader_Adaptor(QObject *parent) : QUiLoader(parent) + { + qt_gsi::QtObjectBase::init (this); + } + + // [expose] bool QUiLoader::isSignalConnected(const QMetaMethod &signal) + bool fp_QUiLoader_isSignalConnected_c2394 (const QMetaMethod &signal) const { + return QUiLoader::isSignalConnected(signal); + } + + // [expose] int QUiLoader::receivers(const char *signal) + int fp_QUiLoader_receivers_c1731 (const char *signal) const { + return QUiLoader::receivers(signal); + } + + // [expose] QObject *QUiLoader::sender() + QObject * fp_QUiLoader_sender_c0 () const { + return QUiLoader::sender(); + } + + // [expose] int QUiLoader::senderSignalIndex() + int fp_QUiLoader_senderSignalIndex_c0 () const { + return QUiLoader::senderSignalIndex(); + } + + // [adaptor impl] QAction *QUiLoader::createAction(QObject *parent, const QString &name) + QAction * cbs_createAction_3219_2(QObject *parent, const QString &name) + { + return QUiLoader::createAction(parent, name); + } + + virtual QAction * createAction(QObject *parent, const QString &name) + { + if (cb_createAction_3219_2.can_issue()) { + return cb_createAction_3219_2.issue(&QUiLoader_Adaptor::cbs_createAction_3219_2, parent, name); + } else { + return QUiLoader::createAction(parent, name); + } + } + + // [adaptor impl] QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) + QActionGroup * cbs_createActionGroup_3219_2(QObject *parent, const QString &name) + { + return QUiLoader::createActionGroup(parent, name); + } + + virtual QActionGroup * createActionGroup(QObject *parent, const QString &name) + { + if (cb_createActionGroup_3219_2.can_issue()) { + return cb_createActionGroup_3219_2.issue(&QUiLoader_Adaptor::cbs_createActionGroup_3219_2, parent, name); + } else { + return QUiLoader::createActionGroup(parent, name); + } + } + + // [adaptor impl] QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) + QLayout * cbs_createLayout_5136_2(const QString &className, QObject *parent, const QString &name) + { + return QUiLoader::createLayout(className, parent, name); + } + + virtual QLayout * createLayout(const QString &className, QObject *parent, const QString &name) + { + if (cb_createLayout_5136_2.can_issue()) { + return cb_createLayout_5136_2.issue(&QUiLoader_Adaptor::cbs_createLayout_5136_2, className, parent, name); + } else { + return QUiLoader::createLayout(className, parent, name); + } + } + + // [adaptor impl] QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) + QWidget * cbs_createWidget_5149_2(const QString &className, QWidget *parent, const QString &name) + { + return QUiLoader::createWidget(className, parent, name); + } + + virtual QWidget * createWidget(const QString &className, QWidget *parent, const QString &name) + { + if (cb_createWidget_5149_2.can_issue()) { + return cb_createWidget_5149_2.issue(&QUiLoader_Adaptor::cbs_createWidget_5149_2, className, parent, name); + } else { + return QUiLoader::createWidget(className, parent, name); + } + } + + // [adaptor impl] bool QUiLoader::event(QEvent *) + bool cbs_event_1217_0(QEvent *arg1) + { + return QUiLoader::event(arg1); + } + + virtual bool event(QEvent *arg1) + { + if (cb_event_1217_0.can_issue()) { + return cb_event_1217_0.issue(&QUiLoader_Adaptor::cbs_event_1217_0, arg1); + } else { + return QUiLoader::event(arg1); + } + } + + // [adaptor impl] bool QUiLoader::eventFilter(QObject *, QEvent *) + bool cbs_eventFilter_2411_0(QObject *arg1, QEvent *arg2) + { + return QUiLoader::eventFilter(arg1, arg2); + } + + virtual bool eventFilter(QObject *arg1, QEvent *arg2) + { + if (cb_eventFilter_2411_0.can_issue()) { + return cb_eventFilter_2411_0.issue(&QUiLoader_Adaptor::cbs_eventFilter_2411_0, arg1, arg2); + } else { + return QUiLoader::eventFilter(arg1, arg2); + } + } + + // [adaptor impl] void QUiLoader::childEvent(QChildEvent *) + void cbs_childEvent_1701_0(QChildEvent *arg1) + { + QUiLoader::childEvent(arg1); + } + + virtual void childEvent(QChildEvent *arg1) + { + if (cb_childEvent_1701_0.can_issue()) { + cb_childEvent_1701_0.issue(&QUiLoader_Adaptor::cbs_childEvent_1701_0, arg1); + } else { + QUiLoader::childEvent(arg1); + } + } + + // [adaptor impl] void QUiLoader::customEvent(QEvent *) + void cbs_customEvent_1217_0(QEvent *arg1) + { + QUiLoader::customEvent(arg1); + } + + virtual void customEvent(QEvent *arg1) + { + if (cb_customEvent_1217_0.can_issue()) { + cb_customEvent_1217_0.issue(&QUiLoader_Adaptor::cbs_customEvent_1217_0, arg1); + } else { + QUiLoader::customEvent(arg1); + } + } + + // [adaptor impl] void QUiLoader::disconnectNotify(const QMetaMethod &signal) + void cbs_disconnectNotify_2394_0(const QMetaMethod &signal) + { + QUiLoader::disconnectNotify(signal); + } + + virtual void disconnectNotify(const QMetaMethod &signal) + { + if (cb_disconnectNotify_2394_0.can_issue()) { + cb_disconnectNotify_2394_0.issue(&QUiLoader_Adaptor::cbs_disconnectNotify_2394_0, signal); + } else { + QUiLoader::disconnectNotify(signal); + } + } + + // [adaptor impl] void QUiLoader::timerEvent(QTimerEvent *) + void cbs_timerEvent_1730_0(QTimerEvent *arg1) + { + QUiLoader::timerEvent(arg1); + } + + virtual void timerEvent(QTimerEvent *arg1) + { + if (cb_timerEvent_1730_0.can_issue()) { + cb_timerEvent_1730_0.issue(&QUiLoader_Adaptor::cbs_timerEvent_1730_0, arg1); + } else { + QUiLoader::timerEvent(arg1); + } + } + + gsi::Callback cb_createAction_3219_2; + gsi::Callback cb_createActionGroup_3219_2; + gsi::Callback cb_createLayout_5136_2; + gsi::Callback cb_createWidget_5149_2; + gsi::Callback cb_event_1217_0; + gsi::Callback cb_eventFilter_2411_0; + gsi::Callback cb_childEvent_1701_0; + gsi::Callback cb_customEvent_1217_0; + gsi::Callback cb_disconnectNotify_2394_0; + gsi::Callback cb_timerEvent_1730_0; +}; + +QUiLoader_Adaptor::~QUiLoader_Adaptor() { } + +// Constructor QUiLoader::QUiLoader(QObject *parent) (adaptor class) + +static void _init_ctor_QUiLoader_Adaptor_1302 (qt_gsi::GenericStaticMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent", true, "0"); + decl->add_arg (argspec_0); + decl->set_return_new (); +} + +static void _call_ctor_QUiLoader_Adaptor_1302 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args ? gsi::arg_reader() (args, heap) : gsi::arg_maker() (0, heap); + ret.write (new QUiLoader_Adaptor (arg1)); +} + + +// void QUiLoader::childEvent(QChildEvent *) + +static void _init_cbs_childEvent_1701_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_childEvent_1701_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QChildEvent *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_childEvent_1701_0 (arg1); +} + +static void _set_callback_cbs_childEvent_1701_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_childEvent_1701_0 = cb; +} + + +// QAction *QUiLoader::createAction(QObject *parent, const QString &name) + +static void _init_cbs_createAction_3219_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_cbs_createAction_3219_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args.read (heap); + const QString &arg2 = args.read (heap); + ret.write ((QAction *)((QUiLoader_Adaptor *)cls)->cbs_createAction_3219_2 (arg1, arg2)); +} + +static void _set_callback_cbs_createAction_3219_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createAction_3219_2 = cb; +} + + +// QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) + +static void _init_cbs_createActionGroup_3219_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("parent"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("name"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_cbs_createActionGroup_3219_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args.read (heap); + const QString &arg2 = args.read (heap); + ret.write ((QActionGroup *)((QUiLoader_Adaptor *)cls)->cbs_createActionGroup_3219_2 (arg1, arg2)); +} + +static void _set_callback_cbs_createActionGroup_3219_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createActionGroup_3219_2 = cb; +} + + +// QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) + +static void _init_cbs_createLayout_5136_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_cbs_createLayout_5136_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = args.read (heap); + QObject *arg2 = args.read (heap); + const QString &arg3 = args.read (heap); + ret.write ((QLayout *)((QUiLoader_Adaptor *)cls)->cbs_createLayout_5136_2 (arg1, arg2, arg3)); +} + +static void _set_callback_cbs_createLayout_5136_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createLayout_5136_2 = cb; +} + + +// QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) + +static void _init_cbs_createWidget_5149_2 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("className"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("parent"); + decl->add_arg (argspec_1); + static gsi::ArgSpecBase argspec_2 ("name"); + decl->add_arg (argspec_2); + decl->set_return (); +} + +static void _call_cbs_createWidget_5149_2 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QString &arg1 = args.read (heap); + QWidget *arg2 = args.read (heap); + const QString &arg3 = args.read (heap); + ret.write ((QWidget *)((QUiLoader_Adaptor *)cls)->cbs_createWidget_5149_2 (arg1, arg2, arg3)); +} + +static void _set_callback_cbs_createWidget_5149_2 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_createWidget_5149_2 = cb; +} + + +// void QUiLoader::customEvent(QEvent *) + +static void _init_cbs_customEvent_1217_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_customEvent_1217_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QEvent *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_customEvent_1217_0 (arg1); +} + +static void _set_callback_cbs_customEvent_1217_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_customEvent_1217_0 = cb; +} + + +// void QUiLoader::disconnectNotify(const QMetaMethod &signal) + +static void _init_cbs_disconnectNotify_2394_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("signal"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_disconnectNotify_2394_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QMetaMethod &arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_disconnectNotify_2394_0 (arg1); +} + +static void _set_callback_cbs_disconnectNotify_2394_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_disconnectNotify_2394_0 = cb; +} + + +// bool QUiLoader::event(QEvent *) + +static void _init_cbs_event_1217_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_event_1217_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QEvent *arg1 = args.read (heap); + ret.write ((bool)((QUiLoader_Adaptor *)cls)->cbs_event_1217_0 (arg1)); +} + +static void _set_callback_cbs_event_1217_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_event_1217_0 = cb; +} + + +// bool QUiLoader::eventFilter(QObject *, QEvent *) + +static void _init_cbs_eventFilter_2411_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + static gsi::ArgSpecBase argspec_1 ("arg2"); + decl->add_arg (argspec_1); + decl->set_return (); +} + +static void _call_cbs_eventFilter_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QObject *arg1 = args.read (heap); + QEvent *arg2 = args.read (heap); + ret.write ((bool)((QUiLoader_Adaptor *)cls)->cbs_eventFilter_2411_0 (arg1, arg2)); +} + +static void _set_callback_cbs_eventFilter_2411_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_eventFilter_2411_0 = cb; +} + + +// exposed bool QUiLoader::isSignalConnected(const QMetaMethod &signal) + +static void _init_fp_isSignalConnected_c2394 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("signal"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_fp_isSignalConnected_c2394 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const QMetaMethod &arg1 = gsi::arg_reader() (args, heap); + ret.write ((bool)((QUiLoader_Adaptor *)cls)->fp_QUiLoader_isSignalConnected_c2394 (arg1)); +} + + +// exposed int QUiLoader::receivers(const char *signal) + +static void _init_fp_receivers_c1731 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("signal"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_fp_receivers_c1731 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + const char *arg1 = gsi::arg_reader() (args, heap); + ret.write ((int)((QUiLoader_Adaptor *)cls)->fp_QUiLoader_receivers_c1731 (arg1)); +} + + +// exposed QObject *QUiLoader::sender() + +static void _init_fp_sender_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_fp_sender_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((QObject *)((QUiLoader_Adaptor *)cls)->fp_QUiLoader_sender_c0 ()); +} + + +// exposed int QUiLoader::senderSignalIndex() + +static void _init_fp_senderSignalIndex_c0 (qt_gsi::GenericMethod *decl) +{ + decl->set_return (); +} + +static void _call_fp_senderSignalIndex_c0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + ret.write ((int)((QUiLoader_Adaptor *)cls)->fp_QUiLoader_senderSignalIndex_c0 ()); +} + + +// void QUiLoader::timerEvent(QTimerEvent *) + +static void _init_cbs_timerEvent_1730_0 (qt_gsi::GenericMethod *decl) +{ + static gsi::ArgSpecBase argspec_0 ("arg1"); + decl->add_arg (argspec_0); + decl->set_return (); +} + +static void _call_cbs_timerEvent_1730_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) +{ + __SUPPRESS_UNUSED_WARNING(args); + tl::Heap heap; + QTimerEvent *arg1 = args.read (heap); + __SUPPRESS_UNUSED_WARNING(ret); + ((QUiLoader_Adaptor *)cls)->cbs_timerEvent_1730_0 (arg1); +} + +static void _set_callback_cbs_timerEvent_1730_0 (void *cls, const gsi::Callback &cb) +{ + ((QUiLoader_Adaptor *)cls)->cb_timerEvent_1730_0 = cb; +} + + +namespace gsi +{ + +gsi::Class &qtdecl_QUiLoader (); + +static gsi::Methods methods_QUiLoader_Adaptor () { + gsi::Methods methods; + methods += new qt_gsi::GenericStaticMethod ("new", "@brief Constructor QUiLoader::QUiLoader(QObject *parent)\nThis method creates an object of class QUiLoader.", &_init_ctor_QUiLoader_Adaptor_1302, &_call_ctor_QUiLoader_Adaptor_1302); + methods += new qt_gsi::GenericMethod ("*childEvent", "@brief Virtual method void QUiLoader::childEvent(QChildEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_childEvent_1701_0, &_call_cbs_childEvent_1701_0); + methods += new qt_gsi::GenericMethod ("*childEvent", "@hide", false, &_init_cbs_childEvent_1701_0, &_call_cbs_childEvent_1701_0, &_set_callback_cbs_childEvent_1701_0); + methods += new qt_gsi::GenericMethod ("createAction", "@brief Virtual method QAction *QUiLoader::createAction(QObject *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createAction_3219_2, &_call_cbs_createAction_3219_2); + methods += new qt_gsi::GenericMethod ("createAction", "@hide", false, &_init_cbs_createAction_3219_2, &_call_cbs_createAction_3219_2, &_set_callback_cbs_createAction_3219_2); + methods += new qt_gsi::GenericMethod ("createActionGroup", "@brief Virtual method QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createActionGroup_3219_2, &_call_cbs_createActionGroup_3219_2); + methods += new qt_gsi::GenericMethod ("createActionGroup", "@hide", false, &_init_cbs_createActionGroup_3219_2, &_call_cbs_createActionGroup_3219_2, &_set_callback_cbs_createActionGroup_3219_2); + methods += new qt_gsi::GenericMethod ("createLayout", "@brief Virtual method QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createLayout_5136_2, &_call_cbs_createLayout_5136_2); + methods += new qt_gsi::GenericMethod ("createLayout", "@hide", false, &_init_cbs_createLayout_5136_2, &_call_cbs_createLayout_5136_2, &_set_callback_cbs_createLayout_5136_2); + methods += new qt_gsi::GenericMethod ("createWidget", "@brief Virtual method QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_createWidget_5149_2, &_call_cbs_createWidget_5149_2); + methods += new qt_gsi::GenericMethod ("createWidget", "@hide", false, &_init_cbs_createWidget_5149_2, &_call_cbs_createWidget_5149_2, &_set_callback_cbs_createWidget_5149_2); + methods += new qt_gsi::GenericMethod ("*customEvent", "@brief Virtual method void QUiLoader::customEvent(QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_customEvent_1217_0, &_call_cbs_customEvent_1217_0); + methods += new qt_gsi::GenericMethod ("*customEvent", "@hide", false, &_init_cbs_customEvent_1217_0, &_call_cbs_customEvent_1217_0, &_set_callback_cbs_customEvent_1217_0); + methods += new qt_gsi::GenericMethod ("*disconnectNotify", "@brief Virtual method void QUiLoader::disconnectNotify(const QMetaMethod &signal)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_disconnectNotify_2394_0, &_call_cbs_disconnectNotify_2394_0); + methods += new qt_gsi::GenericMethod ("*disconnectNotify", "@hide", false, &_init_cbs_disconnectNotify_2394_0, &_call_cbs_disconnectNotify_2394_0, &_set_callback_cbs_disconnectNotify_2394_0); + methods += new qt_gsi::GenericMethod ("event", "@brief Virtual method bool QUiLoader::event(QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_event_1217_0, &_call_cbs_event_1217_0); + methods += new qt_gsi::GenericMethod ("event", "@hide", false, &_init_cbs_event_1217_0, &_call_cbs_event_1217_0, &_set_callback_cbs_event_1217_0); + methods += new qt_gsi::GenericMethod ("eventFilter", "@brief Virtual method bool QUiLoader::eventFilter(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0); + methods += new qt_gsi::GenericMethod ("eventFilter", "@hide", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0, &_set_callback_cbs_eventFilter_2411_0); + methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QUiLoader::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394); + methods += new qt_gsi::GenericMethod ("*receivers", "@brief Method int QUiLoader::receivers(const char *signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_receivers_c1731, &_call_fp_receivers_c1731); + methods += new qt_gsi::GenericMethod ("*sender", "@brief Method QObject *QUiLoader::sender()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_sender_c0, &_call_fp_sender_c0); + methods += new qt_gsi::GenericMethod ("*senderSignalIndex", "@brief Method int QUiLoader::senderSignalIndex()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_senderSignalIndex_c0, &_call_fp_senderSignalIndex_c0); + methods += new qt_gsi::GenericMethod ("*timerEvent", "@brief Virtual method void QUiLoader::timerEvent(QTimerEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0); + methods += new qt_gsi::GenericMethod ("*timerEvent", "@hide", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0, &_set_callback_cbs_timerEvent_1730_0); + return methods; +} + +gsi::Class decl_QUiLoader_Adaptor (qtdecl_QUiLoader (), "QtUiTools", "QUiLoader", + methods_QUiLoader_Adaptor (), + "@qt\n@brief Binding of QUiLoader"); + +} + diff --git a/src/gsiqt/qt5/QtUiTools/gsiDeclQtUiToolsTypeTraits.h b/src/gsiqt/qt5/QtUiTools/gsiDeclQtUiToolsTypeTraits.h new file mode 100644 index 000000000..85928cc3b --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/gsiDeclQtUiToolsTypeTraits.h @@ -0,0 +1,138 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** +* @file generated/gsiDeclQtUiToolsTypeTraits.h +* @brief Type traits for the Qt binding classes +* +* DO NOT EDIT THIS FILE. +* This file has been created automatically +*/ + +#ifndef _HDR_gsiDeclQtUiToolsTypeTraits +#define _HDR_gsiDeclQtUiToolsTypeTraits + +#include "gsiTypes.h" + + +struct QByteArrayDataPtr; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QMessageLogContext; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QMessageLogger; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +struct QMetaObject; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +#include +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QObject; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QObject_Adaptor; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QRegExp; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QSignalBlocker; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; +} + +struct QStringDataPtr; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QStringMatcher; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QSysInfo; +namespace tl { +template <> struct type_traits : public type_traits { +}; +} + +class QUiLoader; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class QUiLoader_Adaptor; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; +} + +class Qt_Namespace; +namespace tl { +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; +} + + +#endif diff --git a/src/gsiqt/qt5/QtUiTools/gsiQtExternals.h b/src/gsiqt/qt5/QtUiTools/gsiQtExternals.h new file mode 100644 index 000000000..789b4e182 --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/gsiQtExternals.h @@ -0,0 +1,48 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/* + External declarations for for Qt bindings + + DO NOT EDIT THIS FILE. + This file has been created automatically +*/ + +#if !defined(HDR_gsiQtUiToolsExternals) +#define HDR_gsiQtUiToolsExternals + +#include "gsiClass.h" +#include "gsiQtUiToolsCommon.h" + +class QUiLoader; + +namespace tl { template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; +}; } + +namespace gsi { GSI_QTUITOOLS_PUBLIC gsi::Class &qtdecl_QUiLoader (); } + + +#define QT_EXTERNAL_BASE(X) gsi::qtdecl_##X(), + +#endif + diff --git a/src/gsiqt/qt5/QtUiTools/gsiQtUiToolsCommon.h b/src/gsiqt/qt5/QtUiTools/gsiQtUiToolsCommon.h new file mode 100644 index 000000000..49782546e --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/gsiQtUiToolsCommon.h @@ -0,0 +1,25 @@ +/** + * Common header for Qt binding definition library + * + * DO NOT EDIT THIS FILE. + * This file has been created automatically + */ + +#include "tlDefs.h" + +#if !defined(HDR_gsiQtUiToolsCommon_h) +# define HDR_gsiQtUiToolsCommon_h + +# ifdef MAKE_GSI_QTUITOOLS_LIBRARY +# define GSI_QTUITOOLS_PUBLIC DEF_INSIDE_PUBLIC +# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_INSIDE_PUBLIC_TEMPLATE +# define GSI_QTUITOOLS_LOCAL DEF_INSIDE_LOCAL +# else +# define GSI_QTUITOOLS_PUBLIC DEF_OUTSIDE_PUBLIC +# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_OUTSIDE_PUBLIC_TEMPLATE +# define GSI_QTUITOOLS_LOCAL DEF_OUTSIDE_LOCAL +# endif + +#define FORCE_LINK_GSI_QTUITOOLS GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f (); int _force_link_gsiQtUiTools = _force_link_gsiQtUiTools_f (); + +#endif diff --git a/src/gsiqt/qt5/QtUiTools/gsiQtUiToolsMain.cc b/src/gsiqt/qt5/QtUiTools/gsiQtUiToolsMain.cc new file mode 100644 index 000000000..fce03b11f --- /dev/null +++ b/src/gsiqt/qt5/QtUiTools/gsiQtUiToolsMain.cc @@ -0,0 +1,11 @@ +/** + * Main source file for Qt binding definition library + * + * DO NOT EDIT THIS FILE. + * This file has been created automatically + */ + +#include "gsiQtUiToolsCommon.h" + +GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f () { return 0; } + diff --git a/src/gsiqt/qt5/QtWidgets/gsiDeclQApplication.cc b/src/gsiqt/qt5/QtWidgets/gsiDeclQApplication.cc index d50d182d1..3b90953fd 100644 --- a/src/gsiqt/qt5/QtWidgets/gsiDeclQApplication.cc +++ b/src/gsiqt/qt5/QtWidgets/gsiDeclQApplication.cc @@ -69,28 +69,6 @@ static void _call_f_autoSipEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, v } -// bool QApplication::notify(QObject *, QEvent *) - - -static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = gsi::arg_reader() (args, heap); - QEvent *arg2 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QApplication *)cls)->notify (arg1, arg2)); -} - - // void QApplication::setAutoSipEnabled(const bool enabled) @@ -1074,7 +1052,6 @@ static gsi::Methods methods_QApplication () { gsi::Methods methods; methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo); methods += new qt_gsi::GenericMethod (":autoSipEnabled", "@brief Method bool QApplication::autoSipEnabled()\n", true, &_init_f_autoSipEnabled_c0, &_call_f_autoSipEnabled_c0); - methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QApplication::notify(QObject *, QEvent *)\nThis is a reimplementation of QGuiApplication::notify", false, &_init_f_notify_2411, &_call_f_notify_2411); methods += new qt_gsi::GenericMethod ("setAutoSipEnabled|autoSipEnabled=", "@brief Method void QApplication::setAutoSipEnabled(const bool enabled)\n", false, &_init_f_setAutoSipEnabled_1559, &_call_f_setAutoSipEnabled_1559); methods += new qt_gsi::GenericMethod ("setStyleSheet|styleSheet=", "@brief Method void QApplication::setStyleSheet(const QString &sheet)\n", false, &_init_f_setStyleSheet_2025, &_call_f_setStyleSheet_2025); methods += new qt_gsi::GenericMethod (":styleSheet", "@brief Method QString QApplication::styleSheet()\n", true, &_init_f_styleSheet_c0, &_call_f_styleSheet_c0); @@ -1296,21 +1273,6 @@ public: emit QApplication::layoutDirectionChanged(direction); } - // [adaptor impl] bool QApplication::notify(QObject *, QEvent *) - bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2) - { - return QApplication::notify(arg1, arg2); - } - - virtual bool notify(QObject *arg1, QEvent *arg2) - { - if (cb_notify_2411_0.can_issue()) { - return cb_notify_2411_0.issue(&QApplication_Adaptor::cbs_notify_2411_0, arg1, arg2); - } else { - return QApplication::notify(arg1, arg2); - } - } - // [emitter impl] void QApplication::objectNameChanged(const QString &objectName) void emitter_QApplication_objectNameChanged_4567(const QString &objectName) { @@ -1430,7 +1392,6 @@ public: } gsi::Callback cb_eventFilter_2411_0; - gsi::Callback cb_notify_2411_0; gsi::Callback cb_childEvent_1701_0; gsi::Callback cb_customEvent_1217_0; gsi::Callback cb_disconnectNotify_2394_0; @@ -1778,32 +1739,6 @@ static void _call_emitter_layoutDirectionChanged_2316 (const qt_gsi::GenericMeth } -// bool QApplication::notify(QObject *, QEvent *) - -static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - static gsi::ArgSpecBase argspec_1 ("arg2"); - decl->add_arg (argspec_1); - decl->set_return (); -} - -static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - QObject *arg1 = args.read (heap); - QEvent *arg2 = args.read (heap); - ret.write ((bool)((QApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2)); -} - -static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb) -{ - ((QApplication_Adaptor *)cls)->cb_notify_2411_0 = cb; -} - - // emitter void QApplication::objectNameChanged(const QString &objectName) static void _init_emitter_objectNameChanged_4567 (qt_gsi::GenericMethod *decl) @@ -2022,8 +1957,6 @@ static gsi::Methods methods_QApplication_Adaptor () { methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QApplication::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394); methods += new qt_gsi::GenericMethod ("emit_lastWindowClosed", "@brief Emitter for signal void QApplication::lastWindowClosed()\nCall this method to emit this signal.", false, &_init_emitter_lastWindowClosed_0, &_call_emitter_lastWindowClosed_0); methods += new qt_gsi::GenericMethod ("emit_layoutDirectionChanged", "@brief Emitter for signal void QApplication::layoutDirectionChanged(Qt::LayoutDirection direction)\nCall this method to emit this signal.", false, &_init_emitter_layoutDirectionChanged_2316, &_call_emitter_layoutDirectionChanged_2316); - methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0); - methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0); methods += new qt_gsi::GenericMethod ("emit_objectNameChanged", "@brief Emitter for signal void QApplication::objectNameChanged(const QString &objectName)\nCall this method to emit this signal.", false, &_init_emitter_objectNameChanged_4567, &_call_emitter_objectNameChanged_4567); methods += new qt_gsi::GenericMethod ("emit_organizationDomainChanged", "@brief Emitter for signal void QApplication::organizationDomainChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationDomainChanged_0, &_call_emitter_organizationDomainChanged_0); methods += new qt_gsi::GenericMethod ("emit_organizationNameChanged", "@brief Emitter for signal void QApplication::organizationNameChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationNameChanged_0, &_call_emitter_organizationNameChanged_0); diff --git a/src/gsiqt/qt5/qt5.pro b/src/gsiqt/qt5/qt5.pro index 5a435a3b8..710001c57 100644 --- a/src/gsiqt/qt5/qt5.pro +++ b/src/gsiqt/qt5/qt5.pro @@ -1,26 +1,53 @@ +include($$PWD/../../klayout.pri) + TEMPLATE = subdirs SUBDIRS = \ QtCore \ QtGui \ - QtNetwork \ - QtSql \ - QtWidgets \ - QtDesigner \ - QtMultimedia \ - QtPrintSupport \ - QtSvg \ - QtXmlPatterns \ - QtXml + QtWidgets QtGui.depends += QtCore -QtNetwork.depends += QtCore -QtSql.depends += QtCore QtWidgets.depends += QtGui -QtDesigner.depends += QtCore -QtMultimedia.depends += QtCore QtWidgets QtNetwork -QtPrintSupport.depends += QtCore QtWidgets -QtSvg.depends += QtCore QtWidgets -QtXmlPatterns.depends += QtCore -QtXml.depends += QtCore + +equals(HAVE_QT_NETWORK, "1") { + SUBDIRS += QtNetwork + QtNetwork.depends += QtCore +} + +equals(HAVE_QT_SQL, "1") { + SUBDIRS += QtSql + QtSql.depends += QtCore +} + +equals(HAVE_QT_SVG, "1") { + SUBDIRS += QtSvg + QtSvg.depends += QtCore QtWidgets +} + +equals(HAVE_QT_PRINTSUPPORT, "1") { + SUBDIRS += QtPrintSupport + QtPrintSupport.depends += QtCore QtWidgets +} + +equals(HAVE_QT_MULTIMEDIA, "1") { + SUBDIRS += QtMultimedia + QtMultimedia.depends += QtCore QtWidgets QtNetwork +} + +equals(HAVE_QT_DESIGNER, "1") { + SUBDIRS += QtDesigner + QtDesigner.depends += QtCore +} + +equals(HAVE_QT_XML, "1") { + SUBDIRS += QtXml QtXmlPatterns + QtXmlPatterns.depends += QtCore + QtXml.depends += QtCore +} + +equals(HAVE_QT_UITOOLS, "1") { + SUBDIRS += QtUiTools + QtUiTools.depends += QtCore +} diff --git a/src/gsiqt/qtbasic/gsiQtDesignerExternals.h b/src/gsiqt/qtbasic/gsiQtDesignerExternals.h index ff9e70738..e969f0fea 100644 --- a/src/gsiqt/qtbasic/gsiQtDesignerExternals.h +++ b/src/gsiqt/qtbasic/gsiQtDesignerExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_DESIGNER) +# define FORCE_LINK_GSI_QTDESIGNER +#elif QT_VERSION >= 0x050000 # include "../qt5/QtDesigner/gsiQtExternals.h" #else # include "../qt4/QtDesigner/gsiQtExternals.h" diff --git a/src/gsiqt/qtbasic/gsiQtMultimediaExternals.h b/src/gsiqt/qtbasic/gsiQtMultimediaExternals.h index 19dc5bf3b..92f3efc62 100644 --- a/src/gsiqt/qtbasic/gsiQtMultimediaExternals.h +++ b/src/gsiqt/qtbasic/gsiQtMultimediaExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_MULTIMEDIA) +# define FORCE_LINK_GSI_QTMULTIMEDIA +#elif QT_VERSION >= 0x050000 # include "../qt5/QtMultimedia/gsiQtExternals.h" #else // no present in Qt4 diff --git a/src/gsiqt/qtbasic/gsiQtNetworkExternals.h b/src/gsiqt/qtbasic/gsiQtNetworkExternals.h index 98cd86856..d7032d221 100644 --- a/src/gsiqt/qtbasic/gsiQtNetworkExternals.h +++ b/src/gsiqt/qtbasic/gsiQtNetworkExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_NETWORK) +# define FORCE_LINK_GSI_QTNETWORK +#elif QT_VERSION >= 0x050000 # include "../qt5/QtNetwork/gsiQtExternals.h" #else # include "../qt4/QtNetwork/gsiQtExternals.h" diff --git a/src/gsiqt/qtbasic/gsiQtPrintSupportExternals.h b/src/gsiqt/qtbasic/gsiQtPrintSupportExternals.h index 267b31b70..251a3dc79 100644 --- a/src/gsiqt/qtbasic/gsiQtPrintSupportExternals.h +++ b/src/gsiqt/qtbasic/gsiQtPrintSupportExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_PRINTSUPPORT) +# define FORCE_LINK_GSI_QTPRINTSUPPORT +#elif QT_VERSION >= 0x050000 # include "../qt5/QtPrintSupport/gsiQtExternals.h" #else // no present in Qt4 diff --git a/src/gsiqt/qtbasic/gsiQtSqlExternals.h b/src/gsiqt/qtbasic/gsiQtSqlExternals.h index 0cb0a4740..b595853eb 100644 --- a/src/gsiqt/qtbasic/gsiQtSqlExternals.h +++ b/src/gsiqt/qtbasic/gsiQtSqlExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_SQL) +# define FORCE_LINK_GSI_QTSQL +#elif QT_VERSION >= 0x050000 # include "../qt5/QtSql/gsiQtExternals.h" #else # include "../qt4/QtSql/gsiQtExternals.h" diff --git a/src/gsiqt/qtbasic/gsiQtSvgExternals.h b/src/gsiqt/qtbasic/gsiQtSvgExternals.h index ccbacac80..fd6468d92 100644 --- a/src/gsiqt/qtbasic/gsiQtSvgExternals.h +++ b/src/gsiqt/qtbasic/gsiQtSvgExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_SVG) +# define FORCE_LINK_GSI_QTSVG +#elif QT_VERSION >= 0x050000 # include "../qt5/QtSvg/gsiQtExternals.h" #else // no present in Qt4 diff --git a/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h new file mode 100644 index 000000000..3b3c740c9 --- /dev/null +++ b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h @@ -0,0 +1,29 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#if !defined(HAVE_QT_UITOOLS) +# define FORCE_LINK_GSI_QTUITOOLS +#elif QT_VERSION >= 0x050000 +# include "../qt5/QtUiTools/gsiQtExternals.h" +#else +# include "../qt4/QtUiTools/gsiQtExternals.h" +#endif diff --git a/src/gsiqt/qtbasic/gsiQtXmlExternals.h b/src/gsiqt/qtbasic/gsiQtXmlExternals.h index ba1da7d32..b4713bd5c 100644 --- a/src/gsiqt/qtbasic/gsiQtXmlExternals.h +++ b/src/gsiqt/qtbasic/gsiQtXmlExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_XML) +# define FORCE_LINK_GSI_QTXML +#elif QT_VERSION >= 0x050000 # include "../qt5/QtXml/gsiQtExternals.h" #else # include "../qt4/QtXml/gsiQtExternals.h" diff --git a/src/gsiqt/qtbasic/gsiQtXmlPatternsExternals.h b/src/gsiqt/qtbasic/gsiQtXmlPatternsExternals.h index ce56bc674..e5c48f1c0 100644 --- a/src/gsiqt/qtbasic/gsiQtXmlPatternsExternals.h +++ b/src/gsiqt/qtbasic/gsiQtXmlPatternsExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_XML) +# define FORCE_LINK_GSI_QTXMLPATTERNS +#elif QT_VERSION >= 0x050000 # include "../qt5/QtXmlPatterns/gsiQtExternals.h" #else // Not present in Qt4 diff --git a/src/gsiqt/qtbasic/qtbasic.pro b/src/gsiqt/qtbasic/qtbasic.pro index 8f08982ac..cf9d23b78 100644 --- a/src/gsiqt/qtbasic/qtbasic.pro +++ b/src/gsiqt/qtbasic/qtbasic.pro @@ -17,5 +17,19 @@ SOURCES += \ gsiQtHelper.cc HEADERS += \ + gsiDeclQtAllTypeTraits.h \ gsiQt.h \ - gsiQtBasicCommon.h \ + gsiQtBasicCommon.h \ \ + gsiQtCoreExternals.h \ + gsiQtDesignerExternals.h \ + gsiQtGuiExternals.h \ + gsiQtHelper.h \ + gsiQtMultimediaExternals.h \ + gsiQtNetworkExternals.h \ + gsiQtPrintSupportExternals.h \ + gsiQtSqlExternals.h \ + gsiQtSvgExternals.h \ + gsiQtUiToolsExternals.h \ + gsiQtWidgetsExternals.h \ + gsiQtXmlExternals.h \ + gsiQtXmlPatternsExternals.h diff --git a/src/img/img/imgObject.cc b/src/img/img/imgObject.cc index 09f8e9c8e..f7b842263 100644 --- a/src/img/img/imgObject.cc +++ b/src/img/img/imgObject.cc @@ -1343,7 +1343,7 @@ Object::from_string (const char *str, const char *base_dir) tl::URI fp_uri (m_filename); if (base_dir && ! tl::is_absolute (fp_uri.path ())) { - m_filename = tl::URI (base_dir).resolved (fp_uri).to_string (); + m_filename = tl::URI (base_dir).resolved (fp_uri).to_abstract_path (); } read_file (); diff --git a/src/img/img/imgPropertiesPage.cc b/src/img/img/imgPropertiesPage.cc index 32a982836..751ea4eff 100644 --- a/src/img/img/imgPropertiesPage.cc +++ b/src/img/img/imgPropertiesPage.cc @@ -219,7 +219,7 @@ PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out) try { tl::from_string (tl::to_string (from_le->text ()), xmin); - lay::indicate_error (from_le, 0); + lay::indicate_error (from_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (from_le, &ex); has_error = true; @@ -227,7 +227,7 @@ PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out) try { tl::from_string (tl::to_string (to_le->text ()), xmax); - lay::indicate_error (to_le, 0); + lay::indicate_error (to_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (to_le, &ex); has_error = true; @@ -336,7 +336,7 @@ PropertiesPage::value_changed () double x = 0.0; try { tl::from_string (tl::to_string (value_le->text ()), x); - lay::indicate_error (value_le, 0); + lay::indicate_error (value_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (value_le, &ex); has_error = true; @@ -805,7 +805,7 @@ PropertiesPage::apply () if (w <= 0.0 || h <= 0.0) { throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values"))); } - lay::indicate_error (width_le, 0); + lay::indicate_error (width_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (width_le, &ex); has_error = true; @@ -813,7 +813,7 @@ PropertiesPage::apply () try { tl::from_string (tl::to_string (height_le->text ()), h); - lay::indicate_error (height_le, 0); + lay::indicate_error (height_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (height_le, &ex); has_error = true; @@ -821,7 +821,7 @@ PropertiesPage::apply () try { tl::from_string (tl::to_string (x_offset_le->text ()), x); - lay::indicate_error (x_offset_le, 0); + lay::indicate_error (x_offset_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (x_offset_le, &ex); has_error = true; @@ -829,7 +829,7 @@ PropertiesPage::apply () try { tl::from_string (tl::to_string (y_offset_le->text ()), y); - lay::indicate_error (y_offset_le, 0); + lay::indicate_error (y_offset_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (y_offset_le, &ex); has_error = true; @@ -837,7 +837,7 @@ PropertiesPage::apply () try { tl::from_string (tl::to_string (angle_le->text ()), a); - lay::indicate_error (angle_le, 0); + lay::indicate_error (angle_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (angle_le, &ex); has_error = true; @@ -848,7 +848,7 @@ PropertiesPage::apply () if (sa <= -45 || sa >= 45) { throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree"))); } - lay::indicate_error (shear_le, 0); + lay::indicate_error (shear_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (shear_le, &ex); has_error = true; @@ -859,7 +859,7 @@ PropertiesPage::apply () if (tx <= -90 || tx >= 90) { throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree"))); } - lay::indicate_error (persp_tx_le, 0); + lay::indicate_error (persp_tx_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (persp_tx_le, &ex); has_error = true; @@ -870,7 +870,7 @@ PropertiesPage::apply () if (ty <= -90 || ty >= 90) { throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree"))); } - lay::indicate_error (persp_ty_le, 0); + lay::indicate_error (persp_ty_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (persp_ty_le, &ex); has_error = true; diff --git a/src/klayout.pri b/src/klayout.pri index e7b3807b7..550c0cba7 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -40,6 +40,15 @@ equals(HAVE_QTBINDINGS, "1") { DEFINES += HAVE_QTBINDINGS } +!equals(HAVE_QT_UITOOLS, "0") { + # auto-select uitools, not all distributions have it + contains(QT_MODULES, "uitools") { + HAVE_QT_UITOOLS = 1 + } else { + HAVE_QT_UITOOLS = 0 + } +} + equals(HAVE_64BIT_COORD, "1") { DEFINES += HAVE_64BIT_COORD } @@ -160,18 +169,77 @@ equals(HAVE_QT, "0") { } else { DEFINES += HAVE_QT - QT += core network xml sql + QT += core xml network - equals(HAVE_QT5, "1") { - QT += designer printsupport widgets - equals(HAVE_QTBINDINGS, "1") { - QT += multimedia multimediawidgets xmlpatterns svg gui + equals(HAVE_QTBINDINGS, "1") { + # sql isn't needed by the base application + !equals(HAVE_QT_SQL, "0") { + QT += sql } - } else { - # questionable: use uitools instead? - CONFIG += designer } + equals(HAVE_QT5, "1") { + + QT += widgets gui printsupport xmlpatterns + + equals(HAVE_QTBINDINGS, "1") { + !equals(HAVE_QT_DESIGNER, "0") { + # designer isn't needed by the base application + QT += designer + } + !equals(HAVE_QT_MULTIMEDIA, "0") { + # multimedia isn't needed by the base application + QT += multimedia multimediawidgets + } + !equals(HAVE_QT_SVG, "0") { + # svg isn't needed by the base application + QT += svg + } + !equals(HAVE_QT_UITOOLS, "0") { + # uitools isn't needed by the base application + QT += uitools + } + } + + } else { + + equals(HAVE_QTBINDINGS, "1") { + !equals(HAVE_QT_DESIGNER, "0") { + # designer isn't needed by the base application + CONFIG += designer + } + !equals(HAVE_QT_UITOOLS, "0") { + # uitools isn't needed by the base application + CONFIG += uitools + } + } + + } + + !equals(HAVE_QT_UITOOLS, "0") { + DEFINES += HAVE_QT_UITOOLS + } + !equals(HAVE_QT_NETWORK, "0") { + DEFINES += HAVE_QT_NETWORK + } + !equals(HAVE_QT_SQL, "0") { + DEFINES += HAVE_QT_SQL + } + !equals(HAVE_QT_SVG, "0") { + DEFINES += HAVE_QT_SVG + } + !equals(HAVE_QT_PRINTSUPPORT, "0") { + DEFINES += HAVE_QT_PRINTSUPPORT + } + !equals(HAVE_QT_MULTIMEDIA, "0") { + DEFINES += HAVE_QT_MULTIMEDIA + } + !equals(HAVE_QT_DESIGNER, "0") { + DEFINES += HAVE_QT_DESIGNER + } + !equals(HAVE_QT_XML, "0") { + DEFINES += HAVE_QT_XML + } } VERSION_STRING = $$KLAYOUT_VERSION diff --git a/src/klayout_main/klayout_main/klayout.cc b/src/klayout_main/klayout_main/klayout.cc index fd1561980..8091c7196 100644 --- a/src/klayout_main/klayout_main/klayout.cc +++ b/src/klayout_main/klayout_main/klayout.cc @@ -51,18 +51,30 @@ // pulls in the Qt GSI binding modules # include "gsiQtGuiExternals.h" +# include "gsiQtWidgetsExternals.h" # include "gsiQtCoreExternals.h" +# include "gsiQtMultimediaExternals.h" +# include "gsiQtPrintSupportExternals.h" # include "gsiQtXmlExternals.h" +# include "gsiQtXmlPatternsExternals.h" # include "gsiQtSqlExternals.h" +# include "gsiQtSvgExternals.h" # include "gsiQtNetworkExternals.h" # include "gsiQtDesignerExternals.h" +# include "gsiQtUiToolsExternals.h" FORCE_LINK_GSI_QTCORE FORCE_LINK_GSI_QTGUI +FORCE_LINK_GSI_QTWIDGETS +FORCE_LINK_GSI_QTMULTIMEDIA +FORCE_LINK_GSI_QTPRINTSUPPORT FORCE_LINK_GSI_QTXML +FORCE_LINK_GSI_QTXMLPATTERNS FORCE_LINK_GSI_QTDESIGNER FORCE_LINK_GSI_QTNETWORK FORCE_LINK_GSI_QTSQL +FORCE_LINK_GSI_QTSVG +FORCE_LINK_GSI_QTUITOOLS #else # define QT_EXTERNAL_BASE(x) diff --git a/src/klayout_main/klayout_main/klayout_main.pro b/src/klayout_main/klayout_main/klayout_main.pro index 64abec3bd..31ab7eb22 100644 --- a/src/klayout_main/klayout_main/klayout_main.pro +++ b/src/klayout_main/klayout_main/klayout_main.pro @@ -5,6 +5,7 @@ include($$PWD/../../klayout.pri) TARGET = klayout +include($$PWD/../../klayout.pri) include($$PWD/../../app.pri) include($$PWD/../../with_all_libs.pri) @@ -25,8 +26,42 @@ INCLUDEPATH += $$QTBASIC_INC DEPENDPATH += $$QTBASIC_INC equals(HAVE_QTBINDINGS, "1") { - LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner - equals(HAVE_QT5, "1") { - LIBS += -lklayout_QtMultimedia -lklayout_QtPrintSupport -lklayout_QtSvg -lklayout_QtWidgets -lklayout_QtXmlPatterns + + LIBS += -lklayout_qtbasic -lklayout_QtGui + + !equals(HAVE_QT_XML, "0") { + LIBS += -lklayout_QtXml } + !equals(HAVE_QT_NETWORK, "0") { + LIBS += -lklayout_QtNetwork + } + !equals(HAVE_QT_SQL, "0") { + LIBS += -lklayout_QtSql + } + !equals(HAVE_QT_DESIGNER, "0") { + LIBS += -lklayout_QtDesigner + } + !equals(HAVE_QT_UITOOLS, "0") { + LIBS += -lklayout_QtUiTools + } + + equals(HAVE_QT5, "1") { + + LIBS += -lklayout_QtWidgets + + !equals(HAVE_QT_MULTIMEDIA, "0") { + LIBS += -lklayout_QtMultimedia + } + !equals(HAVE_QT_PRINTSUPPORT, "0") { + LIBS += -lklayout_QtPrintSupport + } + !equals(HAVE_QT_SVG, "0") { + LIBS += -lklayout_QtSvg + } + !equals(HAVE_QT_XML, "0") { + LIBS += -lklayout_QtXmlPatterns + } + + } + } diff --git a/src/lay/lay/MacroEditorDialog.ui b/src/lay/lay/MacroEditorDialog.ui index a166b21c9..5b2e83302 100644 --- a/src/lay/lay/MacroEditorDialog.ui +++ b/src/lay/lay/MacroEditorDialog.ui @@ -1383,63 +1383,6 @@ p, li { white-space: pre-wrap; } - - - - Qt::Horizontal - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Close - - - false - - - - - - @@ -1596,22 +1539,5 @@ p, li { white-space: pre-wrap; } - - - pushButton - clicked() - MacroEditorDialog - accept() - - - 905 - 694 - - - 929 - 696 - - - - + diff --git a/src/lay/lay/doc/programming/qt_binding.xml b/src/lay/lay/doc/programming/qt_binding.xml index 7d5c22b3a..9ba46caef 100644 --- a/src/lay/lay/doc/programming/qt_binding.xml +++ b/src/lay/lay/doc/programming/qt_binding.xml @@ -30,6 +30,7 @@
  • QtSql: database support
  • QtNetwork: various network protocols and supporting classes
  • QtDesigner: dynamically load designer files (.ui)
  • +
  • QtUiTools: dynamically load designer files (.ui)
  • QtMultimedia (Qt5): multimedia support
  • QtPrintSupport (Qt5): print support
  • QtSvg (Qt5): SVG implementation
  • diff --git a/src/lay/lay/gsiDeclLayHelpDialog.cc b/src/lay/lay/gsiDeclLayHelpDialog.cc index 4eea9886c..1cb6fb7f1 100644 --- a/src/lay/lay/gsiDeclLayHelpDialog.cc +++ b/src/lay/lay/gsiDeclLayHelpDialog.cc @@ -97,7 +97,7 @@ Class decl_HelpDialog (QT_EXTERNAL_BASE (QDialog) "lay", "HelpD LAYBASIC_PUBLIC Class &laybasicdecl_BrowserSource (); Class decl_HelpSource (laybasicdecl_BrowserSource (), "lay", "HelpSource", -#if defined(HAVE_QTBINDINGS) +#if defined(HAVE_QTBINDINGS) && defined(HAVE_QT_XML) gsi::method ("get_dom", &lay::HelpSource::get_dom, "@brief For internal use") + #endif gsi::method ("urls", &lay::HelpSource::urls, "@brief Reserved for internal use") + diff --git a/src/lay/lay/lay.pro b/src/lay/lay/lay.pro index f2ba59502..8a07f7da3 100644 --- a/src/lay/lay/lay.pro +++ b/src/lay/lay/lay.pro @@ -203,7 +203,10 @@ INCLUDEPATH += $$QTBASIC_INC DEPENDPATH += $$QTBASIC_INC equals(HAVE_QTBINDINGS, "1") { - LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtCore + LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtCore + !equals(HAVE_QT_XML, "0") { + LIBS += -lklayout_QtXml + } equals(HAVE_QT5, "1") { LIBS += -lklayout_QtWidgets } diff --git a/src/lay/lay/layLogViewerDialog.cc b/src/lay/lay/layLogViewerDialog.cc index 5493d7aae..e0ca83912 100644 --- a/src/lay/lay/layLogViewerDialog.cc +++ b/src/lay/lay/layLogViewerDialog.cc @@ -200,11 +200,33 @@ LogFile::timeout () } } +void +LogFile::set_max_entries (size_t n) +{ + QMutexLocker locker (&m_lock); + + m_max_entries = n; + + while (m_messages.size () > m_max_entries) { + m_messages.pop_front (); + } +} + +size_t +LogFile::max_entries () const +{ + return m_max_entries; +} + void LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued) { QMutexLocker locker (&m_lock); + if (m_max_entries == 0) { + return; + } + if (m_messages.size () >= m_max_entries) { m_messages.pop_front (); } diff --git a/src/lay/lay/layLogViewerDialog.h b/src/lay/lay/layLogViewerDialog.h index 69caeb327..c9da714a3 100644 --- a/src/lay/lay/layLogViewerDialog.h +++ b/src/lay/lay/layLogViewerDialog.h @@ -192,6 +192,18 @@ public slots: return m_log_receiver; } + /** + * @brief Sets the maximum number of entries to show + * + * Setting this value to 0 basically disables the log collection + */ + void set_max_entries (size_t n); + + /** + * @brief Gets the maximum number of entries to show + */ + size_t max_entries () const; + private slots: void timeout (); diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index c2b3377e4..a5acce812 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -244,6 +244,7 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection m_highlighters (this), m_in_exec (false), m_in_breakpoint (false), + m_ignore_exec_events (false), mp_exec_controller (0), mp_current_interpreter (0), m_continue (false), @@ -355,8 +356,8 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection QMenu *m = new QMenu (searchEditBox); m->addAction (actionUseRegularExpressions); m->addAction (actionCaseSensitive); - connect (actionUseRegularExpressions, SIGNAL (triggered ()), this, SLOT (apply_search ())); - connect (actionCaseSensitive, SIGNAL (triggered ()), this, SLOT (apply_search ())); + connect (actionUseRegularExpressions, SIGNAL (triggered ()), this, SLOT (search_editing ())); + connect (actionCaseSensitive, SIGNAL (triggered ()), this, SLOT (search_editing ())); addAction (actionSearchReplace); connect (actionSearchReplace, SIGNAL (triggered ()), this, SLOT (search_replace ())); @@ -364,7 +365,11 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection searchEditBox->set_clear_button_enabled (true); searchEditBox->set_options_button_enabled (true); searchEditBox->set_options_menu (m); + searchEditBox->set_escape_signal_enabled (true); + searchEditBox->set_tab_signal_enabled (true); replaceText->set_clear_button_enabled (true); + replaceText->set_escape_signal_enabled (true); + replaceText->set_tab_signal_enabled (true); #if QT_VERSION >= 0x40700 searchEditBox->setPlaceholderText (tr ("Find text ...")); replaceText->setPlaceholderText (tr ("Replace text ...")); @@ -382,8 +387,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection tabWidget->setMovable (true); tabWidget->setTabsClosable (true); connect (tabWidget, SIGNAL (tabCloseRequested (int)), this, SLOT (tab_close_requested (int))); - closeButton->hide (); - closeButtonSeparator->hide (); #endif dbgOn->setEnabled (true); @@ -411,7 +414,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection connect (helpButton, SIGNAL (clicked ()), this, SLOT (help_button_clicked ())); connect (addButton, SIGNAL (clicked ()), this, SLOT (add_button_clicked ())); connect (actionAddMacro, SIGNAL (triggered ()), this, SLOT (add_button_clicked ())); - connect (closeButton, SIGNAL (clicked ()), this, SLOT (close_button_clicked ())); connect (deleteButton, SIGNAL (clicked ()), this, SLOT (delete_button_clicked ())); connect (actionDelete, SIGNAL (triggered ()), this, SLOT (delete_button_clicked ())); connect (renameButton, SIGNAL (clicked ()), this, SLOT (rename_button_clicked ())); @@ -438,9 +440,16 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection connect (callStack, SIGNAL (itemDoubleClicked (QListWidgetItem *)), this, SLOT (stack_element_double_clicked (QListWidgetItem *))); connect (singleStepButton, SIGNAL (clicked ()), this, SLOT (single_step_button_clicked ())); connect (nextStepButton, SIGNAL (clicked ()), this, SLOT (next_step_button_clicked ())); + connect (searchEditBox, SIGNAL (textEdited (const QString &)), this, SLOT (search_editing ())); connect (searchEditBox, SIGNAL (returnPressed ()), this, SLOT (search_edited ())); connect (searchEditBox, SIGNAL (editingFinished ()), this, SLOT (search_edited ())); - connect (searchEditBox, SIGNAL (textEdited (QString)), this, SLOT (apply_search ())); + connect (searchEditBox, SIGNAL (esc_pressed ()), this, SLOT (search_finished ())); + connect (searchEditBox, SIGNAL (tab_pressed ()), this, SLOT (find_next_button_clicked ())); + connect (searchEditBox, SIGNAL (backtab_pressed ()), this, SLOT (find_prev_button_clicked ())); + connect (replaceText, SIGNAL (esc_pressed ()), this, SLOT (search_finished ())); + connect (replaceText, SIGNAL (tab_pressed ()), this, SLOT (find_next_button_clicked ())); + connect (replaceText, SIGNAL (backtab_pressed ()), this, SLOT (find_prev_button_clicked ())); + connect (replaceText, SIGNAL (returnPressed ()), this, SLOT (replace_next_button_clicked ())); connect (replaceModeButton, SIGNAL (clicked ()), this, SLOT (replace_mode_button_clicked ())); connect (replaceNextButton, SIGNAL (clicked ()), this, SLOT (replace_next_button_clicked ())); connect (findNextButton, SIGNAL (clicked ()), this, SLOT (find_next_button_clicked ())); @@ -946,15 +955,13 @@ MacroEditorDialog::showEvent (QShowEvent *) void MacroEditorDialog::reject () { - closeEvent (0); - QDialog::reject (); + // .. ignore Esc .. } void MacroEditorDialog::accept () { - closeEvent (0); - QDialog::accept (); + // .. ignore Enter .. } void @@ -1105,12 +1112,6 @@ MacroEditorDialog::can_exit () return true; } -void -MacroEditorDialog::search_replace () -{ - searchEditBox->setFocus (Qt::TabFocusReason); -} - void MacroEditorDialog::add_edit_trace (bool compress) { @@ -1882,6 +1883,18 @@ BEGIN_PROTECTED END_PROTECTED } +void +MacroEditorDialog::set_editor_focus () +{ + MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); + if (! page) { + return; + } + + lay::SignalBlocker signal_blocker (searchEditBox); + page->set_editor_focus (); +} + void MacroEditorDialog::replace_mode_button_clicked () { @@ -1905,10 +1918,27 @@ MacroEditorDialog::find_next_button_clicked () apply_search (true); page->find_next (); - page->set_editor_focus (); + if (sender () != searchEditBox && sender () != replaceText) { + set_editor_focus (); + } } -void +void +MacroEditorDialog::find_prev_button_clicked () +{ + MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); + if (! page) { + return; + } + + apply_search (true); + page->find_prev (); + if (sender () != searchEditBox && sender () != replaceText) { + set_editor_focus (); + } +} + +void MacroEditorDialog::replace_next_button_clicked () { MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); @@ -1918,10 +1948,12 @@ MacroEditorDialog::replace_next_button_clicked () apply_search (true); page->replace_and_find_next (replaceText->text ()); - page->set_editor_focus (); + if (sender () != replaceText) { + set_editor_focus (); + } } -void +void MacroEditorDialog::replace_all_button_clicked () { MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); @@ -1931,7 +1963,34 @@ MacroEditorDialog::replace_all_button_clicked () apply_search (true); page->replace_all (replaceText->text ()); - page->set_editor_focus (); + set_editor_focus (); +} + +void +MacroEditorDialog::search_requested (const QString &s) +{ + searchEditBox->setText (s); + searchEditBox->setFocus (); + search_editing (); +} + +void +MacroEditorDialog::search_replace () +{ + searchEditBox->setFocus (Qt::TabFocusReason); +} + +void +MacroEditorDialog::search_editing () +{ + MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); + if (! page) { + return; + } + + apply_search (); + page->find_reset (); // search from the initial position + page->find_next (); } void @@ -1942,6 +2001,18 @@ MacroEditorDialog::search_edited () md_search_edited (); } +void +MacroEditorDialog::search_finished () +{ + MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); + if (! page) { + return; + } + + page->find_reset (); // search from the initial position + set_editor_focus (); +} + void MacroEditorDialog::do_search_edited () { @@ -1951,8 +2022,9 @@ MacroEditorDialog::do_search_edited () } apply_search (); + page->find_reset (); // search from the initial position page->find_next (); - page->set_editor_focus (); + set_editor_focus (); } void @@ -1963,7 +2035,7 @@ MacroEditorDialog::apply_search (bool if_needed) return; } - if (searchEditBox->text ().size () > 0) { + if (! searchEditBox->text ().isEmpty ()) { QRegExp re (searchEditBox->text (), actionCaseSensitive->isChecked () ? Qt::CaseSensitive : Qt::CaseInsensitive, actionUseRegularExpressions->isChecked () ? QRegExp::RegExp : QRegExp::FixedString); @@ -2080,7 +2152,7 @@ BEGIN_PROTECTED END_PROTECTED } -void +void MacroEditorDialog::help_requested(const QString &s) { lay::MainWindow::instance ()->show_assistant_topic (tl::to_string (s)); @@ -2779,54 +2851,77 @@ MacroEditorDialog::start_exec (gsi::Interpreter *ec) if (m_in_exec) { tl_assert (ec != mp_exec_controller); return; + } else if (m_ignore_exec_events) { + return; } - m_file_to_widget.clear (); - m_include_expanders.clear (); - m_include_paths_to_ids.clear (); - m_include_file_id_cache.clear (); + // prevents recursion + m_ignore_exec_events = true; - m_last_process_events = tl::Clock::current (); + try { - m_in_exec = true; - mp_exec_controller = ec; - m_in_breakpoint = false; - m_continue = true; - m_trace_count = 0; - m_current_stack_depth = -1; - m_process_events_interval = 0.05; + m_file_to_widget.clear (); + m_include_expanders.clear (); + m_include_paths_to_ids.clear (); + m_include_file_id_cache.clear (); - for (std::map::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) { - f->second->exec_model ()->set_current_line (-1); - f->second->exec_model ()->set_run_mode (true); + m_last_process_events = tl::Clock::current (); + + m_in_exec = true; + mp_exec_controller = ec; + m_in_breakpoint = false; + m_continue = true; + m_trace_count = 0; + m_current_stack_depth = -1; + m_process_events_interval = 0.05; + + for (std::map::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) { + f->second->exec_model ()->set_current_line (-1); + f->second->exec_model ()->set_run_mode (true); + } + + do_update_ui_to_run_mode (); + + } catch (...) { + // .. ignore exceptions here .. } - do_update_ui_to_run_mode (); + m_ignore_exec_events = false; } void MacroEditorDialog::end_exec (gsi::Interpreter *ec) { - // ignore calls from other interpreters - if (m_in_exec && ec != mp_exec_controller) { + if ((m_in_exec && ec != mp_exec_controller) || m_ignore_exec_events) { return; } - if (QApplication::activeModalWidget () == this) { - // close this window if it was shown in modal mode - QDialog::accept (); + // prevents recursion + m_ignore_exec_events = true; + + try { + + m_in_exec = false; + mp_exec_controller = 0; + m_continue = false; + m_current_stack_depth = -1; + + if (QApplication::activeModalWidget () == this) { + // close this window if it was shown in modal mode + QDialog::accept (); + } + + for (std::map::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) { + f->second->exec_model ()->set_run_mode (false); + } + + do_update_ui_to_run_mode (); + + } catch (...) { + // .. ignore exceptions here .. } - m_in_exec = false; - mp_exec_controller = 0; - m_continue = false; - m_current_stack_depth = -1; - - for (std::map::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) { - f->second->exec_model ()->set_run_mode (false); - } - - do_update_ui_to_run_mode (); + m_ignore_exec_events = false; } const size_t pseudo_file_offset = std::numeric_limits::max () / 2; @@ -3172,7 +3267,6 @@ MacroEditorDialog::do_update_ui_to_run_mode () addButton->setEnabled (! m_in_exec); actionAddMacro->setEnabled (! m_in_exec); - closeButton->setEnabled (! m_in_exec); deleteButton->setEnabled (! m_in_exec); actionDelete->setEnabled (! m_in_exec); renameButton->setEnabled (! m_in_exec); @@ -3270,6 +3364,7 @@ MacroEditorDialog::create_page (lym::Macro *macro) editor->exec_model ()->set_run_mode (m_in_exec); editor->connect_macro (macro); connect (editor.get (), SIGNAL (help_requested (const QString &)), this, SLOT (help_requested (const QString &))); + connect (editor.get (), SIGNAL (search_requested (const QString &)), this, SLOT (search_requested (const QString &))); connect (editor.get (), SIGNAL (edit_trace (bool)), this, SLOT (add_edit_trace (bool))); return editor.release (); } diff --git a/src/lay/lay/layMacroEditorDialog.h b/src/lay/lay/layMacroEditorDialog.h index 75108d501..750715f79 100644 --- a/src/lay/lay/layMacroEditorDialog.h +++ b/src/lay/lay/layMacroEditorDialog.h @@ -209,12 +209,16 @@ private slots: void commit (); void stack_element_double_clicked (QListWidgetItem *item); void search_edited (); + void search_editing (); + void search_finished (); void tab_close_requested (int); void replace_mode_button_clicked (); void replace_next_button_clicked (); void replace_all_button_clicked (); void find_next_button_clicked (); + void find_prev_button_clicked (); void help_requested (const QString &s); + void search_requested (const QString &s); void macro_changed (lym::Macro *macro); void macro_deleted (lym::Macro *macro); void macro_collection_deleted (lym::MacroCollection *collection); @@ -288,6 +292,7 @@ private: void update_watches (); lym::Macro *new_macro (); void do_search_edited (); + void set_editor_focus (); void select_trace (size_t index); bool configure (const std::string &name, const std::string &value); void config_finalize (); @@ -318,7 +323,7 @@ private: std::map m_include_paths_to_ids; std::map, std::pair > m_include_file_id_cache; std::vector m_macro_trees; - bool m_in_exec, m_in_breakpoint; + bool m_in_exec, m_in_breakpoint, m_ignore_exec_events; gsi::Interpreter *mp_exec_controller, *mp_current_interpreter; bool m_continue; int m_trace_count; diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index ad6d38f84..ad11a8076 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -25,6 +25,7 @@ #include "lymMacroInterpreter.h" #include "tlExceptions.h" #include "tlString.h" +#include "layQtTools.h" #include #include @@ -42,6 +43,9 @@ #include #include #include +#include +#include +#include namespace lay { @@ -475,7 +479,7 @@ void MacroEditorSidePanel::paintEvent (QPaintEvent *) // MacroEditorPage implementation MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters *highlighters) - : mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2) + : mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false) { QVBoxLayout *layout = new QVBoxLayout (this); @@ -499,11 +503,26 @@ MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters connect (mp_text, SIGNAL (textChanged ()), this, SLOT (text_changed ())); connect (mp_text, SIGNAL (cursorPositionChanged ()), this, SLOT (cursor_position_changed ())); + connect (mp_text->horizontalScrollBar (), SIGNAL (valueChanged (int)), this, SLOT (hide_completer ())); + connect (mp_text->verticalScrollBar (), SIGNAL (valueChanged (int)), this, SLOT (hide_completer ())); connect (mp_exec_model, SIGNAL (breakpoints_changed ()), this, SLOT (breakpoints_changed ())); connect (mp_exec_model, SIGNAL (current_line_changed ()), this, SLOT (current_line_changed ())); connect (mp_exec_model, SIGNAL (run_mode_changed ()), this, SLOT (run_mode_changed ())); mp_text->installEventFilter (this); + + mp_completer_popup = new QWidget (window (), Qt::ToolTip); + mp_completer_popup->setWindowModality (Qt::NonModal); + QHBoxLayout *ly = new QHBoxLayout (mp_completer_popup); + ly->setMargin (0); + mp_completer_list = new QListWidget (mp_completer_popup); + ly->addWidget (mp_completer_list); + mp_completer_popup->hide (); + + mp_completer_timer = new QTimer (this); + mp_completer_timer->setInterval (1000); + mp_completer_timer->setSingleShot (true); + connect (mp_completer_timer, SIGNAL (timeout ()), this, SLOT (completer_timer ())); } void MacroEditorPage::update () @@ -566,12 +585,23 @@ void MacroEditorPage::current_line_changed () void MacroEditorPage::run_mode_changed () { - if (mp_exec_model->run_mode ()) { - set_error_line (0); + // this prevents recursion when the following lines trigger anything that routes through the interpreter + bool bl = mp_exec_model->blockSignals (true); + + try { + + if (mp_exec_model->run_mode ()) { + set_error_line (0); + } + + mp_text->setReadOnly (! mp_macro || mp_macro->is_readonly () || mp_exec_model->run_mode ()); + update_extra_selections (); + + } catch (...) { + // .. ignore exceptions here .. } - mp_text->setReadOnly (! mp_macro || mp_macro->is_readonly () || mp_exec_model->run_mode ()); - update_extra_selections (); + mp_exec_model->blockSignals (bl); } void MacroEditorPage::breakpoints_changed () @@ -598,9 +628,110 @@ static bool valid_element (const SyntaxHighlighterElement &e) return e.basic_attribute_id != lay::dsComment && e.basic_attribute_id != lay::dsString; } +void MacroEditorPage::complete () +{ + QTextCursor c = mp_text->textCursor (); + if (c.selectionStart () != c.selectionEnd ()) { + return; + } + + c.select (QTextCursor::WordUnderCursor); + if (mp_completer_list->currentItem ()) { + QString s = mp_completer_list->currentItem ()->text (); + c.insertText (s); + } +} + +void MacroEditorPage::fill_completer_list () +{ + QTextCursor c = mp_text->textCursor (); + if (c.selectionStart () != c.selectionEnd ()) { + return; + } + + int pos = c.anchor (); + c.select (QTextCursor::WordUnderCursor); + int pos0 = c.selectionStart (); + if (pos0 >= pos) { + return; + } + + QString ssel = c.selectedText (); + QString s = ssel.mid (0, pos - pos0); + + QString text = mp_text->toPlainText (); + + std::set words; + + int i = 0; + while (i >= 0) { + i = text.indexOf (s, i); + if (i >= 0) { + QString::iterator c = text.begin () + i; + QString w; + while (c->isLetterOrNumber () || c->toLatin1 () == '_') { + w += *c; + ++c; + } + if (! w.isEmpty () && w != s && w != ssel) { + words.insert (w); + } + ++i; + } + } + + for (std::set::const_iterator w = words.begin (); w != words.end (); ++w) { + mp_completer_list->addItem (*w); + } +} + +void MacroEditorPage::completer_timer () +{ + if (! mp_text->hasFocus ()) { + return; + } + + mp_completer_list->clear (); + fill_completer_list (); + + if (mp_completer_list->count () > 0) { + + mp_completer_list->setCurrentRow (0); + + QTextCursor c = mp_text->textCursor (); + c.clearSelection (); + QRect r = mp_text->cursorRect (c); + QPoint pos = mp_text->mapToGlobal (r.bottomLeft ()); + + QSize sz = mp_completer_list->sizeHint (); + QFontMetrics fm (mp_completer_list->font ()); + mp_completer_popup->setGeometry (pos.x (), pos.y () + r.height () / 3, sz.width (), 4 + 4 * fm.height () /*sz.height ()*/); + mp_completer_popup->show (); + + mp_text->setFocus (); + + } else { + mp_completer_popup->hide (); + } +} + +void MacroEditorPage::hide_completer () +{ + mp_completer_popup->hide (); +} + void MacroEditorPage::cursor_position_changed () { + if (m_ignore_cursor_changed_event) { + return; + } + + mp_completer_popup->hide (); + mp_completer_timer->stop (); + mp_completer_timer->start (); + QTextCursor cursor = mp_text->textCursor (); + m_edit_cursor = cursor; // prepare a format for the bracket highlights QTextCharFormat fmt; @@ -861,11 +992,23 @@ void MacroEditorPage::connect_macro (lym::Macro *macro) } } +void +MacroEditorPage::find_reset () +{ + m_ignore_cursor_changed_event = true; + mp_text->setTextCursor (m_edit_cursor); + m_ignore_cursor_changed_event = false; +} + bool MacroEditorPage::find_prev () { update_extra_selections (); + if (m_current_search == QRegExp ()) { + return false; + } + QTextCursor c = mp_text->textCursor (); bool first = true; @@ -891,7 +1034,9 @@ MacroEditorPage::find_prev () QTextCursor newc (b); newc.setPosition (i + b.position () + l); newc.setPosition (i + b.position (), QTextCursor::KeepAnchor); + m_ignore_cursor_changed_event = true; mp_text->setTextCursor (newc); + m_ignore_cursor_changed_event = false; return true; } @@ -913,6 +1058,10 @@ MacroEditorPage::find_next () { update_extra_selections (); + if (m_current_search == QRegExp ()) { + return false; + } + QTextCursor c = mp_text->textCursor (); bool first = true; @@ -926,7 +1075,9 @@ MacroEditorPage::find_next () QTextCursor newc (b); newc.setPosition (i + b.position () + m_current_search.matchedLength ()); newc.setPosition (i + b.position (), QTextCursor::KeepAnchor); + m_ignore_cursor_changed_event = true; mp_text->setTextCursor (newc); + m_ignore_cursor_changed_event = false; emit edit_trace (false); return true; } @@ -1152,263 +1303,391 @@ MacroEditorPage::current_pos () const return mp_text->textCursor ().position () - mp_text->textCursor ().block ().position (); } +bool +MacroEditorPage::tab_key_pressed () +{ + if (mp_text->isReadOnly ()) { + return false; + } + + QTextBlock bs, be; + bool adjust_end = false; + + bool indent = false; + if (mp_text->textCursor ().hasSelection ()) { + bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ()); + be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ()); + if (be != bs) { + indent = true; + QTextCursor se (mp_text->document ()); + se.setPosition (mp_text->textCursor ().selectionEnd ()); + if (se.atBlockStart ()) { + be = be.previous (); + adjust_end = true; + } + } + } + + if (indent) { + + // tab out + QTextCursor c (mp_text->document ()); + c.setPosition (bs.position ()); + c.beginEditBlock (); + + for (QTextBlock b = bs; ; b = b.next()) { + + c.setPosition (b.position ()); + QString text = b.text (); + + bool has_tabs = false; + int p = 0; + int i = 0; + for (; i < text.length (); ++i) { + if (text [i] == QChar::fromLatin1 (' ')) { + ++p; + } else if (text [i] == QChar::fromLatin1 ('\t')) { + p = (p - p % m_ntab) + m_ntab; + has_tabs = true; + } else { + break; + } + } + + if (has_tabs) { + for ( ; i > 0; --i) { + c.deleteChar (); + } + c.insertText (QString (m_nindent + p, QChar::fromLatin1 (' '))); + } else { + c.insertText (QString (m_nindent, QChar::fromLatin1 (' '))); + } + + if (b == be) { + break; + } + + } + + c.endEditBlock (); + + c.setPosition (bs.position ()); + if (adjust_end) { + c.setPosition (be.next ().position (), QTextCursor::KeepAnchor); + } else { + c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor); + } + mp_text->setTextCursor (c); + + } else { + + QTextCursor c = mp_text->textCursor (); + QString text = c.block ().text (); + int col = c.position () - c.block ().position (); + + int p = 0; + for (int i = 0; i < text.length () && i < col; ++i) { + if (text [i] == QChar::fromLatin1 ('\t')) { + p = (p - p % m_ntab) + m_ntab; + } else { + ++p; + } + } + + c.insertText (QString (m_nindent - p % m_nindent, QChar::fromLatin1 (' '))); + mp_text->setTextCursor (c); + + } + + return true; +} + +bool +MacroEditorPage::back_tab_key_pressed () +{ + if (!mp_text->textCursor ().hasSelection () || mp_text->isReadOnly ()) { + return false; + } + + // tab in + QTextBlock bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ()); + QTextBlock be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ()); + bool adjust_end = false; + if (be != bs) { + QTextCursor se (mp_text->document ()); + se.setPosition (mp_text->textCursor ().selectionEnd ()); + if (se.atBlockStart ()) { + be = be.previous (); + adjust_end = true; + } + } + + QTextCursor c (mp_text->document ()); + c.setPosition (bs.position ()); + c.beginEditBlock (); + + for (QTextBlock b = bs; ; b = b.next()) { + + c.setPosition (b.position ()); + QString text = b.text (); + int n = m_nindent; + int p = 0; + for (int i = 0; i < text.length () && n > 0; ++i) { + if (text [i] == QChar::fromLatin1 (' ')) { + ++p; + --n; + c.deleteChar (); + } else if (text [i] == QChar::fromLatin1 ('\t')) { + c.deleteChar (); + int pp = p; + p = (p - p % m_ntab) + m_ntab; + if (p - pp >= n) { + if (p - pp > n) { + c.insertText (QString (p - pp - n, QChar::fromLatin1 (' '))); + } + n = 0; + } else { + n -= p - pp; + } + } else { + break; + } + } + + if (b == be) { + break; + } + + } + + c.endEditBlock (); + + c.setPosition (bs.position ()); + if (adjust_end) { + c.setPosition (be.next ().position (), QTextCursor::KeepAnchor); + } else { + c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor); + } + mp_text->setTextCursor (c); + + return true; +} + +bool +MacroEditorPage::backspace_pressed () +{ + if (mp_text->textCursor ().hasSelection () || mp_text->isReadOnly()) { + return false; + } + + QTextCursor c = mp_text->textCursor (); + QString text = c.block ().text (); + int col = c.position () - c.block ().position (); + if (col > 0) { + + int p = 0; + bool only_space_before = true; + + for (int i = 0; i < text.length () && i < col; ++i) { + if (text [i] == QChar::fromLatin1 ('\t')) { + p = (p - p % m_ntab) + m_ntab; + } else if (text [i] == QChar::fromLatin1 (' ')) { + ++p; + } else { + only_space_before = false; + } + } + + if (only_space_before) { + + for (int i = 0; i < col; ++i) { + c.deletePreviousChar (); + } + + c.insertText (QString (std::max (0, ((p - 1) / m_nindent) * m_nindent), QChar::fromLatin1 (' '))); + mp_text->setTextCursor (c); + + return true; + + } + + } + + return false; +} + +bool +MacroEditorPage::return_pressed () +{ + if (mp_text->isReadOnly ()) { + return false; + } + + // Implement auto-indent on return + + QTextCursor c = mp_text->textCursor (); + QTextBlock b = c.block (); + + c.insertBlock (); + + QString l; + if (b.isValid ()) { + QString text = b.text (); + for (int i = 0; i < text.length (); ++i) { + if (text [i] == QChar::fromLatin1 ('\t') || text [i] == QChar::fromLatin1 (' ')) { + l += text [i]; + } else { + break; + } + } + } + + c.insertText (l); + mp_text->setTextCursor (c); + + return true; +} + +static bool is_tab_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0; +} + +static bool is_backtab_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0); +} + +static bool is_backspace_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Backspace; +} + +static bool is_escape_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Escape; +} + +static bool is_return_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Return; +} + +static bool is_help_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_F1; +} + +static bool is_find_next_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_F3; +} + +static bool is_find_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0; +} + +static bool is_up_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Up; +} + +static bool is_down_key (QKeyEvent *ke) +{ + return ke->key () == Qt::Key_Down; +} + + +static bool is_any_known_key (QKeyEvent *ke) +{ + return is_tab_key (ke) || + is_backtab_key (ke) || + is_backspace_key (ke) || + is_escape_key (ke) || + is_return_key (ke) || + is_help_key (ke) || + is_find_next_key (ke) || + is_find_key (ke) || + is_up_key (ke) || + is_down_key (ke); +} + bool MacroEditorPage::eventFilter (QObject *watched, QEvent *event) { if (watched == mp_text) { - if (event->type () == QEvent::KeyPress) { + if (event->type () == QEvent::ShortcutOverride) { + + // override shortcuts if the collide with keys we accept ourselves + QKeyEvent *ke = dynamic_cast (event); + if (! ke) { + return false; // should not happen + } + + if (is_any_known_key (ke)) { + event->accept (); + return true; + } + + } else if (event->type () == QEvent::FocusOut) { + + hide_completer (); + return true; + + } else if (event->type () == QEvent::KeyPress) { m_error_line = -1; mp_text->setExtraSelections (QList ()); QKeyEvent *ke = dynamic_cast (event); - if (ke && ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) { + if (! ke) { + return false; // should not happen + } - if (!mp_text->isReadOnly ()) { - - QTextBlock bs, be; - bool adjust_end = false; - - bool indent = false; - if (mp_text->textCursor ().hasSelection ()) { - bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ()); - be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ()); - if (be != bs) { - indent = true; - QTextCursor se (mp_text->document ()); - se.setPosition (mp_text->textCursor ().selectionEnd ()); - if (se.atBlockStart ()) { - be = be.previous (); - adjust_end = true; - } - } - } - - if (indent) { - - // tab out - QTextCursor c (mp_text->document ()); - c.setPosition (bs.position ()); - c.beginEditBlock (); - - for (QTextBlock b = bs; ; b = b.next()) { - - c.setPosition (b.position ()); - QString text = b.text (); - - bool has_tabs = false; - int p = 0; - int i = 0; - for (; i < text.length (); ++i) { - if (text [i] == QChar::fromLatin1 (' ')) { - ++p; - } else if (text [i] == QChar::fromLatin1 ('\t')) { - p = (p - p % m_ntab) + m_ntab; - has_tabs = true; - } else { - break; - } - } - - if (has_tabs) { - for ( ; i > 0; --i) { - c.deleteChar (); - } - c.insertText (QString (m_nindent + p, QChar::fromLatin1 (' '))); - } else { - c.insertText (QString (m_nindent, QChar::fromLatin1 (' '))); - } - - if (b == be) { - break; - } - - } - - c.endEditBlock (); - - c.setPosition (bs.position ()); - if (adjust_end) { - c.setPosition (be.next ().position (), QTextCursor::KeepAnchor); - } else { - c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor); - } - mp_text->setTextCursor (c); - - } else { - - QTextCursor c = mp_text->textCursor (); - QString text = c.block ().text (); - int col = c.position () - c.block ().position (); - - int p = 0; - for (int i = 0; i < text.length () && i < col; ++i) { - if (text [i] == QChar::fromLatin1 ('\t')) { - p = (p - p % m_ntab) + m_ntab; - } else { - ++p; - } - } - - c.insertText (QString (m_nindent - p % m_nindent, QChar::fromLatin1 (' '))); - mp_text->setTextCursor (c); - - } - - } - - return true; - - } else if (ke && (ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) { - - if (mp_text->textCursor ().hasSelection () && !mp_text->isReadOnly ()) { - - // tab in - QTextBlock bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ()); - QTextBlock be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ()); - bool adjust_end = false; - if (be != bs) { - QTextCursor se (mp_text->document ()); - se.setPosition (mp_text->textCursor ().selectionEnd ()); - if (se.atBlockStart ()) { - be = be.previous (); - adjust_end = true; - } - } - - QTextCursor c (mp_text->document ()); - c.setPosition (bs.position ()); - c.beginEditBlock (); - - for (QTextBlock b = bs; ; b = b.next()) { - - c.setPosition (b.position ()); - QString text = b.text (); - int n = m_nindent; - int p = 0; - for (int i = 0; i < text.length () && n > 0; ++i) { - if (text [i] == QChar::fromLatin1 (' ')) { - ++p; - --n; - c.deleteChar (); - } else if (text [i] == QChar::fromLatin1 ('\t')) { - c.deleteChar (); - int pp = p; - p = (p - p % m_ntab) + m_ntab; - if (p - pp >= n) { - if (p - pp > n) { - c.insertText (QString (p - pp - n, QChar::fromLatin1 (' '))); - } - n = 0; - } else { - n -= p - pp; - } - } else { - break; - } - } - - if (b == be) { - break; - } - - } - - c.endEditBlock (); - - c.setPosition (bs.position ()); - if (adjust_end) { - c.setPosition (be.next ().position (), QTextCursor::KeepAnchor); - } else { - c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor); - } - mp_text->setTextCursor (c); - - } - - return true; - - } else if (ke && ke->key () == Qt::Key_Backspace) { - - if (!mp_text->textCursor ().hasSelection () && !mp_text->isReadOnly()) { - - QTextCursor c = mp_text->textCursor (); - QString text = c.block ().text (); - int col = c.position () - c.block ().position (); - if (col > 0) { - - int p = 0; - bool only_space_before = true; - - for (int i = 0; i < text.length () && i < col; ++i) { - if (text [i] == QChar::fromLatin1 ('\t')) { - p = (p - p % m_ntab) + m_ntab; - } else if (text [i] == QChar::fromLatin1 (' ')) { - ++p; - } else { - only_space_before = false; - } - } - - if (only_space_before) { - - for (int i = 0; i < col; ++i) { - c.deletePreviousChar (); - } - - c.insertText (QString (std::max (0, ((p - 1) / m_nindent) * m_nindent), QChar::fromLatin1 (' '))); - mp_text->setTextCursor (c); - - return true; - - } - - } - - } - - } else if (ke && ke->key () == Qt::Key_Escape) { - - // Handle Esc to clear the selection - - QTextCursor c = mp_text->textCursor (); - c.clearSelection (); - mp_text->setTextCursor (c); - - return true; - - } else if (ke && ke->key () == Qt::Key_Return) { - - if (!mp_text->isReadOnly ()) { - - // Implement auto-indent on return - - QTextCursor c = mp_text->textCursor (); - QTextBlock b = c.block (); - - c.insertBlock (); - - QString l; - if (b.isValid ()) { - QString text = b.text (); - for (int i = 0; i < text.length (); ++i) { - if (text [i] == QChar::fromLatin1 ('\t') || text [i] == QChar::fromLatin1 (' ')) { - l += text [i]; - } else { - break; - } - } - } - - c.insertText (l); - mp_text->setTextCursor (c); + if (is_tab_key (ke)) { + if (mp_completer_popup->isVisible ()) { + complete (); return true; - + } else { + return tab_key_pressed (); } - } else if (ke && ke->key () == Qt::Key_F1) { + } else if (is_backtab_key (ke)) { + + return back_tab_key_pressed (); + + } else if (is_backspace_key (ke)) { + + return backspace_pressed (); + + } else if (is_escape_key (ke)) { + + // Handle Esc to return to the before-find position and clear the selection or to hide popup + + if (mp_completer_popup->isVisible ()) { + mp_completer_popup->hide (); + } else { + find_reset (); + QTextCursor c = mp_text->textCursor (); + c.clearSelection (); + mp_text->setTextCursor (c); + } + + return true; + + } else if (is_return_key (ke)) { + + if (mp_completer_popup->isVisible ()) { + complete (); + return true; + } else { + return return_pressed (); + } + + } else if (is_help_key (ke)) { QTextCursor c = mp_text->textCursor (); if (c.selectionStart () == c.selectionEnd ()) { @@ -1418,7 +1697,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return true; - } else if (ke && ke->key () == Qt::Key_F3) { + } else if (mp_completer_popup->isVisible () && (is_up_key (ke) || is_down_key (ke))) { + + QApplication::sendEvent (mp_completer_list, event); + return true; + + } else if (is_find_key (ke)) { + + QTextCursor c = mp_text->textCursor (); + emit search_requested (c.selectedText ()); + + return true; + + } else if (is_find_next_key (ke)) { // Jump to the next occurence of the search string diff --git a/src/lay/lay/layMacroEditorPage.h b/src/lay/lay/layMacroEditorPage.h index dcf1c94e0..732160dfc 100644 --- a/src/lay/lay/layMacroEditorPage.h +++ b/src/lay/lay/layMacroEditorPage.h @@ -45,6 +45,9 @@ typedef QTextEdit TextEditWidget; class QLabel; class QSyntaxHighlighter; +class QTimer; +class QWindow; +class QListWidget; namespace lay { @@ -254,8 +257,8 @@ public: return m_current_search; } + void find_reset (); bool find_next (); - bool find_prev (); void replace_and_find_next (const QString &replace); @@ -268,6 +271,7 @@ public: signals: void help_requested (const QString &s); + void search_requested (const QString &s); void edit_trace (bool); public slots: @@ -280,6 +284,8 @@ protected slots: void breakpoints_changed (); void current_line_changed (); void run_mode_changed (); + void completer_timer (); + void hide_completer (); private: lym::Macro *mp_macro; @@ -294,8 +300,20 @@ private: int m_ntab, m_nindent; std::set m_breakpoints; QRegExp m_current_search; + QTextCursor m_edit_cursor; + bool m_ignore_cursor_changed_event; + QTimer *mp_completer_timer; + QWidget *mp_completer_popup; + QListWidget *mp_completer_list; void update_extra_selections (); + bool return_pressed (); + bool backspace_pressed (); + bool back_tab_key_pressed (); + bool tab_key_pressed (); + void fill_completer_list (); + void complete (); + bool eventFilter (QObject *watched, QEvent *event); }; diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index fa7a19762..d40814b05 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -50,6 +50,7 @@ #include "tlAssert.h" #include "tlStream.h" #include "tlExceptions.h" +#include "tlExpression.h" #include "dbMemStatistics.h" #include "dbManager.h" #include "dbStream.h" @@ -1773,13 +1774,17 @@ MainWindow::cm_goto_position () double x = 0.0, y = 0.0, s = 0.0; std::string tt (tl::to_string (text)); + tl::Extractor ex (tt.c_str ()); - ex >> x >> "," >> y; + x = tl::Eval ().parse (ex).execute ().to_double (); + ex.test (","); + y = tl::Eval ().parse (ex).execute ().to_double (); db::DPoint pt (x, y); if (! ex.at_end ()) { - ex >> "," >> s >> tl::Extractor::end (); + ex.test (","); + s = tl::Eval ().parse (ex).execute ().to_double (); current_view ()->goto_window (pt, s); } else { current_view ()->goto_window (pt); @@ -2520,21 +2525,30 @@ MainWindow::cm_new_layout () std::string technology = m_initial_technology; static std::string s_new_cell_cell_name ("TOP"); static double s_new_cell_window_size = 2.0; + static std::vector s_layers; double dbu = 0.0; lay::NewLayoutPropertiesDialog dialog (this); - if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, m_new_layout_current_panel)) { + if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, s_layers, m_new_layout_current_panel)) { - lay::CellViewRef cellview = create_or_load_layout (0, 0, technology, m_new_layout_current_panel ? 2 : 1 /*= new view*/); + std::unique_ptr handle (new lay::LayoutHandle (new db::Layout (& manager ()), std::string ())); + handle->rename ("new"); if (dbu > 1e-10) { - cellview->layout ().dbu (dbu); + handle->layout ().dbu (dbu); } - db::cell_index_type new_ci = cellview->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ()); - cellview.set_cell (new_ci); + db::cell_index_type new_ci = handle->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ()); - current_view ()->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1)); + for (std::vector::const_iterator l = s_layers.begin (); l != s_layers.end (); ++l) { + handle->layout ().insert_layer (*l); + } + + lay::LayoutView *mp_view = (m_new_layout_current_panel && current_view ()) ? current_view () : view (create_view ()); + + unsigned int ci = mp_view->add_layout (handle.release (), true); + mp_view->cellview_ref (ci).set_cell (new_ci); + mp_view->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1)); } } diff --git a/src/lay/lay/layProgress.cc b/src/lay/lay/layProgress.cc index 28c13a600..36624f20d 100644 --- a/src/lay/lay/layProgress.cc +++ b/src/lay/lay/layProgress.cc @@ -86,14 +86,13 @@ ProgressReporter::set_progress_bar (lay::ProgressBar *pb) void ProgressReporter::register_object (tl::Progress *progress) { - if (mp_objects.empty ()) { + if (begin () == end ()) { // to avoid recursions of any kind, disallow any user interaction except // cancelling the operation QApplication::instance ()->installEventFilter (this); } - mp_objects.push_back (*progress); // this keeps the outmost one visible. push_front would make the latest one visible. - // mp_objects.push_front (progress); + tl::ProgressAdaptor::register_object (progress); if (m_start_time == tl::Clock () && ! m_pw_visible) { m_start_time = tl::Clock::current (); @@ -104,33 +103,47 @@ ProgressReporter::register_object (tl::Progress *progress) set_visible (true); } - update_and_yield (); + if (progress->is_abstract ()) { + if (mp_pb) { + mp_pb->update_progress (progress); + } + process_events (); + } else { + update_and_yield (); + } } void ProgressReporter::unregister_object (tl::Progress *progress) { - progress->unlink (); + tl::ProgressAdaptor::unregister_object (progress); // close or refresh window - if (mp_objects.empty ()) { + if (begin () == end ()) { + if (m_pw_visible) { set_visible (false); } + m_start_time = tl::Clock (); - } - update_and_yield (); + if (mp_pb) { + mp_pb->update_progress (0); + } + + process_events (); - if (mp_objects.empty ()) { QApplication::instance ()->removeEventFilter (this); + + } else { + update_and_yield (); } } void ProgressReporter::trigger (tl::Progress * /*progress*/) { - if (! mp_objects.empty ()) { + if (begin () != end ()) { // make dialog visible after some time has passed if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { set_visible (true); @@ -152,27 +165,22 @@ ProgressReporter::yield (tl::Progress * /*progress*/) } } -void -ProgressReporter::signal_break () -{ - for (tl::list::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) { - k->signal_break (); - } -} - void ProgressReporter::update_and_yield () { - if (m_pw_visible && ! mp_objects.empty ()) { - if (mp_pb) { - mp_pb->update_progress (mp_objects.first ()); - QWidget *w = mp_pb->progress_get_widget (); - if (w) { - mp_objects.first ()->render_progress (w); - } - } - process_events (); // Qt4 seems to need this + if (! m_pw_visible) { + return; } + + if (mp_pb && first ()) { + mp_pb->update_progress (first ()); + QWidget *w = mp_pb->progress_get_widget (); + if (w) { + first ()->render_progress (w); + } + } + + process_events (); // Qt4 seems to need this } void @@ -202,8 +210,8 @@ ProgressReporter::set_visible (bool vis) if (mp_pb) { if (!vis) { mp_pb->progress_remove_widget (); - } else if (mp_pb->progress_wants_widget () && mp_objects.first ()) { - mp_pb->progress_add_widget (mp_objects.first ()->progress_widget ()); + } else if (mp_pb->progress_wants_widget () && first ()) { + mp_pb->progress_add_widget (first ()->progress_widget ()); } } diff --git a/src/lay/lay/layProgress.h b/src/lay/lay/layProgress.h index 570a0506d..7bb7023c0 100644 --- a/src/lay/lay/layProgress.h +++ b/src/lay/lay/layProgress.h @@ -68,16 +68,9 @@ public: virtual void yield (tl::Progress *progress); virtual bool eventFilter (QObject *dest, QEvent *event); - void signal_break (); void set_progress_bar (lay::ProgressBar *pb); - bool is_busy () const - { - return !mp_objects.empty (); - } - private: - tl::list mp_objects; tl::Clock m_start_time; lay::ProgressBar *mp_pb; bool m_pw_visible; diff --git a/src/lay/lay/layProgressWidget.cc b/src/lay/lay/layProgressWidget.cc index 703c5ed41..3c4cfe670 100644 --- a/src/lay/lay/layProgressWidget.cc +++ b/src/lay/lay/layProgressWidget.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -59,7 +60,7 @@ private: ProgressBarWidget::ProgressBarWidget (QWidget *parent, const char *name) : QWidget (parent), - m_value (0.0), m_width (64), m_length (0), m_fw (1), m_bw (0) + m_value (0.0), m_width (200), m_length (0), m_fw (1), m_bw (0) { setObjectName (QString::fromUtf8 (name)); setMinimumSize (64, 10); @@ -134,13 +135,46 @@ ProgressBarWidget::resizeEvent (QResizeEvent *) // -------------------------------------------------------------------- -ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width) +ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw) : QFrame (parent), - mp_widget (0), mp_pr (pr) + mp_widget (0), mp_pr (pr), m_log_file (0, true), m_log_visible (false) { QVBoxLayout *top_layout = new QVBoxLayout (this); top_layout->addStretch (1); + mp_log_frame = new QFrame (this); + mp_log_frame->setFrameShape (QFrame::NoFrame); + mp_log_frame->hide (); + top_layout->addWidget (mp_log_frame); + + QVBoxLayout *log_layout = new QVBoxLayout (mp_log_frame); + + QListView *log_view = new QListView (this); + log_view->setModel (&m_log_file); + log_view->setUniformItemSizes (true); + log_layout->addWidget (log_view); + + QFrame *attn_frame = new QFrame (this); + attn_frame->setFrameShape (QFrame::NoFrame); + attn_frame->hide (); + log_layout->addWidget (attn_frame); + + QHBoxLayout *attn_layout = new QHBoxLayout (attn_frame); + attn_layout->setContentsMargins (0, 0, 0, 0); + + QLabel *attn_label1 = new QLabel (attn_frame); + attn_label1->setPixmap (QPixmap (QString::fromUtf8 (":/warn_16.png"))); + attn_layout->addWidget (attn_label1); + + QLabel *attn_label2 = new QLabel (attn_frame); + attn_label2->setText (tr ("There are errors or warnings")); + attn_layout->addWidget (attn_label2); + + attn_layout->addStretch (1); + + connect (&m_log_file, SIGNAL (layoutChanged ()), log_view, SLOT (scrollToBottom ())); + connect (&m_log_file, SIGNAL (attention_changed (bool)), attn_frame, SLOT (setVisible (bool))); + QFrame *bar_frame = new QFrame (this); top_layout->addWidget (bar_frame); @@ -157,12 +191,11 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full int col = 0; - if (! full_width) { - layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1); - layout->setColumnStretch (col++, 1); - } + layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1); + m_left_col = col++; mp_label = new QLabel (bar_frame); + layout->setColumnStretch(col, 2); layout->addWidget (mp_label, 0, col++, 1, 1); layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); @@ -171,7 +204,6 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain); progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); layout->addWidget (progress_bar_frame, 0, col, 1, 1); - layout->setColumnStretch(col++, 2); QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame); progress_bar_frame->setLayout (pbf_layout); @@ -191,16 +223,41 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full mp_cancel_button->setText (QObject::tr ("Cancel")); layout->addWidget (mp_cancel_button, 0, col++, 1, 1); - if (! full_width) { - layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1); - layout->setColumnStretch (col++, 1); - } + layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1); + m_right_col = col++; layout->addItem (new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0, 1, col); m_widget_col = col; connect (mp_cancel_button, SIGNAL (clicked ()), this, SLOT (signal_break ())); + + set_full_width (fw); +} + +void +ProgressWidget::set_log_visible (bool f) +{ + if (f != m_log_visible) { + m_log_visible = f; + mp_log_frame->setVisible (f); + set_full_width (m_full_width); + } +} +void +ProgressWidget::set_full_width (bool fw) +{ + m_full_width = fw; + + bool f = (fw || m_log_visible); + mp_layout->setColumnStretch (m_left_col, f ? 0 : 1); + mp_layout->setColumnStretch (m_right_col, f ? 0 : 1); +} + +bool +ProgressWidget::full_width () const +{ + return m_full_width; } QWidget * @@ -233,6 +290,13 @@ ProgressWidget::remove_widget () void ProgressWidget::set_progress (tl::Progress *progress) { + if (! progress || progress->is_abstract ()) { + m_log_file.clear (); + m_log_file.set_max_entries (progress ? 1000 : 0); + set_log_visible (progress != 0); + return; + } + bool can_cancel = false; std::string text; diff --git a/src/lay/lay/layProgressWidget.h b/src/lay/lay/layProgressWidget.h index 4e712be4f..0600f7e5d 100644 --- a/src/lay/lay/layProgressWidget.h +++ b/src/lay/lay/layProgressWidget.h @@ -31,11 +31,14 @@ #include #include "layProgress.h" +#include "layLogViewerDialog.h" class QToolButton; class QLabel; class QToolButton; class QGridLayout; +class QListView; +class QFrame; namespace tl { @@ -59,6 +62,8 @@ public: void add_widget (QWidget *widget); void remove_widget (); QWidget *get_widget () const; + void set_full_width (bool fw); + bool full_width () const; QSize sizeHint () const; @@ -73,6 +78,13 @@ private: QGridLayout *mp_layout; QToolButton *mp_cancel_button; ProgressReporter *mp_pr; + lay::LogFile m_log_file; + QFrame *mp_log_frame; + bool m_full_width; + int m_left_col, m_right_col; + bool m_log_visible; + + void set_log_visible (bool f); }; } diff --git a/src/lay/lay/laySaltDownloadManager.cc b/src/lay/lay/laySaltDownloadManager.cc index e2f5d07a9..bc3ed4f4e 100644 --- a/src/lay/lay/laySaltDownloadManager.cc +++ b/src/lay/lay/laySaltDownloadManager.cc @@ -409,8 +409,6 @@ namespace mp_dialog->mark_fetching (m_name); } - virtual void register_object (tl::Progress * /*progress*/) { } - virtual void unregister_object (tl::Progress * /*progress*/) { } virtual void yield (tl::Progress * /*progress*/) { } virtual void trigger (tl::Progress *progress) diff --git a/src/lay/lay/laySearchReplaceDialog.cc b/src/lay/lay/laySearchReplaceDialog.cc index 0c5f5b321..4f8196e64 100644 --- a/src/lay/lay/laySearchReplaceDialog.cc +++ b/src/lay/lay/laySearchReplaceDialog.cc @@ -1040,7 +1040,7 @@ BEGIN_PROTECTED query_to_model (model, lq, iq, std::numeric_limits::max (), true); model.end_changes (); - std::unique_ptr handle (new lay::LayoutHandle (new db::Layout (), std::string ())); + std::unique_ptr handle (new lay::LayoutHandle (new db::Layout (mp_view->manager ()), std::string ())); handle->rename ("query_results"); model.export_layout (handle->layout ()); mp_view->add_layout (handle.release (), true); diff --git a/src/lay/lay/laySession.cc b/src/lay/lay/laySession.cc index 6aebf4b11..0cdaae8ff 100644 --- a/src/lay/lay/laySession.cc +++ b/src/lay/lay/laySession.cc @@ -145,7 +145,7 @@ Session::make_absolute (const std::string &fp) const { tl::URI fp_uri (fp); if (! m_base_dir.empty () && ! tl::is_absolute (fp_uri.path ())) { - return tl::URI (m_base_dir).resolved (fp_uri).to_string (); + return tl::URI (m_base_dir).resolved (fp_uri).to_abstract_path (); } else { return fp; } diff --git a/src/lay/lay/laySignalHandler.cc b/src/lay/lay/laySignalHandler.cc index 62f64ab03..7f98458c3 100644 --- a/src/lay/lay/laySignalHandler.cc +++ b/src/lay/lay/laySignalHandler.cc @@ -447,12 +447,10 @@ void signal_handler (int signo, siginfo_t *si, void *) void install_signal_handlers () { struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); act.sa_sigaction = signal_handler; sigemptyset (&act.sa_mask); act.sa_flags = SA_SIGINFO; -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) - act.sa_restorer = 0; -#endif sigaction (SIGSEGV, &act, NULL); sigaction (SIGILL, &act, NULL); diff --git a/src/lay/lay/layTextProgress.cc b/src/lay/lay/layTextProgress.cc index 829b84896..6d67fc2b8 100644 --- a/src/lay/lay/layTextProgress.cc +++ b/src/lay/lay/layTextProgress.cc @@ -35,6 +35,10 @@ TextProgress::TextProgress (int verbosity) void TextProgress::update_progress (tl::Progress *progress) { + if (! progress || progress->is_abstract ()) { + return; + } + std::string text = progress->desc (); if (m_progress_text != text && tl::verbosity () >= m_verbosity) { tl::info << text << " .."; diff --git a/src/lay/unit_tests/laySessionTests.cc b/src/lay/unit_tests/laySessionTests.cc index 6d7e8b438..34a74cfe3 100644 --- a/src/lay/unit_tests/laySessionTests.cc +++ b/src/lay/unit_tests/laySessionTests.cc @@ -45,6 +45,8 @@ TEST (1) lay::LayoutView *view = mw->current_view (); + view->set_title ("xyz"); + ant::Service *ant_service = view->get_plugin (); tl_assert (ant_service != 0); if (ant_service) { @@ -84,6 +86,8 @@ TEST (1) view = mw->current_view (); tl_assert (view != 0); + EXPECT_EQ (view->title (), "xyz"); + ant_service = view->get_plugin (); tl_assert (ant_service != 0); if (ant_service) { diff --git a/src/laybasic/laybasic/NewLayoutPropertiesDialog.ui b/src/laybasic/laybasic/NewLayoutPropertiesDialog.ui index 200666491..588a93c4f 100644 --- a/src/laybasic/laybasic/NewLayoutPropertiesDialog.ui +++ b/src/laybasic/laybasic/NewLayoutPropertiesDialog.ui @@ -6,8 +6,8 @@ 0 0 - 563 - 234 + 594 + 401
    @@ -50,7 +50,7 @@ 6 - + @@ -60,13 +60,6 @@ - - - - Database unit - - - @@ -80,13 +73,80 @@ - + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Qt::Horizontal + + + + 141 + 20 + + + + + µm + + + + µm + + + + + + + Top cell + + + + + + + Database unit + + + + + + + Technology + + + @@ -100,74 +160,34 @@ - - - - - 0 - 0 - - - - - - - - - + + - Top cell + (empty for default) - - - - - 0 - 0 - - - - - - - - Technology - - - - + Initial window size - - + + - µm + Initial layer(s) - - - - Qt::Horizontal - - - - 141 - 20 - - - - - - + + - (empty for default) + <html><head/><body>Specify a comma or blank separated list of layers to create in the usual layer notation, e.g. "1/0 2/0 3/0", "metal1 via1 metal2" or "metal1 (1/0) via1 (2/0) metal2 (3/0)"</body></html> + + + true @@ -214,10 +234,12 @@ + tech_cbx topcell_le dbu_le window_le - buttonBox + layers_le + current_panel_cb diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index 286715b75..a0ac9a6a5 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -1977,6 +1977,11 @@ static std::string get_technology (const lay::CellViewRef *cv) } } +static tl::Event &get_technology_changed_event (lay::CellViewRef *cv) +{ + return (*cv)->technology_changed_event; +} + static lay::CellViewRef get_active_cellview_ref () { lay::LayoutView *view = lay::LayoutView::current (); @@ -2183,6 +2188,12 @@ Class decl_CellView ("lay", "CellView", "fashion, i.e. describing each instance in detail, not just by cell indexes. If " "the context and target cell are identical, the context path is empty." ) + + event_ext ("on_technology_changed", &get_technology_changed_event, + "@brief An event indicating that the technology has changed\n" + "This event is triggered when the CellView is attached to a different technology.\n" + "\n" + "This event has been introduced in version 0.27.\n" + ) + method_ext ("technology", &get_technology, "@brief Returns the technology name for the layout behind the given cell view\n" "This method has been added in version 0.23.\n" diff --git a/src/laybasic/laybasic/layCellTreeModel.cc b/src/laybasic/laybasic/layCellTreeModel.cc index da4507d0a..e6ad4b2cc 100644 --- a/src/laybasic/laybasic/layCellTreeModel.cc +++ b/src/laybasic/laybasic/layCellTreeModel.cc @@ -87,7 +87,9 @@ struct cmp_cell_tree_item_vs_name_f // CellTreeItem implementation CellTreeItem::CellTreeItem (const db::Layout *layout, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting s) - : mp_layout (layout), mp_parent (0), m_sorting (s), m_is_pcell (is_pcell), m_index (0), m_children (), m_cell_or_pcell_index (cell_or_pcell_index) + : mp_layout (layout), mp_parent (0), m_sorting (s), m_is_pcell (is_pcell), + m_index (0), m_tree_index (0), + m_children (), m_cell_or_pcell_index (cell_or_pcell_index) { if (! flat && ! is_pcell) { m_child_count = int (mp_layout->cell (cell_or_pcell_index).child_cells ()); @@ -104,6 +106,16 @@ CellTreeItem::~CellTreeItem () m_children.clear (); } +size_t +CellTreeItem::assign_serial (size_t index, std::map &serial) +{ + serial.insert (std::make_pair (this, index++)); + for (std::vector::iterator c = m_children.begin (); c != m_children.end (); ++c) { + index = (*c)->assign_serial (index, serial); + } + return index; +} + bool CellTreeItem::is_valid () const { @@ -128,10 +140,22 @@ CellTreeItem::children () const return m_child_count; } -CellTreeItem * -CellTreeItem::child (int index) +int +CellTreeItem::children_in (const std::set &sel) const { - if (! m_is_pcell && int (m_children.size ()) <= index) { + size_t count = 0; + for (std::vector::const_iterator c = m_children.begin (); c != m_children.end (); ++c) { + if (sel.find (*c) != sel.end ()) { + ++count; + } + } + return count; +} + +void +CellTreeItem::ensure_children () +{ + if (! m_is_pcell && m_children.empty ()) { // create a list of child sub-item @@ -146,10 +170,29 @@ CellTreeItem::child (int index) finish_children (); } +} +CellTreeItem * +CellTreeItem::child (int index) +{ + ensure_children (); return m_children [index]; } +CellTreeItem * +CellTreeItem::child_in (const std::set &sel, int index) +{ + ensure_children (); + + for (std::vector::const_iterator c = m_children.begin (); c != m_children.end (); ++c) { + if (sel.find (*c) != sel.end () && index-- <= 0) { + return *c; + } + } + + return 0; +} + void CellTreeItem::add_child (CellTreeItem *item) { @@ -274,6 +317,8 @@ CellTreeModel::CellTreeModel (QWidget *parent, lay::LayoutView *view, int cv_ind m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0); m_pad = ((flags & NoPadding) == 0); + m_filter_mode = false; + m_is_filtered = false; mp_layout = & view->cellview (cv_index)->layout (); mp_library = 0; @@ -295,6 +340,7 @@ CellTreeModel::CellTreeModel (QWidget *parent, db::Layout *layout, unsigned int { m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0); m_pad = ((flags & NoPadding) == 0); + m_filter_mode = false; mp_layout = layout; mp_library = 0; @@ -316,6 +362,7 @@ CellTreeModel::CellTreeModel (QWidget *parent, db::Library *library, unsigned in { m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0); m_pad = ((flags & NoPadding) == 0); + m_filter_mode = false; mp_layout = &library->layout (); mp_library = library; @@ -404,6 +451,8 @@ CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::Layo } else { + emit layoutAboutToBeChanged (); + // Translate persistent indexes: translation happens according to the path given by // a sequence of cell indexes. @@ -465,9 +514,9 @@ CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::Layo changePersistentIndexList (indexes, new_indexes); - } + emit layoutChanged (); - signal_data_changed (); + } // TODO: harden against exceptions for (std::vector::iterator t = old_toplevel_items.begin (); t != old_toplevel_items.end (); ++t) { @@ -475,6 +524,15 @@ CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::Layo } } +void +CellTreeModel::set_filter_mode (bool f) +{ + if (f != m_filter_mode) { + m_filter_mode = f; + signal_data_changed (); + } +} + void CellTreeModel::set_sorting (Sorting s) { @@ -486,6 +544,7 @@ CellTreeModel::set_sorting (Sorting s) void CellTreeModel::signal_data_changed () { + emit layoutAboutToBeChanged (); emit layoutChanged (); } @@ -754,7 +813,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const } else if (role == Qt::BackgroundRole) { - if (m_selected_indexes_set.find (index) != m_selected_indexes_set.end ()) { + if (m_selected_indexes_set.find (index.internalPointer ()) != m_selected_indexes_set.end ()) { // for selected items pick a color between Highlight and Base QPalette pl (mp_parent->palette ()); QColor c1 = pl.color (QPalette::Highlight); @@ -819,11 +878,23 @@ CellTreeModel::rowCount (const QModelIndex &parent) const } else if (! item->is_valid ()) { // for safety we return 0 children for invalid cells return 0; + } else if (m_filter_mode && m_is_filtered) { + return int (item->children_in (m_visible_cell_set)); } else { return int (item->children ()); } } else { - return int (m_toplevel.size ()); + if (m_filter_mode && m_is_filtered) { + size_t n = 0; + for (std::vector ::const_iterator i = m_toplevel.begin (); i != m_toplevel.end (); ++i) { + if (m_visible_cell_set.find (*i) != m_visible_cell_set.end ()) { + ++n; + } + } + return n; + } else { + return int (m_toplevel.size ()); + } } } @@ -839,11 +910,25 @@ CellTreeModel::index (int row, int column, const QModelIndex &parent) const } else if (! item->is_valid ()) { // for safety we don't return valid child indexes for invalid cells return QModelIndex (); + } else if (m_filter_mode && m_is_filtered) { + return createIndex (row, column, item->child_in (m_visible_cell_set, row)); } else { return createIndex (row, column, item->child (row)); } } else if (row >= 0 && row < int (m_toplevel.size ())) { - return createIndex (row, column, m_toplevel [row]); + if (m_filter_mode && m_is_filtered) { + int n = row; + for (std::vector ::const_iterator i = m_toplevel.begin (); i != m_toplevel.end (); ++i) { + if (m_visible_cell_set.find (*i) != m_visible_cell_set.end ()) { + if (n-- == 0) { + return createIndex (row, column, *i); + } + } + } + return QModelIndex (); + } else { + return createIndex (row, column, m_toplevel [row]); + } } else { return QModelIndex (); } @@ -862,9 +947,19 @@ CellTreeModel::parent (const QModelIndex &index) const if (! item) { return QModelIndex (); } + CellTreeItem *pitem = item->parent (); if (pitem) { - return createIndex (int (pitem->index ()), index.column (), pitem); + if (m_filter_mode && m_is_filtered) { + if (pitem->tree_index () == std::numeric_limits::max ()) { + // WARNING: invisible item! + return QModelIndex (); + } else { + return createIndex (int (pitem->tree_index ()), index.column (), pitem); + } + } else { + return createIndex (int (pitem->index ()), index.column (), pitem); + } } else { return QModelIndex (); } @@ -895,6 +990,13 @@ CellTreeModel::model_index (CellTreeItem *item) const { if (mp_layout->under_construction () || (mp_layout->manager () && mp_layout->manager ()->transacting ())) { return QModelIndex (); + } else if (m_filter_mode && m_is_filtered) { + if (item->tree_index () == std::numeric_limits::max ()) { + // WARNING: invisible item! + return QModelIndex (); + } else { + return createIndex (int (item->tree_index ()), 0, item); + } } else { return createIndex (int (item->index ()), 0, item); } @@ -963,10 +1065,72 @@ void CellTreeModel::clear_locate () { m_selected_indexes.clear (); + m_visible_cell_set.clear (); + m_is_filtered = false; m_current_index = m_selected_indexes.begin (); m_selected_indexes_set.clear (); - signal_data_changed (); + emit layoutAboutToBeChanged (); + + if (m_filter_mode) { + + QModelIndexList indexes = persistentIndexList (); + + QModelIndexList new_indexes; + for (QModelIndexList::iterator i = indexes.begin (); i != indexes.end (); ++i) { + new_indexes.push_back (model_index ((CellTreeItem *) i->internalPointer ())); + } + + changePersistentIndexList (indexes, new_indexes); + + } + + emit layoutChanged (); +} + +QModelIndex +CellTreeModel::locate_next (const QModelIndex &index) +{ + if (m_current_index == m_selected_indexes.end ()) { + return QModelIndex (); + } else if (! index.isValid ()) { + return locate_next (); + } + + // easy case: the requested index is a selected one + + for (std::vector ::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) { + if (i->internalPointer () == index.internalPointer ()) { + m_current_index = i; + if (++m_current_index == m_selected_indexes.end ()) { + m_current_index = m_selected_indexes.begin (); + } + return *m_current_index; + } + } + + // otherwise: search by sequential order + + m_current_index = m_selected_indexes.begin (); + + std::map serial_index; + size_t seq = 0; + for (size_t i = 0; i < m_toplevel.size (); ++i) { + seq = m_toplevel [i]->assign_serial (seq, serial_index); + } + + size_t serial = serial_index [(CellTreeItem *) index.internalPointer ()]; + size_t next = 0; + + for (std::vector ::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) { + size_t s = serial_index [(CellTreeItem *) i->internalPointer ()]; + if (s > serial && (next == 0 || s < next)) { + next = s; + m_current_index = i; + } + } + + return *m_current_index; } QModelIndex @@ -1005,19 +1169,42 @@ CellTreeModel::locate_prev () } } -void +bool CellTreeModel::search_children (const tl::GlobPattern &pattern, CellTreeItem *item) { + bool any = false; + size_t ti = 0; + int children = item->children (); for (int i = 0; i < children; ++i) { + CellTreeItem *c = item->child (i); if (c) { + + bool visible = false; + + c->set_tree_index (std::numeric_limits::max ()); if (c->name_matches (pattern)) { + c->set_tree_index (ti); m_selected_indexes.push_back (model_index (c)); + visible = true; } - search_children (pattern, c); + if (search_children (pattern, c)) { + c->set_tree_index (ti); + visible = true; + } + + if (visible) { + ++ti; + m_visible_cell_set.insert (c); + any = true; + } + } + } + + return any; } QModelIndex @@ -1027,26 +1214,75 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, return QModelIndex (); } + emit layoutAboutToBeChanged (); + + QModelIndexList indexes = persistentIndexList (); + std::vector persistent_index_cells; + persistent_index_cells.reserve (indexes.size ()); + + for (QModelIndexList::iterator i = indexes.begin (); i != indexes.end (); ++i) { + persistent_index_cells.push_back ((CellTreeItem *) i->internalPointer ()); + } + m_selected_indexes.clear (); + m_visible_cell_set.clear (); + m_is_filtered = true; tl::GlobPattern p = tl::GlobPattern (std::string (name)); p.set_case_sensitive (case_sensitive); p.set_exact (!glob_pattern); p.set_header_match (true); + size_t ti = 0; + for (std::vector ::const_iterator lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) { + + bool visible = false; + + (*lc)->set_tree_index (std::numeric_limits::max ()); if ((*lc)->name_matches (p)) { + (*lc)->set_tree_index (ti); m_selected_indexes.push_back (model_index (*lc)); + visible = true; } - if (! top_only) { - search_children (p, *lc); + if (! top_only && ! m_flat && search_children (p, *lc)) { + (*lc)->set_tree_index (ti); + visible = true; } + + if (visible) { + ++ti; + m_visible_cell_set.insert (*lc); + } + } m_selected_indexes_set.clear (); - m_selected_indexes_set.insert (m_selected_indexes.begin (), m_selected_indexes.end ()); - - signal_data_changed (); + for (std::vector ::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) { + m_selected_indexes_set.insert (i->internalPointer ()); + } + + // re-layout the items + + if (m_filter_mode) { + + QModelIndexList new_indexes; + + for (std::vector::const_iterator item = persistent_index_cells.begin (); item != persistent_index_cells.end (); ++item) { + if (m_visible_cell_set.find (*item) != m_visible_cell_set.end ()) { + new_indexes.push_back (model_index (*item)); + } else { + new_indexes.push_back (QModelIndex ()); + } + } + + changePersistentIndexList (indexes, new_indexes); + + } + + emit layoutChanged (); + + // make the first selected one current m_current_index = m_selected_indexes.begin (); if (m_current_index == m_selected_indexes.end ()) { diff --git a/src/laybasic/laybasic/layCellTreeModel.h b/src/laybasic/laybasic/layCellTreeModel.h index b55477140..59d9a8934 100644 --- a/src/laybasic/laybasic/layCellTreeModel.h +++ b/src/laybasic/laybasic/layCellTreeModel.h @@ -202,6 +202,11 @@ public: */ QModelIndex locate_prev (); + /** + * @brief Resets the search pointer to the one next to the given index + */ + QModelIndex locate_next (const QModelIndex &index); + /** * @brief Clears the locate flags */ @@ -220,12 +225,21 @@ public: return m_sorting; } + /** + * @brief Sets a flag indicating whether selected indexes are filtered or highlighted + */ + void set_filter_mode (bool f); + + /** + * @brief Gets a flag indicating whether selected indexes are filtered or highlighted + */ + bool get_filter_mode () const + { + return m_filter_mode; + } + /** * @brief Signal to the owner of the model that the data has changed - * - * Basically, this signal should be emitted by the model, if it knew that - * something changed. However, in our current architecture, it does not. So we - * need to tell the model that something has changed. */ void signal_data_changed (); @@ -239,6 +253,7 @@ public: private: bool m_flat, m_pad; + bool m_filter_mode, m_is_filtered; unsigned int m_flags; Sorting m_sorting; QWidget *mp_parent; @@ -248,13 +263,14 @@ private: int m_cv_index; const db::Cell *mp_base; std::vector m_toplevel; - std::set m_selected_indexes_set; + std::set m_selected_indexes_set; + std::set m_visible_cell_set; std::vector m_selected_indexes; std::vector ::const_iterator m_current_index; void build_top_level (); void clear_top_level (); - void search_children (const tl::GlobPattern &pattern, CellTreeItem *item); + bool search_children (const tl::GlobPattern &pattern, CellTreeItem *item); void do_configure (db::Layout *layout, db::Library *library, lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting); }; @@ -271,7 +287,9 @@ public: ~CellTreeItem (); int children () const; + int children_in (const std::set &sel) const; CellTreeItem *child (int index); + CellTreeItem *child_in (const std::set &sel, int index); db::cell_index_type cell_or_pcell_index () const; CellTreeItem *parent () const; bool by_name_less_than (const CellTreeItem *b) const; @@ -300,17 +318,30 @@ public: m_index = index; } + size_t tree_index () const + { + return m_tree_index; + } + + void set_tree_index (size_t index) + { + m_tree_index = index; + } + + size_t assign_serial (size_t index, std::map &serial); + private: const db::Layout *mp_layout; CellTreeItem *mp_parent; CellTreeModel::Sorting m_sorting; bool m_is_pcell; - size_t m_index; + size_t m_index, m_tree_index; std::vector m_children; int m_child_count; size_t m_cell_or_pcell_index; const char *name () const; + void ensure_children (); }; } diff --git a/src/laybasic/laybasic/layDialogs.cc b/src/laybasic/laybasic/layDialogs.cc index 3eb6e7156..886684442 100644 --- a/src/laybasic/laybasic/layDialogs.cc +++ b/src/laybasic/laybasic/layDialogs.cc @@ -129,7 +129,7 @@ NewLayoutPropertiesDialog::tech_changed () } bool -NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &cell_name, double &dbu, double &size, bool ¤t_panel) +NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &cell_name, double &dbu, double &size, std::vector &layers, bool ¤t_panel) { mp_ui->tech_cbx->clear (); unsigned int technology_index = 0; @@ -151,6 +151,15 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce mp_ui->topcell_le->setText (tl::to_qstring (cell_name)); mp_ui->current_panel_cb->setChecked (current_panel); + std::string layer_string; + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + if (l != layers.begin ()) { + layer_string += ", "; + } + layer_string += l->to_string (); + } + mp_ui->layers_le->setText (tl::to_qstring (layer_string)); + if (QDialog::exec ()) { // get the selected technology name @@ -167,8 +176,24 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce } else { dbu = 0.0; } + cell_name = tl::to_string (mp_ui->topcell_le->text ()); current_panel = mp_ui->current_panel_cb->isChecked (); + + layers.clear (); + layer_string = tl::to_string (mp_ui->layers_le->text ()); + tl::Extractor ex (layer_string.c_str ()); + while (! ex.at_end ()) { + db::LayerProperties lp; + try { + lp.read (ex); + } catch (...) { + break; + } + layers.push_back (lp); + ex.test (","); + } + return true; } else { diff --git a/src/laybasic/laybasic/layDialogs.h b/src/laybasic/laybasic/layDialogs.h index 8a12966ea..cb926c3c8 100644 --- a/src/laybasic/laybasic/layDialogs.h +++ b/src/laybasic/laybasic/layDialogs.h @@ -328,7 +328,7 @@ public: NewLayoutPropertiesDialog (QWidget *parent); virtual ~NewLayoutPropertiesDialog (); - bool exec_dialog (std::string &tech_name, std::string &cell_name, double &dbu, double &window_size, bool ¤t_panel); + bool exec_dialog (std::string &tech_name, std::string &cell_name, double &dbu, double &window_size, std::vector &layers, bool ¤t_panel); private slots: void tech_changed (); diff --git a/src/laybasic/laybasic/layEditorOptionsPages.cc b/src/laybasic/laybasic/layEditorOptionsPages.cc index 5b9527220..0d53bae60 100644 --- a/src/laybasic/laybasic/layEditorOptionsPages.cc +++ b/src/laybasic/laybasic/layEditorOptionsPages.cc @@ -205,7 +205,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le Value value = Value (0); tl::from_string (tl::to_string (le->text ()), value); dispatcher->config_set (cfg_name, tl::to_string (value)); - lay::indicate_error (le, 0); + lay::indicate_error (le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (le, &ex); } diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc index fe5665c4c..5fe8ea03c 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.cc +++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc @@ -46,6 +46,7 @@ #include "layCellTreeModel.h" #include "layLayoutView.h" #include "layAbstractMenu.h" +#include "layQtTools.h" #include "layDialogs.h" #include "tlExceptions.h" #include "laybasicConfig.h" @@ -78,6 +79,17 @@ HCPCellTreeWidget::HCPCellTreeWidget (QWidget *parent, const char *name, QWidget setObjectName (QString::fromUtf8 (name)); } +HCPCellTreeWidget::~HCPCellTreeWidget () +{ + // NOTE: this should not be required, but I got a strange crash on closing the app with Qt 5.12.8 + // after using changePersistentIndex inside the model when ~QTreeWidget tried to clean up it's + // persistent indexes and only found a model which was deleted already. + QAbstractItemModel *m = model (); + if (m) { + setModel (0); + delete m; + } +} bool HCPCellTreeWidget::event (QEvent *event) @@ -242,7 +254,7 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa mp_search_close_cb->setMaximumSize (QSize (mp_search_close_cb->maximumSize ().width (), mp_search_close_cb->sizeHint ().height () - 4)); connect (mp_search_close_cb, SIGNAL (clicked ()), this, SLOT (search_editing_finished ())); - mp_search_model = 0; + m_search_index = -1; mp_search_edit_box = new lay::DecoratedLineEdit (mp_search_frame); mp_search_edit_box->setObjectName (QString::fromUtf8 ("cellview_search_edit_box")); mp_search_edit_box->set_escape_signal_enabled (true); @@ -264,11 +276,18 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa mp_case_sensitive->setChecked (true); mp_case_sensitive->setText (tr ("Case sensitive search")); + mp_filter = new QAction (this); + mp_filter->setCheckable (true); + mp_filter->setChecked (false); + mp_filter->setText (tr ("Apply as filter")); + QMenu *m = new QMenu (mp_search_edit_box); m->addAction (mp_use_regular_expressions); m->addAction (mp_case_sensitive); + m->addAction (mp_filter); connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ())); connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ())); + connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ())); mp_search_edit_box->set_clear_button_enabled (true); mp_search_edit_box->set_options_button_enabled (true); @@ -401,20 +420,20 @@ HierarchyControlPanel::cm_cell_select () void HierarchyControlPanel::search_triggered (const QString &t) { - mp_search_model = 0; + m_search_index = -1; lay::HCPCellTreeWidget *w = dynamic_cast (sender ()); if (w) { for (size_t i = 0; i < mp_cell_lists.size (); ++i) { if (mp_cell_lists [i] == w) { // Switch the active list for split mode -> CAUTION: this may trigger a search_editing_finished call select_active (int (i)); - mp_search_model = dynamic_cast (w->model ()); + m_search_index = int (i); break; } } } - if (mp_search_model) { + if (m_search_index >= 0) { mp_search_close_cb->setChecked (true); mp_search_frame->show (); mp_search_edit_box->setText (t); @@ -426,36 +445,43 @@ HierarchyControlPanel::search_triggered (const QString &t) void HierarchyControlPanel::search_edited () { + bool filter_invalid = false; + QString t = mp_search_edit_box->text (); - for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { - if ((*v)->model () == mp_search_model) { - if (t.isEmpty ()) { - mp_search_model->clear_locate (); - (*v)->setCurrentIndex (QModelIndex ()); + if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) { + + lay::CellTreeModel *search_model = dynamic_cast (mp_cell_lists [m_search_index]->model ()); + + search_model->set_filter_mode (mp_filter->isChecked ()); + + if (t.isEmpty ()) { + search_model->clear_locate (); + mp_cell_lists [m_search_index]->setCurrentIndex (QModelIndex ()); + } else { + QModelIndex found = search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false); + mp_cell_lists [m_search_index]->setCurrentIndex (found); + if (found.isValid ()) { + mp_cell_lists [m_search_index]->scrollTo (found); } else { - QModelIndex found = mp_search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false); - (*v)->setCurrentIndex (found); - if (found.isValid ()) { - (*v)->scrollTo (found); - } + filter_invalid = true; } - break; } + } + + lay::indicate_error (mp_search_edit_box, filter_invalid); } void HierarchyControlPanel::search_next () -{ - for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { - if ((*v)->model () == mp_search_model) { - QModelIndex found = mp_search_model->locate_next (); - if (found.isValid ()) { - (*v)->setCurrentIndex (found); - (*v)->scrollTo (found); - } - break; +{ + if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) { + lay::CellTreeModel *search_model = dynamic_cast (mp_cell_lists [m_search_index]->model ()); + QModelIndex found = search_model->locate_next (mp_cell_lists [m_search_index]->currentIndex ()); + if (found.isValid ()) { + mp_cell_lists [m_search_index]->setCurrentIndex (found); + mp_cell_lists [m_search_index]->scrollTo (found); } } } @@ -463,14 +489,12 @@ HierarchyControlPanel::search_next () void HierarchyControlPanel::search_prev () { - for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { - if ((*v)->model () == mp_search_model) { - QModelIndex found = mp_search_model->locate_prev (); - if (found.isValid ()) { - (*v)->setCurrentIndex (found); - (*v)->scrollTo (found); - } - break; + if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) { + lay::CellTreeModel *search_model = dynamic_cast (mp_cell_lists [m_search_index]->model ()); + QModelIndex found = search_model->locate_prev (); + if (found.isValid ()) { + mp_cell_lists [m_search_index]->setCurrentIndex (found); + mp_cell_lists [m_search_index]->scrollTo (found); } } } @@ -490,15 +514,12 @@ HierarchyControlPanel::search_editing_finished () } // give back the focus to the cell list - for (size_t i = 0; i < mp_cell_lists.size (); ++i) { - if (mp_cell_lists [i]->model () == mp_search_model) { - mp_cell_lists [i]->setFocus (); - break; - } + if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) { + mp_cell_lists [m_search_index]->setFocus (); } mp_search_frame->hide (); - mp_search_model = 0; + m_search_index = -1; } void @@ -786,8 +807,12 @@ void HierarchyControlPanel::do_update_content (int cv_index) { // close the search box since we will modify the model + if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) { + lay::CellTreeModel *search_model = dynamic_cast (mp_cell_lists [m_search_index]->model ()); + search_model->clear_locate (); + } mp_search_frame->hide (); - mp_search_model = 0; + m_search_index = -1; unsigned int imin = (cv_index < 0 ? 0 : (unsigned int) cv_index); unsigned int imax = (cv_index < 0 ? std::numeric_limits ::max () : (unsigned int) cv_index); @@ -1199,7 +1224,7 @@ public: menu_entries.push_back (lay::menu_item ("cm_cell_show", "show_cell", at, tl::to_string (QObject::tr ("Show")))); menu_entries.push_back (lay::menu_item ("cm_cell_show_all", "show_all", at, tl::to_string (QObject::tr ("Show All")))); menu_entries.push_back (lay::separator ("utils_group", at)); - menu_entries.push_back (lay::menu_item ("cm_open_current_cell", "open_current", at, tl::to_string (QObject::tr ("Where Am I?")))); + menu_entries.push_back (lay::menu_item ("cm_open_current_cell", "open_current", at, tl::to_string (QObject::tr ("Where am I?")))); menu_entries.push_back (lay::separator ("file_group", at)); menu_entries.push_back (lay::menu_item ("cm_save_current_cell_as", "save_cell_as:hide_vo", at, tl::to_string (QObject::tr ("Save Selected Cells As")))); } diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.h b/src/laybasic/laybasic/layHierarchyControlPanel.h index 826900bd5..1c539a40f 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.h +++ b/src/laybasic/laybasic/layHierarchyControlPanel.h @@ -66,6 +66,7 @@ Q_OBJECT public: HCPCellTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver); + ~HCPCellTreeWidget (); signals: void cell_clicked (const QModelIndex &); @@ -298,7 +299,8 @@ private: lay::DecoratedLineEdit *mp_search_edit_box; QAction *mp_case_sensitive; QAction *mp_use_regular_expressions; - CellTreeModel *mp_search_model; + QAction *mp_filter; + int m_search_index; QFrame *mp_search_frame; QCheckBox *mp_search_close_cb; QSplitter *mp_splitter; diff --git a/src/laybasic/laybasic/layLayerControlPanel.cc b/src/laybasic/laybasic/layLayerControlPanel.cc index 9cfeb1ec5..72ff771d0 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.cc +++ b/src/laybasic/laybasic/layLayerControlPanel.cc @@ -34,6 +34,7 @@ #include "layDialogs.h" #include "layLayoutCanvas.h" #include "layAbstractMenu.h" +#include "layQtTools.h" #include "tlExceptions.h" #include "tlInternational.h" #include "tlAssert.h" @@ -203,12 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage mp_view (view), m_needs_update (true), m_tabs_need_update (true), - m_force_update_hidden_flags (true), + m_hidden_flags_need_update (true), m_in_update (false), m_phase (0), m_do_update_content_dm (this, &LayerControlPanel::do_update_content), - m_hide_empty_layers (false), - m_test_shapes_in_view (false), m_no_stipples (false) { setObjectName (QString::fromUtf8 (name)); @@ -269,11 +268,18 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage mp_case_sensitive->setChecked (true); mp_case_sensitive->setText (tr ("Case sensitive search")); + mp_filter = new QAction (this); + mp_filter->setCheckable (true); + mp_filter->setChecked (false); + mp_filter->setText (tr ("Apply as filter")); + QMenu *m = new QMenu (mp_search_edit_box); m->addAction (mp_use_regular_expressions); m->addAction (mp_case_sensitive); + m->addAction (mp_filter); connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ())); connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ())); + connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ())); mp_search_edit_box->set_clear_button_enabled (true); mp_search_edit_box->set_options_button_enabled (true); @@ -370,6 +376,8 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage m_no_stipples_label->setPixmap (QPixmap (QString::fromUtf8 (":/important.png"))); m_no_stipples_label->setToolTip (tr ("Stipples are disabled - unselect \"View/Show Layers Without Fill\" to re-enable them")); ltb->addWidget (m_no_stipples_label); + + connect (mp_model, SIGNAL (hidden_flags_need_update ()), this, SLOT (update_hidden_flags ())); } LayerControlPanel::~LayerControlPanel () @@ -1126,6 +1134,10 @@ LayerControlPanel::search_edited () return; } + mp_model->set_filter_mode (mp_filter->isChecked ()); + + bool filter_invalid = false; + QString t = mp_search_edit_box->text (); if (t.isEmpty ()) { mp_model->clear_locate (); @@ -1135,8 +1147,12 @@ LayerControlPanel::search_edited () mp_layer_list->setCurrentIndex (found); if (found.isValid ()) { mp_layer_list->scrollTo (found); + } else { + filter_invalid = true; } } + + lay::indicate_error (mp_search_edit_box, filter_invalid); } void @@ -1642,27 +1658,29 @@ LayerControlPanel::set_text_color (QColor c) mp_model->set_text_color (c); } -void +void +LayerControlPanel::update_hidden_flags () +{ + m_hidden_flags_need_update = true; + m_do_update_content_dm (); +} + +void LayerControlPanel::set_hide_empty_layers (bool f) { - if (f != m_hide_empty_layers) { - m_hide_empty_layers = f; - m_force_update_hidden_flags = true; - m_do_update_content_dm (); - } + mp_model->set_hide_empty_layers (f); +} + +bool +LayerControlPanel::hide_empty_layers () +{ + return mp_model->get_hide_empty_layers (); } void LayerControlPanel::set_test_shapes_in_view (bool f) { - if (f != m_test_shapes_in_view) { - m_test_shapes_in_view = f; - mp_model->set_test_shapes_in_view (f); - if (m_hide_empty_layers) { - m_force_update_hidden_flags = true; - } - m_do_update_content_dm (); - } + mp_model->set_test_shapes_in_view (f); } void @@ -1671,6 +1689,7 @@ LayerControlPanel::begin_updates () if (! m_in_update) { m_in_update = true; + m_hidden_flags_need_update = true; mp_model->signal_begin_layer_changed (); // this makes the view redraw the data @@ -1701,13 +1720,13 @@ LayerControlPanel::cancel_updates () { m_in_update = false; m_needs_update = false; + m_hidden_flags_need_update = false; m_tabs_need_update = false; } void LayerControlPanel::end_updates () { - m_force_update_hidden_flags = true; do_update_content (); } @@ -1721,7 +1740,7 @@ LayerControlPanel::set_phase (int phase) } static void -set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty) +set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent) { int rows = model->rowCount (parent); for (int r = 0; r < rows; ++r) { @@ -1730,7 +1749,7 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c if (! model->hasChildren (index)) { - if (hide_empty && model->empty_within_view_predicate (index)) { + if (model->is_hidden (index)) { tree_view->setRowHidden (r, parent, true); } else { tree_view->setRowHidden (r, parent, false); @@ -1738,43 +1757,33 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c } else { tree_view->setRowHidden (r, parent, false); - set_hidden_flags_within_view_rec (model, tree_view, index, hide_empty); - } - - } -} - -static void -set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty) -{ - int rows = model->rowCount (parent); - for (int r = 0; r < rows; ++r) { - - QModelIndex index = model->index (r, 0, parent); - - if (! model->hasChildren (index)) { - - if (hide_empty && model->empty_predicate (index)) { - tree_view->setRowHidden (r, parent, true); - } else { - tree_view->setRowHidden (r, parent, false); - } - - } else { - tree_view->setRowHidden (r, parent, false); - set_hidden_flags_rec (model, tree_view, index, hide_empty); + set_hidden_flags_rec (model, tree_view, index); } } } +void +LayerControlPanel::do_update_hidden_flags () +{ + set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex ()); + + // scroll the current index into view if it was not visible before + QModelIndex current = mp_layer_list->currentIndex (); + if (current.isValid ()) { + QModelIndex parent = mp_layer_list->model ()->parent (current); + if (! mp_layer_list->isRowHidden (current.row (), parent)) { + QRect visual_rect = mp_layer_list->visualRect (current); + if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) { + mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter); + } + } + } +} + void LayerControlPanel::do_update_content () { - // clear search. TODO: update search instead of clearing - mp_search_edit_box->clear (); - mp_model->clear_locate(); - mp_model->set_phase (m_phase); if (m_tabs_need_update) { @@ -1827,7 +1836,7 @@ LayerControlPanel::do_update_content () mp_layer_list->setCurrentIndex(QModelIndex()); // this makes the view redraw the data and establishes a valid selection scheme - mp_model->signal_layer_changed (); + mp_model->signal_layers_changed (); // now realize the selection if required if (! m_new_sel.empty ()) { @@ -1853,47 +1862,28 @@ LayerControlPanel::do_update_content () m_needs_update = false; - } else { + } else if (m_needs_update) { - if (m_needs_update) { + m_needs_update = false; - m_needs_update = false; - - bool has_children = false; - for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) { - if (l->has_children ()) { - has_children = true; - } + bool has_children = false; + for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) { + if (l->has_children ()) { + has_children = true; } - mp_layer_list->setRootIsDecorated (has_children); - mp_layer_list->reset (); - - } else { - mp_model->signal_data_changed (); // this makes the view redraw the data } + mp_layer_list->setRootIsDecorated (has_children); + mp_layer_list->reset (); + } else { + mp_model->signal_data_changed (); // this makes the view redraw the data } - if (m_hide_empty_layers || m_force_update_hidden_flags) { + if (m_hidden_flags_need_update) { - m_force_update_hidden_flags = false; - if (m_test_shapes_in_view) { - set_hidden_flags_within_view_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers); - } else { - set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers); - } + do_update_hidden_flags (); - // scroll the current index into view if it was not visible before - QModelIndex current = mp_layer_list->currentIndex (); - if (current.isValid ()) { - QModelIndex parent = mp_layer_list->model ()->parent (current); - if (! mp_layer_list->isRowHidden (current.row (), parent)) { - QRect visual_rect = mp_layer_list->visualRect (current); - if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) { - mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter); - } - } - } + m_hidden_flags_need_update = false; } } @@ -1975,7 +1965,7 @@ LayerControlPanel::redo (db::Op *op) void LayerControlPanel::signal_vp_changed () { - if (m_test_shapes_in_view) { + if (mp_model->get_test_shapes_in_view ()) { update_required (1); } } @@ -2028,7 +2018,7 @@ LayerControlPanel::update_required (int f) } if ((f & 3) != 0) { - m_force_update_hidden_flags = true; + m_hidden_flags_need_update = true; } m_do_update_content_dm (); diff --git a/src/laybasic/laybasic/layLayerControlPanel.h b/src/laybasic/laybasic/layLayerControlPanel.h index 95f0acf34..f8124f8df 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.h +++ b/src/laybasic/laybasic/layLayerControlPanel.h @@ -184,10 +184,7 @@ public: /** * @brief Get the "hide empty layers" flag */ - bool hide_empty_layers () - { - return m_hide_empty_layers; - } + bool hide_empty_layers (); /** * @brief Set the "test_shapes_in_view" flag @@ -201,7 +198,7 @@ public: */ bool test_shapes_in_view () { - return m_test_shapes_in_view; + return mp_model->get_test_shapes_in_view (); } /** @@ -333,6 +330,9 @@ public slots: void search_next (); void search_prev (); +private slots: + void update_hidden_flags (); + private: QTabBar *mp_tab_bar; LCPTreeWidget *mp_layer_list; @@ -341,19 +341,18 @@ private: lay::LayoutView *mp_view; bool m_needs_update; bool m_tabs_need_update; - bool m_force_update_hidden_flags; + bool m_hidden_flags_need_update; bool m_in_update; std::vector m_new_sel; int m_phase; tl::DeferredMethod m_do_update_content_dm; - bool m_hide_empty_layers; - bool m_test_shapes_in_view; std::set m_expanded; bool m_no_stipples; QLabel *m_no_stipples_label; lay::DecoratedLineEdit *mp_search_edit_box; QAction *mp_case_sensitive; QAction *mp_use_regular_expressions; + QAction *mp_filter; QFrame *mp_search_frame; QCheckBox *mp_search_close_cb; @@ -369,6 +368,7 @@ private: void signal_vp_changed (); void do_update_content (); + void do_update_hidden_flags (); void do_delete (); void do_copy (); void recover (); diff --git a/src/laybasic/laybasic/layLayerTreeModel.cc b/src/laybasic/laybasic/layLayerTreeModel.cc index 9182580e1..66efa50e9 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.cc +++ b/src/laybasic/laybasic/layLayerTreeModel.cc @@ -180,7 +180,7 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutView *view) : QAbstractItemModel (parent), - mp_view (view), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false) + mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false) { // .. nothing yet .. } @@ -210,6 +210,37 @@ LayerTreeModel::set_text_color (QColor color) signal_data_changed (); } +void +LayerTreeModel::set_test_shapes_in_view (bool f) +{ + if (m_test_shapes_in_view != f) { + m_test_shapes_in_view = f; + if (m_hide_empty_layers) { + emit hidden_flags_need_update (); + } + signal_data_changed (); + } +} + +void +LayerTreeModel::set_hide_empty_layers (bool f) +{ + if (m_hide_empty_layers != f) { + m_hide_empty_layers = f; + // we actually can't do this ourselves. + emit hidden_flags_need_update (); + } +} + +void +LayerTreeModel::set_filter_mode (bool f) +{ + if (f != m_filter_mode) { + m_filter_mode = f; + emit hidden_flags_need_update (); + } +} + void LayerTreeModel::set_background_color (QColor background) { @@ -288,6 +319,10 @@ LayerTreeModel::clear_locate () m_selected_ids.clear (); signal_data_changed (); + + if (m_filter_mode) { + emit hidden_flags_need_update (); + } } QModelIndex @@ -358,6 +393,10 @@ LayerTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive signal_data_changed (); + if (m_filter_mode) { + emit hidden_flags_need_update (); + } + m_current_index = m_selected_indexes.begin (); if (m_current_index == m_selected_indexes.end ()) { return QModelIndex (); @@ -382,9 +421,9 @@ LayerTreeModel::signal_begin_layer_changed () } void -LayerTreeModel::signal_layer_changed () +LayerTreeModel::signal_layers_changed () { - // establish a new range of valid iterator indices + // establish a new range of valid iterator indices m_id_start = m_id_end; // TODO: is there a more efficient way to compute that? @@ -394,6 +433,21 @@ LayerTreeModel::signal_layer_changed () } m_id_end += max_id + 1; + // update the persistent indexes + + QModelIndexList indexes = persistentIndexList (); + QModelIndexList new_indexes; + for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end (); ++i) { + lay::LayerPropertiesConstIterator li = iterator (*i); + if (! li.at_end ()) { + new_indexes.push_back (createIndex (li.child_index (), i->column (), (void *) (li.uint () + m_id_start))); + } else { + new_indexes.push_back (QModelIndex ()); + } + } + + changePersistentIndexList (indexes, new_indexes); + m_test_shapes_cache.clear (); emit layoutChanged (); } @@ -481,6 +535,22 @@ single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap, lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, pimage, width, height, false, 0); } +bool +LayerTreeModel::is_hidden (const QModelIndex &index) const +{ + if (m_filter_mode && ! m_selected_ids.empty () && m_selected_ids.find (size_t (index.internalPointer ())) == m_selected_ids.end ()) { + return true; + } + + if (! m_hide_empty_layers) { + return false; + } else if (m_test_shapes_in_view) { + return empty_within_view_predicate (index); + } else { + return empty_predicate (index); + } +} + bool LayerTreeModel::empty_predicate (const QModelIndex &index) const { diff --git a/src/laybasic/laybasic/layLayerTreeModel.h b/src/laybasic/laybasic/layLayerTreeModel.h index 2d2882889..12bba517e 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.h +++ b/src/laybasic/laybasic/layLayerTreeModel.h @@ -126,21 +126,9 @@ public: lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const; /** - * @brief Get a flag indicating that a layer is empty + * @brief Get a flag indicating that an entry is hidden */ - bool empty_predicate (const QModelIndex &index) const; - - /** - * @brief Get a flag indicating that a layer does not have shapes within the shown area - */ - bool empty_within_view_predicate (const QModelIndex &index) const; - - /** - * @brief Set the non-empty layers (the "uint" for the layer iterators) for the "test shapes is view" mode - * - * @return True, if a change has been made. - */ - bool set_non_empty_layers (const std::set &non_empty_layers); + bool is_hidden (const QModelIndex &index) const; /** * @brief Set the animation phase @@ -201,13 +189,42 @@ public: void clear_locate (); /** - * @brief Set the test_shapes_in_view flag - * - * This method does not issue a data changed signal. This has to be done somewhere else. + * @brief Sets a flag indicating whether to test shapes in view for highlighting non-empty layers */ - void set_test_shapes_in_view (bool f) + void set_test_shapes_in_view (bool f); + + /** + * @brief Gets a flag indicating whether to test shapes in view for highlighting non-empty layers + */ + bool get_test_shapes_in_view () { - m_test_shapes_in_view = f; + return m_test_shapes_in_view; + } + + /** + * @brief Sets the flag indicating whether to hide empty layers + */ + void set_hide_empty_layers (bool f); + + /** + * @brief Gets the flag indicating whether to hide empty layers + */ + bool get_hide_empty_layers () const + { + return m_hide_empty_layers; + } + + /** + * @brief Sets a flag indicating whether selected indexes are filtered or highlighted + */ + void set_filter_mode (bool f); + + /** + * @brief Gets a flag indicating whether selected indexes are filtered or highlighted + */ + bool get_filter_mode () const + { + return m_filter_mode; } /** @@ -218,13 +235,22 @@ public: /** * @brief emit a layoutChanged signal */ - void signal_layer_changed (); + void signal_layers_changed (); + +signals: + /** + * @brief This signal is emitted to indicate the hidden flags need update by the client + * Note this is neither done by the view nor the model. It needs to be implemented elsewhere. + */ + void hidden_flags_need_update (); private: lay::LayoutView *mp_view; + bool m_filter_mode; size_t m_id_start, m_id_end; unsigned int m_phase; bool m_test_shapes_in_view; + bool m_hide_empty_layers; QFont m_font; QColor m_text_color, m_background_color; mutable EmptyWithinViewCache m_test_shapes_cache; @@ -232,6 +258,16 @@ private: std::vector m_selected_indexes; std::vector ::const_iterator m_current_index; + /** + * @brief Get a flag indicating that a layer is empty + */ + bool empty_predicate (const QModelIndex &index) const; + + /** + * @brief Get a flag indicating that a layer does not have shapes within the shown area + */ + bool empty_within_view_predicate (const QModelIndex &index) const; + void search_children (const tl::GlobPattern &pattern, const QModelIndex &parent, bool recurse); }; diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 1a4531ac1..c3bd6fc2a 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -2859,6 +2859,8 @@ LayoutView::add_new_layers (const std::vector &layer_ids, int cv_ // create the layers and do a basic recoloring .. lay::LayerPropertiesList new_props (get_properties ()); + bool was_empty = new_props.begin_const_recursive ().at_end (); + // don't create new layers for those, for which there are layers already: compute a // set of layers already present std::set present_layers; @@ -2890,6 +2892,10 @@ LayoutView::add_new_layers (const std::vector &layer_ids, int cv_ set_properties (new_props); + if (was_empty) { + set_current_layer (new_props.begin_const_recursive ()); + } + } } @@ -3291,6 +3297,18 @@ LayoutView::add_layout (lay::LayoutHandle *layout_handle, bool add_cellview, boo } + // select the first layer if nothing else is selected + if (cv_index == 0 && ! mp_control_panel->has_selection ()) { + const lay::LayerPropertiesList &lp = get_properties (); + lay::LayerPropertiesConstIterator li = lp.begin_const_recursive (); + while (! li.at_end () && li->has_children ()) { + ++li; + } + if (! li.at_end ()) { + mp_control_panel->set_current_layer (li); + } + } + // signal to any observers file_open_event (); @@ -3456,6 +3474,18 @@ LayoutView::load_layout (const std::string &filename, const db::LoadLayoutOption // create the initial layer properties create_initial_layer_props (cv_index, lyp_file, add_other_layers); + // select the first layer if nothing else is selected + if (cv_index == 0 && ! mp_control_panel->has_selection ()) { + const lay::LayerPropertiesList &lp = get_properties (); + lay::LayerPropertiesConstIterator li = lp.begin_const_recursive (); + while (! li.at_end () && li->has_children ()) { + ++li; + } + if (! li.at_end ()) { + mp_control_panel->set_current_layer (li); + } + } + // signal to any observers file_open_event (); diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index ce2d9534f..ccca57673 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -199,6 +199,7 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char : QFrame (parent), m_enable_cb (true), mp_view (view), + m_active_index (-1), m_split_mode (false), m_do_update_content_dm (this, &LibrariesView::do_update_content), m_do_full_update_content_dm (this, &LibrariesView::do_full_update_content) @@ -262,11 +263,18 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char mp_case_sensitive->setChecked (true); mp_case_sensitive->setText (tr ("Case sensitive search")); + mp_filter = new QAction (this); + mp_filter->setCheckable (true); + mp_filter->setChecked (false); + mp_filter->setText (tr ("Apply as filter")); + QMenu *m = new QMenu (mp_search_edit_box); m->addAction (mp_use_regular_expressions); m->addAction (mp_case_sensitive); + m->addAction (mp_filter); connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ())); connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ())); + connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ())); mp_search_edit_box->set_clear_button_enabled (true); mp_search_edit_box->set_options_button_enabled (true); @@ -382,6 +390,7 @@ LibrariesView::search_edited () for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { if ((*v)->model () == mp_search_model) { + mp_search_model->set_filter_mode (mp_filter->isChecked ()); if (t.isEmpty ()) { mp_search_model->clear_locate (); (*v)->setCurrentIndex (QModelIndex ()); diff --git a/src/laybasic/laybasic/layLibrariesView.h b/src/laybasic/laybasic/layLibrariesView.h index 712cecd1b..17c140dd2 100644 --- a/src/laybasic/laybasic/layLibrariesView.h +++ b/src/laybasic/laybasic/layLibrariesView.h @@ -242,6 +242,7 @@ private: lay::DecoratedLineEdit *mp_search_edit_box; QAction *mp_case_sensitive; QAction *mp_use_regular_expressions; + QAction *mp_filter; CellTreeModel *mp_search_model; QFrame *mp_search_frame; QCheckBox *mp_search_close_cb; diff --git a/src/laybasic/laybasic/layQtTools.cc b/src/laybasic/laybasic/layQtTools.cc index 2ca162fdc..a769a07be 100644 --- a/src/laybasic/laybasic/layQtTools.cc +++ b/src/laybasic/laybasic/layQtTools.cc @@ -162,22 +162,48 @@ restore_dialog_state (QWidget *dialog, const std::string &s, bool with_section_s void indicate_error (QWidget *le, const tl::Exception *ex) +{ + if (ex) { + indicate_error (le, true); + le->setToolTip (tl::to_qstring (ex->msg ())); + } else { + indicate_error (le, false); + le->setToolTip (QString ()); + } +} + +void +indicate_error (QWidget *le, bool f) { // by the way, update the foreground color of the cell edit box as well (red, if not valid) QPalette pl = le->palette (); - if (ex) { + if (f) { pl.setColor (QPalette::Active, QPalette::Text, Qt::red); pl.setColor (QPalette::Active, QPalette::Base, QColor (Qt::red).lighter (180)); - le->setToolTip (tl::to_qstring (ex->msg ())); } else { QWidget *pw = dynamic_cast (le->parent ()); tl_assert (pw != 0); pl.setColor (QPalette::Active, QPalette::Text, pw->palette ().color (QPalette::Text)); pl.setColor (QPalette::Active, QPalette::Base, pw->palette ().color (QPalette::Base)); - le->setToolTip (QString ()); } le->setPalette (pl); } +#if QT_VERSION < 0x050000 + +SignalBlocker::SignalBlocker (QWidget *w) + : mp_widget (w) +{ + m_state = mp_widget->blockSignals (true); +} + +SignalBlocker::~SignalBlocker () +{ + mp_widget->blockSignals (m_state); +} + +#endif + + } diff --git a/src/laybasic/laybasic/layQtTools.h b/src/laybasic/laybasic/layQtTools.h index fa216cfc8..763a8c706 100644 --- a/src/laybasic/laybasic/layQtTools.h +++ b/src/laybasic/laybasic/layQtTools.h @@ -31,6 +31,7 @@ class QLabel; class QWidget; class QObject; +class QSignalBlocker; namespace tl { @@ -76,6 +77,32 @@ LAYBASIC_PUBLIC void register_help_handler (QObject *object, const char *slot, c */ LAYBASIC_PUBLIC void indicate_error (QWidget *le, const tl::Exception *ex); +/** + * @brief Configures a QLineEdit or other widget to indicate an error + */ +LAYBASIC_PUBLIC void indicate_error (QWidget *le, bool error); + +#if QT_VERSION < 0x050000 + +// Provide missing QSignalBlocker for Qt4 + +class LAYBASIC_PUBLIC SignalBlocker +{ +public: + SignalBlocker (QWidget *w); + ~SignalBlocker (); + +private: + QWidget *mp_widget; + bool m_state; +}; + +#else + +typedef QSignalBlocker SignalBlocker; + +#endif + } // namespace lay #endif diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.cc b/src/laybasic/laybasic/layRedrawThreadWorker.cc index 5b38654b5..052380a38 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.cc +++ b/src/laybasic/laybasic/layRedrawThreadWorker.cc @@ -1531,9 +1531,9 @@ bool draw_array_simplified (lay::Renderer *r, const db::Shape &array_shape, lay: (na <= 1 || trans.ctrans (a.length ()) < 1.5) && (nb <= 1 || trans.ctrans (b.length ()) < 1.5)) { - db::DBox array_box_trans = trans * array_shape.bbox (); - r->draw (array_box_trans, frame, frame, 0, 0); - r->draw (array_box_trans, vertex, vertex, 0, 0); + db::Box array_box = array_shape.bbox (); + r->draw (array_box, trans, frame, frame, 0, 0); + r->draw (array_box, trans, vertex, vertex, 0, 0); return true; } else if (is_regular && diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index 17026ae56..c8d20fee9 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -34,6 +34,7 @@ #include "tlXMLParser.h" #include "tlGlobPattern.h" #include "tlInclude.h" +#include "tlProgress.h" #include "rba.h" #include "pya.h" @@ -1022,6 +1023,8 @@ int Macro::run () const try { + tl::ProgressGarbageCollector progress_gc; + gsi::Interpreter *ip = script_interpreter (interpreter ()); if (ip) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 68ec18f34..c5a7e6626 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -893,8 +893,16 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool } } +template +static db::DVector +via_size (double dbu, const Shape &shape) +{ + db::Box box = db::box_convert () (shape); + return db::DVector (box.width () * dbu, box.height () * dbu); +} + void -DEFImporter::read_vias (db::Layout & /*layout*/, db::Cell & /*design*/, double scale) +DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) { while (test ("-")) { @@ -1036,13 +1044,13 @@ DEFImporter::read_vias (db::Layout & /*layout*/, db::Cell & /*design*/, double s db::Polygon poly; read_polygon (poly, scale); - geo_based_vg->add_polygon (ln, ViaGeometry, poly, mask, 0); + geo_based_vg->add_polygon (ln, ViaGeometry, poly, mask, 0, via_size (layout.dbu (), poly)); } else { db::Polygon poly; read_rect (poly, scale); - geo_based_vg->add_polygon (ln, ViaGeometry, poly, mask, 0); + geo_based_vg->add_polygon (ln, ViaGeometry, poly, mask, 0, via_size (layout.dbu (), poly)); } @@ -1243,6 +1251,101 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) } } +void +DEFImporter::read_fills (db::Layout &layout, db::Cell &design, double scale) +{ + std::map , std::vector > geometry; + + while (test ("-")) { + + if (test ("LAYER")) { + + std::string ln = get (); + + unsigned int mask = 0; + bool opc = false; + + while (test ("+")) { + + if (test ("MASK")) { + mask = get_mask (get_long ()); + } else if (test ("OPC")) { + opc = true; + } else { + error (tl::to_string (tr ("'MASK' or 'OPC' keyword expected"))); + } + + } + + std::vector polygons; + + while (! test (";")) { + + if (test ("RECT")) { + + test ("("); + db::Point pt1 = get_point (scale); + test (")"); + + test ("("); + db::Point pt2 = get_point (scale); + test (")"); + + polygons.push_back (db::Polygon (db::Box (pt1, pt2))); + + } else if (test ("POLYGON")) { + + std::vector points; + + double x = 0.0, y = 0.0; + + while (test ("(")) { + + if (! test ("*")) { + x = get_double (); + } + if (! test ("*")) { + y = get_double (); + } + points.push_back (db::Point (db::DPoint (x * scale, y * scale))); + expect (")"); + + } + + polygons.push_back (db::Polygon ()); + polygons.back ().assign_hull (points.begin (), points.end ()); + + } else { + error (tl::to_string (tr ("'RECT' or 'POLYGON' keyword expected"))); + } + + } + + std::set dl = open_layer (layout, ln, opc ? FillsOPC : Fills, mask); + if (! dl.empty ()) { + for (std::vector::const_iterator p = polygons.begin (); p != polygons.end (); ++p) { + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + design.shapes (*l).insert (*p); + } + } + } + + } else if (test ("VIA")) { + + // TODO: implement + warn (tl::to_string (tr ("VIA not supported on fills currently"))); + + while (! at_end () && ! test (";")) { + take (); + } + + } else { + error (tl::to_string (tr ("'LAYER' or 'VIA' keyword expected"))); + } + + } +} + void DEFImporter::read_styles (double scale) { @@ -1426,10 +1529,16 @@ DEFImporter::do_read (db::Layout &layout) take (); } } else if (test ("FILLS")) { - // read over FILLS statements - while (! test ("END") || ! test ("FILLS")) { - take (); - } + + // Read FILLS statements + get_long (); + expect (";"); + + read_fills (layout, design, scale); + + expect ("END"); + expect ("FILLS"); + } else if (test ("SCANCHAINS")) { // read over SCANCHAINS statements while (! test ("END") || ! test ("SCANCHAINS")) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h index cbfb9c83a..5fee51f1c 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h @@ -85,6 +85,7 @@ private: void read_nets (db::Layout &layout, db::Cell &design, double scale, bool specialnets); void read_vias (db::Layout &layout, db::Cell &design, double scale); void read_pins (db::Layout &layout, db::Cell &design, double scale); + void read_fills (db::Layout &layout, db::Cell &design, double scale); void read_styles (double scale); void read_components (Layout &layout, std::list > &instances, double scale); void read_single_net (std::string &nondefaultrule, db::Layout &layout, db::Cell &design, double scale, properties_id_type prop_id, bool specialnets); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 615b8f556..31cd62093 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -110,6 +110,66 @@ static unsigned int mask (const std::vector &masks, unsigned int i } } +static std::string purpose_to_name (LayerPurpose purpose) +{ + switch (purpose) { + case Outline: + return "OUTLINE"; + case Regions: + return "REGION"; + case PlacementBlockage: + return "BLOCKAGE"; + case Routing: + return "NET"; + case SpecialRouting: + return "SPNET"; + case ViaGeometry: + return "VIA"; + case Label: + return "LABEL"; + case Pins: + return "PIN"; + case Fills: + return "FILL"; + case FillsOPC: + return "FILLOPC"; + case LEFPins: + return "LEFPIN"; + case Obstructions: + return "LEFOBS"; + case Blockage: + return "BLK"; + case All: + return "ALL"; + } + + return std::string (); +} + +static std::string +layer_spec_to_name (const std::string &layer_name, LayerPurpose purpose, unsigned int mask, const db::DVector &via_size) +{ + std::string ps = purpose_to_name (purpose); + + std::string n = layer_name; + if (! n.empty ()) { + n += "."; + } + n += ps; + + if (mask > 0) { + n += ":"; + n += tl::to_string (mask); + } + + if (via_size != db::DVector ()) { + n += ":SIZE"; + n += tl::sprintf ("%.12gX%.12g", via_size.x (), via_size.y ()); + } + + return n; +} + // ----------------------------------------------------------------------------------- // RuleBasedViaGenerator implementation @@ -144,12 +204,12 @@ RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, d std::set dl; - dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom); + dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom, via_box.enlarged (m_be)); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo))); } - dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top); + dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top, via_box.enlarged (m_te)); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo))); } @@ -248,7 +308,7 @@ RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, d cm = (mask_cut + r + c - 1) % num_cut_masks + 1; } - dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm); + dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm, vb); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (db::Polygon (vb)); } @@ -313,12 +373,12 @@ GeometryBasedLayoutGenerator::combine_maskshifts (const std::string &ln, unsigne void GeometryBasedLayoutGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, const std::vector *ext_msl, const std::vector &masks, const LEFDEFNumberOfMasks *nm) { - for (std::map >, db::Shapes>::const_iterator g = m_shapes.begin (); g != m_shapes.end (); ++g) { + for (std::map , db::Shapes>::const_iterator g = m_shapes.begin (); g != m_shapes.end (); ++g) { unsigned int mshift = get_maskshift (g->first.first, ext_msl, masks); - unsigned int mask = mask_for (g->first.first, g->first.second.second, mshift, nm); + unsigned int mask = mask_for (g->first.first, g->first.second.mask, mshift, nm); - std::set dl = reader.open_layer (layout, g->first.first, g->first.second.first, mask); + std::set dl = reader.open_layer (layout, g->first.first, g->first.second.purpose, mask, g->first.second.via_size); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (g->second); } @@ -363,27 +423,27 @@ static db::Shape insert_shape (db::Shapes &shapes, const Shape &shape, db::prope } void -GeometryBasedLayoutGenerator::add_polygon (const std::string &ln, LayerPurpose purpose, const db::Polygon &poly, unsigned int mask, db::properties_id_type prop_id) +GeometryBasedLayoutGenerator::add_polygon (const std::string &ln, LayerPurpose purpose, const db::Polygon &poly, unsigned int mask, db::properties_id_type prop_id, const db::DVector &via_size) { - insert_shape (m_shapes [std::make_pair (ln, std::make_pair (purpose, mask))], poly, prop_id); + insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask, via_size))], poly, prop_id); } void -GeometryBasedLayoutGenerator::add_box (const std::string &ln, LayerPurpose purpose, const db::Box &box, unsigned int mask, db::properties_id_type prop_id) +GeometryBasedLayoutGenerator::add_box (const std::string &ln, LayerPurpose purpose, const db::Box &box, unsigned int mask, db::properties_id_type prop_id, const db::DVector &via_size) { - insert_shape (m_shapes [std::make_pair (ln, std::make_pair (purpose, mask))], box, prop_id); + insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask, via_size))], box, prop_id); } void -GeometryBasedLayoutGenerator::add_path (const std::string &ln, LayerPurpose purpose, const db::Path &path, unsigned int mask, db::properties_id_type prop_id) +GeometryBasedLayoutGenerator::add_path (const std::string &ln, LayerPurpose purpose, const db::Path &path, unsigned int mask, db::properties_id_type prop_id, const db::DVector &via_size) { - insert_shape (m_shapes [std::make_pair (ln, std::make_pair (purpose, mask))], path, prop_id); + insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask, via_size))], path, prop_id); } void GeometryBasedLayoutGenerator::add_text (const std::string &ln, LayerPurpose purpose, const db::Text &text, unsigned int mask, db::properties_id_type prop_id) { - insert_shape (m_shapes [std::make_pair (ln, std::make_pair (purpose, mask))], text, prop_id); + insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask))], text, prop_id); } void @@ -425,6 +485,9 @@ LEFDEFReaderOptions::LEFDEFReaderOptions () m_produce_lef_pins (true), m_lef_pins_suffix (".PIN"), m_lef_pins_datatype (2), + m_produce_fills (true), + m_fills_suffix (".FILL"), + m_fills_datatype (5), m_produce_obstructions (true), m_obstructions_suffix (".OBS"), m_obstructions_datatype (3), @@ -489,6 +552,11 @@ LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions & m_lef_pins_suffixes = d.m_lef_pins_suffixes; m_lef_pins_datatype = d.m_lef_pins_datatype; m_lef_pins_datatypes = d.m_lef_pins_datatypes; + m_produce_fills = d.m_produce_fills; + m_fills_suffix = d.m_fills_suffix; + m_fills_suffixes = d.m_fills_suffixes; + m_fills_datatype = d.m_fills_datatype; + m_fills_datatypes = d.m_fills_datatypes; m_produce_obstructions = d.m_produce_obstructions; m_obstructions_suffix = d.m_obstructions_suffix; m_obstructions_datatype = d.m_obstructions_datatype; @@ -711,6 +779,30 @@ LEFDEFReaderOptions::lef_pins_datatype_str () const return get_datatypes (this, &LEFDEFReaderOptions::lef_pins_datatype, &LEFDEFReaderOptions::lef_pins_datatype_per_mask, max_mask_number ()); } +void +LEFDEFReaderOptions::set_fills_suffix_str (const std::string &s) +{ + set_suffixes (this, &LEFDEFReaderOptions::clear_fills_suffixes_per_mask, &LEFDEFReaderOptions::set_fills_suffix, &LEFDEFReaderOptions::set_fills_suffix_per_mask, s); +} + +std::string +LEFDEFReaderOptions::fills_suffix_str () const +{ + return get_suffixes (this, &LEFDEFReaderOptions::fills_suffix, &LEFDEFReaderOptions::fills_suffix_per_mask, max_mask_number ()); +} + +void +LEFDEFReaderOptions::set_fills_datatype_str (const std::string &s) +{ + set_datatypes (this, &LEFDEFReaderOptions::clear_fills_datatypes_per_mask, &LEFDEFReaderOptions::set_fills_datatype, &LEFDEFReaderOptions::set_fills_datatype_per_mask, s); +} + +std::string +LEFDEFReaderOptions::fills_datatype_str () const +{ + return get_datatypes (this, &LEFDEFReaderOptions::fills_datatype, &LEFDEFReaderOptions::fills_datatype_per_mask, max_mask_number ()); +} + void LEFDEFReaderOptions::set_routing_suffix_str (const std::string &s) { @@ -835,6 +927,8 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::map purpose_translation; purpose_translation ["LEFPIN"] = LEFPins; purpose_translation ["PIN"] = Pins; + purpose_translation ["FILL"] = Fills; + purpose_translation ["FILLOPC"] = FillsOPC; purpose_translation ["LEFOBS"] = Obstructions; purpose_translation ["SPNET"] = SpecialRouting; purpose_translation ["NET"] = Routing; @@ -842,12 +936,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) purpose_translation ["BLOCKAGE"] = Blockage; purpose_translation ["ALL"] = All; - std::map purpose_translation_rev; - for (std::map::const_iterator i = purpose_translation.begin (); i != purpose_translation.end (); ++i) { - purpose_translation_rev.insert (std::make_pair (i->second, i->first)); - } - - std::map >, std::vector > layer_map; + std::map, std::vector > layer_map; while (! ts.at_end ()) { @@ -862,7 +951,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::string w1, w2; std::vector layers, datatypes; - size_t max_purpose_str = 10; + size_t max_purpose_str = 15; if (! ex.try_read_word (w1) || ! ex.try_read_word (w2, "._$,/:") || ! try_read_layers (ex, layers) || ! try_read_layers (ex, datatypes)) { tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d not understood - skipped")), path, ts.line_number ()); @@ -873,7 +962,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { - layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "OUTLINE")); + layer_map [std::make_pair (std::string (), LayerDetailsKey (Outline))].push_back (db::LayerProperties (*l, *d, "OUTLINE")); } } @@ -881,7 +970,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { - layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "REGIONS")); + layer_map [std::make_pair (std::string (), LayerDetailsKey (Regions))].push_back (db::LayerProperties (*l, *d, "REGIONS")); } } @@ -889,7 +978,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { - layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "PLACEMENT_BLK")); + layer_map [std::make_pair (std::string (), LayerDetailsKey (PlacementBlockage))].push_back (db::LayerProperties (*l, *d, "PLACEMENT_BLK")); } } @@ -915,7 +1004,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) for (std::vector::const_iterator ln = layer_names.begin (); ln != layer_names.end (); ++ln) { for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { - layer_map [std::make_pair (*ln, std::make_pair (Label, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, final_name)); + layer_map [std::make_pair (*ln, LayerDetailsKey (Label))].push_back (db::LayerProperties (*l, *d, final_name)); } } } @@ -934,7 +1023,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) // "(M1,PINS): M1.NET/PINS" // (separating, translating and recombing the purposes) - std::set > translated_purposes; + std::set translated_purposes; std::vector purposes = tl::split (w2, ","); std::reverse (purposes.begin (), purposes.end ()); @@ -948,6 +1037,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::string ps; ex.read_word_or_quoted (ps); + db::DVector via_size; std::map::const_iterator i = purpose_translation.find (ps); if (i != purpose_translation.end ()) { @@ -963,9 +1053,11 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } else if (i->second == ViaGeometry) { if (ex.test (":SIZE:")) { - std::string sz; - ex.read_word (sz); - tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: VIA size constraint ignored for layer %s")), path, ts.line_number (), w1); + double sx = 0.0, sy = 0.0; + ex.read (sx); + ex.test("X"); + ex.read (sy); + via_size = db::DVector (sx, sy); } } @@ -984,13 +1076,13 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) for (std::map::const_iterator p = purpose_translation.begin (); p != purpose_translation.end (); ++p) { if (p->second != All) { - translated_purposes.insert (std::make_pair (p->second, mask)); + translated_purposes.insert (LayerDetailsKey (p->second, mask, via_size)); } } } else { - translated_purposes.insert (std::make_pair (i->second, mask)); + translated_purposes.insert (LayerDetailsKey (i->second, mask, via_size)); } @@ -999,19 +1091,15 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) // create a visual description string for the combined purposes std::string purpose_str; - for (std::set >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { + for (std::set::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { if (p != translated_purposes.begin ()) { purpose_str += "/"; } - std::string ps = purpose_translation_rev [p->first]; - if (p->second > 0) { - ps += ":"; - ps += tl::to_string (p->second); - } + std::string ps = layer_spec_to_name (std::string (), p->purpose, p->mask, p->via_size); - if ((purpose_str + ps).size () > max_purpose_str) { + if (p != translated_purposes.begin () && (purpose_str + ps).size () > max_purpose_str) { purpose_str += "..."; break; } else { @@ -1022,7 +1110,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::string final_name = w1 + "." + purpose_str; - for (std::set >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { + for (std::set::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { layer_map [std::make_pair (w1, *p)].push_back (db::LayerProperties (*l, *d, final_name)); @@ -1043,7 +1131,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) m_layer_map.clear (); db::DirectLayerMapping lm (&layout); - for (std::map >, std::vector >::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { + for (std::map, std::vector >::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { for (std::vector::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { unsigned int layer = lm.map_layer (*j).second; m_layers [i->first].insert (layer); @@ -1053,9 +1141,13 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } std::set -LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask) +LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask, const db::DVector &via_size) { - std::map >, std::set >::const_iterator nl = m_layers.find (std::make_pair (n, std::make_pair (purpose, mask))); + std::map , std::set >::const_iterator nl; + nl = m_layers.find (std::make_pair (n, LayerDetailsKey (purpose, mask, via_size))); + if (nl == m_layers.end ()) { + nl = m_layers.find (std::make_pair (n, LayerDetailsKey (purpose, mask))); + } if (nl == m_layers.end ()) { std::set ll; @@ -1064,7 +1156,7 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu ll = open_layer_uncached (layout, n, purpose, mask); } - m_layers.insert (std::make_pair (std::make_pair (n, std::make_pair (purpose, mask)), ll)); + m_layers.insert (std::make_pair (std::make_pair (n, LayerDetailsKey (purpose, mask)), ll)); return ll; } else { @@ -1072,38 +1164,6 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu } } -static std::string purpose_to_name (LayerPurpose purpose) -{ - switch (purpose) { - case Outline: - return "OUTLINE"; - case Regions: - return "REGION"; - case PlacementBlockage: - return "BLOCKAGE"; - case Routing: - return "NET"; - case SpecialRouting: - return "SPNET"; - case ViaGeometry: - return "VIA"; - case Label: - return "LABEL"; - case Pins: - return "PIN"; - case LEFPins: - return "LEFPIN"; - case Obstructions: - return "LEFOBS"; - case Blockage: - return "BLK"; - case All: - return "ALL"; - } - - return std::string (); -} - /** * @brief Implements implicit layer mapping * @@ -1262,6 +1322,10 @@ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout case Pins: produce = mp_tech_comp->produce_pins (); break; + case Fills: + case FillsOPC: + produce = mp_tech_comp->produce_fills (); + break; case LEFPins: produce = mp_tech_comp->produce_lef_pins (); break; @@ -1303,6 +1367,11 @@ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout name_suffix = mp_tech_comp->pins_suffix_per_mask (mask); dt = mp_tech_comp->pins_datatype_per_mask (mask); break; + case Fills: + case FillsOPC: + name_suffix = mp_tech_comp->fills_suffix_per_mask (mask); + dt = mp_tech_comp->fills_datatype_per_mask (mask); + break; case LEFPins: name_suffix = mp_tech_comp->lef_pins_suffix_per_mask (mask); dt = mp_tech_comp->lef_pins_datatype_per_mask (mask); @@ -1420,24 +1489,13 @@ LEFDEFReaderState::finish (db::Layout &layout) db::LayerMap lm; - for (std::map >, std::set >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { + for (std::map , std::set >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { if (l->second.empty ()) { continue; } - std::string ps = purpose_to_name (l->first.second.first); - - std::string n = l->first.first; - if (! n.empty ()) { - n += "."; - } - n += ps; - - if (l->first.second.second > 0) { - n += ":"; - n += tl::to_string (l->first.second.second); - } + std::string n = layer_spec_to_name (l->first.first, l->first.second.purpose, l->first.second.mask, l->first.second.via_size); for (std::set::const_iterator li = l->second.begin (); li != l->second.end (); ++li) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 9ae66d983..203451541 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -476,6 +476,72 @@ public: set_per_mask_value (m_lef_pins_datatypes, mask, s); } + bool produce_fills () const + { + return m_produce_fills; + } + + void set_produce_fills (bool f) + { + m_produce_fills = f; + } + + const std::string &fills_suffix () const + { + return m_fills_suffix; + } + + void set_fills_suffix (const std::string &s) + { + m_fills_suffix = s; + } + + int fills_datatype () const + { + return m_fills_datatype; + } + + void set_fills_datatype (int s) + { + m_fills_datatype = s; + } + + void set_fills_suffix_str (const std::string &s); + std::string fills_suffix_str () const; + + void set_fills_datatype_str (const std::string &s); + std::string fills_datatype_str () const; + + void clear_fills_suffixes_per_mask () + { + m_fills_suffixes.clear (); + } + + void clear_fills_datatypes_per_mask () + { + m_fills_datatypes.clear (); + } + + const std::string &fills_suffix_per_mask (unsigned int mask) const + { + return per_mask_value (m_fills_suffixes, m_fills_suffix, mask); + } + + void set_fills_suffix_per_mask (unsigned int mask, const std::string &s) + { + set_per_mask_value (m_fills_suffixes, mask, s); + } + + int fills_datatype_per_mask (unsigned int mask) const + { + return per_mask_value (m_fills_datatypes, m_fills_datatype, mask); + } + + void set_fills_datatype_per_mask (unsigned int mask, int s) + { + set_per_mask_value (m_fills_datatypes, mask, s); + } + bool produce_obstructions () const { return m_produce_obstructions; @@ -707,6 +773,8 @@ public: get_max_mask_number (mm, m_pins_datatypes); get_max_mask_number (mm, m_lef_pins_suffixes); get_max_mask_number (mm, m_lef_pins_datatypes); + get_max_mask_number (mm, m_fills_suffixes); + get_max_mask_number (mm, m_fills_datatypes); get_max_mask_number (mm, m_routing_suffixes); get_max_mask_number (mm, m_routing_datatypes); get_max_mask_number (mm, m_special_routing_suffixes); @@ -841,6 +909,11 @@ private: int m_lef_pins_datatype; std::map m_lef_pins_suffixes; std::map m_lef_pins_datatypes; + bool m_produce_fills; + std::string m_fills_suffix; + int m_fills_datatype; + std::map m_fills_suffixes; + std::map m_fills_datatypes; bool m_produce_obstructions; std::string m_obstructions_suffix; int m_obstructions_datatype; @@ -875,6 +948,8 @@ enum LayerPurpose { Routing = 0, // from DEF only Pins, // from DEF + Fills, // from DEF + FillsOPC, // from DEF SpecialRouting, // from DEF only LEFPins, // from LEF ViaGeometry, // from LEF+DEF @@ -887,6 +962,46 @@ enum LayerPurpose All // from DEF only }; +/** + * @brief A structure holding the layer details like purpose, mask and via size + */ +struct LayerDetailsKey +{ + LayerDetailsKey () + : purpose (Routing), mask (0) + { } + + LayerDetailsKey (LayerPurpose _purpose, unsigned int _mask = 0, const db::DVector &_via_size = db::DVector ()) + : purpose (_purpose), mask (_mask), via_size (_via_size) + { } + + bool operator< (const LayerDetailsKey &other) const + { + if (purpose != other.purpose) { + return purpose < other.purpose; + } + if (mask != other.mask) { + return mask < other.mask; + } + return via_size.less (other.via_size); + } + + bool operator== (const LayerDetailsKey &other) const + { + if (purpose != other.purpose) { + return false; + } + if (mask != other.mask) { + return false; + } + return via_size.equal (other.via_size); + } + + LayerPurpose purpose; + unsigned int mask; + db::DVector via_size; +}; + /** * @brief An interface for resolving the number of masks from a layer name */ @@ -979,9 +1094,9 @@ public: virtual std::vector maskshift_layers () const { return m_maskshift_layers; } virtual bool is_fixedmask () const { return m_fixedmask; } - void add_polygon (const std::string &ln, LayerPurpose purpose, const db::Polygon &poly, unsigned int mask, properties_id_type prop_id); - void add_box (const std::string &ln, LayerPurpose purpose, const db::Box &box, unsigned int mask, properties_id_type prop_id); - void add_path (const std::string &ln, LayerPurpose purpose, const db::Path &path, unsigned int mask, properties_id_type prop_id); + void add_polygon (const std::string &ln, LayerPurpose purpose, const db::Polygon &poly, unsigned int mask, properties_id_type prop_id, const DVector &via_size = db::DVector ()); + void add_box (const std::string &ln, LayerPurpose purpose, const db::Box &box, unsigned int mask, properties_id_type prop_id, const DVector &via_size = db::DVector ()); + void add_path (const std::string &ln, LayerPurpose purpose, const db::Path &path, unsigned int mask, properties_id_type prop_id, const DVector &via_size = db::DVector ()); void add_via (const std::string &vn, const db::Trans &trans, unsigned int bottom_mask, unsigned int cut_mask, unsigned int top_mask); void add_text (const std::string &ln, LayerPurpose purpose, const db::Text &text, unsigned int mask, db::properties_id_type prop_id); @@ -1008,7 +1123,7 @@ private: db::Trans trans; }; - std::map >, db::Shapes> m_shapes; + std::map , db::Shapes> m_shapes; std::list m_vias; std::vector m_maskshift_layers; bool m_fixedmask; @@ -1054,7 +1169,17 @@ public: /** * @brief Create a new layer or return the index of the given layer */ - std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); + std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask, const DVector &via_size = db::DVector ()); + + /** + * @brief Create a new layer or return the index of the given layer + */ + template + std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask, const Shape &via_shape) + { + db::Box via_box = db::box_convert () (via_shape); + return open_layer (layout, name, purpose, mask, db::DVector (via_box.width () * layout.dbu (), via_box.height () * layout.dbu ())); + } /** * @brief Registers a layer (assign a new default layer number) @@ -1188,7 +1313,7 @@ private: LEFDEFReaderState (const LEFDEFReaderState &); LEFDEFReaderState &operator= (const LEFDEFReaderState &); - std::map >, std::set > m_layers; + std::map , std::set > m_layers; db::LayerMap m_layer_map; bool m_create_layers; bool m_has_explicit_layer_mapping; @@ -1363,9 +1488,9 @@ protected: /** * @brief Create a new layer or return the index of the given layer */ - std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask) + std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask, const db::DVector &via_size = db::DVector ()) { - return mp_reader_state->open_layer (layout, name, purpose, mask); + return mp_reader_state->open_layer (layout, name, purpose, mask, via_size); } /** diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index 6a099a0cb..30d50f357 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -339,6 +339,13 @@ class LEFDEFFormatDeclaration // new: tl::make_member (&LEFDEFReaderOptions::lef_pins_suffix_str, &LEFDEFReaderOptions::set_lef_pins_suffix_str, "special-lef_pins-suffix-string") + tl::make_member (&LEFDEFReaderOptions::lef_pins_datatype_str, &LEFDEFReaderOptions::set_lef_pins_datatype_str, "special-lef_pins-datatype-string") + + tl::make_member (&LEFDEFReaderOptions::produce_fills, &LEFDEFReaderOptions::set_produce_fills, "produce-fills") + + // for backward compatibility + tl::make_member (&LEFDEFReaderOptions::set_fills_suffix, "special-fills-suffix") + + tl::make_member (&LEFDEFReaderOptions::set_fills_datatype, "special-fills-datatype") + + // new: + tl::make_member (&LEFDEFReaderOptions::fills_suffix_str, &LEFDEFReaderOptions::set_fills_suffix_str, "special-fills-suffix-string") + + tl::make_member (&LEFDEFReaderOptions::fills_datatype_str, &LEFDEFReaderOptions::set_fills_datatype_str, "special-fills-datatype-string") + tl::make_member (&LEFDEFReaderOptions::produce_obstructions, &LEFDEFReaderOptions::set_produce_obstructions, "produce-obstructions") + tl::make_member (&LEFDEFReaderOptions::obstructions_suffix, &LEFDEFReaderOptions::set_obstructions_suffix, "obstructions-suffix") + tl::make_member (&LEFDEFReaderOptions::obstructions_datatype, &LEFDEFReaderOptions::set_obstructions_datatype, "obstructions-datatype") + diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index 4e859aaca..2714a5d52 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -517,6 +517,14 @@ LEFImporter::read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &via_desc, } } +template +static db::DVector +via_size (double dbu, const Shape &shape) +{ + db::Box box = db::box_convert () (shape); + return db::DVector (box.width () * dbu, box.height () * dbu); +} + void LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc &via_desc, const std::string &n, double dbu) { @@ -577,7 +585,7 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc db::Polygon p; p.assign_hull (points.begin (), points.end ()); - lg->add_polygon (layer_name, ViaGeometry, p, mask, 0); + lg->add_polygon (layer_name, ViaGeometry, p, mask, 0, via_size (dbu, p)); expect (";"); @@ -599,7 +607,7 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc } db::Box b (points [0], points [1]); - lg->add_box (layer_name, ViaGeometry, b, mask, 0); + lg->add_box (layer_name, ViaGeometry, b, mask, 0, via_size (dbu, b)); expect (";"); diff --git a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index 99533c8fc..44b1279e7 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -502,6 +502,94 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi gsi::method ("lef_pins_datatype_str=", &db::LEFDEFReaderOptions::set_lef_pins_datatype_str, gsi::arg ("datatype"), "@hide" ) + + gsi::method ("produce_fills", &db::LEFDEFReaderOptions::produce_fills, + "@brief Gets a value indicating whether fill geometries shall be produced.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n\n" + "Fill support has been introduced in version 0.27." + ) + + gsi::method ("produce_fills=", &db::LEFDEFReaderOptions::set_produce_fills, gsi::arg ("produce"), + "@brief Sets a value indicating whether fill geometries shall be produced.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n\n" + "Fill support has been introduced in version 0.27." + ) + + gsi::method ("fills_suffix", &db::LEFDEFReaderOptions::fills_suffix, + "@brief Gets the fill geometry layer name suffix.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n\n" + "Fill support has been introduced in version 0.27." + ) + + gsi::method ("fills_suffix=", &db::LEFDEFReaderOptions::set_fills_suffix, gsi::arg ("suffix"), + "@brief Sets the fill geometry layer name suffix.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n\n" + "Fill support has been introduced in version 0.27." + ) + + gsi::method ("fills_datatype", &db::LEFDEFReaderOptions::fills_datatype, + "@brief Gets the fill geometry layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n\n" + "Fill support has been introduced in version 0.27." + ) + + gsi::method ("fills_datatype=", &db::LEFDEFReaderOptions::set_fills_datatype, gsi::arg ("datatype"), + "@brief Sets the fill geometry layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n\n" + "Fill support has been introduced in version 0.27." + ) + + gsi::method ("clear_fills_suffixes_per_mask", &db::LEFDEFReaderOptions::clear_fills_suffixes_per_mask, + "@brief Clears the fill layer name suffix per mask.\n" + "See \\produce_via_geometry for details about this property.\n" + "\n\n" + "Mask specific rules have been introduced in version 0.27." + ) + + gsi::method ("clear_fill_datatypes_per_mask", &db::LEFDEFReaderOptions::clear_fills_datatypes_per_mask, + "@brief Clears the fill layer datatypes per mask.\n" + "See \\produce_via_geometry for details about this property.\n" + "\n\n" + "Mask specific rules have been introduced in version 0.27." + ) + + gsi::method ("fills_suffix_per_mask", &db::LEFDEFReaderOptions::fills_suffix_per_mask, gsi::arg ("mask"), + "@brief Gets the fill geometry layer name suffix per mask.\n" + "See \\produce_via_geometry for details about the layer production rules." + "The mask number is a zero-based mask index (0: MASK 1, 1: MASK 2 ...)." + "\n\n" + "Mask specific rules have been introduced in version 0.27." + ) + + gsi::method ("set_fills_suffix_per_mask", &db::LEFDEFReaderOptions::set_fills_suffix_per_mask, gsi::arg ("mask"), gsi::arg ("suffix"), + "@brief Sets the fill geometry layer name suffix per mask.\n" + "See \\produce_via_geometry for details about the layer production rules." + "The mask number is a zero-based mask index (0: MASK 1, 1: MASK 2 ...)." + "\n\n" + "Mask specific rules have been introduced in version 0.27." + ) + + gsi::method ("fills_datatype", &db::LEFDEFReaderOptions::fills_datatype_per_mask, + "@brief Gets the fill geometry layer datatype value per mask.\n" + "See \\produce_via_geometry for details about the layer production rules." + "The mask number is a zero-based mask index (0: MASK 1, 1: MASK 2 ...)." + "\n\n" + "Mask specific rules have been introduced in version 0.27." + ) + + gsi::method ("set_fills_datatype_per_mask", &db::LEFDEFReaderOptions::set_fills_datatype_per_mask, gsi::arg ("mask"), gsi::arg ("datatype"), + "@brief Sets the fill geometry layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + "The mask number is a zero-based mask index (0: MASK 1, 1: MASK 2 ...)." + "\n\n" + "Mask specific rules have been introduced in version 0.27." + ) + + gsi::method ("fills_suffix_str", &db::LEFDEFReaderOptions::fills_suffix_str, + "@hide" + ) + + gsi::method ("fills_suffix_str=", &db::LEFDEFReaderOptions::set_fills_suffix_str, gsi::arg ("suffix"), + "@hide" + ) + + gsi::method ("fills_datatype_str", &db::LEFDEFReaderOptions::fills_datatype_str, + "@hide" + ) + + gsi::method ("fills_datatype_str=", &db::LEFDEFReaderOptions::set_fills_datatype_str, gsi::arg ("datatype"), + "@hide" + ) + gsi::method ("produce_obstructions", &db::LEFDEFReaderOptions::produce_obstructions, "@brief Gets a value indicating whether obstruction markers shall be produced.\n" "See \\produce_via_geometry for details about the layer production rules." diff --git a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui index 73212cb25..0db23b7f8 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui +++ b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui @@ -33,1222 +33,1301 @@ 9 - - - - 0 - 0 - - - - LEF Files - - - true - - - - 6 - - - 9 - - - 4 - - - 9 - - - 4 - - - - - - 0 - 0 - - - - - 16 - 120 - - - - - 16777215 - 16777215 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 6 - - - - - Delete selected files - - - ... - - - - :/clear.png:/clear.png - - - - - - - - 0 - 0 - - - - QAbstractItemView::ExtendedSelection - - - - - - - Move selected files down - - - ... - - - - :/down.png:/down.png - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Add LEF file - - - ... - - - - :/add.png:/add.png - - - - - - - Move selected files up - - - ... - - - - :/up.png:/up.png - - - - - - - - - - for DEF: also read all LEF files in the same directory than the DEF file - - - - - - - - - - Options - - - true - - - - 4 - - - 4 - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Groups - - - - - - - Layout DBU - - - - - - - Produce a parent cell per group - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - Produce LEF geometry - - - - - - - LEF import into DEF - - - - - - - Via cell name prefix - - - - - - - - 1 - 0 - - - - µm - - - - - - - - - - Global Production Rules (specify what objects to produce and on what layers) - - - true - - - - 9 - - - 4 - - - 9 - - - 4 - - - 6 - - - - - - 50 - false - false - - - - Net names - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - As properties with name ... - - - - - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - - - - - 0 - 0 - - - - - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - <html><body>(<a href="int:/about/variant_notation.xml">See here for the name notation</a>)</body></html> - - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing - - - - - - - - 0 - 0 - - - - - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - Blockages (2*) - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 50 - false - false - false - - - - Produce ... - - - - - - - Inst names - - - - - - - - 1 - 0 - - - - On layer with spec ... - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Produce ... - - - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Regions (2*) - - - - - - - Pin names - - - - - - - - 0 - 0 - - - - Die area (2*) - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - <html><body>(<a href="int:/about/layer_specs.xml">See here for the layer specification</a>)</body></html> - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - + - 0 + 2 - + - Layer Map File + LEF Files - - - + + + - Layer map file + for DEF: also read all LEF files in the same directory than the DEF file - - - - ... + + + + Qt::Vertical - - false + + QSizePolicy::Fixed + + + + 20 + 6 + + + + + + + + Additional LEF files - - - - - - - If a layer map file is given, pattern based rules are ignored. -If used inside a technology, the file will be looked up relative to the technology's base path. -Otherwise it's looked up relative to the LEF or DEF file. - -(2*) Die area, Blockage and Region layers in map file will have priority over global production rules above. - - - true + + + + + 0 + 0 + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 16 + 120 + + + + + 16777215 + 16777215 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + Delete selected files + + + ... + + + + :/clear.png:/clear.png + + + + + + + + 0 + 0 + + + + QAbstractItemView::ExtendedSelection + + + + + + + Move selected files down + + + ... + + + + :/down.png:/down.png + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + Add LEF file + + + ... + + + + :/add.png:/add.png + + + + + + + Move selected files up + + + ... + + + + :/up.png:/up.png + + + + + + + - - + + + + + Options + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Layout DBU + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + µm + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Groups + + + + + + + Produce a parent cell per group + + + + + + + Via cell name prefix + + + + + + + + 0 + 0 + + + + + + + + LEF import into DEF + + + + + + + Produce LEF geometry + + + + + + + + Qt::Vertical 20 - 278 + 40 - + - Pattern Based Layer Production Rules + Production - - - 0 - - - 0 - - - 0 - - - 0 - + - - - QFrame::NoFrame + + + Global Production Rules (specify what objects to produce and on what layers) - + true - - - - 0 - 0 - 616 - 375 - + + + 9 - - - - - - 0 - 0 - + + 4 + + + 9 + + + 4 + + + 6 + + + + + + 50 + false + false + + + + Net names + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + As properties with name ... + + + + + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + <html><body>(<a href="int:/about/variant_notation.xml">See here for the name notation</a>)</body></html> + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + + + + 0 + 0 + + + + + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + Blockages (2*) + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 50 + false + false + false + + + + Produce ... + + + + + + + Inst names + + + + + + + + 1 + 0 + + + + On layer with spec ... + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Produce ... + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Regions (2*) + + + + + + + Pin names + + + + + + + + 0 + 0 + + + + Die area (2*) + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + <html><body>(<a href="int:/about/layer_specs.xml">See here for the layer specification</a>)</body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 1 + + + + Layer Map File + + + + + + Layer map file - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - Special routing (*) - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - Routing (*) - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - Via geometry (*) - - - - - - - Pin labels - - - - - - - LEF Pins (*) - - - - - - - Layer name -suffix ... - - - - - - - Pins (*) - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - GDS data- -type ... - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - Blockages - - - - - - - Obstructions - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - - Layer name -suffix ... - - - - - - - GDS data- -type ... - - - - - - - Qt::Vertical - - - - - - + + - (*) Separate suffixes or datatypes can be given for different masks, using the following notation: -"x,1:y,2:z ..." (which will use x by default, y for MASK 1, z for MASK 2 etc.) + ... + + + false + + + + + + + + + + If a layer map file is given, pattern based rules are ignored. +If used inside a technology, the file will be looked up relative to the technology's base path. +Otherwise it's looked up relative to the LEF or DEF file. + +(2*) Die area, Blockage and Region layers in map file will have priority over global production rules above. true + + + + Qt::Vertical + + + + 20 + 278 + + + + + + + + + Pattern Based Layer Production Rules + + + + 0 + + + 0 + + + 0 + + + 0 + - - - - 0 - 1 - + + + QFrame::NoFrame - - Layer Mapping (filter/modify layers, assign GDS layer/datatypes) - - + true - - - 9 + + + + 0 + 0 + 609 + 591 + - - 4 - - - 9 - - - 4 - - - - - Read all layers (additionally to the ones in the mapping table) - - - - - - - - 0 - 1 - - - - - 16 - 0 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - Qt::Horizontal - - - - + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + Fills (*) + + + + + + + Layer name +suffix ... + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + LEF Pins (*) + + + + + + + Layer name +suffix ... + + + + + + + + + + :/right.png + + + + + + + Via geometry (*) + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + GDS data- +type ... + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + Pins (*) + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + Special routing (*) + + + + + + + Obstructions + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + Pin labels + + + + + + + GDS data- +type ... + + + + + + + Routing (*) + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + + + + Blockages + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + + + (*) Separate suffixes or datatypes can be given for different masks, using the following notation: +"x,1:y,2:z ..." (which will use x by default, y for MASK 1, z for MASK 2 etc.) + + + true + + + + + + + + 0 + 1 + + + + Layer Mapping (filter/modify layers, assign GDS layer/datatypes) + + + true + + + + 9 + + + 4 + + + 9 + + + 4 + + + + + Read all layers (additionally to the ones in the mapping table) + + + + + + + + 0 + 1 + + + + + 16 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + + + + + @@ -1273,14 +1352,16 @@ type ... + tabWidget + read_lef_with_def lef_files add_lef_file del_lef_files move_lef_files_up move_lef_files_down dbu - prefix_via_cellname separate_groups + prefix_via_cellname produce_lef_geo produce_net_names net_prop_name @@ -1295,6 +1376,9 @@ type ... produce_regions region_layer layer_map_mode + mapfile_path + browse_mapfile + scrollArea produce_via_geometry suffix_via_geometry datatype_via_geometry @@ -1304,6 +1388,9 @@ type ... produce_lef_pins suffix_lef_pins datatype_lef_pins + produce_fills + suffix_fills + datatype_fills produce_obstructions suffix_obstructions datatype_obstructions @@ -1319,8 +1406,7 @@ type ... produce_blockages suffix_blockages datatype_blockages - mapfile_path - browse_mapfile + read_all_cbx diff --git a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc index 4c64e034f..3df5ab135 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc +++ b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc @@ -354,6 +354,7 @@ LEFDEFReaderOptionsEditor::LEFDEFReaderOptionsEditor (QWidget *parent) connect (produce_via_geometry, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_pins, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_lef_pins, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); + connect (produce_fills, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_obstructions, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_blockages, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_routing, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); @@ -400,7 +401,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con ex.read (v); ex.expect_end (); data->set_net_property_name (v); - indicate_error (net_prop_name, 0); + indicate_error (net_prop_name, (tl::Exception *) 0); } catch (tl::Exception &ex) { indicate_error (net_prop_name, &ex); has_error = true; @@ -414,7 +415,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con ex.read (v); ex.expect_end (); data->set_inst_property_name (v); - indicate_error (inst_prop_name, 0); + indicate_error (inst_prop_name, (tl::Exception *) 0); } catch (tl::Exception &ex) { indicate_error (inst_prop_name, &ex); has_error = true; @@ -428,7 +429,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con ex.read (v); ex.expect_end (); data->set_pin_property_name (v); - indicate_error (pin_prop_name, 0); + indicate_error (pin_prop_name, (tl::Exception *) 0); } catch (tl::Exception &ex) { indicate_error (pin_prop_name, &ex); has_error = true; @@ -441,7 +442,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con tl::Extractor ex (s.c_str ()); lp.read (ex); ex.expect_end (); - indicate_error (outline_layer, 0); + indicate_error (outline_layer, (tl::Exception *) 0); } catch (tl::Exception &ex) { indicate_error (outline_layer, &ex); has_error = true; @@ -454,7 +455,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con tl::Extractor ex (s.c_str ()); lp.read (ex); ex.expect_end (); - indicate_error (region_layer, 0); + indicate_error (region_layer, (tl::Exception *) 0); } catch (tl::Exception &ex) { indicate_error (region_layer, &ex); has_error = true; @@ -467,7 +468,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con tl::Extractor ex (s.c_str ()); lp.read (ex); ex.expect_end (); - indicate_error (placement_blockage_layer, 0); + indicate_error (placement_blockage_layer, (tl::Exception *) 0); } catch (tl::Exception &ex) { indicate_error (placement_blockage_layer, &ex); has_error = true; @@ -493,6 +494,9 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con data->set_produce_lef_pins (produce_lef_pins->isChecked ()); data->set_lef_pins_suffix_str (tl::to_string (suffix_lef_pins->text ())); data->set_lef_pins_datatype_str (tl::to_string (datatype_lef_pins->text ())); + data->set_produce_fills (produce_fills->isChecked ()); + data->set_fills_suffix_str (tl::to_string (suffix_fills->text ())); + data->set_fills_datatype_str (tl::to_string (datatype_fills->text ())); data->set_produce_obstructions (produce_obstructions->isChecked ()); data->set_obstructions_suffix (tl::to_string (suffix_obstructions->text ())); data->set_obstructions_datatype (datatype_obstructions->text ().toInt ()); @@ -556,6 +560,9 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options produce_lef_pins->setChecked (data->produce_lef_pins ()); suffix_lef_pins->setText (tl::to_qstring (data->lef_pins_suffix_str ())); datatype_lef_pins->setText (tl::to_qstring (data->lef_pins_datatype_str ())); + produce_fills->setChecked (data->produce_fills ()); + suffix_fills->setText (tl::to_qstring (data->fills_suffix_str ())); + datatype_fills->setText (tl::to_qstring (data->fills_datatype_str ())); produce_obstructions->setChecked (data->produce_obstructions ()); suffix_obstructions->setText (tl::to_qstring (data->obstructions_suffix ())); datatype_obstructions->setText (QString::number (data->obstructions_datatype ())); @@ -604,6 +611,7 @@ LEFDEFReaderOptionsEditor::checkbox_changed () suffix_via_geometry->setEnabled (produce_via_geometry->isChecked ()); suffix_pins->setEnabled (produce_pins->isChecked ()); suffix_lef_pins->setEnabled (produce_lef_pins->isChecked ()); + suffix_fills->setEnabled (produce_fills->isChecked ()); suffix_obstructions->setEnabled (produce_obstructions->isChecked ()); suffix_blockages->setEnabled (produce_blockages->isChecked ()); suffix_routing->setEnabled (produce_routing->isChecked ()); @@ -612,6 +620,7 @@ LEFDEFReaderOptionsEditor::checkbox_changed () datatype_via_geometry->setEnabled (produce_via_geometry->isChecked ()); datatype_pins->setEnabled (produce_pins->isChecked ()); datatype_lef_pins->setEnabled (produce_lef_pins->isChecked ()); + datatype_fills->setEnabled (produce_fills->isChecked ()); datatype_obstructions->setEnabled (produce_obstructions->isChecked ()); datatype_blockages->setEnabled (produce_blockages->isChecked ()); datatype_routing->setEnabled (produce_routing->isChecked ()); diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 884253775..560712df3 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -291,7 +291,7 @@ TEST(16) run_test (_this, "def7", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au-new.oas.gz", options); options.set_placement_blockage_layer ("PLACEMENT_BLK (60/0)"); - run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au_with_map_file-new.oas.gz", options); + 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) @@ -332,7 +332,7 @@ TEST(21) TEST(22) { db::LEFDEFReaderOptions opt = default_options (); - run_test (_this, "def13", "map:test.map+lef:test.lef_5.8+def:top.def.gz", "au.oas.gz", opt); + run_test (_this, "def13", "map:test.map+lef:test.lef_5.8+def:top.def.gz", "au2.oas.gz", opt); } TEST(100) @@ -710,20 +710,26 @@ TEST(117_mapfile_all) EXPECT_EQ (lm_read.to_string (), "layer_map(" "'OUTLINE : OUTLINE (1/0)';" - "'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (1/5)';" + "'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/SPNET/...\\' (1/5)';" "'+M1.NET;M1.SPNET : \\'M1.NET/SPNET\\' (16/0)';" "'+M1.NET : M1.NET (18/0)';" - "'+M1.BLK;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (22/2)';" - "'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/...\\' (6/0)';" + "'+M1.BLK;M1.FILL;M1.FILLOPC;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/FILL/...\\' (22/2)';" + "'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/PIN:1/...\\' (6/0)';" "'+\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';" "'+M1.PIN : M1.PIN (3/0)';" "'+M1.PIN : M1.PIN (4/0)';" - "'+M1.VIA : M1.VIA (20/0)';" - "'+M1.VIA : M1.VIA (21/0)';" + "'+M1.FILL : M1.FILL (14/0)';" + "'+M1.FILL : M1.FILL (15/0)';" + "'+M1.FILL : M1.FILL (17/0)';" + "'+M1.FILLOPC : M1.FILLOPC (9/0)';" + "'\\'M1.FILLOPC:1\\' : \\'M1.FILLOPC:1\\' (10/0)';" + "'\\'M1.FILLOPC:2\\' : \\'M1.FILLOPC:2\\' (11/0)';" + "'\\'M1.VIA:SIZE0.05X0.05\\' : \\'M1.VIA:SIZE0.05X0.05\\' (20/0)';" + "'\\'M1.VIA:SIZE3X3\\' : \\'M1.VIA:SIZE3X3\\' (21/0)';" "'+M1.LABEL : M1.LABEL (26/0)';" "'+M1.LABEL : M1.LABEL (27/0)';" "'+M1.LABEL : M1.LABEL (28/1)';" - "'+M1.BLK : M1.BLOCKAGE (13/0)';" + "'+M1.BLK : M1.BLK (13/0)';" "'M1_TEXT.LABEL : M1_TEXT.LABEL (29/0)'" ")" ) @@ -752,6 +758,21 @@ TEST(119_multimapping) ) } +TEST(120_simplefill) +{ + run_test (_this, "fill", "map:simple.map+lef:simple.lef+def:simple.def", "simple_au.oas.gz", default_options (), false); +} + +TEST(121_fillwithmask) +{ + run_test (_this, "fill", "map:with_mask.map+lef:with_mask.lef+def:with_mask.def", "with_mask_au.oas.gz", default_options (), false); +} + +TEST(130_viasize) +{ + run_test (_this, "viasize", "map:test.map+lef:test.lef+def:test.def", "au.oas.gz", default_options (), false); +} + TEST(200_lefdef_plugin) { db::Layout ly; diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index fe9773fd3..71a69ae09 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -211,7 +211,7 @@ static bool find_and_normalize_file (const tl::URI &uri, std::string &path) // TODO: this is not quite efficient, but the only thing we can do for now tl::URI uri_with_ext = uri; uri_with_ext.set_path (uri_with_ext.path () + extensions[e]); - std::string us = uri_with_ext.to_string (); + std::string us = uri_with_ext.to_abstract_path (); if (tl::verbosity () >= 30) { tl::log << tl::to_string (tr ("Trying layout URI: ")) << us; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 41cc5658e..8ee0eead6 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -1566,6 +1566,7 @@ OASISReader::read_repetition () db::Coord x = 0; for (unsigned long i = 0; i <= n; ++i) { + m_progress.set (m_stream.pos ()); db::Coord d = get_ucoord (lgrid); if (d != 0) { x += d; @@ -1590,6 +1591,7 @@ OASISReader::read_repetition () db::Coord y = 0; for (unsigned long i = 0; i <= n; ++i) { + m_progress.set (m_stream.pos ()); db::Coord d = get_ucoord (lgrid); if (d != 0) { y += d; @@ -1633,6 +1635,7 @@ OASISReader::read_repetition () db::Vector p; for (unsigned long i = 0; i <= n; ++i) { + m_progress.set (m_stream.pos ()); db::Vector d = get_gdelta (grid); if (d != db::Vector ()) { p += d; diff --git a/src/plugins/tools/view_25d/view_25d.pro b/src/plugins/tools/view_25d/view_25d.pro index 30278d0c8..3eb5a6fad 100644 --- a/src/plugins/tools/view_25d/view_25d.pro +++ b/src/plugins/tools/view_25d/view_25d.pro @@ -1,6 +1,12 @@ TEMPLATE = subdirs -equals(HAVE_QT5, "1") { - SUBDIRS = lay_plugin unit_tests +contains(QT_CONFIG, opengl) { + + equals(HAVE_QT5, "1") { + SUBDIRS = lay_plugin unit_tests + } + + unit_tests.depends += lay_plugin + } diff --git a/src/pymod/QtCore/QtCoreMain.cc b/src/pymod/QtCore/QtCoreMain.cc index 246cc8276..494255582 100644 --- a/src/pymod/QtCore/QtCoreMain.cc +++ b/src/pymod/QtCore/QtCoreMain.cc @@ -37,3 +37,4 @@ FORCE_LINK_GSI_QTGUI FORCE_LINK_GSI_QTWIDGETS DEFINE_PYMOD(QtCore, "QtCore", "KLayout/Qt module 'QtCore'") + diff --git a/src/pymod/QtUiTools/QtUiTools.pro b/src/pymod/QtUiTools/QtUiTools.pro new file mode 100644 index 000000000..2c1ed0966 --- /dev/null +++ b/src/pymod/QtUiTools/QtUiTools.pro @@ -0,0 +1,13 @@ + +TARGET = QtUiTools + +include($$PWD/../pymod.pri) + +SOURCES = \ + QtUiToolsMain.cc \ + +HEADERS += \ + +LIBS += -lklayout_QtUiTools +LIBS += -lklayout_QtCore + diff --git a/src/pymod/QtUiTools/QtUiToolsMain.cc b/src/pymod/QtUiTools/QtUiToolsMain.cc new file mode 100644 index 000000000..7038f2bfa --- /dev/null +++ b/src/pymod/QtUiTools/QtUiToolsMain.cc @@ -0,0 +1,33 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2021 Matthias Koefferlein + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "../pymodHelper.h" + +// To force linking of the QtCore module +#include "../../gsiqt/qtbasic/gsiQtCoreExternals.h" +FORCE_LINK_GSI_QTCORE + +# include "../../gsiqt/qtbasic/gsiQtUiToolsExternals.h" +FORCE_LINK_GSI_QTUITOOLS + +DEFINE_PYMOD(QtUiTools, "QtUiTools", "KLayout/Qt module 'QtUiTools'") + diff --git a/src/pymod/__init__.py.qt4 b/src/pymod/__init__.py.qt4 index 1404dbe71..7ca1f3e1b 100644 --- a/src/pymod/__init__.py.qt4 +++ b/src/pymod/__init__.py.qt4 @@ -1,5 +1,5 @@ # klayout library definition file -__all__ = [ "tl", "db", "lib", "rdb", "QtCore", "QtGui", "QtXml", "QtSql", "QtNetwork", "QtDesigner", "lay" ] +__all__ = [ "tl", "db", "lib", "rdb", "QtCore", "QtGui", "QtXml", "QtSql", "QtNetwork", "QtDesigner", "QtUiTools", "lay" ] diff --git a/src/pymod/__init__.py.qt5 b/src/pymod/__init__.py.qt5 index 6077d2f06..c6d2339fa 100644 --- a/src/pymod/__init__.py.qt5 +++ b/src/pymod/__init__.py.qt5 @@ -2,7 +2,7 @@ # klayout library definition file __all__ = [ "tl", "db", "lib", "rdb", - "QtCore", "QtGui", "QtNetwork", "QtSql", "QtWidgets", "QtDesigner", + "QtCore", "QtGui", "QtNetwork", "QtSql", "QtWidgets", "QtDesigner", "QtUiTools", "QtMultimedia", "QtPrintSupport", "QtSvg", "QtXmlPatterns", "QtXml", "lay" ] diff --git a/src/pymod/pymod.pro b/src/pymod/pymod.pro index 3cd7e2fe6..1b1998702 100644 --- a/src/pymod/pymod.pro +++ b/src/pymod/pymod.pro @@ -1,4 +1,6 @@ +include($$PWD/../klayout.pri) + TEMPLATE = subdirs SUBDIRS = \ db \ @@ -11,32 +13,53 @@ SUBDIRS = \ SUBDIRS += lay equals(HAVE_QTBINDINGS, "1") { + + SUBDIRS += \ + QtCore \ + QtGui + equals(HAVE_QT5, "1") { - SUBDIRS += \ - QtCore \ - QtGui \ - QtNetwork \ - QtSql \ - QtWidgets \ - QtDesigner \ - QtMultimedia \ - QtPrintSupport \ - QtSvg \ - QtXmlPatterns \ - QtXml + SUBDIRS += QtWidgets - } else { + !equals(HAVE_QT_MULTIMEDIA, "0") { + SUBDIRS += QtMultimedia + } - SUBDIRS += \ - QtCore \ - QtGui \ - QtXml \ - QtSql \ - QtNetwork \ - QtDesigner + !equals(HAVE_QT_PRINTSUPPORT, "0") { + SUBDIRS += QtPrintSupport + } + + !equals(HAVE_QT_SVG, "0") { + SUBDIRS += QtSvg + } + + !equals(HAVE_QT_XML, "0") { + SUBDIRS += QtXmlPatterns + } } + + !equals(HAVE_QT_XML, "0") { + SUBDIRS += QtXml + } + + !equals(HAVE_QT_SQL, "0") { + SUBDIRS += QtSql + } + + !equals(HAVE_QT_NETWORK, "0") { + SUBDIRS += QtNetwork + } + + !equals(HAVE_QT_DESIGNER, "0") { + SUBDIRS += QtDesigner + } + + !equals(HAVE_QT_UITOOLS, "0") { + SUBDIRS += QtUiTools + } + } } diff --git a/src/pymod/unit_tests/pymod_tests.cc b/src/pymod/unit_tests/pymod_tests.cc index 1c5c5e72d..2e9d1d590 100644 --- a/src/pymod/unit_tests/pymod_tests.cc +++ b/src/pymod/unit_tests/pymod_tests.cc @@ -94,18 +94,37 @@ PYMODTEST (import_lay, "import_lay.py") PYMODTEST (import_QtCore, "import_QtCore.py") PYMODTEST (import_QtGui, "import_QtGui.py") +#if defined(HAVE_QT_XML) PYMODTEST (import_QtXml, "import_QtXml.py") +#endif +#if defined(HAVE_QT_SQL) PYMODTEST (import_QtSql, "import_QtSql.py") +#endif +#if defined(HAVE_QT_NETWORK) PYMODTEST (import_QtNetwork, "import_QtNetwork.py") +#endif +#if defined(HAVE_QT_DESIGNER) PYMODTEST (import_QtDesigner, "import_QtDesigner.py") +#endif +#if defined(HAVE_QT_UITOOLS) +PYMODTEST (import_QtUiTools, "import_QtUiTools.py") +#endif #if QT_VERSION >= 0x50000 PYMODTEST (import_QtWidgets, "import_QtWidgets.py") +#if defined(HAVE_QT_MULTIMEDIA) PYMODTEST (import_QtMultimedia, "import_QtMultimedia.py") +#endif +#if defined(HAVE_QT_PRINTSUPPORT) PYMODTEST (import_QtPrintSupport, "import_QtPrintSupport.py") +#endif +#if defined(HAVE_QT_SVG) PYMODTEST (import_QtSvg, "import_QtSvg.py") +#endif +#if defined(HAVE_QT_XML) PYMODTEST (import_QtXmlPatterns, "import_QtXmlPatterns.py") +#endif #endif diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc index 9ac96cbf9..7cdac9988 100644 --- a/src/rba/unit_tests/rbaTests.cc +++ b/src/rba/unit_tests/rbaTests.cc @@ -106,6 +106,8 @@ RUBYTEST (dbInstElementTest, "dbInstElementTest.rb") RUBYTEST (dbLayerMapping, "dbLayerMapping.rb") RUBYTEST (dbLibrary, "dbLibrary.rb") RUBYTEST (dbLayout, "dbLayout.rb") +RUBYTEST (dbRecursiveShapeIterator, "dbRecursiveShapeIterator.rb") +RUBYTEST (dbRecursiveInstanceIterator, "dbRecursiveInstanceIterator.rb") RUBYTEST (dbLayoutTest, "dbLayoutTest.rb") RUBYTEST (dbLayoutDiff, "dbLayoutDiff.rb") RUBYTEST (dbLayoutQuery, "dbLayoutQuery.rb") diff --git a/src/tl/tl/tlInclude.cc b/src/tl/tl/tlInclude.cc index 9a946fec3..53a5a6dc1 100644 --- a/src/tl/tl/tlInclude.cc +++ b/src/tl/tl/tlInclude.cc @@ -97,7 +97,7 @@ IncludeExpander::read (const std::string &path, tl::InputStream &is, std::string include_path = tl::combine_path (tl::dirname (path), include_path); } } else { - include_path = current_uri.resolved (new_uri).to_string (); + include_path = current_uri.resolved (new_uri).to_abstract_path (); } tl::InputStream is (include_path); diff --git a/src/tl/tl/tlProgress.cc b/src/tl/tl/tlProgress.cc index 4015e0107..88d7e4ee0 100644 --- a/src/tl/tl/tlProgress.cc +++ b/src/tl/tl/tlProgress.cc @@ -46,6 +46,18 @@ ProgressAdaptor::~ProgressAdaptor () tl::Progress::register_adaptor (0); } +void +ProgressAdaptor::register_object (Progress *progress) +{ + mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible. +} + +void +ProgressAdaptor::unregister_object (Progress *progress) +{ + progress->unlink (); +} + void ProgressAdaptor::prev (ProgressAdaptor *pa) { @@ -58,6 +70,59 @@ ProgressAdaptor::prev () return mp_prev; } +void +ProgressAdaptor::signal_break () +{ + for (tl::list::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) { + k->signal_break (); + } +} + +tl::Progress * +ProgressAdaptor::first () +{ + for (tl::list::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) { + if (! k->is_abstract ()) { + return k.operator-> (); + } + } + return 0; +} + +// --------------------------------------------------------------------------------------------- +// ProgressGarbageCollector implementation + +ProgressGarbageCollector::ProgressGarbageCollector () +{ + tl::ProgressAdaptor *a = tl::Progress::adaptor (); + if (a) { + for (tl::ProgressAdaptor::iterator p = a->begin (); p != a->end (); ++p) { + mp_valid_objects.insert (p.operator-> ()); + } + } +} + +ProgressGarbageCollector::~ProgressGarbageCollector () +{ + tl::ProgressAdaptor *a = tl::Progress::adaptor (); + if (a) { + + for (tl::ProgressAdaptor::iterator p = a->begin (); p != a->end (); ) { + + tl::ProgressAdaptor::iterator pn = p; + ++pn; + + if (mp_valid_objects.find (p.operator-> ()) == mp_valid_objects.end ()) { + a->unregister_object (p.operator-> ()); + } + + p = pn; + + } + + } +} + // --------------------------------------------------------------------------------------------- // Progress implementation @@ -187,7 +252,21 @@ bool Progress::test(bool force_yield) } // --------------------------------------------------------------------------------------------- -// Progress implementation +// AbstractProgress implementation + +AbstractProgress::AbstractProgress (const std::string &desc) + : tl::Progress (desc) +{ + initialize (); +} + +AbstractProgress::~AbstractProgress () +{ + shutdown (); +} + +// --------------------------------------------------------------------------------------------- +// RelativeProgress implementation RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval) : Progress (desc, yield_interval) diff --git a/src/tl/tl/tlProgress.h b/src/tl/tl/tlProgress.h index d8bf73917..e0001cd28 100644 --- a/src/tl/tl/tlProgress.h +++ b/src/tl/tl/tlProgress.h @@ -31,12 +31,57 @@ #include "tlTimer.h" #include "tlList.h" +#include + class QWidget; namespace tl { class Progress; +class RelativeProgress; +class AbstractProgress; +class AbsoluteProgress; + +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +/** + * @brief A helper class to clean up pending progress objects + * + * Pending progress objects may be created in scripts. If scripts are aborted + * (e.g. in the debugger), progress objects may stay behing a block the application. + * To prevent this, this object keeps track of progress objects created between + * it's constructor and destructor and cleans up the objects created but not + * destroyed. + */ + +class TL_PUBLIC ProgressGarbageCollector +{ +public: + ProgressGarbageCollector (); + ~ProgressGarbageCollector (); + +private: + std::set mp_valid_objects; +}; /** * @brief The receivers for progress reports @@ -48,20 +93,45 @@ class Progress; class TL_PUBLIC ProgressAdaptor { -public: +public: + typedef tl::list::iterator iterator; + ProgressAdaptor (); virtual ~ProgressAdaptor (); - virtual void register_object (Progress *progress) = 0; - virtual void unregister_object (Progress *progress) = 0; + virtual void register_object (Progress *progress); + virtual void unregister_object (Progress *progress); virtual void trigger (Progress *progress) = 0; virtual void yield (Progress *progress) = 0; void prev (ProgressAdaptor *pa); ProgressAdaptor *prev (); + bool is_busy () const + { + return !mp_objects.empty (); + } + + tl::Progress *first (); + + void signal_break (); + +protected: + iterator begin () + { + return mp_objects.begin (); + } + + iterator end () + { + return mp_objects.end (); + } + private: + friend class ProgressGarbageCollector; + ProgressAdaptor *mp_prev; + tl::list mp_objects; }; /** @@ -77,8 +147,6 @@ public: BreakException () : tl::Exception ("Operation cancelled") { } }; -class Progress; - /** * @brief A "progress" reporter class * @@ -138,6 +206,15 @@ public: */ virtual double value () const = 0; + /** + * @brief Returns true if the progress is an abstract one + * + * Abstract progress objcts don't have a value but mark a section begin executed as a top level progress. + * Technically they will open a channel for the UI - e.g. leaving a progress dialog open while the + * operation is running. + */ + virtual bool is_abstract () const = 0; + /** * @brief Creates a widget that renders the progress graphically * @@ -217,6 +294,7 @@ protected: private: friend class ProgressAdaptor; + friend class ProgressGarbageCollector; std::string m_desc; std::string m_title; @@ -231,6 +309,43 @@ private: static void register_adaptor (tl::ProgressAdaptor *pa); }; +/** + * @brief The abstract progress + * + * An abstract progress object can be used as a top-level progress object to mark a section + * in an operation flow. This will provide a hint for the UI to leave the progress dialog open + * for example. + */ +class TL_PUBLIC AbstractProgress + : public Progress +{ +public: + /** + * @brief Constructor + */ + AbstractProgress (const std::string &desc); + + /** + * @brief Destructor + */ + ~AbstractProgress (); + + /** + * @brief Delivers the current progress as a string (empty for the abstract progress) + */ + std::string formatted_value () const { return std::string (); } + + /** + * @brief Delivers the relative progress (0 for the abstract progress) + */ + double value () const { return 0.0; } + + /** + * @brief Indicates this progress reporter is abstract + */ + bool is_abstract() const { return true; } +}; + /** * @brief A relative progress value * @@ -253,9 +368,6 @@ public: */ RelativeProgress (const std::string &desc, size_t max_count = 0, size_t yield_interval = 1000); - /** - * @brief Destructor - */ ~RelativeProgress (); /** @@ -271,6 +383,11 @@ public: */ double value () const; + /** + * @brief Indicates this progress reporter isn't abstract + */ + bool is_abstract() const { return false; } + /** * @brief Set the format of the output. * @@ -345,7 +462,12 @@ public: */ double value () const; - /** + /** + * @brief Indicates this progress reporter isn't abstract + */ + bool is_abstract() const { return false; } + + /** * @brief Set the format of the output. * * This is a sprintf format string with the value being diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index d951c0f8a..7b1f03fc7 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -167,9 +167,10 @@ InputStream::InputStream (const std::string &abstract_path) tl::Extractor ex (abstract_path.c_str ()); -#if defined(HAVE_QT) if (ex.test (":")) { +#if defined(HAVE_QT) + QResource res (tl::to_qstring (abstract_path)); if (res.size () > 0) { @@ -189,20 +190,32 @@ InputStream::InputStream (const std::string &abstract_path) } - } else +#else + throw tl::Exception (tl::to_string (tr ("Qt not enabled - resource paths are not available"))); #endif -#if defined(HAVE_CURL) || defined(HAVE_QT) - if (ex.test ("http:") || ex.test ("https:")) { - mp_delegate = new InputHttpStream (abstract_path); - } else -#endif - if (ex.test ("pipe:")) { + + } else if (ex.test ("pipe:")) { + mp_delegate = new InputPipe (ex.get ()); - } else if (ex.test ("file:")) { - tl::URI uri (abstract_path); - mp_delegate = new InputZLibFile (uri.path ()); + } else { - mp_delegate = new InputZLibFile (abstract_path); + + tl::URI uri (abstract_path); + + if (uri.scheme () == "http" || uri.scheme () == "https") { +#if defined(HAVE_CURL) || defined(HAVE_QT) + mp_delegate = new InputHttpStream (abstract_path); +#else + throw tl::Exception (tl::to_string (tr ("HTTP support not enabled - HTTP/HTTPS paths are not available"))); +#endif + } else if (uri.scheme () == "file") { + mp_delegate = new InputZLibFile (uri.path ()); + } else if (! uri.scheme ().empty ()) { + throw tl::Exception (tl::to_string (tr ("URI scheme not supported: ")) + uri.scheme ()); + } else { + mp_delegate = new InputZLibFile (abstract_path); + } + } if (! mp_buffer) { diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index 31877e1f2..c355beb75 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -398,6 +398,8 @@ public: * * This will automatically create the appropriate delegate and * delete it later. + * + * The abstract path */ InputStream (const std::string &abstract_path); diff --git a/src/tl/tl/tlThreadedWorkers.cc b/src/tl/tl/tlThreadedWorkers.cc index 7cd63cf76..48ddbabd0 100644 --- a/src/tl/tl/tlThreadedWorkers.cc +++ b/src/tl/tl/tlThreadedWorkers.cc @@ -512,8 +512,6 @@ class TL_PUBLIC WorkerProgressAdaptor : public tl::ProgressAdaptor public: WorkerProgressAdaptor (Worker *worker); - virtual void register_object (Progress *progress); - virtual void unregister_object (Progress *progress); virtual void trigger (Progress *progress); virtual void yield (Progress *progress); @@ -527,16 +525,6 @@ WorkerProgressAdaptor::WorkerProgressAdaptor (Worker *worker) // .. nothing yet .. } -void WorkerProgressAdaptor::register_object (Progress * /*progress*/) -{ - // .. nothing yet .. -} - -void WorkerProgressAdaptor::unregister_object (Progress * /*progress*/) -{ - // .. nothing yet .. -} - void WorkerProgressAdaptor::trigger (Progress * /*progress*/) { // .. nothing yet .. diff --git a/src/tl/tl/tlTimer.cc b/src/tl/tl/tlTimer.cc index 35b384616..3827989fc 100644 --- a/src/tl/tl/tlTimer.cc +++ b/src/tl/tl/tlTimer.cc @@ -31,6 +31,8 @@ #elif defined(__MACH__) # include # include +# include +# include #else # include # include diff --git a/src/tl/tl/tlUri.cc b/src/tl/tl/tlUri.cc index a50c945ed..0c9fdf6d2 100644 --- a/src/tl/tl/tlUri.cc +++ b/src/tl/tl/tlUri.cc @@ -209,6 +209,16 @@ URI::to_string () const return res; } +std::string +URI::to_abstract_path () const +{ + if (m_scheme.empty ()) { + return path (); + } else { + return to_string (); + } +} + URI URI::resolved (const URI &other) const { diff --git a/src/tl/tl/tlUri.h b/src/tl/tl/tlUri.h index a507bf6a3..88e534894 100644 --- a/src/tl/tl/tlUri.h +++ b/src/tl/tl/tlUri.h @@ -144,6 +144,19 @@ public: */ std::string to_string () const; + /** + * @brief Turns the URI into an "abstract path" + * + * The "abstract path" is a concept provided by "tl::InputStream". + * URIs with scheme "file", "http" and "https" are equivalent to their abstract path. + * URIs without a scheme turn into system file paths. + * Other schemes are not allowed. + * + * Abstract paths are more powerful as they support pipes and Qt resource access. + * These modes are not supported by URIs. + */ + std::string to_abstract_path () const; + /** * @brief Resolves an URI relative to this one */ diff --git a/src/tl/unit_tests/tlUriTests.cc b/src/tl/unit_tests/tlUriTests.cc index 7c8712d7d..a5f7c9cbf 100644 --- a/src/tl/unit_tests/tlUriTests.cc +++ b/src/tl/unit_tests/tlUriTests.cc @@ -164,6 +164,8 @@ TEST(2) // use case taken from Magic writer: tl::URI uri ("c:\\users\\myself\\path.txt"); + EXPECT_EQ (uri.scheme (), ""); + EXPECT_EQ (uri.path (), "c:\\users\\myself\\path.txt"); std::string ext = tl::extension (uri.path ()); EXPECT_EQ (ext, "txt"); @@ -178,3 +180,16 @@ TEST(2) throw; } } + +// issue #733 +TEST(3_pathsWithPlus) +{ + EXPECT_EQ (tl::URI ("/users/a_plus_b").resolved (tl::URI ("file.txt")).to_string (), "/users/a_plus_b/file.txt"); + EXPECT_EQ (tl::URI ("/users/a+b").resolved (tl::URI ("file.txt")).to_string (), "/users/a%2Bb/file.txt"); + EXPECT_EQ (tl::URI ("/users/a+b").resolved (tl::URI ("file.txt")).to_abstract_path (), "/users/a+b/file.txt"); + EXPECT_EQ (tl::URI ("file://users/a+b").resolved (tl::URI ("file.txt")).to_string (), "file://users/a%2Bb/file.txt"); + EXPECT_EQ (tl::URI ("file://users/a+b").resolved (tl::URI ("file.txt")).to_abstract_path (), "file://users/a%2Bb/file.txt"); + // drive-letter paths + EXPECT_EQ (tl::URI ("c:/users/a+b").resolved (tl::URI ("file.txt")).to_string (), "c:/users/a%2Bb/file.txt"); + EXPECT_EQ (tl::URI ("c:/users/a+b").resolved (tl::URI ("file.txt")).to_abstract_path (), "c:/users/a+b/file.txt"); +} diff --git a/src/unit_tests/unit_tests.pro b/src/unit_tests/unit_tests.pro index a5eb77c46..1676e614a 100644 --- a/src/unit_tests/unit_tests.pro +++ b/src/unit_tests/unit_tests.pro @@ -34,7 +34,9 @@ LIBS += -lklayout_gsi_test DEPENDPATH += $$QTBASIC_INC equals(HAVE_QTBINDINGS, "1") { - LIBS += -lklayout_QtXml + !equals(HAVE_QT_XML, "0") { + LIBS += -lklayout_QtXml + } equals(HAVE_QT5, "1") { LIBS += -lklayout_QtWidgets } diff --git a/testdata/algo/deep_region_au11.gds b/testdata/algo/deep_region_au11.gds index 764182714..cb37c402b 100644 Binary files a/testdata/algo/deep_region_au11.gds and b/testdata/algo/deep_region_au11.gds differ diff --git a/testdata/drc/drcGenericTests_18.drc b/testdata/drc/drcGenericTests_18.drc new file mode 100644 index 000000000..f03aaab29 --- /dev/null +++ b/testdata/drc/drcGenericTests_18.drc @@ -0,0 +1,25 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) + +h = l1 - l2 +h.drc(with_holes == 0).output(100, 0) +h.drc(with_holes != 0).output(101, 0) +h.drc(with_holes == 3).output(102, 0) +h.drc(1 <= with_holes < 3).output(103, 0) +h.drc(1 <= primary.with_holes <= 1).output(104, 0) +h.drc(with_holes >= 2).output(105, 0) +h.drc(with_holes >= 0).output(106, 0) + diff --git a/testdata/drc/drcGenericTests_18.gds b/testdata/drc/drcGenericTests_18.gds new file mode 100644 index 000000000..25e1867e1 Binary files /dev/null and b/testdata/drc/drcGenericTests_18.gds differ diff --git a/testdata/drc/drcGenericTests_au18.gds b/testdata/drc/drcGenericTests_au18.gds new file mode 100644 index 000000000..f656a7608 Binary files /dev/null and b/testdata/drc/drcGenericTests_au18.gds differ diff --git a/testdata/drc/drcGenericTests_au18d.gds b/testdata/drc/drcGenericTests_au18d.gds new file mode 100644 index 000000000..f656a7608 Binary files /dev/null and b/testdata/drc/drcGenericTests_au18d.gds differ diff --git a/testdata/drc/drcSimpleTests_29.drc b/testdata/drc/drcSimpleTests_29.drc new file mode 100644 index 000000000..f46052830 --- /dev/null +++ b/testdata/drc/drcSimpleTests_29.drc @@ -0,0 +1,25 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) + +h = l1 - l2 +h.with_holes(0).output(100, 0) +h.without_holes(0).output(101, 0) +h.with_holes(3).output(102, 0) +h.with_holes(1..3).output(103, 0) +h.with_holes(1..1).output(104, 0) +h.with_holes(2, nil).output(105, 0) +h.with_holes(0, nil).output(106, 0) + diff --git a/testdata/drc/drcSimpleTests_29.gds b/testdata/drc/drcSimpleTests_29.gds new file mode 100644 index 000000000..25e1867e1 Binary files /dev/null and b/testdata/drc/drcSimpleTests_29.gds differ diff --git a/testdata/drc/drcSimpleTests_au29.gds b/testdata/drc/drcSimpleTests_au29.gds new file mode 100644 index 000000000..3c2e167c2 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au29.gds differ diff --git a/testdata/drc/drcSimpleTests_au29d.gds b/testdata/drc/drcSimpleTests_au29d.gds new file mode 100644 index 000000000..3c2e167c2 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au29d.gds differ diff --git a/testdata/lefdef/fill/simple.def b/testdata/lefdef/fill/simple.def new file mode 100644 index 000000000..1e33f486a --- /dev/null +++ b/testdata/lefdef/fill/simple.def @@ -0,0 +1,14 @@ +VERSION 5.8 ; +DESIGN test ; +DIEAREA ( 0 0 ) ( 4000 7000 ) ; +FILLS 2 ; +- LAYER M1 + RECT ( 1000 2000 ) ( 1500 4000 ) + RECT ( 1000 4500 ) ( 1500 6500 ) ; +- LAYER M2 + RECT ( 1000 2000 ) ( 1500 4000 ) + POLYGON ( 1000 500 ) ( 2000 1500 ) ( 3000 1500 ) ( 3000 500 ) ; +- LAYER M2 + OPC + RECT ( 3000 2000 ) ( 3500 4000 ) ; +END FILLS +END DESIGN diff --git a/testdata/lefdef/fill/simple.lef b/testdata/lefdef/fill/simple.lef new file mode 100644 index 000000000..0587b8c54 --- /dev/null +++ b/testdata/lefdef/fill/simple.lef @@ -0,0 +1,29 @@ +VERSION 5.8 ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; +UNITS + DATABASE MICRONS 2000 ; +END UNITS +MANUFACTURINGGRID 0.000500 ; + +LAYER M1 + TYPE ROUTING ; + DIRECTION HORIZONTAL ; + PITCH 100 ; + WIDTH 50 ; + SPACING 50 ; +END M1 + +LAYER VIA1 + TYPE CUT ; +END VIA1 + +LAYER M2 + TYPE ROUTING ; + DIRECTION VERTICAL ; + PITCH 100 ; + WIDTH 50 ; + SPACING 50 ; +END M2 + +END LIBRARY diff --git a/testdata/lefdef/fill/simple.map b/testdata/lefdef/fill/simple.map new file mode 100644 index 000000000..0f013c547 --- /dev/null +++ b/testdata/lefdef/fill/simple.map @@ -0,0 +1,4 @@ +DIEAREA ALL 100 0 +M1 FILL 10 1 +M2 FILL 20 2 +M2 FILLOPC 20 3 diff --git a/testdata/lefdef/fill/simple_au.oas.gz b/testdata/lefdef/fill/simple_au.oas.gz new file mode 100644 index 000000000..c6ca9c9eb Binary files /dev/null and b/testdata/lefdef/fill/simple_au.oas.gz differ diff --git a/testdata/lefdef/fill/with_mask.def b/testdata/lefdef/fill/with_mask.def new file mode 100644 index 000000000..5a45925e6 --- /dev/null +++ b/testdata/lefdef/fill/with_mask.def @@ -0,0 +1,14 @@ +VERSION 5.8 ; +DESIGN test ; +DIEAREA ( 0 0 ) ( 4000 7000 ) ; +FILLS 2 ; +- LAYER M1 + MASK 1 + RECT ( 1000 2000 ) ( 1500 4000 ) + RECT ( 1000 4500 ) ( 1500 6500 ) ; +- LAYER M2 + MASK 2 + RECT ( 1000 2000 ) ( 1500 4000 ) + POLYGON ( 1000 500 ) ( 2000 1500 ) ( 3000 1500 ) ( 3000 500 ) ; +- LAYER M2 + MASK 2 + OPC + RECT ( 3000 2000 ) ( 3500 4000 ) ; +END FILLS +END DESIGN diff --git a/testdata/lefdef/fill/with_mask.lef b/testdata/lefdef/fill/with_mask.lef new file mode 100644 index 000000000..412e7e915 --- /dev/null +++ b/testdata/lefdef/fill/with_mask.lef @@ -0,0 +1,15 @@ +VERSION 5.8 ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; +UNITS + DATABASE MICRONS 2000 ; +END UNITS + +LAYER M1 + TYPE ROUTING ; +END M1 +LAYER M2 + TYPE ROUTING ; +END M2 + +END LIBRARY diff --git a/testdata/lefdef/fill/with_mask.map b/testdata/lefdef/fill/with_mask.map new file mode 100644 index 000000000..e2137e9fa --- /dev/null +++ b/testdata/lefdef/fill/with_mask.map @@ -0,0 +1,4 @@ +DIEAREA ALL 100 0 +M1 FILL:MASK:1 10 1 +M2 FILL:MASK:2 20 2 +M2 FILLOPC:MASK:2 20 3 diff --git a/testdata/lefdef/fill/with_mask_au.oas.gz b/testdata/lefdef/fill/with_mask_au.oas.gz new file mode 100644 index 000000000..946e28973 Binary files /dev/null and b/testdata/lefdef/fill/with_mask_au.oas.gz differ diff --git a/testdata/lefdef/mapfile/au.oas.gz b/testdata/lefdef/mapfile/au.oas.gz index 942c568de..bf3c4bea7 100644 Binary files a/testdata/lefdef/mapfile/au.oas.gz and b/testdata/lefdef/mapfile/au.oas.gz differ diff --git a/testdata/lefdef/masks-2/au.oas.gz b/testdata/lefdef/masks-2/au.oas.gz index 0cceaa128..bb71f6fe6 100644 Binary files a/testdata/lefdef/masks-2/au.oas.gz and b/testdata/lefdef/masks-2/au.oas.gz differ diff --git a/testdata/lefdef/viasize/au.oas.gz b/testdata/lefdef/viasize/au.oas.gz new file mode 100644 index 000000000..944161a0c Binary files /dev/null and b/testdata/lefdef/viasize/au.oas.gz differ diff --git a/testdata/lefdef/viasize/test.def b/testdata/lefdef/viasize/test.def new file mode 100644 index 000000000..10821b311 --- /dev/null +++ b/testdata/lefdef/viasize/test.def @@ -0,0 +1,35 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN chip_top ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 0 0 ) ( 300 300 ) ; +STYLES 2 ; +- STYLE 1 ( 30 10 ) ( 10 30 ) ( -10 30 ) ( -30 10 ) ( -30 -10 ) ( -10 -30 ) ( 10 -30 ) ( 30 -10 ) ; +END STYLES +VIAS 1 ; + - VIA1_small + + RECT M1 ( -20 -15 ) ( 20 15 ) + + RECT VIA1 ( -10 -10 ) ( 10 10 ) + + RECT VIA1 ( -13 -13 ) ( 13 13 ) + + RECT M2 ( -25 -25 ) ( 25 25 ) ; + - VIA1_large + + RECT M1 ( -20 -15 ) ( 20 15 ) + + RECT VIA1 ( -12 -12 ) ( 12 12 ) + + RECT VIA1 ( -13 -13 ) ( 13 13 ) + + RECT M2 ( -25 -25 ) ( 25 25 ) ; +END VIAS +SPECIALNETS 1 ; +- dummy + + ROUTED + RECT M2 ( 350 0 ) ( 250 100 ) + + POLYGON M1 ( 300 0 ) ( 300 50 ) ( 350 50 ) ( 400 100 ) ( 400 0 ) + + ROUTED + POLYGON M2 ( 300 150 ) ( 300 200 ) ( 350 200 ) ( 400 250 ) ( 400 150 ) + + RECT M1 ( 0 0 ) ( 100 200 ) + + ROUTED M1 30 + MASK 2 ( 0 0 15 ) ( 100 0 0 ) VIA1_small ( 100 100 10 ) + + ROUTED M2 50 + SHAPE RING + STYLE 1 ( 0 100 ) ( 100 200 ) ( 200 200 ) + + ROUTED + MASK 2 + RECT M2 ( 250 0 ) ( 150 100 ) + + ROUTED + SHAPE RING + MASK 1 + VIA VIA1_large E ( 200 200 ) +; +END SPECIALNETS +END DESIGN diff --git a/testdata/lefdef/viasize/test.lef b/testdata/lefdef/viasize/test.lef new file mode 100644 index 000000000..da907c86d --- /dev/null +++ b/testdata/lefdef/viasize/test.lef @@ -0,0 +1,24 @@ +VERSION 5.8 ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +MANUFACTURINGGRID 0.001 ; + +LAYER M1 + TYPE ROUTING ; +END M1 + +LAYER VIA1 + TYPE CUT ; +END VIA1 + +LAYER M2 + TYPE ROUTING ; + WIDTH 0.05 ; +END M2 + +END LIBRARY diff --git a/testdata/lefdef/viasize/test.map b/testdata/lefdef/viasize/test.map new file mode 100644 index 000000000..7c58b2c01 --- /dev/null +++ b/testdata/lefdef/viasize/test.map @@ -0,0 +1,8 @@ +# some variations of map file entries +DIEAREA ALL 1 0 +COMP ALL 2 0 +M1 NET,SPNET 7 0 +M2 NET,SPNET 9 0 +VIA1 VIA 8 0 +VIA1 VIA:SIZE:0.02x0.02 8 1 +VIA1 VIA:SIZE:0.024x0.024 8 2 diff --git a/testdata/pymod/import_QtUiTools.py b/testdata/pymod/import_QtUiTools.py new file mode 100755 index 000000000..811e12200 --- /dev/null +++ b/testdata/pymod/import_QtUiTools.py @@ -0,0 +1,43 @@ +# KLayout Layout Viewer +# Copyright (C) 2006-2021 Matthias Koefferlein +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import klayout.QtCore as QtCore +import klayout.QtUiTools as QtUiTools +import unittest +import sys + +# Tests the basic abilities of the module + +class BasicTest(unittest.TestCase): + + def test_1(self): + self.assertEqual("QUiLoader" in QtUiTools.__all__, True) + + def test_2(self): + app = QtCore.QCoreApplication([ "appname" ]) + q = QtUiTools.QUiLoader() + +# run unit tests +if __name__ == '__main__': + suite = unittest.TestSuite() + suite = unittest.TestLoader().loadTestsFromTestCase(BasicTest) + + if not unittest.TextTestRunner(verbosity = 1).run(suite).wasSuccessful(): + sys.exit(1) + + diff --git a/testdata/python/basic.py b/testdata/python/basic.py index 97a2aed30..0e5d67fa7 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -1188,6 +1188,9 @@ class BasicTest(unittest.TestCase): # test client data binding to C++ objects b = pya.B() + + longint = 10000000000000000 + longint_as_int = (sys.maxsize > 5000000000 or (str(longint) == "10000000000000000" and type(longint) is int)) self.assertEqual( b.b20a( 5.0 ), False ) self.assertEqual( b.b20a( None ), True ) @@ -1195,27 +1198,27 @@ class BasicTest(unittest.TestCase): self.assertEqual( b.b20a( "hallo" ), False ) self.assertEqual( b.b20a( False ), False ) self.assertEqual( b.b20a( True ), False ) - self.assertEqual( b.b20a( 10000000000000000 ), False ) + self.assertEqual( b.b20a( longint ), False ) self.assertEqual( b.b20b( 5.0 ), True ) self.assertEqual( b.b20b( None ), False ) self.assertEqual( b.b20b( 1 ), False ) self.assertEqual( b.b20b( "hallo" ), False ) self.assertEqual( b.b20b( False ), False ) self.assertEqual( b.b20b( True ), False ) - if sys.maxsize > 5000000000: - # on 64 bit platforms this fits into a long value, therefore this test returns false: - self.assertEqual( b.b20b( 10000000000000000 ), False ) + if longint_as_int: + # this fits into a long value, therefore this test returns false: + self.assertEqual( b.b20b( longint ), False ) else: # otherwise it is converted to a double: - self.assertEqual( b.b20b( 10000000000000000 ), True ) + self.assertEqual( b.b20b( longint ), True ) self.assertEqual( b.b20c( 5.0 ), False ) self.assertEqual( b.b20c( None ), False ) - if sys.maxsize > 5000000000: - # on 64 bit platforms this fits into a long value, therefore this test returns True: - self.assertEqual( b.b20c( 10000000000000000 ), True ) + if longint_as_int: + # this fits into a long value, therefore this test returns false: + self.assertEqual( b.b20c( longint ), True ) else: # otherwise it is converted to a double and the test returns false: - self.assertEqual( b.b20c( 10000000000000000 ), False ) + self.assertEqual( b.b20c( longint ), False ) self.assertEqual( b.b20c( "hallo" ), False ) self.assertEqual( b.b20c( False ), False ) self.assertEqual( b.b20c( True ), False ) @@ -1225,14 +1228,14 @@ class BasicTest(unittest.TestCase): self.assertEqual( b.b20d( "hallo" ), True ) self.assertEqual( b.b20d( False ), False ) self.assertEqual( b.b20d( True ), False ) - self.assertEqual( b.b20d( 10000000000000000 ), False ) + self.assertEqual( b.b20d( longint ), False ) self.assertEqual( b.b20e( 5.0 ), False ) self.assertEqual( b.b20e( None ), False ) self.assertEqual( b.b20e( 1 ), False ) self.assertEqual( b.b20e( "hallo" ), False ) self.assertEqual( b.b20e( False ), True ) self.assertEqual( b.b20e( True ), True ) - self.assertEqual( b.b20e( 10000000000000000 ), False ) + self.assertEqual( b.b20e( longint ), False ) self.assertEqual( b.b21a( 50 ), "50" ) self.assertEqual( b.b21a( True ), "true" ) diff --git a/testdata/python/dbPolygonTest.py b/testdata/python/dbPolygonTest.py index 1b653d102..ce679554f 100644 --- a/testdata/python/dbPolygonTest.py +++ b/testdata/python/dbPolygonTest.py @@ -289,6 +289,9 @@ class DBPolygonTests(unittest.TestCase): p = pya.Polygon( [ pya.Point.new(0, 0), pya.Point.new(10, 50), pya.Point.new(0, 100), pya.Point.new(200, 100), pya.Point.new(200, 0) ]) self.assertEqual(str(p.smooth(5)), "(0,0;10,50;0,100;200,100;200,0)") self.assertEqual(str(p.smooth(15)), "(0,0;0,100;200,100;200,0)") + p = pya.Polygon( [ pya.Point.new(0, 0), pya.Point.new(10, 50), pya.Point.new(10, 100), pya.Point.new(200, 100), pya.Point.new(200, 0) ]) + self.assertEqual(str(p.smooth(15, False)), "(0,0;10,100;200,100;200,0)") + self.assertEqual(str(p.smooth(15, True)), "(0,0;10,50;10,100;200,100;200,0)") # Ellipse constructor p = pya.Polygon.ellipse( pya.Box(-10000, -20000, 30000, 40000), 200 ) diff --git a/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 81011ed18..008a064d7 100644 --- a/testdata/ruby/basic_testcore.rb +++ b/testdata/ruby/basic_testcore.rb @@ -27,6 +27,7 @@ class Basic_TestClass < TestBase a = nil GC.start + GC.start assert_equal( RBA::A::instance_count, ic0 ) a = RBA::A.new @@ -1460,10 +1461,8 @@ class Basic_TestClass < TestBase assert_equal(RBA::A.a20_get == nil, false) # after "manage" the object gets volatile again - 1.times do - a = RBA::A.a20_get - a._manage - end + a = RBA::A.a20_get + a._manage # Looks like Ruby is keeping the last A instance in some kind of cache: # this will release it @@ -2739,13 +2738,16 @@ class Basic_TestClass < TestBase GC.start + nx = RBA::X::instances z = RBA::Z::new - nx = RBA::X::instances x = RBA::X::new("1") z.set_x(x) assert_equal(RBA::X::instances, nx + 1) + # weird. On WIN/32bit, this makes the test pass (enables GC somehow?): + puts("ANYTHING") + x = nil z.set_x(nil) GC.start @@ -2761,6 +2763,9 @@ class Basic_TestClass < TestBase assert_equal(RBA::X::instances, nx + 1) + # weird. On WIN/32bit, this makes the test pass (enables GC somehow?): + puts("ANYTHING") + # this will release the object - hence it's going to be deleted z.set_x_keep(nil) GC.start diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index 2d805dd7d..b9723def0 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -335,212 +335,6 @@ class DBLayout_TestClass < TestBase end - def test_5 - - # Recursive shape iterator tests - - 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) - - bb = RBA::Box.new(1, 101, 1001, 1201) - c3.shapes(1).insert(bb) - - 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)))) - - i1 = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(0, 0, 100, 100)) - i1copy = i1.dup - assert_equal(i1copy.overlapping?, false) - assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") - i1.reset - assert_equal(dcollect(i1, l), "[c0](0,0.1;1,1.2)/[c1](0,0.1;1,1.2)/[c2](0.1,0;1.1,1.1)") - assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") - - i1 = l.begin_shapes_touching(c0.cell_index, 0, RBA::DBox.new(0, 0, 0.100, 0.100)) - assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") - - i1 = c0.begin_shapes_rec_touching(0, RBA::Box.new(0, 0, 100, 100)) - assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") - - i1 = c0.begin_shapes_rec_touching(0, RBA::DBox.new(0, 0, 0.100, 0.100)) - assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") - - i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(0, 0, 100, 100)); - assert_equal(collect(i1o, l), ""); - i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::DBox.new(0, 0, 0.100, 0.100)); - assert_equal(collect(i1o, l), ""); - i1copy.overlapping = true - assert_equal(i1copy.overlapping?, true) - assert_equal(collect(i1copy, l), ""); - i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(0, 0, 100, 101)); - assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); - i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::DBox.new(0, 0, 0.100, 0.101)); - assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); - i1copy.region = RBA::Box.new(0, 0, 100, 101) - assert_equal(i1copy.region.to_s, "(0,0;100,101)") - assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); - i1copy.region = RBA::Region::new(RBA::Box.new(0, 0, 100, 101)) - assert_equal(i1copy.region.to_s, "(0,0;100,101)") - assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); - i1copy.region = RBA::Box.new(-1000, -1000, 1100, 1101) - i1copy.confine_region(RBA::Box.new(0, 0, 100, 101)) - assert_equal(i1copy.region.to_s, "(0,0;100,101)") - assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); - i1copy.region = RBA::Box.new(-1000, -1000, 1100, 1101) - i1copy.confine_region(RBA::Region::new(RBA::Box.new(0, 0, 100, 101))) - assert_equal(i1copy.region.to_s, "(0,0;100,101)") - assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); - i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(0, 0, 101, 101)); - assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)"); - i1o = c0.begin_shapes_rec_overlapping(0, RBA::Box.new(0, 0, 101, 101)); - assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)"); - - i2 = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(-100, 0, 100, 100)); - assert_equal(collect(i2, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](-1200,0;-100,1000)"); - i2o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(-100, 0, 100, 100)); - assert_equal(collect(i2o, l), ""); - i2o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(-101, 0, 101, 101)); - assert_equal(collect(i2o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](-1200,0;-100,1000)"); - - i4 = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(-100, 0, 2000, 100)); - i4_copy = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(-100, 0, 2000, 100)); - i4.max_depth = 0; - assert_equal(collect(i4, l), "[c0](0,100;1000,1200)"); - - assert_equal(i4 == i4, true); - assert_equal(i4 != i4, false); - assert_equal(i4 == i4_copy, false); - assert_equal(i4 != i4_copy, true); - i4 = i4_copy.dup; - assert_equal(i4 == i4_copy, true); - assert_equal(i4 != i4_copy, false); - i4.max_depth = 1; - assert_equal(collect(i4, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](-1200,0;-100,1000)"); - - i4.assign(i4_copy); - assert_equal(collect(i4, 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)"); - - i5 = l.begin_shapes(c0.cell_index, 0); - assert_equal(collect(i5, 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 = RBA::RecursiveShapeIterator::new - assert_equal(collect(ii, l), "") - - ii = RBA::RecursiveShapeIterator::new(l, c1, 0) - assert_equal(collect(ii, l), "[c1](0,100;1000,1200)") - assert_equal(ii.top_cell.name, "c1") - assert_equal(ii.layout == l, true) - - ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1]) - ic = ii.dup - assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") - assert_equal(collect(ic, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") - - ii = RBA::RecursiveShapeIterator::new(l, c2, 0, RBA::Box.new(-100, 0, 2000, 100), false) - assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") - - ii = RBA::RecursiveShapeIterator::new(l, c2, 0, RBA::Box.new(-100, 0, 2000, 100), true) - assert_equal(collect(ii, l), "") - - ii = RBA::RecursiveShapeIterator::new(l, c2, 0, RBA::Box.new(-100, 0, 2000, 101), true) - assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") - - ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 100), false) - assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") - - ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), false) - assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") - - ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), true) - assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") - - ii = RBA::RecursiveShapeIterator::new(l, c0, 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.reset - ii.unselect_cells("c0") - ii.select_cells("c2") - assert_equal(collect(ii, l), "[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)") - - ii.reset_selection - ii.unselect_cells("c*") - ii.select_cells([ c2.cell_index ]) - assert_equal(collect(ii, l), "[c2](100,0;1100,1100)") - - ii.reset_selection - ii.unselect_all_cells - ii.select_cells("c2") - assert_equal(collect(ii, l), "[c2](100,0;1100,1100)") - - ii.reset_selection - ii.select_all_cells - ii.unselect_cells("c2") - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - - ii.reset_selection - ii.select_cells("c*") - ii.unselect_cells([ c1.cell_index, c2.cell_index ]) - assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") - - end - - def test_5x - - # Recursive shape iterator tests - - 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) - c3.shapes(0).insert(b) - - bb = RBA::Box.new(1, 101, 1001, 1201) - c3.shapes(1).insert(bb) - - 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), RBA::Vector::new(10, 20), RBA::Vector::new(11, 21), 2, 3)) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - - res = [] - i = l.begin_shapes(c0.cell_index, 0) - while !i.at_end? - res << i.shape.box.transformed(i.trans).to_s + " " + i.path.collect { |e| "[" + l.cell(e.cell_inst.cell_index).name + " #" + e.ia.to_s + "," + e.ib.to_s + " -> " + e.specific_trans.to_s + "]" }.join("") - i.next - end - - assert_equal(res.join("\n") + "\n", <<"END") -(1200,0;2200,1100) [c2 #-1,-1 -> r0 100,-100][c3 #-1,-1 -> r0 1100,0] -(-1200,0;-100,1000) [c3 #0,0 -> r90 0,0] -(-1190,20;-90,1020) [c3 #1,0 -> r90 10,20] -(-1189,21;-89,1021) [c3 #0,1 -> r90 11,21] -(-1179,41;-79,1041) [c3 #1,1 -> r90 21,41] -(-1178,42;-78,1042) [c3 #0,2 -> r90 22,42] -(-1168,62;-68,1062) [c3 #1,2 -> r90 32,62] -END - - end - def collect_hier(l) s = "" diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index 468864b35..8f94efafb 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -304,6 +304,9 @@ class DBPolygon_TestClass < TestBase p = RBA::Polygon::new( [ RBA::Point.new(0, 0), RBA::Point.new(10, 50), RBA::Point.new(0, 100), RBA::Point.new(200, 100), RBA::Point.new(200, 0) ]) assert_equal(p.smooth(5).to_s, "(0,0;10,50;0,100;200,100;200,0)") assert_equal(p.smooth(15).to_s, "(0,0;0,100;200,100;200,0)") + p = RBA::Polygon::new( [ RBA::Point.new(0, 0), RBA::Point.new(10, 50), RBA::Point.new(10, 100), RBA::Point.new(200, 100), RBA::Point.new(200, 0) ]) + assert_equal(p.smooth(15, false).to_s, "(0,0;10,100;200,100;200,0)") + assert_equal(p.smooth(15, true).to_s, "(0,0;10,50;10,100;200,100;200,0)") # Ellipse constructor p = RBA::Polygon::ellipse( RBA::Box::new(-10000, -20000, 30000, 40000), 200 ) diff --git a/testdata/ruby/dbReaders.rb b/testdata/ruby/dbReaders.rb index 3c6dcb47e..8288d6c43 100644 --- a/testdata/ruby/dbReaders.rb +++ b/testdata/ruby/dbReaders.rb @@ -289,6 +289,18 @@ class DBReaders_TestClass < TestBase conf.lef_pins_datatype = 181 assert_equal(conf.lef_pins_datatype, 181) + assert_equal(conf.produce_fills, true) + conf.produce_fills = false + assert_equal(conf.produce_fills, false) + + assert_equal(conf.fills_suffix, ".FILL") + conf.fills_suffix = "XFILL" + assert_equal(conf.fills_suffix, "XFILL") + + assert_equal(conf.fills_datatype, 5) + conf.fills_datatype = 19 + assert_equal(conf.fills_datatype, 19) + assert_equal(conf.produce_obstructions, true) conf.produce_obstructions = false assert_equal(conf.produce_obstructions, false) diff --git a/testdata/ruby/dbRecursiveInstanceIterator.rb b/testdata/ruby/dbRecursiveInstanceIterator.rb new file mode 100644 index 000000000..d3cf5b206 --- /dev/null +++ b/testdata/ruby/dbRecursiveInstanceIterator.rb @@ -0,0 +1,265 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2021 Matthias Koefferlein +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class DBLayout_TestClass < TestBase + + def collect(s, l) + + res = [] + while !s.at_end? + r = "[#{s.inst_cell.name}]" + r += (s.trans * s.inst_trans).to_s + res.push(r) + s.next + end + + return res.join("/") + + end + + def dcollect(s, l) + + res = [] + while !s.at_end? + r = "[#{s.inst_cell.name}]" + r += (s.dtrans * s.inst_dtrans).to_s + res.push(r) + s.next + end + + return res.join("/") + + end + + def test_1 + + # Recursive instance iterator tests + + 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) + + bb = RBA::Box.new(1, 101, 1001, 1201) + c3.shapes(1).insert(bb) + + 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)))) + + i1 = c0.begin_instances_rec_touching(RBA::Box.new(0, 0, 100, 100)) + i1copy = i1.dup + assert_equal(i1copy.overlapping?, false) + assert_equal(collect(i1, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100") + i1.reset + assert_equal(dcollect(i1, l), "[c1]r0 *1 0,0/[c2]r0 *1 0.1,-0.1") + assert_equal(collect(i1copy, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100") + + i1 = c0.begin_instances_rec_touching(RBA::DBox.new(0, 0, 0.100, 0.100)) + assert_equal(collect(i1, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100") + + i1o = c0.begin_instances_rec_overlapping(RBA::Box.new(0, 0, 100, 100)); + assert_equal(collect(i1o, l), ""); + i1o = c0.begin_instances_rec_overlapping(RBA::DBox.new(0, 0, 0.100, 0.100)); + assert_equal(collect(i1o, l), ""); + i1copy.overlapping = true + assert_equal(i1copy.overlapping?, true) + assert_equal(collect(i1copy, l), ""); + i1o = c0.begin_instances_rec_overlapping(RBA::Box.new(0, 0, 100, 101)); + assert_equal(collect(i1o, l), "[c1]r0 *1 0,0"); + i1o = c0.begin_instances_rec_overlapping(RBA::DBox.new(0, 0, 0.100, 0.101)); + assert_equal(collect(i1o, l), "[c1]r0 *1 0,0"); + i1copy.region = RBA::Box.new(0, 0, 100, 101) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c1]r0 *1 0,0"); + i1copy.region = RBA::Region::new(RBA::Box.new(0, 0, 100, 101)) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c1]r0 *1 0,0"); + i1copy.region = RBA::Box.new(-1000, -1000, 1100, 1101) + i1copy.confine_region(RBA::Box.new(0, 0, 100, 101)) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c1]r0 *1 0,0"); + i1copy.region = RBA::Box.new(-1000, -1000, 1100, 1101) + i1copy.confine_region(RBA::Region::new(RBA::Box.new(0, 0, 100, 101))) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c1]r0 *1 0,0"); + i1o = c0.begin_instances_rec_overlapping(RBA::Box.new(0, 0, 101, 101)); + assert_equal(collect(i1o, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100"); + i1o = c0.begin_instances_rec_overlapping(RBA::Box.new(0, 0, 101, 101)); + assert_equal(collect(i1o, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100"); + + i2 = c0.begin_instances_rec_touching(RBA::Box.new(-100, 0, 100, 100)); + assert_equal(collect(i2, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100/[c3]r90 *1 0,0"); + i2o = c0.begin_instances_rec_overlapping(RBA::Box.new(-100, 0, 100, 100)); + assert_equal(collect(i2o, l), ""); + i2o = c0.begin_instances_rec_overlapping(RBA::Box.new(-101, 0, 101, 101)); + assert_equal(collect(i2o, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100/[c3]r90 *1 0,0"); + + i4 = c0.begin_instances_rec_touching(RBA::Box.new(-100, 0, 2000, 100)); + i4_copy = c0.begin_instances_rec_touching(RBA::Box.new(-100, 0, 2000, 100)); + i4.max_depth = 0; + assert_equal(collect(i4, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100/[c3]r90 *1 0,0"); + + assert_equal(i4 == i4, true); + assert_equal(i4 != i4, false); + assert_equal(i4 == i4_copy, false); + assert_equal(i4 != i4_copy, true); + i4 = i4_copy.dup + assert_equal(i4 == i4_copy, true); + assert_equal(i4 != i4_copy, false); + i4.max_depth = 1; + assert_equal(i4.max_depth, 1) + assert_equal(collect(i4, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100/[c3]r90 *1 0,0"); + i4.min_depth = 1; + assert_equal(i4.min_depth, 1) + assert_equal(collect(i4, l), "[c3]r0 *1 1200,-100"); + + i4.assign(i4_copy); + assert_equal(collect(i4, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100/[c3]r90 *1 0,0"); + + i5 = c0.begin_instances_rec + assert_equal(collect(i5, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100/[c3]r90 *1 0,0"); + + ii = RBA::RecursiveInstanceIterator::new + assert_equal(collect(ii, l), "") + + ii = RBA::RecursiveInstanceIterator::new(l, c2) + assert_equal(collect(ii, l), "[c3]r0 *1 1100,0") + assert_equal(ii.top_cell.name, "c2") + assert_equal(ii.layout == l, true) + + ii = RBA::RecursiveInstanceIterator::new(l, c0, RBA::Box.new(-100, 0, 2000, 100), false) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100/[c3]r90 *1 0,0") + + ii = RBA::RecursiveInstanceIterator::new(l, c0, RBA::Box.new(-100, 0, 2000, 100), true) + assert_equal(collect(ii, l), "[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100") + + ii = RBA::RecursiveInstanceIterator::new(l, c0, RBA::Box.new(-100, 0, 2000, 101), true) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100") + + ii = RBA::RecursiveInstanceIterator::new(l, c0, RBA::Region::new(RBA::Box.new(-100, 0, 2000, 101)), true) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100") + + ii = RBA::RecursiveInstanceIterator::new(l, c0) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100/[c3]r90 *1 0,0") + + ii.reset + ii.unselect_cells("c0") + ii.select_cells("c2") + assert_equal(collect(ii, l), "[c3]r0 *1 1200,-100") + + ii.reset_selection + ii.unselect_cells("c*") + ii.select_cells([ c2.cell_index ]) + assert_equal(collect(ii, l), "[c3]r0 *1 1200,-100") + + ii.reset_selection + ii.unselect_all_cells + ii.select_cells("c2") + assert_equal(collect(ii, l), "[c3]r0 *1 1200,-100") + + ii.reset_selection + ii.select_all_cells + ii.unselect_cells("c2") + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100/[c3]r90 *1 0,0") + + ii.reset_selection + ii.select_cells("c*") + ii.unselect_cells([ c1.cell_index, c2.cell_index ]) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c2]r0 *1 100,-100/[c3]r90 *1 0,0") + + ii = RBA::RecursiveInstanceIterator::new(l, c0) + assert_equal(ii.all_targets_enabled?, true) + ii.targets = "c3" + assert_equal(ii.all_targets_enabled?, false) + assert_equal(collect(ii, l), "[c3]r0 *1 1200,-100/[c3]r90 *1 0,0") + ii.enable_all_targets + assert_equal(ii.all_targets_enabled?, true) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c2]r0 *1 100,-100/[c3]r90 *1 0,0") + ii.targets = [ c3.cell_index, c1.cell_index ] + assert_equal(ii.all_targets_enabled?, false) + assert_equal(collect(ii, l), "[c1]r0 *1 0,0/[c3]r0 *1 1200,-100/[c3]r90 *1 0,0") + + end + + def test_2 + + # Recursive instance iterator tests + + 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) + c3.shapes(0).insert(b) + + bb = RBA::Box.new(1, 101, 1001, 1201) + c3.shapes(1).insert(bb) + + 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), RBA::Vector::new(10, 20), RBA::Vector::new(11, 21), 2, 3)) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + + res = [] + i = c0.begin_instances_rec + while !i.at_end? + res << i.inst_cell.bbox.transformed(i.trans * i.inst_trans).to_s + " " + (i.path + [ i.current_inst_element ]).collect { |e| "[" + l.cell(e.cell_inst.cell_index).name + " #" + e.ia.to_s + "," + e.ib.to_s + " -> " + e.specific_trans.to_s + "]" }.join("") + i.next + end + + assert_equal(res.join("\n") + "\n", <<"END") +() [c1 #-1,-1 -> r0 0,0] +(1200,0;2201,1101) [c2 #-1,-1 -> r0 100,-100][c3 #-1,-1 -> r0 1100,0] +(1200,0;2201,1101) [c2 #-1,-1 -> r0 100,-100] +(-1201,0;-100,1001) [c3 #0,0 -> r90 0,0] +(-1191,20;-90,1021) [c3 #1,0 -> r90 10,20] +(-1190,21;-89,1022) [c3 #0,1 -> r90 11,21] +(-1180,41;-79,1042) [c3 #1,1 -> r90 21,41] +(-1179,42;-78,1043) [c3 #0,2 -> r90 22,42] +(-1169,62;-68,1063) [c3 #1,2 -> r90 32,62] +END + + end + +end + +load("test_epilogue.rb") diff --git a/testdata/ruby/dbRecursiveShapeIterator.rb b/testdata/ruby/dbRecursiveShapeIterator.rb new file mode 100644 index 000000000..cbec7ee84 --- /dev/null +++ b/testdata/ruby/dbRecursiveShapeIterator.rb @@ -0,0 +1,279 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2021 Matthias Koefferlein +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class DBRecursiveShapeIterator_TestClass < TestBase + + def collect(s, l) + + res = [] + while !s.at_end? + r = "[#{l.cell_name(s.cell_index)}]" + if s.shape.is_box? + box = s.shape.box + r += box.transformed(s.trans).to_s + else + r += "X"; + end + s.next + res.push(r) + end + + return res.join("/") + + end + + def dcollect(s, l) + + res = [] + while !s.at_end? + r = "[#{l.cell_name(s.cell_index)}]" + if s.shape.is_box? + box = s.shape.dbox + r += box.transformed(s.dtrans).to_s + else + r += "X"; + end + s.next + res.push(r) + end + + return res.join("/") + + end + + def test_1 + + # Recursive shape iterator tests + + 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) + + bb = RBA::Box.new(1, 101, 1001, 1201) + c3.shapes(1).insert(bb) + + 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)))) + + i1 = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(0, 0, 100, 100)) + i1copy = i1.dup + assert_equal(i1copy.overlapping?, false) + assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") + i1.reset + assert_equal(dcollect(i1, l), "[c0](0,0.1;1,1.2)/[c1](0,0.1;1,1.2)/[c2](0.1,0;1.1,1.1)") + assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") + + i1 = l.begin_shapes_touching(c0.cell_index, 0, RBA::DBox.new(0, 0, 0.100, 0.100)) + assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") + + i1 = c0.begin_shapes_rec_touching(0, RBA::Box.new(0, 0, 100, 100)) + assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") + + i1 = c0.begin_shapes_rec_touching(0, RBA::DBox.new(0, 0, 0.100, 0.100)) + assert_equal(collect(i1, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)") + + i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(0, 0, 100, 100)); + assert_equal(collect(i1o, l), ""); + i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::DBox.new(0, 0, 0.100, 0.100)); + assert_equal(collect(i1o, l), ""); + i1copy.overlapping = true + assert_equal(i1copy.overlapping?, true) + assert_equal(collect(i1copy, l), ""); + i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(0, 0, 100, 101)); + assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); + i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::DBox.new(0, 0, 0.100, 0.101)); + assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); + i1copy.region = RBA::Box.new(0, 0, 100, 101) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); + i1copy.region = RBA::Region::new(RBA::Box.new(0, 0, 100, 101)) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); + i1copy.region = RBA::Box.new(-1000, -1000, 1100, 1101) + i1copy.confine_region(RBA::Box.new(0, 0, 100, 101)) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); + i1copy.region = RBA::Box.new(-1000, -1000, 1100, 1101) + i1copy.confine_region(RBA::Region::new(RBA::Box.new(0, 0, 100, 101))) + assert_equal(i1copy.region.to_s, "(0,0;100,101)") + assert_equal(collect(i1copy, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)"); + i1o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(0, 0, 101, 101)); + assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)"); + i1o = c0.begin_shapes_rec_overlapping(0, RBA::Box.new(0, 0, 101, 101)); + assert_equal(collect(i1o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)"); + + i2 = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(-100, 0, 100, 100)); + assert_equal(collect(i2, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](-1200,0;-100,1000)"); + i2o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(-100, 0, 100, 100)); + assert_equal(collect(i2o, l), ""); + i2o = l.begin_shapes_overlapping(c0.cell_index, 0, RBA::Box.new(-101, 0, 101, 101)); + assert_equal(collect(i2o, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](-1200,0;-100,1000)"); + + i4 = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(-100, 0, 2000, 100)); + i4_copy = l.begin_shapes_touching(c0.cell_index, 0, RBA::Box.new(-100, 0, 2000, 100)); + i4.max_depth = 0; + assert_equal(collect(i4, l), "[c0](0,100;1000,1200)"); + + assert_equal(i4 == i4, true); + assert_equal(i4 != i4, false); + assert_equal(i4 == i4_copy, false); + assert_equal(i4 != i4_copy, true); + i4 = i4_copy.dup; + assert_equal(i4 == i4_copy, true); + assert_equal(i4 != i4_copy, false); + i4.max_depth = 1; + assert_equal(collect(i4, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](-1200,0;-100,1000)"); + + i4.assign(i4_copy); + assert_equal(collect(i4, 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)"); + + i5 = l.begin_shapes(c0.cell_index, 0); + assert_equal(collect(i5, 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 = RBA::RecursiveShapeIterator::new + assert_equal(collect(ii, l), "") + + ii = RBA::RecursiveShapeIterator::new(l, c1, 0) + assert_equal(collect(ii, l), "[c1](0,100;1000,1200)") + assert_equal(ii.top_cell.name, "c1") + assert_equal(ii.layout == l, true) + + ii.max_depth = 2 + assert_equal(ii.max_depth, 2) + ii.min_depth = 1 + assert_equal(ii.min_depth, 1) + + ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1]) + ic = ii.dup + assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") + assert_equal(collect(ic, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") + + ii = RBA::RecursiveShapeIterator::new(l, c2, 0, RBA::Box.new(-100, 0, 2000, 100), false) + assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") + + ii = RBA::RecursiveShapeIterator::new(l, c2, 0, RBA::Box.new(-100, 0, 2000, 100), true) + assert_equal(collect(ii, l), "") + + ii = RBA::RecursiveShapeIterator::new(l, c2, 0, RBA::Box.new(-100, 0, 2000, 101), true) + assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") + + ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 100), false) + assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") + + ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), false) + assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") + + ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), true) + assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") + + ii = RBA::RecursiveShapeIterator::new(l, c0, 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.reset + ii.unselect_cells("c0") + ii.select_cells("c2") + assert_equal(collect(ii, l), "[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)") + + ii.reset_selection + ii.unselect_cells("c*") + ii.select_cells([ c2.cell_index ]) + assert_equal(collect(ii, l), "[c2](100,0;1100,1100)") + + ii.reset_selection + ii.unselect_all_cells + ii.select_cells("c2") + assert_equal(collect(ii, l), "[c2](100,0;1100,1100)") + + ii.reset_selection + ii.select_all_cells + ii.unselect_cells("c2") + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + + ii.reset_selection + ii.select_cells("c*") + ii.unselect_cells([ c1.cell_index, c2.cell_index ]) + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)") + + end + + def test_2 + + # Recursive shape iterator tests + + 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) + c3.shapes(0).insert(b) + + bb = RBA::Box.new(1, 101, 1001, 1201) + c3.shapes(1).insert(bb) + + 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), RBA::Vector::new(10, 20), RBA::Vector::new(11, 21), 2, 3)) + c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) + + res = [] + i = l.begin_shapes(c0.cell_index, 0) + while !i.at_end? + res << i.shape.box.transformed(i.trans).to_s + " " + i.path.collect { |e| "[" + l.cell(e.cell_inst.cell_index).name + " #" + e.ia.to_s + "," + e.ib.to_s + " -> " + e.specific_trans.to_s + "]" }.join("") + i.next + end + + assert_equal(res.join("\n") + "\n", <<"END") +(1200,0;2200,1100) [c2 #-1,-1 -> r0 100,-100][c3 #-1,-1 -> r0 1100,0] +(-1200,0;-100,1000) [c3 #0,0 -> r90 0,0] +(-1190,20;-90,1020) [c3 #1,0 -> r90 10,20] +(-1189,21;-89,1021) [c3 #0,1 -> r90 11,21] +(-1179,41;-79,1041) [c3 #1,1 -> r90 21,41] +(-1178,42;-78,1042) [c3 #0,2 -> r90 22,42] +(-1168,62;-68,1062) [c3 #1,2 -> r90 32,62] +END + + end + +end + +load("test_epilogue.rb") diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index b5d273646..27cd9b257 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -1049,6 +1049,27 @@ class DBRegion_TestClass < TestBase end + # Some filters + def test_holesfilter + + r = RBA::Region::new + r.insert(RBA::Box::new(RBA::Point::new(0, 0), RBA::Point::new(100, 200))) + rr = RBA::Region::new + rr.insert(RBA::Box::new(RBA::Point::new(10, 10), RBA::Point::new(20, 20))) + rr.insert(RBA::Box::new(RBA::Point::new(30, 30), RBA::Point::new(40, 40))) + r -= rr + + assert_equal(r.with_holes(0, false).to_s, "") + assert_equal(r.with_holes(0, true).to_s, "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)") + assert_equal(rr.with_holes(0, false).to_s, "(10,10;10,20;20,20;20,10);(30,30;30,40;40,40;40,30)") + assert_equal(rr.with_holes(0, true).to_s, "") + assert_equal(rr.with_holes(2, false).to_s, "") + assert_equal(r.with_holes(1, 3, false).to_s, "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)") + assert_equal(r.with_holes(2, 3, false).to_s, "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)") + assert_equal(r.with_holes(1, 2, false).to_s, "") + + end + end load("test_epilogue.rb")