From 96f3ce65c1494f7215299defd11cef0a631f7090 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 26 May 2022 00:07:22 +0200 Subject: [PATCH 01/45] First steps towards LayoutView for headless mode, optional arguments for Layout#load_layout and MainWindow#load_layout --- src/img/img/imgNavigator.cc | 11 +- src/lay/lay/gsiDeclLayMainWindow.cc | 16 +- src/lay/lay/layMainWindow.cc | 24 +- src/lay/lay/layNavigator.cc | 21 +- src/lay/lay/layViewWidgetStack.cc | 10 +- .../laybasic/gsiDeclLayLayoutViewBase.cc | 16 +- src/laybasic/laybasic/layLayoutCanvas.cc | 6 +- src/laybasic/laybasic/layLayoutCanvas.h | 4 - src/laybasic/laybasic/layLayoutViewBase.cc | 35 +- src/laybasic/laybasic/layLayoutViewBase.h | 15 +- src/laybasic/laybasic/layViewObject.cc | 29 +- src/laybasic/laybasic/layViewObject.h | 4 - src/layview/layview/layLayoutView_qt.cc | 408 ++++++++++++------ src/layview/layview/layLayoutView_qt.h | 230 ++++++---- 14 files changed, 478 insertions(+), 351 deletions(-) diff --git a/src/img/img/imgNavigator.cc b/src/img/img/imgNavigator.cc index 634b8bd1e..d01f189a9 100644 --- a/src/img/img/imgNavigator.cc +++ b/src/img/img/imgNavigator.cc @@ -52,13 +52,14 @@ img::Object * Navigator::setup (lay::Dispatcher *root, img::Object *img) { mp_view = new lay::LayoutView (0, false, root, this, "img_navigator_view", lay::LayoutView::LV_Naked + lay::LayoutView::LV_NoZoom + lay::LayoutView::LV_NoServices + lay::LayoutView::LV_NoGrid); - mp_view->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - mp_view->setMinimumWidth (100); - mp_view->setMinimumHeight (100); + tl_assert (mp_view->widget ()); + mp_view->widget ()->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); + mp_view->widget ()->setMinimumWidth (100); + mp_view->widget ()->setMinimumHeight (100); QVBoxLayout *layout = new QVBoxLayout (this); - layout->addWidget (mp_view); - layout->setStretchFactor (mp_view, 1); + layout->addWidget (mp_view->widget ()); + layout->setStretchFactor (mp_view->widget (), 1); layout->setContentsMargins (0, 0, 0, 0); layout->setSpacing (0); setLayout (layout); diff --git a/src/lay/lay/gsiDeclLayMainWindow.cc b/src/lay/lay/gsiDeclLayMainWindow.cc index 17fa2f064..6443f694b 100644 --- a/src/lay/lay/gsiDeclLayMainWindow.cc +++ b/src/lay/lay/gsiDeclLayMainWindow.cc @@ -547,7 +547,7 @@ Class decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M "This version was introduced in version 0.22.\n" "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview.\n" ) + - gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("mode"), + gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("mode", 1), "@brief Loads a new layout\n" "\n" "@param filename The name of the file to load\n" @@ -561,9 +561,9 @@ Class decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M "This version will use the initial technology and the default reader options. " "Others versions are provided which allow specification of technology and reader options explicitly.\n" "\n" - "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview.\n" + "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview. The 'mode' argument has been made optional in version 0.28.\n" ) + - gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, const std::string &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("tech"), gsi::arg ("mode"), + gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, const std::string &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("tech"), gsi::arg ("mode", 1), "@brief Loads a new layout and associate it with the given technology\n" "\n" "@param filename The name of the file to load\n" @@ -575,12 +575,12 @@ Class decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M "into a new view (mode 1) or adding the layout to the current view (mode 2).\n" "In mode 1, the new view is made the current one.\n" "\n" - "If the technology name is not a valid technology name, the default technology will be used.\n" + "If the technology name is not a valid technology name, the default technology will be used. The 'mode' argument has been made optional in version 0.28.\n" "\n" "This version was introduced in version 0.22.\n" "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview.\n" ) + - gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, const db::LoadLayoutOptions &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("mode"), + gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, const db::LoadLayoutOptions &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("mode", 1), "@brief Loads a new layout with the given options\n" "\n" "@param filename The name of the file to load\n" @@ -593,9 +593,9 @@ Class decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M "In mode 1, the new view is made the current one.\n" "\n" "This version was introduced in version 0.22.\n" - "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview.\n" + "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview. The 'mode' argument has been made optional in version 0.28.\n" ) + - gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, const db::LoadLayoutOptions &, const std::string &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("tech"), gsi::arg ("mode"), + gsi::method ("load_layout", (lay::CellViewRef (lay::MainWindow::*) (const std::string &, const db::LoadLayoutOptions &, const std::string &, int)) &lay::MainWindow::load_layout, gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("tech"), gsi::arg ("mode", 1), "@brief Loads a new layout with the given options and associate it with the given technology\n" "\n" "@param filename The name of the file to load\n" @@ -611,7 +611,7 @@ Class decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M "If the technology name is not a valid technology name, the default technology will be used.\n" "\n" "This version was introduced in version 0.22.\n" - "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview.\n" + "Starting with version 0.25, this method returns a cellview object that can be modified to configure the cellview. The 'mode' argument has been made optional in version 0.28.\n" ) + gsi::method ("clone_current_view", &lay::MainWindow::clone_current_view, "@brief Clones the current view and make it current\n" diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index b7bdabddf..a7e412abc 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -3368,21 +3368,23 @@ MainWindow::create_layout (const std::string &technology, int mode) void MainWindow::add_view (lay::LayoutView *view) { - connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); - connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); - connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); - connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); - connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); - connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); - connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); - connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int))); + tl_assert (view->widget ()); + + connect (view->widget (), SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); + connect (view->widget (), SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); + connect (view->widget (), SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); + connect (view->widget (), SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); + connect (view->widget (), SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); + connect (view->widget (), SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); + connect (view->widget (), SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); + connect (view->widget (), SIGNAL (mode_change (int)), this, SLOT (select_mode (int))); mp_views.push_back (view); // we must resize the widget here to set the geometry properly. // This is required to make zoom_fit work. - view->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ()); - view->show (); + view->widget ()->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ()); + view->widget ()->show (); } int @@ -3563,7 +3565,7 @@ MainWindow::view_title_changed () update_tab_title (i); } - if (sender () == current_view ()) { + if (current_view () && sender () == current_view ()->widget ()) { update_window_title (); } } diff --git a/src/lay/lay/layNavigator.cc b/src/lay/lay/layNavigator.cc index 77b19d25a..6977e9702 100644 --- a/src/lay/lay/layNavigator.cc +++ b/src/lay/lay/layNavigator.cc @@ -76,7 +76,11 @@ public: // replace by "real" background color if required if (! c.is_valid ()) { - c = lay::Color (mp_view->palette ().color (QPalette::Normal, QPalette::Base).rgb ()); + if (mp_view->widget ()) { + c = lay::Color (mp_view->widget ()->palette ().color (QPalette::Normal, QPalette::Base).rgb ()); + } else { + c = lay::Color (0xffffff); // white + } } lay::Color contrast; @@ -626,8 +630,8 @@ Navigator::view_closed (int index) void Navigator::resizeEvent (QResizeEvent *) { - if (mp_view) { - mp_view->setGeometry (mp_placeholder_label->geometry ()); + if (mp_view && mp_view->widget ()) { + mp_view->widget ()->setGeometry (mp_placeholder_label->geometry ()); } } @@ -652,11 +656,12 @@ Navigator::attach_view (LayoutView *view) if (mp_source_view) { mp_view = new LayoutView (0, false, mp_source_view, this, "navigator", LayoutView::LV_Naked + LayoutView::LV_NoZoom + LayoutView::LV_NoServices + LayoutView::LV_NoGrid); - mp_view->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - mp_view->setMinimumWidth (100); - mp_view->setMinimumHeight (100); - mp_view->setGeometry (mp_placeholder_label->geometry ()); - mp_view->show (); + tl_assert (mp_view->widget ()); + mp_view->widget ()->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); + mp_view->widget ()->setMinimumWidth (100); + mp_view->widget ()->setMinimumHeight (100); + mp_view->widget ()->setGeometry (mp_placeholder_label->geometry ()); + mp_view->widget ()->show (); mp_service = new NavigatorService (mp_view); mp_view->view_object_widget ()->activate (mp_service); diff --git a/src/lay/lay/layViewWidgetStack.cc b/src/lay/lay/layViewWidgetStack.cc index 430acef9f..d99f3c098 100644 --- a/src/lay/lay/layViewWidgetStack.cc +++ b/src/lay/lay/layViewWidgetStack.cc @@ -42,8 +42,10 @@ ViewWidgetStack::ViewWidgetStack (QWidget *parent, const char *name) void ViewWidgetStack::add_widget (LayoutView *w) { + tl_assert (w->widget ()); + m_widgets.push_back (w); - w->setParent (this); + w->widget ()->setParent (this); resize_children (); raise_widget (m_widgets.size () - 1); @@ -64,7 +66,7 @@ void ViewWidgetStack::raise_widget (size_t index) { if (index < m_widgets.size ()) { mp_bglabel->hide (); - m_widgets [index]->show (); + m_widgets [index]->widget ()->show (); } else { mp_bglabel->show (); } @@ -72,7 +74,7 @@ void ViewWidgetStack::raise_widget (size_t index) size_t i = 0; for (std::vector ::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child, ++i) { if (i != index) { - (*child)->hide (); + (*child)->widget ()->hide (); } } } @@ -95,7 +97,7 @@ void ViewWidgetStack::resize_children () { // set the geometry of all children for (std::vector ::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child) { - (*child)->setGeometry (0, 0, width (), height ()); + (*child)->widget ()->setGeometry (0, 0, width (), height ()); } mp_bglabel->setGeometry (0, 0, width (), height ()); } diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc index b13ae2f36..b6ec122f3 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc @@ -771,7 +771,7 @@ LAYBASIC_PUBLIC Class decl_LayoutViewBase (QT_EXTERNAL_BASE "If a layout is shared between multiple cellviews (which may happen due to a clone of the layout view\n" "for example), all cellviews are renamed.\n" ) + - gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("technology"), gsi::arg ("add_cellview"), + gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("technology"), gsi::arg ("add_cellview", true), "@brief Loads a (new) file into the layout view with the given technology\n" "\n" "Loads the file given by the \"filename\" parameter and associates it with the given technology.\n" @@ -781,9 +781,9 @@ LAYBASIC_PUBLIC Class decl_LayoutViewBase (QT_EXTERNAL_BASE "\n" "@return The index of the cellview loaded.\n" "\n" - "This version has been introduced in version 0.22.\n" + "This version has been introduced in version 0.22. The 'add_cellview' argument has been made optional in version 0.28.\n" ) + - gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("add_cellview"), + gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("options"), gsi::arg ("add_cellview", true), "@brief Loads a (new) file into the layout view\n" "\n" "Loads the file given by the \"filename\" parameter.\n" @@ -793,9 +793,9 @@ LAYBASIC_PUBLIC Class decl_LayoutViewBase (QT_EXTERNAL_BASE "\n" "@return The index of the cellview loaded.\n" "\n" - "This method has been introduced in version 0.18.\n" + "This method has been introduced in version 0.18. The 'add_cellview' argument has been made optional in version 0.28.\n" ) + - gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("technology"), gsi::arg ("add_cellview"), + gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("technology"), gsi::arg ("add_cellview", true), "@brief Loads a (new) file into the layout view with the given technology\n" "\n" "Loads the file given by the \"filename\" parameter and associates it with the given technology.\n" @@ -804,16 +804,16 @@ LAYBASIC_PUBLIC Class decl_LayoutViewBase (QT_EXTERNAL_BASE "\n" "@return The index of the cellview loaded.\n" "\n" - "This version has been introduced in version 0.22.\n" + "This version has been introduced in version 0.22. The 'add_cellview' argument has been made optional in version 0.28.\n" ) + - gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("add_cellview"), + gsi::method ("load_layout", static_cast (&lay::LayoutViewBase::load_layout), gsi::arg ("filename"), gsi::arg ("add_cellview", true), "@brief Loads a (new) file into the layout view\n" "\n" "Loads the file given by the \"filename\" parameter.\n" "The add_cellview param controls whether to create a new cellview (true)\n" "or clear all cellviews before (false).\n" "\n" - "@return The index of the cellview loaded.\n" + "@return The index of the cellview loaded. The 'add_cellview' argument has been made optional in version 0.28.\n" ) + gsi::method ("active_cellview", static_cast (&lay::LayoutViewBase::active_cellview_ref), "@brief Gets the active cellview (shown in hierarchy browser)\n" diff --git a/src/laybasic/laybasic/layLayoutCanvas.cc b/src/laybasic/laybasic/layLayoutCanvas.cc index 22bddfc51..df8448c3f 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.cc +++ b/src/laybasic/laybasic/layLayoutCanvas.cc @@ -274,13 +274,8 @@ invert (unsigned char *data, unsigned int width, unsigned int height) } } -#if defined(HAVE_QT) -LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutViewBase *view, const char *name) - : lay::ViewObjectWidget (parent, name), -#else LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view) : lay::ViewObjectWidget (), -#endif mp_view (view), mp_image (0), mp_image_bg (0), mp_image_fg (0), @@ -300,6 +295,7 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view) #if QT_VERSION > 0x050000 m_dpr = devicePixelRatio (); #endif + setObjectName (QString::fromUtf8 ("canvas")); #endif // The gamma value used for subsampling: something between 1.8 and 2.2. diff --git a/src/laybasic/laybasic/layLayoutCanvas.h b/src/laybasic/laybasic/layLayoutCanvas.h index c66ac1fcd..2024692e1 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.h +++ b/src/laybasic/laybasic/layLayoutCanvas.h @@ -144,11 +144,7 @@ Q_OBJECT #endif public: -#if defined(HAVE_QT) - LayoutCanvas (QWidget *parent, lay::LayoutViewBase *view, const char *name = "canvas"); -#else LayoutCanvas (lay::LayoutViewBase *view); -#endif ~LayoutCanvas (); void set_colors (lay::Color background, lay::Color foreground, lay::Color active); diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index f6f1da238..f91536907 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -235,11 +235,8 @@ struct OpDeleteLayerProps const double animation_interval = 0.5; -LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : -#if defined(HAVE_QT) - QFrame (0), -#endif - lay::Dispatcher (plugin_parent, false /*not standalone*/), +LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) + : lay::Dispatcher (plugin_parent, false /*not standalone*/), mp_ui (0), m_editable (editable), m_options (options), @@ -251,15 +248,8 @@ LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin init (manager); } -#if defined(HAVE_QT) -LayoutViewBase::LayoutViewBase (QWidget *parent, lay::LayoutView *ui, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : -#else -LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : -#endif -#if defined(HAVE_QT) - QFrame (parent), -#endif - lay::Dispatcher (plugin_parent, false /*not standalone*/), +LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) + : lay::Dispatcher (plugin_parent, false /*not standalone*/), mp_ui (ui), m_editable (editable), m_options (options), @@ -271,15 +261,8 @@ LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, db::Manager *manager, bool init (manager); } -#if defined(HAVE_QT) -LayoutViewBase::LayoutViewBase (QWidget *parent, lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : -#else -LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : -#endif -#if defined(HAVE_QT) - QFrame (parent), -#endif - lay::Dispatcher (plugin_parent, false /*not standalone*/), +LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) + : lay::Dispatcher (plugin_parent, false /*not standalone*/), mp_ui (ui), m_editable (editable), m_options (options), @@ -405,11 +388,7 @@ LayoutViewBase::init (db::Manager *mgr) m_layer_properties_lists.back ()->attach_view (this, (unsigned int) (m_layer_properties_lists.size () - 1)); m_current_layer_list = 0; -#if defined(HAVE_QT) - mp_canvas = new lay::LayoutCanvas (widget (), this); -#else mp_canvas = new lay::LayoutCanvas (this); -#endif // occupy services and editables: // these services get deleted by the canvas destructor automatically: @@ -3375,7 +3354,7 @@ LayoutViewBase::box () const QWidget * LayoutViewBase::widget () { - return this; + return 0; } #endif diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index f15239fe9..0e1fa29a7 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -155,9 +155,6 @@ struct LAYBASIC_PUBLIC LayerDisplayProperties * It manages the layer display list, bookmark list etc. */ class LAYBASIC_PUBLIC LayoutViewBase : -#if defined(HAVE_QT) - public QFrame, -#endif public lay::Editables, public lay::Dispatcher { @@ -195,20 +192,12 @@ public: /** * @brief Constructor */ -#if defined(HAVE_QT) - LayoutViewBase (QWidget *parent, lay::LayoutView *ui, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); -#else LayoutViewBase (lay::LayoutView *ui, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); -#endif /** * @brief Constructor (clone from another view) */ -#if defined(HAVE_QT) - LayoutViewBase (QWidget *widget, lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); -#else LayoutViewBase (lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); -#endif /** * @brief Destructor @@ -1648,7 +1637,7 @@ public: void absolute_coordinates (bool f); /** - * @brief Get the view object widget + * @brief Get the view object widget (the canvas where the layout is drawn and view objects are placed) * * This method intentionally delivers the ViewObjectWidget, not the * LayoutCanvas to emphasize that the LayoutCanvas object shall not @@ -2638,7 +2627,7 @@ public: /** * @brief Gets the QWidget interface */ - QWidget *widget (); + virtual QWidget *widget (); #endif /** diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index bd4694ab5..9577f9fcb 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -209,9 +209,10 @@ ViewService::set_cursor (lay::Cursor::cursor_shape cursor) // --------------------------------------------------------------- // ViewObjectWidget implementation +ViewObjectWidget::ViewObjectWidget () #if defined(HAVE_QT) -ViewObjectWidget::ViewObjectWidget (QWidget *parent, const char *name) - : QWidget (parent), + : QWidget (), +#endif m_view_objects_dismissed (false), m_needs_update_static (false), m_needs_update_bg (false), @@ -226,31 +227,13 @@ ViewObjectWidget::ViewObjectWidget (QWidget *parent, const char *name) m_widget_height (0), m_image_updated (false) { - setMouseTracking (true); - setObjectName (QString::fromUtf8 (name)); +#if defined(HAVE_QT) + setMouseTracking (true); setAcceptDrops (true); +#endif m_objects.changed ().add (this, &ViewObjectWidget::objects_changed); } -#else -ViewObjectWidget::ViewObjectWidget () - : m_view_objects_dismissed (false), - m_needs_update_static (false), - m_needs_update_bg (false), - mp_active_service (0), - m_mouse_pressed_state (false), - m_mouse_buttons (0), - m_in_mouse_move (false), - m_mouse_inside (false), - m_cursor (lay::Cursor::none), - m_default_cursor (lay::Cursor::none), - m_widget_width (500), - m_widget_height (500), - m_image_updated (false) -{ - m_objects.changed ().add (this, &ViewObjectWidget::objects_changed); -} -#endif ViewObjectWidget::~ViewObjectWidget () { diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index 1df6d04b0..e6997d139 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -583,11 +583,7 @@ public: /** * @brief ctor */ -#if defined(HAVE_QT) - ViewObjectWidget (QWidget *view, const char *name); -#else ViewObjectWidget (); -#endif /** * @brief dtor diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc index e8805b1b3..b9607b786 100644 --- a/src/layview/layview/layLayoutView_qt.cc +++ b/src/layview/layview/layLayoutView_qt.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include "tlInternational.h" #include "tlExpression.h" @@ -84,10 +85,107 @@ #include "gtf.h" #include +#include namespace lay { +// ------------------------------------------------------------- +// LayoutViewFrame implementation + +LayoutViewFrame::LayoutViewFrame (QWidget *parent, lay::LayoutView *view) + : QFrame (parent), mp_view (view) +{ + // .. nothing yet .. +} + +QSize +LayoutViewFrame::sizeHint () const +{ + return mp_view->size_hint (); +} + +bool +LayoutViewFrame::eventFilter(QObject *obj, QEvent *event) +{ + bool taken = false; + bool res = mp_view->event_filter (obj, event, taken); + if (taken) { + return res; + } else { + return QFrame::eventFilter (obj, event); + } +} + +void LayoutViewFrame::showEvent (QShowEvent *) +{ + mp_view->show_event (); +} + +void LayoutViewFrame::hideEvent (QHideEvent *) +{ + mp_view->hide_event (); +} + +// ------------------------------------------------------------- +// LayoutViewConnector implementation + +LayoutViewSignalConnector::LayoutViewSignalConnector (QObject *parent, lay::LayoutView *view) + : QObject (parent), mp_view (view) +{ + // .. nothing yet .. +} + +void LayoutViewSignalConnector::active_cellview_changed (int index) +{ + mp_view->active_cellview_changed (index); +} + +void LayoutViewSignalConnector::active_library_changed (int index) +{ + mp_view->active_cellview_changed (index); +} + +void LayoutViewSignalConnector::side_panel_destroyed () +{ + mp_view->side_panel_destroyed (sender ()); +} + +void LayoutViewSignalConnector::select_cell_dispatch (const lay::LayoutViewBase::cell_path_type &path, int cellview_index) +{ + mp_view->select_cell_dispatch (path, cellview_index); +} + +void LayoutViewSignalConnector::current_layer_changed_slot (const lay::LayerPropertiesConstIterator &iter) +{ + mp_view->current_layer_changed_slot (iter); +} + +void LayoutViewSignalConnector::timer () +{ + mp_view->timer (); +} + +void LayoutViewSignalConnector::layer_tab_changed () +{ + mp_view->layer_tab_changed (); +} + +void LayoutViewSignalConnector::layer_order_changed () +{ + mp_view->layer_order_changed (); +} + +void LayoutViewSignalConnector::min_hier_changed (int i) +{ + mp_view->min_hier_changed (i); +} + +void LayoutViewSignalConnector::max_hier_changed (int i) +{ + mp_view->max_hier_changed (i); +} + // ------------------------------------------------------------- const int timer_interval = 10; @@ -95,35 +193,37 @@ const int timer_interval = 10; static LayoutView *ms_current = 0; LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options) - : LayoutViewBase (parent, this, manager, editable, plugin_parent, options), + : LayoutViewBase (this, manager, editable, plugin_parent, options), + mp_widget (0), dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages) { // ensures the deferred method scheduler is present tl::DeferredMethodScheduler::instance (); - setObjectName (QString::fromUtf8(name)); - init_ui (); + init_ui (parent, name); } LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options) - : LayoutViewBase (parent, this, source, manager, editable, plugin_parent, options), + : LayoutViewBase (this, source, manager, editable, plugin_parent, options), + mp_widget (0), dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages) { // ensures the deferred method scheduler is present tl::DeferredMethodScheduler::instance (); - setObjectName (QString::fromUtf8 (name)); - init_ui (); + init_ui (parent, name); bookmarks (source->bookmarks ()); set_active_cellview_index (source->active_cellview_index ()); } bool -LayoutView::eventFilter(QObject *obj, QEvent *event) +LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken) { if (obj == mp_min_hier_spbx || obj == mp_max_hier_spbx) { + taken = true; + // Makes the min/max spin boxes accept only numeric and some control keys .. QKeyEvent *keyEvent = dynamic_cast(event); if (keyEvent && @@ -133,13 +233,11 @@ LayoutView::eventFilter(QObject *obj, QEvent *event) keyEvent->key () != Qt::Key_Backspace && (keyEvent->key () < Qt::Key_0 || keyEvent->key () > Qt::Key_9)) { return true; - } else { - return false; } - } else { - return QFrame::eventFilter (obj, event); } + + return false; } void @@ -163,13 +261,21 @@ LayoutView::init_menu () } void -LayoutView::init_ui () +LayoutView::init_ui (QWidget *parent, const char *name) { +#if QT_VERSION < 0x50000 + bool has_gui = (QApplication::type () != Qt::Tty); +#else + bool has_gui = (qGuiApp != 0); +#endif + m_activated = true; m_always_show_source = false; m_always_show_ld = true; m_always_show_layout_index = false; + mp_widget = 0; + mp_connector = 0; mp_timer = 0; mp_left_frame = 0; mp_control_panel = 0; @@ -184,125 +290,126 @@ LayoutView::init_ui () mp_min_hier_spbx = 0; mp_max_hier_spbx = 0; - QVBoxLayout *vbl = new QVBoxLayout (this); - vbl->setContentsMargins (0, 0, 0, 0); - vbl->setSpacing (0); - vbl->addWidget (view_object_widget ()); + if (has_gui) { - if ((options () & LV_NoHierarchyPanel) == 0 && (options () & LV_Naked) == 0) { + mp_widget = new LayoutViewFrame (parent, this); + mp_widget->setObjectName (QString::fromUtf8 (name)); + view_object_widget ()->setParent (mp_widget); - QFrame *hierarchy_frame = new QFrame (0); - hierarchy_frame->setObjectName (QString::fromUtf8 ("left")); - mp_hierarchy_frame = hierarchy_frame; - QVBoxLayout *left_frame_ly = new QVBoxLayout (hierarchy_frame); - left_frame_ly->setContentsMargins (0, 0, 0, 0); - left_frame_ly->setSpacing (0); + mp_connector = new LayoutViewSignalConnector (mp_widget, this); - mp_hierarchy_panel = new lay::HierarchyControlPanel (this, hierarchy_frame, "hcp"); - left_frame_ly->addWidget (mp_hierarchy_panel, 1 /*stretch*/); + QVBoxLayout *vbl = new QVBoxLayout (mp_widget); + vbl->setContentsMargins (0, 0, 0, 0); + vbl->setSpacing (0); + vbl->addWidget (view_object_widget ()); - connect (mp_hierarchy_panel, SIGNAL (cell_selected (cell_path_type, int)), this, SLOT (select_cell_dispatch (cell_path_type, int))); - connect (mp_hierarchy_panel, SIGNAL (active_cellview_changed (int)), this, SLOT (active_cellview_changed (int))); - connect (mp_hierarchy_frame, SIGNAL (destroyed ()), this, SLOT (side_panel_destroyed ())); + if ((options () & LV_NoHierarchyPanel) == 0 && (options () & LV_Naked) == 0) { - QFrame *levels_frame = new QFrame (hierarchy_frame); - levels_frame->setObjectName (QString::fromUtf8 ("lvl_frame")); - left_frame_ly->addWidget (levels_frame); - QHBoxLayout *levels_frame_ly = new QHBoxLayout (levels_frame); - levels_frame_ly->setContentsMargins (1, 1, 1, 1); - QLabel *level_l1 = new QLabel (tl::to_qstring (" " + tl::to_string (QObject::tr ("Levels"))), levels_frame); - levels_frame_ly->addWidget (level_l1); - mp_min_hier_spbx = new QSpinBox (levels_frame); - mp_min_hier_spbx->setObjectName (QString::fromUtf8 ("min_lvl")); - levels_frame_ly->addWidget (mp_min_hier_spbx); - QLabel *level_l2 = new QLabel (QString::fromUtf8 (".."), levels_frame); - levels_frame_ly->addWidget (level_l2); - mp_max_hier_spbx = new QSpinBox (levels_frame); - mp_max_hier_spbx->setObjectName (QString::fromUtf8 ("max_lvl")); - levels_frame_ly->addWidget (mp_max_hier_spbx); + QFrame *hierarchy_frame = new QFrame (0); + hierarchy_frame->setObjectName (QString::fromUtf8 ("left")); + mp_hierarchy_frame = hierarchy_frame; + QVBoxLayout *left_frame_ly = new QVBoxLayout (hierarchy_frame); + left_frame_ly->setContentsMargins (0, 0, 0, 0); + left_frame_ly->setSpacing (0); - mp_min_hier_spbx->installEventFilter (this); - mp_max_hier_spbx->installEventFilter (this); + mp_hierarchy_panel = new lay::HierarchyControlPanel (this, hierarchy_frame, "hcp"); + left_frame_ly->addWidget (mp_hierarchy_panel, 1 /*stretch*/); - mp_min_hier_spbx->setMaximum (0); - mp_min_hier_spbx->setMinimum (-1000); - mp_min_hier_spbx->setValue (0); - mp_max_hier_spbx->setMaximum (999); - mp_max_hier_spbx->setValue (0); - mp_max_hier_spbx->setMinimum (-1000); + QObject::connect (mp_hierarchy_panel, SIGNAL (cell_selected (cell_path_type, int)), mp_connector, SLOT (select_cell_dispatch (cell_path_type, int))); + QObject::connect (mp_hierarchy_panel, SIGNAL (active_cellview_changed (int)), mp_connector, SLOT (active_cellview_changed (int))); + QObject::connect (mp_hierarchy_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ())); - connect (mp_min_hier_spbx, SIGNAL (valueChanged (int)), this, SLOT (min_hier_changed (int))); - connect (mp_max_hier_spbx, SIGNAL (valueChanged (int)), this, SLOT (max_hier_changed (int))); + QFrame *levels_frame = new QFrame (hierarchy_frame); + levels_frame->setObjectName (QString::fromUtf8 ("lvl_frame")); + left_frame_ly->addWidget (levels_frame); + QHBoxLayout *levels_frame_ly = new QHBoxLayout (levels_frame); + levels_frame_ly->setContentsMargins (1, 1, 1, 1); + QLabel *level_l1 = new QLabel (tl::to_qstring (" " + tl::to_string (QObject::tr ("Levels"))), levels_frame); + levels_frame_ly->addWidget (level_l1); + mp_min_hier_spbx = new QSpinBox (levels_frame); + mp_min_hier_spbx->setObjectName (QString::fromUtf8 ("min_lvl")); + levels_frame_ly->addWidget (mp_min_hier_spbx); + QLabel *level_l2 = new QLabel (QString::fromUtf8 (".."), levels_frame); + levels_frame_ly->addWidget (level_l2); + mp_max_hier_spbx = new QSpinBox (levels_frame); + mp_max_hier_spbx->setObjectName (QString::fromUtf8 ("max_lvl")); + levels_frame_ly->addWidget (mp_max_hier_spbx); - } + mp_min_hier_spbx->installEventFilter (mp_widget); + mp_max_hier_spbx->installEventFilter (mp_widget); - if ((options () & LV_NoBookmarksView) == 0 && (options () & LV_Naked) == 0) { + mp_min_hier_spbx->setMaximum (0); + mp_min_hier_spbx->setMinimum (-1000); + mp_min_hier_spbx->setValue (0); + mp_max_hier_spbx->setMaximum (999); + mp_max_hier_spbx->setValue (0); + mp_max_hier_spbx->setMinimum (-1000); - QFrame *bookmarks_frame = new QFrame (0); - bookmarks_frame->setObjectName (QString::fromUtf8 ("bookmarks_frame")); - mp_bookmarks_frame = bookmarks_frame; - QVBoxLayout *left_frame_ly = new QVBoxLayout (bookmarks_frame); - left_frame_ly->setContentsMargins (0, 0, 0, 0); - left_frame_ly->setSpacing (0); + QObject::connect (mp_min_hier_spbx, SIGNAL (valueChanged (int)), mp_connector, SLOT (min_hier_changed (int))); + QObject::connect (mp_max_hier_spbx, SIGNAL (valueChanged (int)), mp_connector, SLOT (max_hier_changed (int))); - mp_bookmarks_view = new lay::BookmarksView (this, bookmarks_frame, "bookmarks"); - left_frame_ly->addWidget (mp_bookmarks_view, 1 /*stretch*/); + } - connect (mp_bookmarks_frame, SIGNAL (destroyed ()), this, SLOT (side_panel_destroyed ())); + if ((options () & LV_NoBookmarksView) == 0 && (options () & LV_Naked) == 0) { - } + QFrame *bookmarks_frame = new QFrame (0); + bookmarks_frame->setObjectName (QString::fromUtf8 ("bookmarks_frame")); + mp_bookmarks_frame = bookmarks_frame; + QVBoxLayout *left_frame_ly = new QVBoxLayout (bookmarks_frame); + left_frame_ly->setContentsMargins (0, 0, 0, 0); + left_frame_ly->setSpacing (0); - if ((options () & LV_NoLibrariesView) == 0 && (options () & LV_Naked) == 0) { + mp_bookmarks_view = new lay::BookmarksView (this, bookmarks_frame, "bookmarks"); + left_frame_ly->addWidget (mp_bookmarks_view, 1 /*stretch*/); - mp_libraries_frame = new QFrame (0); - mp_libraries_frame->setObjectName (QString::fromUtf8 ("libs_frame")); - QVBoxLayout *left_frame_ly = new QVBoxLayout (mp_libraries_frame); - left_frame_ly->setContentsMargins (0, 0, 0, 0); - left_frame_ly->setSpacing (0); + QObject::connect (mp_bookmarks_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ())); - mp_libraries_view = new lay::LibrariesView (this, mp_libraries_frame, "libs"); - left_frame_ly->addWidget (mp_libraries_view, 1 /*stretch*/); + } - connect (mp_libraries_view, SIGNAL (active_library_changed (int)), this, SLOT (active_library_changed (int))); - connect (mp_libraries_frame, SIGNAL (destroyed ()), this, SLOT (side_panel_destroyed ())); + if ((options () & LV_NoLibrariesView) == 0 && (options () & LV_Naked) == 0) { - } + mp_libraries_frame = new QFrame (0); + mp_libraries_frame->setObjectName (QString::fromUtf8 ("libs_frame")); + QVBoxLayout *left_frame_ly = new QVBoxLayout (mp_libraries_frame); + left_frame_ly->setContentsMargins (0, 0, 0, 0); + left_frame_ly->setSpacing (0); - if ((options () & LV_NoEditorOptionsPanel) == 0 && (options () & LV_Naked) == 0) { + mp_libraries_view = new lay::LibrariesView (this, mp_libraries_frame, "libs"); + left_frame_ly->addWidget (mp_libraries_view, 1 /*stretch*/); - mp_editor_options_frame = new lay::EditorOptionsFrame (0); - mp_editor_options_frame->populate (this); + QObject::connect (mp_libraries_view, SIGNAL (active_library_changed (int)), mp_connector, SLOT (active_library_changed (int))); + QObject::connect (mp_libraries_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ())); - connect (mp_editor_options_frame, SIGNAL (destroyed ()), this, SLOT (side_panel_destroyed ())); + } - } + if ((options () & LV_NoEditorOptionsPanel) == 0 && (options () & LV_Naked) == 0) { - if ((options () & LV_NoLayers) == 0 && (options () & LV_Naked) == 0) { + mp_editor_options_frame = new lay::EditorOptionsFrame (0); + mp_editor_options_frame->populate (this); - mp_control_panel = new lay::LayerControlPanel (this, manager (), 0, "lcp"); - mp_control_frame = mp_control_panel; + QObject::connect (mp_editor_options_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ())); - connect (mp_control_frame, SIGNAL (destroyed ()), this, SLOT (side_panel_destroyed ())); - connect (mp_control_panel, SIGNAL (tab_changed ()), this, SLOT (layer_tab_changed ())); - connect (mp_control_panel, SIGNAL (order_changed ()), this, SLOT (layer_order_changed ())); - connect (mp_control_panel, SIGNAL (current_layer_changed (const lay::LayerPropertiesConstIterator &)), this, SLOT (current_layer_changed_slot (const lay::LayerPropertiesConstIterator &))); - /* - connect (mp_control_panel, SIGNAL (marked_changed ()), this, SLOT (prop_changed ())); - connect (mp_control_panel, SIGNAL (width_changed ()), this, SLOT (prop_changed ())); - connect (mp_control_panel, SIGNAL (animation_changed ()), this, SLOT (prop_changed ())); - connect (mp_control_panel, SIGNAL (visibility_changed ()), this, SLOT (visibility_changed ())); - connect (mp_control_panel, SIGNAL (transparency_changed ()), this, SLOT (prop_changed ())); - connect (mp_control_panel, SIGNAL (stipple_changed ()), this, SLOT (prop_changed ())); - connect (mp_control_panel, SIGNAL (color_changed ()), this, SLOT (prop_changed ())); - */ + } + + if ((options () & LV_NoLayers) == 0 && (options () & LV_Naked) == 0) { + + mp_control_panel = new lay::LayerControlPanel (this, manager (), 0, "lcp"); + mp_control_frame = mp_control_panel; + + QObject::connect (mp_control_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ())); + QObject::connect (mp_control_panel, SIGNAL (tab_changed ()), mp_connector, SLOT (layer_tab_changed ())); + QObject::connect (mp_control_panel, SIGNAL (order_changed ()), mp_connector, SLOT (layer_order_changed ())); + QObject::connect (mp_control_panel, SIGNAL (current_layer_changed (const lay::LayerPropertiesConstIterator &)), mp_connector, SLOT (current_layer_changed_slot (const lay::LayerPropertiesConstIterator &))); + + } + + mp_timer = new QTimer (mp_widget); + QObject::connect (mp_timer, SIGNAL (timeout ()), mp_connector, SLOT (timer ())); + mp_timer->start (timer_interval); } config_setup (); - - mp_timer = new QTimer (this); - connect (mp_timer, SIGNAL (timeout ()), this, SLOT (timer ())); - mp_timer->start (timer_interval); } LayoutView::~LayoutView () @@ -369,35 +476,25 @@ void LayoutView::do_setup_editor_options_pages () } } -void LayoutView::side_panel_destroyed () +void LayoutView::side_panel_destroyed (QObject *sender) { - if (sender () == mp_control_frame) { + if (sender == mp_control_frame) { mp_control_frame = 0; mp_control_panel = 0; - } else if (sender () == mp_hierarchy_frame) { + } else if (sender == mp_hierarchy_frame) { mp_hierarchy_frame = 0; mp_hierarchy_panel = 0; - } else if (sender () == mp_libraries_frame) { + } else if (sender == mp_libraries_frame) { mp_libraries_frame = 0; mp_libraries_view = 0; - } else if (sender () == mp_editor_options_frame) { + } else if (sender == mp_editor_options_frame) { mp_editor_options_frame = 0; - } else if (sender () == mp_bookmarks_frame) { + } else if (sender == mp_bookmarks_frame) { mp_bookmarks_frame = 0; mp_bookmarks_view = 0; } } -void LayoutView::hideEvent (QHideEvent *) -{ - hide_event (); -} - -void LayoutView::showEvent (QShowEvent *) -{ - show_event (); -} - void LayoutView::set_current () { set_current (this); @@ -613,6 +710,8 @@ LayoutView::set_current_layer (const lay::LayerPropertiesConstIterator &l) { if (mp_control_panel) { mp_control_panel->set_current_layer (l); + } else { + return LayoutViewBase::set_current_layer (l); } } @@ -622,7 +721,7 @@ LayoutView::current_layer () const if (mp_control_panel) { return mp_control_panel->current_layer (); } else { - return lay::LayerPropertiesConstIterator (); + return LayoutViewBase::current_layer (); } } @@ -632,7 +731,7 @@ LayoutView::selected_layers () const if (mp_control_panel) { return mp_control_panel->selected_layers (); } else { - return std::vector (); + return LayoutViewBase::selected_layers (); } } @@ -641,6 +740,8 @@ LayoutView::set_selected_layers (const std::vectorset_selection (sel); + } else { + LayoutViewBase::set_selected_layers (sel); } } @@ -649,6 +750,8 @@ LayoutView::begin_layer_updates () { if (mp_control_panel) { mp_control_panel->begin_updates (); + } else { + LayoutViewBase::begin_layer_updates (); } } @@ -657,6 +760,8 @@ LayoutView::end_layer_updates () { if (mp_control_panel) { mp_control_panel->end_updates (); + } else { + LayoutViewBase::end_layer_updates (); } } @@ -668,23 +773,27 @@ LayoutView::layer_model_updated () if (mp_control_panel) { return mp_control_panel->model_updated (); } else { - return false; + return LayoutViewBase::layer_model_updated (); } } void LayoutView::bookmark_current_view () { + if (! mp_widget) { + return; + } + QString proposed_name = tl::to_qstring (bookmarks ().propose_new_bookmark_name ()); while (true) { bool ok = false; - QString text = QInputDialog::getText (this, QObject::tr ("Enter Bookmark Name"), QObject::tr ("Bookmark name"), + QString text = QInputDialog::getText (mp_widget, QObject::tr ("Enter Bookmark Name"), QObject::tr ("Bookmark name"), QLineEdit::Normal, proposed_name, &ok); if (! ok) { break; } else if (text.isEmpty ()) { - QMessageBox::critical (this, QObject::tr ("Error"), QObject::tr ("Enter a name for the bookmark")); + QMessageBox::critical (mp_widget, QObject::tr ("Error"), QObject::tr ("Enter a name for the bookmark")); } else { bookmark_view (tl::to_string (text)); break; @@ -695,12 +804,16 @@ LayoutView::bookmark_current_view () void LayoutView::manage_bookmarks () { + if (! mp_widget) { + return; + } + std::set selected_bm; if (mp_bookmarks_frame->isVisible ()) { selected_bm = mp_bookmarks_view->selected_bookmarks (); } - BookmarkManagementForm dialog (this, "bookmark_form", bookmarks (), selected_bm); + BookmarkManagementForm dialog (mp_widget, "bookmark_form", bookmarks (), selected_bm); if (dialog.exec ()) { bookmarks (dialog.bookmarks ()); } @@ -710,7 +823,9 @@ void LayoutView::bookmarks_changed () { mp_bookmarks_view->refresh (); - emit menu_needs_update (); + if (mp_widget) { + mp_widget->emit_menu_needs_update (); + } } void @@ -742,7 +857,11 @@ LayoutView::max_hier_changed (int i) lay::Color LayoutView::default_background_color () { - return lay::Color (palette ().color (QPalette::Normal, QPalette::Base).rgb ()); + if (! mp_widget) { + return LayoutViewBase::default_background_color (); + } else { + return lay::Color (mp_widget->palette ().color (QPalette::Normal, QPalette::Base).rgb ()); + } } void @@ -931,7 +1050,10 @@ LayoutView::deactivate () } } - emit clear_current_pos (); + if (mp_widget) { + mp_widget->emit_clear_current_pos (); + } + free_resources (); mp_timer->stop (); m_activated = false; @@ -964,6 +1086,10 @@ LayoutView::update_content_for_cv (int cellview_index) void LayoutView::current_pos (double x, double y) { + if (! mp_widget) { + return; + } + if (m_activated) { if (dbu_coordinates ()) { double dx = 0.0, dy = 0.0; @@ -972,9 +1098,9 @@ LayoutView::current_pos (double x, double y) dx = x / dbu; dy = y / dbu; } - emit current_pos_changed (dx, dy, true); + mp_widget->emit_current_pos_changed (dx, dy, true); } else { - emit current_pos_changed (x, y, false); + mp_widget->emit_current_pos_changed (x, y, false); } } } @@ -982,25 +1108,33 @@ LayoutView::current_pos (double x, double y) void LayoutView::emit_edits_enabled_changed () { - emit edits_enabled_changed (); + if (mp_widget) { + mp_widget->emit_edits_enabled_changed (); + } } void LayoutView::emit_title_changed () { - emit title_changed (); + if (mp_widget) { + mp_widget->emit_title_changed (); + } } void LayoutView::emit_dirty_changed () { - emit dirty_changed (); + if (mp_widget) { + mp_widget->emit_dirty_changed (); + } } void LayoutView::emit_layer_order_changed () { - emit layer_order_changed (); + if (mp_widget) { + mp_widget->emit_layer_order_changed (); + } } void @@ -1016,7 +1150,9 @@ LayoutView::signal_selection_changed () void LayoutView::message (const std::string &s, int timeout) { - emit show_message (s, timeout * 1000); + if (mp_widget) { + mp_widget->emit_show_message (s, timeout * 1000); + } } void @@ -1050,7 +1186,9 @@ LayoutView::switch_mode (int m) { if (mode () != m) { mode (m); - emit mode_change (m); + if (mp_widget) { + mp_widget->emit_mode_change (m); + } } } @@ -1073,7 +1211,7 @@ LayoutView::open_rdb_browser (int rdb_index, int cv_index) } QSize -LayoutView::sizeHint () const +LayoutView::size_hint () const { if ((options () & LV_Naked) != 0) { return QSize (200, 200); diff --git a/src/layview/layview/layLayoutView_qt.h b/src/layview/layview/layLayoutView_qt.h index fe65fde62..ae44e076b 100644 --- a/src/layview/layview/layLayoutView_qt.h +++ b/src/layview/layview/layLayoutView_qt.h @@ -86,6 +86,118 @@ class ColorButton; class ConfigureAction; class EditorOptionsPages; +/** + * @brief A custom QFrame that acts as the central widget for the LayoutView + */ +class LayoutViewFrame + : public QFrame +{ +Q_OBJECT + +public: + LayoutViewFrame (QWidget *parent, lay::LayoutView *view); + + virtual QSize sizeHint () const; + virtual bool eventFilter(QObject *obj, QEvent *event); + virtual void showEvent (QShowEvent *); + virtual void hideEvent (QHideEvent *); + + void emit_title_changed () { emit title_changed (); } + void emit_dirty_changed () { emit dirty_changed (); } + void emit_show_message (const std::string &s, int ms) { emit show_message (s, ms); } + void emit_current_pos_changed (double x, double y, bool dbu_units) { emit current_pos_changed (x, y, dbu_units); } + void emit_clear_current_pos () { emit clear_current_pos (); } + void emit_edits_enabled_changed () { emit edits_enabled_changed (); } + void emit_mode_change (int m) { emit mode_change (m); } + void emit_current_layer_changed (const lay::LayerPropertiesConstIterator &l) { emit current_layer_changed (l); } + void emit_menu_needs_update () { emit menu_needs_update (); } + void emit_layer_order_changed () { emit layer_order_changed (); } + +signals: + /** + * @brief This signal is emitted when the title changes + */ + void title_changed (); + + /** + * @brief This signal is emitted when the "dirty" flag changes + */ + void dirty_changed (); + + /** + * @brief This signal is emitted when the view wants to show a message for the given time (of infinitely for ms == 0) + */ + void show_message (const std::string &s, int ms); + + /** + * @brief This signal is emitted when the view wants to indicate a mouse position change + */ + void current_pos_changed (double x, double y, bool dbu_units); + + /** + * @brief This signal is emitted when the view wants to clear the mouse position + */ + void clear_current_pos (); + + /** + * @brief This signal is sent when the "edits_enabled" state has changed + */ + void edits_enabled_changed (); + + /** + * @brief This signal is sent when the view wants to update the menu + */ + void menu_needs_update (); + + /** + * @brief The view initiated a mode change + */ + void mode_change (int m); + + /** + * @brief The current layer changed + */ + void current_layer_changed (const lay::LayerPropertiesConstIterator &l); + + /** + * @brief The layer order has changed + */ + void layer_order_changed (); + +private: + LayoutView *mp_view; +}; + +/** + * @brief An object connecting child widget signals with methods from LayoutView + */ +class LayoutViewSignalConnector + : public QObject +{ +Q_OBJECT + +public: + LayoutViewSignalConnector (QObject *parent, lay::LayoutView *view); + + typedef lay::LayoutViewBase::cell_path_type cell_path_type; + +private slots: + void active_cellview_changed (int index); + void active_library_changed (int index); + void side_panel_destroyed (); + void current_layer_changed_slot (const lay::LayerPropertiesConstIterator &iter); + void layer_tab_changed (); + void layer_order_changed (); + void select_cell_dispatch (const cell_path_type &path, int cellview_index); + void min_hier_changed (int i); + void max_hier_changed (int i); + + void timer (); + +private: + LayoutView *mp_view; +}; + /** * @brief The layout view object * @@ -96,8 +208,6 @@ class EditorOptionsPages; class LAYVIEW_PUBLIC LayoutView : public LayoutViewBase { -Q_OBJECT - public: /** * @brief Constructor @@ -409,9 +519,14 @@ public: virtual void cut (); /** - * @brief Deliver a size hint (reimplementation of QWidget) + * @brief Gets the widget object + * + * This pointer may be 0 if the layout view is created in a headless environment. */ - virtual QSize sizeHint () const; + virtual QWidget *widget () + { + return mp_widget; + } /** * @brief An event signalling that the view is going to close @@ -428,7 +543,6 @@ public: */ tl::Event hide_event; -public slots: /** * @brief Store the current state on the "previous states" stack */ @@ -509,25 +623,6 @@ public slots: LayoutViewBase::ensure_selection_visible (); } - /** - * @brief Select a cell by index for a certain cell view - * - * This will be forwarded to select_cell or select_cell_fit depending - * on the m_fit_new_cell flag. - */ - void select_cell_dispatch (const cell_path_type &path, int cellview_index) - { - LayoutViewBase::select_cell_dispatch (path, cellview_index); - } - - /** - * @brief Called when the current layer changed - */ - void current_layer_changed_slot (const lay::LayerPropertiesConstIterator &iter) - { - LayoutViewBase::current_layer_changed_slot (iter); - } - // zoom slots void zoom_fit () { @@ -610,76 +705,15 @@ public slots: LayoutViewBase::redraw_cell_boxes (); } - void layer_tab_changed (); - void layer_order_changed (); - - void timer () - { - LayoutViewBase::timer (); - } - - void min_hier_changed (int i); - void max_hier_changed (int i); - void deactivate_all_browsers (); -private slots: - void active_cellview_changed (int index) - { - LayoutViewBase::active_cellview_changed (index); - } - - void active_library_changed (int index); - void side_panel_destroyed (); - -signals: - /** - * @brief This signal is emitted when the title changes - */ - void title_changed (); - - /** - * @brief This signal is emitted when the "dirty" flag changes - */ - void dirty_changed (); - - /** - * @brief This signal is emitted when the view wants to show a message for the given time (of infinitely for ms == 0) - */ - void show_message (const std::string &s, int ms); - - /** - * @brief This signal is emitted when the view wants to indicate a mouse position change - */ - void current_pos_changed (double x, double y, bool dbu_units); - - /** - * @brief This signal is emitted when the view wants to clear the mouse position - */ - void clear_current_pos (); - - /** - * @brief This signal is sent when the "edits_enabled" state has changed - */ - void edits_enabled_changed (); - - /** - * @brief This signal is sent when the view wants to update the menu - */ - void menu_needs_update (); - - /** - * @brief The view initiated a mode change - */ - void mode_change (int m); - - /** - * @brief The current layer changed - */ - void current_layer_changed (const lay::LayerPropertiesConstIterator &l); - private: + friend class LayoutViewSignalConnector; + friend class LayoutViewFrame; + QTimer *mp_timer; + LayoutViewFrame *mp_widget; + LayoutViewSignalConnector *mp_connector; bool m_activated; QFrame *mp_left_frame; lay::LayerControlPanel *mp_control_panel; @@ -696,7 +730,17 @@ private: tl::DeferredMethod dm_setup_editor_option_pages; - void init_ui (); + void active_library_changed (int index); + void side_panel_destroyed (QObject *sender); + void layer_tab_changed (); + void layer_order_changed (); + void min_hier_changed (int i); + void max_hier_changed (int i); + + bool event_filter (QObject *obj, QEvent *ev, bool &taken); + QSize size_hint () const; + + void init_ui (QWidget *parent, const char *name); void init_menu (); void do_setup_editor_options_pages (); @@ -704,10 +748,6 @@ protected: void activate (); void deactivate (); - virtual bool eventFilter(QObject *obj, QEvent *ev); - virtual void showEvent (QShowEvent *); - virtual void hideEvent (QHideEvent *); - virtual bool configure (const std::string &name, const std::string &value); virtual void config_finalize (); From 03761768cfb0911df666041a0716347ece9f6321 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 26 May 2022 01:51:09 +0200 Subject: [PATCH 02/45] Enabled headless LayoutView. Works. --- src/ant/ant/antPropertiesPage.cc | 4 +- src/ant/ant/antService.cc | 24 +- src/edt/edt/edtMainService.cc | 10 +- src/edt/edt/edtPartialService.cc | 26 +- src/edt/edt/edtService.cc | 8 +- src/img/img/imgLandmarksDialog.cc | 16 +- src/img/img/imgNavigator.cc | 2 +- src/img/img/imgService.cc | 2 +- src/lay/lay/layClipDialog.cc | 13 +- src/lay/lay/layFillDialog.cc | 7 +- src/lay/lay/layNavigator.cc | 22 +- src/lay/lay/laySearchReplacePlugin.cc | 7 +- .../laybasic/gsiDeclLayLayoutViewBase.cc | 16 +- src/laybasic/laybasic/gsiDeclLayPlugin.cc | 12 +- src/laybasic/laybasic/layEditorServiceBase.cc | 14 +- src/laybasic/laybasic/layLayoutCanvas.cc | 74 +- src/laybasic/laybasic/layLayoutCanvas.h | 23 +- src/laybasic/laybasic/layLayoutViewBase.h | 9 +- src/laybasic/laybasic/layMarker.cc | 2 +- src/laybasic/laybasic/layMouseTracker.cc | 6 +- src/laybasic/laybasic/layMove.cc | 10 +- src/laybasic/laybasic/layRubberBox.cc | 2 +- src/laybasic/laybasic/layRubberBox.h | 2 +- src/laybasic/laybasic/laySelector.cc | 10 +- src/laybasic/laybasic/layUtils.cc | 45 ++ src/laybasic/laybasic/layUtils.h | 38 + src/laybasic/laybasic/layViewObject.cc | 686 ++++++++++-------- src/laybasic/laybasic/layViewObject.h | 148 ++-- src/laybasic/laybasic/layZoomBox.cc | 24 +- src/laybasic/laybasic/laybasic.pro | 2 + src/layui/layui/layBrowseInstancesForm.cc | 7 +- src/layui/layui/layBrowseShapesForm.cc | 25 +- src/layui/layui/layHierarchyControlPanel.cc | 2 +- src/layui/layui/layLibrariesView.cc | 2 +- src/layui/layui/layNetlistBrowser.cc | 7 +- src/layui/layui/layNetlistBrowserDialog.cc | 8 +- src/layui/layui/rdbMarkerBrowser.cc | 7 +- src/layview/layview/layGridNet.cc | 2 +- src/layview/layview/layLayoutView_qt.cc | 43 +- .../tools/diff/lay_plugin/layDiffPlugin.cc | 9 +- .../lay_plugin/layNetTracerDialog.cc | 10 +- .../lay_plugin/layNetTracerPlugin.cc | 7 +- .../tools/view_25d/lay_plugin/layD25Plugin.cc | 7 +- .../tools/xor/lay_plugin/layXORPlugin.cc | 9 +- 44 files changed, 779 insertions(+), 630 deletions(-) create mode 100644 src/laybasic/laybasic/layUtils.cc create mode 100644 src/laybasic/laybasic/layUtils.h diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc index 1c7794db4..b381c9c11 100644 --- a/src/ant/ant/antPropertiesPage.cc +++ b/src/ant/ant/antPropertiesPage.cc @@ -205,7 +205,7 @@ PropertiesPage::snap_to_layout_clicked () bool snap_p1 = sender () == p1_to_layout; - double snap_range = service->widget ()->mouse_event_trans ().inverted ().ctrans (service->snap_range ()); + double snap_range = service->ui ()->mouse_event_trans ().inverted ().ctrans (service->snap_range ()); double max_range = 1000 * snap_range; while (snap_range < max_range) { @@ -237,7 +237,7 @@ PropertiesPage::snap_to_layout_clicked () } else { - double snap_range = service->widget ()->mouse_event_trans ().inverted ().ctrans (service->snap_range ()); + double snap_range = service->ui ()->mouse_event_trans ().inverted ().ctrans (service->snap_range ()); snap_range *= 0.5; lay::TwoPointSnapToObjectResult ee = lay::obj_snap2 (service->view (), p1, p2, g, ac, snap_range, snap_range * 1000.0); diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index e9d6401c5..1c366a983 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -727,7 +727,7 @@ is_selected (const ant::Object &ruler, const db::DBox &box, double /*enl*/) // ------------------------------------------------------------- View::View (ant::Service *rulers, const ant::Object *ruler, bool selected) - : lay::ViewObject (rulers->widget ()), + : lay::ViewObject (rulers->ui ()), mp_rulers (rulers), m_selected (selected), mp_ruler (ruler) { // .. nothing else .. @@ -828,7 +828,7 @@ Service::configure (const std::string &name, const std::string &value) // make the color available for the dynamic view objects too. if (lay::test_and_set (m_color, color)) { - widget ()->touch (); + ui ()->touch (); } } else if (name == cfg_ruler_halo) { @@ -838,7 +838,7 @@ Service::configure (const std::string &name, const std::string &value) // make the color available for the dynamic view objects too. if (lay::test_and_set (m_halo, halo)) { - widget ()->touch (); + ui ()->touch (); } } else if (name == cfg_ruler_grid_micron) { @@ -967,20 +967,20 @@ Service::clear_rulers () double Service::catch_distance () { - return double (view ()->search_range ()) / widget ()->mouse_event_trans ().mag (); + return double (view ()->search_range ()) / ui ()->mouse_event_trans ().mag (); } double Service::catch_distance_box () { - return double (view ()->search_range_box ()) / widget ()->mouse_event_trans ().mag (); + return double (view ()->search_range_box ()) / ui ()->mouse_event_trans ().mag (); } void Service::drag_cancel () { if (m_drawing) { - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); m_drawing = false; } @@ -1110,7 +1110,7 @@ bool Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::angle_constraint_type /*ac*/) { // cancel any pending move or drag operations, reset mp_active_ruler - widget ()->drag_cancel (); // KLUDGE: every service does this to the same service manager + ui ()->drag_cancel (); // KLUDGE: every service does this to the same service manager clear_transient_selection (); @@ -1558,7 +1558,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio g = db::DVector (m_grid, m_grid); } - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); snap_range *= 0.5; lay::TwoPointSnapToObjectResult ee = lay::obj_snap2 (mp_view, p, g, ac, snap_range, snap_range * 1000.0); @@ -1592,7 +1592,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio mp_active_ruler->thaw (); m_drawing = true; - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); } @@ -1627,7 +1627,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio ant::Object Service::create_measure_ruler (const db::DPoint &pt, lay::angle_constraint_type ac) { - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); snap_range *= 0.5; ant::Template tpl; @@ -1687,7 +1687,7 @@ Service::snap1_details (const db::DPoint &p, bool obj_snap) g = db::DVector (m_grid, m_grid); } - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); return lay::obj_snap (obj_snap ? mp_view : 0, p, g, snap_range); } @@ -1707,7 +1707,7 @@ Service::snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::O g = db::DVector (m_grid, m_grid); } - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); lay::angle_constraint_type snap_mode = ac == lay::AC_Global ? (obj->angle_constraint () == lay::AC_Global ? m_snap_mode : obj->angle_constraint ()) : ac; return lay::obj_snap (m_obj_snap && obj->snap () ? mp_view : 0, p1, p2, g, snap_mode, snap_range); diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index 3ccc53648..be134d55e 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -2158,7 +2158,7 @@ MainService::cm_tap () tl_assert (false); // see TODO #endif - if (! view ()->view_object_widget ()->mouse_in_window ()) { + if (! view ()->canvas ()->widget () || view ()->canvas ()->mouse_in_window ()) { return; } @@ -2168,7 +2168,7 @@ MainService::cm_tap () finder.set_catch_all (true); // go through all visible layers of all cellviews - db::DPoint pt = view ()->view_object_widget ()->mouse_position_um (); + db::DPoint pt = view ()->canvas ()->mouse_position_um (); finder.find (view (), db::DBox (pt, pt)); std::set > layers_in_selection; @@ -2201,8 +2201,8 @@ MainService::cm_tap () int icon_size = menu->style ()->pixelMetric (QStyle::PM_ButtonIconSize); - db::DPoint mp_local = view ()->view_object_widget ()->mouse_position (); - QPoint mp = view ()->view_object_widget ()->mapToGlobal (QPoint (mp_local.x (), mp_local.y ())); + db::DPoint mp_local = view ()->canvas ()->mouse_position (); + QPoint mp = view ()->canvas ()->widget ()->mapToGlobal (QPoint (mp_local.x (), mp_local.y ())); for (std::vector::const_iterator l = tapped_layers.begin (); l != tapped_layers.end (); ++l) { QAction *a = menu->addAction (lay::LayerTreeModel::icon_for_layer (*l, view (), icon_size, icon_size, 0, true), tl::to_qstring ((*l)->display_string (view (), true, true /*with source*/))); @@ -2216,7 +2216,7 @@ MainService::cm_tap () lay::LayerPropertiesConstIterator iter = tapped_layers [index]; view ()->set_current_layer (iter); - edt::Service *es = dynamic_cast (view ()->view_object_widget ()->active_service ()); + edt::Service *es = dynamic_cast (view ()->canvas ()->active_service ()); if (es) { es->tap (pt); } diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc index 7f89ef2fa..80fd629c9 100644 --- a/src/edt/edt/edtPartialService.cc +++ b/src/edt/edt/edtPartialService.cc @@ -1308,7 +1308,7 @@ const int sr_pixels = 8; // TODO: make variable lay::PointSnapToObjectResult PartialService::snap2 (const db::DPoint &p) const { - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (sr_pixels); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels); return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range); } @@ -1526,7 +1526,7 @@ PartialService::edit_cancel () mp_box = 0; } - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); selection_to_view (); } @@ -1654,10 +1654,10 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo m_p1 = p; m_p2 = p; - mp_box = new lay::RubberBox (widget (), m_color, p, p); + mp_box = new lay::RubberBox (ui (), m_color, p, p); mp_box->set_stipple (6); // coarse hatched - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } else { @@ -1673,7 +1673,7 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo m_current = m_start = p; } - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } @@ -1712,7 +1712,7 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo if (m_current != m_start) { // stop dragging - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); manager ()->transaction (tl::to_string (tr ("Partial move"))); @@ -1743,7 +1743,7 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo return true; - } else if (widget ()->mouse_event_viewport ().contains (p)) { + } else if (ui ()->mouse_event_viewport ().contains (p)) { // clear other selection when this mode gets active // (save the selection so our own selection does not get cleared) @@ -1901,7 +1901,7 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt m_alt_ac = ac_from_buttons (buttons); // stop dragging - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); m_dragging = false; partial_select (db::DBox (p, p), lay::Editable::Replace); @@ -2006,12 +2006,12 @@ PartialService::mouse_release_event (const db::DPoint &p, unsigned int buttons, m_alt_ac = ac_from_buttons (buttons); - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); delete mp_box; mp_box = 0; - if (widget ()->mouse_event_viewport ().contains (p)) { + if (ui ()->mouse_event_viewport ().contains (p)) { lay::Editable::SelectionMode mode = lay::Editable::Replace; bool shift = ((m_buttons & lay::ShiftButton) != 0); @@ -2067,7 +2067,7 @@ void PartialService::del () { // stop dragging - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); std::map >, std::vector > shapes_to_delete_by_cell; @@ -2358,13 +2358,13 @@ PartialService::enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_obj double PartialService::catch_distance () { - return double (view ()->search_range ()) / widget ()->mouse_event_trans ().mag (); + return double (view ()->search_range ()) / ui ()->mouse_event_trans ().mag (); } double PartialService::catch_distance_box () { - return double (view ()->search_range_box ()) / widget ()->mouse_event_trans ().mag (); + return double (view ()->search_range_box ()) / ui ()->mouse_event_trans ().mag (); } db::DPoint diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 7e3320bee..7ff291a1b 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -179,7 +179,7 @@ const int sr_pixels = 8; // TODO: make variable lay::PointSnapToObjectResult Service::snap2_details (const db::DPoint &p) const { - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (sr_pixels); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels); return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range); } @@ -192,7 +192,7 @@ Service::snap2 (const db::DPoint &p) const db::DPoint Service::snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect) const { - double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (sr_pixels); + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels); return lay::obj_snap (m_snap_to_objects ? view () : 0, plast, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, connect ? connect_ac () : move_ac (), snap_range).snapped_point; } @@ -922,13 +922,13 @@ Service::has_transient_selection () double Service::catch_distance () { - return double (view ()->search_range ()) / widget ()->mouse_event_trans ().mag (); + return double (view ()->search_range ()) / ui ()->mouse_event_trans ().mag (); } double Service::catch_distance_box () { - return double (view ()->search_range_box ()) / widget ()->mouse_event_trans ().mag (); + return double (view ()->search_range_box ()) / ui ()->mouse_event_trans ().mag (); } double diff --git a/src/img/img/imgLandmarksDialog.cc b/src/img/img/imgLandmarksDialog.cc index 4be4ba291..4b8d1f886 100644 --- a/src/img/img/imgLandmarksDialog.cc +++ b/src/img/img/imgLandmarksDialog.cc @@ -40,7 +40,7 @@ public: * @brief Constructor attaching to a certain object */ LandmarkMarker (lay::ViewService *service, const db::DPoint &pos, bool selected) - : lay::ViewObject (service->widget ()), + : lay::ViewObject (service->ui ()), mp_service (service), m_pos (pos), m_selected (selected), m_position_set (true) { // .. nothing yet .. @@ -50,7 +50,7 @@ public: * @brief Constructor attaching to a certain object */ LandmarkMarker (lay::ViewService *service, bool selected) - : lay::ViewObject (service->widget ()), + : lay::ViewObject (service->ui ()), mp_service (service), m_pos (), m_selected (selected), m_position_set (false) { // .. nothing yet .. @@ -146,7 +146,7 @@ class LandmarkEditorService { public: LandmarkEditorService (lay::LayoutViewBase *view, img::Object *img) - : lay::ViewService (view->view_object_widget ()), + : lay::ViewService (view->canvas ()), mp_image (img), m_selected (-1), m_dragging (false), m_mode (LandmarksDialog::None) { @@ -182,7 +182,7 @@ public: update (); - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); m_dragging = true; } else if (m_mode == LandmarksDialog::Delete) { @@ -227,7 +227,7 @@ public: update (); - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); m_dragging = false; } @@ -235,7 +235,7 @@ public: } else { int search_range = 5; // TODO: make_variable? - double l = double (search_range) / widget ()->mouse_event_trans ().mag (); + double l = double (search_range) / ui ()->mouse_event_trans ().mag (); db::DBox search_box = db::DBox (p, p).enlarged (db::DVector (l, l)); int li = 0; @@ -307,7 +307,7 @@ public: } else if (! m_dragging) { int search_range = 5; // TODO: make_variable? - double l = double (search_range) / widget ()->mouse_event_trans ().mag (); + double l = double (search_range) / ui ()->mouse_event_trans ().mag (); db::DBox search_box = db::DBox (p, p).enlarged (db::DVector (l, l)); int li = 0; @@ -343,7 +343,7 @@ public: m_dragging = false; } - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); } void set_colors (lay::Color /*background*/, lay::Color /*color*/) diff --git a/src/img/img/imgNavigator.cc b/src/img/img/imgNavigator.cc index d01f189a9..b9ce6bb92 100644 --- a/src/img/img/imgNavigator.cc +++ b/src/img/img/imgNavigator.cc @@ -94,7 +94,7 @@ Navigator::~Navigator () void Navigator::activate_service (lay::ViewService *service) { - mp_view->view_object_widget ()->activate (service); + mp_view->canvas ()->activate (service); } void diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc index de9fd331f..6a120dce9 100644 --- a/src/img/img/imgService.cc +++ b/src/img/img/imgService.cc @@ -410,7 +410,7 @@ View::render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) // img::Service implementation Service::Service (db::Manager *manager, lay::LayoutViewBase *view) - : lay::BackgroundViewObject (view->view_object_widget ()), + : lay::BackgroundViewObject (view->canvas ()), lay::Editable (view), lay::Plugin (view), db::Object (manager), diff --git a/src/lay/lay/layClipDialog.cc b/src/lay/lay/layClipDialog.cc index 2c28187e0..aa0405d8c 100644 --- a/src/lay/lay/layClipDialog.cc +++ b/src/lay/lay/layClipDialog.cc @@ -28,6 +28,7 @@ #include "tlException.h" #include "tlString.h" #include "tlExceptions.h" +#include "layUtils.h" namespace lay { @@ -55,10 +56,14 @@ public: menu_entries.push_back (lay::menu_item ("clip_tool::show", "clip_tool:edit_mode", "edit_menu.utils_menu.end", tl::to_string (QObject::tr ("Clip Tool")))); } - virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const - { - return new ClipDialog (root, view); - } + virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const + { + if (lay::has_gui ()) { + return new ClipDialog (root, view); + } else { + return 0; + } + } }; static tl::RegisteredClass config_decl (new ClipDialogPluginDeclaration (), 20000, "ClipDialogPlugin"); diff --git a/src/lay/lay/layFillDialog.cc b/src/lay/lay/layFillDialog.cc index 458c90afa..2104b9a9b 100644 --- a/src/lay/lay/layFillDialog.cc +++ b/src/lay/lay/layFillDialog.cc @@ -34,6 +34,7 @@ #include "tlExceptions.h" #include "layMainWindow.h" #include "layCellSelectionForm.h" +#include "layUtils.h" #include "edtService.h" namespace lay @@ -64,7 +65,11 @@ public: virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new FillDialog (root, view); + if (lay::has_gui ()) { + return new FillDialog (root, view); + } else { + return 0; + } } }; diff --git a/src/lay/lay/layNavigator.cc b/src/lay/lay/layNavigator.cc index 6977e9702..7c4be5bc2 100644 --- a/src/lay/lay/layNavigator.cc +++ b/src/lay/lay/layNavigator.cc @@ -50,7 +50,7 @@ public: }; NavigatorService (LayoutView *view) - : ViewService (view->view_object_widget ()), + : ViewService (view->canvas ()), mp_view (view), mp_source_view (0), mp_viewport_marker (0), m_drag_mode (DM_none), @@ -101,7 +101,7 @@ public: delete mp_box; mp_box = 0; - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); if (mp_source_view) { mp_source_view->zoom_box (db::DBox (m_p1, m_p2)); @@ -112,7 +112,7 @@ public: } else if (m_dragging) { m_dragging = false; - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); return true; } else { @@ -123,7 +123,7 @@ public: bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio) { if (! prio && (buttons & lay::RightButton) != 0) { - db::DBox vp = widget ()->mouse_event_viewport (); + db::DBox vp = ui ()->mouse_event_viewport (); if (mp_source_view && vp.contains (p)) { db::DVector d = (vp.p2 () - vp.p1 ()) * 0.5; mp_source_view->zoom_box (db::DBox (p - d, p + d)); @@ -156,7 +156,7 @@ public: m_dragging = true; m_p0 = p; m_b0 = m_box; - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); return true; } else { @@ -389,7 +389,7 @@ public: delete mp_box; mp_box = 0; } - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); } void set_colors (lay::Color /*background*/, lay::Color color) @@ -426,9 +426,9 @@ private: mp_box = 0; m_p1 = pos; - m_vp = widget ()->mouse_event_viewport (); + m_vp = ui ()->mouse_event_viewport (); - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } void begin (const db::DPoint &pos) @@ -439,9 +439,9 @@ private: m_p1 = pos; m_p2 = pos; - mp_box = new lay::RubberBox (widget (), m_color, pos, pos); + mp_box = new lay::RubberBox (ui (), m_color, pos, pos); - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } }; @@ -664,7 +664,7 @@ Navigator::attach_view (LayoutView *view) mp_view->widget ()->show (); mp_service = new NavigatorService (mp_view); - mp_view->view_object_widget ()->activate (mp_service); + mp_view->canvas ()->activate (mp_service); mp_source_view->cellviews_changed_event.add (this, &Navigator::content_changed); mp_source_view->cellview_changed_event.add (this, &Navigator::content_changed_with_int); diff --git a/src/lay/lay/laySearchReplacePlugin.cc b/src/lay/lay/laySearchReplacePlugin.cc index 6c4be161b..4f797193d 100644 --- a/src/lay/lay/laySearchReplacePlugin.cc +++ b/src/lay/lay/laySearchReplacePlugin.cc @@ -26,6 +26,7 @@ #include "layMainWindow.h" #include "layApplication.h" +#include "layUtils.h" namespace lay { @@ -65,7 +66,11 @@ public: virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new SearchReplaceDialog (root, view); + if (lay::has_gui ()) { + return new SearchReplaceDialog (root, view); + } else { + return 0; + } } }; diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc index b6ec122f3..745416c09 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc @@ -360,49 +360,49 @@ get_config_names (lay::LayoutViewBase *view) static void send_key_press_event (lay::LayoutViewBase *view, unsigned int key, unsigned int buttons) { - view->view_object_widget ()->send_key_press_event (key, buttons); + view->canvas ()->send_key_press_event (key, buttons); } static void send_mouse_move_event (lay::LayoutViewBase *view, const db::DPoint &pt, unsigned int buttons) { - view->view_object_widget ()->send_mouse_move_event (pt, buttons); + view->canvas ()->send_mouse_move_event (pt, buttons); } static void send_leave_event (lay::LayoutViewBase *view) { - view->view_object_widget ()->send_leave_event (); + view->canvas ()->send_leave_event (); } static void send_enter_event (lay::LayoutViewBase *view) { - view->view_object_widget ()->send_enter_event (); + view->canvas ()->send_enter_event (); } static void send_mouse_press_event (lay::LayoutViewBase *view, const db::DPoint &pt, unsigned int buttons) { - view->view_object_widget ()->send_mouse_press_event (pt, buttons); + view->canvas ()->send_mouse_press_event (pt, buttons); } static void send_mouse_double_clicked_event (lay::LayoutViewBase *view, const db::DPoint &pt, unsigned int buttons) { - view->view_object_widget ()->send_mouse_double_clicked_event (pt, buttons); + view->canvas ()->send_mouse_double_clicked_event (pt, buttons); } static void send_mouse_release_event (lay::LayoutViewBase *view, const db::DPoint &pt, unsigned int buttons) { - view->view_object_widget ()->send_mouse_release_event (pt, buttons); + view->canvas ()->send_mouse_release_event (pt, buttons); } static void send_wheel_event (lay::LayoutViewBase *view, int delta, bool horizontal, const db::DPoint &pt, unsigned int buttons) { - view->view_object_widget ()->send_wheel_event (delta, horizontal, pt, buttons); + view->canvas ()->send_wheel_event (delta, horizontal, pt, buttons); } namespace { diff --git a/src/laybasic/laybasic/gsiDeclLayPlugin.cc b/src/laybasic/laybasic/gsiDeclLayPlugin.cc index bce28aa52..cee6e63cf 100644 --- a/src/laybasic/laybasic/gsiDeclLayPlugin.cc +++ b/src/laybasic/laybasic/gsiDeclLayPlugin.cc @@ -48,7 +48,7 @@ class PluginBase { public: PluginBase () - : lay::Plugin (sp_dispatcher), lay::ViewService (sp_view ? sp_view->view_object_widget () : 0) + : lay::Plugin (sp_dispatcher), lay::ViewService (sp_view ? sp_view->canvas () : 0) { if (! s_in_create_plugin) { throw tl::Exception (tl::to_string (tr ("A PluginBase object can only be created in the PluginFactory's create_plugin method"))); @@ -57,21 +57,21 @@ public: void grab_mouse () { - if (widget ()) { - widget ()->grab_mouse (this, false); + if (ui ()) { + ui ()->grab_mouse (this, false); } } void ungrab_mouse () { - if (widget ()) { - widget ()->ungrab_mouse (this); + if (ui ()) { + ui ()->ungrab_mouse (this); } } void set_cursor (int c) { - if (widget ()) { + if (ui ()) { lay::ViewService::set_cursor ((enum lay::Cursor::cursor_shape) c); } } diff --git a/src/laybasic/laybasic/layEditorServiceBase.cc b/src/laybasic/laybasic/layEditorServiceBase.cc index ea6f5fcff..ac1021ee3 100644 --- a/src/laybasic/laybasic/layEditorServiceBase.cc +++ b/src/laybasic/laybasic/layEditorServiceBase.cc @@ -57,7 +57,7 @@ class TrackingCursorBase : public lay::ViewObject { public: - TrackingCursorBase (lay::EditorServiceBase *service, lay::ViewObjectWidget *widget) + TrackingCursorBase (lay::EditorServiceBase *service, lay::ViewObjectUI *widget) : lay::ViewObject (widget, false), mp_service (service) { } @@ -91,7 +91,7 @@ class MouseCursorViewObject : public TrackingCursorBase { public: - MouseCursorViewObject (lay::EditorServiceBase *service, lay::ViewObjectWidget *widget, const db::DPoint &pt, bool solid) + MouseCursorViewObject (lay::EditorServiceBase *service, lay::ViewObjectUI *widget, const db::DPoint &pt, bool solid) : TrackingCursorBase (service, widget), m_pt (pt), m_solid (solid) { } @@ -139,7 +139,7 @@ class EdgeMarkerViewObject : public TrackingCursorBase { public: - EdgeMarkerViewObject (lay::EditorServiceBase *service, lay::ViewObjectWidget *widget, const db::DEdge &edge, bool solid) + EdgeMarkerViewObject (lay::EditorServiceBase *service, lay::ViewObjectUI *widget, const db::DEdge &edge, bool solid) : TrackingCursorBase (service, widget), m_edge (edge), m_solid (solid) { } @@ -207,7 +207,7 @@ private: // -------------------------------------------------------------------------------------- EditorServiceBase::EditorServiceBase (LayoutViewBase *view) - : lay::ViewService (view->view_object_widget ()), + : lay::ViewService (view->canvas ()), lay::Editable (view), lay::Plugin (view), m_cursor_enabled (true), @@ -226,13 +226,13 @@ EditorServiceBase::add_mouse_cursor (const db::DPoint &pt, bool emphasize) { m_has_tracking_position = true; m_tracking_position = pt; - m_mouse_cursor_markers.push_back (new MouseCursorViewObject (this, widget (), pt, emphasize)); + m_mouse_cursor_markers.push_back (new MouseCursorViewObject (this, ui (), pt, emphasize)); } void EditorServiceBase::add_edge_marker (const db::DEdge &e, bool emphasize) { - m_mouse_cursor_markers.push_back (new EdgeMarkerViewObject (this, widget (), e, emphasize)); + m_mouse_cursor_markers.push_back (new EdgeMarkerViewObject (this, ui (), e, emphasize)); } void @@ -307,7 +307,7 @@ EditorServiceBase::show_error (tl::Exception &ex) { tl::error << ex.msg (); #if defined(HAVE_QT) - QMessageBox::critical (widget (), tr ("Error"), tl::to_qstring (ex.msg ())); + QMessageBox::critical (ui ()->widget (), tr ("Error"), tl::to_qstring (ex.msg ())); #endif } diff --git a/src/laybasic/laybasic/layLayoutCanvas.cc b/src/laybasic/laybasic/layLayoutCanvas.cc index df8448c3f..c7a55d06f 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.cc +++ b/src/laybasic/laybasic/layLayoutCanvas.cc @@ -275,7 +275,7 @@ invert (unsigned char *data, unsigned int width, unsigned int height) } LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view) - : lay::ViewObjectWidget (), + : lay::ViewObjectUI (), mp_view (view), mp_image (0), mp_image_bg (0), mp_image_fg (0), @@ -291,11 +291,25 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view) m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing), m_image_cache_size (1) { + lay::Color bg (0xffffffff), fg (0xff000000), active (0xffc0c0c0); + #if defined(HAVE_QT) + if (widget ()) { + #if QT_VERSION > 0x050000 - m_dpr = devicePixelRatio (); + m_dpr = widget ()->devicePixelRatio (); #endif - setObjectName (QString::fromUtf8 ("canvas")); + + widget ()->setObjectName (QString::fromUtf8 ("canvas")); + widget ()->setBackgroundRole (QPalette::NoRole); + + bg = lay::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Window).rgb ()); + fg = lay::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Text).rgb ()); + active = lay::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Mid).rgb ()); + + widget ()->setAttribute (Qt::WA_NoSystemBackground); + + } #endif // The gamma value used for subsampling: something between 1.8 and 2.2. @@ -307,15 +321,7 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view) mp_redraw_thread = new lay::RedrawThread (this, view); -#if defined(HAVE_QT) - setBackgroundRole (QPalette::NoRole); - set_colors (lay::Color (palette ().color (QPalette::Normal, QPalette::Window).rgb ()), - lay::Color (palette ().color (QPalette::Normal, QPalette::Text).rgb ()), - lay::Color (palette ().color (QPalette::Normal, QPalette::Mid).rgb ())); - setAttribute (Qt::WA_NoSystemBackground); -#else - set_colors (0xffffffff, 0xff000000, 0xffc0c0c0); -#endif + set_colors (bg, fg, active); } LayoutCanvas::~LayoutCanvas () @@ -560,7 +566,7 @@ LayoutCanvas::free_resources () #if defined(HAVE_QT) void -LayoutCanvas::paintEvent (QPaintEvent *) +LayoutCanvas::paint_event () { // this is the update image request tl::SelfTimer timer_info (tl::verbosity () >= 41, tl::to_string (QObject::tr ("PaintEvent"))); @@ -655,7 +661,7 @@ LayoutCanvas::paintEvent (QPaintEvent *) do_render (m_viewport_l, *this, false); // produce the pixmap first and then overdraw with dynamic content. - QPainter painter (this); + QPainter painter (widget ()); QImage img = mp_image_fg->to_image (); #if QT_VERSION > 0x050000 img.setDevicePixelRatio (double (m_dpr)); @@ -978,27 +984,8 @@ LayoutCanvas::screenshot () return img; } -#if defined(HAVE_QT) -void -LayoutCanvas::resizeEvent (QResizeEvent *) -{ - do_resize (width (), height ()); -} -#endif - void -LayoutCanvas::resize (unsigned int width, unsigned int height) -{ - // pass down to the basic view object canvas - lay::ViewObjectWidget::resize (width, height); - - // don't wait until the layout system informs us - which may never take place when - // the widget isn't shown. - do_resize (width, height); -} - -void -LayoutCanvas::do_resize (unsigned int width, unsigned int height) +LayoutCanvas::resize_event (unsigned int width, unsigned int height) { unsigned int w = width * m_dpr, h = height * m_dpr; unsigned int wl = width * m_oversampling * m_dpr, hl = height * m_oversampling * m_dpr; @@ -1099,22 +1086,11 @@ LayoutCanvas::do_update_image () } #if defined(HAVE_QT) -bool -LayoutCanvas::event (QEvent *e) +void +LayoutCanvas::gtf_probe () { - if (e->type () == QEvent::MaxUser) { - - // GTF probe event - // record the contents (the screenshot) as ASCII text - if (gtf::Recorder::instance () && gtf::Recorder::instance ()->recording ()) { - gtf::Recorder::instance ()->probe (this, gtf::image_to_variant (screenshot ().to_image_copy ())); - } - - e->accept (); - return true; - - } else { - return QWidget::event (e); + if (gtf::Recorder::instance () && gtf::Recorder::instance ()->recording ()) { + gtf::Recorder::instance ()->probe (widget (), gtf::image_to_variant (screenshot ().to_image_copy ())); } } #endif diff --git a/src/laybasic/laybasic/layLayoutCanvas.h b/src/laybasic/laybasic/layLayoutCanvas.h index 2024692e1..2a9326b4a 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.h +++ b/src/laybasic/laybasic/layLayoutCanvas.h @@ -134,15 +134,11 @@ private: */ class LAYBASIC_PUBLIC LayoutCanvas - : public lay::ViewObjectWidget, + : public lay::ViewObjectUI, public lay::BitmapViewObjectCanvas, public lay::BitmapRedrawThreadCanvas, public lay::Drawings { -#if defined(HAVE_QT) -Q_OBJECT -#endif - public: LayoutCanvas (lay::LayoutViewBase *view); ~LayoutCanvas (); @@ -339,11 +335,6 @@ public: return m_viewport; } - /** - * @brief Resizes the canvas object in the Qt-less case - */ - void resize (unsigned int width, unsigned int height); - /** * @brief Gets (and resets) a flag indicating that drawing has finished */ @@ -399,13 +390,12 @@ private: tl::Mutex m_mutex; -#if defined(HAVE_QT) - virtual void paintEvent (QPaintEvent *); - virtual void resizeEvent (QResizeEvent *); - virtual bool event (QEvent *e); -#endif - virtual void key_event (unsigned int key, unsigned int buttons); + virtual void resize_event (unsigned int width, unsigned int height); +#if defined(HAVE_QT) + virtual void gtf_probe (); + virtual void paint_event (); +#endif // implementation of the lay::Drawings interface void update_drawings (); @@ -416,7 +406,6 @@ private: void do_update_image (); void do_end_of_drawing (); void do_redraw_all (bool force_redraw = true); - void do_resize (unsigned int width, unsigned int height); void prepare_drawing (); }; diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index 0e1fa29a7..81379af57 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -1637,13 +1637,13 @@ public: void absolute_coordinates (bool f); /** - * @brief Get the view object widget (the canvas where the layout is drawn and view objects are placed) + * @brief Gets the canvas object (where the layout is drawn and view objects are placed) * * This method intentionally delivers the ViewObjectWidget, not the * LayoutCanvas to emphasize that the LayoutCanvas object shall not * be modified. */ - lay::ViewObjectWidget *view_object_widget () + lay::LayoutCanvas *canvas () { return mp_canvas; } @@ -2825,11 +2825,6 @@ protected: virtual LayoutView *get_ui (); - lay::LayoutCanvas *canvas () - { - return mp_canvas; - } - bool configure (const std::string &name, const std::string &value); void config_finalize (); diff --git a/src/laybasic/laybasic/layMarker.cc b/src/laybasic/laybasic/layMarker.cc index 93b298099..7046745bb 100644 --- a/src/laybasic/laybasic/layMarker.cc +++ b/src/laybasic/laybasic/layMarker.cc @@ -189,7 +189,7 @@ void render_cell_inst (const db::Layout &layout, const db::CellInstArray &inst, // ------------------------------------------------------------------------ MarkerBase::MarkerBase (lay::LayoutViewBase *view) - : lay::ViewObject (view->view_object_widget ()), + : lay::ViewObject (view->canvas ()), m_line_width (-1), m_vertex_size (-1), m_halo (-1), m_text_enabled (true), m_vertex_shape (lay::ViewOp::Rect), m_line_style (-1), m_dither_pattern (-1), m_frame_pattern (0), mp_view (view) { // .. nothing yet .. diff --git a/src/laybasic/laybasic/layMouseTracker.cc b/src/laybasic/laybasic/layMouseTracker.cc index 9afc48058..8c10f0793 100644 --- a/src/laybasic/laybasic/layMouseTracker.cc +++ b/src/laybasic/laybasic/layMouseTracker.cc @@ -29,9 +29,9 @@ namespace lay { MouseTracker::MouseTracker (lay::LayoutViewBase *view) - : lay::ViewService (view->view_object_widget ()), mp_view (view) + : lay::ViewService (view->canvas ()), mp_view (view) { - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); } bool @@ -42,7 +42,7 @@ MouseTracker::mouse_move_event (const db::DPoint &p, unsigned int /*buttons*/, b // NOTE: because the tracker grabs first and grabbers are registered first gets served last, the // tracker will receive the event after all other mouse grabbers have been served and had their // chance to set the tracking position. - lay::ViewService *vs = mp_view->view_object_widget ()->active_service (); + lay::ViewService *vs = mp_view->canvas ()->active_service (); db::DPoint tp = p; if (vs && vs->enabled () && vs->has_tracking_position ()) { tp = vs->tracking_position (); diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc index bc22b0332..f5e48a4a5 100644 --- a/src/laybasic/laybasic/layMove.cc +++ b/src/laybasic/laybasic/layMove.cc @@ -35,7 +35,7 @@ namespace lay // MoveService implementation MoveService::MoveService (lay::LayoutViewBase *view) - : lay::ViewService (view->view_object_widget ()), + : lay::ViewService (view->canvas ()), m_dragging (false), m_dragging_transient (false), mp_editables (view), @@ -102,7 +102,7 @@ MoveService::key_event (unsigned int key, unsigned int /*buttons*/) if (! m_dragging && fabs (dx + dy) > 0.0 && mp_editables->has_selection ()) { // determine a shift distance which is 2, 5 or 10 times the grid and is more than 5 pixels - double dmin = double (5 /*pixels min shift*/) / widget ()->mouse_event_trans ().mag (); + double dmin = double (5 /*pixels min shift*/) / ui ()->mouse_event_trans ().mag (); double d = m_global_grid; while (d < dmin) { d *= 2.0; @@ -302,7 +302,7 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_ m_dragging = true; m_dragging_transient = drag_transient; - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); m_shift = db::DPoint (); @@ -314,7 +314,7 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_ m_dragging = false; - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); mp_editables->end_move (p, ac_from_buttons (buttons), mp_transaction.release ()); if (m_dragging_transient) { @@ -334,7 +334,7 @@ MoveService::drag_cancel () if (m_dragging) { mp_editables->edit_cancel (); - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); m_dragging = false; diff --git a/src/laybasic/laybasic/layRubberBox.cc b/src/laybasic/laybasic/layRubberBox.cc index 6f0cb8c07..6930c5774 100644 --- a/src/laybasic/laybasic/layRubberBox.cc +++ b/src/laybasic/laybasic/layRubberBox.cc @@ -32,7 +32,7 @@ namespace lay // ------------------------------------------------------------- // RubberBox implementation -RubberBox::RubberBox (lay::ViewObjectWidget *widget, unsigned int color, const db::DPoint &p1, const db::DPoint &p2) +RubberBox::RubberBox (lay::ViewObjectUI *widget, unsigned int color, const db::DPoint &p1, const db::DPoint &p2) : lay::ViewObject (widget, false /*not static*/), m_p1 (p1), m_p2 (p2), m_color (color), m_stipple (0) { } diff --git a/src/laybasic/laybasic/layRubberBox.h b/src/laybasic/laybasic/layRubberBox.h index 020084f59..8893fe68a 100644 --- a/src/laybasic/laybasic/layRubberBox.h +++ b/src/laybasic/laybasic/layRubberBox.h @@ -34,7 +34,7 @@ class LAYBASIC_PUBLIC RubberBox : public lay::ViewObject { public: - RubberBox (lay::ViewObjectWidget *canvas, unsigned int color, const db::DPoint &p1, const db::DPoint &p2); + RubberBox (lay::ViewObjectUI *canvas, unsigned int color, const db::DPoint &p1, const db::DPoint &p2); void set_color (unsigned int color); void set_stipple (unsigned int s); diff --git a/src/laybasic/laybasic/laySelector.cc b/src/laybasic/laybasic/laySelector.cc index 1db1fd427..5ddb52021 100644 --- a/src/laybasic/laybasic/laySelector.cc +++ b/src/laybasic/laybasic/laySelector.cc @@ -43,7 +43,7 @@ SelectionService::SelectionService (lay::LayoutViewBase *view) : #if defined(HAVE_QT) QObject (), #endif - lay::ViewService (view->view_object_widget ()), + lay::ViewService (view->canvas ()), mp_view (view), mp_box (0), m_color (0), @@ -114,7 +114,7 @@ SelectionService::reset_box () { if (mp_box) { - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); delete mp_box; mp_box = 0; @@ -223,7 +223,7 @@ SelectionService::mouse_click_event (const db::DPoint &p, unsigned int buttons, reset_box (); } - if (prio && mp_view && widget ()->mouse_event_viewport ().contains (p) && (buttons & lay::LeftButton) != 0) { + if (prio && mp_view && ui ()->mouse_event_viewport ().contains (p) && (buttons & lay::LeftButton) != 0) { lay::Editable::SelectionMode mode = lay::Editable::Replace; bool shift = ((buttons & lay::ShiftButton) != 0); @@ -314,10 +314,10 @@ SelectionService::begin (const db::DPoint &pos) m_p1 = pos; m_p2 = pos; - mp_box = new lay::RubberBox (widget (), m_color, pos, pos); + mp_box = new lay::RubberBox (ui (), m_color, pos, pos); mp_box->set_stipple (6); // coarse hatched - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } } diff --git a/src/laybasic/laybasic/layUtils.cc b/src/laybasic/laybasic/layUtils.cc new file mode 100644 index 000000000..ba6084aad --- /dev/null +++ b/src/laybasic/laybasic/layUtils.cc @@ -0,0 +1,45 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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 "layUtils.h" + +#if defined(HAVE_QT) +# include +#endif + +namespace lay { + +bool +has_gui () +{ +#if defined(HAVE_QT) +#if QT_VERSION < 0x50000 + return (QApplication::type () != Qt::Tty); +#else + return (dynamic_cast (QCoreApplication::instance ()) != 0); +#endif +#else + return false; +#endif +} + +} diff --git a/src/laybasic/laybasic/layUtils.h b/src/laybasic/laybasic/layUtils.h new file mode 100644 index 000000000..d5aacb692 --- /dev/null +++ b/src/laybasic/laybasic/layUtils.h @@ -0,0 +1,38 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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_layUtils +#define HDR_layUtils + +#include "laybasicCommon.h" + +namespace lay { + +/** + * @brief Returns true, if GUI is enabled + */ +LAYBASIC_PUBLIC bool has_gui (); + +} + +#endif + diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index 9577f9fcb..0e5f97719 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -25,7 +25,8 @@ # include # include # include -# include +# include +# include #endif #include "layViewObject.h" @@ -34,6 +35,7 @@ #if defined(HAVE_QT) # include "layDragDropData.h" #endif +#include "layUtils.h" #include "tlException.h" #include "tlAlgorithm.h" #include "tlExceptions.h" @@ -72,7 +74,7 @@ qt_to_buttons (Qt::MouseButtons b, Qt::KeyboardModifiers m) // --------------------------------------------------------------- // BackgroundViewObject implementation -BackgroundViewObject::BackgroundViewObject (ViewObjectWidget *widget) +BackgroundViewObject::BackgroundViewObject (ViewObjectUI *widget) : mp_widget (widget), m_visible (true), m_z_order (0) { if (widget) { @@ -115,7 +117,7 @@ BackgroundViewObject::z_order (int z) // --------------------------------------------------------------- // ViewObject implementation -ViewObject::ViewObject (ViewObjectWidget *widget, bool _static) +ViewObject::ViewObject (ViewObjectUI *widget, bool _static) : mp_widget (widget), m_static (_static), m_visible (true), m_dismissable (false) { if (widget) { @@ -178,7 +180,7 @@ ViewObject::freeze () // --------------------------------------------------------------- // ViewService implementation -ViewService::ViewService (ViewObjectWidget *widget) +ViewService::ViewService (ViewObjectUI *widget) : mp_widget (widget), m_abs_grab (false), m_enabled (true) { if (widget) { @@ -206,14 +208,287 @@ ViewService::set_cursor (lay::Cursor::cursor_shape cursor) mp_widget->set_cursor (cursor); } +// --------------------------------------------------------------- +// ViewObjectQWidget implementation + +#if defined(HAVE_QT) + +class ViewObjectQWidget : public QWidget +{ +public: + ViewObjectQWidget (ViewObjectUI *view) + : QWidget (), mp_view (view) + { + // .. nothing yet .. + } + + void resizeEvent (QResizeEvent *) + { + mp_view->resize_event (width (), height ()); + } + + bool focusNextPrevChild (bool /*next*/) + { + return false; + } + + void keyPressEvent (QKeyEvent *e) + { + BEGIN_PROTECTED + unsigned int buttons = qt_to_buttons (Qt::MouseButtons (), e->modifiers ()); + mp_view->send_key_press_event ((unsigned int) e->key (), buttons); + END_PROTECTED + } + + DragDropDataBase *get_drag_drop_data (const QMimeData *data) + { + if (! data || ! data->hasFormat (QString::fromUtf8 (drag_drop_mime_type ()))) { + return 0; + } + + QByteArray ba = data->data (QString::fromUtf8 (drag_drop_mime_type ())); + + // TODO: provide some global mechanism to register drag & drop classes + std::unique_ptr cd (new CellDragDropData ()); + if (cd->deserialize (ba)) { + return cd.release (); + } + + // TODO: more ... + + return 0; + } + + void dragEnterEvent (QDragEnterEvent *event) + { + BEGIN_PROTECTED + + const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ()); + if (dd) { + + db::DPoint p = mp_view->pixel_to_um (db::Point (event->pos ().x (), event->pos ().y ())); + + bool done = mp_view->drag_enter_event (p, dd); + ViewObjectUI::service_iterator svc = mp_view->begin_services (); + while (svc != mp_view->end_services () && !done) { + ViewObjectUI::service_iterator next = svc; + ++next; + done = (*svc)->drag_enter_event (p, dd); + svc = next; + } + + if (done) { + event->acceptProposedAction (); + } + + } + + END_PROTECTED + } + + void dragLeaveEvent (QDragLeaveEvent * /*event*/) + { + BEGIN_PROTECTED + + mp_view->drag_leave_event (); + ViewObjectUI::service_iterator svc = mp_view->begin_services (); + while (svc != mp_view->end_services ()) { + ViewObjectUI::service_iterator next = svc; + ++next; + (*svc)->drag_leave_event (); + svc = next; + } + + END_PROTECTED + } + + void dragMoveEvent (QDragMoveEvent *event) + { + BEGIN_PROTECTED + + const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ()); + if (dd) { + + db::DPoint p = mp_view->pixel_to_um (db::Point (event->pos ().x (), event->pos ().y ())); + + bool done = mp_view->drag_move_event (p, dd); + ViewObjectUI::service_iterator svc = mp_view->begin_services (); + while (svc != mp_view->end_services () && !done) { + ViewObjectUI::service_iterator next = svc; + ++next; + done = (*svc)->drag_move_event (p, dd); + svc = next; + } + + } + + END_PROTECTED + } + + void dropEvent (QDropEvent *event) + { + BEGIN_PROTECTED + + const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ()); + if (dd) { + + db::DPoint p = mp_view->pixel_to_um (db::Point (event->pos ().x (), event->pos ().y ())); + + bool done = mp_view->drop_event (p, dd); + ViewObjectUI::service_iterator svc = mp_view->begin_services (); + while (svc != mp_view->end_services () && !done) { + ViewObjectUI::service_iterator next = svc; + ++next; + done = (*svc)->drop_event (p, dd); + svc = next; + } + + } + + END_PROTECTED + } + + void mouseMoveEvent (QMouseEvent *e) + { + BEGIN_PROTECTED + + db::DPoint p; +#if QT_VERSION < 0x60000 + p = db::DPoint (e->pos ().x (), e->pos ().y ()); +#else + p = db::DPoint (e->position ().x (), e->position ().y ()); +#endif + + mp_view->send_mouse_move_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); + + END_PROTECTED + } + + void mouseDoubleClickEvent (QMouseEvent *e) + { + BEGIN_PROTECTED + + db::DPoint p; +#if QT_VERSION < 0x60000 + p = db::DPoint (e->pos ().x (), e->pos ().y ()); +#else + p = db::DPoint (e->position ().x (), e->position ().y ()); +#endif + + mp_view->send_mouse_double_clicked_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); + + END_PROTECTED + } + + void +#if QT_VERSION >= 0x60000 + enterEvent (QEnterEvent * /*event*/) +#else + enterEvent (QEvent * /*event*/) +#endif + { + BEGIN_PROTECTED + mp_view->send_enter_event (); + END_PROTECTED + } + + void leaveEvent (QEvent * /*event*/) + { + BEGIN_PROTECTED + mp_view->send_leave_event (); + END_PROTECTED + } + + void wheelEvent (QWheelEvent *e) + { + BEGIN_PROTECTED + + db::DPoint p; +#if QT_VERSION < 0x60000 + int delta = e->delta (); + p = db::DPoint (e->pos ().x (), e->pos ().y ()); + bool horizontal = (e->orientation () == Qt::Horizontal); +#else + int delta = e->angleDelta ().y (); + p = db::DPoint (e->position ().x (), e->position ().y ()); + bool horizontal = false; +#endif + + e->ignore (); + + mp_view->send_wheel_event (delta, horizontal, p, qt_to_buttons (e->buttons (), e->modifiers ())); + + END_PROTECTED + } + + void mousePressEvent (QMouseEvent *e) + { + BEGIN_PROTECTED + + db::DPoint p; +#if QT_VERSION < 0x60000 + p = db::DPoint (e->pos ().x (), e->pos ().y ()); +#else + p = db::DPoint (e->position ().x (), e->position ().y ()); +#endif + + mp_view->send_mouse_press_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); + + END_PROTECTED + } + + void mouseReleaseEvent (QMouseEvent *e) + { + BEGIN_PROTECTED + + db::DPoint p; +#if QT_VERSION < 0x60000 + p = db::DPoint (e->pos ().x (), e->pos ().y ()); +#else + p = db::DPoint (e->position ().x (), e->position ().y ()); +#endif + + mp_view->send_mouse_release_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); + + END_PROTECTED + } + + void paintEvent (QPaintEvent *) + { + BEGIN_PROTECTED + mp_view->paint_event (); + END_PROTECTED + } + +#if defined(HAVE_QT) + bool event (QEvent *e) + { + if (e->type () == QEvent::MaxUser) { + + // GTF probe event + // record the contents (the screenshot) as ASCII text + mp_view->gtf_probe (); + + e->accept (); + return true; + + } else { + return QWidget::event (e); + } + } +#endif + +private: + ViewObjectUI *mp_view; +}; + +#endif + // --------------------------------------------------------------- // ViewObjectWidget implementation -ViewObjectWidget::ViewObjectWidget () -#if defined(HAVE_QT) - : QWidget (), -#endif - m_view_objects_dismissed (false), +ViewObjectUI::ViewObjectUI () + : m_view_objects_dismissed (false), m_needs_update_static (false), m_needs_update_bg (false), mp_active_service (0), @@ -228,14 +503,19 @@ ViewObjectWidget::ViewObjectWidget () m_image_updated (false) { #if defined(HAVE_QT) - setMouseTracking (true); - setAcceptDrops (true); + if (lay::has_gui ()) { + mp_widget = new ViewObjectQWidget (this); + mp_widget->setMouseTracking (true); + mp_widget->setAcceptDrops (true); + } else { + mp_widget = 0; + } #endif - m_objects.changed ().add (this, &ViewObjectWidget::objects_changed); + m_objects.changed ().add (this, &ViewObjectUI::objects_changed); } -ViewObjectWidget::~ViewObjectWidget () +ViewObjectUI::~ViewObjectUI () { // release any mouse grabs now while (m_grabbed.begin () != m_grabbed.end ()) { @@ -248,13 +528,13 @@ ViewObjectWidget::~ViewObjectWidget () } void -ViewObjectWidget::register_service (lay::ViewService *svc) +ViewObjectUI::register_service (lay::ViewService *svc) { m_services.push_back (svc); } void -ViewObjectWidget::unregister_service (lay::ViewService *svc) +ViewObjectUI::unregister_service (lay::ViewService *svc) { if (mp_active_service == svc) { mp_active_service = 0; @@ -272,7 +552,7 @@ ViewObjectWidget::unregister_service (lay::ViewService *svc) } void -ViewObjectWidget::activate (lay::ViewService *service) +ViewObjectUI::activate (lay::ViewService *service) { if (mp_active_service != service) { if (mp_active_service) { @@ -296,22 +576,22 @@ END_PROTECTED } void -ViewObjectWidget::set_cursor (lay::Cursor::cursor_shape cursor) +ViewObjectUI::set_cursor (lay::Cursor::cursor_shape cursor) { m_cursor = cursor; } void -ViewObjectWidget::set_default_cursor (lay::Cursor::cursor_shape cursor) +ViewObjectUI::set_default_cursor (lay::Cursor::cursor_shape cursor) { if (cursor != m_default_cursor) { m_default_cursor = cursor; #if defined(HAVE_QT) - if (m_cursor == lay::Cursor::none) { + if (m_cursor == lay::Cursor::none && mp_widget) { if (m_default_cursor == lay::Cursor::none) { - unsetCursor (); + mp_widget->unsetCursor (); } else { - setCursor (lay::Cursor::qcursor (m_default_cursor)); + mp_widget->setCursor (lay::Cursor::qcursor (m_default_cursor)); } } #endif @@ -319,7 +599,7 @@ ViewObjectWidget::set_default_cursor (lay::Cursor::cursor_shape cursor) } void -ViewObjectWidget::ensure_entered () +ViewObjectUI::ensure_entered () { if (! m_mouse_inside) { send_enter_event (); @@ -327,29 +607,31 @@ ViewObjectWidget::ensure_entered () } void -ViewObjectWidget::begin_mouse_event (lay::Cursor::cursor_shape cursor) +ViewObjectUI::begin_mouse_event (lay::Cursor::cursor_shape cursor) { m_cursor = cursor; } void -ViewObjectWidget::end_mouse_event () +ViewObjectUI::end_mouse_event () { #if defined(HAVE_QT) - if (m_cursor == lay::Cursor::none) { - if (m_default_cursor == lay::Cursor::none) { - unsetCursor (); - } else { - setCursor (lay::Cursor::qcursor (m_default_cursor)); + if (mp_widget) { + if (m_cursor == lay::Cursor::none) { + if (m_default_cursor == lay::Cursor::none) { + mp_widget->unsetCursor (); + } else { + mp_widget->setCursor (lay::Cursor::qcursor (m_default_cursor)); + } + } else if (m_cursor != lay::Cursor::keep) { + mp_widget->setCursor (lay::Cursor::qcursor (m_cursor)); } - } else if (m_cursor != lay::Cursor::keep) { - setCursor (lay::Cursor::qcursor (m_cursor)); } #endif } void -ViewObjectWidget::send_key_press_event (unsigned int key, unsigned int buttons) +ViewObjectUI::send_key_press_event (unsigned int key, unsigned int buttons) { bool done = false; if (mp_active_service) { @@ -362,7 +644,7 @@ ViewObjectWidget::send_key_press_event (unsigned int key, unsigned int buttons) } void -ViewObjectWidget::do_mouse_move () +ViewObjectUI::do_mouse_move () { m_in_mouse_move = true; @@ -443,7 +725,7 @@ ViewObjectWidget::do_mouse_move () } void -ViewObjectWidget::send_mouse_move_event (const db::DPoint &pt, unsigned int buttons) +ViewObjectUI::send_mouse_move_event (const db::DPoint &pt, unsigned int buttons) { ensure_entered (); m_mouse_pos = pt; @@ -452,7 +734,7 @@ ViewObjectWidget::send_mouse_move_event (const db::DPoint &pt, unsigned int butt } void -ViewObjectWidget::send_leave_event () +ViewObjectUI::send_leave_event () { try { @@ -492,7 +774,7 @@ ViewObjectWidget::send_leave_event () } void -ViewObjectWidget::send_enter_event () +ViewObjectUI::send_enter_event () { m_mouse_inside = true; @@ -527,11 +809,13 @@ ViewObjectWidget::send_enter_event () } void -ViewObjectWidget::send_mouse_press_event (const db::DPoint &pt, unsigned int buttons) +ViewObjectUI::send_mouse_press_event (const db::DPoint &pt, unsigned int buttons) { ensure_entered (); #if defined(HAVE_QT) - setFocus (); + if (mp_widget) { + mp_widget->setFocus (); + } #endif m_mouse_pos = pt; @@ -543,13 +827,15 @@ ViewObjectWidget::send_mouse_press_event (const db::DPoint &pt, unsigned int but } void -ViewObjectWidget::send_mouse_double_clicked_event (const db::DPoint &pt, unsigned int buttons) +ViewObjectUI::send_mouse_double_clicked_event (const db::DPoint &pt, unsigned int buttons) { ensure_entered (); begin_mouse_event (lay::Cursor::none); #if defined(HAVE_QT) - setFocus (); + if (mp_widget) { + mp_widget->setFocus (); + } #endif bool done = false; @@ -587,7 +873,7 @@ ViewObjectWidget::send_mouse_double_clicked_event (const db::DPoint &pt, unsigne } void -ViewObjectWidget::send_mouse_release_event (const db::DPoint &pt, unsigned int /*buttons*/) +ViewObjectUI::send_mouse_release_event (const db::DPoint &pt, unsigned int /*buttons*/) { try { @@ -651,7 +937,7 @@ ViewObjectWidget::send_mouse_release_event (const db::DPoint &pt, unsigned int / } void -ViewObjectWidget::send_wheel_event (int delta, bool horizontal, const db::DPoint &pt, unsigned int buttons) +ViewObjectUI::send_wheel_event (int delta, bool horizontal, const db::DPoint &pt, unsigned int buttons) { ensure_entered (); begin_mouse_event (); @@ -687,291 +973,57 @@ ViewObjectWidget::send_wheel_event (int delta, bool horizontal, const db::DPoint } -#if defined(HAVE_QT) - -bool -ViewObjectWidget::focusNextPrevChild (bool /*next*/) -{ - return false; -} - -void -ViewObjectWidget::keyPressEvent (QKeyEvent *e) -{ -BEGIN_PROTECTED - unsigned int buttons = qt_to_buttons (Qt::MouseButtons (), e->modifiers ()); - send_key_press_event ((unsigned int) e->key (), buttons); -END_PROTECTED -} - -DragDropDataBase *get_drag_drop_data (const QMimeData *data) -{ - if (! data || ! data->hasFormat (QString::fromUtf8 (drag_drop_mime_type ()))) { - return 0; - } - - QByteArray ba = data->data (QString::fromUtf8 (drag_drop_mime_type ())); - - // TODO: provide some global mechanism to register drag & drop classes - std::unique_ptr cd (new CellDragDropData ()); - if (cd->deserialize (ba)) { - return cd.release (); - } - - // TODO: more ... - - return 0; -} - -void -ViewObjectWidget::dragEnterEvent (QDragEnterEvent *event) -{ -BEGIN_PROTECTED - const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ()); - if (dd) { - - db::DPoint p = pixel_to_um (db::Point (event->pos ().x (), event->pos ().y ())); - - bool done = drag_enter_event (p, dd); - service_iterator svc = begin_services (); - while (svc != end_services () && !done) { - service_iterator next = svc; - ++next; - done = (*svc)->drag_enter_event (p, dd); - svc = next; - } - - if (done) { - event->acceptProposedAction (); - } - - } - -END_PROTECTED -} - -void -ViewObjectWidget::dragLeaveEvent (QDragLeaveEvent * /*event*/) -{ -BEGIN_PROTECTED - - drag_leave_event (); - service_iterator svc = begin_services (); - while (svc != end_services ()) { - service_iterator next = svc; - ++next; - (*svc)->drag_leave_event (); - svc = next; - } - -END_PROTECTED -} - -void -ViewObjectWidget::dragMoveEvent (QDragMoveEvent *event) -{ -BEGIN_PROTECTED - - const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ()); - if (dd) { - - db::DPoint p = pixel_to_um (db::Point (event->pos ().x (), event->pos ().y ())); - - bool done = drag_move_event (p, dd); - service_iterator svc = begin_services (); - while (svc != end_services () && !done) { - service_iterator next = svc; - ++next; - done = (*svc)->drag_move_event (p, dd); - svc = next; - } - - } - -END_PROTECTED -} - -void -ViewObjectWidget::dropEvent (QDropEvent *event) -{ -BEGIN_PROTECTED - - const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ()); - if (dd) { - - db::DPoint p = pixel_to_um (db::Point (event->pos ().x (), event->pos ().y ())); - - bool done = drop_event (p, dd); - service_iterator svc = begin_services (); - while (svc != end_services () && !done) { - service_iterator next = svc; - ++next; - done = (*svc)->drop_event (p, dd); - svc = next; - } - - } - -END_PROTECTED -} - -void -ViewObjectWidget::mouseMoveEvent (QMouseEvent *e) -{ -BEGIN_PROTECTED - - db::DPoint p; -#if QT_VERSION < 0x60000 - p = db::DPoint (e->pos ().x (), e->pos ().y ()); -#else - p = db::DPoint (e->position ().x (), e->position ().y ()); -#endif - - send_mouse_move_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); - -END_PROTECTED -} - void -ViewObjectWidget::mouseDoubleClickEvent (QMouseEvent *e) -{ -BEGIN_PROTECTED - - db::DPoint p; -#if QT_VERSION < 0x60000 - p = db::DPoint (e->pos ().x (), e->pos ().y ()); -#else - p = db::DPoint (e->position ().x (), e->position ().y ()); -#endif - - send_mouse_double_clicked_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); - -END_PROTECTED -} - -void -#if QT_VERSION >= 0x60000 -ViewObjectWidget::enterEvent (QEnterEvent * /*event*/) -#else -ViewObjectWidget::enterEvent (QEvent * /*event*/) -#endif -{ -BEGIN_PROTECTED - send_enter_event (); -END_PROTECTED -} - -void -ViewObjectWidget::leaveEvent (QEvent * /*event*/) -{ -BEGIN_PROTECTED - send_leave_event (); -END_PROTECTED -} - -void -ViewObjectWidget::wheelEvent (QWheelEvent *e) -{ -BEGIN_PROTECTED - - db::DPoint p; -#if QT_VERSION < 0x60000 - int delta = e->delta (); - p = db::DPoint (e->pos ().x (), e->pos ().y ()); - bool horizontal = (e->orientation () == Qt::Horizontal); -#else - int delta = e->angleDelta ().y (); - p = db::DPoint (e->position ().x (), e->position ().y ()); - bool horizontal = false; -#endif - - e->ignore (); - - send_wheel_event (delta, horizontal, p, qt_to_buttons (e->buttons (), e->modifiers ())); - -END_PROTECTED -} - -void -ViewObjectWidget::mousePressEvent (QMouseEvent *e) -{ -BEGIN_PROTECTED - - db::DPoint p; -#if QT_VERSION < 0x60000 - p = db::DPoint (e->pos ().x (), e->pos ().y ()); -#else - p = db::DPoint (e->position ().x (), e->position ().y ()); -#endif - - send_mouse_press_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); - -END_PROTECTED -} - -void -ViewObjectWidget::mouseReleaseEvent (QMouseEvent *e) -{ -BEGIN_PROTECTED - - db::DPoint p; -#if QT_VERSION < 0x60000 - p = db::DPoint (e->pos ().x (), e->pos ().y ()); -#else - p = db::DPoint (e->position ().x (), e->position ().y ()); -#endif - - send_mouse_release_event (p, qt_to_buttons (e->buttons (), e->modifiers ())); - -END_PROTECTED -} - -#endif - -void -ViewObjectWidget::resize (unsigned int w, unsigned int h) +ViewObjectUI::resize (unsigned int w, unsigned int h) { m_widget_width = w; m_widget_height = h; #if defined(HAVE_QT) - QWidget::resize (w, h); + + if (mp_widget) { + mp_widget->resize (w, h); + } + + // don't wait until the layout system informs us - which may never take place when + // the widget isn't shown. + resize_event (w, h); #endif } int -ViewObjectWidget::widget_height () const +ViewObjectUI::widget_height () const { #if defined(HAVE_QT) - return height (); + return mp_widget ? mp_widget->height () : m_widget_height; #else return m_widget_height; #endif } int -ViewObjectWidget::widget_width () const +ViewObjectUI::widget_width () const { #if defined(HAVE_QT) - return width (); + return mp_widget ? mp_widget->width () : m_widget_width; #else return m_widget_width; #endif } db::DPoint -ViewObjectWidget::pixel_to_um (const db::Point &pt) const +ViewObjectUI::pixel_to_um (const db::Point &pt) const { return m_trans.inverted () * db::DPoint (pt.x (), widget_height () - 1 - pt.y ()); } db::DPoint -ViewObjectWidget::pixel_to_um (const db::DPoint &pt) const +ViewObjectUI::pixel_to_um (const db::DPoint &pt) const { return m_trans.inverted () * db::DPoint (pt.x (), widget_height () - 1 - pt.y ()); } void -ViewObjectWidget::mouse_event_trans (const db::DCplxTrans &trans) +ViewObjectUI::mouse_event_trans (const db::DCplxTrans &trans) { if (trans != m_trans) { m_trans = trans; @@ -984,7 +1036,7 @@ ViewObjectWidget::mouse_event_trans (const db::DCplxTrans &trans) } void -ViewObjectWidget::drag_cancel () +ViewObjectUI::drag_cancel () { for (service_iterator svc = begin_services (); svc != end_services (); ++svc) { (*svc)->drag_cancel (); @@ -1005,7 +1057,7 @@ namespace } void -ViewObjectWidget::do_render_bg (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) +ViewObjectUI::do_render_bg (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) { m_needs_update_bg = false; @@ -1028,7 +1080,7 @@ ViewObjectWidget::do_render_bg (const lay::Viewport &vp, lay::ViewObjectCanvas & } void -ViewObjectWidget::do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas, bool st) +ViewObjectUI::do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas, bool st) { if (st) { m_needs_update_static = false; @@ -1046,7 +1098,7 @@ ViewObjectWidget::do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &can } void -ViewObjectWidget::grab_mouse (ViewService *obj, bool a) +ViewObjectUI::grab_mouse (ViewService *obj, bool a) { obj->m_abs_grab = a; // not used currently @@ -1061,7 +1113,7 @@ ViewObjectWidget::grab_mouse (ViewService *obj, bool a) } void -ViewObjectWidget::ungrab_mouse (ViewService *obj) +ViewObjectUI::ungrab_mouse (ViewService *obj) { std::list::iterator g; for (g = m_grabbed.begin (); g != m_grabbed.end () && *g != obj; ++g) { @@ -1073,7 +1125,7 @@ ViewObjectWidget::ungrab_mouse (ViewService *obj) } void -ViewObjectWidget::freeze (ViewObject *obj) +ViewObjectUI::freeze (ViewObject *obj) { if (! obj->m_static) { obj->m_static = true; @@ -1083,7 +1135,7 @@ ViewObjectWidget::freeze (ViewObject *obj) } void -ViewObjectWidget::thaw (ViewObject *obj) +ViewObjectUI::thaw (ViewObject *obj) { if (obj->m_static) { obj->m_static = false; @@ -1107,10 +1159,36 @@ ViewObjectWidget::image_updated () m_image_updated = false; return f; } +#else +void +ViewObjectUI::update () +{ + if (mp_widget) { + mp_widget->update (); + } +} #endif void -ViewObjectWidget::touch () +ViewObjectUI::resize_event (unsigned int /*w*/, unsigned int /*h*/) +{ + // .. nothing yet .. +} + +void +ViewObjectUI::paint_event () +{ + // .. nothing yet .. +} + +void +ViewObjectUI::gtf_probe () +{ + // .. nothing yet .. +} + +void +ViewObjectUI::touch () { if (! m_needs_update_static) { m_needs_update_static = true; @@ -1119,7 +1197,7 @@ ViewObjectWidget::touch () } void -ViewObjectWidget::touch_bg () +ViewObjectUI::touch_bg () { if (! m_needs_update_bg) { m_needs_update_bg = true; @@ -1128,7 +1206,7 @@ ViewObjectWidget::touch_bg () } void -ViewObjectWidget::set_dismiss_view_objects (bool dismiss) +ViewObjectUI::set_dismiss_view_objects (bool dismiss) { if (dismiss != m_view_objects_dismissed) { m_view_objects_dismissed = dismiss; @@ -1138,14 +1216,14 @@ ViewObjectWidget::set_dismiss_view_objects (bool dismiss) } void -ViewObjectWidget::objects_changed () +ViewObjectUI::objects_changed () { touch (); update (); } db::DBox -ViewObjectWidget::mouse_event_viewport () const +ViewObjectUI::mouse_event_viewport () const { db::DPoint p1 = m_trans.inverted () * db::DPoint (0, 0); db::DPoint p2 = m_trans.inverted () * db::DPoint (widget_width (), widget_height ()); diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index e6997d139..242558d00 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -36,7 +36,6 @@ # include # include # include -# include #endif #include "tlObjectCollection.h" @@ -48,6 +47,7 @@ #include "layBitmapRenderer.h" #if defined(HAVE_QT) +class QWidget; class QMouseEvent; class QImage; class QDragEnterEvent; @@ -66,7 +66,7 @@ namespace db namespace lay { class Viewport; -class ViewObjectWidget; +class ViewObjectUI; class ViewObjectCanvas; class CanvasPlane; class Bitmap; @@ -77,6 +77,8 @@ class BitmapBuffer; class DragDropDataBase; #endif +class ViewObjectQWidget; + /** * @brief A view service * @@ -96,7 +98,7 @@ public: /** * @brief Constructor */ - ViewService (ViewObjectWidget *widget = 0); + ViewService (ViewObjectUI *widget = 0); /** * @brief Destructor @@ -238,7 +240,7 @@ public: /** * @brief Accessor to the widget pointer */ - ViewObjectWidget *widget () const + ViewObjectUI *ui () const { return mp_widget; } @@ -289,9 +291,9 @@ public: } private: - friend class ViewObjectWidget; + friend class ViewObjectUI; - ViewObjectWidget *mp_widget; + ViewObjectUI *mp_widget; bool m_abs_grab; bool m_enabled; }; @@ -315,7 +317,7 @@ public: * @param widget The widget object that the object is shown on. * @param _static True, if the object is in frozen mode initially */ - BackgroundViewObject (ViewObjectWidget *widget = 0); + BackgroundViewObject (ViewObjectUI *widget = 0); /** * @brief The destructor @@ -333,9 +335,9 @@ public: /** * @brief Accessor to the widget object pointer */ - ViewObjectWidget *widget () const + ViewObjectUI *widget () const { - return const_cast (mp_widget.get()); + return const_cast (mp_widget.get()); } /** @@ -381,12 +383,12 @@ public: void z_order (int z); private: - friend class ViewObjectWidget; + friend class ViewObjectUI; BackgroundViewObject (const BackgroundViewObject &d); BackgroundViewObject &operator= (const BackgroundViewObject &d); - tl::weak_ptr mp_widget; + tl::weak_ptr mp_widget; bool m_visible; int m_z_order; }; @@ -415,7 +417,7 @@ public: * @param widget The widget object that the object is shown on. * @param _static True, if the object is in frozen mode initially */ - ViewObject (ViewObjectWidget *widget = 0, bool _static = true); + ViewObject (ViewObjectUI *widget = 0, bool _static = true); /** * @brief The destructor @@ -434,9 +436,9 @@ public: /** * @brief Accessor to the widget object pointer */ - ViewObjectWidget *widget () const + ViewObjectUI *widget () const { - return const_cast (mp_widget.get()); + return const_cast (mp_widget.get()); } /** @@ -496,12 +498,12 @@ public: void freeze (); private: - friend class ViewObjectWidget; + friend class ViewObjectUI; ViewObject (const ViewObject &d); ViewObject &operator= (const ViewObject &d); - tl::weak_ptr mp_widget; + tl::weak_ptr mp_widget; bool m_static; bool m_visible; bool m_dismissable; @@ -568,10 +570,7 @@ enum KeyCodes { * painting. */ -class LAYBASIC_PUBLIC ViewObjectWidget : -#if defined(HAVE_QT) - public QWidget, -#endif +class LAYBASIC_PUBLIC ViewObjectUI : public tl::Object { public: @@ -583,12 +582,12 @@ public: /** * @brief ctor */ - ViewObjectWidget (); + ViewObjectUI (); /** * @brief dtor */ - ~ViewObjectWidget (); + ~ViewObjectUI (); /** * @brief Cancel all drag operations @@ -952,6 +951,16 @@ public: bool image_updated (); #endif +#if defined(HAVE_QT) + /** + * @brief Gets the QWidget representing this canvas visually in Qt + */ + QWidget *widget () + { + return mp_widget; + } +#endif + /** * @brief External entry point for key press event generation */ @@ -992,79 +1001,14 @@ public: */ void send_wheel_event (int delta, bool horizontal, const db::DPoint &pt, unsigned int buttons); + /** + * @brief Resizes the widget + */ + void resize (unsigned int w, unsigned int h); + protected: -#if defined(HAVE_QT) - /** - * @brief Qt focus event handler - */ - bool focusNextPrevChild (bool next); + friend class ViewObjectQWidget; - /** - * @brief Qt keyboard event handler - */ - void keyPressEvent (QKeyEvent *e); - - /** - * @brief Qt mouse move event handler - */ - void mouseMoveEvent (QMouseEvent *e); - - /** - * @brief Qt mouse leave event handler - */ - void leaveEvent (QEvent *e); - - /** - * @brief Qt mouse enter event handler - */ -#if QT_VERSION >= 0x60000 - void enterEvent (QEnterEvent *e); -#else - void enterEvent (QEvent *e); -#endif - - /** - * @brief Qt mouse button press event handler - */ - void mousePressEvent (QMouseEvent *e); - - /** - * @brief Qt mouse button double-click event handler - */ - void mouseDoubleClickEvent (QMouseEvent *e); - - /** - * @brief Qt mouse button release event handler - */ - void mouseReleaseEvent (QMouseEvent *e); - - /** - * @brief Qt drag enter event handler - */ - void dragEnterEvent (QDragEnterEvent *event); - - /** - * @brief Qt drag leave event handler - */ - void dragLeaveEvent (QDragLeaveEvent *event); - - /** - * @brief Qt drag enter event handler - */ - void dragMoveEvent (QDragMoveEvent *event); - - /** - * @brief Qt drop event handler - */ - void dropEvent (QDropEvent *event); - - /** - * @brief Qt mouse wheel event handler - */ - void wheelEvent (QWheelEvent *e); -#endif - -#if !defined(HAVE_QT) /** * @brief Emulates the update() method in the non-Qt case * @@ -1072,7 +1016,6 @@ protected: * update needed flag. */ void update (); -#endif /** * @brief Set the transformation for mouse events @@ -1080,15 +1023,28 @@ protected: void mouse_event_trans (const db::DCplxTrans &trans); /** - * @brief Resizes the widget + * @brief Gets called when the view is resized */ - void resize (unsigned int w, unsigned int h); + virtual void resize_event (unsigned int w, unsigned int h); + + /** + * @brief Receives the paint event from Qt + */ + virtual void paint_event (); + + /** + * @brief GTF probe event + */ + virtual void gtf_probe (); private: friend class lay::ViewObject; friend class lay::ViewService; friend class lay::BackgroundViewObject; +#if defined(HAVE_QT) + QWidget *mp_widget; +#endif tl::weak_collection m_objects; tl::weak_collection m_background_objects; std::list m_services; diff --git a/src/laybasic/laybasic/layZoomBox.cc b/src/laybasic/laybasic/layZoomBox.cc index 26538d076..42f1106cb 100644 --- a/src/laybasic/laybasic/layZoomBox.cc +++ b/src/laybasic/laybasic/layZoomBox.cc @@ -32,7 +32,7 @@ namespace lay // ZoomService implementation ZoomService::ZoomService (lay::LayoutViewBase *view) - : lay::ViewService (view->view_object_widget ()), + : lay::ViewService (view->canvas ()), mp_view (view), mp_box (0), m_color (0) @@ -50,7 +50,7 @@ ZoomService::drag_cancel () delete mp_box; mp_box = 0; } - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); } void @@ -118,7 +118,7 @@ bool ZoomService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio) { if (! prio && (buttons & lay::RightButton) != 0) { - db::DBox vp = widget ()->mouse_event_viewport (); + db::DBox vp = ui ()->mouse_event_viewport (); if (mp_view && vp.contains (p)) { db::DVector d = (vp.p2 () - vp.p1 ()) * 0.5; mp_view->zoom_box (db::DBox (p - d, p + d)); @@ -132,21 +132,21 @@ ZoomService::mouse_release_event (const db::DPoint & /*p*/, unsigned int /*butto { if (prio) { - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); if (mp_box) { delete mp_box; mp_box = 0; - db::DBox vp = widget ()->mouse_event_viewport (); + db::DBox vp = ui ()->mouse_event_viewport (); db::DVector d = (vp.p2 () - vp.p1 ()) * 0.5; if (mp_view) { // we need to use the original screen coordinate to find the move direction - db::DPoint p1s = widget ()->mouse_event_trans ().trans (m_p1); - db::DPoint p2s = widget ()->mouse_event_trans ().trans (m_p2); + db::DPoint p1s = ui ()->mouse_event_trans ().trans (m_p1); + db::DPoint p2s = ui ()->mouse_event_trans ().trans (m_p2); if (p2s.x () > p1s.x () && p1s.y () < p2s.y ()) { @@ -185,7 +185,7 @@ ZoomService::wheel_event (int delta, bool /*horizontal*/, const db::DPoint &p, u // Only act without the mouse being grabbed. if (! prio) { - db::DBox vp = widget ()->mouse_event_viewport (); + db::DBox vp = ui ()->mouse_event_viewport (); if (mp_view && vp.contains (p) && vp.width () > 0 && vp.height () > 0) { enum { horizontal, vertical, zoom } direction = zoom; @@ -260,12 +260,12 @@ ZoomService::begin_pan (const db::DPoint &pos) mp_box = 0; m_p1 = pos; - m_vp = widget ()->mouse_event_viewport (); + m_vp = ui ()->mouse_event_viewport (); // store one state which we are going to update mp_view->zoom_box (m_vp); - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } void @@ -277,9 +277,9 @@ ZoomService::begin (const db::DPoint &pos) m_p1 = pos; m_p2 = pos; - mp_box = new lay::RubberBox (widget (), m_color, pos, pos); + mp_box = new lay::RubberBox (ui (), m_color, pos, pos); - widget ()->grab_mouse (this, true); + ui ()->grab_mouse (this, true); } } diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 33b10cf08..479a41d07 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -85,6 +85,7 @@ SOURCES += \ layViewOp.cc \ layViewport.cc \ layZoomBox.cc \ + layUtils.cc \ HEADERS += \ laybasicConfig.h \ @@ -136,6 +137,7 @@ HEADERS += \ layViewOp.h \ layViewport.h \ layZoomBox.h \ + layUtils.h \ laybasicCommon.h \ diff --git a/src/layui/layui/layBrowseInstancesForm.cc b/src/layui/layui/layBrowseInstancesForm.cc index b1946ebb9..c7267c78c 100644 --- a/src/layui/layui/layBrowseInstancesForm.cc +++ b/src/layui/layui/layBrowseInstancesForm.cc @@ -38,6 +38,7 @@ #include "tlAlgorithm.h" #include "layMarker.h" #include "layQtTools.h" +#include "layUtils.h" #include "tlExceptions.h" namespace lay @@ -82,7 +83,11 @@ public: virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new BrowseInstancesForm (root, view); + if (lay::has_gui ()) { + return new BrowseInstancesForm (root, view); + } else { + return 0; + } } }; diff --git a/src/layui/layui/layBrowseShapesForm.cc b/src/layui/layui/layBrowseShapesForm.cc index e75fd9bbb..0c88a0a2e 100644 --- a/src/layui/layui/layBrowseShapesForm.cc +++ b/src/layui/layui/layBrowseShapesForm.cc @@ -37,6 +37,7 @@ #include "tlAlgorithm.h" #include "layQtTools.h" #include "layMarker.h" +#include "layUtils.h" namespace lay @@ -74,17 +75,21 @@ public: return new BrowseShapesConfigPage (parent); } - virtual void get_menu_entries (std::vector &menu_entries) const - { - lay::PluginDeclaration::get_menu_entries (menu_entries); - menu_entries.push_back (lay::separator ("browser_group", "tools_menu.end")); - menu_entries.push_back (lay::menu_item ("browse_shapes::show", "browse_shapes", "tools_menu.end", tl::to_string (QObject::tr ("Browse Shapes")))); - } + virtual void get_menu_entries (std::vector &menu_entries) const + { + lay::PluginDeclaration::get_menu_entries (menu_entries); + menu_entries.push_back (lay::separator ("browser_group", "tools_menu.end")); + menu_entries.push_back (lay::menu_item ("browse_shapes::show", "browse_shapes", "tools_menu.end", tl::to_string (QObject::tr ("Browse Shapes")))); + } - virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const - { - return new BrowseShapesForm (root, view); - } + virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const + { + if (lay::has_gui ()) { + return new BrowseShapesForm (root, view); + } else { + return 0; + } + } }; static tl::RegisteredClass config_decl (new BrowseShapesPluginDeclaration (), 10000, "BrowseShapesPlugin"); diff --git a/src/layui/layui/layHierarchyControlPanel.cc b/src/layui/layui/layHierarchyControlPanel.cc index 304126ba0..ede77feec 100644 --- a/src/layui/layui/layHierarchyControlPanel.cc +++ b/src/layui/layui/layHierarchyControlPanel.cc @@ -890,7 +890,7 @@ HierarchyControlPanel::do_update_content (int cv_index) header->setVisible (split_mode); cl_ly->addWidget (header); - HCPCellTreeWidget *cell_list = new HCPCellTreeWidget (cl_frame, "tree", mp_view->view_object_widget ()); + HCPCellTreeWidget *cell_list = new HCPCellTreeWidget (cl_frame, "tree", mp_view->canvas ()->widget ()); cl_ly->addWidget (cell_list); cell_list->setModel (new CellTreeModel (cell_list, mp_view, cv_index, m_flat ? CellTreeModel::Flat : 0, 0, m_sorting)); cell_list->setUniformRowHeights (true); diff --git a/src/layui/layui/layLibrariesView.cc b/src/layui/layui/layLibrariesView.cc index 203213bf9..d5381a86d 100644 --- a/src/layui/layui/layLibrariesView.cc +++ b/src/layui/layui/layLibrariesView.cc @@ -632,7 +632,7 @@ LibrariesView::do_update_content (int lib_index) header->setVisible (split_mode); cl_ly->addWidget (header); - LibraryTreeWidget *cell_list = new LibraryTreeWidget (cl_frame, "tree", mp_view->view_object_widget ()); + LibraryTreeWidget *cell_list = new LibraryTreeWidget (cl_frame, "tree", mp_view->canvas ()->widget ()); cl_ly->addWidget (cell_list); cell_list->setModel (new CellTreeModel (cell_list, m_libraries [i].get (), CellTreeModel::Flat | CellTreeModel::TopCells | CellTreeModel::BasicCells | CellTreeModel::WithVariants | CellTreeModel::WithIcons, 0)); cell_list->setUniformRowHeights (true); diff --git a/src/layui/layui/layNetlistBrowser.cc b/src/layui/layui/layNetlistBrowser.cc index 4069e9166..d51b17c58 100644 --- a/src/layui/layui/layNetlistBrowser.cc +++ b/src/layui/layui/layNetlistBrowser.cc @@ -26,6 +26,7 @@ #include "layNetlistBrowserDialog.h" #include "layConverters.h" #include "layDispatcher.h" +#include "layUtils.h" #include "ui_NetlistBrowserConfigPage.h" #include "ui_NetlistBrowserConfigPage2.h" @@ -384,7 +385,11 @@ public: virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new lay::NetlistBrowserDialog (root, view); + if (has_gui ()) { + return new lay::NetlistBrowserDialog (root, view); + } else { + return 0; + } } }; diff --git a/src/layui/layui/layNetlistBrowserDialog.cc b/src/layui/layui/layNetlistBrowserDialog.cc index 8c54ccb54..aa18053ed 100644 --- a/src/layui/layui/layNetlistBrowserDialog.cc +++ b/src/layui/layui/layNetlistBrowserDialog.cc @@ -61,7 +61,7 @@ extern const std::string cfg_l2ndb_window_state; NetlistBrowserDialog::NetlistBrowserDialog (lay::Dispatcher *root, LayoutViewBase *vw) : lay::Browser (root, vw), - lay::ViewService (vw->view_object_widget ()), + lay::ViewService (vw->canvas ()), m_window (lay::NetlistBrowserConfig::FitNet), m_window_dim (0.0), m_max_shape_count (0), @@ -225,7 +225,7 @@ void NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path) { // prepare for the net tracing - double l = double (view ()->search_range ()) / widget ()->mouse_event_trans ().mag (); + double l = double (view ()->search_range ()) / ui ()->mouse_event_trans ().mag (); db::DBox start_search_box = db::DBox (p, p).enlarged (db::DVector (l, l)); @@ -348,7 +348,7 @@ NetlistBrowserDialog::release_mouse () { m_mouse_state = 0; view ()->message (); - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); } lay::ViewService * @@ -365,7 +365,7 @@ BEGIN_PROTECTED m_mouse_state = 1; view ()->message (tl::to_string (QObject::tr ("Click on a point in the net"))); - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); END_PROTECTED } diff --git a/src/layui/layui/rdbMarkerBrowser.cc b/src/layui/layui/rdbMarkerBrowser.cc index 4b7e3ec2f..c7ff4e6d1 100644 --- a/src/layui/layui/rdbMarkerBrowser.cc +++ b/src/layui/layui/rdbMarkerBrowser.cc @@ -27,6 +27,7 @@ #include "dbLayout.h" #include "layConverters.h" #include "layDispatcher.h" +#include "layUtils.h" #include "ui_MarkerBrowserConfigPage.h" #include "ui_MarkerBrowserConfigPage2.h" @@ -309,7 +310,11 @@ public: virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new rdb::MarkerBrowserDialog (root, view); + if (lay::has_gui ()) { + return new rdb::MarkerBrowserDialog (root, view); + } else { + return 0; + } } }; diff --git a/src/layview/layview/layGridNet.cc b/src/layview/layview/layGridNet.cc index f17061177..e2b6fcfe2 100644 --- a/src/layview/layview/layGridNet.cc +++ b/src/layview/layview/layGridNet.cc @@ -118,7 +118,7 @@ static tl::RegisteredClass config_decl (new GridNetPlugi // Implementation of the GridNet object GridNet::GridNet (LayoutViewBase *view) - : lay::BackgroundViewObject (view->view_object_widget ()), + : lay::BackgroundViewObject (view->canvas ()), lay::Plugin (view), mp_view (view), m_visible (false), m_show_ruler (true), m_grid (1.0), diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc index b9607b786..4a431e518 100644 --- a/src/layview/layview/layLayoutView_qt.cc +++ b/src/layview/layview/layLayoutView_qt.cc @@ -72,6 +72,7 @@ #include "layBookmarksView.h" #include "layEditorOptionsFrame.h" #include "layEditorOptionsPages.h" +#include "layUtils.h" #include "dbClipboard.h" #include "dbLayout.h" #include "dbLayoutUtils.h" @@ -263,12 +264,6 @@ LayoutView::init_menu () void LayoutView::init_ui (QWidget *parent, const char *name) { -#if QT_VERSION < 0x50000 - bool has_gui = (QApplication::type () != Qt::Tty); -#else - bool has_gui = (qGuiApp != 0); -#endif - m_activated = true; m_always_show_source = false; m_always_show_ld = true; @@ -290,18 +285,18 @@ LayoutView::init_ui (QWidget *parent, const char *name) mp_min_hier_spbx = 0; mp_max_hier_spbx = 0; - if (has_gui) { + if (lay::has_gui ()) { mp_widget = new LayoutViewFrame (parent, this); mp_widget->setObjectName (QString::fromUtf8 (name)); - view_object_widget ()->setParent (mp_widget); + canvas ()->widget ()->setParent (mp_widget); mp_connector = new LayoutViewSignalConnector (mp_widget, this); QVBoxLayout *vbl = new QVBoxLayout (mp_widget); vbl->setContentsMargins (0, 0, 0, 0); vbl->setSpacing (0); - vbl->addWidget (view_object_widget ()); + vbl->addWidget (canvas ()->widget ()); if ((options () & LV_NoHierarchyPanel) == 0 && (options () & LV_Naked) == 0) { @@ -997,33 +992,53 @@ LayoutView::cut () int LayoutView::active_cellview_index () const { - return mp_hierarchy_panel->active (); + if (mp_hierarchy_panel) { + return mp_hierarchy_panel->active (); + } else { + return LayoutViewBase::active_cellview_index (); + } } void LayoutView::set_active_cellview_index (int index) { if (index >= 0 && index < int (cellviews ())) { - mp_hierarchy_panel->select_active (index); + if (mp_hierarchy_panel) { + mp_hierarchy_panel->select_active (index); + } else { + LayoutViewBase::set_active_cellview_index (index); + } } } void LayoutView::selected_cells_paths (int cv_index, std::vector &paths) const { - mp_hierarchy_panel->selected_cells (cv_index, paths); + if (mp_hierarchy_panel) { + mp_hierarchy_panel->selected_cells (cv_index, paths); + } else { + LayoutViewBase::selected_cells_paths (cv_index, paths); + } } void LayoutView::current_cell_path (int cv_index, cell_path_type &path) const { - mp_hierarchy_panel->current_cell (cv_index, path); + if (mp_hierarchy_panel) { + mp_hierarchy_panel->current_cell (cv_index, path); + } else { + LayoutViewBase::current_cell_path (cv_index, path); + } } void LayoutView::set_current_cell_path (int cv_index, const cell_path_type &path) { - mp_hierarchy_panel->set_current_cell (cv_index, path); + if (mp_hierarchy_panel) { + mp_hierarchy_panel->set_current_cell (cv_index, path); + } else { + LayoutViewBase::set_current_cell_path (cv_index, path); + } } void diff --git a/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc b/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc index 8d22390ed..4740f8a5e 100644 --- a/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc +++ b/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc @@ -25,6 +25,7 @@ #include "layPlugin.h" #include "layLayoutViewBase.h" +#include "layUtils.h" namespace lay { @@ -36,7 +37,11 @@ public: DiffPlugin (Plugin *parent, lay::LayoutViewBase *view) : lay::Plugin (parent), mp_view (view) { - mp_dialog = new lay::DiffToolDialog (0); + if (lay::has_gui ()) { + mp_dialog = new lay::DiffToolDialog (0); + } else { + mp_dialog = 0; + } } ~DiffPlugin () @@ -49,7 +54,7 @@ public: { if (symbol == "lay::diff_tool") { - if (mp_dialog->exec_dialog (mp_view)) { + if (mp_dialog && mp_dialog->exec_dialog (mp_view)) { // ... implementation is in layDiffToolDialog.cc ... diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc index cbbf1c069..d4ddd1ed0 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc @@ -55,7 +55,7 @@ namespace lay NetTracerDialog::NetTracerDialog (lay::Dispatcher *root, LayoutViewBase *view) : lay::Browser (root, view, "net_tracer_dialog"), - lay::ViewService (view->view_object_widget ()), + lay::ViewService (view->canvas ()), m_cv_index (0), m_net_index (1), m_window (lay::NTFitNet), @@ -170,7 +170,7 @@ NetTracerDialog::mouse_click_event (const db::DPoint &p, unsigned int buttons, b // prepare for the net tracing clear_markers (); - double l = double (view ()->search_range ()) / widget ()->mouse_event_trans ().mag (); + double l = double (view ()->search_range ()) / ui ()->mouse_event_trans ().mag (); db::DBox start_search_box = db::DBox (p, p).enlarged (db::DVector (l, l)); @@ -1125,7 +1125,7 @@ BEGIN_PROTECTED net_list->setCurrentItem (0); m_mouse_state = 2; view ()->message (tl::to_string (QObject::tr ("Click on the first point in the net"))); - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); END_PROTECTED } @@ -1137,7 +1137,7 @@ BEGIN_PROTECTED net_list->setCurrentItem (0); m_mouse_state = 1; view ()->message (tl::to_string (QObject::tr ("Click on a point in the net"))); - widget ()->grab_mouse (this, false); + ui ()->grab_mouse (this, false); END_PROTECTED } @@ -1160,7 +1160,7 @@ NetTracerDialog::release_mouse () add2_pb->setChecked (false); m_mouse_state = 0; view ()->message (); - widget ()->ungrab_mouse (this); + ui ()->ungrab_mouse (this); } void diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc index 619d12e53..7cc918cd9 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc @@ -29,6 +29,7 @@ #include "layConverters.h" #include "layCellView.h" #include "layLayoutView.h" +#include "layUtils.h" #include "gsiDecl.h" @@ -78,7 +79,11 @@ public: virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new NetTracerDialog (root, view); + if (lay::has_gui ()) { + return new NetTracerDialog (root, view); + } else { + return 0; + } } }; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 4bb1601c8..8ee02c0cd 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -26,6 +26,7 @@ #include "layDispatcher.h" #include "layPlugin.h" +#include "layUtils.h" #include @@ -69,7 +70,11 @@ public: lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const { - return new D25View (root, view); + if (lay::has_gui ()) { + return new D25View (root, view); + } else { + return 0; + } } }; diff --git a/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc b/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc index 6c38c4d85..919078f59 100644 --- a/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc +++ b/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc @@ -27,6 +27,7 @@ #include "layPlugin.h" #include "layLayoutView.h" +#include "layUtils.h" namespace lay { @@ -38,7 +39,11 @@ public: XORPlugin (Plugin *parent, lay::LayoutViewBase *view) : lay::Plugin (parent), mp_view (view) { - mp_dialog = new lay::XORToolDialog (0); + if (lay::has_gui ()) { + mp_dialog = new lay::XORToolDialog (0); + } else { + mp_dialog = 0; + } } ~XORPlugin () @@ -51,7 +56,7 @@ public: { if (symbol == "lay::xor_tool") { - if (mp_dialog->exec_dialog (mp_view)) { + if (mp_dialog && mp_dialog->exec_dialog (mp_view)) { // ... implementation is in layXORToolDialog.cc ... From 2b568cdd5e5d2944abddd59853edbc78ddb783a2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 26 May 2022 07:47:35 +0200 Subject: [PATCH 03/45] Fixed some build errors, added tests --- src/edt/edt/edtMainService.cc | 8 +++- src/laybasic/laybasic/layViewObject.cc | 4 +- src/layview/unit_tests/unit_tests.pro | 6 +-- testdata/klayout_main/main.rb | 54 +++++++++++++++----------- testdata/klayout_main/test10.rb | 8 ++++ 5 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 testdata/klayout_main/test10.rb diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index be134d55e..3a0f52992 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -2158,7 +2158,13 @@ MainService::cm_tap () tl_assert (false); // see TODO #endif - if (! view ()->canvas ()->widget () || view ()->canvas ()->mouse_in_window ()) { +#if defined(HAVE_QT) + if (! view ()->canvas ()->widget ()) { + return; + } +#endif + + if (! view ()->canvas ()->mouse_in_window ()) { return; } diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index 0e5f97719..fc307b75f 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -1146,14 +1146,14 @@ ViewObjectUI::thaw (ViewObject *obj) #if !defined(HAVE_QT) void -ViewObjectWidget::update () +ViewObjectUI::update () { // NOTE: this does not need to be thread-safe as we make sure (as in Qt) that update() is always called from the main thread. m_image_updated = true; } bool -ViewObjectWidget::image_updated () +ViewObjectUI::image_updated () { bool f = m_image_updated; m_image_updated = false; diff --git a/src/layview/unit_tests/unit_tests.pro b/src/layview/unit_tests/unit_tests.pro index 113c3dfb1..36ff7a674 100644 --- a/src/layview/unit_tests/unit_tests.pro +++ b/src/layview/unit_tests/unit_tests.pro @@ -9,10 +9,10 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ layLayoutViewTests.cc \ -INCLUDEPATH += $$TL_INC $$LAYBASIC_INC $$LAYVIEW_INC $$LAYUI_INC $$DB_INC $$RDB_INC $$GSI_INC $$OUT_PWD/../layview -DEPENDPATH += $$TL_INC $$LAYBASIC_INC $$LAYVIEW_INC $$LAYUI_INC $$DB_INC $$RDB_INC $$GSI_INC $$OUT_PWD/../layview +INCLUDEPATH += $$TL_INC $$LAYBASIC_INC $$LAYVIEW_INC $$DB_INC $$RDB_INC $$GSI_INC $$OUT_PWD/../layview +DEPENDPATH += $$TL_INC $$LAYBASIC_INC $$LAYVIEW_INC $$DB_INC $$RDB_INC $$GSI_INC $$OUT_PWD/../layview -LIBS += -L$$DESTDIR_UT -lklayout_layview -lklayout_laybasic -lklayout_layui -lklayout_db -lklayout_tl -lklayout_gsi +LIBS += -L$$DESTDIR_UT -lklayout_layview -lklayout_laybasic -lklayout_db -lklayout_tl -lklayout_gsi !equals(HAVE_QT, "0") { diff --git a/testdata/klayout_main/main.rb b/testdata/klayout_main/main.rb index 1fe083e0f..2f54e511a 100644 --- a/testdata/klayout_main/main.rb +++ b/testdata/klayout_main/main.rb @@ -54,7 +54,7 @@ class KLayoutMain_TestClass < TestBase def test_1 # Basic - version = `#{self.klayout_bin} -v` + version = `#{self.klayout_bin} -v 2>&1` assert_equal(version, "#{RBA::Application.instance.version}\n") end @@ -62,10 +62,10 @@ class KLayoutMain_TestClass < TestBase def test_2 # Basic Ruby - out = `#{self.klayout_bin} -b -rd v1=42 -rd v2=hello -r #{File.join(File.dirname(__FILE__), "test.rb")}` + out = `#{self.klayout_bin} -b -rd v1=42 -rd v2=hello -r #{File.join(File.dirname(__FILE__), "test.rb")} 2>&1` assert_equal(out, "Variable v1=42 v2=hello\n") - out = `#{self.klayout_bin} -b -rd v1=42 -rd v2=hello -r #{File.join(File.dirname(__FILE__), "test.rb")} -rm #{File.join(File.dirname(__FILE__), "test2.rb")} -rm #{File.join(File.dirname(__FILE__), "test3.rb")}` + out = `#{self.klayout_bin} -b -rd v1=42 -rd v2=hello -r #{File.join(File.dirname(__FILE__), "test.rb")} -rm #{File.join(File.dirname(__FILE__), "test2.rb")} -rm #{File.join(File.dirname(__FILE__), "test3.rb")} 2>&1` assert_equal(out, "test2\ntest3\nVariable v1=42 v2=hello\n") end @@ -73,7 +73,7 @@ class KLayoutMain_TestClass < TestBase def test_3 # Basic Python - out = `#{self.klayout_bin} -b -rd v1=42 -rd v2=hello -r #{File.join(File.dirname(__FILE__), "test.py")}` + out = `#{self.klayout_bin} -b -rd v1=42 -rd v2=hello -r #{File.join(File.dirname(__FILE__), "test.py")} 2>&1` assert_equal(out, "Variable v1=42 v2=hello\n") end @@ -83,20 +83,20 @@ class KLayoutMain_TestClass < TestBase # Application class if !RBA.constants.find { |x| x == :QDialog || x == "QDialog" } - out = `#{self.klayout_bin} -b -r #{File.join(File.dirname(__FILE__), "test_app.rb")}` + out = `#{self.klayout_bin} -b -r #{File.join(File.dirname(__FILE__), "test_app.rb")} 2>&1` assert_equal(out, "RBA::Application superclass Object\nMainWindow is not there\n") - out = `#{self.klayout_bin} -z -nc -rx -r #{File.join(File.dirname(__FILE__), "test_app.rb")}` + out = `#{self.klayout_bin} -z -nc -rx -r #{File.join(File.dirname(__FILE__), "test_app.rb")} 2>&1` assert_equal(out, "RBA::Application superclass Object\nMainWindow is there\n") else # QCoreApplication for (headless) mode - out = `#{self.klayout_bin} -b -r #{File.join(File.dirname(__FILE__), "test_app.rb")}` + out = `#{self.klayout_bin} -b -r #{File.join(File.dirname(__FILE__), "test_app.rb")} 2>&1` assert_equal(out, "RBA::Application superclass RBA::QCoreApplication_Native\nMainWindow is not there\n") # QApplication for GUI mode - out = `#{self.klayout_bin} -z -nc -rx -r #{File.join(File.dirname(__FILE__), "test_app.rb")}` + out = `#{self.klayout_bin} -z -nc -rx -r #{File.join(File.dirname(__FILE__), "test_app.rb")} 2>&1` assert_equal(out, "RBA::Application superclass RBA::QApplication_Native\nMainWindow is there\n") end @@ -106,7 +106,7 @@ class KLayoutMain_TestClass < TestBase def test_5 # Script variables - out = `#{self.klayout_bin} -b -wd tv1=17 -wd tv2=25 -wd tv3 -r #{File.join(File.dirname(__FILE__), "test_script.rb")}` + out = `#{self.klayout_bin} -b -wd tv1=17 -wd tv2=25 -wd tv3 -r #{File.join(File.dirname(__FILE__), "test_script.rb")} 2>&1` assert_equal(out, "42\ntrue\n") end @@ -114,10 +114,10 @@ class KLayoutMain_TestClass < TestBase def test_6 # Editable / Non-editable mode - out = `#{self.klayout_bin} -b -ne -r #{File.join(File.dirname(__FILE__), "test_em.rb")}` + out = `#{self.klayout_bin} -b -ne -r #{File.join(File.dirname(__FILE__), "test_em.rb")} 2>&1` assert_equal(out, "false\n") - out = `#{self.klayout_bin} -b -e -r #{File.join(File.dirname(__FILE__), "test_em.rb")}` + out = `#{self.klayout_bin} -b -e -r #{File.join(File.dirname(__FILE__), "test_em.rb")} 2>&1` assert_equal(out, "true\n") end @@ -128,27 +128,27 @@ class KLayoutMain_TestClass < TestBase File.open(cfg_file, "w") { |file| file.puts("") } # Special configuration file - `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config1.rb")}` + `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config1.rb")} 2>&1` - out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")}` + out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")} 2>&1` assert_equal(out, "42\n") # Update - `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config2.rb")}` + `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config2.rb")} 2>&1` - out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")}` + out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")} 2>&1` assert_equal(out, "17\n") # Reset - `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config1.rb")}` + `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config1.rb")} 2>&1` - out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")}` + out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")} 2>&1` assert_equal(out, "42\n") # No update - `#{self.klayout_bin} -b -t -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config2.rb")}` + `#{self.klayout_bin} -b -t -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_set_config2.rb")} 2>&1` - out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")}` + out = `#{self.klayout_bin} -b -c #{cfg_file} -r #{File.join(File.dirname(__FILE__), "test_read_config.rb")} 2>&1` assert_equal(out, "42\n") end @@ -156,13 +156,13 @@ class KLayoutMain_TestClass < TestBase def test_8 # Loading layouts - out = `#{self.klayout_bin} -z -nc -rx #{File.join(File.dirname(__FILE__), "test1.gds")} -r #{File.join(File.dirname(__FILE__), "test_lay.rb")}` + out = `#{self.klayout_bin} -z -nc -rx #{File.join(File.dirname(__FILE__), "test1.gds")} -r #{File.join(File.dirname(__FILE__), "test_lay.rb")} 2>&1` assert_equal(out, "TOP1\n") - out = `#{self.klayout_bin} -z -nc -rx #{File.join(File.dirname(__FILE__), "test1.gds")} #{File.join(File.dirname(__FILE__), "test2.gds")} -r #{File.join(File.dirname(__FILE__), "test_lay2.rb")}` + out = `#{self.klayout_bin} -z -nc -rx #{File.join(File.dirname(__FILE__), "test1.gds")} #{File.join(File.dirname(__FILE__), "test2.gds")} -r #{File.join(File.dirname(__FILE__), "test_lay2.rb")} 2>&1` assert_equal(out, "TOP1\nTOP2\n") - out = `#{self.klayout_bin} -z -nc -rx #{File.join(File.dirname(__FILE__), "test1.gds")} #{File.join(File.dirname(__FILE__), "test2.gds")} -s -r #{File.join(File.dirname(__FILE__), "test_lay2.rb")}` + out = `#{self.klayout_bin} -z -nc -rx #{File.join(File.dirname(__FILE__), "test1.gds")} #{File.join(File.dirname(__FILE__), "test2.gds")} -s -r #{File.join(File.dirname(__FILE__), "test_lay2.rb")} 2>&1` assert_equal(out, "TOP1;TOP2\n") end @@ -170,11 +170,19 @@ class KLayoutMain_TestClass < TestBase def test_9 # Sessions - out = `#{self.klayout_bin} -z -nc -rx -u #{File.join(File.dirname(__FILE__), "session.lys")} -r #{File.join(File.dirname(__FILE__), "test_lay2.rb")}` + out = `#{self.klayout_bin} -z -nc -rx -u #{File.join(File.dirname(__FILE__), "session.lys")} -r #{File.join(File.dirname(__FILE__), "test_lay2.rb")} 2>&1` assert_equal(out, "TOP2;TOP1\n") end + def test_10 + + # Headless LayoutView + out = `#{self.klayout_bin} -b -rd input=#{File.join(File.dirname(__FILE__), "test1.gds")} -r #{File.join(File.dirname(__FILE__), "test10.rb")} 2>&1` + assert_equal(out, "(0,0;8,8)\n") + + end + end load("test_epilogue.rb") diff --git a/testdata/klayout_main/test10.rb b/testdata/klayout_main/test10.rb new file mode 100644 index 000000000..e440b5deb --- /dev/null +++ b/testdata/klayout_main/test10.rb @@ -0,0 +1,8 @@ + +lv = RBA::LayoutView::new +lv.load_layout($input) +lv.resize(800, 500) +lv.save_screenshot("test10_screenshot.png") # smoke test + +puts lv.active_cellview.layout.top_cell.dbbox.to_s + From 5825b7d0c6fb669fe368ed7d2f5bec352a9b989d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 07:57:04 +0200 Subject: [PATCH 04/45] Build fixed for Qt4 --- src/laybasic/laybasic/layUtils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laybasic/laybasic/layUtils.cc b/src/laybasic/laybasic/layUtils.cc index ba6084aad..ff0578027 100644 --- a/src/laybasic/laybasic/layUtils.cc +++ b/src/laybasic/laybasic/layUtils.cc @@ -33,7 +33,7 @@ has_gui () { #if defined(HAVE_QT) #if QT_VERSION < 0x50000 - return (QApplication::type () != Qt::Tty); + return (QApplication::type () != QApplication::Tty); #else return (dynamic_cast (QCoreApplication::instance ()) != 0); #endif From 2e10ef300bba96a7f91f1b0694505166b7123a66 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 08:31:13 +0200 Subject: [PATCH 05/45] Fixed implementation of LayoutView#resize in non-Qt case --- src/laybasic/laybasic/layViewObject.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index fc307b75f..3fc597c20 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -978,16 +978,16 @@ ViewObjectUI::resize (unsigned int w, unsigned int h) { m_widget_width = w; m_widget_height = h; -#if defined(HAVE_QT) +#if defined(HAVE_QT) if (mp_widget) { mp_widget->resize (w, h); } +#endif // don't wait until the layout system informs us - which may never take place when - // the widget isn't shown. + // the widget isn't shown. In the non-Qt case we need it anyway here. resize_event (w, h); -#endif } int From 218117d6b64c9fdcb4d6eb446764864d88a24cf5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 08:31:47 +0200 Subject: [PATCH 06/45] Removed a generated header dependency between modules --- src/layui/layui/laySaveLayoutOptionsDialog.cc | 107 ++++++++++-------- src/layui/layui/laySaveLayoutOptionsDialog.h | 16 ++- 2 files changed, 69 insertions(+), 54 deletions(-) diff --git a/src/layui/layui/laySaveLayoutOptionsDialog.cc b/src/layui/layui/laySaveLayoutOptionsDialog.cc index dc741a3c5..72547e8d9 100644 --- a/src/layui/layui/laySaveLayoutOptionsDialog.cc +++ b/src/layui/layui/laySaveLayoutOptionsDialog.cc @@ -31,6 +31,9 @@ #include "dbStream.h" #include "tlClassRegistry.h" +#include "ui_SaveLayoutOptionsDialog.h" +#include "ui_SaveLayoutAsOptionsDialog.h" + #include #include @@ -76,17 +79,19 @@ static tl::OutputStream::OutputStreamMode index_to_om (unsigned int i) // SaveLayoutOptionsDialog implementation SaveLayoutOptionsDialog::SaveLayoutOptionsDialog (QWidget *parent, const std::string &title) - : QDialog (parent), Ui::SaveLayoutOptionsDialog (), + : QDialog (parent), m_technology_index (-1) { + mp_ui = new Ui::SaveLayoutOptionsDialog (); + setObjectName (QString::fromUtf8 ("save_layout_options_dialog")); - Ui::SaveLayoutOptionsDialog::setupUi (this); + mp_ui->setupUi (this); setWindowTitle (tl::to_qstring (title)); - while (options_tab->count () > 0) { - options_tab->removeTab (0); + while (mp_ui->options_tab->count () > 0) { + mp_ui->options_tab->removeTab (0); } bool any_option = false; @@ -98,11 +103,11 @@ SaveLayoutOptionsDialog::SaveLayoutOptionsDialog (QWidget *parent, const std::st // obtain the config page from the plugin which we identify by format name const StreamWriterPluginDeclaration *decl = StreamWriterPluginDeclaration::plugin_for_format (fmt->format_name ()); - QScrollArea *page_host = new QScrollArea (options_tab); + QScrollArea *page_host = new QScrollArea (mp_ui->options_tab); page_host->setFrameStyle (QFrame::NoFrame); page_host->setWidgetResizable (true); - page = decl ? decl->format_specific_options_page (options_tab) : 0; + page = decl ? decl->format_specific_options_page (mp_ui->options_tab) : 0; if (page) { page_host->setWidget (page); } else { @@ -120,7 +125,7 @@ SaveLayoutOptionsDialog::SaveLayoutOptionsDialog (QWidget *parent, const std::st } if (page_host) { - options_tab->addTab (page_host, tl::to_qstring (fmt->format_desc ())); + mp_ui->options_tab->addTab (page_host, tl::to_qstring (fmt->format_desc ())); m_pages.push_back (std::make_pair (page, fmt->format_name ())); any_option = true; } @@ -128,12 +133,12 @@ SaveLayoutOptionsDialog::SaveLayoutOptionsDialog (QWidget *parent, const std::st } if (! any_option) { - options_tab->hide (); + mp_ui->options_tab->hide (); } - connect (buttonBox, SIGNAL (accepted ()), this, SLOT (ok_button_pressed ())); - connect (buttonBox, SIGNAL (clicked (QAbstractButton *)), this, SLOT (button_pressed (QAbstractButton *))); - connect (tech_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (current_tech_changed (int))); + connect (mp_ui->buttonBox, SIGNAL (accepted ()), this, SLOT (ok_button_pressed ())); + connect (mp_ui->buttonBox, SIGNAL (clicked (QAbstractButton *)), this, SLOT (button_pressed (QAbstractButton *))); + connect (mp_ui->tech_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (current_tech_changed (int))); } SaveLayoutOptionsDialog::~SaveLayoutOptionsDialog () @@ -144,7 +149,7 @@ SaveLayoutOptionsDialog::~SaveLayoutOptionsDialog () void SaveLayoutOptionsDialog::button_pressed (QAbstractButton *button) { - if (button == buttonBox->button (QDialogButtonBox::Reset)) { + if (button == mp_ui->buttonBox->button (QDialogButtonBox::Reset)) { reset_button_pressed (); } } @@ -239,8 +244,8 @@ SaveLayoutOptionsDialog::edit_global_options (lay::Dispatcher *config_root, db:: std::string technology; config_root->config_get (cfg_initial_technology, technology); - tech_cbx->blockSignals (true); - tech_cbx->clear (); + mp_ui->tech_cbx->blockSignals (true); + mp_ui->tech_cbx->clear (); unsigned int i = 0; m_technology_index = -1; @@ -256,16 +261,16 @@ SaveLayoutOptionsDialog::edit_global_options (lay::Dispatcher *config_root, db:: m_opt_array.push_back (t->save_layout_options ()); m_tech_array.push_back (t.operator-> ()); - tech_cbx->addItem (tl::to_qstring (d)); + mp_ui->tech_cbx->addItem (tl::to_qstring (d)); if (t->name () == technology) { - tech_cbx->setCurrentIndex (i); + mp_ui->tech_cbx->setCurrentIndex (i); m_technology_index = i; } } - tech_cbx->blockSignals (false); - tech_cbx->show (); + mp_ui->tech_cbx->blockSignals (false); + mp_ui->tech_cbx->show (); if (get_options_internal ()) { @@ -289,7 +294,7 @@ SaveLayoutOptionsDialog::edit_global_options (lay::Dispatcher *config_root, db:: bool SaveLayoutOptionsDialog::get_options (db::SaveLayoutOptions &options) { - tech_cbx->hide (); + mp_ui->tech_cbx->hide (); m_opt_array.clear (); m_opt_array.push_back (options); @@ -322,22 +327,24 @@ SaveLayoutOptionsDialog::get_options_internal () // SaveLayoutAsOptionsDialog implementation SaveLayoutAsOptionsDialog::SaveLayoutAsOptionsDialog (QWidget *parent, const std::string &title) - : QDialog (parent), Ui::SaveLayoutAsOptionsDialog (), mp_tech (0) + : QDialog (parent), mp_tech (0) { + mp_ui = new Ui::SaveLayoutAsOptionsDialog (); + setObjectName (QString::fromUtf8 ("save_layout_options_dialog")); - Ui::SaveLayoutAsOptionsDialog::setupUi (this); + mp_ui->setupUi (this); setWindowTitle (tl::to_qstring (title)); - QWidget *empty_widget = new QWidget (options_stack); - int empty_widget_index = options_stack->addWidget (empty_widget); + QWidget *empty_widget = new QWidget (mp_ui->options_stack); + int empty_widget_index = mp_ui->options_stack->addWidget (empty_widget); for (tl::Registrar::iterator fmt = tl::Registrar::begin (); fmt != tl::Registrar::end (); ++fmt) { if (fmt->can_write ()) { - fmt_cbx->addItem (tl::to_qstring (fmt->format_title ())); + mp_ui->fmt_cbx->addItem (tl::to_qstring (fmt->format_title ())); // obtain the config page from the plugin which we identify by format name const StreamWriterPluginDeclaration *decl = plugin_for_format (fmt->format_name ()); @@ -367,10 +374,10 @@ SaveLayoutAsOptionsDialog::SaveLayoutAsOptionsDialog (QWidget *parent, const std } else { - StreamWriterOptionsPage *page = decl->format_specific_options_page (options_stack); + StreamWriterOptionsPage *page = decl->format_specific_options_page (mp_ui->options_stack); m_pages.push_back (std::make_pair (page, fmt->format_name ())); - m_tab_positions.push_back (page ? options_stack->addWidget (page) : empty_widget_index); + m_tab_positions.push_back (page ? mp_ui->options_stack->addWidget (page) : empty_widget_index); } @@ -385,8 +392,8 @@ SaveLayoutAsOptionsDialog::SaveLayoutAsOptionsDialog (QWidget *parent, const std } - connect (buttonBox, SIGNAL (accepted ()), this, SLOT (ok_button_pressed ())); - connect (fmt_cbx, SIGNAL (activated (int)), this, SLOT (fmt_cbx_changed (int))); + connect (mp_ui->buttonBox, SIGNAL (accepted ()), this, SLOT (ok_button_pressed ())); + connect (mp_ui->fmt_cbx, SIGNAL (activated (int)), this, SLOT (fmt_cbx_changed (int))); } SaveLayoutAsOptionsDialog::~SaveLayoutAsOptionsDialog () @@ -400,7 +407,7 @@ SaveLayoutAsOptionsDialog::ok_button_pressed () BEGIN_PROTECTED // get the name of the currently selected format - int index = fmt_cbx->currentIndex (); + int index = mp_ui->fmt_cbx->currentIndex (); std::string fmt_name; for (tl::Registrar::iterator fmt = tl::Registrar::begin (); fmt != tl::Registrar::end () && index >= 0; ++fmt) { if (fmt->can_write ()) { @@ -419,7 +426,7 @@ SaveLayoutAsOptionsDialog::ok_button_pressed () if (page->first) { std::unique_ptr options (decl->create_specific_options ()); if (options.get ()) { - page->first->commit (options.get (), mp_tech, tl::OutputStream::output_mode_from_filename (m_filename, index_to_om (compression->currentIndex ())) != tl::OutputStream::OM_Plain); + page->first->commit (options.get (), mp_tech, tl::OutputStream::output_mode_from_filename (m_filename, index_to_om (mp_ui->compression->currentIndex ())) != tl::OutputStream::OM_Plain); } } break; @@ -428,8 +435,8 @@ SaveLayoutAsOptionsDialog::ok_button_pressed () } double x = 0.0; - tl::from_string_ext (tl::to_string (dbu_le->text ()), x); - tl::from_string_ext (tl::to_string (sf_le->text ()), x); + tl::from_string_ext (tl::to_string (mp_ui->dbu_le->text ()), x); + tl::from_string_ext (tl::to_string (mp_ui->sf_le->text ()), x); accept (); @@ -449,19 +456,19 @@ SaveLayoutAsOptionsDialog::get_options (lay::LayoutViewBase *view, unsigned int const db::Layout &layout = cv->layout (); m_filename = fn; - filename_lbl->setText (tl::to_qstring (fn)); - compression->setCurrentIndex (om_to_index (om)); + mp_ui->filename_lbl->setText (tl::to_qstring (fn)); + mp_ui->compression->setCurrentIndex (om_to_index (om)); - dbu_le->setText (tl::to_qstring (tl::to_string (options.dbu ()))); + mp_ui->dbu_le->setText (tl::to_qstring (tl::to_string (options.dbu ()))); - fmt_cbx->setCurrentIndex (0); + mp_ui->fmt_cbx->setCurrentIndex (0); fmt_cbx_changed (0); unsigned int i = 0; for (tl::Registrar::iterator fmt = tl::Registrar::begin (); fmt != tl::Registrar::end (); ++fmt) { if (fmt->can_write ()) { if (fmt->format_name () == options.format ()) { - fmt_cbx->setCurrentIndex (i); + mp_ui->fmt_cbx->setCurrentIndex (i); fmt_cbx_changed (i); break; } @@ -495,9 +502,9 @@ SaveLayoutAsOptionsDialog::get_options (lay::LayoutViewBase *view, unsigned int if (exec ()) { - om = index_to_om (compression->currentIndex ()); + om = index_to_om (mp_ui->compression->currentIndex ()); - int index = fmt_cbx->currentIndex (); + int index = mp_ui->fmt_cbx->currentIndex (); for (tl::Registrar::iterator fmt = tl::Registrar::begin (); fmt != tl::Registrar::end () && index >= 0; ++fmt) { if (fmt->can_write ()) { if (index-- == 0) { @@ -507,19 +514,19 @@ SaveLayoutAsOptionsDialog::get_options (lay::LayoutViewBase *view, unsigned int } double dbu = 0.0; - tl::from_string_ext (tl::to_string (dbu_le->text ()), dbu); + tl::from_string_ext (tl::to_string (mp_ui->dbu_le->text ()), dbu); double sf = 1.0; - tl::from_string_ext (tl::to_string (sf_le->text ()), sf); + tl::from_string_ext (tl::to_string (mp_ui->sf_le->text ()), sf); options.set_dbu (dbu); options.set_scale_factor (sf); - options.set_dont_write_empty_cells (no_empty_cells_cb->isChecked ()); - options.set_keep_instances (keep_instances_cb->isChecked ()); - options.set_write_context_info (store_context_cb->isChecked ()); + options.set_dont_write_empty_cells (mp_ui->no_empty_cells_cb->isChecked ()); + options.set_keep_instances (mp_ui->keep_instances_cb->isChecked ()); + options.set_write_context_info (mp_ui->store_context_cb->isChecked ()); - if (no_hidden_cells_cb->isChecked ()) { + if (mp_ui->no_hidden_cells_cb->isChecked ()) { options.clear_cells (); for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) { if (! view->is_cell_hidden (c->cell_index (), cv_index)) { @@ -530,16 +537,16 @@ SaveLayoutAsOptionsDialog::get_options (lay::LayoutViewBase *view, unsigned int options.select_all_cells (); } - if (layersel_cbx->currentIndex () == 0 /*all*/) { + if (mp_ui->layersel_cbx->currentIndex () == 0 /*all*/) { options.select_all_layers (); - } else if (layersel_cbx->currentIndex () == 1 /*shown layers*/) { + } else if (mp_ui->layersel_cbx->currentIndex () == 1 /*shown layers*/) { options.deselect_all_layers (); for (LayerPropertiesConstIterator layer = view->begin_layers (); layer != view->end_layers (); ++layer) { if (layer->cellview_index () == int (cv_index)) { options.add_layer (layer->layer_index ()); } } - } else if (layersel_cbx->currentIndex () == 2 /*visible layers*/) { + } else if (mp_ui->layersel_cbx->currentIndex () == 2 /*visible layers*/) { options.deselect_all_layers (); for (LayerPropertiesConstIterator layer = view->begin_layers (); layer != view->end_layers (); ++layer) { if (layer->cellview_index () == int (cv_index) && layer->visible (true)) { @@ -559,7 +566,7 @@ SaveLayoutAsOptionsDialog::get_options (lay::LayoutViewBase *view, unsigned int if (specific_options.get ()) { if (page->first) { - page->first->commit (specific_options.get (), mp_tech, tl::OutputStream::output_mode_from_filename (m_filename, index_to_om (compression->currentIndex ())) != tl::OutputStream::OM_Plain); + page->first->commit (specific_options.get (), mp_tech, tl::OutputStream::output_mode_from_filename (m_filename, index_to_om (mp_ui->compression->currentIndex ())) != tl::OutputStream::OM_Plain); } options.set_options (specific_options.release ()); } @@ -579,7 +586,7 @@ void SaveLayoutAsOptionsDialog::fmt_cbx_changed (int index) { if (index >= 0 && index < int (m_tab_positions.size ())) { - options_stack->setCurrentIndex (m_tab_positions[index]); + mp_ui->options_stack->setCurrentIndex (m_tab_positions[index]); } } diff --git a/src/layui/layui/laySaveLayoutOptionsDialog.h b/src/layui/layui/laySaveLayoutOptionsDialog.h index db37f3c4d..ba337ce20 100644 --- a/src/layui/layui/laySaveLayoutOptionsDialog.h +++ b/src/layui/layui/laySaveLayoutOptionsDialog.h @@ -26,16 +26,16 @@ #define HDR_laySaveLayoutOptionsDialog #include "layuiCommon.h" -#include "ui_SaveLayoutOptionsDialog.h" -#include "ui_SaveLayoutAsOptionsDialog.h" #include "dbStream.h" #include "dbSaveLayoutOptions.h" #include "layStream.h" #include "tlStream.h" #include +#include class QScrollArea; +class QAbstractButton; class QWidget; namespace db @@ -44,13 +44,19 @@ namespace db class Technologies; } +namespace Ui +{ + class SaveLayoutAsOptionsDialog; + class SaveLayoutOptionsDialog; +}; + namespace lay { class LayoutViewBase; class LAYUI_PUBLIC SaveLayoutAsOptionsDialog - : public QDialog, private Ui::SaveLayoutAsOptionsDialog + : public QDialog { Q_OBJECT @@ -65,6 +71,7 @@ public slots: void fmt_cbx_changed (int); private: + Ui::SaveLayoutAsOptionsDialog *mp_ui; std::vector< std::pair > m_pages; std::vector m_tab_positions; std::string m_filename; @@ -73,7 +80,7 @@ private: }; class LAYUI_PUBLIC SaveLayoutOptionsDialog - : public QDialog, private Ui::SaveLayoutOptionsDialog + : public QDialog { Q_OBJECT @@ -91,6 +98,7 @@ public slots: void current_tech_changed (int index); private: + Ui::SaveLayoutOptionsDialog *mp_ui; std::vector< std::pair > m_pages; int m_technology_index; std::vector m_opt_array; From 29e481dd526b4510346b400992d829a061e4a246 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 16:48:29 +0200 Subject: [PATCH 07/45] Fixed a compiler warning --- src/tl/unit_tests/tlExpressionTests.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tl/unit_tests/tlExpressionTests.cc b/src/tl/unit_tests/tlExpressionTests.cc index b25c54c44..e3ab6b3f2 100644 --- a/src/tl/unit_tests/tlExpressionTests.cc +++ b/src/tl/unit_tests/tlExpressionTests.cc @@ -920,7 +920,7 @@ TEST(8) try { v = e.parse ("1==1?log('a'):log(2)").execute (); EXPECT_EQ (v.to_string (), std::string ("abc")); - } catch (tl::EvalError) { + } catch (tl::EvalError &) { t = true; } EXPECT_EQ (t, true); @@ -928,7 +928,7 @@ TEST(8) try { v = e.parse ("1==2||log('a')").execute (); EXPECT_EQ (v.to_string (), std::string ("1")); - } catch (tl::EvalError) { + } catch (tl::EvalError &) { t = true; } EXPECT_EQ (t, true); @@ -940,7 +940,7 @@ TEST(8) try { v = e.parse ("1==1&&log('a')").execute (); EXPECT_EQ (v.to_string (), std::string ("false")); - } catch (tl::EvalError) { + } catch (tl::EvalError &) { t = true; } EXPECT_EQ (t, true); From e26afab4e5c648446fe5c64fa3dc3c6b7700c40b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 16:49:05 +0200 Subject: [PATCH 08/45] Further reducing dependency of ui headers files generated for other modules --- src/lay/lay/lay.pro | 5 --- src/layui/layui/laySelectCellViewForm.cc | 53 +++++++++++++----------- src/layui/layui/laySelectCellViewForm.h | 10 ++++- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/lay/lay/lay.pro b/src/lay/lay/lay.pro index 71bd193f7..c93131cc1 100644 --- a/src/lay/lay/lay.pro +++ b/src/lay/lay/lay.pro @@ -192,11 +192,6 @@ win32 { LIBS += -lexecinfo } -# Note: this accounts for UI-generated headers placed into the output folders in -# shadow builds: -INCLUDEPATH += $$DESTDIR/laybasic/laybasic -DEPENDPATH += $$DESTDIR/laybasic/laybasic - INCLUDEPATH += $$QTBASIC_INC DEPENDPATH += $$QTBASIC_INC diff --git a/src/layui/layui/laySelectCellViewForm.cc b/src/layui/layui/laySelectCellViewForm.cc index ccdb27d1d..a8aba6b60 100644 --- a/src/layui/layui/laySelectCellViewForm.cc +++ b/src/layui/layui/laySelectCellViewForm.cc @@ -26,29 +26,34 @@ #include "layCellView.h" #include "layLayoutViewBase.h" +#include "ui_SelectCellViewForm.h" + + namespace lay { // ------------------------------------------------------------ SelectCellViewForm::SelectCellViewForm (QWidget *parent, lay::LayoutViewBase *view, const std::string &title, bool single) - : QDialog (parent), Ui::SelectCellViewForm () + : QDialog (parent) { + mp_ui = new Ui::SelectCellViewForm (); + setObjectName (QString::fromUtf8 ("select_cv")); - Ui::SelectCellViewForm::setupUi (this); + mp_ui->setupUi (this); if (single) { - cvs_lb->setSelectionMode (QAbstractItemView::SingleSelection); + mp_ui->cvs_lb->setSelectionMode (QAbstractItemView::SingleSelection); } // signals and slots connections - connect( ok_button, SIGNAL( clicked() ), this, SLOT( accept() ) ); - connect( cancel_button, SIGNAL( clicked() ), this, SLOT( reject() ) ); - connect( select_all_pb, SIGNAL( clicked() ), this, SLOT( select_all() ) ); + connect (mp_ui->ok_button, SIGNAL( clicked() ), this, SLOT( accept() )); + connect (mp_ui->cancel_button, SIGNAL( clicked() ), this, SLOT( reject() )); + connect (mp_ui->select_all_pb, SIGNAL( clicked() ), this, SLOT( select_all() )); if (single) { - select_all_pb->hide (); + mp_ui->select_all_pb->hide (); } for (unsigned int i = 0; i < view->cellviews (); ++i) { @@ -61,19 +66,19 @@ SelectCellViewForm::SelectCellViewForm (QWidget *parent, lay::LayoutViewBase *vi void SelectCellViewForm::set_selection (int sel) { - for (int i = 0; i < int (cvs_lb->count ()); ++i) { - cvs_lb->item (i)->setSelected (false); + for (int i = 0; i < int (mp_ui->cvs_lb->count ()); ++i) { + mp_ui->cvs_lb->item (i)->setSelected (false); } - if (sel >= 0 && sel < int (cvs_lb->count ())) { - cvs_lb->setCurrentItem (cvs_lb->item (sel)); - cvs_lb->item (sel)->setSelected (true); + if (sel >= 0 && sel < int (mp_ui->cvs_lb->count ())) { + mp_ui->cvs_lb->setCurrentItem (mp_ui->cvs_lb->item (sel)); + mp_ui->cvs_lb->item (sel)->setSelected (true); } } void SelectCellViewForm::set_title (const std::string &title) { - title_lbl->setText (tl::to_qstring (title)); + mp_ui->title_lbl->setText (tl::to_qstring (title)); } void @@ -85,16 +90,16 @@ SelectCellViewForm::set_caption (const std::string &caption) void SelectCellViewForm::tell_cellview (const lay::CellView &cv) { - cvs_lb->addItem (tl::to_qstring (cv->name ())); - cvs_lb->setCurrentItem (0); - cvs_lb->item (0)->setSelected (true); + mp_ui->cvs_lb->addItem (tl::to_qstring (cv->name ())); + mp_ui->cvs_lb->setCurrentItem (0); + mp_ui->cvs_lb->item (0)->setSelected (true); } bool SelectCellViewForm::all_selected () const { - for (int i = 0; i < int (cvs_lb->count ()); ++i) { - if (! cvs_lb->item (i)->isSelected ()) { + for (int i = 0; i < int (mp_ui->cvs_lb->count ()); ++i) { + if (! mp_ui->cvs_lb->item (i)->isSelected ()) { return false; } } @@ -106,8 +111,8 @@ SelectCellViewForm::selected_cellviews () const { std::vector res; - for (int i = 0; i < int (cvs_lb->count ()); ++i) { - if (cvs_lb->item (i)->isSelected ()) { + for (int i = 0; i < int (mp_ui->cvs_lb->count ()); ++i) { + if (mp_ui->cvs_lb->item (i)->isSelected ()) { res.push_back (i); } } @@ -118,8 +123,8 @@ SelectCellViewForm::selected_cellviews () const int SelectCellViewForm::selected_cellview () const { - for (int i = 0; i < int (cvs_lb->count ()); ++i) { - if (cvs_lb->item (i)->isSelected ()) { + for (int i = 0; i < int (mp_ui->cvs_lb->count ()); ++i) { + if (mp_ui->cvs_lb->item (i)->isSelected ()) { return i; } } @@ -129,8 +134,8 @@ SelectCellViewForm::selected_cellview () const void SelectCellViewForm::select_all () { - cvs_lb->clearSelection (); // without this, not all items may be selected in "selectAll" - cvs_lb->selectAll (); + mp_ui->cvs_lb->clearSelection (); // without this, not all items may be selected in "selectAll" + mp_ui->cvs_lb->selectAll (); } } diff --git a/src/layui/layui/laySelectCellViewForm.h b/src/layui/layui/laySelectCellViewForm.h index 9d3a1d63c..4c749c61c 100644 --- a/src/layui/layui/laySelectCellViewForm.h +++ b/src/layui/layui/laySelectCellViewForm.h @@ -32,7 +32,10 @@ #include -#include "ui_SelectCellViewForm.h" +namespace Ui +{ + class SelectCellViewForm; +} namespace lay { @@ -41,7 +44,7 @@ class CellView; class LayoutViewBase; class LAYUI_PUBLIC SelectCellViewForm - : public QDialog, private Ui::SelectCellViewForm + : public QDialog { Q_OBJECT @@ -85,6 +88,9 @@ public: public slots: virtual void select_all (); + +private: + Ui::SelectCellViewForm *mp_ui; }; } From 5eacb67368b6f5475455a1667c0ddfcbf9118859 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 17:55:27 +0200 Subject: [PATCH 09/45] Provide deferred execution also for the non-Qt case --- src/tl/tl/tlDeferredExecution.cc | 54 ++++++++++++++++++- src/tl/tl/tlDeferredExecution.h | 22 ++------ src/tl/tl/tlWebDAV.h | 4 ++ src/tl/unit_tests/tlDeferredExecutionTests.cc | 41 +++++++++----- src/tl/unit_tests/tlWebDAVTests.cc | 4 ++ 5 files changed, 93 insertions(+), 32 deletions(-) diff --git a/src/tl/tl/tlDeferredExecution.cc b/src/tl/tl/tlDeferredExecution.cc index 4577784de..baf9fa4b4 100644 --- a/src/tl/tl/tlDeferredExecution.cc +++ b/src/tl/tl/tlDeferredExecution.cc @@ -34,6 +34,21 @@ namespace tl static DeferredMethodScheduler *s_inst = 0; +// ----------------------------------------------------------------------------------- + +/** + * @brief A default scheduler which is used for example in non-Qt environments + */ +class DefaultDeferredMethodScheduler + : public DeferredMethodScheduler +{ +public: + DefaultDeferredMethodScheduler () : DeferredMethodScheduler () { } + void queue_event() {} +}; + +// ----------------------------------------------------------------------------------- + DeferredMethodScheduler::DeferredMethodScheduler () : m_disabled (0), m_scheduled (false) { @@ -55,9 +70,35 @@ DeferredMethodScheduler::instance () new DeferredMethodSchedulerQt (); } #endif + if (! s_inst) { + new DefaultDeferredMethodScheduler (); + } return s_inst; } +void +DeferredMethodScheduler::enable (bool en) +{ + if (instance ()) { + instance ()->do_enable (en); + } +} + +void +DeferredMethodScheduler::execute () +{ + if (instance ()) { + while (instance ()->do_execute ()) + ; + } +} + +bool +DeferredMethodScheduler::is_disabled () const +{ + return m_disabled; +} + void DeferredMethodScheduler::schedule (DeferredMethodBase *method) { @@ -105,10 +146,18 @@ DeferredMethodScheduler::do_enable (bool en) } } -void +bool DeferredMethodScheduler::do_execute () { m_lock.lock (); + + if (m_disabled) { + m_lock.unlock (); + return false; + } + + bool any_pending = false; + m_executing.clear (); m_unqueued.clear (); m_executing.swap (m_methods); @@ -143,7 +192,10 @@ DeferredMethodScheduler::do_execute () m_lock.lock (); m_unqueued.clear (); m_executing.clear (); + any_pending = !m_methods.empty (); m_lock.unlock (); + + return any_pending; } } diff --git a/src/tl/tl/tlDeferredExecution.h b/src/tl/tl/tlDeferredExecution.h index 380859e92..ef8f53d2d 100644 --- a/src/tl/tl/tlDeferredExecution.h +++ b/src/tl/tl/tlDeferredExecution.h @@ -90,32 +90,19 @@ public: * Enabling is cumulative: multiple enable(true) calls must be matched to * the same number of enable(false) calls. */ - static void enable (bool en) - { - if (instance ()) { - instance ()->do_enable (en); - } - } + static void enable (bool en); /** * @brief Execute all queued methods * * This method can be called to force execution of all queued methods. */ - static void execute () - { - if (instance ()) { - instance ()->do_execute (); - } - } + static void execute (); /** * @brief Gets a value indicating whether the scheduler is disabled */ - bool is_disabled () const - { - return m_disabled; - } + bool is_disabled () const; protected: /** @@ -126,8 +113,9 @@ protected: /** * @brief Executes the pending methods + * Returns true if more calls are required because handlers have issued more calls */ - void do_execute (); + bool do_execute (); /** * @brief Constructor diff --git a/src/tl/tl/tlWebDAV.h b/src/tl/tl/tlWebDAV.h index 380a6e325..2e98332af 100644 --- a/src/tl/tl/tlWebDAV.h +++ b/src/tl/tl/tlWebDAV.h @@ -30,6 +30,10 @@ #include #include +#if !defined(HAVE_CURL) && !defined(HAVE_QT) +# error "tlWebDAV.h can only be used with either curl or Qt enabled" +#endif + namespace tl { diff --git a/src/tl/unit_tests/tlDeferredExecutionTests.cc b/src/tl/unit_tests/tlDeferredExecutionTests.cc index d71505159..f87aa7a02 100644 --- a/src/tl/unit_tests/tlDeferredExecutionTests.cc +++ b/src/tl/unit_tests/tlDeferredExecutionTests.cc @@ -40,11 +40,24 @@ public: int na, nb; }; +void trigger_execution () +{ +#if defined(HAVE_QT) + if (QCoreApplication::instance ()) { + QCoreApplication::instance ()->processEvents (); + return; + } +#endif + + // explicit execute if timer does not do it + tl::DeferredMethodScheduler::execute (); +} + TEST(1) { g_na = g_nb = 0; - QCoreApplication::instance ()->processEvents (); + trigger_execution (); X *x = new X (); @@ -53,7 +66,7 @@ TEST(1) EXPECT_EQ (g_na, 0); EXPECT_EQ (g_nb, 0); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 0); EXPECT_EQ (x->nb, 0); @@ -71,7 +84,7 @@ TEST(1) tl::DeferredMethodScheduler::enable (false); tl::DeferredMethodScheduler::enable (false); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 0); EXPECT_EQ (x->nb, 0); @@ -83,7 +96,7 @@ TEST(1) x->db (); x->db (); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 0); EXPECT_EQ (x->nb, 0); @@ -92,14 +105,14 @@ TEST(1) tl::DeferredMethodScheduler::enable (true); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 1); EXPECT_EQ (x->nb, 2); EXPECT_EQ (g_na, 1); EXPECT_EQ (g_nb, 2); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 1); EXPECT_EQ (x->nb, 2); @@ -116,14 +129,14 @@ TEST(1) EXPECT_EQ (g_na, 1); EXPECT_EQ (g_nb, 2); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 2); EXPECT_EQ (x->nb, 4); EXPECT_EQ (g_na, 2); EXPECT_EQ (g_nb, 4); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 2); EXPECT_EQ (x->nb, 4); @@ -132,7 +145,7 @@ TEST(1) delete x; - QCoreApplication::instance ()->processEvents (); + trigger_execution (); x = new X (); @@ -141,7 +154,7 @@ TEST(1) EXPECT_EQ (g_na, 2); EXPECT_EQ (g_nb, 4); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 0); EXPECT_EQ (x->nb, 0); @@ -158,14 +171,14 @@ TEST(1) EXPECT_EQ (g_na, 2); EXPECT_EQ (g_nb, 4); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 1); EXPECT_EQ (x->nb, 2); EXPECT_EQ (g_na, 3); EXPECT_EQ (g_nb, 6); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (x->na, 1); EXPECT_EQ (x->nb, 2); @@ -179,7 +192,7 @@ TEST(1) delete x; - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (g_na, 3); EXPECT_EQ (g_nb, 6); @@ -208,7 +221,7 @@ TEST(2) y->da (); y->db (); - QCoreApplication::instance ()->processEvents (); + trigger_execution (); EXPECT_EQ (y_inst, 0); } diff --git a/src/tl/unit_tests/tlWebDAVTests.cc b/src/tl/unit_tests/tlWebDAVTests.cc index 6e7346030..b72ee0941 100644 --- a/src/tl/unit_tests/tlWebDAVTests.cc +++ b/src/tl/unit_tests/tlWebDAVTests.cc @@ -20,6 +20,7 @@ */ +#if defined(HAVE_CURL) || defined(HAVE_QT) #include "tlWebDAV.h" #include "tlHttpStream.h" @@ -149,3 +150,6 @@ TEST(5) EXPECT_EQ (ba21, "A text II.I.\n"); text21.close (); } + +#endif + From 7702d8c200c11c42ec743269504ec425365bb498 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 18:10:01 +0200 Subject: [PATCH 10/45] libpng option in build script --- build.sh | 8 +++++++ src/laybasic/laybasic/layLayoutViewBase.cc | 26 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index daafa8c93..6c6c61c9a 100755 --- a/build.sh +++ b/build.sh @@ -36,6 +36,7 @@ HAVE_QT_DESIGNER=1 HAVE_QT_XML=1 HAVE_64BIT_COORD=0 HAVE_QT=1 +HAVE_PNG=0 HAVE_CURL=0 HAVE_EXPAT=0 @@ -199,6 +200,9 @@ while [ "$*" != "" ]; do -dry-run) RUN_MAKE=0 ;; + -libpng) + HAVE_PNG=1 + ;; -libcurl) HAVE_CURL=1 ;; @@ -260,6 +264,7 @@ while [ "$*" != "" ]; do echo "" echo " -libcurl Use libcurl instead of QtNetwork (for Qt<4.7)" echo " -libexpat Use libexpat instead of QtXml" + echo " -libpng Use libpng instead of Qt for PNG generation" echo "" echo "Environment Variables:" echo "" @@ -487,6 +492,9 @@ fi if [ $HAVE_CURL != 0 ]; then echo " Uses libcurl for network access" fi +if [ $HAVE_PNG != 0 ]; then + echo " Uses libpng for PNG generation" +fi if [ "$RPATH" = "" ]; then RPATH="$BIN" fi diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index f91536907..853da6195 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -2549,7 +2549,7 @@ LayoutViewBase::save_screenshot (const std::string &fn) tl::log << "Saved screen shot to " << fn; } -#else +#elif defined(HAVE_PNG) void LayoutViewBase::save_screenshot (const std::string &fn) { @@ -2565,6 +2565,12 @@ LayoutViewBase::save_screenshot (const std::string &fn) tl::log << "Saved screen shot to " << fn; } +#else +void +LayoutViewBase::save_screenshot (const std::string &) +{ + throw tl::Exception (tl::to_string (tr ("Unable to write screenshot - PNG library not compiled in"))); +} #endif #if defined(HAVE_QT) @@ -2656,7 +2662,7 @@ LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned tl::log << "Saved image to " << fn; } -#else +#elif defined(HAVE_PNG) void LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned int height) { @@ -2675,6 +2681,12 @@ LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned tl::log << "Saved image to " << fn; } +#else +void +LayoutViewBase::save_image (const std::string &, unsigned int, unsigned int) +{ + throw tl::Exception (tl::to_string (tr ("Unable to save image - PNG library not compiled in"))); +} #endif #if defined(HAVE_QT) && !defined(PREFER_LIBPNG_FOR_SAVE) @@ -2708,7 +2720,7 @@ LayoutViewBase::save_image_with_options (const std::string &fn, tl::log << "Saved image to " << fn; } -#else +#elif defined(HAVE_PNG) void LayoutViewBase::save_image_with_options (const std::string &fn, unsigned int width, unsigned int height, int linewidth, int oversampling, double resolution, @@ -2739,6 +2751,14 @@ LayoutViewBase::save_image_with_options (const std::string &fn, tl::log << "Saved image to " << fn; } +#else +void +LayoutViewBase::save_image_with_options (const std::string &, + unsigned int, unsigned int, int, int, double, + lay::Color, lay::Color, lay::Color, const db::DBox &, bool) +{ + throw tl::Exception (tl::to_string (tr ("Unable to save image - PNG library not compiled in"))); +} #endif void From 001d695fccbde1c48d844084a537a9ae6da6c228 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 18:41:01 +0200 Subject: [PATCH 11/45] Build fix for non-Qt case --- src/tl/unit_tests/tlDeferredExecutionTests.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tl/unit_tests/tlDeferredExecutionTests.cc b/src/tl/unit_tests/tlDeferredExecutionTests.cc index f87aa7a02..b3b5bce0f 100644 --- a/src/tl/unit_tests/tlDeferredExecutionTests.cc +++ b/src/tl/unit_tests/tlDeferredExecutionTests.cc @@ -23,7 +23,9 @@ #include "tlDeferredExecution.h" #include "tlUnitTest.h" -#include +#if defined(HAVE_QT) +# include +#endif int g_na = 0; int g_nb = 0; From ad87b22d91f853fa210ec7734de1548d9d3fce88 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 19:20:37 +0200 Subject: [PATCH 12/45] Potential segfault fixed: skip invalid cell views --- src/laybasic/laybasic/layLayoutViewBase.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index 853da6195..75b3fe78e 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -3390,7 +3390,7 @@ LayoutViewBase::timer () { bool dirty = false; for (std::list::const_iterator i = m_cellviews.begin (); i != m_cellviews.end () && ! dirty; ++i) { - dirty = (*i)->layout ().is_editable () && (*i)->is_dirty (); + dirty = (*i).is_valid () && (*i)->layout ().is_editable () && (*i)->is_dirty (); } if (dirty != m_dirty) { From d5723391fd90247ddd3471443fa09d2d09c78053 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 19:38:37 +0200 Subject: [PATCH 13/45] Better dependency model for shared objects --- src/klayout.pro | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/klayout.pro b/src/klayout.pro index 228db95b3..2fac8b69b 100644 --- a/src/klayout.pro +++ b/src/klayout.pro @@ -34,7 +34,7 @@ equals(HAVE_RUBY, "1") { } -LANG_DEPENDS = +LANG_DEPENDS = MAIN_DEPENDS = equals(HAVE_RUBY, "1") { @@ -64,7 +64,6 @@ db.depends += gsi rdb.depends += db lib.depends += db -buddies.depends += plugins lym $$LANG_DEPENDS lym.depends += gsi $$LANG_DEPENDS laybasic.depends += rdb @@ -74,10 +73,10 @@ ant.depends += layview img.depends += layview edt.depends += layview -plugins.depends += lib rdb db ant +plugins.depends += lib equals(HAVE_PYTHON, "1") { - pymod.depends += layview ant img edt lym + pymod.depends += layview lib ant img edt lym } equals(HAVE_RUBY, "1") { @@ -113,6 +112,11 @@ equals(HAVE_RUBY, "1") { klayout_main.depends += plugins $$MAIN_DEPENDS +} else { + + plugins.depends += layview ant img edt + } -unit_tests.depends += plugins $$MAIN_DEPENDS $$LANG_DEPENDS +buddies.depends += plugins lym $$LANG_DEPENDS +unit_tests.depends += plugins lym $$MAIN_DEPENDS $$LANG_DEPENDS From b22c7091ae7e4b684290dfdb8a12d577753cb718 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 27 May 2022 20:26:47 +0200 Subject: [PATCH 14/45] Skip resources in non-Qt case --- src/drc/drc/drc.pro | 6 ++++-- src/lvs/lvs/lvs.pro | 6 ++++-- src/rba/unit_tests/unit_tests.pro | 5 ++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/drc/drc/drc.pro b/src/drc/drc/drc.pro index 9f0f97cb6..2304dc132 100644 --- a/src/drc/drc/drc.pro +++ b/src/drc/drc/drc.pro @@ -13,8 +13,10 @@ HEADERS = \ drcCommon.h \ drcForceLink.h \ -RESOURCES = \ - drcResources.qrc +!equals(HAVE_QT, "0") { + RESOURCES = \ + drcResources.qrc +} INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC $$LYM_INC $$RDB_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC $$LYM_INC $$RDB_INC diff --git a/src/lvs/lvs/lvs.pro b/src/lvs/lvs/lvs.pro index 81437c6da..722270f84 100644 --- a/src/lvs/lvs/lvs.pro +++ b/src/lvs/lvs/lvs.pro @@ -13,8 +13,10 @@ HEADERS = \ lvsCommon.h \ lvsForceLink.h \ -RESOURCES = \ - lvsResources.qrc +!equals(HAVE_QT, "0") { + RESOURCES = \ + lvsResources.qrc +} INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC $$LYM_INC $$RDB_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC $$LYM_INC $$RDB_INC diff --git a/src/rba/unit_tests/unit_tests.pro b/src/rba/unit_tests/unit_tests.pro index 54ab31c3d..26a48aed4 100644 --- a/src/rba/unit_tests/unit_tests.pro +++ b/src/rba/unit_tests/unit_tests.pro @@ -14,4 +14,7 @@ DEPENDPATH += $$RBA_INC $$TL_INC $$DB_INC $$GSI_INC LIBS += -L$$DESTDIR_UT -lklayout_rba -lklayout_tl -lklayout_db -lklayout_gsi -RESOURCES = unit_tests.qrc \ +!equals(HAVE_QT, "0") { + RESOURCES = \ + unit_tests.qrc +} From ca3d840cb2e73f8561e68e8c19e8958ff20dc9ca Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 28 May 2022 00:33:08 +0200 Subject: [PATCH 15/45] Alternative implementation for resources for the non-Qt case. --- scripts/pyqrc.py | 154 ++++++++++++++++++++++++++ src/drc/drc/drc.pro | 2 +- src/klayout.pri | 12 ++ src/tl/tl/tl.pro | 2 + src/tl/tl/tlResources.cc | 127 +++++++++++++++++++++ src/tl/tl/tlResources.h | 74 +++++++++++++ src/tl/tl/tlStream.cc | 75 ++++++++++--- src/tl/unit_tests/tlDeflateTests.cc | 9 +- src/tl/unit_tests/tlResourcesTests.cc | 91 +++++++++++++++ src/tl/unit_tests/unit_tests.pro | 1 + 10 files changed, 524 insertions(+), 23 deletions(-) create mode 100755 scripts/pyqrc.py create mode 100644 src/tl/tl/tlResources.cc create mode 100644 src/tl/tl/tlResources.h create mode 100644 src/tl/unit_tests/tlResourcesTests.cc diff --git a/scripts/pyqrc.py b/scripts/pyqrc.py new file mode 100755 index 000000000..f0cbe3f9f --- /dev/null +++ b/scripts/pyqrc.py @@ -0,0 +1,154 @@ + +# A lean substitute for QRC which is employed in the non-Qt case + +import xml.etree.ElementTree as et +import argparse +import zlib +import os + + +# A class providing the generator + +class RCFile(object): + + def __init__(self, alias, path): + self.path = path + self.alias = alias + + def write(self, file, index): + + f = open(self.path, "rb") + raw_data = f.read() + f.close() + + data = zlib.compress(raw_data) + compressed = "true" + + cb = "{" + bc = "}" + cls = "Resource" + str(index) + file.write(f"\n// Resource file {self.path} as {self.alias}\n") + file.write( "namespace {\n") + file.write( "\n") + file.write(f" class {cls}\n") + file.write( " {\n") + file.write(f" {cls}() {cb}\n") + file.write(f" static bool compressed = {compressed};\n") + file.write(f" static const char *name = \"{self.alias}\";\n") + file.write( " static const unsigned char data[] = {") + n = 0 + for b in data: + if n == 0: + file.write("\n ") + file.write("0x%02x," % b) + n += 1 + if n == 16: + n = 0 + file.write( "\n") + file.write( " };\n") + file.write( " m_id = tl::register_resource(name, compressed, data, sizeof(data) / sizeof(data[0]));\n") + file.write( " }\n") + file.write(f" ~{cls}() {cb}\n") + file.write( " tl::unregister_resource(m_id)\n") + file.write( " }\n") + file.write( " tl::resource_id_type m_id;\n") + file.write(f" {bc} resource_instance{index}\n") + file.write( "\n") + file.write( "}\n") + + +class RCGenerator(object): + + def __init__(self): + self.files = [] + + def append(self, path, alias): + self.files.append(RCFile(path, alias)) + + def dump_files(self): + for f in self.files: + print(f.path) + + def write(self, file): + file.write(f""" +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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 + +*/ + +/** +* DO NOT EDIT THIS FILE. +* This file has been created automatically +*/ + +#include "tlResources.h" +""") + i = 1 + for f in self.files: + f.write(file, i) + i += 1 + + +# The main code + +generator = RCGenerator() + +# argument parsing + +parser = argparse.ArgumentParser(description='Lean QRC parser') +parser.add_argument('input', type=str, nargs='+', + help='The QRC input file') +parser.add_argument('--output', '-o', type=str, nargs='?', + help='The C++ output file') +parser.add_argument('--path', '-p', type=str, nargs='?', + help='Path to the input files (default is current directory)') + +args = parser.parse_args() + +# read the input file + +for input in args.input: + + root_node = et.parse(input).getroot() + + for qresource in root_node.findall('qresource'): + prefix = qresource.get('prefix') + for file in qresource.findall('file'): + alias = file.get('alias') + path = file.text + if alias is None: + alias = path + if prefix is not None: + alias = prefix + "/" + alias + if args.path is not None: + path = os.path.join(args.path, path) + else: + path = os.path.join(os.path.dirname(input), path) + generator.append(alias, path) + +# produce the output file + +if args.output is not None: + f = open(args.output, "w") + generator.write(f) + f.close() +else: + generator.dump_files() + + diff --git a/src/drc/drc/drc.pro b/src/drc/drc/drc.pro index 2304dc132..c43e875d0 100644 --- a/src/drc/drc/drc.pro +++ b/src/drc/drc/drc.pro @@ -13,7 +13,7 @@ HEADERS = \ drcCommon.h \ drcForceLink.h \ -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ drcResources.qrc } diff --git a/src/klayout.pri b/src/klayout.pri index 9bf6debac..ad0504dd2 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -182,6 +182,17 @@ equals(HAVE_QT, "0") { QT = + # fake qrc made with python + !equals(HAVE_PYTHON, "0") { + new_qrc.output = qrc_${QMAKE_FILE_BASE}.cc + new_qrc.commands = $$PYTHON $$PWD/../scripts/pyqrc.py ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT} + new_qrc.depend_command = $$PYTHON $$PWD/../scripts/pyqrc.py ${QMAKE_FILE_NAME} + new_qrc.input = RESOURCES + new_qrc.variable_out = SOURCES + new_qrc.CONFIG += dep_lines + QMAKE_EXTRA_COMPILERS += new_qrc + } + } else { DEFINES += HAVE_QT @@ -290,3 +301,4 @@ DEFINES += \ KLAYOUT_TINY_VERSION=$$KLAYOUT_TINY_VERSION \ VERSION = $$KLAYOUT_VERSION + diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index 0b1d91ead..2fc72a1fe 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -26,6 +26,7 @@ SOURCES = \ tlLog.cc \ tlObject.cc \ tlProgress.cc \ + tlResources.cc \ tlScriptError.cc \ tlSleep.cc \ tlStaticObjects.cc \ @@ -76,6 +77,7 @@ HEADERS = \ tlObject.h \ tlObjectCollection.h \ tlProgress.h \ + tlResources.h \ tlReuseVector.h \ tlScriptError.h \ tlSleep.h \ diff --git a/src/tl/tl/tlResources.cc b/src/tl/tl/tlResources.cc new file mode 100644 index 000000000..b09febe0d --- /dev/null +++ b/src/tl/tl/tlResources.cc @@ -0,0 +1,127 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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 "tlResources.h" + +#include +#include + +namespace tl +{ + +namespace { + +class ResourceDict +{ +public: + struct DictEntry + { + const unsigned char *data; + size_t data_size; + bool compressed; + }; + + ResourceDict () { } + + resource_id_type add (const char *name, bool compressed, const unsigned char *data, size_t data_size) + { + m_dict[std::string (name)] = m_entries.size (); + m_entries.push_back (DictEntry ()); + m_entries.back ().data = data; + m_entries.back ().data_size = data_size; + m_entries.back ().compressed = compressed; + return m_entries.size () - 1; + } + + void remove (resource_id_type id) + { + if (id < m_entries.size ()) { + m_entries [id].data = 0; + m_entries [id].data_size = 0; + } + } + + DictEntry *entry (const char *name) + { + auto i = m_dict.find (std::string (name)); + if (i != m_dict.end () && i->second < m_entries.size ()) { + return &m_entries [i->second]; + } else { + return 0; + } + } + +private: + std::map m_dict; + std::vector m_entries; +}; + +} + +static ResourceDict *ms_dict = 0; + +resource_id_type register_resource (const char *name, bool compressed, const unsigned char *data, size_t data_size) +{ + if (! ms_dict) { + ms_dict = new ResourceDict (); + } + return ms_dict->add (name, compressed, data, data_size); +} + +void unregister_resource (size_t id) +{ + if (ms_dict) { + ms_dict->remove (id); + } +} + +tl::InputStream *get_resource (const char *name) +{ + if (! ms_dict) { + return 0; + } + + ResourceDict::DictEntry *entry = ms_dict->entry (name); + if (! entry || ! entry->data) { + return 0; + } + + if (entry->compressed) { + + tl_assert (entry->data_size > 6); + + // NOTE: zlib compression (used in pyqrc) adds two bytes header before the data block and + // 4 bytes after (CRC32) + auto stream = new tl::InputStream (new tl::InputMemoryStream ((const char *) entry->data + 2, entry->data_size - 6)); + stream->inflate (); + return stream; + + } else { + + // raw data + return new tl::InputStream (new tl::InputMemoryStream ((const char *) entry->data, entry->data_size)); + + } +} + +} + diff --git a/src/tl/tl/tlResources.h b/src/tl/tl/tlResources.h new file mode 100644 index 000000000..3fbdaef0d --- /dev/null +++ b/src/tl/tl/tlResources.h @@ -0,0 +1,74 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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_tlResources +#define HDR_tlResources + +#include "tlAssert.h" +#include "tlStream.h" + +#include + +namespace tl +{ + +typedef size_t resource_id_type; + +/** + * @brief A facility for retrieving resource data similar to Qt resources + * + * This feature is intended to substitute Qt resources when Qt is not available. + */ + +/** + * @brief Registers the resource data under the given name + * + * @param name The name of the resource + * @param compressed True, if the data is gzip-compressed + * @param data The data pointer - needs to stay valid during the lifetime of the application + * @param data_size The size of the data block + * + * The return value is an Id by which the resource can be unregistered. + */ +TL_PUBLIC resource_id_type register_resource (const char *name, bool compressed, const unsigned char *data, size_t data_size); + +/** + * @brief Registers the resource data under the given name + * + * @param id The id of the resource to unregister (see "register_resource") + */ +TL_PUBLIC void unregister_resource (size_t id); + +/** + * @brief Gets the resource data as a stream + * + * @param name The resource name + * @return A tl::InputStream object delivering the data or 0 if there is no such resource + * It is the responsibility of the called to delete the input stream. + */ +TL_PUBLIC tl::InputStream *get_resource (const char *name); + +} + +#endif + diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 06b45849f..f8984e094 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -285,7 +285,7 @@ InputStream::get (size_t n, bool bypass_inflate) delete mp_inflate; mp_inflate = 0; } - } + } if (m_blen < n) { @@ -341,16 +341,36 @@ std::string InputStream::read_all (size_t max_count) { std::string str; - while (max_count > 0) { - size_t n = std::min (max_count, std::max (size_t (1), m_blen)); - const char *b = get (n); - if (b) { - str += std::string (b, n); - max_count -= n; - } else { - break; + + if (mp_inflate) { + + // Inflate is special - it does not have a guaranteed byte delivery, so we have to go the + // hard way and pick the file byte by byte + while (max_count > 0) { + const char *b = get (1); + if (b) { + str += *b; + --max_count; + } else { + break; + } } - } + + } else { + + while (max_count > 0) { + size_t n = std::min (max_count, std::max (size_t (1), m_blen)); + const char *b = get (n); + if (b) { + str += std::string (b, n); + max_count -= n; + } else { + break; + } + } + + } + return str; } @@ -358,15 +378,34 @@ std::string InputStream::read_all () { std::string str; - while (true) { - size_t n = std::max (size_t (1), m_blen); - const char *b = get (n); - if (b) { - str += std::string (b, n); - } else { - break; + + if (mp_inflate) { + + // Inflate is special - it does not have a guaranteed byte delivery, so we have to go the + // hard way and pick the file byte by byte + while (true) { + const char *b = get (1); + if (b) { + str += *b; + } else { + break; + } } - } + + } else { + + while (true) { + size_t n = std::max (size_t (1), m_blen); + const char *b = get (n); + if (b) { + str += std::string (b, n); + } else { + break; + } + } + + } + return str; } diff --git a/src/tl/unit_tests/tlDeflateTests.cc b/src/tl/unit_tests/tlDeflateTests.cc index f7be73257..948f90ce7 100644 --- a/src/tl/unit_tests/tlDeflateTests.cc +++ b/src/tl/unit_tests/tlDeflateTests.cc @@ -30,7 +30,7 @@ TEST(1) { unsigned char data[] = { - // gzip header + // gzip header: // 0x1f, 0x8b, 0x08, 0x08, // 0xed, 0x11, 0x07, 0x50, // 0x00, 0x03, @@ -39,9 +39,10 @@ TEST(1) 0x56, 0x00, 0xa2, 0x44, 0x85, 0x92, 0xd4, 0xe2, 0x12, 0x85, 0x18, 0x45, - 0x2e, 0x00, 0x20, 0xc7, - 0x43, 0x6a, 0x12, 0x00, - 0x00, 0x00 + 0x2e, 0x00, + // gzip tail (8 bytes): + // 0x20, 0xc7, 0x43, 0x6a, CRC32 + // 0x12, 0x00, 0x00, 0x00 uncompressed file size }; tl::InputMemoryStream ims ((const char *) data, sizeof (data)); diff --git a/src/tl/unit_tests/tlResourcesTests.cc b/src/tl/unit_tests/tlResourcesTests.cc new file mode 100644 index 000000000..044daa017 --- /dev/null +++ b/src/tl/unit_tests/tlResourcesTests.cc @@ -0,0 +1,91 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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 "tlUnitTest.h" +#include "tlResources.h" + +#include + +// uncompressed resources + +TEST(1) +{ + unsigned char hw[] = "hello, world!\n"; + + const char *name; + std::unique_ptr s; + + name = "__test_resource1"; + tl::resource_id_type id = tl::register_resource (name, false, hw, sizeof (hw)); + + s.reset (tl::get_resource ("__doesnotexist")); + EXPECT_EQ (s.get () == 0, true); + + s.reset (tl::get_resource (name)); + EXPECT_EQ (s.get () == 0, false); + if (s) { + std::string data = s->read_all (); + EXPECT_EQ (data.size (), strlen ((const char *) hw) + 1); + EXPECT_EQ (data, std::string ((const char *) hw, sizeof (hw))); + } + + tl::unregister_resource (id); + s.reset (tl::get_resource (name)); + EXPECT_EQ (s.get () == 0, true); +} + +// compressed resources + +TEST(2) +{ + const unsigned char hw[] = { + 0x78,0x9c, // zlib header + // data: + 0xcb,0x48,0xcd,0xc9,0xc9,0xd7,0x51,0x28,0xcf,0x2f,0xca,0x49,0x51,0xe4, + 0x02,0x00, + 0x26,0xb2,0x04,0xb4, // zlib CRC + }; + unsigned char hw_decoded[] = "hello, world!\n"; + + const char *name; + std::unique_ptr s; + + name = "__test_resource2"; + tl::resource_id_type id = tl::register_resource (name, true, hw, sizeof (hw)); + + s.reset (tl::get_resource ("__doesnotexist")); + EXPECT_EQ (s.get () == 0, true); + + s.reset (tl::get_resource (name)); + EXPECT_EQ (s.get () == 0, false); + if (s) { + std::string data = s->read_all (); + EXPECT_EQ (data.size (), strlen ((const char *) hw_decoded)); + EXPECT_EQ (data, std::string ((const char *) hw_decoded, sizeof (hw_decoded) - 1)); + } + + tl::unregister_resource (id); + s.reset (tl::get_resource (name)); + EXPECT_EQ (s.get () == 0, true); +} + diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 768faad17..05fe5f202 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -27,6 +27,7 @@ SOURCES = \ tlLongIntTests.cc \ tlMathTests.cc \ tlObjectTests.cc \ + tlResourcesTests.cc \ tlReuseVectorTests.cc \ tlStableVectorTests.cc \ tlStreamTests.cc \ From 89547a6fde9211df0c7eba043025ceb75d9aaf8d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 28 May 2022 01:37:59 +0200 Subject: [PATCH 16/45] Enabling non-qt resources in InputStream --- src/tl/tl/tlStream.cc | 50 +++++++++++++++++++++++++++++++------------ src/tl/tl/tlStream.h | 7 +++++- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index f8984e094..6807aaf73 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -42,6 +42,7 @@ #include "tlAssert.h" #include "tlFileUtils.h" #include "tlLog.h" +#include "tlResources.h" #include "tlException.h" #include "tlString.h" @@ -195,7 +196,15 @@ InputStream::InputStream (const std::string &abstract_path) } #else - throw tl::Exception (tl::to_string (tr ("Qt not enabled - resource paths are not available"))); + + tl::InputStream *stream = tl::get_resource (ex.get ()); + if (! stream) { + throw tl::Exception (tl::to_string (tr ("Resource not found: ")) + abstract_path); + } + + swap (*stream); + delete stream; + #endif } else if (ex.test ("pipe:")) { @@ -229,6 +238,22 @@ InputStream::InputStream (const std::string &abstract_path) m_owns_delegate = true; } +InputStream::~InputStream () +{ + if (mp_delegate && m_owns_delegate) { + delete mp_delegate; + mp_delegate = 0; + } + if (mp_inflate) { + delete mp_inflate; + mp_inflate = 0; + } + if (mp_buffer) { + delete[] mp_buffer; + mp_buffer = 0; + } +} + std::string InputStream::absolute_path (const std::string &abstract_path) { // TODO: align this implementation with InputStream ctor @@ -254,20 +279,17 @@ std::string InputStream::absolute_path (const std::string &abstract_path) } } -InputStream::~InputStream () +void +InputStream::swap (InputStream &other) { - if (mp_delegate && m_owns_delegate) { - delete mp_delegate; - mp_delegate = 0; - } - if (mp_inflate) { - delete mp_inflate; - mp_inflate = 0; - } - if (mp_buffer) { - delete[] mp_buffer; - mp_buffer = 0; - } + std::swap (m_pos, other.m_pos); + std::swap (mp_buffer, other.mp_buffer); + std::swap (m_bcap, other.m_bcap); + std::swap (m_blen, other.m_blen); + std::swap (mp_bptr, other.mp_bptr); + std::swap (mp_delegate, other.mp_delegate); + std::swap (m_owns_delegate, other.m_owns_delegate); + std::swap (mp_inflate, other.mp_inflate); } const char * diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index 35539589e..a49704eab 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -453,7 +453,7 @@ public: * @brief Copies the content of the stream to the output stream * Throws an exception on error. */ - void copy_to(tl::OutputStream &os); + void copy_to (tl::OutputStream &os); /** * @brief Enable uncompression of the following DEFLATE-compressed block @@ -539,6 +539,11 @@ public: { return mp_delegate; } + + /** + * @brief Swaps two streams + */ + void swap (InputStream &other); protected: void reset_pos () From 8e21dab345a8d6d3a31f4250b1482dcd7c113d4f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 28 May 2022 19:27:40 +0200 Subject: [PATCH 17/45] Reworked lym::MacroCollection for not using Qt (too much) --- scripts/pyqrc.py | 6 +- src/buddies/src/bd/strmrun.cc | 2 + src/drc/drc/built-in-macros/_drc_engine.rb | 2 +- src/drc/drc/built-in-macros/drc_install.lym | 2 +- .../drc/built-in-macros/drc_interpreters.lym | 4 +- .../layview/gsiDeclLayLayoutView_noqt.cc | 36 ++ src/layview/layview/layLayoutView_noqt.cc | 12 + src/layview/layview/layLayoutView_noqt.h | 10 + src/lvs/lvs/built-in-macros/lvs_install.lym | 2 +- .../lvs/built-in-macros/lvs_interpreters.lym | 4 +- src/lvs/lvs/lvs.pro | 2 +- src/lym/lym/lymMacroCollection.cc | 321 +++++++++--------- src/lym/lym/lymMacroCollection.h | 64 +--- src/tl/tl/tlFileUtils.cc | 11 + src/tl/tl/tlFileUtils.h | 6 + src/tl/tl/tlResources.cc | 62 +++- src/tl/tl/tlResources.h | 18 + src/tl/tl/tlStream.cc | 27 +- src/tl/tl/tlStream.h | 5 - src/unit_tests/unit_test_main.cc | 14 +- src/with_all_libs.pri | 12 +- 21 files changed, 360 insertions(+), 262 deletions(-) diff --git a/scripts/pyqrc.py b/scripts/pyqrc.py index f0cbe3f9f..168748e30 100755 --- a/scripts/pyqrc.py +++ b/scripts/pyqrc.py @@ -30,7 +30,7 @@ class RCFile(object): file.write(f"\n// Resource file {self.path} as {self.alias}\n") file.write( "namespace {\n") file.write( "\n") - file.write(f" class {cls}\n") + file.write(f" struct {cls}\n") file.write( " {\n") file.write(f" {cls}() {cb}\n") file.write(f" static bool compressed = {compressed};\n") @@ -49,10 +49,10 @@ class RCFile(object): file.write( " m_id = tl::register_resource(name, compressed, data, sizeof(data) / sizeof(data[0]));\n") file.write( " }\n") file.write(f" ~{cls}() {cb}\n") - file.write( " tl::unregister_resource(m_id)\n") + file.write( " tl::unregister_resource(m_id);\n") file.write( " }\n") file.write( " tl::resource_id_type m_id;\n") - file.write(f" {bc} resource_instance{index}\n") + file.write(f" {bc} resource_instance{index};\n") file.write( "\n") file.write( "}\n") diff --git a/src/buddies/src/bd/strmrun.cc b/src/buddies/src/bd/strmrun.cc index 0d58374a9..dac4a9981 100644 --- a/src/buddies/src/bd/strmrun.cc +++ b/src/buddies/src/bd/strmrun.cc @@ -83,6 +83,8 @@ BD_PUBLIC int strmrun (int argc, char *argv[]) python.define_variable (v->first, v->second); } + // @@@ ... add Python and Ruby built-in macro collections, autorun-early and autorun ... + std::string script = tl::absolute_file_path (data.script); lym::Macro macro; diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index a168a5442..1382f2524 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -2685,7 +2685,7 @@ CODE end def _process_events - if RBA::Application.instance + if RBA.constants.member?(:Application) && RBA::Application.instance RBA::Application.instance.process_events end end diff --git a/src/drc/drc/built-in-macros/drc_install.lym b/src/drc/drc/built-in-macros/drc_install.lym index 78d1ef3b0..24f67c2f4 100644 --- a/src/drc/drc/built-in-macros/drc_install.lym +++ b/src/drc/drc/built-in-macros/drc_install.lym @@ -19,7 +19,7 @@ module DRC # Installs the home menu entries (needs to be done on autorun, not autorun-early) - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window cat = "drc" diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index a5c4d13ed..dbd8591dd 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -88,7 +88,7 @@ module DRC create_template(":/drc-templates/drc.lym") # if available, create a menu branch - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window mw = RBA::Application::instance.main_window mw.menu.insert_menu("tools_menu.verification_group+", "drc", "DRC") end @@ -160,7 +160,7 @@ module DRC DRCPlainTextInterpreter::new(drc_recipe) # Creates a new macro category - if RBA::Application::instance + if RBA.constants.member?(:Application) && RBA::Application::instance RBA::Application::instance.add_macro_category("drc", "DRC", [ "drc" ]) end diff --git a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc index a0eaf8235..7af7cdc21 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc @@ -66,6 +66,18 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "\n" "This event has been introduced in version 0.28." ) + + gsi::method ("current", &lay::LayoutView::current, + "@brief Returns the current view\n" + "The current view is the one that is made current by using \\current=.\n" + "\n" + "This variation has been introduced for the non-Qt case in version 0.28." + ) + + gsi::method ("current=", &lay::LayoutView::set_current, gsi::arg ("view"), + "@brief Sets the current view\n" + "See \\current for details.\n" + "\n" + "This method has been introduced for the non-Qt case in version 0.28." + ) + gsi::method ("timer", static_cast (&lay::LayoutView::timer), "@brief A callback required to be called regularily in the non-Qt case.\n" "\n" @@ -84,12 +96,36 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This object controls these aspects of the view and controls the appearance of the data. " ); +static lay::CellViewRef get_active_cellview_ref () +{ + lay::LayoutView *view = 0; // @@@ lay::LayoutView::current (); + if (! view) { + return lay::CellViewRef (); + } + if (view->active_cellview_index () >= 0) { + return view->active_cellview_ref (); + } else { + return lay::CellViewRef (); + } +} + static lay::LayoutView *get_view (lay::CellViewRef *cv) { return cv->view ()->ui (); } static ClassExt extdecl_CellView ( + method ("active", &get_active_cellview_ref, + "@brief Gets the active CellView\n" + "The active CellView is the one that is selected in the current layout view. This method is " + "equivalent to\n" + "@code\n" + "RBA::LayoutView::current.active_cellview\n" + "@/code\n" + "If no CellView is active, this method returns nil.\n" + "\n" + "This method has been introduced in version 0.23." + ) + method_ext ("view", &get_view, "@brief Gets the view the cellview resides in\n" "This reference will be nil if the cellview is not a valid one.\n" diff --git a/src/layview/layview/layLayoutView_noqt.cc b/src/layview/layview/layLayoutView_noqt.cc index 6b8743a40..da85aab88 100644 --- a/src/layview/layview/layLayoutView_noqt.cc +++ b/src/layview/layview/layLayoutView_noqt.cc @@ -59,6 +59,18 @@ LayoutView::timer () } } +static tl::weak_ptr s_current_view; + +LayoutView *LayoutView::current () +{ + return s_current_view.get (); +} + +void LayoutView::set_current (LayoutView *view) +{ + s_current_view.reset (view); +} + } // namespace lay #endif diff --git a/src/layview/layview/layLayoutView_noqt.h b/src/layview/layview/layLayoutView_noqt.h index 0288d6081..959748bbb 100644 --- a/src/layview/layview/layLayoutView_noqt.h +++ b/src/layview/layview/layLayoutView_noqt.h @@ -66,6 +66,16 @@ public: */ void timer (); + /** + * @brief Gets the current view + */ + static LayoutView *current (); + + /** + * @brief Sets the current view + */ + static void set_current (LayoutView *view); + protected: /** * @brief Gets the LayoutView interface diff --git a/src/lvs/lvs/built-in-macros/lvs_install.lym b/src/lvs/lvs/built-in-macros/lvs_install.lym index d2b17657f..967ea1d5e 100644 --- a/src/lvs/lvs/built-in-macros/lvs_install.lym +++ b/src/lvs/lvs/built-in-macros/lvs_install.lym @@ -19,7 +19,7 @@ module LVS # Installs the home menu entries (needs to be done on autorun, not autorun-early) - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window cat = "lvs" diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index 24cd20021..c99c21e98 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -88,7 +88,7 @@ module LVS create_template(":/lvs-templates/lvs.lym") # if available, create a menu branch - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window mw = RBA::Application::instance.main_window mw.menu.insert_menu("tools_menu.verification_group+", "lvs", "LVS") end @@ -160,7 +160,7 @@ module LVS LVSPlainTextInterpreter::new(lvs_recipe) # Creates a new macro category - if RBA::Application::instance + if RBA.constants.member?(:Application) && RBA::Application::instance RBA::Application::instance.add_macro_category("lvs", "LVS", [ "lvs" ]) end diff --git a/src/lvs/lvs/lvs.pro b/src/lvs/lvs/lvs.pro index 722270f84..5a8c53f27 100644 --- a/src/lvs/lvs/lvs.pro +++ b/src/lvs/lvs/lvs.pro @@ -13,7 +13,7 @@ HEADERS = \ lvsCommon.h \ lvsForceLink.h \ -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ lvsResources.qrc } diff --git a/src/lym/lym/lymMacroCollection.cc b/src/lym/lym/lymMacroCollection.cc index 5ea264937..7955f7ce4 100644 --- a/src/lym/lym/lymMacroCollection.cc +++ b/src/lym/lym/lymMacroCollection.cc @@ -23,8 +23,6 @@ #include "lymMacroCollection.h" -#if defined(HAVE_QT) - #include "lymMacroInterpreter.h" #include "tlExceptions.h" #include "gsiDecl.h" @@ -38,14 +36,15 @@ #include "tlGlobPattern.h" #include "tlInclude.h" #include "tlProgress.h" +#include "tlFileUtils.h" +#include "tlResources.h" #include "rba.h" #include "pya.h" -#include -#include -#include -#include +#if defined(HAVE_QT) +# include +#endif #include #include @@ -90,20 +89,26 @@ void MacroCollection::begin_changes () if (mp_parent) { mp_parent->begin_changes (); } else { +#if defined(HAVE_QT) emit about_to_change (); +#endif } } void MacroCollection::on_menu_needs_update () { +#if defined(HAVE_QT) emit menu_needs_update (); +#endif } void MacroCollection::on_changed () { // Note: it is very important that each on_changed occurs after exactly one begin_changes. // (See #459 for example) +#if defined(HAVE_QT) emit changed (); +#endif on_macro_collection_changed (this); } @@ -112,13 +117,17 @@ void MacroCollection::on_macro_collection_changed (MacroCollection *mc) if (mp_parent) { mp_parent->on_macro_collection_changed (mc); } else { +#if defined(HAVE_QT) emit macro_collection_changed (mc); +#endif } } void MacroCollection::on_child_deleted (MacroCollection *mc) { +#if defined(HAVE_QT) emit child_deleted (mc); +#endif on_macro_collection_deleted (mc); } @@ -127,13 +136,17 @@ void MacroCollection::on_macro_collection_deleted (MacroCollection *mc) if (mp_parent) { mp_parent->on_macro_collection_deleted (mc); } else { +#if defined(HAVE_QT) emit macro_collection_deleted (mc); +#endif } } void MacroCollection::on_macro_deleted_here (Macro *macro) { +#if defined(HAVE_QT) emit macro_deleted_here (macro); +#endif on_macro_deleted (macro); } @@ -142,7 +155,9 @@ void MacroCollection::on_macro_deleted (Macro *macro) if (mp_parent) { mp_parent->on_macro_deleted (macro); } else { +#if defined(HAVE_QT) emit macro_deleted (macro); +#endif } } @@ -151,7 +166,9 @@ void MacroCollection::on_macro_changed (Macro *macro) if (mp_parent) { mp_parent->on_macro_changed (macro); } else { +#if defined(HAVE_QT) emit macro_changed (macro); +#endif } } @@ -215,7 +232,7 @@ std::string MacroCollection::path () const if (m_virtual_mode) { return m_path; } else if (mp_parent) { - return tl::to_string (QFileInfo (QDir (tl::to_qstring (mp_parent->path ())), tl::to_qstring (m_path)).filePath ()); + return tl::combine_path (mp_parent->path (), m_path); } else { return m_path; } @@ -245,64 +262,62 @@ MacroCollection::make_readonly (bool f) } MacroCollection * -MacroCollection::add_folder (const std::string &description, const std::string &path, const std::string &cat, bool readonly, bool force_create) +MacroCollection::add_folder (const std::string &description, const std::string &p, const std::string &cat, bool readonly, bool force_create) { - if (! path.empty () && path[0] == ':') { + if (! p.empty () && p[0] == ':') { + readonly = true; + } else { - QFileInfo file_info (tl::to_qstring (path)); + std::string fp = p; + if (! tl::is_absolute (fp)) { + fp = tl::combine_path (path (), fp); + } - if (! file_info.exists ()) { + if (! tl::file_exists (fp)) { // Try to create the folder since it does not exist yet or skip that one if (! force_create) { if (tl::verbosity () >= 20) { - tl::log << "Folder does not exist - skipping: " << path; + tl::log << "Folder does not exist - skipping: " << fp; } return 0; } else { if (tl::verbosity () >= 20) { - tl::log << "Folder does not exist yet - trying to create it: " << path; + tl::log << "Folder does not exist yet - trying to create it: " << fp; } - if (! QDir::root ().mkpath (file_info.absoluteFilePath ())) { + if (! tl::mkpath (fp)) { if (tl::verbosity () >= 10) { - tl::error << "Unable to create folder path: " << path; + tl::error << "Unable to create folder path: " << fp; } return 0; } } - file_info.refresh (); - } - if (! file_info.isDir ()) { + if (! tl::is_dir (fp)) { if (tl::verbosity () >= 10) { - tl::error << "Folder is not a directory: " << path; + tl::error << "Folder is not a directory: " << fp; } return 0; } - QString cp = file_info.canonicalFilePath (); - if (cp.isEmpty ()) { - return 0; - } - for (child_iterator f = m_folders.begin (); f != m_folders.end (); ++f) { // skip, if that folder is in the collection already - if (QFileInfo (tl::to_qstring (f->first)).canonicalFilePath () == cp) { + if (f->second->path () == fp) { return 0; } } - if (! readonly && ! file_info.isWritable ()) { + if (! readonly && ! tl::is_writable (fp)) { readonly = true; if (tl::verbosity () >= 20) { - tl::log << "Folder is read-only: " << path; + tl::log << "Folder is read-only: " << fp; } } @@ -310,12 +325,12 @@ MacroCollection::add_folder (const std::string &description, const std::string & begin_changes (); - MacroCollection *mc = m_folders.insert (std::make_pair (path, new MacroCollection ())).first->second; - mc->set_name (path); + MacroCollection *mc = m_folders.insert (std::make_pair (p, new MacroCollection ())).first->second; + mc->set_name (p); mc->set_description (description); mc->set_category (cat); mc->set_readonly (readonly); - mc->scan (path); + mc->scan (); mc->set_parent (this); on_changed (); @@ -327,10 +342,11 @@ MacroCollection::add_folder (const std::string &description, const std::string & void MacroCollection::rescan () { for (std::map ::const_iterator m = m_folders.begin (); m != m_folders.end (); ++m) { - m->second->scan (m->first); + m->second->scan (); } } +#if defined(HAVE_QT) namespace { /** @@ -345,168 +361,85 @@ namespace { }; } +#endif -void MacroCollection::scan (const std::string &path) +void MacroCollection::scan () { + std::string p = path (); + if (tl::verbosity () >= 20) { - tl::info << "Scanning macro path " << path << " (readonly=" << m_readonly << ")"; + tl::info << "Scanning macro path " << p << " (readonly=" << m_readonly << ")"; } - if (! path.empty () && path[0] == ':') { + if (! p.empty () && p[0] == ':') { - ResourceWithChildren res (tl::to_qstring (path)); +#if defined(HAVE_QT) + + ResourceWithChildren res (tl::to_qstring (p)); QStringList children = res.children (); children.sort (); - for (QStringList::const_iterator c = children.begin (); c != children.end (); ++c) { + for (auto c = children.begin (); c != children.end (); ++c) { - std::string url = path + "/" + tl::to_string (*c); + std::string url = p + "/" + tl::to_string (*c); QResource res (tl::to_qstring (url)); if (res.size () > 0) { - - QByteArray data; -#if QT_VERSION >= 0x60000 - if (res.compressionAlgorithm () == QResource::ZlibCompression) { -#else - if (res.isCompressed ()) { -#endif - data = qUncompress ((const unsigned char *)res.data (), (int)res.size ()); - } else { - data = QByteArray ((const char *)res.data (), (int)res.size ()); - } - - try { - - Macro::Format format = Macro::NoFormat; - Macro::Interpreter interpreter = Macro::None; - std::string dsl_name; - bool autorun = false; - - if (Macro::format_from_suffix (tl::to_string (*c), interpreter, dsl_name, autorun, format)) { - - std::string n = tl::to_string (QFileInfo (*c).baseName ()); - - iterator mm = m_macros.find (n); - bool found = false; - while (mm != m_macros.end () && mm->first == n && ! found) { - if ((interpreter == Macro::None || mm->second->interpreter () == interpreter) && - (dsl_name.empty () || mm->second->dsl_interpreter () == dsl_name) && - mm->second->format () == format) { - found = true; - } - ++mm; - } - if (! found) { - Macro *m = m_macros.insert (std::make_pair (n, new Macro ()))->second; - m->set_interpreter (interpreter); - m->set_autorun_default (autorun); - m->set_autorun (autorun); - m->set_dsl_interpreter (dsl_name); - m->set_format (format); - m->set_name (n); - m->load_from_string (std::string (data.constData (), data.size ()), url); - m->set_readonly (m_readonly); - m->reset_modified (); - m->set_is_file (); - m->set_parent (this); - } - - } - - } catch (tl::Exception &ex) { - tl::error << "Reading " << url << ": " << ex.msg (); - } - + create_entry (url); } } +#else + + std::vector res = tl::find_resources (std::string (p, 1) + "/*"); + for (auto c = res.begin (); c != res.end (); ++c) { + create_entry (":" + *c); + } + +#endif + } else { - QDir dir (tl::to_qstring (path)); - QStringList filters; - filters << QString::fromUtf8 ("*.lym"); - filters << QString::fromUtf8 ("*.txt"); + std::set suffixes; + suffixes.insert ("lym"); + suffixes.insert ("txt"); // TODO: should be either *.rb or *.python, depending on the category. // Right now we rely on the folders not containing foreign files. - filters << QString::fromUtf8 ("*.rb"); - filters << QString::fromUtf8 ("*.py"); + suffixes.insert ("rb"); + suffixes.insert ("py"); // add the suffixes in the DSL interpreter declarations for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { if (! cls->suffix ().empty ()) { - filters << tl::to_qstring ("*." + cls->suffix ()); + suffixes.insert (cls->suffix ()); } } - QStringList files = dir.entryList (filters, QDir::Files); - for (QStringList::ConstIterator f = files.begin (); f != files.end (); ++f) { - - std::unique_ptr new_macro; - - try { - - std::string n = tl::to_string (QFileInfo (*f).completeBaseName ()); - std::string mp = tl::to_string (dir.absoluteFilePath (*f)); - - Macro::Format format = Macro::NoFormat; - Macro::Interpreter interpreter = Macro::None; - std::string dsl_name; - bool autorun = false; - - if (Macro::format_from_suffix (tl::to_string (*f), interpreter, dsl_name, autorun, format)) { - - iterator mm = m_macros.find (n); - bool found = false; - while (mm != m_macros.end () && mm->first == n && ! found) { - if ((interpreter == Macro::None || mm->second->interpreter () == interpreter) && - (dsl_name.empty () || mm->second->dsl_interpreter () == dsl_name) && - mm->second->format () == format) { - found = true; - } - ++mm; - } - if (! found) { - Macro *m = new Macro (); - new_macro.reset (m); - m->set_format (format); - m->set_autorun_default (autorun); - m->set_autorun (autorun); - m->set_interpreter (interpreter); - m->set_dsl_interpreter (dsl_name); - m->set_name (n); - m->load_from (mp); - m->reset_modified (); - m->set_readonly (m_readonly); - m->set_parent (this); - } - - } - - if (new_macro.get ()) { - m_macros.insert (std::make_pair (n, new_macro.release ())); - } - - } catch (tl::Exception &ex) { - tl::error << "Reading " << tl::to_string (*f) << " in " << path << ": " << ex.msg (); + std::vector files = tl::dir_entries (p, true /*with_files*/, false /*with_dirs*/, true /*without_dotfiles*/); + for (auto f = files.begin (); f != files.end (); ++f) { + if (suffixes.find (tl::extension (*f)) != suffixes.end ()) { + create_entry (tl::combine_path (p, *f)); } - } - QStringList folders = dir.entryList (QDir::Dirs | QDir::NoDotAndDotDot); - for (QStringList::ConstIterator f = folders.begin (); f != folders.end (); ++f) { + std::vector dirs = tl::dir_entries (p, false /*with_files*/, true /*with_dirs*/, true /*without_dotfiles*/); + for (auto f = files.begin (); f != files.end (); ++f) { + + std::string fp = tl::combine_path (p, *f); + if (! tl::is_dir (fp)) { + continue; + } try { - std::string n = tl::to_string (*f); - MacroCollection *&mc = m_folders.insert (std::make_pair (n, (MacroCollection *) 0)).first->second; + MacroCollection *&mc = m_folders.insert (std::make_pair (*f, (MacroCollection *) 0)).first->second; if (! mc) { mc = new MacroCollection (); - mc->set_name (n); + mc->set_name (*f); mc->set_virtual_mode (NotVirtual); - bool ro = (m_readonly || ! QFileInfo (dir.filePath (*f)).isWritable ()); + bool ro = (m_readonly || ! tl::is_writable (fp)); mc->set_readonly (ro); - mc->scan (tl::to_string (dir.filePath (*f))); + mc->scan (); mc->set_parent (this); } @@ -519,6 +452,59 @@ void MacroCollection::scan (const std::string &path) } } +void +MacroCollection::create_entry (const std::string &path) +{ + try { + + std::string n = tl::complete_basename (path); + + Macro::Format format = Macro::NoFormat; + Macro::Interpreter interpreter = Macro::None; + std::string dsl_name; + bool autorun = false; + + std::unique_ptr new_macro; + + if (Macro::format_from_suffix (path, interpreter, dsl_name, autorun, format)) { + + iterator mm = m_macros.find (n); + bool found = false; + while (mm != m_macros.end () && mm->first == n && ! found) { + if ((interpreter == Macro::None || mm->second->interpreter () == interpreter) && + (dsl_name.empty () || mm->second->dsl_interpreter () == dsl_name) && + mm->second->format () == format) { + found = true; + } + ++mm; + } + if (! found) { + Macro *m = new Macro (); + new_macro.reset (m); + m->set_interpreter (interpreter); + m->set_autorun_default (autorun); + m->set_autorun (autorun); + m->set_dsl_interpreter (dsl_name); + m->set_format (format); + m->set_name (n); + m->load_from (path); + m->set_readonly (m_readonly); + m->reset_modified (); + m->set_is_file (); + m->set_parent (this); + } + + } + + if (new_macro.get ()) { + m_macros.insert (std::make_pair (n, new_macro.release ())); + } + + } catch (tl::Exception &ex) { + tl::error << "Reading " << path << ": " << ex.msg (); + } +} + void MacroCollection::clear () { begin_changes (); @@ -594,9 +580,8 @@ bool MacroCollection::rename (const std::string &n) if (tl::verbosity () >= 20) { tl::info << "Renaming macro folder " << path () << " to " << n; } - QFile f (tl::to_qstring (path ())); begin_changes (); - if (! f.rename (QFileInfo (QDir (tl::to_qstring (mp_parent->path ())), tl::to_qstring (n)).filePath ())) { + if (! tl::rename_file (path (), n)) { on_changed (); return false; } else { @@ -621,7 +606,7 @@ lym::MacroCollection *MacroCollection::create_folder (const char *prefix, bool m ++n; } while (true); - if (mkdir && ! QDir (tl::to_qstring (path ())).mkdir (tl::to_qstring (name))) { + if (mkdir && ! tl::mkpath (tl::combine_path (path (), name))) { return 0; } @@ -673,8 +658,8 @@ void MacroCollection::add_unspecific (lym::Macro *m) bool MacroCollection::add (lym::Macro *m) { - QDir d (tl::to_qstring (path ())); - QDir dd = QFileInfo (tl::to_qstring (m->path ())).dir (); + std::string d = tl::normalize_path (path ()); + std::string dd = tl::normalize_path (m->dir ()); if (d == dd) { @@ -694,21 +679,26 @@ bool MacroCollection::add (lym::Macro *m) // try to detect new child folders. If that is the case, create that folder and add // the macro there. - QDir dm (tl::to_qstring (m->dir ())); + std::string dm = tl::normalize_path (m->dir ()); while (true) { - std::string folder_name = tl::to_string (dm.dirName ()); - if (! dm.cdUp ()) { + std::string folder_name = tl::filename (dm); + dm = tl::dirname (dm); + if (dm.empty () || dm == ".") { break; } if (dm == d) { + begin_changes (); lym::MacroCollection *mc = m_folders.insert (std::make_pair (folder_name, new MacroCollection ())).first->second; mc->set_virtual_mode (NotVirtual); + mc->set_name (folder_name); mc->set_parent (this); on_changed (); + return mc->add (m); + } } @@ -723,7 +713,7 @@ bool MacroCollection::del () if (tl::verbosity () >= 20) { tl::info << "Deleting macro folder " << path (); } - return QDir ().rmdir (tl::to_qstring (path ())); + return tl::rm_dir_recursive (path ()); } void MacroCollection::rename_macro (Macro *macro, const std::string &new_name) @@ -984,4 +974,3 @@ void MacroCollection::dump (int l) } -#endif diff --git a/src/lym/lym/lymMacroCollection.h b/src/lym/lym/lymMacroCollection.h index 9df9f3d87..aea4b2f7e 100644 --- a/src/lym/lym/lymMacroCollection.h +++ b/src/lym/lym/lymMacroCollection.h @@ -27,13 +27,13 @@ #include "lymCommon.h" #include "lymMacro.h" -#if defined(HAVE_QT) - #include #include #include -#include +#if defined(HAVE_QT) +# include +#endif namespace lym { @@ -45,9 +45,13 @@ namespace lym * a folder containing *.lym, *.rb or other script files. */ class LYM_PUBLIC MacroCollection +#if defined(HAVE_QT) : public QObject +#endif { +#if defined(HAVE_QT) Q_OBJECT +#endif public: typedef std::multimap ::iterator iterator; @@ -334,6 +338,11 @@ public: /** * @brief Gets the begin iterator of the folders + * + * The iterator will deliver a pair of a string and a MacroCollection object. + * The string is the absolute path of the child folder. Child folders do not + * necessarily live inside the directory of the parent folder. Specifically for + * the root folder, children with any kind of paths may be present. */ child_iterator begin_children () { @@ -382,6 +391,7 @@ public: * @brief Gets a folder by name * * If no folder with that name exists, this method will return 0. + * The name is either relative to the folders path or it is an absolute path. */ MacroCollection *folder_by_name (const std::string &name); @@ -389,6 +399,7 @@ public: * @brief Gets a folder by name * * If no folder with that name exists, this method will return 0. + * The name is either relative to the folders path or it is an absolute path. */ const MacroCollection *folder_by_name (const std::string &name) const; @@ -445,6 +456,7 @@ public: */ void dump (int l = 0); +#if defined(HAVE_QT) signals: /** * @brief This signal is sent when the collection changes @@ -496,6 +508,7 @@ signals: * @brief This signal is emitted from the collection root if the menu needs to be updated */ void menu_needs_update (); +#endif private: friend class Macro; @@ -518,10 +531,8 @@ private: void on_changed (); void on_menu_needs_update (); - /** - * @brief Scans a folder creating the macro collection - */ - void scan (const std::string &path); + void scan (); + void create_entry (const std::string &path); void rename_macro (Macro *macro, const std::string &new_name); @@ -551,44 +562,5 @@ private: } -#else // without QT: - -#include - -namespace lym -{ - -/** - * @brief Dummy implementation for Qt-less builds. - * - * This dummy implementation does not provide any services but acts as a dummy anchor - * for lym::Macro. - * - * Without Qt, the MacroCollection does not make much sense as there is no - * application specific file system without an Application object. - */ -class LYM_PUBLIC MacroCollection -{ -public: - MacroCollection () - { - // .. nothing yet .. - } - - std::string path () const - { - return std::string (); - } - - void rename_macro (lym::Macro *, const std::string &) - { - // .. nothing yet .. - } -}; - -} - -#endif - #endif diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index 163df8aaf..19cce3c2e 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -314,6 +314,17 @@ std::string basename (const std::string &s) } } +std::string complete_basename (const std::string &s) +{ + std::vector fnp = split_filename (filename (s)); + if (fnp.size () > 0) { + fnp.pop_back (); + return tl::join (fnp, "."); + } else { + return std::string (); + } +} + std::string extension (const std::string &s) { std::vector fnp = split_filename (filename (s)); diff --git a/src/tl/tl/tlFileUtils.h b/src/tl/tl/tlFileUtils.h index 4b628006c..da6bd50ae 100644 --- a/src/tl/tl/tlFileUtils.h +++ b/src/tl/tl/tlFileUtils.h @@ -85,6 +85,12 @@ std::string TL_PUBLIC filename (const std::string &s); */ std::string TL_PUBLIC basename (const std::string &s); +/** + * @brief Gets the basename for a given file path (file name without the last extensions) + * This will strip all extensions (i.e. "archive.tar.gz" will become "archive.tar"). + */ +std::string TL_PUBLIC complete_basename (const std::string &s); + /** * @brief Gets the complete extension for a given file path */ diff --git a/src/tl/tl/tlResources.cc b/src/tl/tl/tlResources.cc index b09febe0d..c37cb4e5d 100644 --- a/src/tl/tl/tlResources.cc +++ b/src/tl/tl/tlResources.cc @@ -21,6 +21,7 @@ */ #include "tlResources.h" +#include "tlGlobPattern.h" #include #include @@ -35,17 +36,21 @@ class ResourceDict public: struct DictEntry { + std::string name; const unsigned char *data; size_t data_size; bool compressed; }; + typedef std::vector::const_iterator iterator; + ResourceDict () { } resource_id_type add (const char *name, bool compressed, const unsigned char *data, size_t data_size) { m_dict[std::string (name)] = m_entries.size (); m_entries.push_back (DictEntry ()); + m_entries.back ().name = name; m_entries.back ().data = data; m_entries.back ().data_size = data_size; m_entries.back ().compressed = compressed; @@ -55,6 +60,7 @@ public: void remove (resource_id_type id) { if (id < m_entries.size ()) { + m_entries [id].name.clear (); m_entries [id].data = 0; m_entries [id].data_size = 0; } @@ -70,6 +76,16 @@ public: } } + iterator begin () + { + return m_entries.begin (); + } + + iterator end () + { + return m_entries.end (); + } + private: std::map m_dict; std::vector m_entries; @@ -94,15 +110,15 @@ void unregister_resource (size_t id) } } -tl::InputStream *get_resource (const char *name) +std::pair get_resource_reader (const char *name) { if (! ms_dict) { - return 0; + return std::pair (0, false); } ResourceDict::DictEntry *entry = ms_dict->entry (name); if (! entry || ! entry->data) { - return 0; + return std::pair (0, false); } if (entry->compressed) { @@ -111,16 +127,48 @@ tl::InputStream *get_resource (const char *name) // NOTE: zlib compression (used in pyqrc) adds two bytes header before the data block and // 4 bytes after (CRC32) - auto stream = new tl::InputStream (new tl::InputMemoryStream ((const char *) entry->data + 2, entry->data_size - 6)); - stream->inflate (); - return stream; + return std::make_pair (new tl::InputMemoryStream ((const char *) entry->data + 2, entry->data_size - 6), true); } else { // raw data - return new tl::InputStream (new tl::InputMemoryStream ((const char *) entry->data, entry->data_size)); + return std::make_pair (new tl::InputMemoryStream ((const char *) entry->data, entry->data_size), false); } + +} + +tl::InputStream *get_resource (const char *name) +{ + std::pair rr = get_resource_reader (name); + if (! rr.first) { + return 0; + } else { + auto stream = new tl::InputStream (rr.first); + if (rr.second) { + stream->inflate (); + } + return stream; + } +} + +std::vector +find_resources (const std::string &pattern) +{ + if (! ms_dict) { + return std::vector (); + } + + std::vector res; + tl::GlobPattern p (pattern); + + for (ResourceDict::iterator i = ms_dict->begin (); i != ms_dict->end (); ++i) { + if (i->data && p.match (i->name)) { + res.push_back (i->name); + } + } + + return res; } } diff --git a/src/tl/tl/tlResources.h b/src/tl/tl/tlResources.h index 3fbdaef0d..699e2089b 100644 --- a/src/tl/tl/tlResources.h +++ b/src/tl/tl/tlResources.h @@ -68,6 +68,24 @@ TL_PUBLIC void unregister_resource (size_t id); */ TL_PUBLIC tl::InputStream *get_resource (const char *name); +/** + * @brief Gets the resource data as a stream reader delegate plus compressed flag + * + * @param name The resource name + * @return A pair of reader delegate and a flag indicating whether the stream is compressed. + * If the resource is not found, the reade delegate is 0. + * It is the responsibility of the called to delete the reader delegate. + */ +TL_PUBLIC std::pair get_resource_reader (const char *name); + +/** + * @brief Get resource names matching a glob pattern + * + * For example, find_resources("/group/*") will find resources below "group". + * "*" also matches "/", so resources from subgroups will be listed too. + */ +TL_PUBLIC std::vector find_resources (const std::string &pattern); + } #endif diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 6807aaf73..92077af57 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -166,6 +166,8 @@ InputStream::InputStream (const std::string &abstract_path) m_blen = 0; mp_buffer = 0; + bool needs_inflate = false; + tl::Extractor ex (abstract_path.c_str ()); if (ex.test (":")) { @@ -197,13 +199,13 @@ InputStream::InputStream (const std::string &abstract_path) #else - tl::InputStream *stream = tl::get_resource (ex.get ()); - if (! stream) { + std::pair rr = tl::get_resource_reader (ex.get ()); + if (! rr.first) { throw tl::Exception (tl::to_string (tr ("Resource not found: ")) + abstract_path); } - swap (*stream); - delete stream; + mp_delegate = rr.first; + needs_inflate = rr.second; #endif @@ -236,6 +238,10 @@ InputStream::InputStream (const std::string &abstract_path) } m_owns_delegate = true; + + if (needs_inflate) { + inflate (); + } } InputStream::~InputStream () @@ -279,19 +285,6 @@ std::string InputStream::absolute_path (const std::string &abstract_path) } } -void -InputStream::swap (InputStream &other) -{ - std::swap (m_pos, other.m_pos); - std::swap (mp_buffer, other.mp_buffer); - std::swap (m_bcap, other.m_bcap); - std::swap (m_blen, other.m_blen); - std::swap (mp_bptr, other.mp_bptr); - std::swap (mp_delegate, other.mp_delegate); - std::swap (m_owns_delegate, other.m_owns_delegate); - std::swap (mp_inflate, other.mp_inflate); -} - const char * InputStream::get (size_t n, bool bypass_inflate) { diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index a49704eab..0747a4b7e 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -540,11 +540,6 @@ public: return mp_delegate; } - /** - * @brief Swaps two streams - */ - void swap (InputStream &other); - protected: void reset_pos () { diff --git a/src/unit_tests/unit_test_main.cc b/src/unit_tests/unit_test_main.cc index 9000037d9..4bc19ed7f 100644 --- a/src/unit_tests/unit_test_main.cc +++ b/src/unit_tests/unit_test_main.cc @@ -30,6 +30,7 @@ #include "tlCommandLineParser.h" #include "tlFileUtils.h" #include "tlGlobPattern.h" +#include "lymMacroCollection.h" #include "rba.h" #include "pya.h" #include "gsiDecl.h" @@ -66,9 +67,9 @@ // (some in non-Qt case) #include "libForceLink.h" #include "rdbForceLink.h" -#if defined(HAVE_RUBY) && defined(HAVE_QT) -#include "drcForceLink.h" -#include "lvsForceLink.h" +#if defined(HAVE_RUBY) +# include "drcForceLink.h" +# include "lvsForceLink.h" #endif static int main_cont (int &argc, char **argv); @@ -530,6 +531,13 @@ main_cont (int &argc, char **argv) python_interpreter.reset (new pya::PythonInterpreter ()); python_interpreter->push_console (&console); + lym::MacroCollection &lym_root = lym::MacroCollection::root (); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-macros", "macros", true); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-pymacros", "pymacros", true); + + lym_root.autorun_early (); + lym_root.autorun (); + #endif bool editable = false, non_editable = false; diff --git a/src/with_all_libs.pri b/src/with_all_libs.pri index 23ea4963e..72085c5a7 100644 --- a/src/with_all_libs.pri +++ b/src/with_all_libs.pri @@ -29,13 +29,11 @@ equals(HAVE_PYTHON, "1") { LIBS += -lklayout_pyastub } -!equals(HAVE_QT, "0") { - equals(HAVE_RUBY, "1") { - # DRC is only available with Ruby - INCLUDEPATH += $$DRC_INC $$LVS_INC - DEPENDPATH += $$DRC_INC $$LVS_INC - LIBS += -lklayout_drc -lklayout_lvs - } +equals(HAVE_RUBY, "1") { + # DRC is only available with Ruby + INCLUDEPATH += $$DRC_INC $$LVS_INC + DEPENDPATH += $$DRC_INC $$LVS_INC + LIBS += -lklayout_drc -lklayout_lvs } msvc { From 1edaf2b6b40a242aa1f9c4286ee3ae5810270e3b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 28 May 2022 22:49:40 +0200 Subject: [PATCH 18/45] WIP: working on further consolidation of non-Qt case --- src/buddies/src/bd/strmrun.cc | 9 +- src/db/db/db.pro | 2 +- src/db/db/dbGlyphs.cc | 11 +- src/db/db/dbGlyphs.h | 2 - src/db/db/gsiDeclDbGlyphs.cc | 3 +- src/drc/drc/built-in-macros/_drc_layer.rb | 9 + .../layview/gsiDeclLayLayoutView_noqt.cc | 50 ---- .../layview/gsiDeclLayLayoutView_qt.cc | 50 ---- src/layview/layview/layview.pro | 1 + src/lib_ut.pri | 10 +- .../{unit_tests.qrc => rba_unit_tests.qrc} | 0 src/rba/unit_tests/unit_tests.pro | 4 +- testdata/ruby/dbLayoutTest.rb | 238 ++++++++---------- testdata/ruby/layMenuTest.rb | 16 ++ 14 files changed, 153 insertions(+), 252 deletions(-) rename src/rba/unit_tests/{unit_tests.qrc => rba_unit_tests.qrc} (100%) diff --git a/src/buddies/src/bd/strmrun.cc b/src/buddies/src/bd/strmrun.cc index dac4a9981..92b522afa 100644 --- a/src/buddies/src/bd/strmrun.cc +++ b/src/buddies/src/bd/strmrun.cc @@ -35,6 +35,7 @@ #include "libForceLink.h" #include "rdbForceLink.h" #include "lymMacro.h" +#include "lymMacroCollection.h" struct RunnerData { @@ -83,7 +84,13 @@ BD_PUBLIC int strmrun (int argc, char *argv[]) python.define_variable (v->first, v->second); } - // @@@ ... add Python and Ruby built-in macro collections, autorun-early and autorun ... + // install the built-in macros so we can run DRC and LVS scripts + lym::MacroCollection &lym_root = lym::MacroCollection::root (); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-macros", "macros", true); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-pymacros", "pymacros", true); + + lym_root.autorun_early (); + lym_root.autorun (); std::string script = tl::absolute_file_path (data.script); diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 35293190d..16f2caffb 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -392,7 +392,7 @@ HEADERS = \ dbShapeCollection.h \ dbShapeCollectionUtils.h -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ dbResources.qrc \ diff --git a/src/db/db/dbGlyphs.cc b/src/db/db/dbGlyphs.cc index 362de0dd2..a61c9722e 100644 --- a/src/db/db/dbGlyphs.cc +++ b/src/db/db/dbGlyphs.cc @@ -147,20 +147,11 @@ TextGenerator::text_as_region (const std::string &t, double target_dbu, double m return region; } -#if defined(HAVE_QT) void TextGenerator::load_from_resource (const std::string &name) { - QResource res (tl::to_qstring (name)); - if (res.size () == 0) { - throw tl::Exception (tl::to_string (tr ("Unable to load font resource from ")) + name); - } - - QByteArray data = qUncompress (QByteArray ((const char *) res.data (), int (res.size ()))); - - load_from_data (data.constData (), data.size (), tl::to_string (QFileInfo (tl::to_qstring (name)).baseName ()), name); + load_from_file (name); } -#endif void TextGenerator::load_from_data (const char *data, size_t ndata, const std::string &name, const std::string &description) diff --git a/src/db/db/dbGlyphs.h b/src/db/db/dbGlyphs.h index a3073984f..c42e186fd 100644 --- a/src/db/db/dbGlyphs.h +++ b/src/db/db/dbGlyphs.h @@ -76,12 +76,10 @@ public: */ TextGenerator (); -#if defined(HAVE_QT) /** * @brief Loads the font from the given resource */ void load_from_resource (const std::string &name); -#endif /** * @brief Loads from the given binary data diff --git a/src/db/db/gsiDeclDbGlyphs.cc b/src/db/db/gsiDeclDbGlyphs.cc index 95f2fd02e..f471f79d9 100644 --- a/src/db/db/gsiDeclDbGlyphs.cc +++ b/src/db/db/gsiDeclDbGlyphs.cc @@ -65,12 +65,11 @@ static std::vector generators () } Class decl_TextGenerator ("db", "TextGenerator", -#if defined(HAVE_QT) method ("load_from_resource", &db::TextGenerator::load_from_resource, arg ("resource_path"), "@brief Loads the given resource data (as layout data) into the generator\n" + "The resource path has to start with a colon, i.e. ':/my/resource.gds'. " "See the description of the class how the layout data is read." ) + -#endif method ("load_from_file", &db::TextGenerator::load_from_file, arg ("path"), "@brief Loads the given file into the generator\n" "See the description of the class how the layout data is read." diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index bde1c2ee7..8432a1890 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -3265,6 +3265,15 @@ CODE self.data.is_a?(RBA::EdgePairs) end + # %DRC% + # @name texts? + # @brief Returns true, if the layer is a text collection + # @synopsis layer.texts? + + def texts? + self.data.is_a?(RBA::Texts) + end + # %DRC% # @name is_deep? # @brief Returns true, if the layer is a deep (hierarchical) layer diff --git a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc index 7af7cdc21..84ad80b9a 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc @@ -96,56 +96,6 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This object controls these aspects of the view and controls the appearance of the data. " ); -static lay::CellViewRef get_active_cellview_ref () -{ - lay::LayoutView *view = 0; // @@@ lay::LayoutView::current (); - if (! view) { - return lay::CellViewRef (); - } - if (view->active_cellview_index () >= 0) { - return view->active_cellview_ref (); - } else { - return lay::CellViewRef (); - } -} - -static lay::LayoutView *get_view (lay::CellViewRef *cv) -{ - return cv->view ()->ui (); -} - -static ClassExt extdecl_CellView ( - method ("active", &get_active_cellview_ref, - "@brief Gets the active CellView\n" - "The active CellView is the one that is selected in the current layout view. This method is " - "equivalent to\n" - "@code\n" - "RBA::LayoutView::current.active_cellview\n" - "@/code\n" - "If no CellView is active, this method returns nil.\n" - "\n" - "This method has been introduced in version 0.23." - ) + - method_ext ("view", &get_view, - "@brief Gets the view the cellview resides in\n" - "This reference will be nil if the cellview is not a valid one.\n" - "This method has been added in version 0.25.\n" - ) -); - -static lay::LayoutView *get_view_from_lp (lay::LayerPropertiesNode *node) -{ - return node->view ()->ui (); -} - -static ClassExt extdecl_LayerPropertiesNode ( - method_ext ("view", &get_view_from_lp, - "@brief Gets the view this node lives in\n" - "\n" - "This reference can be nil if the node is a orphan node that lives outside a view." - ) -); - } #endif diff --git a/src/layview/layview/gsiDeclLayLayoutView_qt.cc b/src/layview/layview/gsiDeclLayLayoutView_qt.cc index 4a86add4b..8f104d62f 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_qt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_qt.cc @@ -171,56 +171,6 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This object controls these aspects of the view and controls the appearance of the data. " ); -static lay::CellViewRef get_active_cellview_ref () -{ - lay::LayoutView *view = lay::LayoutView::current (); - if (! view) { - return lay::CellViewRef (); - } - if (view->active_cellview_index () >= 0) { - return view->active_cellview_ref (); - } else { - return lay::CellViewRef (); - } -} - -static lay::LayoutView *get_view (lay::CellViewRef *cv) -{ - return cv->view ()->ui (); -} - -static ClassExt extdecl_CellView ( - method ("active", &get_active_cellview_ref, - "@brief Gets the active CellView\n" - "The active CellView is the one that is selected in the current layout view. This method is " - "equivalent to\n" - "@code\n" - "RBA::LayoutView::current.active_cellview\n" - "@/code\n" - "If no CellView is active, this method returns nil.\n" - "\n" - "This method has been introduced in version 0.23." - ) + - method_ext ("view", &get_view, - "@brief Gets the view the cellview resides in\n" - "This reference will be nil if the cellview is not a valid one.\n" - "This method has been added in version 0.25.\n" - ) -); - -static lay::LayoutView *get_view_from_lp (lay::LayerPropertiesNode *node) -{ - return node->view ()->ui (); -} - -static ClassExt extdecl_LayerPropertiesNode ( - method_ext ("view", &get_view_from_lp, - "@brief Gets the view this node lives in\n" - "\n" - "This reference can be nil if the node is a orphan node that lives outside a view." - ) -); - } #endif diff --git a/src/layview/layview/layview.pro b/src/layview/layview/layview.pro index 30d92982f..4fd39c63e 100644 --- a/src/layview/layview/layview.pro +++ b/src/layview/layview/layview.pro @@ -11,6 +11,7 @@ RESOURCES = \ SOURCES = \ layGridNet.cc \ layviewForceLink.cc \ + gsiDeclLayAdditional.cc \ HEADERS = \ layGridNet.h \ diff --git a/src/lib_ut.pri b/src/lib_ut.pri index e80c7ba32..c54e5aac3 100644 --- a/src/lib_ut.pri +++ b/src/lib_ut.pri @@ -17,8 +17,10 @@ win32 { QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut } -greaterThan(QT_MAJOR_VERSION, 4) { - QT += testlib -} else { - CONFIG += qtestlib +!equals(HAVE_QT, "0") { + greaterThan(QT_MAJOR_VERSION, 4) { + QT += testlib + } else { + CONFIG += qtestlib + } } diff --git a/src/rba/unit_tests/unit_tests.qrc b/src/rba/unit_tests/rba_unit_tests.qrc similarity index 100% rename from src/rba/unit_tests/unit_tests.qrc rename to src/rba/unit_tests/rba_unit_tests.qrc diff --git a/src/rba/unit_tests/unit_tests.pro b/src/rba/unit_tests/unit_tests.pro index 26a48aed4..6bca18f2f 100644 --- a/src/rba/unit_tests/unit_tests.pro +++ b/src/rba/unit_tests/unit_tests.pro @@ -14,7 +14,7 @@ DEPENDPATH += $$RBA_INC $$TL_INC $$DB_INC $$GSI_INC LIBS += -L$$DESTDIR_UT -lklayout_rba -lklayout_tl -lklayout_db -lklayout_gsi -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ - unit_tests.qrc + rba_unit_tests.qrc } diff --git a/testdata/ruby/dbLayoutTest.rb b/testdata/ruby/dbLayoutTest.rb index 29a7f3dc2..d45f27249 100644 --- a/testdata/ruby/dbLayoutTest.rb +++ b/testdata/ruby/dbLayoutTest.rb @@ -310,12 +310,8 @@ class DBLayoutTest_TestClass < TestBase assert_equal( inst.nb, 20 ) assert_equal( inst.cell_index, c1.cell_index ) - if( RBA::Application::instance.is_editable? ) - c2.each_inst { |inst| c2.erase( inst ) } - assert_equal( c2.bbox.to_s, "()" ) - else - c2.clear_insts - end + c2.each_inst { |inst| c2.erase( inst ) } + assert_equal( c2.bbox.to_s, "()" ) tr = RBA::CplxTrans::new( 1.5, 90.0, true, RBA::DPoint::new( 100, -50 ) ) inst = RBA::CellInstArray::new( c1.cell_index, tr, RBA::Point::new( 100, 0 ), RBA::Point::new( 0, 100 ), 10, 20 ) @@ -555,12 +551,7 @@ class DBLayoutTest_TestClass < TestBase assert_equal( inst.nb, 20 ) assert_equal( inst.cell_index, c1.cell_index ) - if( RBA::Application::instance.is_editable? ) - c2.each_inst { |inst| c2.erase( inst ) } - assert_equal( c2.bbox.to_s, "()" ) - else - c2.clear_insts - end + c2.each_inst { |inst| c2.erase( inst ) } assert_equal( c2.bbox.to_s, "()" ) tr = RBA::CplxTrans::new( 1.5, 90.0, true, RBA::DPoint::new( 100, -50 ) ) @@ -702,90 +693,86 @@ class DBLayoutTest_TestClass < TestBase # Instances and bboxes (editable mode) def test_6_Layout_new - if( RBA::Application::instance.is_editable? ) + ly = RBA::Layout::new + pid1 = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a ) + pid2 = ly.properties_id( { 100 => "x" }.to_a ) - ly = RBA::Layout::new - pid1 = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a ) - pid2 = ly.properties_id( { 100 => "x" }.to_a ) + ci1 = ly.add_cell( "c1" ) + ci2 = ly.add_cell( "c2" ) + ci3 = ly.add_cell( "c3" ) + c1 = ly.cell( ci1 ) + c2 = ly.cell( ci2 ) + c3 = ly.cell( ci3 ) - ci1 = ly.add_cell( "c1" ) - ci2 = ly.add_cell( "c2" ) - ci3 = ly.add_cell( "c3" ) - c1 = ly.cell( ci1 ) - c2 = ly.cell( ci2 ) - c3 = ly.cell( ci3 ) + tr = RBA::Trans::new( RBA::Trans::R90, RBA::Point::new( 100, -50 ) ) + inst_1 = RBA::CellInstArray::new( c1.cell_index, tr ) + new_inst_1 = c2.insert( inst_1, pid1 ) + new_inst_2 = c2.insert( inst_1, pid2 ) + inst_2 = RBA::CellInstArray::new( c3.cell_index, tr*tr ) + new_inst_3 = c1.insert( inst_2 ) - tr = RBA::Trans::new( RBA::Trans::R90, RBA::Point::new( 100, -50 ) ) - inst_1 = RBA::CellInstArray::new( c1.cell_index, tr ) - new_inst_1 = c2.insert( inst_1, pid1 ) - new_inst_2 = c2.insert( inst_1, pid2 ) - inst_2 = RBA::CellInstArray::new( c3.cell_index, tr*tr ) - new_inst_3 = c1.insert( inst_2 ) + assert_equal( new_inst_1.cell_index, c1.cell_index ) + assert_equal( new_inst_1.trans.to_s, tr.to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, 0 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - assert_equal( new_inst_1.cell_index, c1.cell_index ) - assert_equal( new_inst_1.trans.to_s, tr.to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, 0 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - new_inst_3 = c1.replace_prop_id( new_inst_3, pid2 ) - - assert_equal( new_inst_1.cell_index, c1.cell_index ) - assert_equal( new_inst_1.trans.to_s, tr.to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, pid2 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - begin - new_inst_1 = c1.replace( new_inst_1, inst_2 ) - assert_equal( true, false ) - rescue - # OK: gives an error since we are trying to erase an object from a list that is does not belong to - end - - new_inst_1 = c2.replace( new_inst_1, inst_2 ) - - assert_equal( new_inst_1.cell_index, c3.cell_index ) - assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, pid2 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - new_inst_1 = c2.replace( new_inst_1, inst_2, pid1 ) - - assert_equal( new_inst_1.cell_index, c3.cell_index ) - assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, pid2 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - assert_equal( new_inst_1.is_null?, false ) - assert_equal( RBA::Instance.new.is_null?, true ) - - assert_equal( c2.is_leaf?, false ) - c2.erase( new_inst_1 ) - c2.erase( new_inst_2 ) - assert_equal( c2.is_leaf?, true ) - assert_equal( c2.child_instances, 0 ) + new_inst_3 = c1.replace_prop_id( new_inst_3, pid2 ) + + assert_equal( new_inst_1.cell_index, c1.cell_index ) + assert_equal( new_inst_1.trans.to_s, tr.to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, pid2 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) + begin + new_inst_1 = c1.replace( new_inst_1, inst_2 ) + assert_equal( true, false ) + rescue + # OK: gives an error since we are trying to erase an object from a list that is does not belong to end + new_inst_1 = c2.replace( new_inst_1, inst_2 ) + + assert_equal( new_inst_1.cell_index, c3.cell_index ) + assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, pid2 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) + + new_inst_1 = c2.replace( new_inst_1, inst_2, pid1 ) + + assert_equal( new_inst_1.cell_index, c3.cell_index ) + assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, pid2 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) + + assert_equal( new_inst_1.is_null?, false ) + assert_equal( RBA::Instance.new.is_null?, true ) + + assert_equal( c2.is_leaf?, false ) + c2.erase( new_inst_1 ) + c2.erase( new_inst_2 ) + assert_equal( c2.is_leaf?, true ) + assert_equal( c2.child_instances, 0 ) + end def shapes_to_s(ly, shapes) @@ -810,11 +797,6 @@ class DBLayoutTest_TestClass < TestBase # Copy/move between cells def test_7_cells_copy_move - # because of set_property ... - if !RBA::Application::instance.is_editable? - return - end - ly1 = RBA::Layout::new la1 = ly1.insert_layer(RBA::LayerInfo::new(1, 0)) lb1 = ly1.insert_layer(RBA::LayerInfo::new(2, 0)) @@ -976,54 +958,50 @@ class DBLayoutTest_TestClass < TestBase c3.each_inst { |i| str << i.to_s(true) } assert_equal(str.join(";"), "") - if RBA::Application::instance.is_editable? + i1.cell_index = ci3 - i1.cell_index = ci3 + str = [] + c1.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "c3 r90 100,-50") - str = [] - c1.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "c3 r90 100,-50") + str = [] + c2.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c2.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + str = [] + c3.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c3.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + i1.cell = c2 - i1.cell = c2 + str = [] + c1.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "c2 r90 100,-50") - str = [] - c1.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "c2 r90 100,-50") + str = [] + c2.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c2.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + str = [] + c3.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c3.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + assert_equal(i1.parent_cell.name, "c1") - assert_equal(i1.parent_cell.name, "c1") + i1.cell = c1 + i1.parent_cell = c2 - i1.cell = c1 - i1.parent_cell = c2 + str = [] + c1.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c1.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + str = [] + c2.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "c1 r90 100,-50") - str = [] - c2.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "c1 r90 100,-50") - - str = [] - c3.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") - - end + str = [] + c3.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") end diff --git a/testdata/ruby/layMenuTest.rb b/testdata/ruby/layMenuTest.rb index 891070c59..a0135a7bf 100644 --- a/testdata/ruby/layMenuTest.rb +++ b/testdata/ruby/layMenuTest.rb @@ -313,6 +313,10 @@ RESULT def test_3 + if !RBA.constants.member?(:AbstractMenu) + return + end + map = RBA::AbstractMenu::unpack_key_binding("'path.a':X;'path.b':''") assert_equal(map["path.a"], "X") assert_equal(map["path.b"], "") @@ -333,6 +337,10 @@ RESULT def test_4 + if !RBA.constants.member?(:Action) + return + end + action = RBA::Action::new action.title = "title:n1" @@ -359,6 +367,10 @@ RESULT def test_5 + if !RBA.constants.member?(:Action) + return + end + action = RBA::Action::new action.title = "title:n1" @@ -386,6 +398,10 @@ RESULT def test_6 + if !RBA.constants.member?(:Application) + return + end + app = RBA::Application.instance mw = app.main_window From 29b3718b2d1493e35d970d27b8adf020a3b31ab8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 10:11:16 +0200 Subject: [PATCH 19/45] Further reducing dependency on Qt, fixed tests --- src/buddies/unit_tests/buddies_main.cc | 3 +- src/layui/layui/rdbMarkerBrowserPage.cc | 13 ++-- src/rdb/rdb/gsiDeclRdb.cc | 11 +-- src/rdb/rdb/rdb.cc | 75 +++++++++++--------- src/rdb/rdb/rdb.h | 39 +++++----- src/rdb/rdb/rdbFile.cc | 2 - src/tl/tl/tlResources.cc | 2 +- src/tl/tl/tlResources.h | 4 +- src/tl/tl/tlStream.cc | 94 ++++++++++++++++++------- src/tl/tl/tlStream.h | 10 +++ src/unit_tests/unit_test_main.cc | 8 +++ testdata/buddies/buddies.rb | 2 +- testdata/ruby/dbGlyphs.rb | 2 +- 13 files changed, 173 insertions(+), 92 deletions(-) diff --git a/src/buddies/unit_tests/buddies_main.cc b/src/buddies/unit_tests/buddies_main.cc index a8bbd4e25..1f26d86f8 100644 --- a/src/buddies/unit_tests/buddies_main.cc +++ b/src/buddies/unit_tests/buddies_main.cc @@ -28,9 +28,8 @@ #include "rba.h" #include "gsiDecl.h" -// On Windows, ruby.h is not compatible with windows.h which is included by utHead - at least not if -// windows.h is included before ruby.h ... #include "tlUnitTest.h" +#include "tlFileUtils.h" void run_rubytest (tl::TestBase * /*_this*/, const std::string &fn) { diff --git a/src/layui/layui/rdbMarkerBrowserPage.cc b/src/layui/layui/rdbMarkerBrowserPage.cc index 52bd2b58a..a5d93ce50 100644 --- a/src/layui/layui/rdbMarkerBrowserPage.cc +++ b/src/layui/layui/rdbMarkerBrowserPage.cc @@ -2001,9 +2001,10 @@ MarkerBrowserPage::update_info_text () info += ""; - if (item->image () != 0) { + QImage image = item->image (); + if (! image.isNull ()) { info += "

Snapshot image
(click to enlarge)

"; - info_text->set_image (*item->image ()); + info_text->set_image (image); } } @@ -2802,7 +2803,7 @@ MarkerBrowserPage::remove_snapshot_button_clicked () if (selected_item->column () == 0) { const rdb::Item *i = list_model->item (selected_item->row ()); if (i) { - mp_database->set_item_image (i, 0); + mp_database->set_item_image (i, QImage ()); } } } @@ -2830,7 +2831,7 @@ MarkerBrowserPage::snapshot_button_clicked () const rdb::Item *i = list_model->item (selected_item->row ()); if (i) { - mp_database->set_item_image (i, new QImage (mp_view->get_screenshot ())); + mp_database->set_item_image (i, QImage (mp_view->get_screenshot ())); markers_list->selectionModel ()->setCurrentIndex (*selected_item, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); update_info_text (); @@ -3125,8 +3126,8 @@ MarkerBrowserPage::info_anchor_clicked (const QUrl &link) QModelIndex current = markers_list->selectionModel ()->currentIndex (); const rdb::Item *i = list_model->item (current.row ()); - if (i && i->image () != 0) { - MarkerBrowserSnapshotView *snapshot_view = new MarkerBrowserSnapshotView (this, *i->image ()); + if (i && i->has_image ()) { + MarkerBrowserSnapshotView *snapshot_view = new MarkerBrowserSnapshotView (this, i->image ()); snapshot_view->exec (); delete snapshot_view; #if QT_VERSION < 0x040300 diff --git a/src/rdb/rdb/gsiDeclRdb.cc b/src/rdb/rdb/gsiDeclRdb.cc index 1a410e670..838e0bc19 100644 --- a/src/rdb/rdb/gsiDeclRdb.cc +++ b/src/rdb/rdb/gsiDeclRdb.cc @@ -808,16 +808,19 @@ Class decl_RdbItem ("rdb", "RdbItem", "@brief Sets the tags from a string\n" "@param tags A comma-separated list of tags\n" ) + -#if defined(HAVE_QT) - gsi::method ("image_str", &rdb::Item::image_str, + gsi::method ("has_image?", &rdb::Item::has_image, + "@brief Gets a value indicating that the item has an image attached\n" + "See \\image_str how to obtain the image.\n\n" + "This method has been introduced in version 0.28.\n" + ) + + gsi::method ("image_str", &rdb::Item::image_str, "@brief Gets the image associated with this item as a string\n" - "@return A base64-encoded image file (usually in PNG format)\n" + "@return A base64-encoded image file (in PNG format)\n" ) + gsi::method ("image_str=", &rdb::Item::set_image_str, gsi::arg ("image"), "@brief Sets the image from a string\n" "@param image A base64-encoded image file (preferably in PNG format)\n" ) + -#endif /* Not supported yet: gsi::method ("multiplicity", &rdb::Item::multiplicity, "@brief Gets the item's multiplicity\n" diff --git a/src/rdb/rdb/rdb.cc b/src/rdb/rdb/rdb.cc index 1187bbb27..013cefe7f 100644 --- a/src/rdb/rdb/rdb.cc +++ b/src/rdb/rdb/rdb.cc @@ -821,15 +821,7 @@ Item &Item::operator= (const Item &d) m_visited = d.m_visited; m_multiplicity = d.m_multiplicity; m_tag_ids = d.m_tag_ids; - -#if defined(HAVE_QT) - if (mp_image.get ()) { - mp_image.reset (0); - } - if (d.mp_image.get ()) { - mp_image.reset (new QImage (*d.mp_image)); - } -#endif + m_image_str = d.m_image_str; } return *this; @@ -952,48 +944,60 @@ Item::set_tag_str (const std::string &tags) #if defined(HAVE_QT) void -Item::set_image (QImage *image) +Item::set_image (const QImage &image) { - mp_image.reset (image); -} + if (image.isNull ()) { + + m_image_str.clear (); -std::string -Item::image_str () const -{ - if (! mp_image.get ()) { - return std::string (); } else { QByteArray img_data; QBuffer img_io_device (&img_data); - mp_image->save (&img_io_device, "PNG"); + image.save (&img_io_device, "PNG"); - return std::string (img_data.toBase64 ().constData ()); + m_image_str = std::string (img_data.toBase64 ().constData ()); } } -void -Item::set_image_str (const std::string &s) +const QImage +Item::image () const { - if (s.empty ()) { - set_image (0); + if (m_image_str.empty ()) { + + return QImage (); + } else { - QByteArray img_data (QByteArray::fromBase64 (QByteArray::fromRawData (s.c_str (), int (s.size ())))); + QByteArray img_data (QByteArray::fromBase64 (QByteArray::fromRawData (m_image_str.c_str (), int (m_image_str.size ())))); - QImage *image = new QImage (); - if (image->loadFromData (img_data)) { - set_image (image); - } else { - delete image; - set_image (0); - } + QImage image; + image.loadFromData (img_data); + return image; } } #endif +bool +Item::has_image () const +{ + return !m_image_str.empty (); +} + +std::string +Item::image_str () const +{ + return m_image_str; +} + +void +Item::set_image_str (const std::string &s) +{ + m_image_str = s; +} + // ------------------------------------------------------------------------------------------ // Database implementation @@ -1324,13 +1328,20 @@ Database::remove_item_tag (const Item *item, id_type tag) #if defined(HAVE_QT) void -Database::set_item_image (const Item *item, QImage *image) +Database::set_item_image (const Item *item, const QImage &image) { set_modified (); const_cast (item)->set_image (image); } #endif +void +Database::set_item_image_str (const Item *item, const std::string &image_str) +{ + set_modified (); + const_cast (item)->set_image_str (image_str); +} + void Database::set_item_multiplicity (const Item *item, size_t n) { diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index f62637142..a8c513ab9 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -941,35 +941,37 @@ public: #if defined(HAVE_QT) /** - * @brief Get the image object attached to this item + * @brief Gets the image object attached to this item * - * @return The image object or 0 if no object is attached + * @return The image object or an empty image if no image is attached */ - const QImage *image () const - { - return mp_image.get (); - } + const QImage image () const; /** - * @brief Set an image for this item - * - * The image object will become owned by the item + * @brief Set the image for this item */ - void set_image (QImage *image); + void set_image (const QImage &image); +#endif /** - * @brief Get an image as a string (base64 coded) + * @brief Gets a value indicating whether the item has an image + */ + bool has_image () const; + + /** + * @brief Gets the image as a string (PNG, base64 coded) + * + * Note: if neither PNG support for Qt are compiled in, this string will be empty */ std::string image_str () const; /** - * @brief Get an image from a string (base64 coded) + * @brief Gets the image from a string (PNG, base64 coded) * * If the image string is empty, the image will be cleared. * If the image string is not valid, the image will also be cleared. */ void set_image_str (const std::string &s); -#endif /** * @brief Get the database reference @@ -998,9 +1000,7 @@ private: bool m_visited; std::vector m_tag_ids; Database *mp_database; -#if defined(HAVE_QT) - std::unique_ptr mp_image; -#endif + std::string m_image_str; Item (); @@ -2226,9 +2226,14 @@ public: /** * @brief Set the image of an item */ - void set_item_image (const Item *item, QImage *image); + void set_item_image (const Item *item, const QImage &image); #endif + /** + * @brief Set the image string of an item + */ + void set_item_image_str (const Item *item, const std::string &image_str); + /** * @brief Set the multiplicity of an item */ diff --git a/src/rdb/rdb/rdbFile.cc b/src/rdb/rdb/rdbFile.cc index 82ad16dc8..8006be4d5 100644 --- a/src/rdb/rdb/rdbFile.cc +++ b/src/rdb/rdb/rdbFile.cc @@ -106,9 +106,7 @@ make_rdb_structure (rdb::Database *rdb) tl::make_member (&rdb::Item::cell_qname, &rdb::Item::set_cell_qname, "cell") + tl::make_member (&rdb::Item::visited, &rdb::Item::set_visited, "visited") + tl::make_member (&rdb::Item::multiplicity, &rdb::Item::set_multiplicity, "multiplicity") + -#if defined(HAVE_QT) tl::make_member (&rdb::Item::image_str, &rdb::Item::set_image_str, "image") + -#endif tl::make_element (&rdb::Item::values, &rdb::Item::set_values, "values", tl::make_member (&rdb::Values::begin, &rdb::Values::end, &rdb::Values::add, "value", ValueConverter (rdb)) ) diff --git a/src/tl/tl/tlResources.cc b/src/tl/tl/tlResources.cc index c37cb4e5d..f158eda62 100644 --- a/src/tl/tl/tlResources.cc +++ b/src/tl/tl/tlResources.cc @@ -146,7 +146,7 @@ tl::InputStream *get_resource (const char *name) } else { auto stream = new tl::InputStream (rr.first); if (rr.second) { - stream->inflate (); + stream->inflate_always (); } return stream; } diff --git a/src/tl/tl/tlResources.h b/src/tl/tl/tlResources.h index 699e2089b..2c88e8644 100644 --- a/src/tl/tl/tlResources.h +++ b/src/tl/tl/tlResources.h @@ -81,8 +81,8 @@ TL_PUBLIC std::pair get_resource_reader (const char /** * @brief Get resource names matching a glob pattern * - * For example, find_resources("/group/*") will find resources below "group". - * "*" also matches "/", so resources from subgroups will be listed too. + * For example, find_resources("/group*") will find resources whose name start with "group". + * "*" also matches "/"! */ TL_PUBLIC std::vector find_resources (const std::string &pattern); diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 92077af57..80fa4ef1a 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -143,8 +143,39 @@ public: // --------------------------------------------------------------- // InputStream implementation +namespace { + +/** + * @brief A dummy delegate to provide for the case of raw data stashed inside the stream itself + */ +class RawDataDelegate + : public InputStreamBase +{ +public: + RawDataDelegate (const std::string &source) + : m_source (source) + { } + + virtual size_t read (char *, size_t) + { + return 0; + } + + virtual void reset () { } + virtual void close () { } + + virtual std::string source () const { return m_source; } + virtual std::string absolute_path () const { return m_source; } + virtual std::string filename () const { return m_source; } + +public: + std::string m_source; +}; + +} + InputStream::InputStream (InputStreamBase &delegate) - : m_pos (0), mp_bptr (0), mp_delegate (&delegate), m_owns_delegate (false), mp_inflate (0) + : m_pos (0), mp_bptr (0), mp_delegate (&delegate), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false) { m_bcap = 4096; // initial buffer capacity m_blen = 0; @@ -152,7 +183,7 @@ InputStream::InputStream (InputStreamBase &delegate) } InputStream::InputStream (InputStreamBase *delegate) - : m_pos (0), mp_bptr (0), mp_delegate (delegate), m_owns_delegate (true), mp_inflate (0) + : m_pos (0), mp_bptr (0), mp_delegate (delegate), m_owns_delegate (true), mp_inflate (0), m_inflate_always (false) { m_bcap = 4096; // initial buffer capacity m_blen = 0; @@ -160,7 +191,7 @@ InputStream::InputStream (InputStreamBase *delegate) } InputStream::InputStream (const std::string &abstract_path) - : m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0) + : m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false) { m_bcap = 4096; // initial buffer capacity m_blen = 0; @@ -175,28 +206,30 @@ InputStream::InputStream (const std::string &abstract_path) #if defined(HAVE_QT) QResource res (tl::to_qstring (abstract_path)); - if (res.size () > 0) { - - QByteArray data; -#if QT_VERSION >= 0x60000 - if (res.compressionAlgorithm () == QResource::ZlibCompression) { -#else - if (res.isCompressed ()) { -#endif - data = qUncompress ((const unsigned char *)res.data (), (int)res.size ()); - } else { - data = QByteArray ((const char *)res.data (), (int)res.size ()); - } - - mp_buffer = new char[data.size ()]; - memcpy (mp_buffer, data.constData (), data.size ()); - - mp_bptr = mp_buffer; - m_bcap = data.size (); - m_blen = m_bcap; - + if (res.size () == 0) { + throw tl::Exception (tl::to_string (tr ("Resource not found: ")) + abstract_path); } + QByteArray data; +#if QT_VERSION >= 0x60000 + if (res.compressionAlgorithm () == QResource::ZlibCompression) { +#else + if (res.isCompressed ()) { +#endif + data = qUncompress ((const unsigned char *)res.data (), (int)res.size ()); + } else { + data = QByteArray ((const char *)res.data (), (int)res.size ()); + } + + mp_buffer = new char[data.size ()]; + memcpy (mp_buffer, data.constData (), data.size ()); + + mp_bptr = mp_buffer; + m_bcap = data.size (); + m_blen = m_bcap; + + mp_delegate = new RawDataDelegate (abstract_path); + #else std::pair rr = tl::get_resource_reader (ex.get ()); @@ -240,7 +273,7 @@ InputStream::InputStream (const std::string &abstract_path) m_owns_delegate = true; if (needs_inflate) { - inflate (); + inflate_always (); } } @@ -441,6 +474,13 @@ InputStream::inflate () mp_inflate = new tl::InflateFilter (*this); } +void +InputStream::inflate_always () +{ + m_inflate_always = true; + reset (); +} + void InputStream::close () { @@ -468,6 +508,8 @@ InputStream::reset () } else { + tl_assert (mp_delegate != 0); + mp_delegate->reset (); m_pos = 0; @@ -481,6 +523,10 @@ InputStream::reset () mp_buffer = new char [m_bcap]; } + + if (m_inflate_always) { + inflate (); + } } // --------------------------------------------------------------- diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index 0747a4b7e..9cd53a983 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -466,6 +466,15 @@ public: */ void inflate (); + /** + * @brief Enables "inflate" right from the beginning + * + * Contrary to "inflate" (which is temporary), this version enables + * decompression right from the beginning of the file. It does a "reset" + * implicitly. + */ + void inflate_always (); + /** * @brief Obtain the current file position */ @@ -557,6 +566,7 @@ private: // inflate support InflateFilter *mp_inflate; + bool m_inflate_always; // No copying currently InputStream (const InputStream &); diff --git a/src/unit_tests/unit_test_main.cc b/src/unit_tests/unit_test_main.cc index 4bc19ed7f..0f66e0952 100644 --- a/src/unit_tests/unit_test_main.cc +++ b/src/unit_tests/unit_test_main.cc @@ -607,6 +607,14 @@ main_cont (int &argc, char **argv) tl::set_continue_flag (continue_flag); tl::set_debug_mode (debug_mode); + // set some global variables + if (rba::RubyInterpreter::instance ()) { + rba::RubyInterpreter::instance ()->define_variable ("ut_inst_path", tl::get_inst_path ()); + } + if (pya::PythonInterpreter::instance ()) { + pya::PythonInterpreter::instance ()->define_variable ("ut_inst_path", tl::get_inst_path ()); + } + FILE *output_file = 0; try { diff --git a/testdata/buddies/buddies.rb b/testdata/buddies/buddies.rb index 7658e6007..0864169cd 100644 --- a/testdata/buddies/buddies.rb +++ b/testdata/buddies/buddies.rb @@ -32,7 +32,7 @@ load("test_prologue.rb") class Buddies_TestClass < TestBase def buddy_bin(name) - file = File.join(RBA::Application::instance.inst_path, name) + file = File.join($ut_inst_path, name) return file end diff --git a/testdata/ruby/dbGlyphs.rb b/testdata/ruby/dbGlyphs.rb index c7b5792c8..75bb1e3f2 100644 --- a/testdata/ruby/dbGlyphs.rb +++ b/testdata/ruby/dbGlyphs.rb @@ -69,7 +69,7 @@ class DBGlyph_TestClass < TestBase tg.load_from_resource(":/fonts/does_not_exist.gds") assert_equal(false, true) rescue => ex - assert_equal(ex.to_s, "Unable to load font resource from :/fonts/does_not_exist.gds in TextGenerator::load_from_resource") + assert_equal(ex.to_s, "Resource not found: :/fonts/does_not_exist.gds in TextGenerator::load_from_resource") end end From 68f05bf0693ffe9404758e14fbcc4f4b64f48725 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 10:14:29 +0200 Subject: [PATCH 20/45] Added missing file --- src/layview/layview/gsiDeclLayAdditional.cc | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/layview/layview/gsiDeclLayAdditional.cc diff --git a/src/layview/layview/gsiDeclLayAdditional.cc b/src/layview/layview/gsiDeclLayAdditional.cc new file mode 100644 index 000000000..06bc9116c --- /dev/null +++ b/src/layview/layview/gsiDeclLayAdditional.cc @@ -0,0 +1,81 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 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 "gsiSignals.h" +#include "layLayoutView.h" +#include "laybasicCommon.h" + +namespace gsi +{ + +static lay::CellViewRef get_active_cellview_ref () +{ + lay::LayoutView *view = lay::LayoutView::current (); + if (! view) { + return lay::CellViewRef (); + } + if (view->active_cellview_index () >= 0) { + return view->active_cellview_ref (); + } else { + return lay::CellViewRef (); + } +} + +static lay::LayoutView *get_view (lay::CellViewRef *cv) +{ + return cv->view ()->ui (); +} + +static ClassExt extdecl_CellView ( + method ("active", &get_active_cellview_ref, + "@brief Gets the active CellView\n" + "The active CellView is the one that is selected in the current layout view. This method is " + "equivalent to\n" + "@code\n" + "RBA::LayoutView::current.active_cellview\n" + "@/code\n" + "If no CellView is active, this method returns nil.\n" + "\n" + "This method has been introduced in version 0.23." + ) + + method_ext ("view", &get_view, + "@brief Gets the view the cellview resides in\n" + "This reference will be nil if the cellview is not a valid one.\n" + "This method has been added in version 0.25.\n" + ) +); + +static lay::LayoutView *get_view_from_lp (lay::LayerPropertiesNode *node) +{ + return node->view ()->ui (); +} + +static ClassExt extdecl_LayerPropertiesNode ( + method_ext ("view", &get_view_from_lp, + "@brief Gets the view this node lives in\n" + "\n" + "This reference can be nil if the node is a orphan node that lives outside a view." + ) +); + +} From 1d8db227e52960400e98d6e8cb3e4c5a3bef6ce7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 11:41:40 +0200 Subject: [PATCH 21/45] Minor code enhancements --- src/layview/layview/layLayoutView_noqt.cc | 5 +++++ src/layview/layview/layLayoutView_noqt.h | 5 +++++ testdata/ruby/rdbTest.rb | 14 ++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/layview/layview/layLayoutView_noqt.cc b/src/layview/layview/layLayoutView_noqt.cc index da85aab88..9b80e44ee 100644 --- a/src/layview/layview/layLayoutView_noqt.cc +++ b/src/layview/layview/layLayoutView_noqt.cc @@ -71,6 +71,11 @@ void LayoutView::set_current (LayoutView *view) s_current_view.reset (view); } +void LayoutView::set_current () +{ + s_current_view.reset (this); +} + } // namespace lay #endif diff --git a/src/layview/layview/layLayoutView_noqt.h b/src/layview/layview/layLayoutView_noqt.h index 959748bbb..9578aa2c0 100644 --- a/src/layview/layview/layLayoutView_noqt.h +++ b/src/layview/layview/layLayoutView_noqt.h @@ -66,6 +66,11 @@ public: */ void timer (); + /** + * @brief Makes this view the current one + */ + void set_current (); + /** * @brief Gets the current view */ diff --git a/testdata/ruby/rdbTest.rb b/testdata/ruby/rdbTest.rb index 9e3f06f32..1bdaca1fd 100644 --- a/testdata/ruby/rdbTest.rb +++ b/testdata/ruby/rdbTest.rb @@ -422,12 +422,14 @@ class RDB_TestClass < TestBase assert_equal(item.has_tag?(db.tag_id("x1")), false) assert_equal(item.tags_str, "") - if item.respond_to?(:image_str) - is="iVBORw0KGgoAAAANSUhEUgAAACoAAAA0CAIAAABzfT3nAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAA0SAAANOgHo3ZneAAAA3UlEQVRYhe2WwQ3DIAxFoco8XaGZIaeO43FyYgZYgYXcQ6SWuDGgBhWq/qccIvGCEd9SbAwAAPSGaW2lFR2rfWDpXrPpSe2SP10fvnn/PZHZH9IwbKFVZZ/Z6wMtZcjW02Bn2FVpZYdWdkr2nvh23S2FyDNJuVITpwmRjTGbNr0v20U5byNtJuuJt/fO2f93+UlbEJl5UjVPr3Y71EQ/PoPPlU+lDJtWlCt3GwCMG33BuJGAcWMEMG6c1jBudCyf/nzV8nbZPRohclFLHdGbZ8eNSjN1fmf0AACA1jwA4hKxu4C6P7EAAAAASUVORK5CYII=" - item.image_str=is - # Only the first 30 bytes count ... the remaining part is too different for different versions of Qt - assert_equal(item.image_str[0..30], is[0..30]) - end + assert_equal(item.image_str, "") + assert_equal(item.has_image?, false) + + # can actually by any string, but only base64-encoded PNG images make sense + is="iVBORw0KGgoAAAANSUhEUgAAACoAAAA0CAIAAABzfT3nAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAA0SAAANOgHo3ZneAAAA3UlEQVRYhe2WwQ3DIAxFoco8XaGZIaeO43FyYgZYgYXcQ6SWuDGgBhWq/qccIvGCEd9SbAwAAPSGaW2lFR2rfWDpXrPpSe2SP10fvnn/PZHZH9IwbKFVZZ/Z6wMtZcjW02Bn2FVpZYdWdkr2nvh23S2FyDNJuVITpwmRjTGbNr0v20U5byNtJuuJt/fO2f93+UlbEJl5UjVPr3Y71EQ/PoPPlU+lDJtWlCt3GwCMG33BuJGAcWMEMG6c1jBudCyf/nzV8nbZPRohclFLHdGbZ8eNSjN1fmf0AACA1jwA4hKxu4C6P7EAAAAASUVORK5CYII=" + item.image_str=is + assert_equal(item.image_str, is) + assert_equal(item.has_image?, true) vs = RBA::RdbItemValue.new("a string") vs2 = RBA::RdbItemValue.new("a string (ii)") From e231f2b987dbf58a35628cc289474b3d10e44c16 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 13:25:50 +0200 Subject: [PATCH 22/45] Must not use tl::to_string on quoted strings --- src/img/img/imgObject.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/img/img/imgObject.cc b/src/img/img/imgObject.cc index e2912b2d1..4719fb7f7 100644 --- a/src/img/img/imgObject.cc +++ b/src/img/img/imgObject.cc @@ -1702,7 +1702,7 @@ Object::read_file () } #else - throw tl::Exception (tl::to_string ("No PNG support compiled in - cannot load PNG files")); + throw tl::Exception ("No PNG support compiled in - cannot load PNG files"); #endif } From 40eb3aaebe0c8f1b676c35a6395f667fff8fbe68 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 14:16:44 +0200 Subject: [PATCH 23/45] Enabling input files in batch mode, fixed a segfault during tests --- src/lay/lay/layApplication.cc | 115 +++++++++++++++++---- src/lay/lay/layApplication.h | 7 ++ src/lay/lay/layMainWindow.cc | 34 +----- src/lay/lay/layMainWindow.h | 7 -- src/laybasic/laybasic/layLayoutViewBase.cc | 42 +++++++- src/laybasic/laybasic/layLayoutViewBase.h | 8 ++ src/laybasic/laybasic/layViewObject.cc | 27 +++-- src/laybasic/laybasic/layViewObject.h | 7 ++ src/layview/layview/layLayoutView_qt.cc | 11 +- 9 files changed, 184 insertions(+), 74 deletions(-) diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 1ed3c8285..60c3d572b 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1091,6 +1091,10 @@ ApplicationBase::run () // Run plugin and macro specific initializations autorun (); + // Some objects we need during batch mode view generation + db::Manager batch_mode_manager; + tl::shared_ptr batch_mode_view; + if (mw) { for (std::vector > >::const_iterator f = m_files.begin (); f != m_files.end (); ++f) { @@ -1141,11 +1145,7 @@ ApplicationBase::run () if (! m_layer_props_file.empty ()) { - if (m_lyp_map_all_cvs && mw->is_single_cv_layer_properties_file (m_layer_props_file)) { - mw->load_layer_properties (m_layer_props_file, -1, true /*all views*/, m_lyp_add_default); - } else { - mw->load_layer_properties (m_layer_props_file, true /*all views*/, m_lyp_add_default); - } + mw->load_layer_properties (m_layer_props_file, true /*all views*/, m_lyp_add_default); tl::log << "Layer properties loaded '" << m_layer_props_file << "'"; @@ -1165,25 +1165,79 @@ ApplicationBase::run () player.replay (m_gtf_replay_rate, m_gtf_replay_stop); } - // Give the plugins a change to do some last-minute initialisation and checks - for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { - lay::PluginDeclaration *pd = const_cast (&*cls); - pd->initialized (dispatcher ()); - } - - if (! m_no_gui && m_gtf_replay.empty () && m_gtf_record.empty ()) { - // Show initial tip window if required - mw->about_to_exec (); - } - - } else if (dispatcher ()) { - - // Give the plugins a change to do some last-minute initialisation and checks + } else { + + // in batch mode create at least one + + for (std::vector > >::const_iterator f = m_files.begin (); f != m_files.end (); ++f) { + + if (f->first == layout_file || f->first == layout_file_with_tech) { + + std::string filename = f->second.first; + + if (batch_mode_view.get () != 0 && ! m_same_view) { + tl::warn << tl::sprintf (tl::to_string (tr ("Ignoring additional views in batch mode (file %s)")), filename); + continue; + } + + if (! batch_mode_view) { + batch_mode_view.reset (create_view (batch_mode_manager)); + } + + if (f->first != layout_file_with_tech) { + batch_mode_view->load_layout (f->second.first, true); + } else { + batch_mode_view->load_layout (f->second.first, f->second.second, true); + } + + // Make the first one loaded the active one. + batch_mode_view->set_active_cellview_index (0); + + } else if (f->first == rdb_file) { + + if (! batch_mode_view) { + batch_mode_view.reset (create_view (batch_mode_manager)); + } + + std::unique_ptr db (new rdb::Database ()); + db->load (f->second.first); + batch_mode_view->add_rdb (db.release ()); + + } else if (f->first == l2ndb_file) { + + if (! batch_mode_view) { + batch_mode_view.reset (create_view (batch_mode_manager)); + } + + batch_mode_view->add_l2ndb (db::LayoutToNetlist::create_from_file (f->second.first)); + + } + } + + if (! m_layer_props_file.empty () && batch_mode_view.get ()) { + + batch_mode_view->load_layer_props (m_layer_props_file, m_lyp_add_default); + + tl::log << "Layer properties loaded '" << m_layer_props_file << "'"; + + // because the layer may carry transformations, we need to refit the cellviews. + batch_mode_view->zoom_fit (); + + } + + } + + // Give the plugins a change to do some last-minute initialisation and checks + if (dispatcher ()) { for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { lay::PluginDeclaration *pd = const_cast (&*cls); pd->initialized (dispatcher ()); } + } + if (mw && ! m_no_gui && m_gtf_replay.empty () && m_gtf_record.empty ()) { + // Show initial tip window if required + mw->about_to_exec (); } if (! m_run_macro.empty ()) { @@ -1200,9 +1254,29 @@ ApplicationBase::run () finish (); + batch_mode_view.reset (0); + return result; } +lay::LayoutView * +ApplicationBase::create_view (db::Manager &manager) +{ + // create a new view + lay::LayoutView *view = new lay::LayoutView (&manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), 0 /*parent*/); + + // set initial attributes + view->set_synchronous (m_sync_mode); + + int tl = 0; + dispatcher ()->config_get (cfg_initial_hier_depth, tl); + view->set_hier_levels (std::make_pair (0, tl)); + + view->set_current (); + + return view; +} + void ApplicationBase::autorun () { @@ -1250,7 +1324,8 @@ dump_children (QObject *obj, int level = 0) void ApplicationBase::process_events_impl (QEventLoop::ProcessEventsFlags /*flags*/, bool /*silent*/) { - // The base class implementation does nothing .. + // in the non-UI case there are no events, but we can at least schedule deferred method calls. + tl::DeferredMethodScheduler::execute (); } bool diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 887fc42c5..b821cc7a0 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -54,6 +54,11 @@ namespace lym class MacroCollection; } +namespace db +{ + class Manager; +} + namespace lay { @@ -61,6 +66,7 @@ class MainWindow; class Dispatcher; class ProgressReporter; class ProgressBar; +class LayoutView; /** * @brief The application base class @@ -324,6 +330,7 @@ protected: private: std::vector scan_global_modules (); + lay::LayoutView *create_view (db::Manager &manager); enum file_type { layout_file, diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index a7e412abc..c9abd8ddc 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -1985,38 +1985,6 @@ MainWindow::load_layer_properties (const std::string &fn, int cv_index, bool all } } -bool -MainWindow::is_single_cv_layer_properties_file (const std::string &fn) -{ - // If the file contains information for a single layout but we have multiple ones, - // show the dialog to determine what layout to apply the information to. - std::vector props; - try { - tl::XMLFileSource in (fn); - props.push_back (lay::LayerPropertiesList ()); - props.back ().load (in); - } catch (...) { - props.clear (); - tl::XMLFileSource in (fn); - lay::LayerPropertiesList::load (in, props); - } - - // Collect all cv indices in the layer properties - std::set cv; - for (std::vector::const_iterator p = props.begin (); p != props.end (); ++p) { - for (lay::LayerPropertiesConstIterator lp = p->begin_const_recursive (); ! lp.at_end (); ++lp) { - if (! lp->has_children ()) { - cv.insert (lp->source (true).cv_index ()); - if (cv.size () >= 2) { - break; - } - } - } - } - - return (cv.size () == 1); -} - void MainWindow::cm_save_layer_props () { @@ -2054,7 +2022,7 @@ MainWindow::load_layer_props_from_file (const std::string &fn) int target_cv_index = -2; - if (current_view ()->cellviews () > 1 && is_single_cv_layer_properties_file (fn)) { + if (current_view ()->cellviews () > 1 && lay::LayoutView::is_single_cv_layer_properties_file (fn)) { QStringList items; items << QString (QObject::tr ("Take it as it is")); diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h index 8c40b7250..434edf347 100644 --- a/src/lay/lay/layMainWindow.h +++ b/src/lay/lay/layMainWindow.h @@ -239,13 +239,6 @@ public: */ void clone_current_view (); - /** - * @brief Determine whether a given layer properties file is a single-layout file - * - * @return True, if the file contains definitions of a single layout only. - */ - bool is_single_cv_layer_properties_file (const std::string &fn); - /** * @brief Load a layer definition file * diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index 75b3fe78e..665a9f075 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -408,7 +408,8 @@ LayoutViewBase::init (db::Manager *mgr) create_plugins (); } -LayoutViewBase::~LayoutViewBase () +void +LayoutViewBase::shutdown () { // detach all observers // This is to prevent signals to partially destroyed observers that own a LayoutViewBase @@ -457,10 +458,15 @@ LayoutViewBase::~LayoutViewBase () delete *p; } - // detach from the manager, so we can safely delete the manager + // detach from the manager, so we can safely delete the manager manager (0); stop (); +} + +LayoutViewBase::~LayoutViewBase () +{ + shutdown (); // because LayoutViewBase and LayoutCanvas both control lifetimes of // ruler objects for example, it is safer to explicitly delete the @@ -2287,6 +2293,38 @@ LayoutViewBase::bookmark_view (const std::string &name) bookmarks_changed (); } +bool +LayoutViewBase::is_single_cv_layer_properties_file (const std::string &fn) +{ + // If the file contains information for a single layout but we have multiple ones, + // show the dialog to determine what layout to apply the information to. + std::vector props; + try { + tl::XMLFileSource in (fn); + props.push_back (lay::LayerPropertiesList ()); + props.back ().load (in); + } catch (...) { + props.clear (); + tl::XMLFileSource in (fn); + lay::LayerPropertiesList::load (in, props); + } + + // Collect all cv indices in the layer properties + std::set cv; + for (std::vector::const_iterator p = props.begin (); p != props.end (); ++p) { + for (lay::LayerPropertiesConstIterator lp = p->begin_const_recursive (); ! lp.at_end (); ++lp) { + if (! lp->has_children ()) { + cv.insert (lp->source (true).cv_index ()); + if (cv.size () >= 2) { + break; + } + } + } + } + + return (cv.size () == 1); +} + void LayoutViewBase::load_layer_props (const std::string &fn) { diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index 81379af57..fadf48bb2 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -799,6 +799,13 @@ public: */ void load_layer_props (const std::string &fn, int cv_index, bool add_default); + /** + * @brief Determine whether a given layer properties file is a single-layout file + * + * @return True, if the file contains definitions of a single layout only. + */ + static bool is_single_cv_layer_properties_file (const std::string &fn); + /** * @brief Bookmark the current view under the given name */ @@ -2836,6 +2843,7 @@ protected: virtual void create_plugins (const lay::PluginDeclaration *except_this = 0); void free_resources (); + void shutdown (); virtual lay::Color default_background_color (); virtual void do_set_background_color (lay::Color color, lay::Color contrast); diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index 3fc597c20..d782656a9 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -488,7 +488,8 @@ private: // ViewObjectWidget implementation ViewObjectUI::ViewObjectUI () - : m_view_objects_dismissed (false), + : mp_widget (0), + m_view_objects_dismissed (false), m_needs_update_static (false), m_needs_update_bg (false), mp_active_service (0), @@ -502,16 +503,6 @@ ViewObjectUI::ViewObjectUI () m_widget_height (0), m_image_updated (false) { -#if defined(HAVE_QT) - if (lay::has_gui ()) { - mp_widget = new ViewObjectQWidget (this); - mp_widget->setMouseTracking (true); - mp_widget->setAcceptDrops (true); - } else { - mp_widget = 0; - } -#endif - m_objects.changed ().add (this, &ViewObjectUI::objects_changed); } @@ -527,6 +518,20 @@ ViewObjectUI::~ViewObjectUI () } } +#if defined(HAVE_QT) +void +ViewObjectUI::init_ui (QWidget *parent) +{ + // we rely on the parent to delete the UI widget + tl_assert (parent != 0); + tl_assert (mp_widget == 0); + + mp_widget = new ViewObjectQWidget (this); + mp_widget->setMouseTracking (true); + mp_widget->setAcceptDrops (true); +} +#endif + void ViewObjectUI::register_service (lay::ViewService *svc) { diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index 242558d00..7f3e14694 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -589,6 +589,13 @@ public: */ ~ViewObjectUI (); +#if defined(HAVE_QT) + /** + * @brief Initializes the UI components + */ + void init_ui (QWidget *parent); +#endif + /** * @brief Cancel all drag operations */ diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc index 4a431e518..4727fedf3 100644 --- a/src/layview/layview/layLayoutView_qt.cc +++ b/src/layview/layview/layLayoutView_qt.cc @@ -289,7 +289,8 @@ LayoutView::init_ui (QWidget *parent, const char *name) mp_widget = new LayoutViewFrame (parent, this); mp_widget->setObjectName (QString::fromUtf8 (name)); - canvas ()->widget ()->setParent (mp_widget); + + canvas ()->init_ui (mp_widget); mp_connector = new LayoutViewSignalConnector (mp_widget, this); @@ -415,6 +416,9 @@ LayoutView::~LayoutView () ms_current = 0; } + // release all components and plugins before we delete the user interface + shutdown (); + if (mp_control_frame) { delete mp_control_frame; } @@ -443,6 +447,11 @@ LayoutView::~LayoutView () } mp_bookmarks_frame = 0; mp_bookmarks_view = 0; + + if (mp_widget) { + delete mp_widget; + mp_widget = 0; + } } void From 60393400220b128f687caa75f77f6f9e5604b411 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 14:23:10 +0200 Subject: [PATCH 24/45] Fixed non-Qt build --- src/laybasic/laybasic/layViewObject.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index d782656a9..805e6c69f 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -488,8 +488,7 @@ private: // ViewObjectWidget implementation ViewObjectUI::ViewObjectUI () - : mp_widget (0), - m_view_objects_dismissed (false), + : m_view_objects_dismissed (false), m_needs_update_static (false), m_needs_update_bg (false), mp_active_service (0), @@ -504,6 +503,10 @@ ViewObjectUI::ViewObjectUI () m_image_updated (false) { m_objects.changed ().add (this, &ViewObjectUI::objects_changed); + +#if defined(HAVE_QT) + mp_widget = 0; +#endif } ViewObjectUI::~ViewObjectUI () From 27894420f878cea4412d4cd3b747f40ff9ddcc52 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 14:46:35 +0200 Subject: [PATCH 25/45] Fixed build script (HAVE_PNG option missing) --- build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sh b/build.sh index 6c6c61c9a..c2a7bd11a 100755 --- a/build.sh +++ b/build.sh @@ -630,6 +630,7 @@ qmake_options=( HAVE_QT="$HAVE_QT" HAVE_CURL="$HAVE_CURL" HAVE_EXPAT="$HAVE_EXPAT" + HAVE_PNG="$HAVE_PNG" PREFIX="$BIN" RPATH="$RPATH" KLAYOUT_VERSION="$KLAYOUT_VERSION" From a5d467b51ec55f9d9d300b5fa51e485be7e0b66f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 14:47:22 +0200 Subject: [PATCH 26/45] Dummy change to trigger builds --- src/laybasic/laybasic/layPixelBuffer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/laybasic/laybasic/layPixelBuffer.h b/src/laybasic/laybasic/layPixelBuffer.h index 943d445c0..536896c96 100644 --- a/src/laybasic/laybasic/layPixelBuffer.h +++ b/src/laybasic/laybasic/layPixelBuffer.h @@ -20,7 +20,6 @@ */ - #ifndef HDR_layPixelBuffer #define HDR_layPixelBuffer From a02e9b4d051f4f4c086bb6dc6afc8b101e43518b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 16:53:03 +0200 Subject: [PATCH 27/45] Include lym dependency in lay library --- src/klayout.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/klayout.pro b/src/klayout.pro index 2fac8b69b..ff82db09e 100644 --- a/src/klayout.pro +++ b/src/klayout.pro @@ -106,7 +106,7 @@ equals(HAVE_RUBY, "1") { layui.depends += laybasic layview.depends += layui - lay.depends += ant img edt layui + lay.depends += ant img edt layui lym plugins.depends += lay From f2b91997f02641953e3318ec57d7db57ae12981f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 17:36:54 +0200 Subject: [PATCH 28/45] Don't print Qt warnings for verbosity 0 - this will simplify the application tests --- src/klayout_main/klayout_main/klayout.cc | 29 ++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/klayout_main/klayout_main/klayout.cc b/src/klayout_main/klayout_main/klayout.cc index 1e23482ce..54086adc0 100644 --- a/src/klayout_main/klayout_main/klayout.cc +++ b/src/klayout_main/klayout_main/klayout.cc @@ -154,14 +154,16 @@ main(int a_argc, const char **a_argv) #endif #if QT_VERSION >= 0x050000 -void myMessageOutput(QtMsgType type, const QMessageLogContext & /*ctx*/, const QString &msg) +void custom_message_handler(QtMsgType type, const QMessageLogContext & /*ctx*/, const QString &msg) { switch (type) { case QtDebugMsg: fprintf(stderr, "Debug: %s\n", msg.toLocal8Bit ().constData ()); break; case QtWarningMsg: - fprintf(stderr, "Warning: %s\n", msg.toLocal8Bit ().constData ()); + if (tl::verbosity () > 0) { + fprintf(stderr, "Warning: %s\n", msg.toLocal8Bit ().constData ()); + } break; case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", msg.toLocal8Bit ().constData ()); @@ -175,14 +177,16 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext & /*ctx*/, const Q } } #else -void myMessageOutput(QtMsgType type, const char *msg) +void custom_message_handler(QtMsgType type, const char *msg) { switch (type) { case QtDebugMsg: fprintf(stderr, "Debug: %s\n", msg); break; case QtWarningMsg: - fprintf(stderr, "Warning: %s\n", msg); + if (tl::verbosity () > 0) { + fprintf(stderr, "Warning: %s\n", msg); + } break; case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", msg); @@ -223,7 +227,9 @@ klayout_main (int &argc, char **argv) about_text += prg_about_text; lay::Version::set_about_text (about_text.c_str ()); - // Capture the shortcut command line arguments + // Capture the shortcut command line arguments and the verbosity settings + // for early errors and warnings + for (int i = 1; i < argc; ++i) { if (argv [i] == std::string ("-v")) { @@ -236,6 +242,15 @@ klayout_main (int &argc, char **argv) tl::info << lay::ApplicationBase::usage () << tl::noendl; return 0; + } else if (argv [i] == std::string ("-d") && (i + 1) < argc) { + + int v = 0; + tl::from_string (argv [++i], v); + if (v < 0) { + v = 0; + } + tl::verbosity (v); + } } @@ -255,9 +270,9 @@ int klayout_main_cont (int &argc, char **argv) { #if QT_VERSION >= 0x050000 - qInstallMessageHandler (myMessageOutput); + qInstallMessageHandler (custom_message_handler); #else - qInstallMsgHandler (myMessageOutput); + qInstallMsgHandler (custom_message_handler); #endif int result = 0; From baa92d44553ba498bac64bafddfee7214629a055 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 19:33:30 +0200 Subject: [PATCH 29/45] Fixed non-Qt thread-local storage implementation: needs to reuse holder object when using 'setLocalData' --- src/tl/tl/tlThreads.h | 7 +++++-- src/tl/unit_tests/tlThreadsTests.cc | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tl/tl/tlThreads.h b/src/tl/tl/tlThreads.h index 1f4a7a870..2fbd7204d 100644 --- a/src/tl/tl/tlThreads.h +++ b/src/tl/tl/tlThreads.h @@ -228,7 +228,6 @@ protected: } }; -// TODO: this is the non-threaded dummy implementation template class ThreadStorage : public ThreadStorageBase @@ -253,7 +252,11 @@ public: void setLocalData (const T &data) { - add (new ThreadStorageHolder (new T (data))); + if (hasLocalData ()) { + localData () = data; + } else { + add (new ThreadStorageHolder (new T (data))); + } } }; diff --git a/src/tl/unit_tests/tlThreadsTests.cc b/src/tl/unit_tests/tlThreadsTests.cc index c5a65d4a5..57d2285a9 100644 --- a/src/tl/unit_tests/tlThreadsTests.cc +++ b/src/tl/unit_tests/tlThreadsTests.cc @@ -229,7 +229,7 @@ TEST(3) MyThread3 my_thread; my_thread.start (); // While we start the loop inside the thread we run it outside. Since - // the counter is TLS, both loops will to the same but with different data. + // the counter is TLS, both loops will do the same but with different data. // A mutex is not involved. EXPECT_EQ (my_thread.do_run (9999999), 9999999); my_thread.wait (); From 7748433669b6f1e35b7c8af2db7250410eb7df54 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 20:06:04 +0200 Subject: [PATCH 30/45] Bugfix: use last extension only for macro type determination --- src/lym/lym/lymMacro.cc | 2 +- src/lym/lym/lymMacroCollection.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index 26fbd4708..5fc10c79b 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -309,7 +309,7 @@ void Macro::load () bool Macro::format_from_suffix (const std::string &fn, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format) { - return format_from_suffix_string (tl::extension (fn), interpreter, dsl_name, autorun_pref, format); + return format_from_suffix_string (tl::extension_last (fn), interpreter, dsl_name, autorun_pref, format); } std::pair diff --git a/src/lym/lym/lymMacroCollection.cc b/src/lym/lym/lymMacroCollection.cc index 7955f7ce4..e0e4dd2ce 100644 --- a/src/lym/lym/lymMacroCollection.cc +++ b/src/lym/lym/lymMacroCollection.cc @@ -417,7 +417,7 @@ void MacroCollection::scan () std::vector files = tl::dir_entries (p, true /*with_files*/, false /*with_dirs*/, true /*without_dotfiles*/); for (auto f = files.begin (); f != files.end (); ++f) { - if (suffixes.find (tl::extension (*f)) != suffixes.end ()) { + if (suffixes.find (tl::extension_last (*f)) != suffixes.end ()) { create_entry (tl::combine_path (p, *f)); } } From b8fa458ad6569a55dd711273466a915d05a00e83 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 May 2022 20:15:56 +0200 Subject: [PATCH 31/45] Small add-on: -rr option for application --- src/lay/lay/layApplication.cc | 19 ++++++++++++++++++- src/lay/lay/layApplication.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 60c3d572b..46b7648f4 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -185,6 +185,7 @@ ApplicationBase::ApplicationBase (bool non_ui_mode) : gsi::ObjectBase (), m_lyp_map_all_cvs (true), m_lyp_add_default (false), + m_run_macro_and_exit (true), m_packages_with_dep (false), m_write_config_file (false), m_gtf_replay_rate (0), @@ -353,8 +354,19 @@ ApplicationBase::parse_cmd (int &argc, char **argv) } else if (a == "-r" && (i + 1) < argc) { + if (! m_run_macro.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Option -r or -rr can only be used once"))); + } m_run_macro = args [++i]; + } else if (a == "-rr" && (i + 1) < argc) { + + if (! m_run_macro.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Option -r or -rr can only be used once"))); + } + m_run_macro = args [++i]; + m_run_macro_and_exit = false; + } else if (a == "-rx") { m_no_macros = true; @@ -998,7 +1010,8 @@ ApplicationBase::usage () r += tl::to_string (QObject::tr (" -nn Technology file (.lyt) to use for next layout(s) on command line")) + "\n"; r += tl::to_string (QObject::tr (" -p Load the plugin (can be used multiple times)")) + "\n"; r += tl::to_string (QObject::tr (" -r