From b97413234adb91ad34219aa95080eb2b272b3042 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 7 Feb 2021 19:14:20 +0100 Subject: [PATCH 01/53] trying to provide a log along with progress --- src/lay/lay/layProgressWidget.cc | 7 ++++++- src/lay/lay/layProgressWidget.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lay/lay/layProgressWidget.cc b/src/lay/lay/layProgressWidget.cc index 703c5ed41..60c61830c 100644 --- a/src/lay/lay/layProgressWidget.cc +++ b/src/lay/lay/layProgressWidget.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -136,7 +137,7 @@ ProgressBarWidget::resizeEvent (QResizeEvent *) ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width) : QFrame (parent), - mp_widget (0), mp_pr (pr) + mp_widget (0), mp_pr (pr), m_log_file (6, true) { QVBoxLayout *top_layout = new QVBoxLayout (this); top_layout->addStretch (1); @@ -144,6 +145,10 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full QFrame *bar_frame = new QFrame (this); top_layout->addWidget (bar_frame); + QListView *log_list = new QListView (this); + log_list->setModel (&m_log_file); + top_layout->addWidget (log_list); + top_layout->addStretch (1); // this does not allow the label to control the overall size, so a long string does not hurt: diff --git a/src/lay/lay/layProgressWidget.h b/src/lay/lay/layProgressWidget.h index 4e712be4f..c47ea9a8d 100644 --- a/src/lay/lay/layProgressWidget.h +++ b/src/lay/lay/layProgressWidget.h @@ -31,6 +31,7 @@ #include #include "layProgress.h" +#include "layLogViewerDialog.h" class QToolButton; class QLabel; @@ -73,6 +74,7 @@ private: QGridLayout *mp_layout; QToolButton *mp_cancel_button; ProgressReporter *mp_pr; + lay::LogFile m_log_file; }; } From 620776fe5158d31fc3993c48eba8a677295b68ec Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 7 Feb 2021 19:15:47 +0100 Subject: [PATCH 02/53] Provide better log output for region --- src/db/db/dbAsIfFlatRegion.cc | 14 ++++++++++++++ src/db/db/dbDeepRegion.cc | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) 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) { From 94e6f0f7a6d84475f318fd6f651b8b3b00f25f5c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 7 Feb 2021 23:41:53 +0100 Subject: [PATCH 03/53] Logging progress for DRC, introducing 'abstract progress' concept --- src/buddies/src/bd/bdInit.cc | 26 +--- src/drc/drc/built-in-macros/_drc_engine.rb | 16 +- .../drc/built-in-macros/drc_interpreters.lym | 5 + src/gsi/gsi/gsiDeclTl.cc | 40 ++--- src/lay/lay/layLogViewerDialog.cc | 22 +++ src/lay/lay/layLogViewerDialog.h | 12 ++ src/lay/lay/layProgress.cc | 66 +++++---- src/lay/lay/layProgress.h | 7 - src/lay/lay/layProgressWidget.cc | 91 ++++++++++-- src/lay/lay/layProgressWidget.h | 10 ++ src/lay/lay/laySaltDownloadManager.cc | 2 - src/lay/lay/layTextProgress.cc | 4 + src/lym/lym/lymMacro.cc | 3 + src/tl/tl/tlProgress.cc | 81 +++++++++- src/tl/tl/tlProgress.h | 140 ++++++++++++++++-- src/tl/tl/tlThreadedWorkers.cc | 12 -- 16 files changed, 418 insertions(+), 119 deletions(-) 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/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_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/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/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/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 60c61830c..3c4cfe670 100644 --- a/src/lay/lay/layProgressWidget.cc +++ b/src/lay/lay/layProgressWidget.cc @@ -60,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); @@ -135,20 +135,49 @@ 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), m_log_file (6, true) + 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); - QListView *log_list = new QListView (this); - log_list->setModel (&m_log_file); - top_layout->addWidget (log_list); - top_layout->addStretch (1); // this does not allow the label to control the overall size, so a long string does not hurt: @@ -162,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); @@ -176,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); @@ -196,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 * @@ -238,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 c47ea9a8d..0600f7e5d 100644 --- a/src/lay/lay/layProgressWidget.h +++ b/src/lay/lay/layProgressWidget.h @@ -37,6 +37,8 @@ class QToolButton; class QLabel; class QToolButton; class QGridLayout; +class QListView; +class QFrame; namespace tl { @@ -60,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; @@ -75,6 +79,12 @@ private: 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/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/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/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/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 .. From a9fa5d73f9dd7d25bc7006da0d6f98cc2e5e2d34 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 8 Feb 2021 20:59:17 +0100 Subject: [PATCH 04/53] Introducing 'with_holes' and 'without_holes' in DRC and RBA::Region. --- src/db/db/dbRegionUtils.cc | 28 +++++++++++ src/db/db/dbRegionUtils.h | 45 ++++++++++++++++++ src/db/db/gsiDeclDbRegion.cc | 36 ++++++++++++++ src/db/unit_tests/dbRegionTests.cc | 21 +++++++++ src/drc/drc/built-in-macros/_drc_layer.rb | 57 ++++++++++++++++++++++- src/drc/unit_tests/drcSimpleTests.cc | 11 +++++ testdata/ruby/dbRegionTest.rb | 21 +++++++++ 7 files changed, 218 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index a1eacf9f7..0d2ed0de1 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 diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 28ce19f67..89392bd0d 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 * diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index a52ca5717..91ee1dfec 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 " 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/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/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/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") From 1c8eca50bf874f4c739a73a6266880d1aa5b84d9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 8 Feb 2021 20:59:48 +0100 Subject: [PATCH 05/53] Added test case files. --- testdata/drc/drcSimpleTests_29.drc | 25 +++++++++++++++++++++++++ testdata/drc/drcSimpleTests_29.gds | Bin 0 -> 554 bytes testdata/drc/drcSimpleTests_au29.gds | Bin 0 -> 2170 bytes testdata/drc/drcSimpleTests_au29d.gds | Bin 0 -> 2170 bytes 4 files changed, 25 insertions(+) create mode 100644 testdata/drc/drcSimpleTests_29.drc create mode 100644 testdata/drc/drcSimpleTests_29.gds create mode 100644 testdata/drc/drcSimpleTests_au29.gds create mode 100644 testdata/drc/drcSimpleTests_au29d.gds 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 0000000000000000000000000000000000000000..25e1867e1ccb9a41d3ed44fdf504766abdceca6b GIT binary patch literal 554 zcmaLTKQ9D99LDkQ&F#%@h|QfWiE||viOW$CK|+Yazo--t^NP?fH9k zXRz?}czR5y@lVhDtBXrWGVo)L8a{VGuUUum2&UJD_IuF22Geqxv?BeP2W{L#aOxH| z^<~p?8SRf0>VH76InXTQrIyQT-&N-y&7u1W!TED&bxSRm(f-`KIxi5M{LH)c7&magX#8MkOdkaZn zEk1%TU@Ja?_m~`Z5k}A=#a7>PXU@*OXATSkIJbvt%H`hS5Tb-8%JFZ6F4*2!1xo4c z(#lnH>*e8deyuxmf49GjYW5dh5L}#{1DOyAMjTQI@(w_~kOp!)z{En2jXF@d1Vq)1 znW9HOd20(d09oz;%l2ncb)#25R5JY=Ko+{z%V_UNBT$KNctdOolSB3@Q)u P@B2Of%X^Tsr#FKybIAbH literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au29d.gds b/testdata/drc/drcSimpleTests_au29d.gds new file mode 100644 index 0000000000000000000000000000000000000000..3c2e167c2b7178b0e7da8070ab477a0182b69ddd GIT binary patch literal 2170 zcmds&y-EW?6opSF$!1Xui9{hWr3Aqc8zrcqC>H)c7&magX#8MkOdkaZn zEk1%TU@Ja?_m~`Z5k}A=#a7>PXU@*OXATSkIJbvt%H`hS5Tb-8%JFZ6F4*2!1xo4c z(#lnH>*e8deyuxmf49GjYW5dh5L}#{1DOyAMjTQI@(w_~kOp!)z{En2jXF@d1Vq)1 znW9HOd20(d09oz;%l2ncb)#25R5JY=Ko+{z%V_UNBT$KNctdOolSB3@Q)u P@B2Of%X^Tsr#FKybIAbH literal 0 HcmV?d00001 From b3685c67225eb89caae28d8a5b469b7be72ceb52 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 8 Feb 2021 21:29:41 +0100 Subject: [PATCH 06/53] Implemented with_holes for generic DRC too --- src/db/db/gsiDeclDbCompoundOperation.cc | 11 ++++++ .../drc/built-in-macros/_drc_complex_ops.rb | 32 +++++++++++++++--- .../built-in-macros/_drc_cop_integration.rb | 13 +++++++ src/drc/unit_tests/drcGenericTests.cc | 10 ++++++ testdata/drc/drcGenericTests_18.drc | 25 ++++++++++++++ testdata/drc/drcGenericTests_18.gds | Bin 0 -> 554 bytes testdata/drc/drcGenericTests_au18.gds | Bin 0 -> 1962 bytes testdata/drc/drcGenericTests_au18d.gds | Bin 0 -> 1962 bytes 8 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 testdata/drc/drcGenericTests_18.drc create mode 100644 testdata/drc/drcGenericTests_18.gds create mode 100644 testdata/drc/drcGenericTests_au18.gds create mode 100644 testdata/drc/drcGenericTests_au18d.gds diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index 90ad2447b..05ff115a0 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -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"); @@ -672,6 +678,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/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index 1c8419bbe..db5607c5b 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% @@ -1003,6 +1004,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 +1571,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 +1592,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/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/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 0000000000000000000000000000000000000000..25e1867e1ccb9a41d3ed44fdf504766abdceca6b GIT binary patch literal 554 zcmaLTKQ9D99LDkQ&F#%@h|QfWiE||viOW$CK|+Yazo--t^NP?fH9k zXRz?}czR5y@lVhDtBXrWGVo)L8a{VGuUUum2&UJD_IuF22Geqxv?BeP2W{L#aOxH| z^<~p?8SRf0>VH76InXTQrIyQT-&N-y&7u1W!TED&bxSRm(f-`KIxi5M{LB$5awDJ2Mo*eIfcqFDHcm4!%3jX#YRK7$}wh^01m_7;-D zT6_dwz*c+&&zKCm2v^V|MXE2Hy|d?>xkDBKoZCe$<-&J3L@1+*T=F*}7i_Js0Ht(x zarts~^X1`lZnZOYf48@TTJ{%R5S*W$0htI0h8g zrs&a+-`ay4fE>F5mh8=<>PD}AsAT##fGl)umXVmM8Q4YU*#?UBn5rAS z`iWQ5JObqChwZ)*Q+1?Ngw2ke4;<}MLy}AeAjzPZ=9zg=E|e4YW-gQy=AY+CB$5awDJ2Mo*eIfcqFDHcm4!%3jX#YRK7$}wh^01m_7;-D zT6_dwz*c+&&zKCm2v^V|MXE2Hy|d?>xkDBKoZCe$<-&J3L@1+*T=F*}7i_Js0Ht(x zarts~^X1`lZnZOYf48@TTJ{%R5S*W$0htI0h8g zrs&a+-`ay4fE>F5mh8=<>PD}AsAT##fGl)umXVmM8Q4YU*#?UBn5rAS z`iWQ5JObqChwZ)*Q+1?Ngw2ke4;<}MLy}AeAjzPZ=9zg=E|e4YW-gQy=AY+C Date: Wed, 10 Feb 2021 00:17:01 +0100 Subject: [PATCH 07/53] Enhancements to cell name search feature. Needs more debugging. --- src/ant/ant/antPropertiesPage.cc | 8 +- src/edt/edt/edtEditorOptionsPages.cc | 30 +-- src/edt/edt/edtInstPropertiesPage.cc | 24 +- src/edt/edt/edtPCellParametersPage.cc | 4 +- src/edt/edt/edtPropertiesPages.cc | 32 +-- src/img/img/imgPropertiesPage.cc | 22 +- src/laybasic/laybasic/layCellTreeModel.cc | 208 +++++++++++++++++- src/laybasic/laybasic/layCellTreeModel.h | 42 +++- .../laybasic/layEditorOptionsPages.cc | 2 +- .../laybasic/layHierarchyControlPanel.cc | 23 +- .../laybasic/layHierarchyControlPanel.h | 1 + src/laybasic/laybasic/layQtTools.cc | 16 +- src/laybasic/laybasic/layQtTools.h | 5 + .../lay_plugin/layLEFDEFImportDialogs.cc | 12 +- 14 files changed, 341 insertions(+), 88 deletions(-) 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/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/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/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/laybasic/laybasic/layCellTreeModel.cc b/src/laybasic/laybasic/layCellTreeModel.cc index da4507d0a..9dc6ff0c7 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,7 @@ 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; mp_layout = & view->cellview (cv_index)->layout (); mp_library = 0; @@ -295,6 +339,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 +361,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; @@ -475,6 +521,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) { @@ -754,7 +809,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,6 +874,8 @@ 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_visible_cell_set.empty ()) { + return int (item->children_in (m_visible_cell_set)); } else { return int (item->children ()); } @@ -839,6 +896,8 @@ 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_visible_cell_set.empty ()) { + return createIndex (row, column, item->child_in (m_visible_cell_set, row)); } else { return createIndex (row, column, item->child (row)); } @@ -862,9 +921,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_visible_cell_set.empty ()) { + 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 +964,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_visible_cell_set.empty ()) { + 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,12 +1039,58 @@ void CellTreeModel::clear_locate () { m_selected_indexes.clear (); + m_visible_cell_set.clear (); m_current_index = m_selected_indexes.begin (); m_selected_indexes_set.clear (); signal_data_changed (); } +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 CellTreeModel::locate_next () { @@ -1005,19 +1127,41 @@ 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; + if (c->name_matches (pattern)) { m_selected_indexes.push_back (model_index (c)); + visible = true; } - search_children (pattern, c); + if (search_children (pattern, c)) { + visible = true; + } + + if (visible) { + c->set_tree_index (ti++); + m_visible_cell_set.insert (c); + any = true; + } else { + c->set_tree_index (std::numeric_limits::max ()); + } + } + } + + return any; } QModelIndex @@ -1027,27 +1171,67 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, return QModelIndex (); } + QModelIndexList indexes = persistentIndexList (); + m_selected_indexes.clear (); + m_visible_cell_set.clear (); 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; + if ((*lc)->name_matches (p)) { m_selected_indexes.push_back (model_index (*lc)); + visible = true; } - if (! top_only) { - search_children (p, *lc); + if (! top_only && search_children (p, *lc)) { + visible = true; } + + if (visible) { + (*lc)->set_tree_index (ti++); + m_visible_cell_set.insert (*lc); + } else { + (*lc)->set_tree_index (std::numeric_limits::max ()); + } + } m_selected_indexes_set.clear (); - m_selected_indexes_set.insert (m_selected_indexes.begin (), m_selected_indexes.end ()); - + 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 (QModelIndexList::iterator i = indexes.begin (); i != indexes.end (); ++i) { + CellTreeItem *item = (CellTreeItem *) i->internalPointer (); + 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); + + } + signal_data_changed (); + // make the first selected one current + m_current_index = m_selected_indexes.begin (); if (m_current_index == m_selected_indexes.end ()) { return QModelIndex (); diff --git a/src/laybasic/laybasic/layCellTreeModel.h b/src/laybasic/laybasic/layCellTreeModel.h index b55477140..1c667f6c2 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,6 +225,19 @@ 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 * @@ -238,7 +256,7 @@ public: } private: - bool m_flat, m_pad; + bool m_flat, m_pad, m_filter_mode; unsigned int m_flags; Sorting m_sorting; QWidget *mp_parent; @@ -248,13 +266,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 +290,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 +321,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/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..37727e855 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" @@ -264,11 +265,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); @@ -426,6 +434,10 @@ HierarchyControlPanel::search_triggered (const QString &t) void HierarchyControlPanel::search_edited () { + bool filter_invalid = false; + + mp_search_model->set_filter_mode (mp_filter->isChecked ()); + QString t = mp_search_edit_box->text (); for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { @@ -438,11 +450,15 @@ HierarchyControlPanel::search_edited () (*v)->setCurrentIndex (found); if (found.isValid ()) { (*v)->scrollTo (found); + } else { + filter_invalid = true; } } break; } } + + lay::indicate_error (mp_search_edit_box, filter_invalid); } void @@ -450,7 +466,7 @@ 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 (); + QModelIndex found = mp_search_model->locate_next ((*v)->currentIndex ()); if (found.isValid ()) { (*v)->setCurrentIndex (found); (*v)->scrollTo (found); @@ -786,6 +802,9 @@ void HierarchyControlPanel::do_update_content (int cv_index) { // close the search box since we will modify the model + if (mp_search_model) { + mp_search_model->clear_locate (); + } mp_search_frame->hide (); mp_search_model = 0; @@ -1199,7 +1218,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..31def9efe 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.h +++ b/src/laybasic/laybasic/layHierarchyControlPanel.h @@ -298,6 +298,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..bc7a1e537 100644 --- a/src/laybasic/laybasic/layQtTools.cc +++ b/src/laybasic/laybasic/layQtTools.cc @@ -162,19 +162,29 @@ 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); } diff --git a/src/laybasic/laybasic/layQtTools.h b/src/laybasic/laybasic/layQtTools.h index fa216cfc8..fc11d89ee 100644 --- a/src/laybasic/laybasic/layQtTools.h +++ b/src/laybasic/laybasic/layQtTools.h @@ -76,6 +76,11 @@ 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); + } // namespace lay #endif diff --git a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc index 4c64e034f..d4c12aed8 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc +++ b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc @@ -400,7 +400,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 +414,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 +428,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 +441,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 +454,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 +467,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; From 423dddae62040917ebbd0eb7f5264da7b7d4b0f2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 12 Feb 2021 00:44:31 +0100 Subject: [PATCH 08/53] Bug fixes on cell name search feature. --- src/laybasic/laybasic/layCellTreeModel.cc | 55 ++++++++++++++----- src/laybasic/laybasic/layCellTreeModel.h | 4 -- .../laybasic/layHierarchyControlPanel.cc | 11 ++++ .../laybasic/layHierarchyControlPanel.h | 1 + 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/laybasic/laybasic/layCellTreeModel.cc b/src/laybasic/laybasic/layCellTreeModel.cc index 9dc6ff0c7..503328a42 100644 --- a/src/laybasic/laybasic/layCellTreeModel.cc +++ b/src/laybasic/laybasic/layCellTreeModel.cc @@ -450,6 +450,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. @@ -511,9 +513,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) { @@ -541,6 +543,7 @@ CellTreeModel::set_sorting (Sorting s) void CellTreeModel::signal_data_changed () { + emit layoutAboutToBeChanged (); emit layoutChanged (); } @@ -1043,7 +1046,22 @@ CellTreeModel::clear_locate () 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 @@ -1141,20 +1159,21 @@ CellTreeModel::search_children (const tl::GlobPattern &pattern, CellTreeItem *it 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; } if (search_children (pattern, c)) { + c->set_tree_index (ti); visible = true; } if (visible) { - c->set_tree_index (ti++); + ++ti; m_visible_cell_set.insert (c); any = true; - } else { - c->set_tree_index (std::numeric_limits::max ()); } } @@ -1171,7 +1190,15 @@ 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 (); @@ -1187,19 +1214,20 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, 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)) { + (*lc)->set_tree_index (ti); visible = true; } if (visible) { - (*lc)->set_tree_index (ti++); + ++ti; m_visible_cell_set.insert (*lc); - } else { - (*lc)->set_tree_index (std::numeric_limits::max ()); } } @@ -1215,10 +1243,9 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, QModelIndexList new_indexes; - for (QModelIndexList::iterator i = indexes.begin (); i != indexes.end (); ++i) { - CellTreeItem *item = (CellTreeItem *) i->internalPointer (); - if (m_visible_cell_set.find (item) != m_visible_cell_set.end ()) { - new_indexes.push_back (model_index (item)); + 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 ()); } @@ -1228,7 +1255,7 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, } - signal_data_changed (); + emit layoutChanged (); // make the first selected one current diff --git a/src/laybasic/laybasic/layCellTreeModel.h b/src/laybasic/laybasic/layCellTreeModel.h index 1c667f6c2..65abc1f73 100644 --- a/src/laybasic/laybasic/layCellTreeModel.h +++ b/src/laybasic/laybasic/layCellTreeModel.h @@ -240,10 +240,6 @@ public: /** * @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 (); diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc index 37727e855..30c6f62b2 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.cc +++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc @@ -79,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) diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.h b/src/laybasic/laybasic/layHierarchyControlPanel.h index 31def9efe..58d2a8688 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 &); From c64dad0b3abef9ceda903729d1562f52ca7f4f13 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 12 Feb 2021 01:20:38 +0100 Subject: [PATCH 09/53] Bugfix, crash on switching to flat cell list --- .../laybasic/layHierarchyControlPanel.cc | 85 +++++++++---------- .../laybasic/layHierarchyControlPanel.h | 2 +- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc index 30c6f62b2..5fe8ea03c 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.cc +++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc @@ -254,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); @@ -420,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); @@ -447,26 +447,27 @@ HierarchyControlPanel::search_edited () { bool filter_invalid = false; - mp_search_model->set_filter_mode (mp_filter->isChecked ()); - 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); - } else { - filter_invalid = true; - } + filter_invalid = true; } - break; } + } lay::indicate_error (mp_search_edit_box, filter_invalid); @@ -474,15 +475,13 @@ HierarchyControlPanel::search_edited () 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 ((*v)->currentIndex ()); - 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); } } } @@ -490,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); } } } @@ -517,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 @@ -813,11 +807,12 @@ void HierarchyControlPanel::do_update_content (int cv_index) { // close the search box since we will modify the model - if (mp_search_model) { - mp_search_model->clear_locate (); + 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); diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.h b/src/laybasic/laybasic/layHierarchyControlPanel.h index 58d2a8688..1c539a40f 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.h +++ b/src/laybasic/laybasic/layHierarchyControlPanel.h @@ -300,7 +300,7 @@ private: QAction *mp_case_sensitive; QAction *mp_use_regular_expressions; QAction *mp_filter; - CellTreeModel *mp_search_model; + int m_search_index; QFrame *mp_search_frame; QCheckBox *mp_search_close_cb; QSplitter *mp_splitter; From 71f64f5f63d5d441bf2c2cf2d6dedb8c7e3f4cfa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 12 Feb 2021 23:46:57 +0100 Subject: [PATCH 10/53] Bugfixed search function for cells. --- src/laybasic/laybasic/layCellTreeModel.cc | 39 +++++++++++++++++++---- src/laybasic/laybasic/layCellTreeModel.h | 3 +- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/laybasic/laybasic/layCellTreeModel.cc b/src/laybasic/laybasic/layCellTreeModel.cc index 503328a42..e6ad4b2cc 100644 --- a/src/laybasic/laybasic/layCellTreeModel.cc +++ b/src/laybasic/laybasic/layCellTreeModel.cc @@ -318,6 +318,7 @@ 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; @@ -877,13 +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_visible_cell_set.empty ()) { + } 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 ()); + } } } @@ -899,13 +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_visible_cell_set.empty ()) { + } 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 (); } @@ -927,7 +950,7 @@ CellTreeModel::parent (const QModelIndex &index) const CellTreeItem *pitem = item->parent (); if (pitem) { - if (m_filter_mode && ! m_visible_cell_set.empty ()) { + if (m_filter_mode && m_is_filtered) { if (pitem->tree_index () == std::numeric_limits::max ()) { // WARNING: invisible item! return QModelIndex (); @@ -967,7 +990,7 @@ 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_visible_cell_set.empty ()) { + } else if (m_filter_mode && m_is_filtered) { if (item->tree_index () == std::numeric_limits::max ()) { // WARNING: invisible item! return QModelIndex (); @@ -1043,6 +1066,7 @@ 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 (); @@ -1202,6 +1226,7 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, 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); @@ -1220,7 +1245,7 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, 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; } diff --git a/src/laybasic/laybasic/layCellTreeModel.h b/src/laybasic/laybasic/layCellTreeModel.h index 65abc1f73..59d9a8934 100644 --- a/src/laybasic/laybasic/layCellTreeModel.h +++ b/src/laybasic/laybasic/layCellTreeModel.h @@ -252,7 +252,8 @@ public: } private: - bool m_flat, m_pad, m_filter_mode; + bool m_flat, m_pad; + bool m_filter_mode, m_is_filtered; unsigned int m_flags; Sorting m_sorting; QWidget *mp_parent; From 0f8dc9ac13e46b80a9d91ce984b161e91a1c6a97 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 13 Feb 2021 09:51:28 +0100 Subject: [PATCH 11/53] Improvements on layer list search and filtering --- src/laybasic/laybasic/layLayerControlPanel.cc | 163 ++++++++---------- src/laybasic/laybasic/layLayerControlPanel.h | 17 +- src/laybasic/laybasic/layLayerTreeModel.cc | 57 +++++- src/laybasic/laybasic/layLayerTreeModel.h | 73 ++++++-- 4 files changed, 189 insertions(+), 121 deletions(-) diff --git a/src/laybasic/laybasic/layLayerControlPanel.cc b/src/laybasic/laybasic/layLayerControlPanel.cc index 9cfeb1ec5..0316d6711 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_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_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags), 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,28 @@ LayerControlPanel::set_text_color (QColor c) mp_model->set_text_color (c); } -void +void +LayerControlPanel::update_hidden_flags () +{ + m_do_update_hidden_flags_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 @@ -1707,7 +1724,6 @@ LayerControlPanel::cancel_updates () void LayerControlPanel::end_updates () { - m_force_update_hidden_flags = true; do_update_content (); } @@ -1721,7 +1737,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 +1746,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 +1754,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) { @@ -1853,48 +1859,21 @@ LayerControlPanel::do_update_content () m_needs_update = false; + } else if (m_needs_update) { + + 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; + } + } + mp_layer_list->setRootIsDecorated (has_children); + mp_layer_list->reset (); + } else { - - if (m_needs_update) { - - 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; - } - } - 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) { - - 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); - } - - // 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); - } - } - } - + mp_model->signal_data_changed (); // this makes the view redraw the data } } @@ -1975,7 +1954,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 +2007,7 @@ LayerControlPanel::update_required (int f) } if ((f & 3) != 0) { - m_force_update_hidden_flags = true; + m_do_update_hidden_flags_dm (); } m_do_update_content_dm (); diff --git a/src/laybasic/laybasic/layLayerControlPanel.h b/src/laybasic/laybasic/layLayerControlPanel.h index 95f0acf34..8d235c877 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,17 @@ private: lay::LayoutView *mp_view; bool m_needs_update; bool m_tabs_need_update; - bool m_force_update_hidden_flags; 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; + tl::DeferredMethod m_do_update_content_dm, m_do_update_hidden_flags_dm; 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 +367,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..c5c6f2b99 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 (); @@ -481,6 +520,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..10404160c 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; } /** @@ -220,11 +237,19 @@ public: */ void signal_layer_changed (); +signals: + /** + * @brief This signal is emitted to indicate + */ + 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 +257,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); }; From 92d36868bb8a9f82f3e89a419076563a6c23771c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 13 Feb 2021 19:13:22 +0100 Subject: [PATCH 12/53] Enhancements to search and replace in macro editor. --- src/lay/lay/MacroEditorDialog.ui | 76 +--- src/lay/lay/layMacroEditorDialog.cc | 121 +++++-- src/lay/lay/layMacroEditorDialog.h | 5 + src/lay/lay/layMacroEditorPage.cc | 532 ++++++++++++++++------------ src/lay/lay/layMacroEditorPage.h | 10 +- 5 files changed, 412 insertions(+), 332 deletions(-) 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/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index c2b3377e4..7573154e0 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -355,8 +355,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 +364,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 +386,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 +413,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 +439,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 +954,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 +1111,6 @@ MacroEditorDialog::can_exit () return true; } -void -MacroEditorDialog::search_replace () -{ - searchEditBox->setFocus (Qt::TabFocusReason); -} - void MacroEditorDialog::add_edit_trace (bool compress) { @@ -1882,6 +1882,18 @@ BEGIN_PROTECTED END_PROTECTED } +void +MacroEditorDialog::set_editor_focus () +{ + MacroEditorPage *page = dynamic_cast (tabWidget->currentWidget ()); + if (! page) { + return; + } + + QSignalBlocker signal_blocker (searchEditBox); + page->set_editor_focus (); +} + void MacroEditorDialog::replace_mode_button_clicked () { @@ -1905,10 +1917,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 +1947,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 +1962,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 +2000,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 +2021,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 +2034,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 +2151,7 @@ BEGIN_PROTECTED END_PROTECTED } -void +void MacroEditorDialog::help_requested(const QString &s) { lay::MainWindow::instance ()->show_assistant_topic (tl::to_string (s)); @@ -3172,7 +3243,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 +3340,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..fd60dbb0b 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 (); diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index ad6d38f84..03c41abdc 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -475,7 +475,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); @@ -600,7 +600,12 @@ static bool valid_element (const SyntaxHighlighterElement &e) void MacroEditorPage::cursor_position_changed () { + if (m_ignore_cursor_changed_event) { + return; + } + QTextCursor cursor = mp_text->textCursor (); + m_edit_cursor = cursor; // prepare a format for the bracket highlights QTextCharFormat fmt; @@ -861,11 +866,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 +908,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 +932,10 @@ MacroEditorPage::find_next () { update_extra_selections (); + if (m_current_search == QRegExp ()) { + return false; + } + QTextCursor c = mp_text->textCursor (); bool first = true; @@ -926,7 +949,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,225 +1177,289 @@ 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; +} + bool MacroEditorPage::eventFilter (QObject *watched, QEvent *event) { if (watched == mp_text) { - if (event->type () == QEvent::KeyPress) { + if (event->type () == QEvent::ShortcutOverride) { + + // override shortcuts + event->accept (); + 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 ()) { + if (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) { - QTextBlock bs, be; - bool adjust_end = false; + return tab_key_pressed (); - 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; - } - } - } + } else if ((ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) { - if (indent) { + return back_tab_key_pressed (); - // tab out - QTextCursor c (mp_text->document ()); - c.setPosition (bs.position ()); - c.beginEditBlock (); + } else if (ke->key () == Qt::Key_Backspace) { - for (QTextBlock b = bs; ; b = b.next()) { + return backspace_pressed (); - c.setPosition (b.position ()); - QString text = b.text (); + } else if (ke->key () == Qt::Key_Escape) { - 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; - } - } + // Handle Esc to return to the before-find position and clear the selection - 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 + find_reset (); QTextCursor c = mp_text->textCursor (); c.clearSelection (); @@ -1378,37 +1467,11 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return true; - } else if (ke && ke->key () == Qt::Key_Return) { + } else if (ke->key () == Qt::Key_Return) { - if (!mp_text->isReadOnly ()) { + return return_pressed (); - // 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; - - } - - } else if (ke && ke->key () == Qt::Key_F1) { + } else if (ke->key () == Qt::Key_F1) { QTextCursor c = mp_text->textCursor (); if (c.selectionStart () == c.selectionEnd ()) { @@ -1418,7 +1481,14 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return true; - } else if (ke && ke->key () == Qt::Key_F3) { + } else if (ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0) { + + QTextCursor c = mp_text->textCursor (); + emit search_requested (c.selectedText ()); + + return true; + + } else if (ke->key () == Qt::Key_F3) { // 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..8eee34048 100644 --- a/src/lay/lay/layMacroEditorPage.h +++ b/src/lay/lay/layMacroEditorPage.h @@ -254,8 +254,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 +268,7 @@ public: signals: void help_requested (const QString &s); + void search_requested (const QString &s); void edit_trace (bool); public slots: @@ -294,8 +295,15 @@ private: int m_ntab, m_nindent; std::set m_breakpoints; QRegExp m_current_search; + QTextCursor m_edit_cursor; + bool m_ignore_cursor_changed_event; void update_extra_selections (); + bool return_pressed (); + bool backspace_pressed (); + bool back_tab_key_pressed (); + bool tab_key_pressed (); + bool eventFilter (QObject *watched, QEvent *event); }; From 16f6174ad93a318400767b94ac89419089958e90 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 14 Feb 2021 21:07:36 +0100 Subject: [PATCH 13/53] 'apply as filter' for search feature in libraries view too --- src/laybasic/laybasic/layLibrariesView.cc | 8 ++++++++ src/laybasic/laybasic/layLibrariesView.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index ce2d9534f..322ce3ba6 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -262,11 +262,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 +389,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; From effa8027cc63a05aa18dc02858888c14f3530895 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 14 Feb 2021 23:12:50 +0100 Subject: [PATCH 14/53] Implemented completer for macro editor. --- src/lay/lay/layMacroEditorPage.cc | 153 ++++++++++++++++++++++++++++-- src/lay/lay/layMacroEditorPage.h | 10 ++ 2 files changed, 155 insertions(+), 8 deletions(-) diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index 03c41abdc..0eb04be59 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -42,6 +42,10 @@ #include #include #include +#include +#include +#include +#include namespace lay { @@ -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 | Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput); + 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 () @@ -598,12 +617,107 @@ 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 s = c.selectedText ().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) { + 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; @@ -1433,6 +1547,11 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) event->accept (); return true; + } else if (event->type () == QEvent::FocusOut) { + + hide_completer (); + return true; + } else if (event->type () == QEvent::KeyPress) { m_error_line = -1; @@ -1445,7 +1564,12 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) if (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) { - return tab_key_pressed (); + if (mp_completer_popup->isVisible ()) { + complete (); + return true; + } else { + return tab_key_pressed (); + } } else if ((ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) { @@ -1457,19 +1581,27 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) } else if (ke->key () == Qt::Key_Escape) { - // Handle Esc to return to the before-find position and clear the selection + // Handle Esc to return to the before-find position and clear the selection or to hide popup - find_reset (); - - QTextCursor c = mp_text->textCursor (); - c.clearSelection (); - mp_text->setTextCursor (c); + 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 (ke->key () == Qt::Key_Return) { - return return_pressed (); + if (mp_completer_popup->isVisible ()) { + complete (); + return true; + } else { + return return_pressed (); + } } else if (ke->key () == Qt::Key_F1) { @@ -1481,6 +1613,11 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return true; + } else if (mp_completer_popup->isVisible () && (ke->key () == Qt::Key_Up || ke->key () == Qt::Key_Down)) { + + QApplication::sendEvent (mp_completer_list, event); + return true; + } else if (ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0) { QTextCursor c = mp_text->textCursor (); diff --git a/src/lay/lay/layMacroEditorPage.h b/src/lay/lay/layMacroEditorPage.h index 8eee34048..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 { @@ -281,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; @@ -297,12 +302,17 @@ private: 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); }; From 412056afed763b5f23f6716ace6350384a6d2c00 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Feb 2021 00:40:05 +0100 Subject: [PATCH 15/53] Recursive instance iterator, first draft. --- src/db/db/db.pro | 2 + src/db/db/dbRecursiveInstanceIterator.cc | 714 ++++++++++ src/db/db/dbRecursiveInstanceIterator.h | 660 +++++++++ .../dbRecursiveInstanceIteratorTests.cc | 1252 +++++++++++++++++ .../dbRecursiveShapeIteratorTests.cc | 15 + src/db/unit_tests/unit_tests.pro | 1 + 6 files changed, 2644 insertions(+) create mode 100644 src/db/db/dbRecursiveInstanceIterator.cc create mode 100644 src/db/db/dbRecursiveInstanceIterator.h create mode 100644 src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 16f9df099..1903f4e3d 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 \ @@ -269,6 +270,7 @@ HEADERS = \ dbPolygonGenerators.h \ dbPropertiesRepository.h \ dbReader.h \ + dbRecursiveInstanceIterator.h \ dbRecursiveShapeIterator.h \ dbRegion.h \ dbRegionLocalOperations.h \ diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc new file mode 100644 index 000000000..b6b56745d --- /dev/null +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -0,0 +1,714 @@ + +/* + + 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_max_depth = d.m_max_depth; + m_min_depth = d.m_min_depth; + m_shape_flags = d.m_shape_flags; + m_shape_inv_prop_sel = d.m_shape_inv_prop_sel; + 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_shape_inv_prop_sel = false; + m_needs_reinit = false; + m_inst_quad_id = 0; +} + +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_shape_inv_prop_sel = false; + m_inst_quad_id = 0; + mp_cell = 0; +} + +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; +} + +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) { + 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; + + } +} + +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; + new_inst (receiver); + next_instance (receiver); + } +} + +void +RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) const +{ + while (true) { + + if (! m_inst.at_end ()) { + + if (int (m_inst_iterators.size ()) < m_max_depth) { + down (receiver); + } + + } else { + + if (! m_inst_iterators.empty ()) { + // no more instances: up and next instance + up (receiver); + } else { + break; + } + + if (! m_inst.at_end () && int (m_inst_iterators.size () + 1) >= m_min_depth && ! is_inactive ()) { + break; + } + + } + + if (! m_inst.at_end ()) { + if (int (m_inst_iterators.size () + 1) < m_min_depth || is_inactive ()) { + ++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); + } + +// @@@ drop? + // skip instance quad if possible + if (! m_local_complex_region_stack.empty ()) { + skip_inst_iter_for_complex_region (); + } +// @@@ + + 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..9d94d84d1 --- /dev/null +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -0,0 +1,660 @@ + +/* + + 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 top-down and breadth-first. + * + * While the iterator delivers instances, it will first deliver the instances of cells + * and then the instances of cells inside cells whose instances have been delivered already. + * No differentiation is made for leaf or non-leaf cells. + */ +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::ICplxTrans cplx_trans_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 shapes from the initial cell. + * The depth must be specified before the shapes 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 shapes from the top level. + * 1 instructs to deliver shapes from the first child level. + * The minimum depth must be specified before the shapes 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 shapes are selected when a region is used + */ + bool overlapping () const + { + return m_overlapping; + } + + /** + * @brief Sets a flag indicating whether overlapping shapes 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 Select cells + * + * 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. + */ + void select_all_cells (); + + /** + * @brief Unselect cells + * + * This method will remove the given cells (plus their sub-hierarchy) from the selection. + */ + 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. + */ + 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. + */ + 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_type instance () const + { + return *operator-> (); + } + + /** + * @brief Access operator + * + * The access operator is identical to the instance method. + */ + instance_type operator* () const + { + return *operator-> (); + } + + /** + * @brief Access (arrow) operator + * + * The access operator is identical to the instance method. + */ + const instance_type *operator-> () const + { + validate (0); + return m_inst.operator-> (); + } + + /** + * @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; + unsigned int m_shape_flags; + bool m_shape_inv_prop_sel; + bool m_overlapping; + std::set m_start, m_stop; + + 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 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; + + 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); + 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/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc new file mode 100644 index 000000000..95bdb8028 --- /dev/null +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -0,0 +1,1252 @@ + +/* + + 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->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(1); + 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, 100, 100)); + i1_11.min_depth(1); + i1_11.max_depth(1); + 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, 100, 100)); + i1_12.min_depth(1); + i1_12.max_depth(2); + x = collect(i1_12, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + x = collect_with_copy(i1_12, g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + + db::RecursiveInstanceIterator i1_22 (g, c0, db::Box (0, 0, 100, 100)); + i1_22.min_depth(2); + i1_22.max_depth(2); + x = collect(i1_22, g); + EXPECT_EQ (x, ""); + x = collect_with_copy(i1_22, g); + EXPECT_EQ (x, ""); + + 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::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"); + +} + +#if 0 +TEST(1a) +{ + db::Manager m (true); + db::Layout g (&m); + g.insert_layer (0); + g.insert_layer (1); + 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::Cell &c3 (g.cell (g.add_cell ())); + + db::Box b (0, 100, 1000, 1200); + c1.shapes (0).insert (b); + c2.shapes (0).insert (b); + c3.shapes (0).insert (b); + + db::Box bb (1, 101, 1001, 1201); + c2.shapes (1).insert (bb); + + 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 i0 (g, c0, 0, db::Box ()); + x = collect_with_copy(i0, g); + EXPECT_EQ (x, ""); + x = collect(i0, g); + EXPECT_EQ (x, ""); + + db::RecursiveInstanceIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100)); + x = collect_with_copy(i1, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); + x = collect(i1, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); + + db::RecursiveInstanceIterator i1o (g, c0, 0, db::Box (0, 0, 100, 100), true); + x = collect_with_copy(i1o, g); + EXPECT_EQ (x, ""); + x = collect(i1o, g); + EXPECT_EQ (x, ""); + i1o = db::RecursiveInstanceIterator (g, c0, 0, db::Box (0, 0, 100, 101), true); + x = collect_with_copy(i1o, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)"); + x = collect(i1o, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)"); + i1o = db::RecursiveInstanceIterator (g, c0, 0, db::Box (0, 0, 101, 101), true); + x = collect_with_copy(i1o, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); + x = collect(i1o, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); + + db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (-100, 0, 100, 100)); + x = collect_with_copy(i2, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + x = collect(i2, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + db::RecursiveInstanceIterator i2o (g, c0, 0, db::Box (-100, 0, 100, 100), true); + x = collect_with_copy(i2o, g); + EXPECT_EQ (x, ""); + x = collect(i2o, g); + EXPECT_EQ (x, ""); + i2o = db::RecursiveInstanceIterator (g, c0, 0, db::Box (-101, 0, 101, 101), true); + x = collect_with_copy(i2o, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + x = collect(i2o, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + + db::RecursiveInstanceIterator i4 (g, c0, 0, db::Box (-100, 0, 2000, 100)); + db::RecursiveInstanceIterator i4_copy (g, c0, 0, db::Box (-100, 0, 2000, 100)); + i4.max_depth (0); + x = collect_with_copy(i4, g); + EXPECT_EQ (x, ""); + x = collect(i4, g); + EXPECT_EQ (x, ""); + + 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_with_copy(i4, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + x = collect(i4, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + + i4 = i4_copy; + x = collect_with_copy(i4, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + x = collect(i4, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + + db::RecursiveInstanceIterator i5 (g, c0, 0, db::Box::world ()); + x = collect_with_copy(i5, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + x = collect(i5, g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + + i5.set_layer (1); + x = collect_with_copy(i5, g); + EXPECT_EQ (x, "[$3](101,1;1101,1101)"); + x = collect(i5, g); + EXPECT_EQ (x, "[$3](101,1;1101,1101)"); + + std::set ll; + + db::RecursiveInstanceIterator i5a (g, c0, ll, db::Box::world ()); + x = collect_with_copy(i5a, g, true); + EXPECT_EQ (x, ""); + x = collect(i5a, g, true); + EXPECT_EQ (x, ""); + + ll.insert (0); + db::RecursiveInstanceIterator i5b (g, c0, ll, db::Box::world ()); + x = collect_with_copy(i5b, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + x = collect(i5b, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + + ll.insert (1); + db::RecursiveInstanceIterator i5c (g, c0, ll, db::Box::world ()); + db::RecursiveInstanceIterator i5cc = i5c; + x = collect_with_copy(i5c, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + x = collect(i5c, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + x = collect_with_copy(i5cc, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + x = collect(i5cc, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + + std::vector ll_new; + ll_new.push_back (0); + i5c.set_layers (ll_new); + x = collect_with_copy(i5c, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); + x = collect(i5c, g, true); + EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); +} + +TEST(1b) +{ + 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 b; + b = db::Box (0, 0, 2000, 2000000); + c1.shapes (0).insert (b); + b = db::Box (1998000, 0, 2000000, 2000000); + c1.shapes (0).insert (b); + b = db::Box (0, 0, 2000000, 2000); + c1.shapes (0).insert (b); + b = db::Box (0, 1998000, 2000000, 2000000); + c1.shapes (0).insert (b); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + + db::RecursiveInstanceIterator i (g, c0, 0, db::Box (1000000, 1000000, 10001000, 10001000)); + std::string x; + x = collect_with_copy(i, g); + EXPECT_EQ (x, "[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)/[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)"); + x = collect(i, g); + EXPECT_EQ (x, "[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)/[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)"); + + db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (1000000, 1000000, 1001000, 1001000)); + x = collect_with_copy(i2, g); + EXPECT_EQ (x, ""); + x = collect(i2, g); + EXPECT_EQ (x, ""); +} + +TEST(2) +{ + 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 b (1000, -500, 2000, 500); + c2.shapes (0).insert (b); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); + c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); + + std::string x; + + db::RecursiveInstanceIterator i0 (g, c0, 0, db::Box ()); + x = collect(i0, g); + EXPECT_EQ (x, ""); + + db::RecursiveInstanceIterator i (g, c0, 0, db::Box::world ()); + x = collect_with_copy(i, g); + EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); + x = collect(i, g); + EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); + + db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (3400, 3450, 5600, 6500)); + x = collect_with_copy(i2, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); + x = collect(i2, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); + + db::RecursiveInstanceIterator i3 (g, c0, 0, db::Box (6650, 5300, 10000, 7850)); + x = collect_with_copy(i3, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + x = collect(i3, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + + db::RecursiveInstanceIterator i2o (g, c0, 0, db::Box (3400, 3450, 5600, 6500), true); + x = collect_with_copy(i2o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + x = collect(i2o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + + db::RecursiveInstanceIterator i3o (g, c0, 0, db::Box (6650, 5300, 10000, 7850), true); + x = collect_with_copy(i3o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect(i3o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); +} + +TEST(3) +{ + 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 b (1000, -500, 2000, 500); + c2.shapes (0).insert (b); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); + c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); + + std::string x; + + db::RecursiveInstanceIterator i (g, c0, 0, db::Box::world ()); + x = collect_with_copy(i, g); + EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); + x = collect(i, g); + EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); + + db::RecursiveInstanceIterator i2 (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500))); + EXPECT_EQ (i2.has_complex_region (), false); + EXPECT_EQ (i2.region ().to_string (), "(3400,3450;5600,6500)"); + x = collect_with_copy(i2, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); + x = collect(i2, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); + + db::RecursiveInstanceIterator i3 (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850))); + x = collect_with_copy(i3, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + x = collect(i3, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + + db::Region rr; + rr.insert (db::Box (3400, 3450, 5600, 6500)); + rr.insert (db::Box (6650, 5300, 10000, 7850)); + + db::RecursiveInstanceIterator i23 (g, c0, 0, rr); + x = collect_with_copy(i23, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + x = collect(i23, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + + db::RecursiveInstanceIterator i2o (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500)), true); + x = collect_with_copy(i2o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + x = collect(i2o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + + db::RecursiveInstanceIterator i3o (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850)), true); + x = collect_with_copy(i3o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect(i3o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + db::Region rro; + rro.insert (db::Box (3400, 3450, 5600, 6500)); + rro.insert (db::Box (6650, 5300, 10000, 7850)); + + db::RecursiveInstanceIterator i23o (g, c0, 0, rro, true); + EXPECT_EQ (i23o.has_complex_region (), true); + EXPECT_EQ (i23o.complex_region ().to_string (), "(3400,3450;3400,6500;5600,6500;5600,3450);(6650,5300;6650,7850;10000,7850;10000,5300)"); + + db::RecursiveInstanceIterator i23ocopy = i23o; + + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + x = collect_with_copy (i23ocopy, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect (i23ocopy, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + // reset + i23o.reset (); + x = collect_with_copy (i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect (i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + // copy constructor + i23ocopy = i23o; + i23ocopy.reset (); + x = collect_with_copy (i23ocopy, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect (i23ocopy, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + // setting of region + + db::Region rg; + i23o.set_region (rg); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, ""); + x = collect(i23o, g); + EXPECT_EQ (x, ""); + + rg.insert (db::Box (3400, 3450, 5600, 6500)); + rg.insert (db::Box (16650, 5300, 20000, 7850)); + + i23o.set_region (rg); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + + i23o.set_region (db::Box (6650, 5300, 10000, 7850)); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + // region confinement + + i23o.confine_region (db::Box (3400, 3450, 5600, 6500)); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, ""); + x = collect(i23o, g); + EXPECT_EQ (x, ""); + + i23o.set_region (rro); + i23o.confine_region (db::Box (3400, 3450, 5600, 6500)); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + + i23o.set_region (db::Box (3400, 3450, 5600, 6500)); + i23o.confine_region (rro); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + + i23o.set_region (rro); + i23o.confine_region (rro); + x = collect_with_copy(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); +} + +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; +} + +class FlatPusher + : public db::RecursiveShapeReceiver +{ +public: + FlatPusher (std::set *boxes) : mp_boxes (boxes) { } + + void shape (const db::RecursiveInstanceIterator * /*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) +{ + // Big fun + + db::Manager m (true); + db::Layout g (&m); + g.insert_layer(0); + + db::Cell &c0 (g.cell (g.add_cell ())); + + std::set boxes; + + for (int i = 0; i < 100000; ++i) { + + int x = rand () % 10000; + int y = rand () % 10000; + db::Box box (x, y, x + 10, y + 10); + + boxes.insert (box); + + c0.shapes (0).insert (box); + + } + + db::Box search_box (2500, 2500, 7500, 7500); + + std::set selected_boxes; + std::set selected_boxes2; + + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, 0, search_box, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter->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, 0, 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, 0, reg, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter->bbox ()); + } + + 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, 0, 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(5) +{ + // 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, 0, search_box, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter.trans () * iter->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, 0, 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, 0, reg, true); !iter.at_end (); ++iter) { + selected_boxes.insert (iter.trans () * iter->bbox ()); + } + + 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, 0, 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); +} + +class LoggingReceiver + : public db::RecursiveShapeReceiver +{ +public: + LoggingReceiver () { } + + const std::string &text () const { return m_text; } + + virtual void begin (const db::RecursiveInstanceIterator * /*iter*/) { m_text += "begin\n"; } + virtual void end (const db::RecursiveInstanceIterator * /*iter*/) { m_text += "end\n"; } + + virtual void enter_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + { + m_text += std::string ("enter_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; + } + + virtual void leave_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell) + { + m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; + } + + virtual new_inst_mode new_inst (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) + { + m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ()); + if (all) { + m_text += ",all"; + } + m_text += ")\n"; + return NI_all; + } + + virtual bool new_inst_member (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) + { + m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans); + if (all) { + m_text += ",all"; + } + m_text += ")\n"; + return true; + } + + virtual void shape (const db::RecursiveInstanceIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + { + m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n"; + } + +private: + std::string m_text; +}; + +class ReceiverRejectingACellInstanceArray + : public LoggingReceiver +{ +public: + ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { } + + virtual new_inst_mode new_inst (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) + { + LoggingReceiver::new_inst (iter, inst, region, complex_region, all); + return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip; + } + +private: + db::cell_index_type m_rejected; +}; + +class ReceiverRejectingACellInstanceArrayExceptOne + : public LoggingReceiver +{ +public: + ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { } + + virtual new_inst_mode new_inst (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) + { + LoggingReceiver::new_inst (iter, inst, region, complex_region, all); + return inst.object ().cell_index () != m_rejected ? NI_all : NI_single; + } + +private: + db::cell_index_type m_rejected; +}; + +class ReceiverRejectingACellInstance + : public LoggingReceiver +{ +public: + ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { } + + virtual bool new_inst_member (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all) + { + LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all); + return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected; + } + +private: + db::cell_index_type m_rejected; + db::ICplxTrans m_trans_rejected; +}; + +// Push mode with cells +TEST(10) +{ + 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 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)); + c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); + + LoggingReceiver lr1; + db::RecursiveInstanceIterator i1 (g, c0, 0); + i1.push (&lr1); + + EXPECT_EQ (lr1.text (), + "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" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,6000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,8000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,0)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "end\n" + ); + + ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ()); + db::RecursiveInstanceIterator ir1 (g, c0, 0); + ir1.push (&rr1); + + EXPECT_EQ (rr1.text (), + "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" + "new_inst_member($2,r0 *1 0,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "leave_cell($2)\n" + "end\n" + ); + + ReceiverRejectingACellInstanceArrayExceptOne rs1 (c2.cell_index ()); + db::RecursiveInstanceIterator is1 (g, c0, 0); + is1.push (&rs1); + + EXPECT_EQ (rs1.text (), + "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" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,6000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,0)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "end\n" + ); + + ReceiverRejectingACellInstance rri1 (c2.cell_index (), db::ICplxTrans ()); + db::RecursiveInstanceIterator iri1 (g, c0, 0); + iri1.push (&rri1); + + EXPECT_EQ (rri1.text (), + "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 + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,8000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "end\n" + ); + + ReceiverRejectingACellInstanceArray rr2 (c1.cell_index ()); + db::RecursiveInstanceIterator ir2 (g, c0, 0); + ir2.push (&rr2); + + 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" + ); + + LoggingReceiver lr2; + db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (0, 0, 5000, 5000)); + i2.push (&lr2); + + EXPECT_EQ (lr2.text (), + "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" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 0,2000)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,1000)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" + "leave_cell($3)\n" + "new_inst_member($3,r0 *1 3000,3000)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "end\n" + ); +} +#endif diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index bfef1084f..cc61b571b 100644 --- a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc @@ -1023,6 +1023,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 +1038,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 +1131,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 +1159,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 +1203,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 +1282,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 +1295,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/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 \ From 6527d29f8fd859aeaba1034e29654df21e3a849e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Feb 2021 00:48:07 +0100 Subject: [PATCH 16/53] Recursive instance iterator, debugging. --- src/db/db/dbRecursiveInstanceIterator.cc | 4 ++-- .../dbRecursiveInstanceIteratorTests.cc | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc index b6b56745d..bb15bf9f4 100644 --- a/src/db/db/dbRecursiveInstanceIterator.cc +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -432,14 +432,14 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c break; } - if (! m_inst.at_end () && int (m_inst_iterators.size () + 1) >= m_min_depth && ! is_inactive ()) { + if (! m_inst.at_end () && int (m_inst_iterators.size ()) >= m_min_depth && ! is_inactive ()) { break; } } if (! m_inst.at_end ()) { - if (int (m_inst_iterators.size () + 1) < m_min_depth || is_inactive ()) { + if (int (m_inst_iterators.size ()) < m_min_depth || is_inactive ()) { ++m_inst; new_inst (receiver); } else { diff --git a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc index 95bdb8028..e075e4db2 100644 --- a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -104,31 +104,31 @@ TEST(1) 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(1); + 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, 100, 100)); - i1_11.min_depth(1); - i1_11.max_depth(1); + 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, 100, 100)); - i1_12.min_depth(1); - i1_12.max_depth(2); + 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/[$1]$3 r0 100,-100"); + 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/[$1]$3 r0 100,-100"); + 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, 100, 100)); - i1_22.min_depth(2); - i1_22.max_depth(2); + i1_22.min_depth(1); + i1_22.max_depth(1); x = collect(i1_22, g); EXPECT_EQ (x, ""); x = collect_with_copy(i1_22, g); From 0f47ff68a53006781c30a56f9dcef163034f81e8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Feb 2021 01:03:05 +0100 Subject: [PATCH 17/53] Recursive instance iterator, debugging. --- src/db/db/dbRecursiveInstanceIterator.cc | 53 ++++++++++++++++++------ src/db/db/dbRecursiveInstanceIterator.h | 34 +++++++++++++++ 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc index bb15bf9f4..a52274c5c 100644 --- a/src/db/db/dbRecursiveInstanceIterator.cc +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -40,6 +40,9 @@ RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const Recursive { 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_shape_flags = d.m_shape_flags; @@ -91,6 +94,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator () m_shape_inv_prop_sel = false; 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) @@ -138,6 +142,7 @@ RecursiveInstanceIterator::init () m_shape_inv_prop_sel = false; m_inst_quad_id = 0; mp_cell = 0; + m_all_targets = true; } void @@ -212,6 +217,26 @@ RecursiveInstanceIterator::confine_region (const region_type ®ion) m_needs_reinit = true; } +void +RecursiveInstanceIterator::all_targets () +{ + if (! m_all_targets) { + m_all_targets = true; + m_targets.clear (); + m_needs_reinit = true; + } +} + +void +RecursiveInstanceIterator::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 @@ -280,8 +305,15 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const } 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); + } } @@ -412,6 +444,12 @@ RecursiveInstanceIterator::next (RecursiveInstanceReceiver *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 { @@ -419,7 +457,7 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c if (! m_inst.at_end ()) { - if (int (m_inst_iterators.size ()) < m_max_depth) { + 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); } @@ -432,14 +470,10 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c break; } - if (! m_inst.at_end () && int (m_inst_iterators.size ()) >= m_min_depth && ! is_inactive ()) { - break; - } - } if (! m_inst.at_end ()) { - if (int (m_inst_iterators.size ()) < m_min_depth || is_inactive ()) { + if (! needs_visit ()) { ++m_inst; new_inst (receiver); } else { @@ -549,13 +583,6 @@ RecursiveInstanceIterator::new_cell (RecursiveInstanceReceiver *receiver) const set_inactive (new_cell_inactive); } -// @@@ drop? - // skip instance quad if possible - if (! m_local_complex_region_stack.empty ()) { - skip_inst_iter_for_complex_region (); - } -// @@@ - m_inst = cell ()->begin_touching (correct_box_overlapping (m_local_region_stack.back ())); m_inst_quad_id = 0; diff --git a/src/db/db/dbRecursiveInstanceIterator.h b/src/db/db/dbRecursiveInstanceIterator.h index 9d94d84d1..1a018e3c0 100644 --- a/src/db/db/dbRecursiveInstanceIterator.h +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -274,6 +274,36 @@ public: m_needs_reinit = true; } + /** + * @brief Gets the selected target cells + * + * Only cells from the targets section are reported if "select_all_targets" is false. + */ + const std::set &targets () const + { + return m_targets; + } + + /** + * @brief Gets a flags indicating whether all targets are selected + */ + bool all_targets () const + { + return m_all_targets; + } + + /** + * @brief Selects all target cells + */ + void all_targets (); + + /** + * @brief Selects the given targets + * + * This will reset the "all_targets" flag to false. + */ + void targets (const std::set &targets); + /** * @brief Select cells * @@ -493,6 +523,8 @@ private: bool m_shape_inv_prop_sel; 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; @@ -515,6 +547,7 @@ private: 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); @@ -522,6 +555,7 @@ private: 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; From ca11f0799ad970bb63a7414e58e37f331a014a06 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Feb 2021 01:09:17 +0100 Subject: [PATCH 18/53] Recursive instance iterator, selection of target cells. --- src/db/db/dbRecursiveInstanceIterator.h | 2 +- .../dbRecursiveInstanceIteratorTests.cc | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbRecursiveInstanceIterator.h b/src/db/db/dbRecursiveInstanceIterator.h index 1a018e3c0..fbf1afdfe 100644 --- a/src/db/db/dbRecursiveInstanceIterator.h +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -287,7 +287,7 @@ public: /** * @brief Gets a flags indicating whether all targets are selected */ - bool all_targets () const + bool has_all_targets () const { return m_all_targets; } diff --git a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc index e075e4db2..f49a382d5 100644 --- a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -251,6 +251,23 @@ TEST(1) 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.has_all_targets (), true); + std::set ct; + ct.insert (c3.cell_index ()); + i1z.targets (ct); + EXPECT_EQ (i1z.has_all_targets (), false); + EXPECT_EQ (i1z.targets () == ct, true); + i1z.all_targets (); + EXPECT_EQ (i1z.has_all_targets (), true); + + i1z.targets (ct); + EXPECT_EQ (i1z.has_all_targets (), 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"); } #if 0 From a1bae225e309dc0edb07056631736df8707b45fa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Feb 2021 17:50:32 +0100 Subject: [PATCH 19/53] Recursive instance iterator, tests --- src/db/db/dbRecursiveInstanceIterator.cc | 4 +- src/db/db/dbRecursiveInstanceIterator.h | 54 +- .../dbRecursiveInstanceIteratorTests.cc | 1092 ++++------------- 3 files changed, 260 insertions(+), 890 deletions(-) diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc index a52274c5c..4af46223b 100644 --- a/src/db/db/dbRecursiveInstanceIterator.cc +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -218,7 +218,7 @@ RecursiveInstanceIterator::confine_region (const region_type ®ion) } void -RecursiveInstanceIterator::all_targets () +RecursiveInstanceIterator::enable_all_targets () { if (! m_all_targets) { m_all_targets = true; @@ -228,7 +228,7 @@ RecursiveInstanceIterator::all_targets () } void -RecursiveInstanceIterator::targets (const std::set &tgt) +RecursiveInstanceIterator::set_targets (const std::set &tgt) { if (m_all_targets || m_targets != tgt) { m_targets = tgt; diff --git a/src/db/db/dbRecursiveInstanceIterator.h b/src/db/db/dbRecursiveInstanceIterator.h index fbf1afdfe..5ac6f6168 100644 --- a/src/db/db/dbRecursiveInstanceIterator.h +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -49,11 +49,7 @@ class RecursiveInstanceReceiver; * 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 top-down and breadth-first. - * - * While the iterator delivers instances, it will first deliver the instances of cells - * and then the instances of cells inside cells whose instances have been delivered already. - * No differentiation is made for leaf or non-leaf cells. + * The general iteration scheme is iterating is depth-first and child instances before parent instances. */ class DB_PUBLIC RecursiveInstanceIterator { @@ -134,8 +130,9 @@ public: /** * @brief Specify the maximum hierarchy depth to look into * - * A depth of 0 instructs the iterator to deliver only shapes from the initial cell. - * The depth must be specified before the shapes are being retrieved. + * 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) { @@ -156,9 +153,9 @@ public: /** * @brief Specify the minimum hierarchy depth to look into * - * A depth of 0 instructs the iterator to deliver shapes from the top level. - * 1 instructs to deliver shapes from the first child level. - * The minimum depth must be specified before the shapes are being retrieved. + * 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) { @@ -248,7 +245,7 @@ public: void confine_region (const region_type ®ion); /** - * @brief Gets a flag indicating whether overlapping shapes are selected when a region is used + * @brief Gets a flag indicating whether overlapping instances are selected when a region is used */ bool overlapping () const { @@ -256,7 +253,7 @@ public: } /** - * @brief Sets a flag indicating whether overlapping shapes are selected when a region is used + * @brief Sets a flag indicating whether overlapping instances are selected when a region is used */ void set_overlapping (bool f) { @@ -277,7 +274,13 @@ public: /** * @brief Gets the selected target cells * - * Only cells from the targets section are reported if "select_all_targets" is false. + * 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 { @@ -286,27 +289,38 @@ public: /** * @brief Gets a flags indicating whether all targets are selected + * See \targets for more details. */ - bool has_all_targets () const + bool all_targets_enabled () const { return m_all_targets; } /** * @brief Selects all target cells + * See \targets for more details. */ - void all_targets (); + void enable_all_targets (); /** * @brief Selects the given targets * * This will reset the "all_targets" flag to false. + * See \targets for more details. */ - void targets (const std::set &targets); + 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. @@ -318,6 +332,8 @@ public: * * 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 (); @@ -325,6 +341,8 @@ public: * @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); @@ -333,6 +351,8 @@ public: * * 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 (); @@ -342,6 +362,8 @@ public: * 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 (); diff --git a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc index f49a382d5..35eb4496d 100644 --- a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -171,6 +171,25 @@ TEST(1) 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); @@ -252,17 +271,17 @@ TEST(1) 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.has_all_targets (), true); + EXPECT_EQ (i1z.all_targets_enabled (), true); std::set ct; ct.insert (c3.cell_index ()); - i1z.targets (ct); - EXPECT_EQ (i1z.has_all_targets (), false); + i1z.set_targets (ct); + EXPECT_EQ (i1z.all_targets_enabled (), false); EXPECT_EQ (i1z.targets () == ct, true); - i1z.all_targets (); - EXPECT_EQ (i1z.has_all_targets (), true); + i1z.enable_all_targets (); + EXPECT_EQ (i1z.all_targets_enabled (), true); - i1z.targets (ct); - EXPECT_EQ (i1z.has_all_targets (), false); + 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"); @@ -270,393 +289,6 @@ TEST(1) EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$4 r90 0,0"); } -#if 0 -TEST(1a) -{ - db::Manager m (true); - db::Layout g (&m); - g.insert_layer (0); - g.insert_layer (1); - 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::Cell &c3 (g.cell (g.add_cell ())); - - db::Box b (0, 100, 1000, 1200); - c1.shapes (0).insert (b); - c2.shapes (0).insert (b); - c3.shapes (0).insert (b); - - db::Box bb (1, 101, 1001, 1201); - c2.shapes (1).insert (bb); - - 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 i0 (g, c0, 0, db::Box ()); - x = collect_with_copy(i0, g); - EXPECT_EQ (x, ""); - x = collect(i0, g); - EXPECT_EQ (x, ""); - - db::RecursiveInstanceIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100)); - x = collect_with_copy(i1, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); - x = collect(i1, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); - - db::RecursiveInstanceIterator i1o (g, c0, 0, db::Box (0, 0, 100, 100), true); - x = collect_with_copy(i1o, g); - EXPECT_EQ (x, ""); - x = collect(i1o, g); - EXPECT_EQ (x, ""); - i1o = db::RecursiveInstanceIterator (g, c0, 0, db::Box (0, 0, 100, 101), true); - x = collect_with_copy(i1o, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)"); - x = collect(i1o, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)"); - i1o = db::RecursiveInstanceIterator (g, c0, 0, db::Box (0, 0, 101, 101), true); - x = collect_with_copy(i1o, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); - x = collect(i1o, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); - - db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (-100, 0, 100, 100)); - x = collect_with_copy(i2, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); - x = collect(i2, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); - db::RecursiveInstanceIterator i2o (g, c0, 0, db::Box (-100, 0, 100, 100), true); - x = collect_with_copy(i2o, g); - EXPECT_EQ (x, ""); - x = collect(i2o, g); - EXPECT_EQ (x, ""); - i2o = db::RecursiveInstanceIterator (g, c0, 0, db::Box (-101, 0, 101, 101), true); - x = collect_with_copy(i2o, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); - x = collect(i2o, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); - - db::RecursiveInstanceIterator i4 (g, c0, 0, db::Box (-100, 0, 2000, 100)); - db::RecursiveInstanceIterator i4_copy (g, c0, 0, db::Box (-100, 0, 2000, 100)); - i4.max_depth (0); - x = collect_with_copy(i4, g); - EXPECT_EQ (x, ""); - x = collect(i4, g); - EXPECT_EQ (x, ""); - - 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_with_copy(i4, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); - x = collect(i4, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); - - i4 = i4_copy; - x = collect_with_copy(i4, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); - x = collect(i4, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); - - db::RecursiveInstanceIterator i5 (g, c0, 0, db::Box::world ()); - x = collect_with_copy(i5, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); - x = collect(i5, g); - EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); - - i5.set_layer (1); - x = collect_with_copy(i5, g); - EXPECT_EQ (x, "[$3](101,1;1101,1101)"); - x = collect(i5, g); - EXPECT_EQ (x, "[$3](101,1;1101,1101)"); - - std::set ll; - - db::RecursiveInstanceIterator i5a (g, c0, ll, db::Box::world ()); - x = collect_with_copy(i5a, g, true); - EXPECT_EQ (x, ""); - x = collect(i5a, g, true); - EXPECT_EQ (x, ""); - - ll.insert (0); - db::RecursiveInstanceIterator i5b (g, c0, ll, db::Box::world ()); - x = collect_with_copy(i5b, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - x = collect(i5b, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - - ll.insert (1); - db::RecursiveInstanceIterator i5c (g, c0, ll, db::Box::world ()); - db::RecursiveInstanceIterator i5cc = i5c; - x = collect_with_copy(i5c, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - x = collect(i5c, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - x = collect_with_copy(i5cc, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - x = collect(i5cc, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$3](101,1;1101,1101)*1/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - - std::vector ll_new; - ll_new.push_back (0); - i5c.set_layers (ll_new); - x = collect_with_copy(i5c, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); - x = collect(i5c, g, true); - EXPECT_EQ (x, "[$2](0,100;1000,1200)*0/[$3](100,0;1100,1100)*0/[$4](1200,0;2200,1100)*0/[$4](-1200,0;-100,1000)*0"); -} - -TEST(1b) -{ - 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 b; - b = db::Box (0, 0, 2000, 2000000); - c1.shapes (0).insert (b); - b = db::Box (1998000, 0, 2000000, 2000000); - c1.shapes (0).insert (b); - b = db::Box (0, 0, 2000000, 2000); - c1.shapes (0).insert (b); - b = db::Box (0, 1998000, 2000000, 2000000); - c1.shapes (0).insert (b); - - db::Trans tt; - c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); - c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); - - db::RecursiveInstanceIterator i (g, c0, 0, db::Box (1000000, 1000000, 10001000, 10001000)); - std::string x; - x = collect_with_copy(i, g); - EXPECT_EQ (x, "[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)/[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)"); - x = collect(i, g); - EXPECT_EQ (x, "[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)/[$2](1998000,0;2000000,2000000)/[$2](0,1998000;2000000,2000000)"); - - db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (1000000, 1000000, 1001000, 1001000)); - x = collect_with_copy(i2, g); - EXPECT_EQ (x, ""); - x = collect(i2, g); - EXPECT_EQ (x, ""); -} - -TEST(2) -{ - 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 b (1000, -500, 2000, 500); - c2.shapes (0).insert (b); - - db::Trans tt; - c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); - c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); - - std::string x; - - db::RecursiveInstanceIterator i0 (g, c0, 0, db::Box ()); - x = collect(i0, g); - EXPECT_EQ (x, ""); - - db::RecursiveInstanceIterator i (g, c0, 0, db::Box::world ()); - x = collect_with_copy(i, g); - EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); - x = collect(i, g); - EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); - - db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (3400, 3450, 5600, 6500)); - x = collect_with_copy(i2, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); - x = collect(i2, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); - - db::RecursiveInstanceIterator i3 (g, c0, 0, db::Box (6650, 5300, 10000, 7850)); - x = collect_with_copy(i3, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); - x = collect(i3, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); - - db::RecursiveInstanceIterator i2o (g, c0, 0, db::Box (3400, 3450, 5600, 6500), true); - x = collect_with_copy(i2o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - x = collect(i2o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - - db::RecursiveInstanceIterator i3o (g, c0, 0, db::Box (6650, 5300, 10000, 7850), true); - x = collect_with_copy(i3o, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect(i3o, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); -} - -TEST(3) -{ - 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 b (1000, -500, 2000, 500); - c2.shapes (0).insert (b); - - db::Trans tt; - c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); - c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); - - std::string x; - - db::RecursiveInstanceIterator i (g, c0, 0, db::Box::world ()); - x = collect_with_copy(i, g); - EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); - x = collect(i, g); - EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); - - db::RecursiveInstanceIterator i2 (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500))); - EXPECT_EQ (i2.has_complex_region (), false); - EXPECT_EQ (i2.region ().to_string (), "(3400,3450;5600,6500)"); - x = collect_with_copy(i2, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); - x = collect(i2, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); - - db::RecursiveInstanceIterator i3 (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850))); - x = collect_with_copy(i3, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); - x = collect(i3, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); - - db::Region rr; - rr.insert (db::Box (3400, 3450, 5600, 6500)); - rr.insert (db::Box (6650, 5300, 10000, 7850)); - - db::RecursiveInstanceIterator i23 (g, c0, 0, rr); - x = collect_with_copy(i23, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); - x = collect(i23, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); - - db::RecursiveInstanceIterator i2o (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500)), true); - x = collect_with_copy(i2o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - x = collect(i2o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - - db::RecursiveInstanceIterator i3o (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850)), true); - x = collect_with_copy(i3o, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect(i3o, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - - db::Region rro; - rro.insert (db::Box (3400, 3450, 5600, 6500)); - rro.insert (db::Box (6650, 5300, 10000, 7850)); - - db::RecursiveInstanceIterator i23o (g, c0, 0, rro, true); - EXPECT_EQ (i23o.has_complex_region (), true); - EXPECT_EQ (i23o.complex_region ().to_string (), "(3400,3450;3400,6500;5600,6500;5600,3450);(6650,5300;6650,7850;10000,7850;10000,5300)"); - - db::RecursiveInstanceIterator i23ocopy = i23o; - - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - - x = collect_with_copy (i23ocopy, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect (i23ocopy, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - - // reset - i23o.reset (); - x = collect_with_copy (i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect (i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - - // copy constructor - i23ocopy = i23o; - i23ocopy.reset (); - x = collect_with_copy (i23ocopy, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect (i23ocopy, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - - // setting of region - - db::Region rg; - i23o.set_region (rg); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, ""); - x = collect(i23o, g); - EXPECT_EQ (x, ""); - - rg.insert (db::Box (3400, 3450, 5600, 6500)); - rg.insert (db::Box (16650, 5300, 20000, 7850)); - - i23o.set_region (rg); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - x = collect(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - - i23o.set_region (db::Box (6650, 5300, 10000, 7850)); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect(i23o, g); - EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - - // region confinement - - i23o.confine_region (db::Box (3400, 3450, 5600, 6500)); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, ""); - x = collect(i23o, g); - EXPECT_EQ (x, ""); - - i23o.set_region (rro); - i23o.confine_region (db::Box (3400, 3450, 5600, 6500)); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - x = collect(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - - i23o.set_region (db::Box (3400, 3450, 5600, 6500)); - i23o.confine_region (rro); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - x = collect(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); - - i23o.set_region (rro); - i23o.confine_region (rro); - x = collect_with_copy(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); - x = collect(i23o, g); - EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); -} - static db::Layout boxes2layout (const std::set &boxes) { db::Layout l; @@ -671,106 +303,21 @@ static db::Layout boxes2layout (const std::set &boxes) } class FlatPusher - : public db::RecursiveShapeReceiver + : public db::RecursiveInstanceReceiver { public: FlatPusher (std::set *boxes) : mp_boxes (boxes) { } - void shape (const db::RecursiveInstanceIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + void enter_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { - mp_boxes->insert (trans * shape.bbox ()); + mp_boxes->insert (iter->trans () * cell->bbox ()); } private: std::set *mp_boxes; }; -TEST(4) -{ - // Big fun - - db::Manager m (true); - db::Layout g (&m); - g.insert_layer(0); - - db::Cell &c0 (g.cell (g.add_cell ())); - - std::set boxes; - - for (int i = 0; i < 100000; ++i) { - - int x = rand () % 10000; - int y = rand () % 10000; - db::Box box (x, y, x + 10, y + 10); - - boxes.insert (box); - - c0.shapes (0).insert (box); - - } - - db::Box search_box (2500, 2500, 7500, 7500); - - std::set selected_boxes; - std::set selected_boxes2; - - for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, 0, search_box, true); !iter.at_end (); ++iter) { - selected_boxes.insert (iter->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, 0, 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, 0, reg, true); !iter.at_end (); ++iter) { - selected_boxes.insert (iter->bbox ()); - } - - 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, 0, 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(5) +TEST(2) { // Big fun with cells @@ -802,7 +349,7 @@ TEST(5) std::set selected_boxes; std::set selected_boxes2; - for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, 0, search_box, true); !iter.at_end (); ++iter) { + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box, true); !iter.at_end (); ++iter) { selected_boxes.insert (iter.trans () * iter->bbox ()); } @@ -819,7 +366,7 @@ TEST(5) { selected_boxes.clear (); FlatPusher pusher (&selected_boxes); - db::RecursiveInstanceIterator (g, c0, 0, search_box, true).push (&pusher); + db::RecursiveInstanceIterator (g, c0, search_box, true).push (&pusher); } EXPECT_EQ (selected_boxes.size () > 100, true); @@ -834,7 +381,7 @@ TEST(5) reg.insert (search_box); reg.insert (search_box2); - for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, 0, reg, true); !iter.at_end (); ++iter) { + for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg, true); !iter.at_end (); ++iter) { selected_boxes.insert (iter.trans () * iter->bbox ()); } @@ -851,115 +398,17 @@ TEST(5) { selected_boxes.clear (); FlatPusher pusher (&selected_boxes); - db::RecursiveInstanceIterator (g, c0, 0, reg, true).push (&pusher); + 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); } -class LoggingReceiver - : public db::RecursiveShapeReceiver +TEST(3) { -public: - LoggingReceiver () { } + // Big fun with cells - 2 hierarchy levels - const std::string &text () const { return m_text; } - - virtual void begin (const db::RecursiveInstanceIterator * /*iter*/) { m_text += "begin\n"; } - virtual void end (const db::RecursiveInstanceIterator * /*iter*/) { m_text += "end\n"; } - - virtual void enter_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) - { - m_text += std::string ("enter_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; - } - - virtual void leave_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell) - { - m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; - } - - virtual new_inst_mode new_inst (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) - { - m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ()); - if (all) { - m_text += ",all"; - } - m_text += ")\n"; - return NI_all; - } - - virtual bool new_inst_member (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) - { - m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans); - if (all) { - m_text += ",all"; - } - m_text += ")\n"; - return true; - } - - virtual void shape (const db::RecursiveInstanceIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) - { - m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n"; - } - -private: - std::string m_text; -}; - -class ReceiverRejectingACellInstanceArray - : public LoggingReceiver -{ -public: - ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { } - - virtual new_inst_mode new_inst (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) - { - LoggingReceiver::new_inst (iter, inst, region, complex_region, all); - return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip; - } - -private: - db::cell_index_type m_rejected; -}; - -class ReceiverRejectingACellInstanceArrayExceptOne - : public LoggingReceiver -{ -public: - ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { } - - virtual new_inst_mode new_inst (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) - { - LoggingReceiver::new_inst (iter, inst, region, complex_region, all); - return inst.object ().cell_index () != m_rejected ? NI_all : NI_single; - } - -private: - db::cell_index_type m_rejected; -}; - -class ReceiverRejectingACellInstance - : public LoggingReceiver -{ -public: - ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { } - - virtual bool new_inst_member (const db::RecursiveInstanceIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all) - { - LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all); - return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected; - } - -private: - db::cell_index_type m_rejected; - db::ICplxTrans m_trans_rejected; -}; - -// Push mode with cells -TEST(10) -{ db::Manager m (true); db::Layout g (&m); g.insert_layer(0); @@ -968,302 +417,201 @@ TEST(10) db::Cell &c1 (g.cell (g.add_cell ())); db::Cell &c2 (g.cell (g.add_cell ())); - 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::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)))); - db::Trans tt; - c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); - c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); + std::set boxes; - LoggingReceiver lr1; - db::RecursiveInstanceIterator i1 (g, c0, 0); - i1.push (&lr1); + int nboxes = 100000; + for (int i = 0; i < nboxes; ++i) { - EXPECT_EQ (lr1.text (), - "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" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 0,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,6000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,8000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,0)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "end\n" - ); + int x, y; - ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ()); - db::RecursiveInstanceIterator ir1 (g, c0, 0); - ir1.push (&rr1); + do { + x = rand () % 10000; + y = rand () % 10000; + } while (boxes.find (basic_box.moved (db::Vector (x + 1, y - 1))) != boxes.end ()); - EXPECT_EQ (rr1.text (), - "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" - "new_inst_member($2,r0 *1 0,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "leave_cell($2)\n" - "end\n" - ); + boxes.insert (basic_box.moved (db::Vector (x + 1, y - 1))); - ReceiverRejectingACellInstanceArrayExceptOne rs1 (c2.cell_index ()); - db::RecursiveInstanceIterator is1 (g, c0, 0); - is1.push (&rs1); + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y)))); - EXPECT_EQ (rs1.text (), - "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" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 0,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,6000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,0)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "end\n" - ); + } - ReceiverRejectingACellInstance rri1 (c2.cell_index (), db::ICplxTrans ()); - db::RecursiveInstanceIterator iri1 (g, c0, 0); - iri1.push (&rri1); + db::Box search_box (2500, 2500, 7500, 7500); - EXPECT_EQ (rri1.text (), - "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 - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 0,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,8000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000,all)\n" - "enter_cell($2)\n" - "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0,all)\n" - "new_inst_member($3,r0 *1 0,2000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000,all)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "end\n" - ); + std::set selected_boxes; + std::set selected_boxes2; - ReceiverRejectingACellInstanceArray rr2 (c1.cell_index ()); - db::RecursiveInstanceIterator ir2 (g, c0, 0); - ir2.push (&rr2); + 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 ()); + } - 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" - ); + 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); + } + } - LoggingReceiver lr2; - db::RecursiveInstanceIterator i2 (g, c0, 0, db::Box (0, 0, 5000, 5000)); - i2.push (&lr2); + EXPECT_EQ (n, nn); - EXPECT_EQ (lr2.text (), - "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" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" - "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" - "enter_cell($3)\n" - "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" - "leave_cell($3)\n" - "leave_cell($2)\n" - "end\n" - ); + 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 ()); + } + + 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); } -#endif + +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 ()); + } + + 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 ()); + } + + 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); +} + From 0f4a10441dfc046327160e37c964601043d86bd4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Feb 2021 22:17:43 +0100 Subject: [PATCH 20/53] RecursiveInstanceIterator: Doc fixes, tests, instance array iteration. --- src/db/db/db.pro | 1 + src/db/db/dbRecursiveInstanceIterator.cc | 32 +- src/db/db/dbRecursiveInstanceIterator.h | 17 +- src/db/db/gsiDeclDbCell.cc | 100 ++++ src/db/db/gsiDeclDbLayout.cc | 38 +- .../db/gsiDeclDbRecursiveInstanceIterator.cc | 558 ++++++++++++++++++ src/db/db/gsiDeclDbRecursiveShapeIterator.cc | 82 +-- .../dbRecursiveInstanceIteratorTests.cc | 20 +- src/rba/unit_tests/rbaTests.cc | 2 + testdata/ruby/dbLayout.rb | 206 ------- testdata/ruby/dbRecursiveInstanceIterator.rb | 265 +++++++++ testdata/ruby/dbRecursiveShapeIterator.rb | 279 +++++++++ 12 files changed, 1323 insertions(+), 277 deletions(-) create mode 100644 src/db/db/gsiDeclDbRecursiveInstanceIterator.cc create mode 100644 testdata/ruby/dbRecursiveInstanceIterator.rb create mode 100644 testdata/ruby/dbRecursiveShapeIterator.rb diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 1903f4e3d..bd6371526 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -115,6 +115,7 @@ SOURCES = \ gsiDeclDbPoint.cc \ gsiDeclDbPolygon.cc \ gsiDeclDbReader.cc \ + gsiDeclDbRecursiveInstanceIterator.cc \ gsiDeclDbRecursiveShapeIterator.cc \ gsiDeclDbRegion.cc \ gsiDeclDbShape.cc \ diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc index 4af46223b..c4782ad8d 100644 --- a/src/db/db/dbRecursiveInstanceIterator.cc +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -45,8 +45,6 @@ RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const Recursive m_max_depth = d.m_max_depth; m_min_depth = d.m_min_depth; - m_shape_flags = d.m_shape_flags; - m_shape_inv_prop_sel = d.m_shape_inv_prop_sel; m_overlapping = d.m_overlapping; m_start = d.m_start; m_stop = d.m_stop; @@ -91,7 +89,6 @@ RecursiveInstanceIterator::RecursiveInstanceIterator () m_overlapping = false; m_max_depth = std::numeric_limits::max (); // all m_min_depth = 0; - m_shape_inv_prop_sel = false; m_needs_reinit = false; m_inst_quad_id = 0; m_all_targets = true; @@ -139,7 +136,6 @@ RecursiveInstanceIterator::init () m_needs_reinit = true; m_max_depth = std::numeric_limits::max (); // all m_min_depth = 0; // from the beginning - m_shape_inv_prop_sel = false; m_inst_quad_id = 0; mp_cell = 0; m_all_targets = true; @@ -390,6 +386,14 @@ RecursiveInstanceIterator::select_all_cells () } } +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 { @@ -438,9 +442,14 @@ void RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver) { if (! at_end ()) { - ++m_inst; - new_inst (receiver); - next_instance (receiver); + ++m_inst_array; + if (! m_inst_array.at_end ()) { + new_inst_member (receiver); + } else { + ++m_inst; + new_inst (receiver); + next_instance (receiver); + } } } @@ -474,8 +483,13 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c if (! m_inst.at_end ()) { if (! needs_visit ()) { - ++m_inst; - new_inst (receiver); + ++m_inst_array; + if (! m_inst_array.at_end ()) { + new_inst_member (receiver); + } else { + ++m_inst; + new_inst (receiver); + } } else { break; } diff --git a/src/db/db/dbRecursiveInstanceIterator.h b/src/db/db/dbRecursiveInstanceIterator.h index 5ac6f6168..8b2eabc50 100644 --- a/src/db/db/dbRecursiveInstanceIterator.h +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -63,7 +63,9 @@ public: 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; /** @@ -416,7 +418,7 @@ public: * Returns the instance currently referred to by the recursive iterator. * This instance is not transformed yet and is located in the current cell. */ - instance_type instance () const + instance_element_type instance () const { return *operator-> (); } @@ -426,7 +428,7 @@ public: * * The access operator is identical to the instance method. */ - instance_type operator* () const + instance_element_type operator* () const { return *operator-> (); } @@ -436,11 +438,7 @@ public: * * The access operator is identical to the instance method. */ - const instance_type *operator-> () const - { - validate (0); - return m_inst.operator-> (); - } + const instance_element_type *operator-> () const; /** * @brief End of iterator predicate @@ -509,7 +507,7 @@ public: /** * @brief The instance path */ - std::vector path () const; + std::vector path () const; /** * @brief Push-mode delivery @@ -541,8 +539,6 @@ public: private: int m_max_depth; int m_min_depth; - unsigned int m_shape_flags; - bool m_shape_inv_prop_sel; bool m_overlapping; std::set m_start, m_stop; std::set m_targets; @@ -557,6 +553,7 @@ private: 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; 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/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/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/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc index 35eb4496d..2a1a15b63 100644 --- a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -41,7 +41,7 @@ std::string collect(db::RecursiveInstanceIterator &s, const db::Layout &layout) } else { res += "[]"; } - res += s->to_string (true); + res += s->inst_ptr.to_string (true); ++s; } return res; @@ -126,13 +126,13 @@ TEST(1) 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, 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, ""); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); x = collect_with_copy(i1_22, g); - EXPECT_EQ (x, ""); + EXPECT_EQ (x, "[$3]$4 r0 1100,0"); db::RecursiveInstanceIterator i1o (g, c0, db::Box (0, 0, 100, 100), true); x = collect(i1o, g); @@ -350,7 +350,7 @@ TEST(2) 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->bbox ()); + selected_boxes.insert (iter.trans () * iter->inst_ptr.bbox ()); } for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { @@ -382,7 +382,7 @@ TEST(2) 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 ()); + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); } for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { @@ -451,7 +451,7 @@ TEST(3) int n = 0; for ( ; !iter.at_end (); ++iter) { ++n; - selected_boxes.insert (iter.trans () * iter->bbox ()); + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); } int nn = 0; @@ -487,7 +487,7 @@ TEST(3) 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 ()); + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); } for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { @@ -556,7 +556,7 @@ TEST(4) int n = 0; for ( ; !iter.at_end (); ++iter) { ++n; - selected_boxes.insert (iter.trans () * iter->bbox ()); + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); } int nn = 0; @@ -592,7 +592,7 @@ TEST(4) reg.insert (search_box2); for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg); !iter.at_end (); ++iter) { - selected_boxes.insert (iter.trans () * iter->bbox ()); + selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert (g))); } for (std::set::const_iterator b = boxes.begin (); b != boxes.end (); ++b) { 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/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/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") From b1fc6008d9af6cc5b5c1c1363085d5764a88acb2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 28 Jul 2019 16:07:35 +0200 Subject: [PATCH 21/53] WIP: better progress when reading OASIS irregular repetitions. --- src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc | 3 +++ 1 file changed, 3 insertions(+) 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; From b31a64b36706db5446f91ab46e54fc2bc1dff37b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 08:45:54 +0100 Subject: [PATCH 22/53] Formulas for 'goto position' dialog. --- src/lay/lay/layMainWindow.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index fa7a19762..4b01a130a 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); From 2168a72b9d2831a69589e56dda73961342894be9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 09:12:13 +0100 Subject: [PATCH 23/53] Technology changed event for CellView --- src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) 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" From 96e3570c6d0d29784b4be7172ca9501b05b2c6f8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 17:28:58 +0100 Subject: [PATCH 24/53] LEF/DEF: preparations for FILLS support, UI rearrangement. --- src/buddies/src/bd/bdReaderOptions.cc | 17 + src/buddies/src/bd/bdReaderOptions.h | 3 + .../lefdef/db_plugin/dbDEFImporter.cc | 2 + .../lefdef/db_plugin/dbDEFImporter.h | 1 + .../lefdef/db_plugin/dbLEFDEFImporter.cc | 47 + .../lefdef/db_plugin/dbLEFDEFImporter.h | 75 + .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 7 + .../lefdef/db_plugin/gsiDeclDbLEFDEF.cc | 88 + .../LEFDEFTechnologyComponentEditor.ui | 2426 +++++++++-------- .../lay_plugin/layLEFDEFImportDialogs.cc | 9 + .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 10 + 11 files changed, 1505 insertions(+), 1180 deletions(-) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 925212796..270d6f97b 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." 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/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 68ec18f34..bc97a32da 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -1426,10 +1426,12 @@ DEFImporter::do_read (db::Layout &layout) take (); } } else if (test ("FILLS")) { + // read over FILLS statements while (! test ("END") || ! test ("FILLS")) { take (); } + } 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..c5f26970b 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h @@ -82,6 +82,7 @@ private: void read_regions (std::map > ®ions, double scale); void read_groups (std::list &groups, double scale); void read_blockages (db::Layout &layout, db::Cell &design, double scale); + void read_fills (db::Layout &layout, db::Cell &design, double scale); 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); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 615b8f556..97f75ce09 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -425,6 +425,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 +492,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 +719,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 +867,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; @@ -1091,6 +1125,10 @@ static std::string purpose_to_name (LayerPurpose purpose) return "LABEL"; case Pins: return "PIN"; + case Fills: + return "FILL"; + case FillsOPC: + return "FILLOPC"; case LEFPins: return "LEFPIN"; case Obstructions: @@ -1262,6 +1300,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 +1345,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); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 9ae66d983..7a85c62b1 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 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/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..1c8979355 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 + + + + + + + + + + 0 + + + + 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,15 +1352,6 @@ type ... - lef_files - add_lef_file - del_lef_files - move_lef_files_up - move_lef_files_down - dbu - prefix_via_cellname - separate_groups - produce_lef_geo produce_net_names net_prop_name produce_inst_names @@ -1294,7 +1364,6 @@ type ... placement_blockage_layer produce_regions region_layer - layer_map_mode produce_via_geometry suffix_via_geometry datatype_via_geometry @@ -1316,9 +1385,6 @@ type ... produce_labels suffix_labels datatype_labels - produce_blockages - suffix_blockages - datatype_blockages mapfile_path browse_mapfile diff --git a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc index 4c64e034f..1ebe6c8b8 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 ())); @@ -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..83e1b3f37 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -752,6 +752,16 @@ TEST(119_multimapping) ) } +TEST(120_simplefill) +{ + run_test (_this, "fill", "lef:simple.lef+def:simple.def+map:simple.map", "simple_au.oas.gz", default_options (), false); +} + +TEST(121_fillwithmask) +{ + run_test (_this, "fill", "lef:with_mask.lef+def:with_mask.def+map:with_mask.map", "with_mask_au.oas.gz", default_options (), false); +} + TEST(200_lefdef_plugin) { db::Layout ly; From 898dbf07e9a62bca60e2020ba822bae7117004a3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 18:27:25 +0100 Subject: [PATCH 25/53] Implemented FILLS support for LEF/DEF --- .../lefdef/db_plugin/dbDEFImporter.cc | 107 +++++++++++++++++- .../lefdef/db_plugin/dbDEFImporter.h | 2 +- .../LEFDEFTechnologyComponentEditor.ui | 26 ++++- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 4 +- testdata/lefdef/fill/simple.def | 14 +++ testdata/lefdef/fill/simple.lef | 29 +++++ testdata/lefdef/fill/simple.map | 4 + testdata/lefdef/fill/simple_au.oas.gz | Bin 0 -> 545 bytes testdata/lefdef/fill/with_mask.def | 14 +++ testdata/lefdef/fill/with_mask.lef | 15 +++ testdata/lefdef/fill/with_mask.map | 4 + testdata/lefdef/fill/with_mask_au.oas.gz | Bin 0 -> 557 bytes 12 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 testdata/lefdef/fill/simple.def create mode 100644 testdata/lefdef/fill/simple.lef create mode 100644 testdata/lefdef/fill/simple.map create mode 100644 testdata/lefdef/fill/simple_au.oas.gz create mode 100644 testdata/lefdef/fill/with_mask.def create mode 100644 testdata/lefdef/fill/with_mask.lef create mode 100644 testdata/lefdef/fill/with_mask.map create mode 100644 testdata/lefdef/fill/with_mask_au.oas.gz diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index bc97a32da..b0deb624b 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -1243,6 +1243,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) { @@ -1427,10 +1522,14 @@ DEFImporter::do_read (db::Layout &layout) } } 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 diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h index c5f26970b..5fee51f1c 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h @@ -82,10 +82,10 @@ private: void read_regions (std::map > ®ions, double scale); void read_groups (std::list &groups, double scale); void read_blockages (db::Layout &layout, db::Cell &design, double scale); - void read_fills (db::Layout &layout, db::Cell &design, double scale); 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/lay_plugin/LEFDEFTechnologyComponentEditor.ui b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui index 1c8979355..0db23b7f8 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui +++ b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui @@ -714,7 +714,7 @@ - 0 + 1 @@ -1352,6 +1352,17 @@ type ... + tabWidget + read_lef_with_def + lef_files + add_lef_file + del_lef_files + move_lef_files_up + move_lef_files_down + dbu + separate_groups + prefix_via_cellname + produce_lef_geo produce_net_names net_prop_name produce_inst_names @@ -1364,6 +1375,10 @@ type ... placement_blockage_layer produce_regions region_layer + layer_map_mode + mapfile_path + browse_mapfile + scrollArea produce_via_geometry suffix_via_geometry datatype_via_geometry @@ -1373,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 @@ -1385,8 +1403,10 @@ type ... produce_labels suffix_labels datatype_labels - mapfile_path - browse_mapfile + produce_blockages + suffix_blockages + datatype_blockages + read_all_cbx diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 83e1b3f37..099b25960 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -754,12 +754,12 @@ TEST(119_multimapping) TEST(120_simplefill) { - run_test (_this, "fill", "lef:simple.lef+def:simple.def+map:simple.map", "simple_au.oas.gz", default_options (), false); + 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", "lef:with_mask.lef+def:with_mask.def+map:with_mask.map", "with_mask_au.oas.gz", default_options (), false); + 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(200_lefdef_plugin) 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 0000000000000000000000000000000000000000..c6ca9c9eb9a987510b7f66b6ac6786a01fe4dbc6 GIT binary patch literal 545 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>u#}`0moS4#Zg&6B5FbxJSLPIE1|DP% zH@mN)o|~tS4>K1tBM&kMC}RYX5n*Nm${;x0Tu_dGfHSiQGcykwpO---IfY??{0%cv zdoD&srUmjZ*e~!ekmqJNA}l1TEyBdY+)>+5+gAI6T~q@iy+B@6i1~vaQ^QCG3=9BO C5xwI8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..946e28973695b10e059f9b780053048df697f9f8 GIT binary patch literal 557 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>u#}`0moS4#Zg&6B5FbxJSLPIE1|DP% zH>auV86h>K%Sf7h_H~Twg?job4P7MZCmXNc2Nz8^a6QNA?6QyObsI$ HFfafB=6S$% literal 0 HcmV?d00001 From eda1992a7d26d0e4805089cf1479f8836228b948 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 21:00:55 +0100 Subject: [PATCH 26/53] Added VIA size selectors for LEF/DEF .map files. --- .../lefdef/db_plugin/dbDEFImporter.cc | 14 +- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 193 +++++++++--------- .../lefdef/db_plugin/dbLEFDEFImporter.h | 66 +++++- .../lefdef/db_plugin/dbLEFImporter.cc | 12 +- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 5 + testdata/lefdef/viasize/au.oas.gz | Bin 0 -> 863 bytes testdata/lefdef/viasize/test.def | 35 ++++ testdata/lefdef/viasize/test.lef | 24 +++ testdata/lefdef/viasize/test.map | 8 + 9 files changed, 253 insertions(+), 104 deletions(-) create mode 100644 testdata/lefdef/viasize/au.oas.gz create mode 100644 testdata/lefdef/viasize/test.def create mode 100644 testdata/lefdef/viasize/test.lef create mode 100644 testdata/lefdef/viasize/test.map diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index b0deb624b..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)); } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 97f75ce09..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 @@ -876,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 ()) { @@ -896,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 ()); @@ -907,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")); } } @@ -915,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")); } } @@ -923,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")); } } @@ -949,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)); } } } @@ -968,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 ()); @@ -982,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 ()) { @@ -997,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); } } @@ -1018,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)); } @@ -1033,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 { @@ -1056,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)); @@ -1077,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); @@ -1087,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; @@ -1098,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 { @@ -1106,42 +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 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 (); -} - /** * @brief Implements implicit layer mapping * @@ -1467,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 7a85c62b1..203451541 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -962,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 */ @@ -1054,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); @@ -1083,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; @@ -1129,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) @@ -1263,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; @@ -1438,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/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/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 099b25960..75e473fe1 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -762,6 +762,11 @@ 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/testdata/lefdef/viasize/au.oas.gz b/testdata/lefdef/viasize/au.oas.gz new file mode 100644 index 0000000000000000000000000000000000000000..944161a0c09d7af5eea35af6e955bf85cca7fa95 GIT binary patch literal 863 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>a3p7B7Q~n27qIgM$Gf`(#|H%Y2e<}> zL~^pGl;-AEGQ$-x^M!dj#sjfod~t4KP7V@3C$T6!m7Co^G{nc#&y|^xnSlqH!_DJs zsORSzq8}UpB$?TP(ikE@HAYBkIKgVrM7TLXw(9{2W)7e{3XfY1CTA7w8RcrAXJ8Zo zB7iCxdGN?_OJL|T0c$h?>SW@e|ASubqh%Cs+$fThm zD$2_s_>E}-^8{wW4~!=m8AJ{gk$e}L&6(=nzVe$gJVD3XpfOmJlT#&%FZxt XVY~toW@G{x^M#o~mZ@PR0|o{F;1vXa literal 0 HcmV?d00001 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 From fe2d4eb570785a578769897bbd63c6f0464db85b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 21:07:13 +0100 Subject: [PATCH 27/53] Bugfix: LEF/DEF FILLS options were not active in buddy scripts. --- src/buddies/src/bd/bdReaderOptions.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 270d6f97b..57c31cd95 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -741,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); From 3db1db831fe021a630f6585c48af59af99a4a995 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 21:23:45 +0100 Subject: [PATCH 28/53] Test update after update of LEF/DEF reader. --- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 22 +++++++++++------- testdata/lefdef/mapfile/au.oas.gz | Bin 1043 -> 1213 bytes testdata/lefdef/masks-2/au.oas.gz | Bin 3190 -> 3290 bytes testdata/ruby/dbReaders.rb | 12 ++++++++++ 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 75e473fe1..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)'" ")" ) diff --git a/testdata/lefdef/mapfile/au.oas.gz b/testdata/lefdef/mapfile/au.oas.gz index 942c568de6f272436bf824a5f90b385709a0b28e..bf3c4bea7585299965d8ea76b58a552e58947610 100644 GIT binary patch delta 382 zcmbQtv6pkg4Sg|Rg8+X$Ki3fb08c;t-~bRyPfw4TiNDmi6quhI($EK0eGm z%rh8yP1cpO7dI#*u*sPLg9#`J)@X=DBQI1Vn%w4S HrX7p`L26Vs delta 212 zcmdnXIhkX^4P^meg8+X$Ki3fb08c-CJv}{UE@lQE6w%4-jFyv+F!t1Q`x@#w`S?3~ zJG#3v^Ds|m=xc~>9W&56?84kIVI%{YK~`ZGpWMSdZSo|Ru*o&7Ad8I9 zEn)>*giRP|5kwftB36h+*u*D4W0^Mj4Qt%wPi(*-4D)m}K(~qs6ofb=xDgUa)-i#D z5UvGPX0iv{s>ylmNs}u$AQoZ-A`8?)Y!YA#AreT&vcN3FCNudQ`>M@fIP931c~*!_ RHs#i3=KG<%Ih9+G5ddQpjTry{ delta 474 zcmca5`AuSj0Mq0JOe-b}Flhzw`5FZH>jilFSsCi<>FF^uGUxGN5#vUP89~)uVnk91 z7o62Y`P*#YcXhM_K*b*j-v9Fli#s&*(U zi{Ruv>?xBsaIBcDzyUEFIUrb|hNFpr4Tp$93}=BEjwZM{jMIUMneT`4 Date: Sun, 21 Feb 2021 21:55:36 +0100 Subject: [PATCH 29/53] Qt4 compatibility. --- src/lay/lay/layMacroEditorDialog.cc | 2 +- src/lay/lay/layMacroEditorPage.cc | 1 - src/laybasic/laybasic/layQtTools.cc | 16 ++++++++++++++++ src/laybasic/laybasic/layQtTools.h | 22 ++++++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index 7573154e0..ac46f6402 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -1890,7 +1890,7 @@ MacroEditorDialog::set_editor_focus () return; } - QSignalBlocker signal_blocker (searchEditBox); + lay::SignalBlocker signal_blocker (searchEditBox); page->set_editor_focus (); } diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index 0eb04be59..3cdd98a78 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -43,7 +43,6 @@ #include #include #include -#include #include #include diff --git a/src/laybasic/laybasic/layQtTools.cc b/src/laybasic/laybasic/layQtTools.cc index bc7a1e537..a769a07be 100644 --- a/src/laybasic/laybasic/layQtTools.cc +++ b/src/laybasic/laybasic/layQtTools.cc @@ -189,5 +189,21 @@ indicate_error (QWidget *le, bool f) 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 fc11d89ee..36a02b368 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 { @@ -81,6 +82,27 @@ LAYBASIC_PUBLIC void indicate_error (QWidget *le, const tl::Exception *ex); */ LAYBASIC_PUBLIC void indicate_error (QWidget *le, bool error); +#if QT_VERSION < 0x050000 + +// Provide missing QSignalBlocker for Qt4 + +class SignalBlocker +{ +public: + SignalBlocker (QWidget *w); + ~SignalBlocker (); + +private: + QWidget *mp_widget; + bool m_state; +}; + +#else + +typedef QSignalBlocker SignalBlocker; + +#endif + } // namespace lay #endif From 9074c918bb293d8b8586c4c0821d9a63b507a954 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 22:11:33 +0100 Subject: [PATCH 30/53] Fixed a linker name clash. --- .../dbRecursiveInstanceIteratorTests.cc | 26 +++++++++++-------- .../dbRecursiveShapeIteratorTests.cc | 26 +++++++++++-------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc index 2a1a15b63..a13dad263 100644 --- a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -302,20 +302,24 @@ static db::Layout boxes2layout (const std::set &boxes) return l; } -class FlatPusher - : public db::RecursiveInstanceReceiver -{ -public: - FlatPusher (std::set *boxes) : mp_boxes (boxes) { } +namespace { - void enter_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + class FlatPusher + : public db::RecursiveInstanceReceiver { - mp_boxes->insert (iter->trans () * cell->bbox ()); - } + public: + FlatPusher (std::set *boxes) : mp_boxes (boxes) { } -private: - std::set *mp_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) { diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index cc61b571b..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) { From 835133854ccaf877d95a50c9f8958ed4a1504ea0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 22:42:52 +0100 Subject: [PATCH 31/53] Qt4 compatibility, some enhancement of macro IDE completer --- src/lay/lay/layMacroEditorPage.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index 3cdd98a78..3e6b34b7b 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -510,7 +510,7 @@ MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters mp_text->installEventFilter (this); - mp_completer_popup = new QWidget (window (), Qt::ToolTip | Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput); + mp_completer_popup = new QWidget (window (), Qt::ToolTip); mp_completer_popup->setWindowModality (Qt::NonModal); QHBoxLayout *ly = new QHBoxLayout (mp_completer_popup); ly->setMargin (0); @@ -644,7 +644,8 @@ void MacroEditorPage::fill_completer_list () return; } - QString s = c.selectedText ().mid (0, pos - pos0); + QString ssel = c.selectedText (); + QString s = ssel.mid (0, pos - pos0); QString text = mp_text->toPlainText (); @@ -660,7 +661,7 @@ void MacroEditorPage::fill_completer_list () w += *c; ++c; } - if (! w.isEmpty () && w != s) { + if (! w.isEmpty () && w != s && w != ssel) { words.insert (w); } ++i; From f700b3e0562a1e01953433af5a6dee31b391dcd9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Feb 2021 23:18:57 +0100 Subject: [PATCH 32/53] Linker issue solved --- src/laybasic/laybasic/layQtTools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laybasic/laybasic/layQtTools.h b/src/laybasic/laybasic/layQtTools.h index 36a02b368..763a8c706 100644 --- a/src/laybasic/laybasic/layQtTools.h +++ b/src/laybasic/laybasic/layQtTools.h @@ -86,7 +86,7 @@ LAYBASIC_PUBLIC void indicate_error (QWidget *le, bool error); // Provide missing QSignalBlocker for Qt4 -class SignalBlocker +class LAYBASIC_PUBLIC SignalBlocker { public: SignalBlocker (QWidget *w); From 8b2ecf41df43ef796d4ace1fc398c4e9e807146a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Thu, 25 Feb 2021 21:28:48 +0100 Subject: [PATCH 33/53] Fixed issue by providing a compatibility bridge between tl::Stream (abstract paths) and tl::URI (#734) --- src/db/db/dbNetlistSpiceReader.cc | 2 +- src/img/img/imgObject.cc | 2 +- src/lay/lay/laySession.cc | 2 +- .../streamers/magic/db_plugin/dbMAGReader.cc | 2 +- src/tl/tl/tlInclude.cc | 2 +- src/tl/tl/tlStream.cc | 37 +++++++++++++------ src/tl/tl/tlStream.h | 2 + src/tl/tl/tlUri.cc | 10 +++++ src/tl/tl/tlUri.h | 13 +++++++ src/tl/unit_tests/tlUriTests.cc | 15 ++++++++ 10 files changed, 70 insertions(+), 17 deletions(-) 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/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/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/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/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/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/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"); +} From b968f2b47ff748aa6f0f22a1e9b0ecf1e31326d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Thu, 25 Feb 2021 21:29:21 +0100 Subject: [PATCH 34/53] =?UTF-8?q?#730:=20providing=20a=20new=20Qt=20module?= =?UTF-8?q?=20named=20QtUiTools=20for=20QUiLoader=20class=20s=E2=80=A6=20(?= =?UTF-8?q?#735)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #730: providing a new Qt module named QtUiTools for QUiLoader class support. * Fixed a compile error on Mac * Added QtUiTools to some more places * Fixed a linker issue in the QtUiTools Python lib * On occasion fixed a infinite recursion problem in the debugger The recursion happened because by mistake I instantiated a QApplication inside an in-application Python script. This crashed the debugger due to infinite recursion. This is not a real use case but to prevent similar issues, a recursion sentinel was added. * Removed QCoreApplication#notify from script bindings Reasoning: "notify" made standalone scripts using QApplication and QUiLoader virtually impossible. Problem description: - When a QApplication object is instantiated, e.g. in Python, the Qt binding will install reimplementation hooks as the object may be dynamically extended. - A notify is virtual this means the *every* "notify" call in the application is routed through the interpreter. - For one thing this will slow down the application - But as "notify" is called a zillion times this has more than this side effect. - Specifically "notify" is called from within the QWidget constructor to indicate a new widget. Then, if a QDialog for example is instatiated, it's base class constructor will call "notify" when the object isn't ready yet. - This has another severe side effect: as the object isn't ready yet, it gets registered in the Python space with the wrong class and QDialog is not visible as such. To mitigate these problems, the most efficient solution is to disable "notify" in general. There is hardly any use case in a script environment (in C++, apart from hacking the only reasonable use case is exception handling, but this does not apply to scripts). For providing the call functionality of "notify" you should better use "postEvent" or "sendEvent" anyway. So farewell QCoreApplication.notify ... * Fixed python test for QtUiTools module * Fixed UiTools test on Qt4 - QUiLoader needs an application object Co-authored-by: Kazunari Sekigawa --- .gitignore | 1 + scripts/mkqtdecl.sh | 4 +- scripts/mkqtdecl4/QtUiTools/allofqt.cpp | 1 + scripts/mkqtdecl4/mkqtdecl.conf | 12 + scripts/mkqtdecl5/QtUiTools/allofqt.cpp | 1 + scripts/mkqtdecl5/mkqtdecl.conf | 13 + .../qt4/QtCore/gsiDeclQCoreApplication.cc | 67 - src/gsiqt/qt4/QtGui/gsiDeclQApplication.cc | 67 - src/gsiqt/qt4/QtUiTools/QtUiTools.pri | 13 + src/gsiqt/qt4/QtUiTools/QtUiTools.pro | 20 + src/gsiqt/qt4/QtUiTools/gsiDeclQUiLoader.cc | 1093 +++++++++++++++++ .../QtUiTools/gsiDeclQtUiToolsTypeTraits.h | 86 ++ src/gsiqt/qt4/QtUiTools/gsiQtExternals.h | 48 + src/gsiqt/qt4/QtUiTools/gsiQtUiToolsCommon.h | 25 + src/gsiqt/qt4/QtUiTools/gsiQtUiToolsMain.cc | 11 + src/gsiqt/qt4/qt4.pro | 4 +- .../qt5/QtCore/gsiDeclQCoreApplication.cc | 67 - src/gsiqt/qt5/QtGui/gsiDeclQGuiApplication.cc | 67 - src/gsiqt/qt5/QtUiTools/QtUiTools.pri | 13 + src/gsiqt/qt5/QtUiTools/QtUiTools.pro | 20 + src/gsiqt/qt5/QtUiTools/gsiDeclQUiLoader.cc | 1045 ++++++++++++++++ .../QtUiTools/gsiDeclQtUiToolsTypeTraits.h | 138 +++ src/gsiqt/qt5/QtUiTools/gsiQtExternals.h | 48 + src/gsiqt/qt5/QtUiTools/gsiQtUiToolsCommon.h | 25 + src/gsiqt/qt5/QtUiTools/gsiQtUiToolsMain.cc | 11 + .../qt5/QtWidgets/gsiDeclQApplication.cc | 67 - src/gsiqt/qt5/qt5.pro | 4 +- src/gsiqt/qtbasic/gsiQtUiToolsExternals.h | 27 + src/klayout.pri | 4 +- src/klayout_main/klayout_main/klayout.cc | 12 + .../klayout_main/klayout_main.pro | 2 +- src/lay/lay/doc/programming/qt_binding.xml | 1 + src/lay/lay/layMacroEditorDialog.cc | 86 +- src/lay/lay/layMacroEditorDialog.h | 2 +- src/lay/lay/layMacroEditorPage.cc | 20 +- src/pymod/QtCore/QtCoreMain.cc | 1 + src/pymod/QtUiTools/QtUiTools.pro | 11 + src/pymod/QtUiTools/QtUiToolsMain.cc | 33 + src/pymod/__init__.py.qt4 | 2 +- src/pymod/__init__.py.qt5 | 2 +- src/pymod/pymod.pro | 4 +- src/pymod/unit_tests/pymod_tests.cc | 1 + src/tl/tl/tlTimer.cc | 2 + testdata/pymod/import_QtUiTools.py | 43 + 44 files changed, 2843 insertions(+), 381 deletions(-) create mode 100644 scripts/mkqtdecl4/QtUiTools/allofqt.cpp create mode 100644 scripts/mkqtdecl5/QtUiTools/allofqt.cpp create mode 100644 src/gsiqt/qt4/QtUiTools/QtUiTools.pri create mode 100644 src/gsiqt/qt4/QtUiTools/QtUiTools.pro create mode 100644 src/gsiqt/qt4/QtUiTools/gsiDeclQUiLoader.cc create mode 100644 src/gsiqt/qt4/QtUiTools/gsiDeclQtUiToolsTypeTraits.h create mode 100644 src/gsiqt/qt4/QtUiTools/gsiQtExternals.h create mode 100644 src/gsiqt/qt4/QtUiTools/gsiQtUiToolsCommon.h create mode 100644 src/gsiqt/qt4/QtUiTools/gsiQtUiToolsMain.cc create mode 100644 src/gsiqt/qt5/QtUiTools/QtUiTools.pri create mode 100644 src/gsiqt/qt5/QtUiTools/QtUiTools.pro create mode 100644 src/gsiqt/qt5/QtUiTools/gsiDeclQUiLoader.cc create mode 100644 src/gsiqt/qt5/QtUiTools/gsiDeclQtUiToolsTypeTraits.h create mode 100644 src/gsiqt/qt5/QtUiTools/gsiQtExternals.h create mode 100644 src/gsiqt/qt5/QtUiTools/gsiQtUiToolsCommon.h create mode 100644 src/gsiqt/qt5/QtUiTools/gsiQtUiToolsMain.cc create mode 100644 src/gsiqt/qtbasic/gsiQtUiToolsExternals.h create mode 100644 src/pymod/QtUiTools/QtUiTools.pro create mode 100644 src/pymod/QtUiTools/QtUiToolsMain.cc create mode 100755 testdata/pymod/import_QtUiTools.py 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/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/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..31fab2d54 100644 --- a/src/gsiqt/qt4/qt4.pro +++ b/src/gsiqt/qt4/qt4.pro @@ -7,10 +7,12 @@ SUBDIRS = \ QtXml \ QtSql \ QtNetwork \ - QtDesigner + QtDesigner \ + QtUiTools QtGui.depends += QtCore QtNetwork.depends += QtCore QtSql.depends += QtCore QtDesigner.depends += QtCore QtXml.depends += QtCore +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..58b1f6c0c --- /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 + +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..7b882b8bc 100644 --- a/src/gsiqt/qt5/qt5.pro +++ b/src/gsiqt/qt5/qt5.pro @@ -12,7 +12,8 @@ SUBDIRS = \ QtPrintSupport \ QtSvg \ QtXmlPatterns \ - QtXml + QtXml \ + QtUiTools QtGui.depends += QtCore QtNetwork.depends += QtCore @@ -24,3 +25,4 @@ QtPrintSupport.depends += QtCore QtWidgets QtSvg.depends += QtCore QtWidgets QtXmlPatterns.depends += QtCore QtXml.depends += QtCore +QtUiTools.depends += QtCore diff --git a/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h new file mode 100644 index 000000000..341ff42d5 --- /dev/null +++ b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h @@ -0,0 +1,27 @@ + +/* + + 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 QT_VERSION >= 0x050000 +# include "../qt5/QtUiTools/gsiQtExternals.h" +#else +# include "../qt4/QtUiTools/gsiQtExternals.h" +#endif diff --git a/src/klayout.pri b/src/klayout.pri index e7b3807b7..cffd8ab63 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -163,13 +163,13 @@ equals(HAVE_QT, "0") { QT += core network xml sql equals(HAVE_QT5, "1") { - QT += designer printsupport widgets + QT += designer printsupport widgets uitools equals(HAVE_QTBINDINGS, "1") { QT += multimedia multimediawidgets xmlpatterns svg gui } } else { # questionable: use uitools instead? - CONFIG += designer + CONFIG += designer uitools } } 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..0200f2285 100644 --- a/src/klayout_main/klayout_main/klayout_main.pro +++ b/src/klayout_main/klayout_main/klayout_main.pro @@ -25,7 +25,7 @@ INCLUDEPATH += $$QTBASIC_INC DEPENDPATH += $$QTBASIC_INC equals(HAVE_QTBINDINGS, "1") { - LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner + LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner -lklayout_QtUiTools equals(HAVE_QT5, "1") { LIBS += -lklayout_QtMultimedia -lklayout_QtPrintSupport -lklayout_QtSvg -lklayout_QtWidgets -lklayout_QtXmlPatterns } 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/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index ac46f6402..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), @@ -2850,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; diff --git a/src/lay/lay/layMacroEditorDialog.h b/src/lay/lay/layMacroEditorDialog.h index fd60dbb0b..750715f79 100644 --- a/src/lay/lay/layMacroEditorDialog.h +++ b/src/lay/lay/layMacroEditorDialog.h @@ -323,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 3e6b34b7b..10fe4c9e6 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 @@ -584,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 () 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..616b04042 --- /dev/null +++ b/src/pymod/QtUiTools/QtUiTools.pro @@ -0,0 +1,11 @@ + +TARGET = QtUiTools + +include($$PWD/../pymod.pri) + +SOURCES = \ + QtUiToolsMain.cc \ + +HEADERS += \ + +LIBS += -lklayout_QtUiTools -lklayout_QtCore diff --git a/src/pymod/QtUiTools/QtUiToolsMain.cc b/src/pymod/QtUiTools/QtUiToolsMain.cc new file mode 100644 index 000000000..49d8fbc34 --- /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..82f6124f1 100644 --- a/src/pymod/pymod.pro +++ b/src/pymod/pymod.pro @@ -20,6 +20,7 @@ SUBDIRS = \ QtSql \ QtWidgets \ QtDesigner \ + QtUiTools \ QtMultimedia \ QtPrintSupport \ QtSvg \ @@ -34,7 +35,8 @@ SUBDIRS = \ QtXml \ QtSql \ QtNetwork \ - QtDesigner + QtDesigner \ + QtUiTools } } diff --git a/src/pymod/unit_tests/pymod_tests.cc b/src/pymod/unit_tests/pymod_tests.cc index 1c5c5e72d..16de70c82 100644 --- a/src/pymod/unit_tests/pymod_tests.cc +++ b/src/pymod/unit_tests/pymod_tests.cc @@ -98,6 +98,7 @@ PYMODTEST (import_QtXml, "import_QtXml.py") PYMODTEST (import_QtSql, "import_QtSql.py") PYMODTEST (import_QtNetwork, "import_QtNetwork.py") PYMODTEST (import_QtDesigner, "import_QtDesigner.py") +PYMODTEST (import_QtUiTools, "import_QtUiTools.py") #if QT_VERSION >= 0x50000 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/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) + + From 68e1284c93e60b2521abb2b4a29d1ebb7c525595 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 25 Feb 2021 22:03:41 +0100 Subject: [PATCH 35/53] Fixed #728 --- src/lay/lay/laySignalHandler.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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); From f993c0397d775a978024f14ae071a43d243d7330 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 25 Feb 2021 23:08:42 +0100 Subject: [PATCH 36/53] A linker issue fixed on Windows. --- src/gsiqt/qt5/QtUiTools/QtUiTools.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gsiqt/qt5/QtUiTools/QtUiTools.pro b/src/gsiqt/qt5/QtUiTools/QtUiTools.pro index 58b1f6c0c..eec9abbec 100644 --- a/src/gsiqt/qt5/QtUiTools/QtUiTools.pro +++ b/src/gsiqt/qt5/QtUiTools/QtUiTools.pro @@ -10,7 +10,7 @@ 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 +LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_qtbasic -lklayout_QtCore SOURCES += \ From 9350b33bcbd06384caadcdbfdc29358c6de44330 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 26 Feb 2021 23:59:23 +0100 Subject: [PATCH 37/53] Squashed commit of the following: commit 2a8a2d228db65f7734e17e323bb28e2b3b6ec9dd Author: Matthias Koefferlein Date: Fri Feb 26 23:54:08 2021 +0100 One more fix. commit 8c4d76505ccc3071dab2e65827afe0005a9d660f Author: Matthias Koefferlein Date: Fri Feb 26 23:03:07 2021 +0100 More patches for uitools-less build for CentOS 8 commit 2ac28292b833778173658aab5ac12fd85b5e33e9 Author: Matthias Koefferlein Date: Fri Feb 26 22:52:27 2021 +0100 First steps for fixing build on CentOS 8 without uitools --- src/gsiqt/qt4/qt4.pro | 10 +++++++--- src/gsiqt/qt5/qt5.pro | 10 +++++++--- src/gsiqt/qtbasic/gsiQtUiToolsExternals.h | 4 +++- src/klayout.pri | 11 +++++++++-- src/klayout_main/klayout_main/klayout_main.pro | 5 ++++- src/pymod/QtUiTools/QtUiTools.pro | 7 ++++++- src/pymod/QtUiTools/QtUiToolsMain.cc | 4 +++- src/pymod/unit_tests/pymod_tests.cc | 5 +++++ 8 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/gsiqt/qt4/qt4.pro b/src/gsiqt/qt4/qt4.pro index 31fab2d54..5a420947b 100644 --- a/src/gsiqt/qt4/qt4.pro +++ b/src/gsiqt/qt4/qt4.pro @@ -7,12 +7,16 @@ SUBDIRS = \ QtXml \ QtSql \ QtNetwork \ - QtDesigner \ - QtUiTools + QtDesigner QtGui.depends += QtCore QtNetwork.depends += QtCore QtSql.depends += QtCore QtDesigner.depends += QtCore QtXml.depends += QtCore -QtUiTools.depends += QtCore + +contains(QT_MODULES, uitools) { + # Not all distributions have uitools + SUBDIRS += QtUiTools + QtUiTools.depends += QtCore +} diff --git a/src/gsiqt/qt5/qt5.pro b/src/gsiqt/qt5/qt5.pro index 7b882b8bc..cadc57021 100644 --- a/src/gsiqt/qt5/qt5.pro +++ b/src/gsiqt/qt5/qt5.pro @@ -12,8 +12,7 @@ SUBDIRS = \ QtPrintSupport \ QtSvg \ QtXmlPatterns \ - QtXml \ - QtUiTools + QtXml QtGui.depends += QtCore QtNetwork.depends += QtCore @@ -25,4 +24,9 @@ QtPrintSupport.depends += QtCore QtWidgets QtSvg.depends += QtCore QtWidgets QtXmlPatterns.depends += QtCore QtXml.depends += QtCore -QtUiTools.depends += QtCore + +contains(QT_MODULES, uitools) { + # Not all distributions have uitools + SUBDIRS += QtUiTools + QtUiTools.depends += QtCore +} diff --git a/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h index 341ff42d5..49462cbed 100644 --- a/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h +++ b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h @@ -20,7 +20,9 @@ */ -#if QT_VERSION >= 0x050000 +#if !defined(HAVE_QT_UITOOLS) +# defined FORCE_LINK_GSI_QTUITOOLS +#elif QT_VERSION >= 0x050000 # include "../qt5/QtUiTools/gsiQtExternals.h" #else # include "../qt4/QtUiTools/gsiQtExternals.h" diff --git a/src/klayout.pri b/src/klayout.pri index cffd8ab63..506c8003d 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -163,15 +163,22 @@ equals(HAVE_QT, "0") { QT += core network xml sql equals(HAVE_QT5, "1") { - QT += designer printsupport widgets uitools + QT += designer printsupport widgets + contains(QT_MODULES, "uitools") { + # not all distributions have uitools + QT += uitools + } equals(HAVE_QTBINDINGS, "1") { QT += multimedia multimediawidgets xmlpatterns svg gui } } else { - # questionable: use uitools instead? CONFIG += designer uitools } + contains(QT_MODULES, "uitools") { + DEFINES += HAVE_QT_UITOOLS + } + } VERSION_STRING = $$KLAYOUT_VERSION diff --git a/src/klayout_main/klayout_main/klayout_main.pro b/src/klayout_main/klayout_main/klayout_main.pro index 0200f2285..3b2de1643 100644 --- a/src/klayout_main/klayout_main/klayout_main.pro +++ b/src/klayout_main/klayout_main/klayout_main.pro @@ -25,7 +25,10 @@ INCLUDEPATH += $$QTBASIC_INC DEPENDPATH += $$QTBASIC_INC equals(HAVE_QTBINDINGS, "1") { - LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner -lklayout_QtUiTools + LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner + contains(QT_MODULES, uitools) { + LIBS += -lklayout_QtUiTools + } equals(HAVE_QT5, "1") { LIBS += -lklayout_QtMultimedia -lklayout_QtPrintSupport -lklayout_QtSvg -lklayout_QtWidgets -lklayout_QtXmlPatterns } diff --git a/src/pymod/QtUiTools/QtUiTools.pro b/src/pymod/QtUiTools/QtUiTools.pro index 616b04042..200791fd3 100644 --- a/src/pymod/QtUiTools/QtUiTools.pro +++ b/src/pymod/QtUiTools/QtUiTools.pro @@ -8,4 +8,9 @@ SOURCES = \ HEADERS += \ -LIBS += -lklayout_QtUiTools -lklayout_QtCore +contains(QT_MODULES, uitools) { + LIBS += -lklayout_QtUiTools +} + +LIBS += -lklayout_QtCore + diff --git a/src/pymod/QtUiTools/QtUiToolsMain.cc b/src/pymod/QtUiTools/QtUiToolsMain.cc index 49d8fbc34..d70d419d4 100644 --- a/src/pymod/QtUiTools/QtUiToolsMain.cc +++ b/src/pymod/QtUiTools/QtUiToolsMain.cc @@ -26,8 +26,10 @@ #include "../../gsiqt/qtbasic/gsiQtCoreExternals.h" FORCE_LINK_GSI_QTCORE -#include "../../gsiqt/qtbasic/gsiQtUiToolsExternals.h" +#if defined(HAVE_QT_UITOOLS) +# include "../../gsiqt/qtbasic/gsiQtUiToolsExternals.h" FORCE_LINK_GSI_QTUITOOLS +#endif DEFINE_PYMOD(QtUiTools, "QtUiTools", "KLayout/Qt module 'QtUiTools'") diff --git a/src/pymod/unit_tests/pymod_tests.cc b/src/pymod/unit_tests/pymod_tests.cc index 16de70c82..9812fa666 100644 --- a/src/pymod/unit_tests/pymod_tests.cc +++ b/src/pymod/unit_tests/pymod_tests.cc @@ -98,8 +98,13 @@ PYMODTEST (import_QtXml, "import_QtXml.py") PYMODTEST (import_QtSql, "import_QtSql.py") PYMODTEST (import_QtNetwork, "import_QtNetwork.py") PYMODTEST (import_QtDesigner, "import_QtDesigner.py") + +#if defined(HAVE_QT_UITOOLS) + PYMODTEST (import_QtUiTools, "import_QtUiTools.py") +#endif + #if QT_VERSION >= 0x50000 PYMODTEST (import_QtWidgets, "import_QtWidgets.py") From 66199958a5575cb3a49217c6ff2a7a975ac06f06 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 27 Feb 2021 00:02:09 +0100 Subject: [PATCH 38/53] Stupid typo fixed --- src/gsiqt/qtbasic/gsiQtUiToolsExternals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h index 49462cbed..3b3c740c9 100644 --- a/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h +++ b/src/gsiqt/qtbasic/gsiQtUiToolsExternals.h @@ -21,7 +21,7 @@ */ #if !defined(HAVE_QT_UITOOLS) -# defined FORCE_LINK_GSI_QTUITOOLS +# define FORCE_LINK_GSI_QTUITOOLS #elif QT_VERSION >= 0x050000 # include "../qt5/QtUiTools/gsiQtExternals.h" #else From 33ae3b0239ebf91e9d2c18e57cee623b7ff098e9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 27 Feb 2021 18:03:37 +0100 Subject: [PATCH 39/53] Added a build system option to enable/disable uitools support as some distributions do not support that --- build.sh | 12 +++++++--- src/gsiqt/qt4/qt4.pro | 6 +++-- src/gsiqt/qt5/qt5.pro | 5 ++-- src/klayout.pri | 23 ++++++++++++++----- .../klayout_main/klayout_main.pro | 3 ++- src/pymod/QtUiTools/QtUiTools.pro | 2 +- src/pymod/pymod.pro | 10 +++++--- 7 files changed, 43 insertions(+), 18 deletions(-) diff --git a/build.sh b/build.sh index c2f1d6bfe..1caeccba9 100755 --- a/build.sh +++ b/build.sh @@ -26,6 +26,7 @@ IS_WINDOWS="no" IS_LINUX="no" HAVE_QTBINDINGS=1 +HAVE_QT_UITOOLS=1 HAVE_64BIT_COORD=0 HAVE_QT=1 HAVE_QT5="" # not set @@ -83,15 +84,18 @@ 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 + ;; -with-64bit-coord) HAVE_64BIT_COORD=1 ;; @@ -207,6 +211,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 +609,7 @@ qmake_options=( PYTHONEXTSUFFIX="$PYTHONEXTSUFFIX" HAVE_PYTHON="$HAVE_PYTHON" HAVE_QTBINDINGS="$HAVE_QTBINDINGS" + HAVE_QT_UITOOLS="$HAVE_QT_UITOOLS" HAVE_64BIT_COORD="$HAVE_64BIT_COORD" HAVE_QT="$HAVE_QT" HAVE_QT5="$HAVE_QT5" diff --git a/src/gsiqt/qt4/qt4.pro b/src/gsiqt/qt4/qt4.pro index 5a420947b..4b511b874 100644 --- a/src/gsiqt/qt4/qt4.pro +++ b/src/gsiqt/qt4/qt4.pro @@ -1,4 +1,6 @@ +include($$PWD/../../klayout.pri) + TEMPLATE = subdirs SUBDIRS = \ @@ -15,8 +17,8 @@ QtSql.depends += QtCore QtDesigner.depends += QtCore QtXml.depends += QtCore -contains(QT_MODULES, uitools) { - # Not all distributions have uitools +equals(HAVE_QT_UITOOLS, "1") { SUBDIRS += QtUiTools QtUiTools.depends += QtCore } + diff --git a/src/gsiqt/qt5/qt5.pro b/src/gsiqt/qt5/qt5.pro index cadc57021..5e4fd0074 100644 --- a/src/gsiqt/qt5/qt5.pro +++ b/src/gsiqt/qt5/qt5.pro @@ -1,4 +1,6 @@ +include($$PWD/../../klayout.pri) + TEMPLATE = subdirs SUBDIRS = \ @@ -25,8 +27,7 @@ QtSvg.depends += QtCore QtWidgets QtXmlPatterns.depends += QtCore QtXml.depends += QtCore -contains(QT_MODULES, uitools) { - # Not all distributions have uitools +equals(HAVE_QT_UITOOLS, "1") { SUBDIRS += QtUiTools QtUiTools.depends += QtCore } diff --git a/src/klayout.pri b/src/klayout.pri index 506c8003d..28ec64ef7 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 } @@ -164,18 +173,20 @@ equals(HAVE_QT, "0") { equals(HAVE_QT5, "1") { QT += designer printsupport widgets - contains(QT_MODULES, "uitools") { - # not all distributions have uitools - QT += uitools - } equals(HAVE_QTBINDINGS, "1") { QT += multimedia multimediawidgets xmlpatterns svg gui } + equals(HAVE_QT_UITOOLS, "1") { + QT += uitools + } } else { - CONFIG += designer uitools + CONFIG += designer + equals(HAVE_QT_UITOOLS, "1") { + CONFIG += uitools + } } - contains(QT_MODULES, "uitools") { + equals(HAVE_QT_UITOOLS, "1") { DEFINES += HAVE_QT_UITOOLS } diff --git a/src/klayout_main/klayout_main/klayout_main.pro b/src/klayout_main/klayout_main/klayout_main.pro index 3b2de1643..acb5aeb23 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) @@ -26,7 +27,7 @@ DEPENDPATH += $$QTBASIC_INC equals(HAVE_QTBINDINGS, "1") { LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner - contains(QT_MODULES, uitools) { + equals(HAVE_QT_UITOOLS, "1") { LIBS += -lklayout_QtUiTools } equals(HAVE_QT5, "1") { diff --git a/src/pymod/QtUiTools/QtUiTools.pro b/src/pymod/QtUiTools/QtUiTools.pro index 200791fd3..c378c58ea 100644 --- a/src/pymod/QtUiTools/QtUiTools.pro +++ b/src/pymod/QtUiTools/QtUiTools.pro @@ -8,7 +8,7 @@ SOURCES = \ HEADERS += \ -contains(QT_MODULES, uitools) { +equals(HAVE_QT_UITOOLS, "1") { LIBS += -lklayout_QtUiTools } diff --git a/src/pymod/pymod.pro b/src/pymod/pymod.pro index 82f6124f1..fecb30b33 100644 --- a/src/pymod/pymod.pro +++ b/src/pymod/pymod.pro @@ -1,4 +1,6 @@ +include($$PWD/../klayout.pri) + TEMPLATE = subdirs SUBDIRS = \ db \ @@ -20,7 +22,6 @@ SUBDIRS = \ QtSql \ QtWidgets \ QtDesigner \ - QtUiTools \ QtMultimedia \ QtPrintSupport \ QtSvg \ @@ -35,13 +36,16 @@ SUBDIRS = \ QtXml \ QtSql \ QtNetwork \ - QtDesigner \ - QtUiTools + QtDesigner } } } +equals(HAVE_QT_UITOOLS, "1") { + SUBDIRS += QtUiTools +} + ALL_DIRS = $$SUBDIRS SUBDIRS += unit_tests From be5714607f3cef8a6b13a7d9a4c7aae57eb9de2d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 27 Feb 2021 19:08:43 +0100 Subject: [PATCH 40/53] Added a build dependency for safer building --- src/plugins/tools/view_25d/view_25d.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/tools/view_25d/view_25d.pro b/src/plugins/tools/view_25d/view_25d.pro index 30278d0c8..b4279b44e 100644 --- a/src/plugins/tools/view_25d/view_25d.pro +++ b/src/plugins/tools/view_25d/view_25d.pro @@ -4,3 +4,5 @@ TEMPLATE = subdirs equals(HAVE_QT5, "1") { SUBDIRS = lay_plugin unit_tests } + +unit_tests.depends += lay_plugin From 77356cd87744bf5a457817a7dc8dfe60e190b11c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 27 Feb 2021 21:31:32 +0100 Subject: [PATCH 41/53] More unit test stability --- src/buddies/unit_tests/bdStrmrunTests.cc | 2 ++ testdata/ruby/basic_testcore.rb | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) 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/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 81011ed18..12b919a0f 100644 --- a/testdata/ruby/basic_testcore.rb +++ b/testdata/ruby/basic_testcore.rb @@ -1460,10 +1460,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 From b353f7db79f54dc01c8bae797cb697e287b46293 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 28 Feb 2021 13:50:33 +0100 Subject: [PATCH 42/53] Test stability for Windows/32bit --- testdata/python/basic.py | 25 ++++++++++++++----------- testdata/ruby/basic_testcore.rb | 9 ++++++++- 2 files changed, 22 insertions(+), 12 deletions(-) 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/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 12b919a0f..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 @@ -2737,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 @@ -2759,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 From 2a9564856b16b7d0941ccac4d675a713db5f7849 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 28 Feb 2021 23:31:06 +0100 Subject: [PATCH 43/53] Fixed Qt-binding less builds --- src/pymod/pymod.pro | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pymod/pymod.pro b/src/pymod/pymod.pro index fecb30b33..71f8ddaaa 100644 --- a/src/pymod/pymod.pro +++ b/src/pymod/pymod.pro @@ -13,6 +13,7 @@ SUBDIRS = \ SUBDIRS += lay equals(HAVE_QTBINDINGS, "1") { + equals(HAVE_QT5, "1") { SUBDIRS += \ @@ -39,11 +40,12 @@ SUBDIRS = \ QtDesigner } - } -} -equals(HAVE_QT_UITOOLS, "1") { - SUBDIRS += QtUiTools + equals(HAVE_QT_UITOOLS, "1") { + SUBDIRS += QtUiTools + } + + } } ALL_DIRS = $$SUBDIRS From 44baeea362d2b41ca2b1cc1f7a267fa709e2e94f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 2 Mar 2021 22:01:08 +0100 Subject: [PATCH 44/53] Disable view25d plugin if OpenGL is not enabled. --- src/plugins/tools/view_25d/view_25d.pro | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/tools/view_25d/view_25d.pro b/src/plugins/tools/view_25d/view_25d.pro index b4279b44e..3eb5a6fad 100644 --- a/src/plugins/tools/view_25d/view_25d.pro +++ b/src/plugins/tools/view_25d/view_25d.pro @@ -1,8 +1,12 @@ TEMPLATE = subdirs -equals(HAVE_QT5, "1") { - SUBDIRS = lay_plugin unit_tests -} +contains(QT_CONFIG, opengl) { -unit_tests.depends += lay_plugin + equals(HAVE_QT5, "1") { + SUBDIRS = lay_plugin unit_tests + } + + unit_tests.depends += lay_plugin + +} From 687059525cfbcee47f6df4126bc35338b3e2e1e4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 2 Mar 2021 23:28:35 +0100 Subject: [PATCH 45/53] Fine-grained Qt module selection for Qt binding and disabling of view_25d plugin without OpenGL --- build.sh | 35 +++++++++ src/gsiqt/qt4/qt4.pro | 30 +++++--- src/gsiqt/qt5/qt5.pro | 54 ++++++++----- src/gsiqt/qtbasic/gsiQtDesignerExternals.h | 4 +- src/gsiqt/qtbasic/gsiQtMultimediaExternals.h | 4 +- src/gsiqt/qtbasic/gsiQtNetworkExternals.h | 4 +- .../qtbasic/gsiQtPrintSupportExternals.h | 4 +- src/gsiqt/qtbasic/gsiQtSqlExternals.h | 4 +- src/gsiqt/qtbasic/gsiQtSvgExternals.h | 4 +- src/gsiqt/qtbasic/gsiQtXmlExternals.h | 4 +- src/gsiqt/qtbasic/gsiQtXmlPatternsExternals.h | 4 +- src/gsiqt/qtbasic/qtbasic.pro | 16 +++- src/klayout.pri | 76 ++++++++++++++++--- .../klayout_main/klayout_main.pro | 37 ++++++++- src/lay/lay/gsiDeclLayHelpDialog.cc | 2 +- src/lay/lay/lay.pro | 5 +- src/pymod/QtUiTools/QtUiTools.pro | 5 +- src/pymod/QtUiTools/QtUiToolsMain.cc | 2 - src/pymod/pymod.pro | 57 +++++++++----- src/pymod/unit_tests/pymod_tests.cc | 19 ++++- src/unit_tests/unit_tests.pro | 4 +- 21 files changed, 292 insertions(+), 82 deletions(-) diff --git a/build.sh b/build.sh index 1caeccba9..79555a24f 100755 --- a/build.sh +++ b/build.sh @@ -27,6 +27,13 @@ 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 @@ -96,6 +103,27 @@ while [ "$*" != "" ]; do -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 ;; @@ -610,6 +638,13 @@ qmake_options=( 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/src/gsiqt/qt4/qt4.pro b/src/gsiqt/qt4/qt4.pro index 4b511b874..5aeee7dfd 100644 --- a/src/gsiqt/qt4/qt4.pro +++ b/src/gsiqt/qt4/qt4.pro @@ -5,17 +5,29 @@ 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 diff --git a/src/gsiqt/qt5/qt5.pro b/src/gsiqt/qt5/qt5.pro index 5e4fd0074..710001c57 100644 --- a/src/gsiqt/qt5/qt5.pro +++ b/src/gsiqt/qt5/qt5.pro @@ -6,26 +6,46 @@ 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 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/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/klayout.pri b/src/klayout.pri index 28ec64ef7..312e0c6a3 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -169,27 +169,81 @@ equals(HAVE_QT, "0") { } else { DEFINES += HAVE_QT - QT += core network xml sql + QT += core xml network + + equals(HAVE_QTBINDINGS, "1") { + # sql isn't needed by the base application + !equals(HAVE_QT_SQL, "0") { + QT += sql + } + } equals(HAVE_QT5, "1") { - QT += designer printsupport widgets + + QT += widgets gui printsupport + equals(HAVE_QTBINDINGS, "1") { - QT += multimedia multimediawidgets xmlpatterns svg gui - } - equals(HAVE_QT_UITOOLS, "1") { - QT += uitools + !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_XML, "0") { + # xmlpatterns isn't needed by the base application + QT += xmlpatterns + } + !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 { - CONFIG += designer - equals(HAVE_QT_UITOOLS, "1") { - CONFIG += uitools + + 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, "1") { + !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_main.pro b/src/klayout_main/klayout_main/klayout_main.pro index acb5aeb23..31ab7eb22 100644 --- a/src/klayout_main/klayout_main/klayout_main.pro +++ b/src/klayout_main/klayout_main/klayout_main.pro @@ -26,11 +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_QT_UITOOLS, "1") { + + 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_QtMultimedia -lklayout_QtPrintSupport -lklayout_QtSvg -lklayout_QtWidgets -lklayout_QtXmlPatterns + + 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/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/pymod/QtUiTools/QtUiTools.pro b/src/pymod/QtUiTools/QtUiTools.pro index c378c58ea..2c1ed0966 100644 --- a/src/pymod/QtUiTools/QtUiTools.pro +++ b/src/pymod/QtUiTools/QtUiTools.pro @@ -8,9 +8,6 @@ SOURCES = \ HEADERS += \ -equals(HAVE_QT_UITOOLS, "1") { - LIBS += -lklayout_QtUiTools -} - +LIBS += -lklayout_QtUiTools LIBS += -lklayout_QtCore diff --git a/src/pymod/QtUiTools/QtUiToolsMain.cc b/src/pymod/QtUiTools/QtUiToolsMain.cc index d70d419d4..7038f2bfa 100644 --- a/src/pymod/QtUiTools/QtUiToolsMain.cc +++ b/src/pymod/QtUiTools/QtUiToolsMain.cc @@ -26,10 +26,8 @@ #include "../../gsiqt/qtbasic/gsiQtCoreExternals.h" FORCE_LINK_GSI_QTCORE -#if defined(HAVE_QT_UITOOLS) # include "../../gsiqt/qtbasic/gsiQtUiToolsExternals.h" FORCE_LINK_GSI_QTUITOOLS -#endif DEFINE_PYMOD(QtUiTools, "QtUiTools", "KLayout/Qt module 'QtUiTools'") diff --git a/src/pymod/pymod.pro b/src/pymod/pymod.pro index 71f8ddaaa..1b1998702 100644 --- a/src/pymod/pymod.pro +++ b/src/pymod/pymod.pro @@ -14,34 +14,49 @@ SUBDIRS = \ 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_UITOOLS, "1") { + !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 9812fa666..2e9d1d590 100644 --- a/src/pymod/unit_tests/pymod_tests.cc +++ b/src/pymod/unit_tests/pymod_tests.cc @@ -94,24 +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/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 } From 9cb7c2cc2a5d2fb2b8ca8350a5a9c13cef7f3e2c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 3 Mar 2021 00:15:12 +0100 Subject: [PATCH 46/53] Fixed a build issue without HAVE_QT_XML --- src/klayout.pri | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/klayout.pri b/src/klayout.pri index 312e0c6a3..550c0cba7 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -180,7 +180,7 @@ equals(HAVE_QT, "0") { equals(HAVE_QT5, "1") { - QT += widgets gui printsupport + QT += widgets gui printsupport xmlpatterns equals(HAVE_QTBINDINGS, "1") { !equals(HAVE_QT_DESIGNER, "0") { @@ -191,10 +191,6 @@ equals(HAVE_QT, "0") { # multimedia isn't needed by the base application QT += multimedia multimediawidgets } - !equals(HAVE_QT_XML, "0") { - # xmlpatterns isn't needed by the base application - QT += xmlpatterns - } !equals(HAVE_QT_SVG, "0") { # svg isn't needed by the base application QT += svg From 0ca3484e986db928ee364b0187419b70bfcd37df Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 4 Mar 2021 22:00:46 +0100 Subject: [PATCH 47/53] Fixed #739 (display bug) --- src/laybasic/laybasic/layRedrawThreadWorker.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 && From 3a9a7e81fb11551f5cfe9826b9bbb59c68ab9279 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 4 Mar 2021 23:11:54 +0100 Subject: [PATCH 48/53] Implemented new layout dialog with intial layers Plus small enhancements: the first layer will be selected initially, so you can starting drawing immediately. --- src/lay/lay/layMainWindow.cc | 21 ++- src/lay/lay/laySearchReplaceDialog.cc | 2 +- .../laybasic/NewLayoutPropertiesDialog.ui | 152 ++++++++++-------- src/laybasic/laybasic/layDialogs.cc | 27 +++- src/laybasic/laybasic/layDialogs.h | 2 +- src/laybasic/laybasic/layLayoutView.cc | 30 ++++ 6 files changed, 160 insertions(+), 74 deletions(-) diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 4b01a130a..d40814b05 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -2525,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/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/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/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/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 (); From beefaf40f58e94089d29d07b523ca62ced37a464 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 4 Mar 2021 23:21:50 +0100 Subject: [PATCH 49/53] Added test to discover that the issue is already fixed. --- src/lay/unit_tests/laySessionTests.cc | 4 ++++ 1 file changed, 4 insertions(+) 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) { From 175fde2562baa008e2019df8f571d819ee1a3a67 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 7 Mar 2021 22:19:23 +0100 Subject: [PATCH 50/53] Enabled shortcuts for actions in macro editor widget For example, Ctrl+S was captured by the editor rather than forwarded to the action. --- src/lay/lay/layMacroEditorPage.cc | 96 +++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 12 deletions(-) diff --git a/src/lay/lay/layMacroEditorPage.cc b/src/lay/lay/layMacroEditorPage.cc index 10fe4c9e6..ad11a8076 100644 --- a/src/lay/lay/layMacroEditorPage.cc +++ b/src/lay/lay/layMacroEditorPage.cc @@ -1548,6 +1548,71 @@ MacroEditorPage::return_pressed () 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) { @@ -1555,9 +1620,16 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) if (event->type () == QEvent::ShortcutOverride) { - // override shortcuts - event->accept (); - return true; + // 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) { @@ -1574,7 +1646,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return false; // should not happen } - if (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) { + if (is_tab_key (ke)) { if (mp_completer_popup->isVisible ()) { complete (); @@ -1583,15 +1655,15 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return tab_key_pressed (); } - } else if ((ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) { + } else if (is_backtab_key (ke)) { return back_tab_key_pressed (); - } else if (ke->key () == Qt::Key_Backspace) { + } else if (is_backspace_key (ke)) { return backspace_pressed (); - } else if (ke->key () == Qt::Key_Escape) { + } else if (is_escape_key (ke)) { // Handle Esc to return to the before-find position and clear the selection or to hide popup @@ -1606,7 +1678,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return true; - } else if (ke->key () == Qt::Key_Return) { + } else if (is_return_key (ke)) { if (mp_completer_popup->isVisible ()) { complete (); @@ -1615,7 +1687,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return return_pressed (); } - } else if (ke->key () == Qt::Key_F1) { + } else if (is_help_key (ke)) { QTextCursor c = mp_text->textCursor (); if (c.selectionStart () == c.selectionEnd ()) { @@ -1625,19 +1697,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event) return true; - } else if (mp_completer_popup->isVisible () && (ke->key () == Qt::Key_Up || ke->key () == Qt::Key_Down)) { + } else if (mp_completer_popup->isVisible () && (is_up_key (ke) || is_down_key (ke))) { QApplication::sendEvent (mp_completer_list, event); return true; - } else if (ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0) { + } else if (is_find_key (ke)) { QTextCursor c = mp_text->textCursor (); emit search_requested (c.selectedText ()); return true; - } else if (ke->key () == Qt::Key_F3) { + } else if (is_find_next_key (ke)) { // Jump to the next occurence of the search string From a7c263bc988ab4d30ffa45384b798ab057ac8f08 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 7 Mar 2021 22:20:18 +0100 Subject: [PATCH 51/53] Fixed an uninitialized member. --- src/laybasic/laybasic/layLibrariesView.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index 322ce3ba6..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) From 9e3183250f10aafada3ff64f4097e84c45e3964a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 7 Mar 2021 22:20:28 +0100 Subject: [PATCH 52/53] Fixed some flaws in the layer list - sometimes, layers which were supposed to be hidden were still shown (e.g. after paste, "add other layer views" etc.) - sometimes, layers were only partially hightlighted due to invalid persistent model indexes. --- src/laybasic/laybasic/layLayerControlPanel.cc | 19 +++++++++++++++---- src/laybasic/laybasic/layLayerControlPanel.h | 3 ++- src/laybasic/laybasic/layLayerTreeModel.cc | 19 +++++++++++++++++-- src/laybasic/laybasic/layLayerTreeModel.h | 5 +++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/laybasic/laybasic/layLayerControlPanel.cc b/src/laybasic/laybasic/layLayerControlPanel.cc index 0316d6711..72ff771d0 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.cc +++ b/src/laybasic/laybasic/layLayerControlPanel.cc @@ -204,10 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage mp_view (view), m_needs_update (true), m_tabs_need_update (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_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags), m_no_stipples (false) { setObjectName (QString::fromUtf8 (name)); @@ -1661,7 +1661,8 @@ LayerControlPanel::set_text_color (QColor c) void LayerControlPanel::update_hidden_flags () { - m_do_update_hidden_flags_dm (); + m_hidden_flags_need_update = true; + m_do_update_content_dm (); } void @@ -1688,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 @@ -1718,6 +1720,7 @@ LayerControlPanel::cancel_updates () { m_in_update = false; m_needs_update = false; + m_hidden_flags_need_update = false; m_tabs_need_update = false; } @@ -1833,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 ()) { @@ -1875,6 +1878,14 @@ LayerControlPanel::do_update_content () } else { mp_model->signal_data_changed (); // this makes the view redraw the data } + + if (m_hidden_flags_need_update) { + + do_update_hidden_flags (); + + m_hidden_flags_need_update = false; + + } } void @@ -2007,7 +2018,7 @@ LayerControlPanel::update_required (int f) } if ((f & 3) != 0) { - m_do_update_hidden_flags_dm (); + 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 8d235c877..f8124f8df 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.h +++ b/src/laybasic/laybasic/layLayerControlPanel.h @@ -341,10 +341,11 @@ private: lay::LayoutView *mp_view; bool m_needs_update; bool m_tabs_need_update; + 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, m_do_update_hidden_flags_dm; + tl::DeferredMethod m_do_update_content_dm; std::set m_expanded; bool m_no_stipples; QLabel *m_no_stipples_label; diff --git a/src/laybasic/laybasic/layLayerTreeModel.cc b/src/laybasic/laybasic/layLayerTreeModel.cc index c5c6f2b99..66efa50e9 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.cc +++ b/src/laybasic/laybasic/layLayerTreeModel.cc @@ -421,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? @@ -433,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 (); } diff --git a/src/laybasic/laybasic/layLayerTreeModel.h b/src/laybasic/laybasic/layLayerTreeModel.h index 10404160c..12bba517e 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.h +++ b/src/laybasic/laybasic/layLayerTreeModel.h @@ -235,11 +235,12 @@ public: /** * @brief emit a layoutChanged signal */ - void signal_layer_changed (); + void signal_layers_changed (); signals: /** - * @brief This signal is emitted to indicate + * @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 (); From 184f2bee50c5ede22f4dbd3c7d4cab80655786d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Sun, 14 Mar 2021 12:27:36 +0100 Subject: [PATCH 53/53] Smooth bug (#740) * Smoothing function: provide ability to keep horizontal/vertical lines (important for cut lines) * Introducting API compatibility macros for generic plugins. --- src/db/db/dbPolygonTools.cc | 12 +-- src/db/db/dbPolygonTools.h | 7 +- src/db/db/dbRegion.cc | 8 +- src/db/db/dbRegion.h | 4 +- src/db/db/dbRegionUtils.cc | 4 +- src/db/db/dbRegionUtils.h | 3 +- src/db/db/gsiDeclDbCompoundOperation.cc | 9 ++- src/db/db/gsiDeclDbPolygon.cc | 9 ++- src/db/db/gsiDeclDbRegion.cc | 6 +- src/db/unit_tests/dbDeepRegionTests.cc | 4 +- src/db/unit_tests/dbPolygonToolsTests.cc | 70 +++++++++++++----- .../drc/built-in-macros/_drc_complex_ops.rb | 10 ++- src/edt/edt/edtMainService.cc | 2 +- testdata/algo/deep_region_au11.gds | Bin 16538 -> 19378 bytes testdata/python/dbPolygonTest.py | 3 + testdata/ruby/dbPolygonTest.rb | 3 + 16 files changed, 105 insertions(+), 49 deletions(-) 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/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 0d2ed0de1..9f0e6f513 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -868,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 89392bd0d..f1da9196d 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -504,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; @@ -517,6 +517,7 @@ public: private: db::Coord m_d; + bool m_keep_hv; db::MagnificationReducer m_vars; }; diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index 05ff115a0..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) @@ -572,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" 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/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 91ee1dfec..6614be324 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1412,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 " @@ -1423,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/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index db5607c5b..6e24ce748 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -739,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 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/testdata/algo/deep_region_au11.gds b/testdata/algo/deep_region_au11.gds index 7641827146cec428d073536a386ffa541b330680..cb37c402b7f4449ab5bb003508f1734bff2af8d8 100644 GIT binary patch delta 2527 zcmah~X>g5K7=FH+xY0^-Z-)xm_2F=V<`<j1ABcRj zTU~0=F0o^y$kAw^V`EH%0*S+cE~&(8Tuaet`RKe`r9}@YNA@o@F;)PxU zB%%pvVw&LLNo4wrxn{?W>ty>I4^Fp!`dhE*J$<$*+WjUlVgsEqso4+dY$Wj38B5cV z)P9fxMmARk0quG{`)h6MWBRx@)8^WZcIOq7qH1xgGE`}c)-FH%R}sK&xA#{ELW7hu z&=vGA6{dy+ZcJAWpnH*;`6W;?Ndvr#We{iy=vKr{$Ok__j_4H%e#W29B z#50zT)%6x0e~0TcnY_<{A#qIFRUq?$mAs4-Pw{mobrsN;$vqMY^l2}0asdnF0%_5Y zE}W427Dj9)CL;#zd$S5k$TO2wQNv1FOm6L2HLQZTlbR=EIj&9z2YZr}U%bzIKY3_A znwRFMdFuRIyn&1pT>lCfu!HByt)KqZYkE(gZHjgORMrM1JTwb<`#gOG067aRNptGp zN1?b-r^bc2Jat+&{qN~EkLlyuOq**r+MQQQN~)#R5^Jfoi$BTa$ySkvD~LBm z9#?4uTHa7*O0cKC2#81rW*oI}dKi(tF_kqK#SWkNA<&+MoX;AKISu4JVIPrv?j=sS zP8Pba0AnaXCa2n{HVkZoW^D!BB*1rE&zivik8y811&HEQ`9=JwrFZ%irlzQeagOjQ z6fnLkFpZTII~sVOFM{sn`ZF5UjZ|0Py?lbAVKm#zU=|WHL>^p(;j>ZXULP2s9(Upy zBxSzEu5Uai@_VKBAab)-V*#%=wg_yH>^XdRgv8T#;XTqzL?KoB>J4y9QbLGqw znZnWuA}(ZY1lo~mmu=#UFK$)$R`JN&C}l7 z1N1jp?Mw^yXp=F#yuhB-UsX3+ciz@x;huA$Gom delta 383 zcmdlqopDwpV-y1$0~1pOgA5}R`(p+s24My<26hH@WHti_6Pu5x69ax7l1YITx*-hRjXgpb$iFb3I&=hVL{H8Oo zv9UQaFtFfPwRxR_0ORC;iVl8&rRpWm2DFidg#iG~cvWNo 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/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 )