From 1ad9dd2c11ea09ad1dfffbdbc85a2b8a00f9ac8c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 7 May 2022 23:44:08 +0200 Subject: [PATCH] WIP: preparations for a non-Qt event loop protocol --- src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 28 +++++++ src/laybasic/laybasic/gsiDeclLayPlugin.cc | 46 +++++++++++- src/laybasic/laybasic/layCellView.cc | 4 +- src/laybasic/laybasic/layLayoutCanvas.cc | 34 ++++++--- src/laybasic/laybasic/layLayoutCanvas.h | 6 ++ src/laybasic/laybasic/layLayoutView.cc | 20 +++++ src/laybasic/laybasic/layLayoutView.h | 15 ++++ src/laybasic/laybasic/layLayoutViewBase.cc | 3 +- src/laybasic/laybasic/layLayoutViewBase.h | 5 ++ src/laybasic/laybasic/layMove.cc | 10 +-- src/laybasic/laybasic/layViewObject.cc | 45 ++++++++--- src/laybasic/laybasic/layViewObject.h | 75 +++++++++++++++++-- 12 files changed, 252 insertions(+), 39 deletions(-) diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index 10b39367d..5e204847a 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -1593,6 +1593,34 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "Returns an array of \\LayerPropertiesIterator objects pointing to the currently selected layers. " "If no layer view is selected currently, an empty array is returned.\n" ) + +#if !defined(HAVE_QT) + gsi::event ("on_image_updated_event", static_cast (&lay::LayoutView::image_updated_event), + "@brief An event indicating that the image (\"screenshot\") was updated\n" + "\n" + "This event is triggered when calling \\timer." + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_drawing_finished_event", static_cast (&lay::LayoutView::drawing_finished_event), + "@brief An event indicating that the image is fully drawn\n" + "\n" + "This event is triggered when calling \\timer. " + "Before this event is issue, a final \\on_image_updated_event may be issued.\n" + "\n" + "This event has been introduced 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" + "This callback eventually implements the event loop in the non-Qt case. The main task " + "is to indicate new versions of the layout image while it is drawn. " + "When a new image has arrived, this method will issue an \\on_image_updated_event. " + "In the implementation of the latter, \"screenshot\" may be called to retrieve the current image.\n" + "When drawing has finished, the \\on_drawing_finished_event will be triggered.\n" + "\n" + "This method has been introduced in version 0.28." + ) + +#endif gsi::event ("on_active_cellview_changed", static_cast (&lay::LayoutView::active_cellview_changed_event), "@brief An event indicating that the active cellview has changed\n" "\n" diff --git a/src/laybasic/laybasic/gsiDeclLayPlugin.cc b/src/laybasic/laybasic/gsiDeclLayPlugin.cc index d1b1f5d6b..f45415cf9 100644 --- a/src/laybasic/laybasic/gsiDeclLayPlugin.cc +++ b/src/laybasic/laybasic/gsiDeclLayPlugin.cc @@ -912,7 +912,51 @@ Class decl_ButtonState ("lay", "ButtonState", "This class has been introduced in version 0.22.\n" ); -static std::vector +class KeyCodesNamespace { }; + +static int const_KeyEscape() { return (int) lay::KeyEscape; } +static int const_KeyTab() { return (int) lay::KeyTab; } +static int const_KeyBacktab() { return (int) lay::KeyBacktab; } +static int const_KeyBackspace() { return (int) lay::KeyBackspace; } +static int const_KeyReturn() { return (int) lay::KeyReturn; } +static int const_KeyEnter() { return (int) lay::KeyEnter; } +static int const_KeyInsert() { return (int) lay::KeyInsert; } +static int const_KeyDelete() { return (int) lay::KeyDelete; } +static int const_KeyHome() { return (int) lay::KeyHome; } +static int const_KeyEnd() { return (int) lay::KeyEnd; } +static int const_KeyDown() { return (int) lay::KeyDown; } +static int const_KeyUp() { return (int) lay::KeyUp; } +static int const_KeyLeft() { return (int) lay::KeyLeft; } +static int const_KeyRight() { return (int) lay::KeyRight; } +static int const_KeyPageUp() { return (int) lay::KeyPageUp; } +static int const_KeyPageDown() { return (int) lay::KeyPageDown; } + +Class decl_KeyCode ("lay", "KeyCode", + method ("Escape", &const_KeyEscape, "@brief Indicates the Escape key") + + method ("Tab", &const_KeyTab, "@brief Indicates the Tab key") + + method ("Backtab", &const_KeyBacktab, "@brief Indicates the Backtab key") + + method ("Backspace", &const_KeyBackspace, "@brief Indicates the Backspace key") + + method ("Return", &const_KeyReturn, "@brief Indicates the Return key") + + method ("Enter", &const_KeyEnter, "@brief Indicates the Enter key") + + method ("Insert", &const_KeyInsert, "@brief Indicates the Insert key") + + method ("Delete", &const_KeyDelete, "@brief Indicates the Delete key") + + method ("Home", &const_KeyHome, "@brief Indicates the Home key") + + method ("End", &const_KeyEnd, "@brief Indicates the End key") + + method ("Down", &const_KeyDown, "@brief Indicates the Down key") + + method ("Up", &const_KeyUp, "@brief Indicates the Up key") + + method ("Left", &const_KeyLeft, "@brief Indicates the Left key") + + method ("Right", &const_KeyRight, "@brief Indicates the Right key") + + method ("PageUp", &const_KeyPageUp, "@brief Indicates the PageUp key") + + method ("PageDown", &const_KeyPageDown, "@brief Indicates the PageDown key"), + "@brief The namespace for the some key codes.\n" + "This namespace defines some key codes understood by built-in \\LayoutView components. " + "When compiling with Qt, these codes are compatible with Qt's key codes.\n" + "The key codes are intended to be used when directly interfacing with \\LayoutView in non-Qt-based environments.\n" + "\n" + "This class has been introduced in version 0.28.\n" +); + +static std::vector get_config_names (lay::Dispatcher *dispatcher) { std::vector names; diff --git a/src/laybasic/laybasic/layCellView.cc b/src/laybasic/laybasic/layCellView.cc index 1fa389ca9..f71e1e512 100644 --- a/src/laybasic/laybasic/layCellView.cc +++ b/src/laybasic/laybasic/layCellView.cc @@ -23,7 +23,7 @@ #include "layCellView.h" #include "layLayoutView.h" -#if defined(HAVE_QT) // @@@ +#if defined(HAVE_QT) # include "layStream.h" #endif #include "dbLayout.h" @@ -292,7 +292,7 @@ LayoutHandle::set_save_options (const db::SaveLayoutOptions &options, bool valid void LayoutHandle::update_save_options (db::SaveLayoutOptions &options) { -#if defined(HAVE_QT) // @@@ +#if defined(HAVE_QT) for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { const lay::StreamWriterPluginDeclaration *decl = dynamic_cast (&*cls); diff --git a/src/laybasic/laybasic/layLayoutCanvas.cc b/src/laybasic/laybasic/layLayoutCanvas.cc index 7f533ff30..1838a26e1 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.cc +++ b/src/laybasic/laybasic/layLayoutCanvas.cc @@ -296,6 +296,7 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view) m_redraw_clearing (false), m_redraw_force_update (true), m_update_image (true), + m_drawing_finished (false), m_do_update_image_dm (this, &LayoutCanvas::do_update_image), m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing), m_image_cache_size (1) @@ -358,23 +359,23 @@ LayoutCanvas::key_event (unsigned int key, unsigned int buttons) { #if defined(HAVE_QT) // @@@ if (! (buttons & lay::ShiftButton)) { - if (int (key) == Qt::Key_Down) { + if (int (key) == lay::KeyDown) { emit down_arrow_key_pressed (); - } else if (int (key) == Qt::Key_Up) { + } else if (int (key) == lay::KeyUp) { emit up_arrow_key_pressed (); - } else if (int (key) == Qt::Key_Left) { + } else if (int (key) == lay::KeyLeft) { emit left_arrow_key_pressed (); - } else if (int (key) == Qt::Key_Right) { + } else if (int (key) == lay::KeyRight) { emit right_arrow_key_pressed (); } } else { - if (int (key) == Qt::Key_Down) { + if (int (key) == lay::KeyDown) { emit down_arrow_key_pressed_with_shift (); - } else if (int (key) == Qt::Key_Up) { + } else if (int (key) == lay::KeyUp) { emit up_arrow_key_pressed_with_shift (); - } else if (int (key) == Qt::Key_Left) { + } else if (int (key) == lay::KeyLeft) { emit left_arrow_key_pressed_with_shift (); - } else if (int (key) == Qt::Key_Right) { + } else if (int (key) == lay::KeyRight) { emit right_arrow_key_pressed_with_shift (); } } @@ -1017,13 +1018,12 @@ LayoutCanvas::resizeEvent (QResizeEvent *) 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); - -#if defined(HAVE_QT) - QWidget::resize (width, height); -#endif } void @@ -1093,6 +1093,14 @@ LayoutCanvas::zoom_trans (const db::DCplxTrans &trans) update_viewport (); } +bool +LayoutCanvas::drawing_finished () +{ + bool f = m_drawing_finished; + m_drawing_finished = false; + return f; +} + void LayoutCanvas::do_end_of_drawing () { @@ -1109,6 +1117,8 @@ LayoutCanvas::do_end_of_drawing () } set_default_cursor (lay::Cursor::none); + + m_drawing_finished = true; } void diff --git a/src/laybasic/laybasic/layLayoutCanvas.h b/src/laybasic/laybasic/layLayoutCanvas.h index 574abf17d..2083745da 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.h +++ b/src/laybasic/laybasic/layLayoutCanvas.h @@ -346,6 +346,11 @@ public: */ void resize (unsigned int width, unsigned int height); + /** + * @brief Gets (and resets) a flag indicating that drawing has finished + */ + bool drawing_finished (); + /** * @brief An event indicating that the viewport was changed. * If the viewport (the rectangle that is shown) changes, this event is fired. @@ -385,6 +390,7 @@ private: bool m_redraw_clearing; bool m_redraw_force_update; bool m_update_image; + bool m_drawing_finished; std::vector m_need_redraw_layer; std::vector m_layers; diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 11dedc436..9ad09fe7b 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -1128,6 +1128,26 @@ LayoutView::LayoutView (lay::LayoutView *source, db::Manager *mgr, bool editable // .. nothing yet .. } +// NOTE: this methods needs to be called "frequently" +void +LayoutView::timer () +{ + LayoutViewBase::timer (); + + // Without Qt, this is also the opportunity to execute deferred methods + tl::DeferredMethodScheduler::execute (); + + // We also issue the "image_updated" event if the image ("screenshot") has been updated + if (canvas ()->image_updated ()) { + image_updated_event (); + } + + // And also the drawing_finished event + if (canvas ()->drawing_finished ()) { + drawing_finished_event (); + } +} + } // namespace lay #endif diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index 3766b4e1c..0ce115255 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -794,6 +794,21 @@ public: */ LayoutView (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); + /** + * @brief This event is triggered in the "timer" callback when the image ("screenshot") was updated. + */ + tl::Event image_updated_event; + + /** + * @brief This event is triggered in the "timer" callback when the drawing thread has finished. + */ + tl::Event drawing_finished_event; + + /** + * @brief A callback that needs to be called "frequently" + */ + void timer (); + protected: /** * @brief Gets the LayoutView interface diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index c5b448825..4b0487e19 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -34,6 +34,7 @@ #include "tlLog.h" #include "tlAssert.h" #include "tlExceptions.h" +#include "tlDeferredExecution.h" #include "layLayoutViewBase.h" #include "layViewOp.h" #include "layViewObject.h" @@ -3357,7 +3358,7 @@ LayoutViewBase::get_ui () return mp_ui; } -// @@@ needs to be called "as often as possible" +// NOTE: this methods needs to be called "frequently" void LayoutViewBase::timer () { diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index 91022595e..742f3fccc 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -2762,6 +2762,11 @@ 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/layMove.cc b/src/laybasic/laybasic/layMove.cc index 9667ccb77..da4264da4 100644 --- a/src/laybasic/laybasic/layMove.cc +++ b/src/laybasic/laybasic/layMove.cc @@ -89,17 +89,15 @@ bool MoveService::key_event (unsigned int key, unsigned int /*buttons*/) { double dx = 0.0, dy = 0.0; -#if defined(HAVE_QT) // @@@ - if (int (key) == Qt::Key_Down) { + if (int (key) == lay::KeyDown) { dy = -1.0; - } else if (int (key) == Qt::Key_Up) { + } else if (int (key) == lay::KeyUp) { dy = 1.0; - } else if (int (key) == Qt::Key_Left) { + } else if (int (key) == lay::KeyLeft) { dx = -1.0; - } else if (int (key) == Qt::Key_Right) { + } else if (int (key) == lay::KeyRight) { dx = 1.0; } -#endif if (! m_dragging && fabs (dx + dy) > 0.0 && mp_editables->has_selection ()) { diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index 528b3e689..8a881c321 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -232,9 +232,7 @@ ViewObject::redraw () if (m_static) { widget ()->touch (); } else { -#if defined(HAVE_QT) - widget ()->update (); // @@@ -#endif + widget ()->update (); } } } @@ -287,9 +285,9 @@ ViewService::set_cursor (lay::Cursor::cursor_shape cursor) } // --------------------------------------------------------------- -// ViewObject implementation +// ViewObjectWidget implementation -#if defined(HAVE_QT) // @@@ +#if defined(HAVE_QT) ViewObjectWidget::ViewObjectWidget (QWidget *parent, const char *name) : QWidget (parent), m_view_objects_dismissed (false), @@ -301,7 +299,10 @@ ViewObjectWidget::ViewObjectWidget (QWidget *parent, const char *name) m_in_mouse_move (false), m_mouse_inside (false), m_cursor (lay::Cursor::none), - m_default_cursor (lay::Cursor::none) + m_default_cursor (lay::Cursor::none), + m_widget_width (0), + m_widget_height (0), + m_image_updated (false) { setMouseTracking (true); setObjectName (QString::fromUtf8 (name)); @@ -320,7 +321,10 @@ ViewObjectWidget::ViewObjectWidget () m_in_mouse_move (false), m_mouse_inside (false), m_cursor (lay::Cursor::none), - m_default_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); } @@ -395,7 +399,7 @@ ViewObjectWidget::set_cursor (lay::Cursor::cursor_shape cursor) void ViewObjectWidget::set_default_cursor (lay::Cursor::cursor_shape cursor) { -#if defined(HAVE_QT) // @@@ +#if defined(HAVE_QT) if (cursor != m_default_cursor) { m_default_cursor = cursor; if (m_cursor == lay::Cursor::none) { @@ -920,13 +924,23 @@ END_PROTECTED } #endif +void +ViewObjectWidget::resize (unsigned int w, unsigned int h) +{ + m_widget_width = w; + m_widget_height = h; +#if defined(HAVE_QT) + QWidget::resize (w, h); +#endif +} + int ViewObjectWidget::widget_height () const { #if defined(HAVE_QT) return height (); #else - return 500; // @@@ + return m_widget_height; #endif } @@ -936,7 +950,7 @@ ViewObjectWidget::widget_width () const #if defined(HAVE_QT) return width (); #else - return 800; // @@@ + return m_widget_width; #endif } @@ -1078,7 +1092,16 @@ ViewObjectWidget::thaw (ViewObject *obj) void ViewObjectWidget::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 () +{ + bool f = m_image_updated; + m_image_updated = false; + return f; } #endif diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index bd1350dff..dfd24623d 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -638,12 +638,53 @@ private: * @brief Describes the button state (supposed to be ored) */ enum ButtonState { - ShiftButton = 1, + ShiftButton = 1, ControlButton = 2, - AltButton = 4, - LeftButton = 8, - MidButton = 16, - RightButton = 32 + AltButton = 4, + LeftButton = 8, + MidButton = 16, + RightButton = 32 +}; + +/** + * @brief Key codes for keys understood by the standard components + */ +enum KeyCodes { +#if defined(HAVE_QT) + KeyEscape = int(Qt::Key_Escape), + KeyTab = int(Qt::Key_Tab), + KeyBacktab = int(Qt::Key_Backtab), + KeyBackspace = int(Qt::Key_Backspace), + KeyReturn = int(Qt::Key_Return), + KeyEnter = int(Qt::Key_Enter), + KeyInsert = int(Qt::Key_Insert), + KeyDelete = int(Qt::Key_Delete), + KeyHome = int(Qt::Key_Home), + KeyEnd = int(Qt::Key_End), + KeyDown = int(Qt::Key_Down), + KeyUp = int(Qt::Key_Up), + KeyLeft = int(Qt::Key_Left), + KeyRight = int(Qt::Key_Right), + KeyPageUp = int(Qt::Key_PageUp), + KeyPageDown = int(Qt::Key_PageDown) +#else + KeyEscape = 0x01000000, + KeyTab = 0x01000001, + KeyBacktab = 0x01000002, + KeyBackspace = 0x01000003, + KeyReturn = 0x01000004, + KeyEnter = 0x01000005, + KeyInsert = 0x01000006, + KeyDelete = 0x01000007, + KeyHome = 0x01000010, + KeyEnd = 0x01000011, + KeyLeft = 0x01000012, + KeyUp = 0x01000013, + KeyRight = 0x01000014, + KeyDown = 0x01000015, + KeyPageUp = 0x01000016, + KeyPageDown = 0x01000017 +#endif }; /** @@ -1031,6 +1072,15 @@ public: return m_mouse_inside; } +#if !defined(HAVE_QT) + /** + * @brief Gets a value indicating that the image data has been updated + * + * This method will return true once after "update" was called. + */ + bool image_updated (); +#endif + protected: #if defined(HAVE_QT) // @@@ /** @@ -1103,7 +1153,13 @@ protected: void wheelEvent (QWheelEvent *e); #endif -#if !defined(HAVE_QT) // @@@ +#if !defined(HAVE_QT) + /** + * @brief Emulates the update() method in the non-Qt case + * + * After calling this method, the next image_updated() call will return true while also resetting the + * update needed flag. + */ void update (); #endif @@ -1112,6 +1168,11 @@ protected: */ void mouse_event_trans (const db::DCplxTrans &trans); + /** + * @brief Resizes the widget + */ + void resize (unsigned int w, unsigned int h); + private: friend class lay::ViewObject; friend class lay::ViewService; @@ -1133,6 +1194,8 @@ private: bool m_in_mouse_move; bool m_mouse_inside; lay::Cursor::cursor_shape m_cursor, m_default_cursor; + unsigned int m_widget_width, m_widget_height; + bool m_image_updated; void ensure_entered (); void do_mouse_move ();