diff --git a/src/ant/RulerConfigPage4.ui b/src/ant/RulerConfigPage4.ui index feb37602b..44bd546f2 100644 --- a/src/ant/RulerConfigPage4.ui +++ b/src/ant/RulerConfigPage4.ui @@ -7,7 +7,7 @@ 0 0 668 - 373 + 410 @@ -169,7 +169,7 @@ - + QFrame::StyledPanel @@ -192,51 +192,13 @@ 6 - - + + ... position - - - - If checked, snap to edges or vertices of objects unless disabled above - - - Snap to objects - - - - - - - Outline - - - - - - - Specify the main label format - - - - - - - Label format - - - - - - - Angle constraints - - - @@ -244,18 +206,122 @@ - - + + - Style + Angle constraints - - - - Specify the y label format (applicable only for outline modes that have a vertical component, i.e. box) + + + + QFrame::NoFrame + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 148 + 20 + + + + + + + + H + + + + + + + + 0 + 0 + + + + + Auto + + + + + H. center + + + + + Left + + + + + Right + + + + + + + + V + + + + + + + + 0 + 0 + + + + + Auto + + + + + V. center + + + + + Bottom + + + + + Top + + + + + @@ -433,64 +499,41 @@ - - + + - ... position + X label format - - - - Override the global angle constraint setting for this type of rulers - - - - Any angle - - - - - Diagonal - - - - - Orthogonal - - - - - Horizontal only - - - - - Vertical only - - - - - Use global setting - - - - - - - - Y label format - - - - + <html>(See <a href="int:/manual/ruler_properties.xml">here</a> for a description of the properties)</html> + + + + Specify the y label format (applicable only for outline modes that have a vertical component, i.e. box) + + + + + + + Label format + + + + + + + Style + + + @@ -533,67 +576,81 @@ - - - - Specify style of the ruler template - - - - Ruler - - - - - Arrow at end - - - - - Arrow at start - - - - - Arrow at both ends - - - - - Plain line - - - - - Cross at end - - - - - Cross at start - - - - - Cross at both ends - - - - - - + + - X label format + Outline - - + + + + If checked, snap to edges or vertices of objects unless disabled above + + + Snap to objects + + + + + + + Specify the main label format + + + + + + + Y label format + + + + + ... position + + + + Override the global angle constraint setting for this type of rulers + + + + Any angle + + + + + Diagonal + + + + + Orthogonal + + + + + Horizontal only + + + + + Vertical only + + + + + Use global setting + + + + @@ -705,115 +762,84 @@ - - - - QFrame::NoFrame + + + + Specify style of the ruler template - - QFrame::Raised + + + Ruler + + + + + Arrow at end + + + + + Arrow at start + + + + + Arrow at both ends + + + + + Plain line + + + + + Cross at end + + + + + Cross at start + + + + + Cross at both ends + + + + + + + + ... position - - - 0 + + + + + + + Normal - - 0 + + + + Single click (both points will be equal) - - 0 + + + + Auto measure (points will be set automatically) - - 0 - - - - - Qt::Horizontal - - - - 148 - 20 - - - - - - - - H - - - - - - - - 0 - 0 - - - - - Auto - - - - - H. center - - - - - Left - - - - - Right - - - - - - - - V - - - - - - - - 0 - 0 - - - - - Auto - - - - - V. center - - - - - Bottom - - - - - Top - - - - - + + + + + + + Mode + diff --git a/src/ant/antConfig.cc b/src/ant/antConfig.cc index 5bb886519..70f19d5e2 100644 --- a/src/ant/antConfig.cc +++ b/src/ant/antConfig.cc @@ -230,6 +230,35 @@ AlignmentConverter::from_string (const std::string &s, ant::Object::alignment_ty } } +std::string +RulerModeConverter::to_string (ant::Template::ruler_mode_type m) +{ + if (m == ant::Template::RulerNormal) { + return "normal"; + } else if (m == ant::Template::RulerSingleClick) { + return "single_click"; + } else if (m == ant::Template::RulerAutoMetric) { + return "auto_metric"; + } else { + return "normal"; + } +} + +void +RulerModeConverter::from_string (const std::string &s, ant::Template::ruler_mode_type &a) +{ + std::string t (tl::trim (s)); + if (t == "normal") { + a = ant::Template::RulerNormal; + } else if (t == "single_click") { + a = ant::Template::RulerSingleClick; + } else if (t == "auto_metric") { + a = ant::Template::RulerAutoMetric; + } else { + a = ant::Template::RulerNormal; + } +} + std::string TemplatesConverter::to_string (const std::vector &t) { diff --git a/src/ant/antConfig.h b/src/ant/antConfig.h index 8b94b6a09..ee6060d5a 100644 --- a/src/ant/antConfig.h +++ b/src/ant/antConfig.h @@ -81,6 +81,12 @@ struct AlignmentConverter void from_string (const std::string &s, ant::Object::alignment_type &a); }; +struct RulerModeConverter +{ + std::string to_string (ant::Template::ruler_mode_type a); + void from_string (const std::string &s, ant::Template::ruler_mode_type &a); +}; + struct TemplatesConverter { std::string to_string (const std::vector &t); diff --git a/src/ant/antConfigPage.cc b/src/ant/antConfigPage.cc index 794c82548..58b2433f3 100644 --- a/src/ant/antConfigPage.cc +++ b/src/ant/antConfigPage.cc @@ -355,6 +355,7 @@ ConfigPage4::show () mp_ui->outline_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].outline ()); mp_ui->t_angle_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].angle_constraint ()); mp_ui->t_snap_cbx->setChecked (m_ruler_templates [m_current_template].snap ()); + mp_ui->t_mode_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].mode ()); mp_ui->main_position->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].main_position ()); mp_ui->main_xalign->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].main_xalign ()); @@ -385,6 +386,9 @@ ConfigPage4::commit () lay::angle_constraint_type ac = lay::angle_constraint_type (mp_ui->t_angle_cb->currentIndex ()); m_ruler_templates [m_current_template].angle_constraint (ac); + ant::Template::ruler_mode_type mode = ant::Template::ruler_mode_type (mp_ui->t_mode_cb->currentIndex ()); + m_ruler_templates [m_current_template].set_mode (mode); + m_ruler_templates [m_current_template].snap (mp_ui->t_snap_cbx->isChecked ()); m_ruler_templates [m_current_template].set_main_position (Object::position_type (mp_ui->main_position->currentIndex ())); diff --git a/src/ant/antObject.cc b/src/ant/antObject.cc index cbb95f967..a49091d7f 100644 --- a/src/ant/antObject.cc +++ b/src/ant/antObject.cc @@ -63,6 +63,7 @@ Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::T 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 ()), diff --git a/src/ant/antService.cc b/src/ant/antService.cc index a7201acfe..6159fa44b 100644 --- a/src/ant/antService.cc +++ b/src/ant/antService.cc @@ -125,7 +125,7 @@ draw_ruler (const db::DPoint &q1, double arrow_length = 12 / renderer.resolution (); double sel_width = 2 / renderer.resolution (); - if (length_u < 1e-5 /*micron*/) { + if (length_u < 1e-5 /*micron*/ && style != ant::Object::STY_cross_both && style != ant::Object::STY_cross_end && style != ant::Object::STY_cross_start) { if (sel) { @@ -153,7 +153,7 @@ draw_ruler (const db::DPoint &q1, // normal and unit vector double len = q1.double_distance (q2); - if (style == ant::Object::STY_arrow_end && len < double (arrow_length) * 1.2) { + if ((style == ant::Object::STY_arrow_end || style == ant::Object::STY_arrow_start) && len < double (arrow_length) * 1.2) { arrow_length = len / 1.2; arrow_width = arrow_length * 2.0 / 3.0; } else if (style == ant::Object::STY_arrow_both && len < double (arrow_length) * 2.4) { @@ -165,7 +165,7 @@ draw_ruler (const db::DPoint &q1, if (len > 1e-10) { qq *= 1.0 / len; } else { - qq = db::DVector (1.0, 0.0); + qq = db::DVector (0.0, 1.0); } if (!right) { qq = -qq; @@ -340,7 +340,7 @@ draw_text (const db::DPoint &q1, pos = ant::Object::POS_p2; } - if (length_u < 1e-5 /*micron*/) { + if (length_u < 1e-5 /*micron*/ && style != ant::Object::STY_cross_both && style != ant::Object::STY_cross_end && style != ant::Object::STY_cross_start) { renderer.draw (db::DBox (q1, q1), label, @@ -357,7 +357,7 @@ draw_text (const db::DPoint &q1, // normal and unit vector double len = q1.double_distance (q2); - if (style == ant::Object::STY_arrow_end && len < double (arrow_length) * 1.2) { + if ((style == ant::Object::STY_arrow_end || style == ant::Object::STY_arrow_start) && len < double (arrow_length) * 1.2) { arrow_length = len / 1.2; arrow_width = arrow_length * 2.0 / 3.0; } else if (style == ant::Object::STY_arrow_both && len < double (arrow_length) * 2.4) { @@ -369,17 +369,26 @@ draw_text (const db::DPoint &q1, if (len > 1e-10) { qq *= 1.0 / len; } else { - qq = db::DVector (1.0, 0.0); + qq = db::DVector (0.0, 1.0); } if (!right) { qq = -qq; } + db::DVector qu = q2 - q1; + if (len > 1e-10) { + qu *= 1.0 / len; + } else { + qu = db::DVector (1.0, 0.0); + } + db::HAlign text_halign = db::HAlignCenter; if (halign == ant::Object::AL_auto) { // Compute a nice alignment depending on the anchor point if (fabs (qq.x ()) > 1e-6) { text_halign = qq.x () > 0.0 ? db::HAlignLeft : db::HAlignRight; + } else if (length_u < 1e-5) { + text_halign = db::HAlignLeft; } else if (pos == ant::Object::POS_p2) { text_halign = q2.x () < q1.x () ? db::HAlignLeft : db::HAlignRight; } else if (pos == ant::Object::POS_p1) { @@ -396,7 +405,9 @@ draw_text (const db::DPoint &q1, db::VAlign text_valign = db::VAlignCenter; if (valign == ant::Object::AL_auto) { // Compute a nice alignment depending on the anchor point - if (fabs (qq.y ()) > 1e-6) { + if (length_u < 1e-5) { + text_valign = db::VAlignBottom; + } else if (fabs (qq.y ()) > 1e-6) { text_valign = qq.y () > 0.0 ? db::VAlignBottom : db::VAlignTop; } else if (pos == ant::Object::POS_p2) { text_valign = q1.y () > q2.y () ? db::VAlignBottom : db::VAlignTop; @@ -415,7 +426,17 @@ draw_text (const db::DPoint &q1, if (style == ant::Object::STY_arrow_start || style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_end) { tv_text = qq * (arrow_width * 0.5 + 2.0); } else if (style == ant::Object::STY_cross_start || style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_end) { - tv_text = qq * (arrow_width + 2.0); + if (length_u < 1e-5 /*micron*/) { + if (text_halign == db::HAlignRight) { + tv_text = (qq - qu) * 2.0; + } else if (text_halign == db::HAlignLeft) { + tv_text = (qq + qu) * 2.0; + } else { + tv_text = qq * 2.0; + } + } else { + tv_text = qq * (arrow_width + 2.0); + } } else { tv_text = qq * (tick_length + 2.0); } @@ -1366,21 +1387,40 @@ 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); - m_p1 = snap1 (p, m_obj_snap && current_template ().snap ()).second; + const ant::Template &tpl = current_template (); + + m_p1 = snap1 (p, m_obj_snap && tpl.snap ()).second; // create and start dragging the ruler - m_current = ant::Object (m_p1, m_p1, 0, current_template ()); - show_message (); - - if (mp_active_ruler) { - delete mp_active_ruler; - } - mp_active_ruler = new ant::View (this, &m_current, false /*not selected*/); - mp_active_ruler->thaw (); - m_drawing = true; + if (tpl.mode () == ant::Template::RulerSingleClick) { - widget ()->grab_mouse (this, false); + // begin the transaction + tl_assert (! manager ()->transacting ()); + manager ()->transaction (tl::to_string (QObject::tr ("Create ruler"))); + + show_message (); + + insert_ruler (ant::Object (m_p1, m_p1, 0, tpl), true); + + // end the transaction + manager ()->commit (); + + } else { + + m_current = ant::Object (m_p1, m_p1, 0, tpl); + show_message (); + + if (mp_active_ruler) { + delete mp_active_ruler; + } + mp_active_ruler = new ant::View (this, &m_current, false /*not selected*/); + mp_active_ruler->thaw (); + m_drawing = true; + + widget ()->grab_mouse (this, false); + + } } else { @@ -2046,6 +2086,33 @@ Service::menu_activated (const std::string &symbol) } } +void +Service::register_annotation_template (const ant::Template &t) +{ + std::string value = lay::PluginRoot::instance ()->config_get (cfg_ruler_templates); + + std::vector templates = ant::Template::from_string (value); + + // Remove a template with the same category if such a template already exists + if (! t.category ().empty ()) { + for (size_t i = 0; i < templates.size (); ) { + if (templates[i].category () == t.category ()) { + templates.erase (templates.begin () + i); + } else { + ++i; + } + } + } + + // and add the new one + templates.push_back (t); + + value = ant::Template::to_string (templates); + + lay::PluginRoot::instance ()->config_set (cfg_ruler_templates, value); + lay::PluginRoot::instance ()->config_end (); +} + // ------------------------------------------------------------- } // namespace ant diff --git a/src/ant/antService.h b/src/ant/antService.h index 6edaeccf2..c98bad8e3 100644 --- a/src/ant/antService.h +++ b/src/ant/antService.h @@ -437,6 +437,11 @@ public: * @brief An event triggered when the selected annotations changed */ tl::Event annotation_selection_changed_event; + + /** + * @brief Registers an annotation template globally + */ + static void register_annotation_template (const ant::Template &t); private: // Ruler display and snapping configuration diff --git a/src/ant/antTemplate.cc b/src/ant/antTemplate.cc index f799b702a..3f2a7559d 100644 --- a/src/ant/antTemplate.cc +++ b/src/ant/antTemplate.cc @@ -38,7 +38,8 @@ Template::Template () m_main_position (ant::Object::POS_auto), m_main_xalign (ant::Object::AL_auto), m_main_yalign (ant::Object::AL_auto), m_xlabel_xalign (ant::Object::AL_auto), m_xlabel_yalign (ant::Object::AL_auto), - m_ylabel_xalign (ant::Object::AL_auto), m_ylabel_yalign (ant::Object::AL_auto) + m_ylabel_xalign (ant::Object::AL_auto), m_ylabel_yalign (ant::Object::AL_auto), + m_mode (ant::Template::RulerNormal) { // .. nothing yet .. } @@ -53,20 +54,23 @@ Template::Template (const std::string &title, m_main_position (ant::Object::POS_auto), m_main_xalign (ant::Object::AL_auto), m_main_yalign (ant::Object::AL_auto), m_xlabel_xalign (ant::Object::AL_auto), m_xlabel_yalign (ant::Object::AL_auto), - m_ylabel_xalign (ant::Object::AL_auto), m_ylabel_yalign (ant::Object::AL_auto) + m_ylabel_xalign (ant::Object::AL_auto), m_ylabel_yalign (ant::Object::AL_auto), + m_mode (ant::Template::RulerNormal) { // .. nothing else .. } Template::Template (const ant::Template &d) : m_title (d.m_title), + m_category (d.m_category), 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), m_main_position (d.m_main_position), m_main_xalign (d.m_main_xalign), m_main_yalign (d.m_main_yalign), m_xlabel_xalign (d.m_xlabel_xalign), m_xlabel_yalign (d.m_xlabel_yalign), - m_ylabel_xalign (d.m_ylabel_xalign), m_ylabel_yalign (d.m_ylabel_yalign) + m_ylabel_xalign (d.m_ylabel_xalign), m_ylabel_yalign (d.m_ylabel_yalign), + m_mode (d.m_mode) { // .. nothing else .. } @@ -76,6 +80,7 @@ Template::operator= (const ant::Template &d) { if (this != &d) { m_title = d.m_title; + m_category = d.m_category; m_fmt_x = d.m_fmt_x; m_fmt_y = d.m_fmt_y; m_fmt = d.m_fmt; @@ -90,6 +95,7 @@ Template::operator= (const ant::Template &d) m_xlabel_yalign = d.m_xlabel_yalign; m_ylabel_xalign = d.m_ylabel_xalign; m_ylabel_yalign = d.m_ylabel_yalign; + m_mode = d.m_mode; } return *this; } @@ -109,13 +115,30 @@ Template::from_string (const std::string &s) while (! ex.at_end ()) { - if (ex.test ("title=")) { + if (ex.test ("mode=")) { + + std::string s; + ex.read_word_or_quoted (s); + ant::RulerModeConverter mc; + ant::Template::ruler_mode_type mode; + mc.from_string (s, mode); + r.back ().set_mode (mode); + ex.test (","); + + } else if (ex.test ("title=")) { std::string s; ex.read_word_or_quoted (s); r.back ().title (s); ex.test (","); + } else if (ex.test ("category=")) { + + std::string s; + ex.read_word_or_quoted (s); + r.back ().category (s); + ex.test (","); + } else if (ex.test ("fmt=")) { std::string s; @@ -276,9 +299,17 @@ Template::to_string (const std::vector