From 8cbe5a235959d4a259616e0292ef2c42c91539ff Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 28 Sep 2022 00:37:37 +0200 Subject: [PATCH] WIP: debugging, first implementation of new templates --- src/ant/ant/RulerConfigPage4.ui | 20 +++++-- src/ant/ant/antConfig.cc | 8 +++ src/ant/ant/antObject.h | 8 +++ src/ant/ant/antPlugin.cc | 50 ++++++++++++++-- src/ant/ant/antService.cc | 102 ++++++++++++++++++++++++-------- src/ant/ant/antService.h | 6 ++ src/ant/ant/antTemplate.h | 12 +++- src/ant/ant/gsiDeclAnt.cc | 26 +++++++- 8 files changed, 195 insertions(+), 37 deletions(-) diff --git a/src/ant/ant/RulerConfigPage4.ui b/src/ant/ant/RulerConfigPage4.ui index ac380684e..649d18d44 100644 --- a/src/ant/ant/RulerConfigPage4.ui +++ b/src/ant/ant/RulerConfigPage4.ui @@ -89,7 +89,7 @@ ... - + :/up_16px.png:/up_16px.png @@ -103,7 +103,7 @@ ... - + :/add_16px.png:/add_16px.png @@ -117,7 +117,7 @@ ... - + :/del_16px.png:/del_16px.png @@ -131,7 +131,7 @@ ... - + :/down_16px.png:/down_16px.png @@ -833,6 +833,16 @@ Auto measure (points will be set automatically) + + + Angle measurement (three mouse clicks) + + + + + Multi-segment (finish with double click) + + @@ -866,7 +876,7 @@ t_snap_cbx - + diff --git a/src/ant/ant/antConfig.cc b/src/ant/ant/antConfig.cc index 78356a41b..250945a98 100644 --- a/src/ant/ant/antConfig.cc +++ b/src/ant/ant/antConfig.cc @@ -239,6 +239,10 @@ RulerModeConverter::to_string (ant::Template::ruler_mode_type m) return "single_click"; } else if (m == ant::Template::RulerAutoMetric) { return "auto_metric"; + } else if (m == ant::Template::RulerMultiSegment) { + return "multi_segment"; + } else if (m == ant::Template::RulerAngle) { + return "angle"; } else { return "normal"; } @@ -254,6 +258,10 @@ RulerModeConverter::from_string (const std::string &s, ant::Template::ruler_mode a = ant::Template::RulerSingleClick; } else if (t == "auto_metric") { a = ant::Template::RulerAutoMetric; + } else if (t == "multi_segment") { + a = ant::Template::RulerMultiSegment; + } else if (t == "angle") { + a = ant::Template::RulerAngle; } else { a = ant::Template::RulerNormal; } diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h index 7304c5bed..60752449d 100644 --- a/src/ant/ant/antObject.h +++ b/src/ant/ant/antObject.h @@ -292,6 +292,14 @@ public: */ void set_points (const point_list &points); + /** + * @brief Sets the ruler's definition points without cleaning + */ + void set_points_exact (const point_list &points) + { + m_points = points; + } + /** * @brief Gets the first point of the indicated segment */ diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc index fda6d5b8a..74918b24c 100644 --- a/src/ant/ant/antPlugin.cc +++ b/src/ant/ant/antPlugin.cc @@ -68,12 +68,18 @@ static std::vector make_standard_templates () templates.push_back (ant::Template (tl::to_string (tr ("Ruler")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_ruler")); + templates.push_back (ant::Template (tl::to_string (tr ("Multi-ruler")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_multi_ruler")); + templates.back ().set_mode (ant::Template::RulerMultiSegment); + templates.push_back (ant::Template (tl::to_string (tr ("Cross")), "", "", "$U,$V", ant::Object::STY_cross_both, ant::Object::OL_diag, true, lay::AC_Global, "_cross")); templates.back ().set_mode (ant::Template::RulerSingleClick); templates.push_back (ant::Template (tl::to_string (tr ("Measure")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_measure")); templates.back ().set_mode (ant::Template::RulerAutoMetric); + templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_diag, true, lay::AC_Global, "_angle")); + templates.back ().set_mode (ant::Template::RulerAngle); + templates.push_back (ant::Template (tl::to_string (tr ("Ellipse")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_ellipse, true, lay::AC_Global, std::string ())); templates.push_back (ant::Template (tl::to_string (tr ("Box")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_box, true, lay::AC_Global, std::string ())); @@ -197,14 +203,50 @@ PluginDeclaration::initialized (lay::Dispatcher *root) // Check if we already have templates (initial setup) // NOTE: this is not done by using a default value for the configuration item but dynamically. // This provides a migration path from earlier versions (not having templates) to recent ones. - bool any_templates = false; - for (std::vector::iterator i = m_templates.begin (); ! any_templates && i != m_templates.end (); ++i) { - any_templates = ! i->category ().empty (); + std::map cat_names; + for (auto i = m_templates.begin (); i != m_templates.end (); ++i) { + if (! i->category ().empty ()) { + cat_names.insert (std::make_pair (i->category (), i.operator-> ())); + } } - if (! any_templates) { + bool any_missing = false; + auto std_templates = make_standard_templates (); + for (auto t = std_templates.begin (); ! any_missing && t != std_templates.end (); ++t) { + if (! t->category ().empty () && cat_names.find (t->category ()) == cat_names.end ()) { + any_missing = true; + } + } + + if (cat_names.empty ()) { + + // full initial configuration root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ())); root->config_end (); + + } else if (any_missing) { + + // some standard templates are missing - add them now (migration path for later versions) + decltype (m_templates) new_templates; + for (auto t = std_templates.begin (); t != std_templates.end (); ++t) { + if (! t->category ().empty ()) { + auto tt = cat_names.find (t->category ()); + if (tt != cat_names.end ()) { + new_templates.push_back (*tt->second); + } else { + new_templates.push_back (*t); + } + } + } + for (auto i = m_templates.begin (); i != m_templates.end (); ++i) { + if (i->category ().empty ()) { + new_templates.push_back (*i); + } + } + + root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (new_templates)); + root->config_end (); + } } diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index ffd1e22cb..fb76bc076 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -1560,11 +1560,52 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio return mouse_click_event (p, buttons, prio); } -bool +void +Service::finish_drawing () +{ + // create the ruler object + + // begin the transaction + if (manager ()) { + tl_assert (! manager ()->transacting ()); + manager ()->transaction (tl::to_string (tr ("Create ruler"))); + } + + show_message (); + + insert_ruler (ant::Object (m_current.points (), 0, current_template ()), true); + + // stop dragging + drag_cancel (); + clear_transient_selection (); + + // end the transaction + if (manager ()) { + manager ()->commit (); + } +} + +bool +Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio) +{ + if (m_drawing && prio && (buttons & lay::LeftButton) != 0) { + + // ends the current ruler (specifically in multi-segment mode) + finish_drawing (); + return true; + + } + + return false; +} + +bool Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio) { if (prio && (buttons & lay::LeftButton) != 0) { + const ant::Template &tpl = current_template (); + if (! m_drawing) { // cancel any edit operations so far @@ -1577,8 +1618,6 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio // and clear surplus rulers reduce_rulers (m_max_number_of_rulers - 1); - const ant::Template &tpl = current_template (); - // create and start dragging the ruler if (tpl.mode () == ant::Template::RulerSingleClick) { @@ -1648,7 +1687,13 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio m_p1 = snap1 (p, m_obj_snap && tpl.snap ()).second; - m_current = ant::Object (m_p1, m_p1, 0, tpl); + // NOTE: generating the ruler this way makes sure we have two points + ant::Object::point_list pts; + m_current = ant::Object (pts, 0, tpl); + pts.push_back (m_p1); + pts.push_back (m_p1); + m_current.set_points_exact (pts); + show_message (); if (mp_active_ruler) { @@ -1662,29 +1707,29 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio } + } else if (tpl.mode () == ant::Template::RulerMultiSegment || tpl.mode () == ant::Template::RulerAngle) { + + ant::Object::point_list pts = m_current.points (); + tl_assert (! pts.empty ()); + + if (tpl.mode () == ant::Template::RulerAngle && pts.size () == 3) { + + finish_drawing (); + + } else { + + // add a new point + m_p1 = pts.back (); + + pts.push_back (m_p1); + m_current.set_points_exact (pts); + + } + } else { - // create the ruler object + finish_drawing (); - // begin the transaction - if (manager ()) { - tl_assert (! manager ()->transacting ()); - manager ()->transaction (tl::to_string (tr ("Create ruler"))); - } - - show_message (); - - insert_ruler (ant::Object (m_current.p1 (), m_current.p2 (), 0, current_template ()), true); - - // stop dragging - drag_cancel (); - clear_transient_selection (); - - // end the transaction - if (manager ()) { - manager ()->commit (); - } - } return true; @@ -1731,7 +1776,14 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio) set_cursor (lay::Cursor::cross); - m_current.p2 (snap2 (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)).second); + // NOTE: we use the direct access path so we do not encounter cleanup by the p1 and p2 setters + // otherwise we risk manipulating p1 too. + ant::Object::point_list pts = m_current.points (); + if (! pts.empty ()) { + pts.back () = snap2 (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)).second; + } + m_current.set_points_exact (pts); + mp_active_ruler->redraw (); show_message (); diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h index 6b4c5be9d..5d55af179 100644 --- a/src/ant/ant/antService.h +++ b/src/ant/ant/antService.h @@ -566,6 +566,7 @@ private: virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio); virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio); 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 void deactivated (); /** @@ -585,6 +586,11 @@ private: */ void reduce_rulers (int num); + /** + * @brief Finishes drawing mode and creates the ruler + */ + void finish_drawing (); + /** * @brief Delete the selected rulers * diff --git a/src/ant/ant/antTemplate.h b/src/ant/ant/antTemplate.h index 0d8b921f5..6b1bbbf8b 100644 --- a/src/ant/ant/antTemplate.h +++ b/src/ant/ant/antTemplate.h @@ -62,7 +62,17 @@ public: /** * @brief The ruler is auto-metric: a single click will place a ruler and the ruler will extend to the next adjacent structures */ - RulerAutoMetric = 2 + RulerAutoMetric = 2, + + /** + * @brief The ruler an angle type (two segments, three mouse clicks) for angle and circle radius measurements + */ + RulerAngle = 3, + + /** + * @brief The ruler is a multi-segment type + */ + RulerMultiSegment = 4 }; /** diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc index 949cb5c09..24b3d47ca 100644 --- a/src/ant/ant/gsiDeclAnt.cc +++ b/src/ant/ant/gsiDeclAnt.cc @@ -432,6 +432,16 @@ static int ruler_mode_auto_metric () return ant::Template::RulerAutoMetric; } +static int ruler_mode_angle () +{ + return ant::Template::RulerAngle; +} + +static int ruler_mode_multi_segment () +{ + return ant::Template::RulerMultiSegment; +} + static void register_annotation_template (const ant::Object &a, const std::string &title, int mode) { ant::Template t = ant::Template::from_object (a, title, mode); @@ -503,16 +513,28 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat ) + gsi::method ("RulerModeSingleClick", &gsi::ruler_mode_single_click, "@brief Specifies single-click ruler mode for the \\register_template method\n" - "In single click-mode, a ruler can be placed with a single click and p1 will be == p2." + "In single click-mode, a ruler can be placed with a single click and p1 will be == p2.\n" "\n" "This constant has been introduced in version 0.25" ) + gsi::method ("RulerModeAutoMetric", &gsi::ruler_mode_auto_metric, "@brief Specifies auto-metric ruler mode for the \\register_template method\n" - "In auto-metric mode, a ruler can be placed with a single click and p1/p2 will be determined from the neighborhood." + "In auto-metric mode, a ruler can be placed with a single click and p1/p2 will be determined from the neighborhood.\n" "\n" "This constant has been introduced in version 0.25" ) + + gsi::method ("RulerAngle", &gsi::ruler_mode_angle, + "@brief Specifies angle ruler mode for the \\register_template method\n" + "In angle ruler mode, two segments are created for angle and circle radius measurements. Three mouse clicks are required.\n" + "\n" + "This constant has been introduced in version 0.28" + ) + + gsi::method ("RulerMultiSegment", &gsi::ruler_mode_multi_segment, + "@brief Specifies multi-segment mode\n" + "In multi-segment mode, multiple segments can be created. The ruler is finished with a double click.\n" + "\n" + "This constant has been introduced in version 0.28" + ) + gsi::method ("StyleRuler|#style_ruler", &gsi::style_ruler, "@brief Gets the ruler style code for use the \\style method\n" "When this style is specified, the annotation will show a ruler with "