From d1b7cd1f8f61894971e3d041ca5f3ed3f12f2e64 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 26 Sep 2022 23:37:22 +0200 Subject: [PATCH] WIP: first steps towards multi-segment rulers --- src/ant/ant/RulerPropertiesPage.ui | 1154 ++++++++++++++++------------ src/ant/ant/antObject.cc | 288 +++++-- src/ant/ant/antObject.h | 128 ++- src/ant/ant/antPropertiesPage.cc | 194 ++++- src/ant/ant/antPropertiesPage.h | 10 +- src/ant/ant/antService.cc | 74 +- src/ant/ant/gsiDeclAnt.cc | 85 +- 7 files changed, 1280 insertions(+), 653 deletions(-) diff --git a/src/ant/ant/RulerPropertiesPage.ui b/src/ant/ant/RulerPropertiesPage.ui index 5e4497bbd..567287ddc 100644 --- a/src/ant/ant/RulerPropertiesPage.ui +++ b/src/ant/ant/RulerPropertiesPage.ui @@ -13,10 +13,7 @@ Form - - - 6 - + 9 @@ -29,7 +26,7 @@ 9 - + QFrame::NoFrame @@ -53,13 +50,95 @@ 6 - - + + - Second point (x/y) + X label format + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + + + + + + Label format + + + + + + + Y label format + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + @@ -67,173 +146,31 @@ - - + + - <html>(See <a href="int:/manual/ruler_properties.xml">here</a> for a description of the properties)</html> + Outline - - + + + + + ... position - - - - Qt::Vertical - - - - 20 - 5 - - - - - - - - - - - - Diagonal - - - - - Horizonal and vertical (in this order) - - - - - Diagonal plus horizonal and vertical (triangle) - - - - - Vertical and horizonal (in this order) - - - - - Diagonal plus vertical and horizontal (triangle) - - - - - Box - - - - - Ellipse - - - - - - + + - d = + ... position - - - - Qt::Vertical - - - - 20 - 5 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 456 - 16 - - - - - - - - - Ruler - - - - - Arrow at end - - - - - Arrow at start - - - - - Arrow at both ends - - - - - Plain line - - - - - Cross at end - - - - - Cross at start - - - - - Cross at both ends - - - - - - - - - 1 - 0 - - - - - - - - Delta (x/y) - - - - + QFrame::NoFrame @@ -378,42 +315,176 @@ - - + + + + + Diagonal + + + + + Horizonal and vertical (in this order) + + + + + Diagonal plus horizonal and vertical (triangle) + + + + + Vertical and horizonal (in this order) + + + + + Diagonal plus vertical and horizontal (triangle) + + + + + Box + + + + + Ellipse + + + + + + + + + Ruler + + + + + Arrow at end + + + + + Arrow at start + + + + + Arrow at both ends + + + + + Plain line + + + + + Cross at end + + + + + Cross at start + + + + + Cross at both ends + + + + + + + + <html>(See <a href="int:/manual/ruler_properties.xml">here</a> for a description of the properties)</html> + + + + + + + + 0 + 0 + + + + + Sans Serif + 12 + false + true + false + false + + + + Ruler Properties + + + + + - Qt::Horizontal + Qt::Vertical + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + - - - - x = - - - - - - - Label format - - - - - - - Length - - - - - - - Outline - - - - + QFrame::NoFrame @@ -524,210 +595,7 @@ - - - - - 1 - 0 - - - - true - - - - - - - - 1 - 0 - - - - true - - - - - - - First point (x/y) - - - - - - - - 1 - 0 - - - - - - - - y = - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Swap points - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 20 - - - - - - - - Snap to layout: - - - - - - - P1 - - - false - - - - - - - P2 - - - false - - - - - - - Both (auto-measure) - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Qt::Vertical - - - - 20 - 5 - - - - - - - - y = - - - - - - - - - - - 1 - 0 - - - - true - - - - - - - - 1 - 0 - - - - - - - - ... position - - - - - - - + QFrame::NoFrame @@ -838,98 +706,429 @@ - - + + ... position - - - - x = - - - - - + + - - 1 - 0 - - - - - - - - Y label format - - - - - - - X label format - - - - - - - y = - - - - - - - x = - - - - - - - + 0 - 0 + 1 - - - Sans Serif - 12 - 75 - false - true - false - false - + + + 0 + 100 + - - Ruler Properties + + 1 + + + Single + + + + + + First point (x/y) + + + + + + + x = + + + + + + + + 1 + 0 + + + + + + + + y = + + + + + + + + 1 + 0 + + + + + + + + Qt::Vertical + + + + 558 + 157 + + + + + + + + + Line + + + + + + y = + + + + + + + First point (x/y) + + + + + + + d = + + + + + + + y = + + + + + + + y = + + + + + + + + 1 + 0 + + + + true + + + + + + + Length + + + + + + + x = + + + + + + + Delta (x/y) + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + + + + + Second point (x/y) + + + + + + + + 1 + 0 + + + + + + + + x = + + + + + + + + 1 + 0 + + + + true + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + x = + + + + + + + + 1 + 0 + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 30 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Swap points + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + Snap to layout + + + + + + + P1 + + + false + + + + + + + P2 + + + false + + + + + + + Both (auto-measure) + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Multi-Segment + + + + + + false + + + true + + + + x + + + + + y + + + + + + + + + Text edit + + + + + + false + + + + + - - - - Qt::Vertical - - - - 20 - 0 - - - - @@ -937,13 +1136,6 @@ fmt_y_le style_cb outline_cb - x1 - y1 - x2 - y2 - dx - dy - dd diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc index 43bdf736b..5603de0d8 100644 --- a/src/ant/ant/antObject.cc +++ b/src/ant/ant/antObject.cc @@ -33,7 +33,7 @@ namespace ant { Object::Object () - : m_p1 (), m_p2 (), m_id (-1), + : m_id (-1), m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"), m_style (STY_ruler), m_outline (OL_diag), m_snap (true), m_angle_constraint (lay::AC_Global), @@ -45,8 +45,8 @@ Object::Object () // .. nothing yet .. } -Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint) - : m_p1 (p1), m_p2 (p2), m_id (id), +Object::Object (const db::DPoint &_p1, const db::DPoint &_p2, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint) + : m_id (id), m_fmt_x (fmt_x), m_fmt_y (fmt_y), m_fmt (fmt), m_style (style), m_outline (outline), m_snap (snap), m_angle_constraint (angle_constraint), @@ -55,11 +55,25 @@ Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const std::s m_xlabel_xalign (AL_auto), m_xlabel_yalign (AL_auto), m_ylabel_xalign (AL_auto), m_ylabel_yalign (AL_auto) { - // .. nothing else .. + p1 (_p1); + p2 (_p2); } -Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::Template &t) - : m_p1 (p1), m_p2 (p2), m_id (id), +Object::Object (const Object::point_list &pts, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint) + : m_id (id), + m_fmt_x (fmt_x), m_fmt_y (fmt_y), m_fmt (fmt), + m_style (style), m_outline (outline), + m_snap (snap), m_angle_constraint (angle_constraint), + m_main_position (POS_auto), + m_main_xalign (AL_auto), m_main_yalign (AL_auto), + m_xlabel_xalign (AL_auto), m_xlabel_yalign (AL_auto), + m_ylabel_xalign (AL_auto), m_ylabel_yalign (AL_auto) +{ + set_points (pts); +} + +Object::Object (const db::DPoint &_p1, const db::DPoint &_p2, int id, const ant::Template &t) + : m_id (id), m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()), m_style (t.style ()), m_outline (t.outline ()), m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()), @@ -69,11 +83,26 @@ Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::T m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()), m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ()) { - // .. nothing else .. + p1 (_p1); + p2 (_p2); +} + +Object::Object (const Object::point_list &pts, int id, const ant::Template &t) + : m_id (id), + m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()), + m_style (t.style ()), m_outline (t.outline ()), + m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()), + m_category (t.category ()), + m_main_position (t.main_position ()), + m_main_xalign (t.main_xalign ()), m_main_yalign (t.main_yalign ()), + m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()), + m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ()) +{ + set_points (pts); } Object::Object (const ant::Object &d) - : m_p1 (d.m_p1), m_p2 (d.m_p2), m_id (d.m_id), + : m_points (d.m_points), m_id (d.m_id), m_fmt_x (d.m_fmt_x), m_fmt_y (d.m_fmt_y), m_fmt (d.m_fmt), m_style (d.m_style), m_outline (d.m_outline), m_snap (d.m_snap), m_angle_constraint (d.m_angle_constraint), @@ -90,8 +119,7 @@ Object & Object::operator= (const ant::Object &d) { if (this != &d) { - m_p1 = d.m_p1; - m_p2 = d.m_p2; + m_points = d.m_points; m_id = d.m_id; m_fmt_x = d.m_fmt_x; m_fmt_y = d.m_fmt_y; @@ -119,11 +147,8 @@ Object::operator< (const ant::Object &b) const if (m_id != b.m_id) { return m_id < b.m_id; } - if (m_p1 != b.m_p1) { - return m_p1 < b.m_p1; - } - if (m_p2 != b.m_p2) { - return m_p2 < b.m_p2; + if (m_points != b.m_points) { + return m_points < b.m_points; } if (m_fmt_x != b.m_fmt_x) { return m_fmt_x < b.m_fmt_x; @@ -187,7 +212,7 @@ Object::equals (const db::DUserObjectBase *d) const bool Object::operator== (const ant::Object &d) const { - return m_p1 == d.m_p1 && m_p2 == d.m_p2 && m_id == d.m_id && + return m_points == d.m_points && m_id == d.m_id && m_fmt_x == d.m_fmt_x && m_fmt_y == d.m_fmt_y && m_fmt == d.m_fmt && m_style == d.m_style && m_outline == d.m_outline && m_snap == d.m_snap && m_angle_constraint == d.m_angle_constraint && @@ -199,6 +224,87 @@ Object::operator== (const ant::Object &d) const ; } +void +Object::set_points (const point_list &points) +{ + point_list new_points; + auto p = points.begin (); + while (p != points.end ()) { + auto pp = p + 1; + while (pp != points.end () && *pp == *p) { + ++pp; + } + new_points.push_back (*p); + p = pp; + } + + if (m_points != new_points) { + m_points = new_points; + property_changed (); + } +} + +db::DPoint +Object::seg_p1 (size_t seg_index) const +{ + if (seg_index < m_points.size ()) { + return m_points[seg_index]; + } else if (m_points.empty ()) { + return db::DPoint (); + } else { + return m_points.back (); + } +} + +db::DPoint +Object::seg_p2 (size_t seg_index) const +{ + if (seg_index + 1 < m_points.size ()) { + return m_points[seg_index + 1]; + } else if (m_points.empty ()) { + return db::DPoint (); + } else { + return m_points.back (); + } +} + +void +Object::p1 (const db::DPoint &p) +{ + if (! p1 ().equal (p)) { + if (m_points.size () < 1) { + m_points.push_back (p); + } else { + m_points.front () = p; + // makes sure there is only one point if p1 == p2 + if (m_points.size () == 2 && m_points.back () == m_points.front ()) { + m_points.pop_back (); + } + } + property_changed (); + } +} + +void +Object::p2 (const db::DPoint &p) +{ + if (! p2 ().equal (p)) { + if (m_points.size () < 2) { + if (m_points.empty ()) { + m_points.push_back (db::DPoint ()); + } + m_points.push_back (p); + } else { + m_points.back () = p; + } + // makes sure there is only one point if p1 == p2 + if (m_points.size () == 2 && m_points.back () == m_points.front ()) { + m_points.pop_back (); + } + property_changed (); + } +} + bool Object::less (const db::DUserObjectBase *d) const { @@ -226,7 +332,11 @@ Object::clone () const db::DBox Object::box () const { - return db::DBox (m_p1, m_p2); + db::DBox bx; + for (auto d = m_points.begin (); d != m_points.end (); ++d) { + bx += *d; + } + return bx; } class AnnotationEval @@ -245,38 +355,12 @@ private: db::DFTrans m_trans; }; -static double -delta_x (const Object &obj, const db::DFTrans &t) -{ - double dx = ((t * obj.p2 ()).x () - (t * obj.p1 ()).x ()); - - // avoid "almost 0" outputs - if (fabs (dx) < 1e-5 /*micron*/) { - dx = 0; - } - - return dx; -} - -static double -delta_y (const Object &obj, const db::DFTrans &t) -{ - double dy = ((t * obj.p2 ()).y () - (t * obj.p1 ()).y ()); - - // avoid "almost 0" outputs - if (fabs (dy) < 1e-5 /*micron*/) { - dy = 0; - } - - return dy; -} - class AnnotationEvalFunction : public tl::EvalFunction { public: - AnnotationEvalFunction (char function, const AnnotationEval *eval) - : m_function (function), mp_eval (eval) + AnnotationEvalFunction (char function, const AnnotationEval *eval, size_t index) + : m_function (function), mp_eval (eval), m_index (index) { // .. nothing yet .. } @@ -301,36 +385,73 @@ public: } else if (m_function == 'Y') { out = delta_y (obj, trans); } else if (m_function == 'U') { - out = (trans * obj.p1 ()).x (); + out = (trans * p1 (obj)).x (); } else if (m_function == 'V') { - out = (trans * obj.p1 ()).y (); + out = (trans * p1 (obj)).y (); } else if (m_function == 'P') { - out = (trans * obj.p2 ()).x (); + out = (trans * p2 (obj)).x (); } else if (m_function == 'Q') { - out = (trans * obj.p2 ()).y (); + out = (trans * p2 (obj)).y (); } else { out = tl::Variant (); } } + db::DPoint p1 (const Object &obj) const + { + return obj.seg_p1 (m_index); + } + + db::DPoint p2 (const Object &obj) const + { + return obj.seg_p2 (m_index); + } + + double + delta_x (const Object &obj, const db::DFTrans &t) const + { + double dx = ((t * p2 (obj)).x () - (t * p1 (obj)).x ()); + + // avoid "almost 0" outputs + if (fabs (dx) < 1e-5 /*micron*/) { + dx = 0; + } + + return dx; + } + + double + delta_y (const Object &obj, const db::DFTrans &t) const + { + double dy = ((t * p2 (obj)).y () - (t * p1 (obj)).y ()); + + // avoid "almost 0" outputs + if (fabs (dy) < 1e-5 /*micron*/) { + dy = 0; + } + + return dy; + } + private: char m_function; const AnnotationEval *mp_eval; + size_t m_index; }; std::string -Object::formatted (const std::string &fmt, const db::DFTrans &t) const +Object::formatted (const std::string &fmt, const db::DFTrans &t, size_t index) const { AnnotationEval eval (*this, t); - eval.define_function ("L", new AnnotationEvalFunction('L', &eval)); // manhattan length - eval.define_function ("D", new AnnotationEvalFunction('D', &eval)); // euclidian distance - eval.define_function ("X", new AnnotationEvalFunction('X', &eval)); // x delta - eval.define_function ("Y", new AnnotationEvalFunction('Y', &eval)); // y delta - eval.define_function ("U", new AnnotationEvalFunction('U', &eval)); // p1.x - eval.define_function ("V", new AnnotationEvalFunction('V', &eval)); // p1.y - eval.define_function ("P", new AnnotationEvalFunction('P', &eval)); // p2.x - eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval)); // p2.y - eval.define_function ("A", new AnnotationEvalFunction('A', &eval)); // area mm2 + eval.define_function ("L", new AnnotationEvalFunction('L', &eval, index)); // manhattan length + eval.define_function ("D", new AnnotationEvalFunction('D', &eval, index)); // euclidian distance + eval.define_function ("X", new AnnotationEvalFunction('X', &eval, index)); // x delta + eval.define_function ("Y", new AnnotationEvalFunction('Y', &eval, index)); // y delta + eval.define_function ("U", new AnnotationEvalFunction('U', &eval, index)); // p1.x + eval.define_function ("V", new AnnotationEvalFunction('V', &eval, index)); // p1.y + eval.define_function ("P", new AnnotationEvalFunction('P', &eval, index)); // p2.x + eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval, index)); // p2.y + eval.define_function ("A", new AnnotationEvalFunction('A', &eval, index)); // area mm2 return eval.interpolate (fmt); } @@ -343,6 +464,9 @@ Object::class_name () const void Object::from_string (const char *s, const char * /*base_dir*/) { + m_points.clear (); + point_list new_points; + tl::Extractor ex (s); while (! ex.at_end ()) { @@ -408,6 +532,14 @@ Object::from_string (const char *s, const char * /*base_dir*/) p.set_y (q); p2 (p); + } else if (ex.test ("pt=")) { + + double x = 0.0, y = 0.0; + ex.read (x); + ex.expect (":"); + ex.read (y); + new_points.push_back (db::DPoint (x, y)); + } else if (ex.test ("position=")) { std::string s; @@ -518,6 +650,10 @@ Object::from_string (const char *s, const char * /*base_dir*/) ex.test (","); } + + if (! new_points.empty ()) { + set_points (new_points); + } } std::string @@ -529,18 +665,28 @@ Object::to_string () const r += tl::to_string (id ()); r += ","; - r += "x1="; - r += tl::to_string (p1 ().x ()); - r += ","; - r += "y1="; - r += tl::to_string (p1 ().y ()); - r += ","; - r += "x2="; - r += tl::to_string (p2 ().x ()); - r += ","; - r += "y2="; - r += tl::to_string (p2 ().y ()); - r += ","; + if (m_points.size () > 2) { + for (auto p = m_points.begin (); p != m_points.end (); ++p) { + r += "pt="; + r += tl::to_string (p->x ()); + r += ":"; + r += tl::to_string (p->y ()); + r += ","; + } + } else { + r += "x1="; + r += tl::to_string (p1 ().x ()); + r += ","; + r += "y1="; + r += tl::to_string (p1 ().y ()); + r += ","; + r += "x2="; + r += tl::to_string (p2 ().x ()); + r += ","; + r += "y2="; + r += tl::to_string (p2 ().y ()); + r += ","; + } r += "category="; r += tl::to_word_or_quoted_string (category ()); diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h index 3fe1422a8..6358417c0 100644 --- a/src/ant/ant/antObject.h +++ b/src/ant/ant/antObject.h @@ -50,6 +50,7 @@ class ANT_PUBLIC Object { public: typedef db::coord_traits coord_traits; + typedef std::vector point_list; /** * @brief The ruler style @@ -109,11 +110,21 @@ public: */ Object (const db::DPoint &p1, const db::DPoint &p2, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint); + /** + * @brief Parametrized constructor and a list of points + */ + Object (const point_list &points, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint); + /** * @brief Parametrized constructor from a template */ Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::Template &d); + /** + * @brief Parametrized constructor from a template and a list of points + */ + Object (const point_list &points, int id, const ant::Template &d); + /** * @brief Copy constructor */ @@ -185,8 +196,9 @@ public: */ virtual void transform (const db::DCplxTrans &t) { - m_p1 = t * m_p1; - m_p2 = t * m_p2; + for (auto p = m_points.begin (); p != m_points.end (); ++p) { + *p = t * *p; + } property_changed (); } @@ -195,8 +207,9 @@ public: */ virtual void transform (const db::DTrans &t) { - m_p1 = t * m_p1; - m_p2 = t * m_p2; + for (auto p = m_points.begin (); p != m_points.end (); ++p) { + *p = t * *p; + } property_changed (); } @@ -205,8 +218,9 @@ public: */ virtual void transform (const db::DFTrans &t) { - m_p1 = t * m_p1; - m_p2 = t * m_p2; + for (auto p = m_points.begin (); p != m_points.end (); ++p) { + *p = t * *p; + } property_changed (); } @@ -224,10 +238,11 @@ public: /** * @brief Moves the object by the given distance */ - Object &move (const db::DVector &p) + Object &move (const db::DVector &d) { - m_p1 += p; - m_p2 += p; + for (auto p = m_points.begin (); p != m_points.end (); ++p) { + *p += d; + } return *this; } @@ -265,42 +280,71 @@ public: } /** - * @brief Gets the first definition point + * @brief Gets the ruler's definition points */ - const db::DPoint &p1 () const + const point_list &points () const { - return m_p1; + return m_points; + } + + /** + * @brief Sets the ruler's definition points + */ + void set_points (const point_list &points); + + /** + * @brief Gets the first point of the indicated segment + */ + db::DPoint seg_p1 (size_t seg_index) const; + + /** + * @brief Gets the second point of the indicated segment + */ + db::DPoint seg_p2 (size_t seg_index) const; + + /** + * @brief Gets the number of segments + * + * The number of segments is at least 1 for backward compatibility. + */ + size_t segments () const + { + return m_points.size () < 2 ? 1 : m_points.size () - 1; + } + + /** + * @brief Gets the first definition point + * + * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval. + */ + db::DPoint p1 () const + { + return seg_p1 (0); } /** * @brief Gets the second definition point + * + * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval. */ - const db::DPoint &p2 () const + db::DPoint p2 () const { - return m_p2; + return seg_p2 (0); } /** * @brief Sets the first definition point + * + * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval. */ - void p1 (const db::DPoint &p) - { - if (!m_p1.equal (p)) { - m_p1 = p; - property_changed (); - } - } + void p1 (const db::DPoint &p); /** * @brief Sets the second definition point + * + * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval. */ - void p2 (const db::DPoint &p) - { - if (!m_p2.equal (p)) { - m_p2 = p; - property_changed (); - } - } + void p2 (const db::DPoint &p); /** * @brief Gets the ID of the annotation object @@ -619,52 +663,52 @@ public: /** * @brief Gets the formatted text for the x label */ - std::string text_x () const + std::string text_x (size_t index) const { - return formatted (m_fmt_x, db::DFTrans ()); + return formatted (m_fmt_x, db::DFTrans (), index); } /** * @brief Gets the formatted text for the y label */ - std::string text_y () const + std::string text_y (size_t index) const { - return formatted (m_fmt_y, db::DFTrans ()); + return formatted (m_fmt_y, db::DFTrans (), index); } /** * @brief Gets the formatted text for the main label */ - std::string text () const + std::string text (size_t index) const { - return formatted (m_fmt, db::DFTrans ()); + return formatted (m_fmt, db::DFTrans (), index); } /** * @brief Gets the formatted text for the x label * @param t The transformation to apply to the vector before producing the text */ - std::string text_x (const db::DFTrans &t) const + std::string text_x (size_t index, const db::DFTrans &t) const { - return formatted (m_fmt_x, t); + return formatted (m_fmt_x, t, index); } /** * @brief Gets the formatted text for the y label * @param t The transformation to apply to the vector before producing the text */ - std::string text_y (const db::DFTrans &t) const + std::string text_y (size_t index, const db::DFTrans &t) const { - return formatted (m_fmt_y, t); + return formatted (m_fmt_y, t, index); } /** * @brief Gets the formatted text for the main label * @param t The transformation to apply to the vector before producing the text */ - std::string text (const db::DFTrans &t) const + std::string text (size_t index, const db::DFTrans &t) const { - return formatted (m_fmt, t); + return formatted (m_fmt, t, index); } /** @@ -695,7 +739,7 @@ protected: virtual void property_changed (); private: - db::DPoint m_p1, m_p2; + point_list m_points; int m_id; std::string m_fmt_x; std::string m_fmt_y; @@ -710,7 +754,7 @@ private: alignment_type m_xlabel_xalign, m_xlabel_yalign; alignment_type m_ylabel_xalign, m_ylabel_yalign; - std::string formatted (const std::string &fmt, const db::DFTrans &trans) const; + std::string formatted (const std::string &fmt, const db::DFTrans &trans, size_t index) const; }; } diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc index b381c9c11..7b81af0f0 100644 --- a/src/ant/ant/antPropertiesPage.cc +++ b/src/ant/ant/antPropertiesPage.cc @@ -25,6 +25,7 @@ #include "antPropertiesPage.h" #include "layLayoutViewBase.h" #include "layQtTools.h" +#include "tlException.h" namespace ant { @@ -33,7 +34,7 @@ namespace ant // PropertiesPage implementation PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWidget *parent) - : lay::PropertiesPage (parent, manager, rulers), mp_rulers (rulers), m_enable_cb_callback (true) + : lay::PropertiesPage (parent, manager, rulers), mp_rulers (rulers), m_enable_cb_callback (true), m_in_text_changed (false) { mp_rulers->get_selection (m_selection); m_pos = m_selection.begin (); @@ -56,8 +57,10 @@ PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWid connect (fmt_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); connect (fmt_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); connect (fmt_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (x0, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); connect (x1, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); connect (x2, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (y0, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); connect (y1, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); connect (y2, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); @@ -71,6 +74,8 @@ PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWid connect (ylabel_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ())); connect (ylabel_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ())); + connect (points_edit, SIGNAL (textChanged ()), this, SLOT (text_changed ())); + } else { fmt_le->setReadOnly (true); @@ -172,6 +177,80 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2) p2 = db::DPoint (dx2, dy2); } +void +PropertiesPage::get_point (db::DPoint &p) +{ + double dx = 0.0, dy = 0.0; + bool has_error = false; + + try { + tl::from_string_ext (tl::to_string (x0->text ()), dx); + lay::indicate_error (x0, (tl::Exception *) 0); + } catch (tl::Exception &ex) { + lay::indicate_error (x0, &ex); + has_error = true; + } + + try { + tl::from_string_ext (tl::to_string (y0->text ()), dy); + lay::indicate_error (y0, (tl::Exception *) 0); + } catch (tl::Exception &ex) { + lay::indicate_error (y0, &ex); + has_error = true; + } + + if (has_error) { + throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields"))); + } + + p = db::DPoint (dx, dy); +} + +void +PropertiesPage::get_points (ant::Object::point_list &points) +{ + std::string coordinates = tl::to_string (points_edit->toPlainText ()); + points.clear (); + + try { + + tl::Extractor ex (coordinates.c_str ()); + while (! ex.at_end ()) { + double x = 0.0, y = 0.0; + ex.read (x); + ex.test (","); + ex.read (y); + ex.test (";"); + ex.test (","); + points.push_back (db::DPoint (x, y)); + } + + lay::indicate_error (points_edit, (tl::Exception *) 0); + + } catch (tl::Exception &ex) { + lay::indicate_error (points_edit, &ex); + throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields"))); + } +} + +void +PropertiesPage::text_changed () +{ + if (m_in_text_changed) { + return; + } + + try { + m_in_text_changed = true; + update_with (get_object ()); + emit edited (); + m_in_text_changed = false; + } catch (...) { + m_in_text_changed = false; + // ignore exceptions - the edit field will be highlighted anyway + } +} + void PropertiesPage::snap_to_layout_clicked () { @@ -296,32 +375,74 @@ void PropertiesPage::update () { mp_rulers->highlight (std::distance (m_selection.begin (), m_pos)); + update_with (current ()); +} - fmt_le->setText (tl::to_qstring (current ().fmt ())); - fmt_x_le->setText (tl::to_qstring (current ().fmt_x ())); - fmt_y_le->setText (tl::to_qstring (current ().fmt_y ())); - style_cb->setCurrentIndex (current ().style ()); - outline_cb->setCurrentIndex (current ().outline ()); +void +PropertiesPage::update_with (const ant::Object &obj) +{ + fmt_le->setText (tl::to_qstring (obj.fmt ())); + fmt_x_le->setText (tl::to_qstring (obj.fmt_x ())); + fmt_y_le->setText (tl::to_qstring (obj.fmt_y ())); + style_cb->setCurrentIndex (obj.style ()); + outline_cb->setCurrentIndex (obj.outline ()); - x1->setText (tl::to_qstring (tl::micron_to_string (current ().p1 ().x ()))); + main_position->setCurrentIndex (obj.main_position ()); + main_xalign->setCurrentIndex (obj.main_xalign ()); + main_yalign->setCurrentIndex (obj.main_yalign ()); + xlabel_xalign->setCurrentIndex (obj.xlabel_xalign ()); + xlabel_yalign->setCurrentIndex (obj.xlabel_yalign ()); + ylabel_xalign->setCurrentIndex (obj.ylabel_xalign ()); + ylabel_yalign->setCurrentIndex (obj.ylabel_yalign ()); + + int tab = 2; + if (obj.points ().size () == 1) { + tab = 0; + } else if (obj.points ().size () == 2) { + tab = 1; + } + + segments_tab->setTabEnabled (0, tab == 0); + segments_tab->setTabEnabled (1, tab == 1); + + if (! m_in_text_changed) { + segments_tab->setCurrentIndex (tab); + } + + point_list->clear (); + for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) { + QTreeWidgetItem *item = new QTreeWidgetItem (point_list); + item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (tl::to_string (p->x ())))); + item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (tl::to_string (p->y ())))); + } + + if (! m_in_text_changed) { + std::string text; + for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) { + text += tl::to_string (p->x ()); + text += ", "; + text += tl::to_string (p->y ()); + text += "\n"; + } + points_edit->setPlainText (tl::to_qstring (text)); + } + + x0->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().x ()))); + x0->setCursorPosition (0); + y0->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().y ()))); + y0->setCursorPosition (0); + + x1->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().x ()))); x1->setCursorPosition (0); - x2->setText (tl::to_qstring (tl::micron_to_string (current ().p2 ().x ()))); + x2->setText (tl::to_qstring (tl::micron_to_string (obj.p2 ().x ()))); x2->setCursorPosition (0); - y1->setText (tl::to_qstring (tl::micron_to_string (current ().p1 ().y ()))); + y1->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().y ()))); y1->setCursorPosition (0); - y2->setText (tl::to_qstring (tl::micron_to_string (current ().p2 ().y ()))); + y2->setText (tl::to_qstring (tl::micron_to_string (obj.p2 ().y ()))); y2->setCursorPosition (0); - main_position->setCurrentIndex (current ().main_position ()); - main_xalign->setCurrentIndex (current ().main_xalign ()); - main_yalign->setCurrentIndex (current ().main_yalign ()); - xlabel_xalign->setCurrentIndex (current ().xlabel_xalign ()); - xlabel_yalign->setCurrentIndex (current ().xlabel_yalign ()); - ylabel_xalign->setCurrentIndex (current ().ylabel_xalign ()); - ylabel_yalign->setCurrentIndex (current ().ylabel_yalign ()); - - double sx = (current ().p2 ().x () - current ().p1 ().x ()); - double sy = (current ().p2 ().y () - current ().p1 ().y ()); + double sx = (obj.p2 ().x () - obj.p1 ().x ()); + double sy = (obj.p2 ().y () - obj.p1 ().y ()); dx->setText (tl::to_qstring (tl::micron_to_string (sx))); dx->setCursorPosition (0); dy->setText (tl::to_qstring (tl::micron_to_string (sy))); @@ -339,9 +460,13 @@ PropertiesPage::readonly () void PropertiesPage::apply () { - // only adjust the values if the text has changed - db::DPoint p1, p2; - get_points (p1, p2); + mp_rulers->change_ruler (*m_pos, get_object ()); +} + +ant::Object +PropertiesPage::get_object () +{ + ant::Object ruler; std::string fmt = tl::to_string (fmt_le->text ()); std::string fmt_x = tl::to_string (fmt_x_le->text ()); @@ -349,7 +474,26 @@ PropertiesPage::apply () Object::style_type style = Object::style_type (style_cb->currentIndex ()); Object::outline_type outline = Object::outline_type (outline_cb->currentIndex ()); - ant::Object ruler (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ()); + if (segments_tab->currentIndex () == 0 || segments_tab->currentIndex () == 1) { + + db::DPoint p1, p2; + if (segments_tab->currentIndex () == 0) { + get_points (p1, p2); + } else { + get_point (p1); + p2 = p1; + } + + ruler = ant::Object (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ()); + + } else if (segments_tab->currentIndex () == 2 || segments_tab->currentIndex () == 3) { + + ant::Object::point_list points; + get_points (points); + + ruler = ant::Object (points, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ()); + + } ruler.set_main_position (Object::position_type (main_position->currentIndex ())); ruler.set_main_xalign (Object::alignment_type (main_xalign->currentIndex ())); @@ -361,7 +505,7 @@ PropertiesPage::apply () ruler.set_category (current ().category ()); - mp_rulers->change_ruler (*m_pos, ruler); + return ruler; } } diff --git a/src/ant/ant/antPropertiesPage.h b/src/ant/ant/antPropertiesPage.h index 8e50f4dc4..26e351e2d 100644 --- a/src/ant/ant/antPropertiesPage.h +++ b/src/ant/ant/antPropertiesPage.h @@ -52,20 +52,26 @@ public: virtual void update (); virtual void leave (); virtual bool readonly (); - virtual void apply (); + virtual void apply (); private slots: void swap_points_clicked (); void snap_to_layout_clicked (); + void text_changed (); private: std::vector m_selection; std::vector ::iterator m_pos; ant::Service *mp_rulers; bool m_enable_cb_callback; + bool m_in_text_changed; const ant::Object ¤t () const; - void get_points(db::DPoint &p1, db::DPoint &p2); + void get_points (db::DPoint &p1, db::DPoint &p2); + void get_point (db::DPoint &p); + void get_points (ant::Object::point_list &points); + void update_with (const ant::Object &obj); + ant::Object get_object (); }; } diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index b7a4f55a9..a93c05885 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -570,21 +570,23 @@ draw_ellipse (const db::DPoint &q1, } void -draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer) +draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer) { + db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index); + // round the starting point, shift both, and round the end point - std::pair v = lay::snap (trans * ruler.p1 (), trans * ruler.p2 ()); + std::pair v = lay::snap (trans * p1, trans * p2); db::DPoint q1 = v.first; db::DPoint q2 = v.second; bool xy_swapped = ((trans.rot () % 2) != 0); - double lu = ruler.p1 ().double_distance (ruler.p2 ()); + double lu = p1.double_distance (p2); int min_tick_spc = int (0.5 + 20 / renderer.resolution ()); // min tick spacing in canvas units double mu = double (min_tick_spc) / trans.ctrans (1.0); if (ruler.outline () == Object::OL_diag) { draw_ruler (q1, q2, lu, mu, sel, q2.x () < q1.x (), ruler.style (), bitmap, renderer); - draw_text (q1, q2, lu, ruler.text (), q2.x () < q1.x (), ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); + draw_text (q1, q2, lu, ruler.text (index), q2.x () < q1.x (), ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); } if ((!xy_swapped && (ruler.outline () == Object::OL_xy || ruler.outline () == Object::OL_diag_xy)) || @@ -594,12 +596,12 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay if (ruler.outline () == Object::OL_diag_xy || ruler.outline () == Object::OL_diag_yx) { draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer); - draw_text (q1, q2, lu, ruler.text (), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); + draw_text (q1, q2, lu, ruler.text (index), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); } draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer); - draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); + draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer); - draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); + draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); } @@ -610,12 +612,12 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay if (ruler.outline () == Object::OL_diag_xy || ruler.outline () == Object::OL_diag_yx) { draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer); - draw_text (q1, q2, lu, ruler.text (), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); + draw_text (q1, q2, lu, ruler.text (index), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); } draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer); - draw_text (q1, db::DPoint (q1.x (), q2.y ()), lu, ruler.text_y (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); + draw_text (q1, db::DPoint (q1.x (), q2.y ()), lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer); - draw_text (db::DPoint (q1.x (), q2.y ()), q2, lu, ruler.text_x (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); + draw_text (db::DPoint (q1.x (), q2.y ()), q2, lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); } @@ -624,34 +626,43 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ()); draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer); - draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); + draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer); - draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); + draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, !r, ruler.style (), bitmap, renderer); draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer); - draw_text (q1, q2, lu, ruler.text (), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); + draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); } else if (ruler.outline () == Object::OL_ellipse) { bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ()); - draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); - draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); - draw_text (q1, q2, lu, ruler.text (), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); + draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer); + draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer); + draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer); draw_ellipse (q1, q2, lu, sel, bitmap, renderer); } } -static bool -is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance) +void +draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer) { + for (size_t index = 0; index < ruler.segments (); ++index) { + draw_ruler_segment (ruler, index, trans, sel, bitmap, renderer); + } +} + +static bool +is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, double enl, double &distance) +{ + db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index); + db::DBox b (p1, p2); + if (ruler.outline () == ant::Object::OL_ellipse) { // special handling of the (non-degenerated) ellipse case - db::DBox b (ruler.p1 (), ruler.p2 ()); - if (b.height () > 1e-6 && b.width () > 1e-6) { double dx = (pos.x () - b.center ().x ()) / (b.width () * 0.5); @@ -674,8 +685,6 @@ is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double } - db::DBox b (ruler.p1 (), ruler.p2 ()); - // enlarge this box by some pixels b.enlarge (db::DVector (enl, enl)); @@ -717,10 +726,23 @@ is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double return false; } +static bool +is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance) +{ + bool any = false; + for (size_t index = 0; index < ruler.segments (); ++index) { + // NOTE: we check *all* since distance is updated herein. + if (is_selected (ruler, index, pos, enl, distance)) { + any = true; + } + } + return any; +} + static bool is_selected (const ant::Object &ruler, const db::DBox &box, double /*enl*/) { - return (box.contains (ruler.p1 ()) && box.contains (ruler.p2 ())); + return ruler.box ().inside (box); } @@ -2180,7 +2202,11 @@ Service::display_status (bool transient) if (! transient) { msg = tl::to_string (tr ("selected: ")); } - msg += tl::sprintf (tl::to_string (tr ("annotation(d=%s x=%s y=%s)")), ruler->text (), ruler->text_x (), ruler->text_y ()); + if (ruler->segments () > 1) { + msg += tl::sprintf (tl::to_string (tr ("annotation(d=%s x=%s y=%s ...)")), ruler->text (0), ruler->text_x (0), ruler->text_y (0)); + } else { + msg += tl::sprintf (tl::to_string (tr ("annotation(d=%s x=%s y=%s)")), ruler->text (0), ruler->text_x (0), ruler->text_y (0)); + } view ()->message (msg); } diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc index a1284d3ff..949cb5c09 100644 --- a/src/ant/ant/gsiDeclAnt.cc +++ b/src/ant/ant/gsiDeclAnt.cc @@ -236,6 +236,13 @@ static AnnotationRef create_measure_ruler (lay::LayoutViewBase *view, const db:: } } +static AnnotationRef *ant_from_s (const std::string &s) +{ + std::unique_ptr aref (new AnnotationRef ()); + aref->from_string (s.c_str ()); + return aref.release (); +} + static int get_style (const AnnotationRef *obj) { return int (obj->style ()); @@ -704,27 +711,80 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat "\n" "This method has been introduced in version 0.25." ) + - gsi::method ("p1", (const db::DPoint & (AnnotationRef::*) () const) &AnnotationRef::p1, + gsi::method ("points", &AnnotationRef::points, + "@brief Gets the points of the ruler\n" + "A single-segmented ruler has two points. Rulers with more points " + "have more segments correspondingly. Note that the point list may have one point " + "only (single-point ruler) or may even be empty.\n" + "\n" + "Use \\points= to set the segment points. Use \\segments to get the number of " + "segments and \\seg_p1 and \\seg_p2 to get the first and second point of one segment.\n" + "\n" + "Multi-segmented rulers have been introduced in version 0.28" + ) + + gsi::method ("points=", &AnnotationRef::set_points, gsi::arg ("points"), + "@brief Sets the points for a (potentially) multi-segmented ruler\n" + "See \\points for a description of multi-segmented rulers. " + "The list of points passed to this method is cleaned from duplicates before being " + "stored inside the ruler.\n" + "\n" + "This method has been introduced in version 0.28." + ) + + gsi::method ("segments", &AnnotationRef::segments, + "@brief Gets the number of segments.\n" + "This method returns the number of segments the ruler is made up. Even though the " + "ruler can be one or even zero points, the number of segments is at least 1.\n" + "\n" + "This method has been introduced in version 0.28." + ) + + gsi::method ("seg_p1", &AnnotationRef::seg_p1, gsi::arg ("segment_index"), + "@brief Gets the first point of the given segment.\n" + "The segment is indicated by the segment index which is a number between 0 and \\segments-1.\n" + "\n" + "This method has been introduced in version 0.28." + ) + + gsi::method ("seg_p2", &AnnotationRef::seg_p2, gsi::arg ("segment_index"), + "@brief Gets the second point of the given segment.\n" + "The segment is indicated by the segment index which is a number between 0 and \\segments-1.\n" + "The second point of a segment is also the first point of the following segment if there is one.\n" + "\n" + "This method has been introduced in version 0.28." + ) + + gsi::method ("p1", (db::DPoint (AnnotationRef::*) () const) &AnnotationRef::p1, "@brief Gets the first point of the ruler or marker\n" "The points of the ruler or marker are always given in micron units in floating-point " "coordinates.\n" + "\n" + "This method is provided for backward compatibility. Starting with version 0.28, rulers can " + "be multi-segmented. Use \\points or \\seg_p1 to retrieve the points of the ruler segments.\n" + "\n" "@return The first point\n" ) + - gsi::method ("p2", (const db::DPoint & (AnnotationRef::*) () const) &AnnotationRef::p2, + gsi::method ("p2", (db::DPoint (AnnotationRef::*) () const) &AnnotationRef::p2, "@brief Gets the second point of the ruler or marker\n" "The points of the ruler or marker are always given in micron units in floating-point " "coordinates.\n" + "\n" + "This method is provided for backward compatibility. Starting with version 0.28, rulers can " + "be multi-segmented. Use \\points or \\seg_p1 to retrieve the points of the ruler segments.\n" + "\n" "@return The second point\n" ) + gsi::method ("p1=", (void (AnnotationRef::*) (const db::DPoint &)) &AnnotationRef::p1, gsi::arg ("point"), "@brief Sets the first point of the ruler or marker\n" "The points of the ruler or marker are always given in micron units in floating-point " "coordinates.\n" + "\n" + "This method is provided for backward compatibility. Starting with version 0.28, rulers can " + "be multi-segmented. Use \\points= to specify the ruler segments.\n" ) + gsi::method ("p2=", (void (AnnotationRef::*) (const db::DPoint &)) &AnnotationRef::p2, gsi::arg ("point"), "@brief Sets the second point of the ruler or marker\n" "The points of the ruler or marker are always given in micron units in floating-point " "coordinates.\n" + "\n" + "This method is provided for backward compatibility. Starting with version 0.28, rulers can " + "be multi-segmented. Use \\points= to specify the ruler segments.\n" ) + gsi::method ("box", &AnnotationRef::box, "@brief Gets the bounding box of the object (not including text)\n" @@ -924,14 +984,17 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat "@brief Returns the angle constraint attribute\n" "See \\angle_constraint= for a more detailed description." ) + - gsi::method ("text_x", (std::string (AnnotationRef::*)() const) &AnnotationRef::text_x, - "@brief Returns the formatted text for the x-axis label" + gsi::method ("text_x", (std::string (AnnotationRef::*)(size_t index) const) &AnnotationRef::text_x, gsi::arg ("index", 0), + "@brief Returns the formatted text for the x-axis label\n" + "The index parameter indicates which segment to use (0 is the first one). It has been added in version 0.28.\n" ) + - gsi::method ("text_y", (std::string (AnnotationRef::*)() const) &AnnotationRef::text_y, - "@brief Returns the formatted text for the y-axis label" + gsi::method ("text_y", (std::string (AnnotationRef::*)(size_t index) const) &AnnotationRef::text_y, gsi::arg ("index", 0), + "@brief Returns the formatted text for the y-axis label\n" + "The index parameter indicates which segment to use (0 is the first one). It has been added in version 0.28.\n" ) + - gsi::method ("text", (std::string (AnnotationRef::*)() const) &AnnotationRef::text, - "@brief Returns the formatted text for the main label" + gsi::method ("text", (std::string (AnnotationRef::*)(size_t index) const) &AnnotationRef::text, gsi::arg ("index", 0), + "@brief Returns the formatted text for the main label\n" + "The index parameter indicates which segment to use (0 is the first one). It has been added in version 0.28.\n" ) + gsi::method ("id", (int (AnnotationRef::*)() const) &AnnotationRef::id, "@brief Returns the annotation's ID" @@ -953,6 +1016,12 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat "\n" "This method was introduced in version 0.19." ) + + gsi::constructor ("from_s", &ant_from_s, gsi::arg ("s"), + "@brief Creates a ruler from a string representation\n" + "This function creates a ruler from the string returned by \\to_s.\n" + "\n" + "This method was introduced in version 0.28." + ) + gsi::method ("==", &AnnotationRef::operator==, gsi::arg ("other"), "@brief Equality operator\n" ) +