Implementing 'diagonal only' for rulers

This commit is contained in:
Matthias Koefferlein 2026-01-14 02:37:26 +01:00
parent cca73a8ebb
commit 6666b2b68c
14 changed files with 134 additions and 147 deletions

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>665</width> <width>665</width>
<height>103</height> <height>108</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -56,6 +56,13 @@
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
<item row="1" column="1">
<widget class="QRadioButton" name="ruler_diag_rb">
<property name="text">
<string>Diagonal</string>
</property>
</widget>
</item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QRadioButton" name="ruler_hor_rb"> <widget class="QRadioButton" name="ruler_hor_rb">
<property name="text"> <property name="text">
@ -77,17 +84,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="0" column="3">
<widget class="QRadioButton" name="ruler_diag_rb"> <widget class="QRadioButton" name="ruler_vert_rb">
<property name="text"> <property name="text">
<string>Diagonal</string> <string>Vertical only</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QRadioButton" name="ruler_vert_rb"> <widget class="QRadioButton" name="ruler_diag_only_rb">
<property name="text"> <property name="text">
<string>Vertical only</string> <string>Diagonal only</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -102,7 +109,6 @@
<tabstop>ruler_ortho_rb</tabstop> <tabstop>ruler_ortho_rb</tabstop>
<tabstop>ruler_diag_rb</tabstop> <tabstop>ruler_diag_rb</tabstop>
<tabstop>ruler_hor_rb</tabstop> <tabstop>ruler_hor_rb</tabstop>
<tabstop>ruler_vert_rb</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -644,6 +644,11 @@
<string>Orthogonal</string> <string>Orthogonal</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>Diagonal only</string>
</property>
</item>
<item> <item>
<property name="text"> <property name="text">
<string>Horizontal only</string> <string>Horizontal only</string>

View File

@ -29,47 +29,6 @@ namespace ant
// ------------------------------------------------------------ // ------------------------------------------------------------
// Helper functions to get and set the configuration // Helper functions to get and set the configuration
std::string
ACConverter::to_string (const lay::angle_constraint_type &m)
{
if (m == lay::AC_Any) {
return "any";
} else if (m == lay::AC_Diagonal) {
return "diagonal";
} else if (m == lay::AC_Ortho) {
return "ortho";
} else if (m == lay::AC_Horizontal) {
return "horizontal";
} else if (m == lay::AC_Vertical) {
return "vertical";
} else if (m == lay::AC_Global) {
return "global";
} else {
return "";
}
}
void
ACConverter::from_string (const std::string &tt, lay::angle_constraint_type &m)
{
std::string t (tl::trim (tt));
if (t == "any") {
m = lay::AC_Any;
} else if (t == "diagonal") {
m = lay::AC_Diagonal;
} else if (t == "ortho") {
m = lay::AC_Ortho;
} else if (t == "horizontal") {
m = lay::AC_Horizontal;
} else if (t == "vertical") {
m = lay::AC_Vertical;
} else if (t == "global") {
m = lay::AC_Global;
} else {
m = lay::AC_Any;
}
}
std::string std::string
StyleConverter::to_string (ant::Object::style_type s) StyleConverter::to_string (ant::Object::style_type s)
{ {

View File

@ -51,12 +51,6 @@ extern ANT_PUBLIC const std::string cfg_current_ruler_template;
// ------------------------------------------------------------ // ------------------------------------------------------------
// Helper functions to get and set the configuration // Helper functions to get and set the configuration
struct ACConverter
{
std::string to_string (const lay::angle_constraint_type &m);
void from_string (const std::string &s, lay::angle_constraint_type &m);
};
struct StyleConverter struct StyleConverter
{ {
std::string to_string (ant::Object::style_type s); std::string to_string (ant::Object::style_type s);

View File

@ -159,10 +159,11 @@ ConfigPage3::setup (lay::Dispatcher *root)
{ {
// snap mode // snap mode
lay::angle_constraint_type rm = lay::AC_Any; lay::angle_constraint_type rm = lay::AC_Any;
root->config_get (cfg_ruler_snap_mode, rm, ACConverter ()); root->config_get (cfg_ruler_snap_mode, rm, lay::ACConverter ());
mp_ui->ruler_any_angle_rb->setChecked (rm == lay::AC_Any); mp_ui->ruler_any_angle_rb->setChecked (rm == lay::AC_Any);
mp_ui->ruler_ortho_rb->setChecked (rm == lay::AC_Ortho); mp_ui->ruler_ortho_rb->setChecked (rm == lay::AC_Ortho);
mp_ui->ruler_diag_rb->setChecked (rm == lay::AC_Diagonal); mp_ui->ruler_diag_rb->setChecked (rm == lay::AC_Diagonal);
mp_ui->ruler_diag_only_rb->setChecked (rm == lay::AC_DiagonalOnly);
mp_ui->ruler_hor_rb->setChecked (rm == lay::AC_Horizontal); mp_ui->ruler_hor_rb->setChecked (rm == lay::AC_Horizontal);
mp_ui->ruler_vert_rb->setChecked (rm == lay::AC_Vertical); mp_ui->ruler_vert_rb->setChecked (rm == lay::AC_Vertical);
} }
@ -180,13 +181,16 @@ ConfigPage3::commit (lay::Dispatcher *root)
if (mp_ui->ruler_diag_rb->isChecked ()) { if (mp_ui->ruler_diag_rb->isChecked ()) {
rm = lay::AC_Diagonal; rm = lay::AC_Diagonal;
} }
if (mp_ui->ruler_diag_only_rb->isChecked ()) {
rm = lay::AC_DiagonalOnly;
}
if (mp_ui->ruler_hor_rb->isChecked ()) { if (mp_ui->ruler_hor_rb->isChecked ()) {
rm = lay::AC_Horizontal; rm = lay::AC_Horizontal;
} }
if (mp_ui->ruler_vert_rb->isChecked ()) { if (mp_ui->ruler_vert_rb->isChecked ()) {
rm = lay::AC_Vertical; rm = lay::AC_Vertical;
} }
root->config_set (cfg_ruler_snap_mode, rm, ACConverter ()); root->config_set (cfg_ruler_snap_mode, rm, lay::ACConverter ());
} }
// ------------------------------------------------------------ // ------------------------------------------------------------

View File

@ -24,6 +24,7 @@
#include "antObject.h" #include "antObject.h"
#include "antTemplate.h" #include "antTemplate.h"
#include "antConfig.h" #include "antConfig.h"
#include "layConverters.h"
#include "tlString.h" #include "tlString.h"
#include "tlExpression.h" #include "tlExpression.h"
@ -713,7 +714,7 @@ Object::from_string (const char *s, const char * /*base_dir*/)
std::string s; std::string s;
ex.read_word (s); ex.read_word (s);
ant::ACConverter sc; lay::ACConverter sc;
lay::angle_constraint_type sm; lay::angle_constraint_type sm;
sc.from_string (s, sm); sc.from_string (s, sm);
angle_constraint (sm); angle_constraint (sm);
@ -817,7 +818,7 @@ Object::to_string () const
r += ","; r += ",";
r += "angle_constraint="; r += "angle_constraint=";
ant::ACConverter acc; lay::ACConverter acc;
r += acc.to_string (angle_constraint ()); r += acc.to_string (angle_constraint ());
return r; return r;

View File

@ -102,7 +102,7 @@ PluginDeclaration::get_options (std::vector < std::pair<std::string, std::string
options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_range, "8")); options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_range, "8"));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_color, lay::ColorConverter ().to_string (tl::Color ()))); options.push_back (std::pair<std::string, std::string> (cfg_ruler_color, lay::ColorConverter ().to_string (tl::Color ())));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_halo, "true")); options.push_back (std::pair<std::string, std::string> (cfg_ruler_halo, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_mode, ACConverter ().to_string (lay::AC_Any))); options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_mode, lay::ACConverter ().to_string (lay::AC_Any)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_obj_snap, tl::to_string (true))); options.push_back (std::pair<std::string, std::string> (cfg_ruler_obj_snap, tl::to_string (true)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_grid_snap, tl::to_string (false))); options.push_back (std::pair<std::string, std::string> (cfg_ruler_grid_snap, tl::to_string (false)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_templates, std::string ())); options.push_back (std::pair<std::string, std::string> (cfg_ruler_templates, std::string ()));

View File

@ -1134,7 +1134,7 @@ Service::configure (const std::string &name, const std::string &value)
} else if (name == cfg_ruler_snap_mode) { } else if (name == cfg_ruler_snap_mode) {
lay::angle_constraint_type sm = lay::AC_Any; lay::angle_constraint_type sm = lay::AC_Any;
ACConverter ().from_string (value, sm); lay::ACConverter ().from_string (value, sm);
m_snap_mode = sm; m_snap_mode = sm;
} else if (name == cfg_ruler_templates) { } else if (name == cfg_ruler_templates) {

View File

@ -23,6 +23,7 @@
#include "antTemplate.h" #include "antTemplate.h"
#include "antConfig.h" #include "antConfig.h"
#include "layConverters.h"
#include "tlInternational.h" #include "tlInternational.h"
#include "tlException.h" #include "tlException.h"
#include "tlLog.h" #include "tlLog.h"
@ -263,7 +264,7 @@ Template::from_string (const std::string &s)
} else if (key == "angle_constraint") { } else if (key == "angle_constraint") {
ant::ACConverter sc; lay::ACConverter sc;
lay::angle_constraint_type sm; lay::angle_constraint_type sm;
sc.from_string (s, sm); sc.from_string (s, sm);
r.back ().angle_constraint (sm); r.back ().angle_constraint (sm);
@ -373,7 +374,7 @@ Template::to_string (const std::vector<Template> &v)
r += ","; r += ",";
r += "angle_constraint="; r += "angle_constraint=";
ant::ACConverter acc; lay::ACConverter acc;
r += acc.to_string (t->angle_constraint ()); r += acc.to_string (t->angle_constraint ());
} }

View File

@ -53,6 +53,7 @@ static int outline_radius () { return int (ant::Object::OL_radius); }
static int angle_any () { return int (lay::AC_Any); } static int angle_any () { return int (lay::AC_Any); }
static int angle_diagonal () { return int (lay::AC_Diagonal); } static int angle_diagonal () { return int (lay::AC_Diagonal); }
static int angle_diagonal_only () { return int (lay::AC_DiagonalOnly); }
static int angle_ortho () { return int (lay::AC_Ortho); } static int angle_ortho () { return int (lay::AC_Ortho); }
static int angle_horizontal () { return int (lay::AC_Horizontal); } static int angle_horizontal () { return int (lay::AC_Horizontal); }
static int angle_vertical () { return int (lay::AC_Vertical); } static int angle_vertical () { return int (lay::AC_Vertical); }
@ -653,6 +654,11 @@ gsi::Class<AnnotationRef> decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"@brief Gets the diagonal angle code for use with the \\angle_constraint method\n" "@brief Gets the diagonal angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only multiples of 45 degree are allowed." "If this value is specified for the angle constraint, only multiples of 45 degree are allowed."
) + ) +
gsi::method ("AngleDiagonalOnly", &gsi::angle_diagonal_only,
"@brief Gets the diagonal angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only 45 degree or 135 degree are allowed.\n"
"This constant has been introduced in version 0.30.6."
) +
gsi::method ("AngleOrtho", &gsi::angle_ortho, gsi::method ("AngleOrtho", &gsi::angle_ortho,
"@brief Gets the ortho angle code for use with the \\angle_constraint method\n" "@brief Gets the ortho angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only multiples of 90 degree are allowed." "If this value is specified for the angle constraint, only multiples of 90 degree are allowed."

View File

@ -1406,15 +1406,6 @@ PartialService::snap (const db::DVector &v_org) const
} }
} }
const int sr_pixels = 8; // TODO: make variable
lay::PointSnapToObjectResult
PartialService::snap2 (const db::DPoint &p) const
{
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
return lay::obj_snap (m_snap_to_objects ? view () : 0, m_start, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, move_ac (), snap_range);
}
void void
PartialService::transform (const db::DCplxTrans &tr) PartialService::transform (const db::DCplxTrans &tr)
{ {
@ -1790,17 +1781,11 @@ PartialService::wheel_event (int /*delta*/, bool /*horizontal*/, const db::DPoin
return false; return false;
} }
bool const int sr_pixels = 8; // TODO: make variable
PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
void
PartialService::move_impl (const db::DPoint &p)
{ {
clear_mouse_cursors ();
if (m_dragging) {
set_cursor (lay::Cursor::size_all);
m_alt_ac = lay::ac_from_buttons (buttons);
// drag the vertex or edge/segment // drag the vertex or edge/segment
if (is_single_point_selection () || is_single_edge_selection ()) { if (is_single_point_selection () || is_single_edge_selection ()) {
@ -1808,7 +1793,8 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
// for a single selected point or edge, m_start is the original position and we snap the target - // for a single selected point or edge, m_start is the original position and we snap the target -
// thus, we can bring the point on grid or to an object's edge or vertex // thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p); double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
snap_details = lay::obj_snap (m_snap_to_objects ? view () : 0, m_start, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, lay::AC_Any, snap_range);;
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) { if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
@ -1820,6 +1806,7 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
m_current = snapped_to_object; m_current = snapped_to_object;
if (snap_details.object_snap != lay::PointSnapToObjectResult::ObjectVertex) { if (snap_details.object_snap != lay::PointSnapToObjectResult::ObjectVertex) {
// snap to grid on longer side of reference edge and to object on shorter // snap to grid on longer side of reference edge and to object on shorter
auto snapped_to_object_and_grid = m_start + snap_move (snapped_to_object - m_start); auto snapped_to_object_and_grid = m_start + snap_move (snapped_to_object - m_start);
if (std::abs (snap_details.object_ref.dx ()) > std::abs (snap_details.object_ref.dy ())) { if (std::abs (snap_details.object_ref.dx ()) > std::abs (snap_details.object_ref.dy ())) {
@ -1837,21 +1824,47 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
m_current.set_x (cp.second.x ()); m_current.set_x (cp.second.x ());
} }
} }
} }
mouse_cursor_from_snap_details (snap_details); mouse_cursor_from_snap_details (snap_details);
} }
if (is_single_edge_selection ()) {
// in case of edge movement, project the move vector to the edge normal -
// that is cosmetic, so we don't imply a lateral shift
auto e = single_selected_edge ().d ();
if (e.double_length () > db::epsilon) {
db::DVector n = db::DVector (e.y (), -e.x ()) * (1.0 / e.double_length ());
m_current = m_start + n * db::sprod (m_current - m_start, n);
}
}
} else { } else {
// snap movement to angle and grid without object // snap movement to angle and grid without object
m_current = m_start + snap_move (p - m_start); m_current = m_start + snap_move (p - m_start);
clear_mouse_cursors ();
} }
selection_to_view (); selection_to_view ();
}
bool
PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
clear_mouse_cursors ();
if (m_dragging) {
set_cursor (lay::Cursor::size_all);
m_alt_ac = lay::ac_from_buttons (buttons);
move_impl (p);
call_editor_hooks (m_editor_hooks, &edt::EditorHooks::begin_edits); call_editor_hooks (m_editor_hooks, &edt::EditorHooks::begin_edits);
issue_editor_hook_calls (m_editor_hooks); issue_editor_hook_calls (m_editor_hooks);
@ -2457,34 +2470,12 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
m_alt_ac = ac; m_alt_ac = ac;
set_cursor (lay::Cursor::size_all); set_cursor (lay::Cursor::size_all);
// drag the vertex or edge/segment
if (is_single_point_selection () || is_single_edge_selection ()) {
lay::PointSnapToObjectResult snap_details;
// for a single selected point or edge, m_start is the original position and we snap the target -
// thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
m_current = m_start + snap_move (p - m_start);
} else {
m_current = snap_details.snapped_point;
mouse_cursor_from_snap_details (snap_details);
}
} else {
// snap movement to angle and grid without object
m_current = m_start + snap_move (p - m_start);
clear_mouse_cursors (); clear_mouse_cursors ();
} move_impl (p);
propose_move_transformation (db::DTrans (m_current - m_start), 0); propose_move_transformation (db::DTrans (m_current - m_start), 0);
selection_to_view ();
m_alt_ac = lay::AC_Global; m_alt_ac = lay::AC_Global;
} }

View File

@ -386,10 +386,10 @@ private:
db::DPoint snap (const db::DPoint &p) const; db::DPoint snap (const db::DPoint &p) const;
db::DVector snap (const db::DVector &p) const; db::DVector snap (const db::DVector &p) const;
lay::PointSnapToObjectResult snap2 (const db::DPoint &p) const;
void update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const; void update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const;
db::DVector snap_marker_to_grid (const db::DVector &v, bool &snapped) const; db::DVector snap_marker_to_grid (const db::DVector &v, bool &snapped) const;
db::DVector snap_move(const db::DVector &p) const; db::DVector snap_move(const db::DVector &p) const;
void move_impl (const db::DPoint &p);
void enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_objects::const_iterator sel, const std::map <PointWithIndex, db::Point> &new_points, const std::map <EdgeWithIndex, db::Edge> &new_edges, const db::ICplxTrans &gt, const std::vector<db::DCplxTrans> &tv, bool transient); void enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_objects::const_iterator sel, const std::map <PointWithIndex, db::Point> &new_points, const std::map <EdgeWithIndex, db::Edge> &new_edges, const db::ICplxTrans &gt, const std::vector<db::DCplxTrans> &tv, bool transient);
void enter_vertices (size_t &nmarker, partial_objects::const_iterator sel, const std::map <PointWithIndex, db::Point> &new_points, const std::map <EdgeWithIndex, db::Edge> &new_edges, const db::ICplxTrans &gt, const std::vector<db::DCplxTrans> &tv, bool transient); void enter_vertices (size_t &nmarker, partial_objects::const_iterator sel, const std::map <PointWithIndex, db::Point> &new_points, const std::map <EdgeWithIndex, db::Edge> &new_edges, const db::ICplxTrans &gt, const std::vector<db::DCplxTrans> &tv, bool transient);

View File

@ -1092,6 +1092,10 @@ gsi::Enum<lay::angle_constraint_type> decl_AngleConstraintType ("lay", "AngleCon
gsi::enum_const ("AC_Diagonal", lay::AC_Diagonal, gsi::enum_const ("AC_Diagonal", lay::AC_Diagonal,
"@brief Specifies to use multiples of 45 degree.\n" "@brief Specifies to use multiples of 45 degree.\n"
) + ) +
gsi::enum_const ("AC_DiagonalOnly", lay::AC_DiagonalOnly,
"@brief Specifies to use 45 degree or 135 degree only.\n"
"This variant has been introduced in version 0.30.6."
) +
gsi::enum_const ("AC_Ortho", lay::AC_Ortho, gsi::enum_const ("AC_Ortho", lay::AC_Ortho,
"@brief Specifies to use multiples of 90 degree.\n" "@brief Specifies to use multiples of 90 degree.\n"
) + ) +

View File

@ -87,8 +87,16 @@ ACConverter::to_string (const lay::angle_constraint_type &m)
return "any"; return "any";
} else if (m == lay::AC_Diagonal) { } else if (m == lay::AC_Diagonal) {
return "diagonal"; return "diagonal";
} else if (m == lay::AC_DiagonalOnly) {
return "diagonal_only";
} else if (m == lay::AC_Ortho) { } else if (m == lay::AC_Ortho) {
return "ortho"; return "ortho";
} else if (m == lay::AC_Horizontal) {
return "horizontal";
} else if (m == lay::AC_Vertical) {
return "vertical";
} else if (m == lay::AC_Global) {
return "global";
} else { } else {
return ""; return "";
} }
@ -102,8 +110,16 @@ ACConverter::from_string (const std::string &tt, lay::angle_constraint_type &m)
m = lay::AC_Any; m = lay::AC_Any;
} else if (t == "diagonal") { } else if (t == "diagonal") {
m = lay::AC_Diagonal; m = lay::AC_Diagonal;
} else if (t == "diagonal_only") {
m = lay::AC_DiagonalOnly;
} else if (t == "ortho") { } else if (t == "ortho") {
m = lay::AC_Ortho; m = lay::AC_Ortho;
} else if (t == "horizontal") {
m = lay::AC_Horizontal;
} else if (t == "vertical") {
m = lay::AC_Vertical;
} else if (t == "global") {
m = lay::AC_Global;
} else { } else {
m = lay::AC_Any; m = lay::AC_Any;
} }