From 9184bef6f852c65c8246885bea3811dea719f843 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 28 Jan 2024 18:25:02 +0100 Subject: [PATCH] Transient mode for auto-measure ruler --- src/ant/ant/antService.cc | 159 ++++++++++++++++++++----- src/ant/ant/antService.h | 50 +++++++- src/laybasic/laybasic/layMove.cc | 5 +- src/laybasic/laybasic/laySelector.h | 9 +- src/laybasic/laybasic/layViewObject.cc | 10 +- src/laybasic/laybasic/layViewObject.h | 16 +++ 6 files changed, 200 insertions(+), 49 deletions(-) diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index f7506bea6..e1cc12f97 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -1056,8 +1056,18 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view) m_drawing (false), m_current (), m_move_mode (MoveNone), m_seg_index (0), - m_current_template (0) -{ + m_current_template (0), + m_hover (false), + m_hover_wait (false), + m_hover_buttons (0), + m_mouse_in_window (false) +{ +#if defined(HAVE_QT) + m_timer.setInterval (100 /*hover time*/); + m_timer.setSingleShot (true); + connect (&m_timer, SIGNAL (timeout ()), this, SLOT (timeout ())); +#endif + mp_view->annotations_changed_event.add (this, &Service::annotations_changed); } @@ -1809,9 +1819,36 @@ Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int button return false; } +lay::TwoPointSnapToObjectResult +Service::auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl) +{ + // for auto-metric we need some cutline constraint - any or global won't do. + if (ac == lay::AC_Global) { + ac = tpl.angle_constraint (); + } + if (ac == lay::AC_Global) { + ac = m_snap_mode; + } + if (ac == lay::AC_Global) { + ac = lay::AC_Diagonal; + } + + db::DVector g; + if (m_grid_snap) { + g = db::DVector (m_grid, m_grid); + } + + double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (m_snap_range); + snap_range *= 0.5; + + return lay::obj_snap2 (mp_view, p, g, ac, snap_range, snap_range * 1000.0); +} + bool Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio) { + hover_reset (); + if (prio && (buttons & lay::LeftButton) != 0) { const ant::Template &tpl = current_template (); @@ -1852,27 +1889,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio } else if (tpl.mode () == ant::Template::RulerAutoMetric) { - // for auto-metric we need some cutline constraint - any or global won't do. - lay::angle_constraint_type ac = ac_from_buttons (buttons); - if (ac == lay::AC_Global) { - ac = tpl.angle_constraint (); - } - if (ac == lay::AC_Global) { - ac = m_snap_mode; - } - if (ac == lay::AC_Global) { - ac = lay::AC_Diagonal; - } - - db::DVector g; - if (m_grid_snap) { - g = db::DVector (m_grid, m_grid); - } - - 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); + lay::TwoPointSnapToObjectResult ee = auto_measure (p, ac_from_buttons (buttons), tpl); if (ee.any) { // begin the transaction @@ -1968,21 +1985,33 @@ Service::create_measure_ruler (const db::DPoint &pt, lay::angle_constraint_type bool Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio) { - if (prio) { + if (! prio) { + return false; + } - lay::PointSnapToObjectResult snap_details; - if (m_drawing) { - snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)); - } else { - const ant::Template &tpl = current_template (); - snap_details = snap1_details (p, m_obj_snap && tpl.snap ()); - } + if (! m_drawing && m_mouse_in_window && view ()->transient_selection_mode ()) { - mouse_cursor_from_snap_details (snap_details); + // Restart hover timer + m_hover_wait = true; +#if defined(HAVE_QT) + m_timer.start (); +#endif + m_hover_point = p; + m_hover_buttons = buttons; } - if (m_drawing && prio) { + lay::PointSnapToObjectResult snap_details; + if (m_drawing) { + snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)); + } else { + const ant::Template &tpl = current_template (); + snap_details = snap1_details (p, m_obj_snap && tpl.snap ()); + } + + mouse_cursor_from_snap_details (snap_details); + + if (m_drawing) { set_cursor (lay::Cursor::cross); @@ -2284,6 +2313,70 @@ Service::click_proximity (const db::DPoint &pos, lay::Editable::SelectionMode mo } } +bool +Service::enter_event (bool /*prio*/) +{ + m_mouse_in_window = true; + return false; +} + +bool +Service::leave_event (bool) +{ + m_mouse_in_window = false; + hover_reset (); + return false; +} + +void +Service::hover_reset () +{ + if (m_hover_wait) { +#if defined(HAVE_QT) + m_timer.stop (); +#endif + m_hover_wait = false; + } + if (m_hover) { + // as we use the transient selection for the hover ruler, we have to remove it here + clear_transient_selection (); + m_hover = false; + } +} + +#if defined(HAVE_QT) +void +Service::timeout () +{ + m_hover_wait = false; + m_hover = true; + + // as we use the transient selection for the hover ruler, we have to remove it here + clear_transient_selection (); + + // transiently create an auto-metric ruler if requested + + const ant::Template &tpl = current_template (); + if (tpl.mode () == ant::Template::RulerAutoMetric) { + + lay::TwoPointSnapToObjectResult ee = auto_measure (m_hover_point, ac_from_buttons (m_hover_buttons), tpl); + if (ee.any) { + + m_current = ant::Object (ee.first, ee.second, 0, tpl); + + // HINT: there is no special style for "transient selection on rulers" + mp_transient_ruler = new ant::View (this, &m_current, true /*not selected*/); + + if (! editables ()->has_selection ()) { + display_status (true); + } + + } + + } +} +#endif + bool Service::transient_select (const db::DPoint &pos) { diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h index eaf664726..fb3ed67fe 100644 --- a/src/ant/ant/antService.h +++ b/src/ant/ant/antService.h @@ -39,6 +39,11 @@ #include #include +#if defined (HAVE_QT) +# include +# include +#endif + namespace ant { class LayoutViewBase; @@ -177,12 +182,19 @@ private: // ------------------------------------------------------------- -class ANT_PUBLIC Service - : public lay::EditorServiceBase, +class ANT_PUBLIC Service : +#if defined (HAVE_QT) + public QObject, +#endif + public lay::EditorServiceBase, public lay::Drawing, public db::Object { -public: +#if defined (HAVE_QT) +Q_OBJECT +#endif + +public: typedef lay::AnnotationShapes::iterator obj_iterator; /** @@ -341,6 +353,21 @@ public: */ virtual db::DBox selection_bbox (); + /** + * @brief Implementation of the editables API + */ + virtual bool enter_event (bool); + + /** + * @brief Implementation of the editables API + */ + virtual bool leave_event (bool); + + /** + * @brief Implementation of the editables API + */ + virtual void hover_reset (); + /** * @brief Transform the selection (reimplementation of lay::Editable interface) */ @@ -506,6 +533,11 @@ public: */ tl::Event annotation_selection_changed_event; +#if defined (HAVE_QT) +public slots: + void timeout (); +#endif + private: // Ruler display and snapping configuration tl::Color m_color; @@ -551,10 +583,22 @@ private: std::vector m_ruler_templates; unsigned int m_current_template; + // Hover detector + bool m_hover; + bool m_hover_wait; + db::DPoint m_hover_point; + unsigned int m_hover_buttons; +#if defined (HAVE_QT) + QTimer m_timer; +#endif + + bool m_mouse_in_window; + std::pair snap1 (const db::DPoint &p, bool obj_snap); lay::PointSnapToObjectResult snap1_details (const db::DPoint &p, bool obj_snap); std::pair snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac); lay::PointSnapToObjectResult snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac); + lay::TwoPointSnapToObjectResult auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl); const ant::Template ¤t_template () const; diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc index ab6c4d6d6..4bc22e7d0 100644 --- a/src/laybasic/laybasic/layMove.cc +++ b/src/laybasic/laybasic/layMove.cc @@ -305,10 +305,7 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_ if (mp_editables->begin_move (p, ac_from_buttons (buttons))) { - lay::SelectionService *selector = mp_view->selection_service (); - if (selector) { - selector->hover_reset (); - } + ui ()->hover_reset (); mp_view->clear_transient_selection (); diff --git a/src/laybasic/laybasic/laySelector.h b/src/laybasic/laybasic/laySelector.h index a47789158..6ad7600a9 100644 --- a/src/laybasic/laybasic/laySelector.h +++ b/src/laybasic/laybasic/laySelector.h @@ -69,14 +69,7 @@ public: virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio); virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio); virtual bool wheel_event (int delta, bool horizontal, const db::DPoint &p, unsigned int buttons, bool prio); - - /** - * @brief Reset the hover timer for the transient selection - * - * This method may be used by other services (in particular Move) to avoid the transient to - * be triggered from a move operation. - */ - void hover_reset (); + virtual void hover_reset (); #if defined (HAVE_QT) public slots: diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index 0927fd261..d794fe87f 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -1051,7 +1051,15 @@ ViewObjectUI::drag_cancel () } } -namespace +void +ViewObjectUI::hover_reset () +{ + for (service_iterator svc = begin_services (); svc != end_services (); ++svc) { + (*svc)->hover_reset (); + } +} + +namespace { struct z_order_compare_f { diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index 76f9b5175..8ba1bebb9 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -147,6 +147,17 @@ public: virtual bool drop_event (const db::DPoint & /*p*/, const DragDropDataBase * /*data*/) { return false; } #endif + /** + * @brief Hover reset request + * + * This event is issued for services providing some "hover" mode - i.e. capture + * mouse move events and start a timer on them. + * + * The implementation of this event should cancel this timer and + * not raise a hover condition. + */ + virtual void hover_reset () { } + /** * @brief Mouse press event handler * @@ -605,6 +616,11 @@ public: */ void drag_cancel (); + /** + * @brief Calls hover_reset on all services + */ + void hover_reset (); + /** * @brief CanvasPlane rendering *