diff --git a/src/ant/ant/RulerConfigPage3.ui b/src/ant/ant/RulerConfigPage3.ui
index e9d90e434..4e7fed45d 100644
--- a/src/ant/ant/RulerConfigPage3.ui
+++ b/src/ant/ant/RulerConfigPage3.ui
@@ -7,7 +7,7 @@
00665
- 103
+ 108
@@ -56,6 +56,13 @@
0
+
+
+
+ Diagonal
+
+
+
@@ -77,17 +84,17 @@
-
-
+
+
- Diagonal
+ Vertical only
-
+
- Vertical only
+ Diagonal only
@@ -102,7 +109,6 @@
ruler_ortho_rbruler_diag_rbruler_hor_rb
- ruler_vert_rb
diff --git a/src/ant/ant/RulerConfigPage4.ui b/src/ant/ant/RulerConfigPage4.ui
index 87e5dc3cc..1f5ec4a29 100644
--- a/src/ant/ant/RulerConfigPage4.ui
+++ b/src/ant/ant/RulerConfigPage4.ui
@@ -644,6 +644,11 @@
Orthogonal
+
+
+ Diagonal only
+
+ Horizontal only
diff --git a/src/ant/ant/ant.pro b/src/ant/ant/ant.pro
index c6052dab5..1d1286c73 100644
--- a/src/ant/ant/ant.pro
+++ b/src/ant/ant/ant.pro
@@ -31,6 +31,7 @@ SOURCES = \
HEADERS += \
antConfig.h \
+ antEditorOptionsPages.h \
antObject.h \
antPlugin.h \
antService.h \
@@ -40,6 +41,7 @@ HEADERS += \
SOURCES += \
antConfig.cc \
+ antEditorOptionsPages.cc \
antObject.cc \
antPlugin.cc \
antService.cc \
diff --git a/src/ant/ant/antConfig.cc b/src/ant/ant/antConfig.cc
index bec7c21f4..b2f4c239b 100644
--- a/src/ant/ant/antConfig.cc
+++ b/src/ant/ant/antConfig.cc
@@ -29,47 +29,6 @@ namespace ant
// ------------------------------------------------------------
// 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
StyleConverter::to_string (ant::Object::style_type s)
{
diff --git a/src/ant/ant/antConfig.h b/src/ant/ant/antConfig.h
index cb1bb5e10..4c603ac37 100644
--- a/src/ant/ant/antConfig.h
+++ b/src/ant/ant/antConfig.h
@@ -51,12 +51,6 @@ extern ANT_PUBLIC const std::string cfg_current_ruler_template;
// ------------------------------------------------------------
// 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
{
std::string to_string (ant::Object::style_type s);
diff --git a/src/ant/ant/antConfigPage.cc b/src/ant/ant/antConfigPage.cc
index 1dcd1cc69..6647035be 100644
--- a/src/ant/ant/antConfigPage.cc
+++ b/src/ant/ant/antConfigPage.cc
@@ -159,10 +159,11 @@ ConfigPage3::setup (lay::Dispatcher *root)
{
// snap mode
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_ortho_rb->setChecked (rm == lay::AC_Ortho);
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_vert_rb->setChecked (rm == lay::AC_Vertical);
}
@@ -180,13 +181,16 @@ ConfigPage3::commit (lay::Dispatcher *root)
if (mp_ui->ruler_diag_rb->isChecked ()) {
rm = lay::AC_Diagonal;
}
+ if (mp_ui->ruler_diag_only_rb->isChecked ()) {
+ rm = lay::AC_DiagonalOnly;
+ }
if (mp_ui->ruler_hor_rb->isChecked ()) {
rm = lay::AC_Horizontal;
}
if (mp_ui->ruler_vert_rb->isChecked ()) {
rm = lay::AC_Vertical;
}
- root->config_set (cfg_ruler_snap_mode, rm, ACConverter ());
+ root->config_set (cfg_ruler_snap_mode, rm, lay::ACConverter ());
}
// ------------------------------------------------------------
diff --git a/src/ant/ant/antEditorOptionsPages.cc b/src/ant/ant/antEditorOptionsPages.cc
new file mode 100644
index 000000000..56dea4a17
--- /dev/null
+++ b/src/ant/ant/antEditorOptionsPages.cc
@@ -0,0 +1,155 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2025 Matthias Koefferlein
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#if defined(HAVE_QT)
+
+#include "antService.h"
+#include "antEditorOptionsPages.h"
+
+#include "layWidgets.h"
+#include "layDispatcher.h"
+#include "tlInternational.h"
+
+#include
+
+namespace ant
+{
+
+// ------------------------------------------------------------------
+// Annotations Toolbox widget
+
+ToolkitWidget::ToolkitWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher)
+{
+ mp_layout = new QHBoxLayout (this);
+
+ mp_x_le = new lay::DecoratedLineEdit (this);
+ mp_x_le->set_label ("dx:");
+ mp_layout->addWidget (mp_x_le);
+
+ mp_y_le = new lay::DecoratedLineEdit (this);
+ mp_y_le->set_label ("dy:");
+ mp_layout->addWidget (mp_y_le);
+
+ mp_d_le = new lay::DecoratedLineEdit (this);
+ mp_d_le->set_label ("d:");
+ mp_layout->addWidget (mp_d_le);
+
+ mp_layout->addStretch (1);
+
+ hide ();
+
+ set_toolbox_widget (true);
+ set_transparent (true);
+}
+
+ToolkitWidget::~ToolkitWidget ()
+{
+ // .. nothing yet ..
+}
+
+std::string
+ToolkitWidget::title () const
+{
+ return "Box Options";
+}
+
+const char *
+ToolkitWidget::name () const
+{
+ return ant::Service::editor_options_name ();
+}
+
+void
+ToolkitWidget::deactivated ()
+{
+ hide ();
+}
+
+void
+ToolkitWidget::commit (lay::Dispatcher *dispatcher)
+{
+ try {
+
+ if (mp_d_le->hasFocus ()) {
+
+ double d = 0.0;
+
+ tl::from_string (tl::to_string (mp_d_le->text ()), d);
+
+ dispatcher->call_function (ant::Service::d_function_name (), tl::to_string (d));
+
+ } else {
+
+ double dx = 0.0, dy = 0.0;
+
+ tl::from_string (tl::to_string (mp_x_le->text ()), dx);
+ tl::from_string (tl::to_string (mp_y_le->text ()), dy);
+
+ dispatcher->call_function (ant::Service::xy_function_name (), db::DVector (dx, dy).to_string ());
+
+ }
+
+ } catch (...) {
+ }
+}
+
+void
+ToolkitWidget::configure (const std::string &name, const std::string &value)
+{
+ if (name == ant::Service::xy_configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
+
+ try {
+
+ db::DVector mv;
+ tl::from_string (value, mv);
+
+ mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
+ mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
+
+ } catch (...) {
+ }
+
+ } else if (name == ant::Service::d_configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
+
+ try {
+
+ double d;
+ tl::from_string (value, d);
+
+ mp_d_le->setText (tl::to_qstring (tl::micron_to_string (d)));
+
+ } catch (...) {
+ }
+
+ }
+}
+
+// ------------------------------------------------------------------
+// Registrations
+
+// toolkit widgets
+static tl::RegisteredClass s_tookit_widget_factory (new lay::EditorOptionsPageFactory ("ant::Plugin"), 0);
+
+}
+
+#endif
diff --git a/src/ant/ant/antEditorOptionsPages.h b/src/ant/ant/antEditorOptionsPages.h
new file mode 100644
index 000000000..470a69686
--- /dev/null
+++ b/src/ant/ant/antEditorOptionsPages.h
@@ -0,0 +1,68 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2025 Matthias Koefferlein
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#if defined(HAVE_QT)
+
+#ifndef HDR_antEditorOptionsPages
+#define HDR_antEditorOptionsPages
+
+#include "layEditorOptionsPageWidget.h"
+
+class QHBoxLayout;
+
+namespace lay
+{
+ class DecoratedLineEdit;
+}
+
+namespace ant
+{
+
+/**
+ * @brief The toolbox widget for annotations
+ */
+class ToolkitWidget
+ : public lay::EditorOptionsPageWidget
+{
+Q_OBJECT
+
+public:
+ ToolkitWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+ ~ToolkitWidget ();
+
+ virtual std::string title () const;
+ virtual const char *name () const;
+ virtual int order () const { return 0; }
+ virtual void configure (const std::string &name, const std::string &value);
+ virtual void commit (lay::Dispatcher *root);
+ virtual void deactivated ();
+
+private:
+ QHBoxLayout *mp_layout;
+ lay::DecoratedLineEdit *mp_x_le, *mp_y_le, *mp_d_le;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index 9ce86eed3..aa3dbb693 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -24,6 +24,7 @@
#include "antObject.h"
#include "antTemplate.h"
#include "antConfig.h"
+#include "layConverters.h"
#include "tlString.h"
#include "tlExpression.h"
@@ -425,7 +426,24 @@ class AnnotationEvalFunction
: public tl::EvalFunction
{
public:
- AnnotationEvalFunction (char function, const AnnotationEval *eval, size_t index)
+ enum FunctionType {
+ ManhattanLength, // L
+ ManhattanLengthIncremental, // LL
+ EuclidianDistance, // D
+ EuclidianDistanceIncremental, // DD
+ XDelta, // X
+ XDeltaIncremental, // XX
+ YDelta, // Y
+ YDeltaIncremental, // YY
+ P1X, // U
+ P1Y, // V
+ P2X, // P
+ P2Y, // Q
+ Area, // A
+ Angle // G
+ };
+
+ AnnotationEvalFunction (FunctionType function, const AnnotationEval *eval, size_t index)
: m_function (function), mp_eval (eval), m_index (index)
{
// .. nothing yet ..
@@ -440,25 +458,53 @@ class AnnotationEvalFunction
const Object &obj = mp_eval->obj ();
const db::DFTrans &trans = mp_eval->trans ();
- if (m_function == 'L') {
- out = fabs (delta_x (obj, trans)) + fabs (delta_y (obj, trans));
- } else if (m_function == 'D') {
- out = sqrt (delta_x (obj, trans) * delta_x (obj, trans) + delta_y (obj, trans) * delta_y (obj, trans));
- } else if (m_function == 'A') {
- out = delta_x (obj, trans) * delta_y (obj, trans) * 1e-6;
- } else if (m_function == 'X') {
- out = delta_x (obj, trans);
- } else if (m_function == 'Y') {
- out = delta_y (obj, trans);
- } else if (m_function == 'U') {
- out = (trans * p1 (obj)).x ();
- } else if (m_function == 'V') {
- out = (trans * p1 (obj)).y ();
- } else if (m_function == 'P') {
- out = (trans * p2 (obj)).x ();
- } else if (m_function == 'Q') {
- out = (trans * p2 (obj)).y ();
- } else if (m_function == 'G') {
+ if (m_function == ManhattanLength) {
+ out = fabs (delta_x (obj, trans, m_index)) + fabs (delta_y (obj, trans, m_index));
+ } else if (m_function == ManhattanLengthIncremental) {
+ double res = 0.0;
+ for (size_t index = 0; index <= m_index; ++index) {
+ res += fabs (delta_x (obj, trans, index)) + fabs (delta_y (obj, trans, index));
+ }
+ out = res;
+ } else if (m_function == EuclidianDistance) {
+ auto dx = delta_x (obj, trans, m_index);
+ auto dy = delta_y (obj, trans, m_index);
+ out = sqrt (dx * dx + dy * dy);
+ } else if (m_function == EuclidianDistanceIncremental) {
+ double res = 0.0;
+ for (size_t index = 0; index <= m_index; ++index) {
+ auto dx = delta_x (obj, trans, index);
+ auto dy = delta_y (obj, trans, index);
+ res += sqrt (dx * dx + dy * dy);
+ }
+ out = res;
+ } else if (m_function == Area) {
+ out = delta_x (obj, trans, m_index) * delta_y (obj, trans, m_index) * 1e-6;
+ } else if (m_function == XDelta) {
+ out = delta_x (obj, trans, m_index);
+ } else if (m_function == XDeltaIncremental) {
+ double res = 0.0;
+ for (size_t index = 0; index <= m_index; ++index) {
+ res += delta_x (obj, trans, index);
+ }
+ out = res;
+ } else if (m_function == YDelta) {
+ out = delta_y (obj, trans, m_index);
+ } else if (m_function == YDeltaIncremental) {
+ double res = 0.0;
+ for (size_t index = 0; index <= m_index; ++index) {
+ res += delta_y (obj, trans, index);
+ }
+ out = res;
+ } else if (m_function == P1X) {
+ out = (trans * p1 (obj, m_index)).x ();
+ } else if (m_function == P1Y) {
+ out = (trans * p1 (obj, m_index)).y ();
+ } else if (m_function == P2X) {
+ out = (trans * p2 (obj, m_index)).x ();
+ } else if (m_function == P2Y) {
+ out = (trans * p2 (obj, m_index)).y ();
+ } else if (m_function == Angle) {
double r, a1, a2;
db::DPoint c;
if (obj.compute_angle_parameters (r, c, a1, a2)) {
@@ -471,20 +517,20 @@ class AnnotationEvalFunction
}
}
- db::DPoint p1 (const Object &obj) const
+ db::DPoint p1 (const Object &obj, size_t index) const
{
- return obj.seg_p1 (m_index);
+ return obj.seg_p1 (index);
}
- db::DPoint p2 (const Object &obj) const
+ db::DPoint p2 (const Object &obj, size_t index) const
{
- return obj.seg_p2 (m_index);
+ return obj.seg_p2 (index);
}
double
- delta_x (const Object &obj, const db::DFTrans &t) const
+ delta_x (const Object &obj, const db::DFTrans &t, size_t index) const
{
- double dx = ((t * p2 (obj)).x () - (t * p1 (obj)).x ());
+ double dx = ((t * p2 (obj, index)).x () - (t * p1 (obj, index)).x ());
// avoid "almost 0" outputs
if (fabs (dx) < 1e-5 /*micron*/) {
@@ -495,9 +541,9 @@ class AnnotationEvalFunction
}
double
- delta_y (const Object &obj, const db::DFTrans &t) const
+ delta_y (const Object &obj, const db::DFTrans &t, size_t index) const
{
- double dy = ((t * p2 (obj)).y () - (t * p1 (obj)).y ());
+ double dy = ((t * p2 (obj, index)).y () - (t * p1 (obj, index)).y ());
// avoid "almost 0" outputs
if (fabs (dy) < 1e-5 /*micron*/) {
@@ -508,7 +554,7 @@ class AnnotationEvalFunction
}
private:
- char m_function;
+ FunctionType m_function;
const AnnotationEval *mp_eval;
size_t m_index;
};
@@ -517,16 +563,20 @@ std::string
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, 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
- eval.define_function ("G", new AnnotationEvalFunction('G', &eval, index)); // angle (if applicable)
+ eval.define_function ("L", new AnnotationEvalFunction (AnnotationEvalFunction::ManhattanLength, &eval, index)); // manhattan length
+ eval.define_function ("LL", new AnnotationEvalFunction (AnnotationEvalFunction::ManhattanLengthIncremental, &eval, index)); // manhattan length
+ eval.define_function ("D", new AnnotationEvalFunction (AnnotationEvalFunction::EuclidianDistance, &eval, index)); // euclidian distance
+ eval.define_function ("DD", new AnnotationEvalFunction (AnnotationEvalFunction::EuclidianDistanceIncremental, &eval, index)); // euclidian distance (incremental, for multi-rulers)
+ eval.define_function ("X", new AnnotationEvalFunction (AnnotationEvalFunction::XDelta, &eval, index)); // x delta
+ eval.define_function ("XX", new AnnotationEvalFunction (AnnotationEvalFunction::XDeltaIncremental, &eval, index)); // x delta (incremental, for multi-rulers)
+ eval.define_function ("Y", new AnnotationEvalFunction (AnnotationEvalFunction::YDelta, &eval, index)); // y delta
+ eval.define_function ("YY", new AnnotationEvalFunction (AnnotationEvalFunction::YDeltaIncremental, &eval, index)); // y delta (incremental, for multi-rulers)
+ eval.define_function ("U", new AnnotationEvalFunction (AnnotationEvalFunction::P1X, &eval, index)); // p1.x
+ eval.define_function ("V", new AnnotationEvalFunction (AnnotationEvalFunction::P1Y, &eval, index)); // p1.y
+ eval.define_function ("P", new AnnotationEvalFunction (AnnotationEvalFunction::P2X, &eval, index)); // p2.x
+ eval.define_function ("Q", new AnnotationEvalFunction (AnnotationEvalFunction::P2Y, &eval, index)); // p2.y
+ eval.define_function ("A", new AnnotationEvalFunction (AnnotationEvalFunction::Area, &eval, index)); // area mm2
+ eval.define_function ("G", new AnnotationEvalFunction (AnnotationEvalFunction::Angle, &eval, index)); // angle (if applicable)
return eval.interpolate (fmt);
}
@@ -713,7 +763,7 @@ Object::from_string (const char *s, const char * /*base_dir*/)
std::string s;
ex.read_word (s);
- ant::ACConverter sc;
+ lay::ACConverter sc;
lay::angle_constraint_type sm;
sc.from_string (s, sm);
angle_constraint (sm);
@@ -817,7 +867,7 @@ Object::to_string () const
r += ",";
r += "angle_constraint=";
- ant::ACConverter acc;
+ lay::ACConverter acc;
r += acc.to_string (angle_constraint ());
return r;
diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc
index ab21a915c..aaed7f8d6 100644
--- a/src/ant/ant/antPlugin.cc
+++ b/src/ant/ant/antPlugin.cc
@@ -102,7 +102,7 @@ PluginDeclaration::get_options (std::vector < std::pair (cfg_ruler_snap_range, "8"));
options.push_back (std::pair (cfg_ruler_color, lay::ColorConverter ().to_string (tl::Color ())));
options.push_back (std::pair (cfg_ruler_halo, "true"));
- options.push_back (std::pair (cfg_ruler_snap_mode, ACConverter ().to_string (lay::AC_Any)));
+ options.push_back (std::pair (cfg_ruler_snap_mode, lay::ACConverter ().to_string (lay::AC_Any)));
options.push_back (std::pair (cfg_ruler_obj_snap, tl::to_string (true)));
options.push_back (std::pair (cfg_ruler_grid_snap, tl::to_string (false)));
options.push_back (std::pair (cfg_ruler_templates, std::string ()));
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index 6f6c0e556..90f070655 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -33,6 +33,7 @@
#include "layConverters.h"
#include "layLayoutCanvas.h"
#include "layFixedFont.h"
+#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "layProperties.h"
#endif
@@ -1041,6 +1042,12 @@ View::render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
// -------------------------------------------------------------
// ant::Service implementation
+const char *Service::editor_options_name () { return "ant-toolkit-widget-name"; }
+const char *Service::xy_configure_name () { return "ant-toolkit-widget-xy-value"; }
+const char *Service::d_configure_name () { return "ant-toolkit-widget-d-value"; }
+const char *Service::xy_function_name () { return "ant-toolkit-widget-xy-commit"; }
+const char *Service::d_function_name () { return "ant-toolkit-widget-d-commit"; }
+
Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
: lay::EditorServiceBase (view),
lay::Drawing (1/*number of planes*/, view->drawings ()),
@@ -1056,6 +1063,9 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
m_drawing (false), m_current (),
m_move_mode (MoveNone),
m_seg_index (0),
+ m_length_confined (false),
+ m_length (0.0),
+ m_centered (false),
m_current_template (0),
m_hover (false),
m_hover_wait (false),
@@ -1134,7 +1144,7 @@ Service::configure (const std::string &name, const std::string &value)
} else if (name == cfg_ruler_snap_mode) {
lay::angle_constraint_type sm = lay::AC_Any;
- ACConverter ().from_string (value, sm);
+ lay::ACConverter ().from_string (value, sm);
m_snap_mode = sm;
} else if (name == cfg_ruler_templates) {
@@ -1169,6 +1179,21 @@ Service::config_finalize ()
{
}
+void
+Service::show_toolbox (bool visible)
+{
+ lay::EditorOptionsPage *tb = toolbox_widget ();
+ if (tb) {
+ tb->set_visible (visible);
+ }
+}
+
+lay::EditorOptionsPage *
+Service::toolbox_widget ()
+{
+ return mp_view->editor_options_pages () ? mp_view->editor_options_pages ()->page_with_name (editor_options_name ()) : 0;
+}
+
void
Service::annotations_changed ()
{
@@ -1244,6 +1269,7 @@ void
Service::drag_cancel ()
{
if (m_drawing) {
+ show_toolbox (false);
ui ()->ungrab_mouse (this);
m_drawing = false;
}
@@ -1598,72 +1624,84 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
clear_mouse_cursors ();
+ if (m_move_mode == MoveSelected) {
+
+ db::DVector dp = p - m_p1;
+ dp = lay::snap_angle (dp, ac_eff);
+
+ m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
+
+ propose_move_transformation (m_trans, 1);
+
+ snap_rulers (ac_eff);
+
+ for (std::vector::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
+ (*r)->transform_by (db::DCplxTrans (m_trans));
+ }
+
+ show_message ();
+
+ } else if (m_move_mode != MoveNone) {
+
+ db::DPoint ps = snap2_visual (m_p1, p, &m_current, ac);
+ m_trans = db::DTrans (ps - m_p1);
+
+ apply_partial_move (ps);
+
+ propose_move_transformation (db::DTrans (ps - m_p1), 1);
+
+ // display current move distance
+ std::string pos = std::string ("dx: ") + tl::micron_to_string (ps.x () - m_p1.x ()) + " "
+ + "dy: " + tl::micron_to_string (ps.y () - m_p1.y ());
+ view ()->message (pos);
+
+ }
+}
+
+void
+Service::apply_partial_move (db::DPoint &ps)
+{
if (m_move_mode == MoveP1) {
-
- m_current.seg_p1 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
- m_rulers [0]->redraw ();
+
+ m_current.seg_p1 (m_seg_index, ps);
} else if (m_move_mode == MoveP2) {
-
- m_current.seg_p2 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
- m_rulers [0]->redraw ();
+
+ m_current.seg_p2 (m_seg_index, ps);
} else if (m_move_mode == MoveP12) {
-
- db::DPoint p12 = snap2_visual (m_p1, p, &m_current, ac);
- m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), p12.y ()));
- m_current.seg_p2 (m_seg_index, db::DPoint (p12.x (), m_current.seg_p2 (m_seg_index).y ()));
- m_rulers [0]->redraw ();
+
+ m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), ps.y ()));
+ m_current.seg_p2 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p2 (m_seg_index).y ()));
} else if (m_move_mode == MoveP21) {
-
- db::DPoint p21 = snap2_visual (m_p1, p, &m_current, ac);
- m_current.seg_p1 (m_seg_index, db::DPoint (p21.x (), m_current.seg_p1 (m_seg_index).y ()));
- m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), p21.y ()));
- m_rulers [0]->redraw ();
+
+ m_current.seg_p1 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p1 (m_seg_index).y ()));
+ m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), ps.y ()));
} else if (m_move_mode == MoveP1X) {
-
- db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
- m_current.seg_p1 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p1 (m_seg_index).y ()));
- m_rulers [0]->redraw ();
- } else if (m_move_mode == MoveP2X) {
-
- db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
- m_current.seg_p2 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p2 (m_seg_index).y ()));
- m_rulers [0]->redraw ();
+ ps.set_y (m_p1.y ());
+ m_current.seg_p1 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p1 (m_seg_index).y ()));
- } else if (m_move_mode == MoveP1Y) {
-
- db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
- m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), pc.y ()));
- m_rulers [0]->redraw ();
+ } else if (m_move_mode == MoveP2X) {
- } else if (m_move_mode == MoveP2Y) {
-
- db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
- m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), pc.y ()));
- m_rulers [0]->redraw ();
+ ps.set_y (m_p1.y ());
+ m_current.seg_p2 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p2 (m_seg_index).y ()));
- } else if (m_move_mode == MoveSelected) {
+ } else if (m_move_mode == MoveP1Y) {
- db::DVector dp = p - m_p1;
- dp = lay::snap_angle (dp, ac_eff);
+ ps.set_x (m_p1.x ());
+ m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), ps.y ()));
- m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
+ } else if (m_move_mode == MoveP2Y) {
- snap_rulers (ac_eff);
-
- for (std::vector::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
- (*r)->transform_by (db::DCplxTrans (m_trans));
- }
+ ps.set_x (m_p1.x ());
+ m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), ps.y ()));
}
- if (m_move_mode != MoveSelected) {
- show_message ();
- }
+ m_rulers [0]->redraw ();
}
void
@@ -1676,6 +1714,13 @@ Service::show_message ()
view ()->message (pos);
}
+void
+Service::end_move (const db::DVector &v)
+{
+ m_trans = db::DTrans (v) * db::DTrans (m_trans.fp_trans ());
+ end_move (db::DPoint (), lay::AC_Any);
+}
+
void
Service::end_move (const db::DPoint &, lay::angle_constraint_type)
{
@@ -1705,6 +1750,9 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
} else if (m_move_mode != MoveNone) {
+ db::DPoint ps = m_trans * m_p1;
+ apply_partial_move (ps);
+
// replace the ruler that was moved
m_current.clean_points ();
mp_view->annotation_shapes ().replace (*m_selected.begin (), db::DUserObject (new ant::Object (m_current)));
@@ -1830,9 +1878,23 @@ Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int button
finish_drawing ();
return true;
+ } else {
+ return false;
}
+}
- return false;
+bool
+Service::key_event (unsigned int key, unsigned int buttons)
+{
+ if (m_drawing && buttons == 0 && (key == lay::KeyEnter || key == lay::KeyReturn)) {
+
+ // ends the current ruler (specifically in multi-segment mode)
+ finish_drawing ();
+ return true;
+
+ } else {
+ return false;
+ }
}
lay::TwoPointSnapToObjectResult
@@ -1873,6 +1935,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
// cancel any edit operations so far
m_move_mode = MoveNone;
+ m_length_confined = false;
// reset selection
clear_selection ();
@@ -1969,6 +2032,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
mp_active_ruler->thaw ();
m_drawing = true;
+ show_toolbox (true);
ui ()->grab_mouse (this, false);
}
@@ -1989,6 +2053,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
pts.push_back (m_p1);
m_current.set_points_exact (pts);
+ m_length_confined = false;
}
@@ -2021,6 +2086,116 @@ Service::create_measure_ruler (const db::DPoint &pt, lay::angle_constraint_type
}
}
+void
+Service::function (const std::string &name, const std::string &value)
+{
+ if (name == xy_function_name ()) {
+
+ try {
+
+ db::DVector s;
+ tl::from_string (value, s);
+
+ if (m_drawing) {
+
+ ant::Object::point_list pts = m_current.points ();
+ if (pts.size () >= 2) {
+
+ db::DVector d = pts.back () - pts [pts.size () - 2];
+
+ // Adjust the direction so positive coordinates are in the current drag direction
+ s = db::DVector (s.x () * (d.x () < 0 ? -1.0 : 1.0), s.y () * (d.y () < 0 ? -1.0 : 1.0));
+
+ pts.back () = pts [pts.size () - 2] + s;
+ m_current.set_points_exact (pts);
+
+ }
+
+ const ant::Template &tpl = current_template ();
+
+ if (tpl.mode () == ant::Template::RulerMultiSegment || tpl.mode () == ant::Template::RulerThreeClicks) {
+
+ if (tpl.mode () == ant::Template::RulerThreeClicks && 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 {
+
+ finish_drawing ();
+
+ }
+
+ }
+
+ } catch (...) {
+ }
+
+ } else if (name == d_function_name ()) {
+
+ try {
+
+ double s = 0.0;
+ tl::from_string (value, s);
+
+ if (m_drawing) {
+
+ m_length_confined = true;
+ m_length = s;
+
+ ant::Object::point_list pts = m_current.points ();
+ confine_length (pts);
+ m_current.set_points_exact (pts);
+
+ }
+
+ } catch (...) {
+ }
+
+ }
+}
+
+void
+Service::confine_length (ant::Object::point_list &pts)
+{
+ if (m_length_confined && pts.size () >= 2) {
+
+ const ant::Template &tpl = current_template ();
+ bool is_box_style = tpl.mode () == ant::Template::RulerNormal && (tpl.outline () == ant::Object::OL_box || tpl.outline () == ant::Object::OL_ellipse);
+
+ db::DPoint p1 = m_centered ? m_p1 : pts [pts.size () - 2];
+ db::DVector s = pts.back () - p1;
+ if (is_box_style) {
+ db::DVector snew = s;
+ double l = m_centered ? m_length * 0.5 : m_length;
+ if (fabs (s.x ()) < fabs (s.y ()) + db::epsilon) {
+ snew.set_y (l * (s.y () < 0 ? -1.0 : 1.0));
+ }
+ if (fabs (s.y ()) < fabs (s.x ()) + db::epsilon) {
+ snew.set_x (l * (s.x () < 0 ? -1.0 : 1.0));
+ }
+ s = snew;
+ } else {
+ double l = s.double_length ();
+ if (l > db::epsilon) {
+ s *= m_length / l;
+ }
+ }
+
+ pts.back () = p1 + s;
+
+ }
+}
+
bool
Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
@@ -2040,11 +2215,26 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
}
+ const ant::Template &tpl = current_template ();
+
+ // for normal rulers with box or ellipse rendering we use a different button scheme:
+ // Shift will keep the center, Ctrl will confine the box to a square/ellipse to a circle
+ bool is_box_style = tpl.mode () == ant::Template::RulerNormal && (tpl.outline () == ant::Object::OL_box || tpl.outline () == ant::Object::OL_ellipse);
+ bool snap_square = is_box_style && (buttons & lay::ControlButton) != 0;
+ m_centered = is_box_style && (buttons & lay::ShiftButton) != 0;
+
lay::PointSnapToObjectResult snap_details;
if (m_drawing) {
- snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons));
+ lay::angle_constraint_type ac;
+ if (snap_square) {
+ ac = lay::AC_DiagonalOnly;
+ } else if (is_box_style) {
+ ac = lay::AC_Any;
+ } else {
+ ac = ac_from_buttons (buttons);
+ }
+ snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac);
} else {
- const ant::Template &tpl = current_template ();
snap_details = snap1_details (p, m_obj_snap && tpl.snap () && (tpl.mode () != ant::Template::RulerAutoMetricEdge || ! view ()->transient_selection_mode ()));
}
@@ -2058,10 +2248,36 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
// otherwise we risk manipulating p1 too.
ant::Object::point_list pts = m_current.points ();
if (! pts.empty ()) {
+
pts.back () = snap_details.snapped_point;
+
+ confine_length (pts);
+
+ if (is_box_style) {
+ if (m_centered) {
+ pts.front () = m_p1 - (pts.back () - m_p1);
+ } else {
+ pts.front () = m_p1;
+ }
+ }
+
}
+
m_current.set_points_exact (pts);
+ db::DVector delta;
+ if (pts.size () >= 2) {
+ delta = pts.back () - pts[pts.size () - 2];
+ delta = db::DVector (fabs (delta.x ()), fabs (delta.y ()));
+ }
+
+ lay::EditorOptionsPage *tb = toolbox_widget ();
+ if (tb) {
+ double d = is_box_style ? std::min (fabs (delta.x ()), fabs (delta.y ())) : delta.length ();
+ tb->configure (xy_configure_name (), delta.to_string ());
+ tb->configure (d_configure_name (), tl::to_string (d));
+ }
+
mp_active_ruler->redraw ();
show_message ();
diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h
index 13086eeb4..2bd5c574d 100644
--- a/src/ant/ant/antService.h
+++ b/src/ant/ant/antService.h
@@ -197,6 +197,13 @@ Q_OBJECT
public:
typedef lay::AnnotationShapes::iterator obj_iterator;
+ // for communicating with the toolbox widget
+ static const char *editor_options_name ();
+ static const char *xy_configure_name ();
+ static const char *d_configure_name ();
+ static const char *xy_function_name ();
+ static const char *d_function_name ();
+
/**
* The current move mode:
* MoveNone - not moving
@@ -347,6 +354,11 @@ Q_OBJECT
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
+ /**
+ * @brief Terminate a "move" operation with compulsory move vector
+ */
+ virtual void end_move (const db::DVector &v);
+
/**
* @brief Return the bbox of the selection (reimplementation of lay::Editable interface)
*/
@@ -498,10 +510,15 @@ Q_OBJECT
}
/**
- * @brief Implement the menu response function
+ * @brief Implements the menu response function
*/
void menu_activated (const std::string &symbol);
+ /**
+ * @brief Implements the toolbox widget response function
+ */
+ void function (const std::string &name, const std::string &value);
+
/**
* @brief Return the annotation iterator that delivers the annotations (and only these)
*/
@@ -583,6 +600,11 @@ public slots:
MoveMode m_move_mode;
// The currently moving segment
size_t m_seg_index;
+ // When set to true, the length is confined to the value given by m_length
+ bool m_length_confined;
+ double m_length;
+ // When set to true, the last point was established in centered fashion
+ bool m_centered;
// The ruler template
std::vector m_ruler_templates;
unsigned int m_current_template;
@@ -603,10 +625,15 @@ public slots:
db::DPoint snap2_visual (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
lay::TwoPointSnapToObjectResult auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl);
+ void confine_length (ant::Object::point_list &pts);
const ant::Template ¤t_template () const;
+ void show_toolbox (bool visible);
+ lay::EditorOptionsPage *toolbox_widget ();
+
void show_message ();
+ void apply_partial_move (db::DPoint &ps);
/**
* @brief A handler for the shape container's changed event
@@ -617,6 +644,7 @@ public slots:
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 bool key_event (unsigned int key, unsigned int buttons);
virtual void deactivated ();
void snap_rulers (lay::angle_constraint_type ac);
diff --git a/src/ant/ant/antTemplate.cc b/src/ant/ant/antTemplate.cc
index 58994d619..2c5c7d537 100644
--- a/src/ant/ant/antTemplate.cc
+++ b/src/ant/ant/antTemplate.cc
@@ -23,6 +23,7 @@
#include "antTemplate.h"
#include "antConfig.h"
+#include "layConverters.h"
#include "tlInternational.h"
#include "tlException.h"
#include "tlLog.h"
@@ -263,7 +264,7 @@ Template::from_string (const std::string &s)
} else if (key == "angle_constraint") {
- ant::ACConverter sc;
+ lay::ACConverter sc;
lay::angle_constraint_type sm;
sc.from_string (s, sm);
r.back ().angle_constraint (sm);
@@ -373,7 +374,7 @@ Template::to_string (const std::vector &v)
r += ",";
r += "angle_constraint=";
- ant::ACConverter acc;
+ lay::ACConverter acc;
r += acc.to_string (t->angle_constraint ());
}
diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc
index e5087c2e6..80a5eea04 100644
--- a/src/ant/ant/gsiDeclAnt.cc
+++ b/src/ant/ant/gsiDeclAnt.cc
@@ -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_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_horizontal () { return int (lay::AC_Horizontal); }
static int angle_vertical () { return int (lay::AC_Vertical); }
@@ -653,6 +654,11 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"@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."
) +
+ 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,
"@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."
diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc
index f709df749..c45cdc503 100644
--- a/src/db/db/dbPolygonTools.cc
+++ b/src/db/db/dbPolygonTools.cc
@@ -814,7 +814,7 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
if (keep_hv && (p1.x () == p0.x () || p1.y () == p0.y () || p2.x () == p1.x () || p2.y () == p1.y ())) {
// keep points which participate in either a vertical or horizontal edge
- } else if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
+ } else if (p1.double_distance (p0) <= d * (1.0 + db::epsilon) && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
// jog configurations with small edges are candidates
can_drop = true;
} else if (db::vprod_sign (p2 - p1, p1 - p0) < 0) {
@@ -826,7 +826,7 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
}
for (size_t j = pi0; can_drop; ) {
- if (std::abs (db::Edge (p0, p2).distance (org_points [j])) > d) {
+ if (std::abs (db::DEdge (db::DPoint (p0), db::DPoint (p2)).distance (db::DPoint (org_points [j]))) > d * (1.0 + db::epsilon)) {
can_drop = false;
}
if (j == pi2) {
diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc
index 3c83fe30c..9d45b739a 100644
--- a/src/db/db/gsiDeclDbEdgePairs.cc
+++ b/src/db/db/gsiDeclDbEdgePairs.cc
@@ -31,6 +31,7 @@
#include "dbEdgesUtils.h"
#include "dbEdgePairFilters.h"
#include "dbPropertiesFilter.h"
+#include "dbRegionProcessors.h"
#include "gsiDeclDbContainerHelpers.h"
#include "gsiDeclDbMeasureHelpers.h"
@@ -531,6 +532,71 @@ static db::Region extents0 (const db::EdgePairs *r)
return extents2 (r, 0, 0);
}
+namespace {
+
+// a combined processor that implements db::RelativeExtents on the edge bounding boxes
+
+class DB_PUBLIC EdgePairsRelativeExtents
+ : virtual public db::EdgePairToPolygonProcessorBase,
+ virtual public db::RelativeExtents
+{
+public:
+ EdgePairsRelativeExtents (double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
+ : db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy)
+ {
+ // .. nothing yet ..
+ }
+
+ // not needed, but mutes
+ void process (const db::PolygonWithProperties &poly, std::vector &result) const
+ {
+ db::RelativeExtents::process (poly, result);
+ }
+
+ void process (const db::EdgePairWithProperties &ep, std::vector &result) const
+ {
+ db::RelativeExtents::process (db::Polygon (ep.bbox ()), result);
+ }
+};
+
+class DB_PUBLIC EdgePairsRelativeExtentsAsEdges
+ : virtual public db::EdgePairToEdgeProcessorBase,
+ virtual public db::RelativeExtentsAsEdges
+{
+public:
+ EdgePairsRelativeExtentsAsEdges (double fx1, double fy1, double fx2, double fy2)
+ : db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2)
+ {
+ // .. nothing yet ..
+ }
+
+ void process (const db::PolygonWithProperties &poly, std::vector &result) const
+ {
+ db::RelativeExtentsAsEdges::process (poly, result);
+ }
+
+ void process (const db::EdgePairWithProperties &ep, std::vector &result) const
+ {
+ db::RelativeExtentsAsEdges::process (db::Polygon (ep.bbox ()), result);
+ }
+};
+
+}
+
+static db::Region extent_refs (const db::EdgePairs *r, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
+{
+ db::Region result;
+ r->processed (result, EdgePairsRelativeExtents (fx1, fy1, fx2, fy2, dx, dy));
+ return result;
+}
+
+static db::Edges extent_refs_edges (const db::EdgePairs *r, double fx1, double fy1, double fx2, double fy2)
+{
+ db::Edges result;
+ r->processed (result, EdgePairsRelativeExtentsAsEdges (fx1, fy1, fx2, fy2));
+ return result;
+}
+
static db::Edges edges (const db::EdgePairs *ep)
{
db::Edges e;
@@ -1247,7 +1313,15 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
) +
- method_ext ("filter", &filter, gsi::arg ("filter"),
+ method_ext ("extent_refs", &extent_refs,
+ "@hide\n"
+ "This method is provided for DRC implementation.\n"
+ ) +
+ method_ext ("extent_refs_edges", &extent_refs_edges,
+ "@hide\n"
+ "This method is provided for DRC implementation.\n"
+ ) +
+ method_ext ("filter", &filter, gsi::arg ("filter"),
"@brief Applies a generic filter in place (replacing the edge pairs from the EdgePair collection)\n"
"See \\EdgePairFilter for a description of this feature.\n"
"\n"
diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc
index 109101272..a600c1732 100644
--- a/src/db/db/gsiDeclDbEdges.cc
+++ b/src/db/db/gsiDeclDbEdges.cc
@@ -32,6 +32,7 @@
#include "dbOriginalLayerRegion.h"
#include "dbLayoutUtils.h"
#include "dbPropertiesFilter.h"
+#include "dbRegionProcessors.h"
#include "gsiDeclDbContainerHelpers.h"
#include "gsiDeclDbMeasureHelpers.h"
@@ -941,6 +942,69 @@ static std::vector split_interacting_with_region (const db::Edges *r,
return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count));
}
+namespace {
+
+// a combined processor that implements db::RelativeExtents on the edge bounding boxes
+
+class DB_PUBLIC EdgesRelativeExtents
+ : virtual public db::EdgeToPolygonProcessorBase,
+ virtual public db::RelativeExtents
+{
+public:
+ EdgesRelativeExtents (double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
+ : db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy)
+ {
+ // .. nothing yet ..
+ }
+
+ // not needed, but mutes
+ void process (const db::PolygonWithProperties &poly, std::vector &result) const
+ {
+ db::RelativeExtents::process (poly, result);
+ }
+
+ void process (const db::EdgeWithProperties &edge, std::vector &result) const
+ {
+ db::RelativeExtents::process (db::Polygon (edge.bbox ()), result);
+ }
+};
+
+class DB_PUBLIC EdgesRelativeExtentsAsEdges
+ : virtual public db::EdgeProcessorBase,
+ virtual public db::RelativeExtentsAsEdges
+{
+public:
+ EdgesRelativeExtentsAsEdges (double fx1, double fy1, double fx2, double fy2)
+ : db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2)
+ {
+ // .. nothing yet ..
+ }
+
+ void process (const db::PolygonWithProperties &poly, std::vector &result) const
+ {
+ db::RelativeExtentsAsEdges::process (poly, result);
+ }
+
+ void process (const db::EdgeWithProperties &edge, std::vector &result) const
+ {
+ db::RelativeExtentsAsEdges::process (db::Polygon (edge.bbox ()), result);
+ }
+};
+
+}
+
+static db::Region extent_refs (const db::Edges *r, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
+{
+ db::Region result;
+ r->processed (result, EdgesRelativeExtents (fx1, fy1, fx2, fy2, dx, dy));
+ return result;
+}
+
+static db::Edges extent_refs_edges (const db::Edges *r, double fx1, double fy1, double fx2, double fy2)
+{
+ return r->processed (EdgesRelativeExtentsAsEdges (fx1, fy1, fx2, fy2));
+}
+
static tl::Variant nth (const db::Edges *edges, size_t n)
{
const db::Edge *e = edges->nth (n);
@@ -2372,6 +2436,14 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
) +
+ method_ext ("extent_refs", &extent_refs,
+ "@hide\n"
+ "This method is provided for DRC implementation.\n"
+ ) +
+ method_ext ("extent_refs_edges", &extent_refs_edges,
+ "@hide\n"
+ "This method is provided for DRC implementation.\n"
+ ) +
method_ext ("extended_in", &extended_in, gsi::arg ("e"),
"@brief Returns a region with shapes representing the edges with the given width\n"
"@param e The extension width\n"
diff --git a/src/db/unit_tests/dbPolygonToolsTests.cc b/src/db/unit_tests/dbPolygonToolsTests.cc
index dab78ba79..5b672f6d1 100644
--- a/src/db/unit_tests/dbPolygonToolsTests.cc
+++ b/src/db/unit_tests/dbPolygonToolsTests.cc
@@ -1366,6 +1366,65 @@ TEST(106)
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,73235;1200,90468;2300,114468;2800,138468;2800,154468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
}
+// smoothing, small units
+TEST(107)
+{
+ db::Point pattern [] = {
+ db::Point (1, 1),
+ db::Point (1, 2),
+ db::Point (2, 2),
+ db::Point (2, 4),
+ db::Point (3, 4),
+ db::Point (3, 5),
+ db::Point (4, 5),
+ db::Point (4, 7),
+ db::Point (5, 7),
+ db::Point (5, 8),
+ db::Point (6, 8),
+ db::Point (6, 9),
+ db::Point (7, 9),
+ db::Point (7, 16),
+ db::Point (8, 16),
+ db::Point (8, 17),
+ db::Point (9, 17),
+ db::Point (9, 18),
+ db::Point (10, 18),
+ db::Point (10, 19),
+ db::Point (12, 19),
+ db::Point (12, 20),
+ db::Point (16, 20),
+ db::Point (16, 21),
+ db::Point (17, 21),
+ db::Point (17, 22),
+ db::Point (18, 22),
+ db::Point (18, 23),
+ db::Point (24, 23),
+ db::Point (24, 15),
+ db::Point (23, 15),
+ db::Point (23, 14),
+ db::Point (22, 14),
+ db::Point (22, 12),
+ db::Point (21, 12),
+ db::Point (21, 10),
+ db::Point (20, 10),
+ db::Point (20, 8),
+ db::Point (19, 8),
+ db::Point (19, 6),
+ db::Point (18, 6),
+ db::Point (18, 4),
+ db::Point (17, 4),
+ db::Point (17, 3),
+ db::Point (16, 3),
+ db::Point (16, 1)
+ };
+
+ db::Polygon p;
+ p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
+
+ EXPECT_EQ (smooth (p, 0, false).to_string (), "(1,1;1,2;2,2;2,4;3,4;3,5;4,5;4,7;5,7;5,8;6,8;6,9;7,9;7,16;8,16;8,17;9,17;9,18;10,18;10,19;12,19;12,20;16,20;16,21;17,21;17,22;18,22;18,23;24,23;24,15;23,15;23,14;22,14;22,12;21,12;21,10;20,10;20,8;19,8;19,6;18,6;18,4;17,4;17,3;16,3;16,1)");
+ EXPECT_EQ (smooth (p, 1, false).to_string (), "(1,1;2,4;4,5;4,7;7,9;7,16;10,18;18,22;24,23;24,15;22,14;18,4;17,4;16,1)");
+}
+
// rounding
TEST(200)
{
diff --git a/src/doc/doc/about/drc_ref.xml b/src/doc/doc/about/drc_ref.xml
index 203941a1d..3974cf751 100644
--- a/src/doc/doc/about/drc_ref.xml
+++ b/src/doc/doc/about/drc_ref.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/drc_ref_drc.xml b/src/doc/doc/about/drc_ref_drc.xml
index a4ad2a239..78e0e1744 100644
--- a/src/doc/doc/about/drc_ref_drc.xml
+++ b/src/doc/doc/about/drc_ref_drc.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/drc_ref_global.xml b/src/doc/doc/about/drc_ref_global.xml
index 735374f88..da588bf12 100644
--- a/src/doc/doc/about/drc_ref_global.xml
+++ b/src/doc/doc/about/drc_ref_global.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/drc_ref_layer.xml b/src/doc/doc/about/drc_ref_layer.xml
index df0a8c7cc..0e485e947 100644
--- a/src/doc/doc/about/drc_ref_layer.xml
+++ b/src/doc/doc/about/drc_ref_layer.xml
@@ -1,7 +1,7 @@
-
+
@@ -1182,20 +1182,19 @@ The formal specifiers for lines are:
:right or :r : the right line
-Dots are represented by small (2x2 DBU) boxes or point-like
-edges with edge output. Lines are represented by narrow or
-flat (2 DBU) boxes or edges for edge output. Edges will follow
-the orientation convention for the corresponding edges - i.e.
-"inside" of the bounding box is on the right side of the edge.
-
The following additional option controls the output format:
-
as_boxes : with this option, small boxes will be produced as markers
-
as_dots or as_edges : with this option, point-like edges will be produced for dots
-and edges will be produced for line-like selections
+
as_boxes : with this option, boxes (rectangular polygons) will be produced on output
+
as_dots or as_edges : with this option, edges will be produced on output
+Dots on are represented by small (2x2 DBU) boxes or point-like
+edges with edge output. Lines are represented by narrow or
+flat (2 DBU) boxes or edges for edge output. Edges will follow
+the orientation convention for the corresponding edges - i.e.
+"inside" of the bounding box is on the right side of the edge.
+
Hint: A box, once created, will remain a box. For example, it is not possible to delete one vertex
+
+ While you drag the box, two edit boxes are shown at the top of the layout view.
+ Press the Tab key to enter these edit boxes.
+ Use the Tab and Shift+Tab keys to navigate between the boxes.
+ You can specify numerical values for the box width and height here. Pressing the Enter key will apply these
+ dimensions. Pressing the Escape key will leave the edit fields.
+
+
+
Note: A box, once created, will remain a box. For example, it is not possible to delete one vertex
of it, thus forming a triangle. This is only possible for polygons.
diff --git a/src/doc/doc/manual/create_path.xml b/src/doc/doc/manual/create_path.xml
index e6763c061..d7c48e5ac 100644
--- a/src/doc/doc/manual/create_path.xml
+++ b/src/doc/doc/manual/create_path.xml
@@ -18,8 +18,24 @@
To actually draw a path,
choose a layer from the layer panel in which to create a new path.
Left click at the first vertex, move the mouse to the second vertex, click to place this one and continue
- to the last vertex. Double-click at the last vertex to finish the path. Press the ESC key to cancel the operation.
- Use the backspace key to remove the current segment and go back to the previous segment.
+ to the last vertex. Double-click at the last vertex or press the Enter key to finish the path.
+ Press the Escape key to cancel the operation.
+ Use the Backspace key to remove the current segment and go back to the previous segment.
+
+
+
+ To temporarily constrain the segment direction, press the Shift or Ctrl key or both while dragging
+ the segment. Shift will apply Manhattan
+ constraints (vertical and horizontal only), Ctrl will allow diagonal directions in addition and
+ pressing Shift+Ctrl will allow all directions.
+
+
+
+ While you drag a path segment, two edit boxes are shown at the top of the layout view.
+ Press the Tab key to enter these edit boxes.
+ Use the Tab and Shift+Tab keys to navigate between the boxes.
+ You can specify a numerical values for the segment vector here. Pressing the Enter key will apply these
+ relative coordinates and enter a new segment. Pressing the Escape key will leave the edit fields.
diff --git a/src/doc/doc/manual/create_polygon.xml b/src/doc/doc/manual/create_polygon.xml
index 1d1d42f33..6e00a85e5 100644
--- a/src/doc/doc/manual/create_polygon.xml
+++ b/src/doc/doc/manual/create_polygon.xml
@@ -14,11 +14,28 @@
with a left mouse button click. Move to the next vertex. Depending on the connection mode, the edges
created are confined to certain directions. See
for a detailed description of the modes. Use the "editor options" dialog (F3 shortcut) to change the mode,
- even during editing.
+ even during editing.
- Double-click at the final point to finish the polygon. Press the ESC key to cancel the operation.
+ To temporarily constrain the segment direction, press the Shift or Ctrl key or both while dragging
+ the segment. Shift will apply Manhattan
+ constraints (vertical and horizontal only), Ctrl will allow diagonal directions in addition and
+ pressing Shift+Ctrl will allow all directions.
+
+
+
+ Double-click at the final point or press the Enter key to finish the polygon.
+ Press the Escape key to cancel the operation. Use the Backspace key to delete the
+ last segment.
+
+
+
+ While you drag a polygon segment, two edit boxes are shown at the top of the layout view.
+ Press the Tab key to enter these edit boxes.
+ Use the Tab and Shift+Tab keys to navigate between the boxes.
+ You can specify a numerical values for the segment vector here. Pressing the Enter key will apply these
+ relative coordinates and enter a new segment. Pressing the Escape key will leave the edit fields.
A measurement can be performed by clicking on the ruler icon in the
toolbar and selecting "Ruler" from the drop-down options.
- Left-click on a point in the layout and then left-click again to
- specify the second point. A ruler will be shown that indicates
- the distance measured.
+ Left-click on a point in the layout and then left-click again
+ or press the Enter key to set the second point.
+ A ruler will be shown that indicates the distance measured.
- A more convenient way is provided with the single-click measurement
+ While you move the endpoint, you can hold the Shift or Ctrl key
+ or both. With only the Shift key pressed, the ruler's direction
+ will be limited to horizontal or vertical only. With only the Ctrl
+ key pressed, the direction is limited to horizontal, vertical or
+ diagonal. With Ctrl and Shift pressed together, no limitation
+ of direction applies.
+
+
+
+ While the ruler is dragged, the current drag distance is indicated
+ in three edit fields at the top of the layout view. By pressing the
+ Tab key, the input focus changes to these edit fields. You can
+ specify a numerical value for the distances here. Use Tab and
+ Shift+Tab to jump between the fields. Press the Escape key to
+ leave the edit fields. Pressing the Enter key while
+ the cursor is on the "dx" or "dy" field will
+ accept the values and apply them to the ruler.
+ If you specify a value in the last field labelled "d" and press
+ Enter, the ruler will enter "fixed length" mode - in that mode you
+ can still define the ruler's direction with the mouse, but the
+ length is fixed to the given value.
+
+
+
+ A convenient way to measure a distance is the single-click measurement
ruler. Select "Measure" from the drop-down options of the ruler symbol.
In this mode, a single click will set a ruler to the specified
position. This feature will look for edges in the vicinity of the
@@ -24,6 +48,11 @@
is attached perpendicular to the edge next to the initial point.
+
+ The "Measure Edge" ruler type is also a single-click measurement
+ ruler, but measures the length of an edge at the click position.
+
+
You can mark a position with a single click by selecting the "Cross"
ruler type. Clicking at a location will place such a ruler. The ruler
@@ -35,7 +64,12 @@
object. Click and the first point to start such a ruler. Then click
on more points to add new segments to the ruler. Each segment is shown
as an individual ruler with tick marks and a length. Finish the sequence
- with a double-click.
+ with a double-click or by pressing the Enter key.
+ Note that the lengths indicated by the ruler labels are the lengths
+ of the individual segments. To get an incremental length (the sum
+ of all segment length), change the ruler's label format from "$D" to "$DD" ("DD"
+ is variable giving the incremental length).
+ See the description of ruler templates below, about how to make this change permanent.
diff --git a/src/doc/doc/manual/move_layer_sel.xml b/src/doc/doc/manual/move_layer_sel.xml
index 997fd5954..ece22ce01 100644
--- a/src/doc/doc/manual/move_layer_sel.xml
+++ b/src/doc/doc/manual/move_layer_sel.xml
@@ -12,10 +12,16 @@
All selected shapes are moved to the layer that is the current one (marked with a rectangle) in the layer list.
The shapes will not be moved across the hierarchy but just inside their cell.
+
All layers (source and target) must be located in the same layout. To move shapes to a
different layout, use copy & paste.
+
+ You can also change the layer in the shape properties. This will effectively
+ move shapes to other layers too.
+
While moving, the whole selection can be rotated by 90 degree counterclockwise with a right mouse
button click.
- The ESC key will cancel the operation.
+ The Escape key will cancel the operation.
For movements, the movement direction constraint apply.
See for details about the modes
- available. For example, in manhattan mode, only horizontal and vertical movements are allowed.
+ available. For example, in Manhattan mode, only horizontal and vertical movements are allowed.
The global movement constraint can be overridden by pressing Shift (orthogonal), Ctrl (diagonal) or
both Shift and Ctrl (any angle) while moving the mouse.
- If a move distance and direction is known numerically, "Move By" from the "Edit/Selection" menu can be used.
+ While you move the selection, two edit boxes are shown at the top of the layout view.
+ Press the Tab key to enter these edit boxes.
+ Use the Tab and Shift+Tab keys to navigate between the boxes.
+ You can specify a numerical shift value here. Pressing the Enter key will apply these
+ shifts. Pressing the Escape key will leave the edit fields.
+
+
+
+ To apply a specific shift, you can also use "Move By" from the "Edit/Selection" menu.
A dialog will open that allows specification of the horizontal and vertical move distance in micrometers.
Positive values move to the top or right and negative ones to the bottom or left.
This dialog also applies to partial mode, so that edges or parts of a layout can be
diff --git a/src/doc/doc/manual/partial.xml b/src/doc/doc/manual/partial.xml
index db0bed8d9..adda0fdc0 100644
--- a/src/doc/doc/manual/partial.xml
+++ b/src/doc/doc/manual/partial.xml
@@ -35,7 +35,9 @@
Simply clicking at an item immediately enters "move" mode. In this mode, you can position the element at the desired
target location and place it there by left-clicking at the position. Press "ESC" to cancel the operation.
When a complex selection is made, move mode is entered by clicking at one of the selected items (the edges
- or vertices, not the shape to which they belong).
+ or vertices, not the shape to which they belong). While you move, two edit boxes are shown at the top of
+ the layout view. Press the Tab key to enter these edit fields. You can specify explicit move distances there.
+ Press the Enter key to apply them or the Escape key to leave these edit fields.
$X: The value of the X variable (the horizontal distance, see below for a complete list of variables).
-
$(sprintf('%.2f',X)): The value of the 'X' variable formatted as two digit fixed precision value.
-
$(abs(X)+abs(Y)): The manhattan distance of the ruler.
+
$(sprintf('%.2f',X)): The value of the 'X' variable formatted as two digit fixed precision value.
+ The "sprintf" function follows the conventions of the same standard C function.
+
$(abs(X)+abs(Y)): The Manhattan distance of the ruler.
$min(X,Y): The minimum of X and Y.
+
$(X) ($Y): the value of the X variable, followed by the value of the Y variables in brackets.
+ This will give a string like "2.5 (-0.5)". Note
+ that you cannot simply write "$X ($Y)" because the expression evaluation reads that as an attempt to call a
+ function named "X".
@@ -68,7 +73,7 @@
D: The length of the ruler in micron units.
-
L: The manhattan length of the ruler in micron units.
+
L: The Manhattan length of the ruler in micron units.
U: The x-position of the ruler's first point in micron units.
V: The y-position of the ruler's first point in micron units.
P: The x-position of the ruler's second point in micron units.
@@ -79,5 +84,17 @@
G: The angle enclosed by the first and last segment of the ruler (used for angle measurement rulers).
+
+ For multi-rulers additional variables are provided for "incremental" values.
+ These are the sums of the respective values up to the given part:
+
+
+
+
DD: The sum of all lengths up to the labelled segment.
+
LL: The sum of all Manhattan up to the labelled segment.
+
XX: The horizontal distance between first and current point.
+
YY: The vertical distance between first and current point.
+
+
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index 44466da10..eeb76e244 100644
--- a/src/drc/drc/built-in-macros/_drc_layer.rb
+++ b/src/drc/drc/built-in-macros/_drc_layer.rb
@@ -1463,20 +1463,19 @@ def corners(*args)
# @li @b :right @/b or @b :r @/b: the right line @/li
# @/ul
#
- # Dots are represented by small (2x2 DBU) boxes or point-like
- # edges with edge output. Lines are represented by narrow or
- # flat (2 DBU) boxes or edges for edge output. Edges will follow
- # the orientation convention for the corresponding edges - i.e.
- # "inside" of the bounding box is on the right side of the edge.
- #
# The following additional option controls the output format:
#
# @ul
- # @li @b as_boxes @/b: with this option, small boxes will be produced as markers @/li
- # @li @b as_dots @/b or @b as_edges @/b: with this option, point-like edges will be produced for dots
- # and edges will be produced for line-like selections @/li
+ # @li @b as_boxes @/b: with this option, boxes (rectangular polygons) will be produced on output @/li
+ # @li @b as_dots @/b or @b as_edges @/b: with this option, edges will be produced on output @/li
# @/ul
#
+ # Dots on are represented by small (2x2 DBU) boxes or point-like
+ # edges with edge output. Lines are represented by narrow or
+ # flat (2 DBU) boxes or edges for edge output. Edges will follow
+ # the orientation convention for the corresponding edges - i.e.
+ # "inside" of the bounding box is on the right side of the edge.
+ #
# The following table shows a few applications:
#
# @table
@@ -1511,7 +1510,7 @@ def #{f}(*args)
@engine._context("#{f}") do
- requires_region
+ requires_edges_edge_pairs_or_region
f = []
as_edges = false
@@ -1714,7 +1713,7 @@ def #{f}(&block)
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
@engine.run_timed("\\"#{f}\\" in: " + @engine.src_line, self.data) do
- self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
+ self.data.send(self.data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans)
end
new_data
@@ -6105,6 +6104,10 @@ def requires_edges_or_region(name = nil)
self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::Region) || raise(name ? "#{name} requires an edge or polygon layer" : "Requires an edge or polygon layer")
end
+ def requires_edges_edge_pairs_or_region(name = nil)
+ self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::EdgePairs) || raise(name ? "#{name} requires an edge, edge pair or polygon layer" : "Requires an edge, edge pair or polygon layer")
+ end
+
def requires_edges_texts_or_region(name = nil)
self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Texts) || raise(name ? "#{name} requires an edge, text or polygon layer" : "Requires an edge, text or polygon layer")
end
diff --git a/src/edt/edt/edtBoxService.cc b/src/edt/edt/edtBoxService.cc
index 8b1cdd173..68ad5658e 100644
--- a/src/edt/edt/edtBoxService.cc
+++ b/src/edt/edt/edtBoxService.cc
@@ -24,6 +24,7 @@
#include "edtBoxService.h"
#include "layLayoutViewBase.h"
+#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
@@ -35,8 +36,11 @@ namespace edt
// -----------------------------------------------------------------------------
// BoxService implementation
+const char *BoxService::configure_name () { return "box-toolkit-widget-value"; }
+const char *BoxService::function_name () { return "box-toolkit-widget-commit"; }
+
BoxService::BoxService (db::Manager *manager, lay::LayoutViewBase *view)
- : ShapeEditService (manager, view, db::ShapeIterator::Boxes)
+ : ShapeEditService (manager, view, db::ShapeIterator::Boxes), m_centered (false)
{
// .. nothing yet ..
}
@@ -65,10 +69,42 @@ BoxService::do_begin_edit (const db::DPoint &p)
update_marker ();
}
+void
+BoxService::function (const std::string &name, const std::string &value)
+{
+ if (name == function_name ()) {
+
+ try {
+
+ db::DVector dim;
+ tl::from_string (value, dim);
+
+ if (! m_centered) {
+ // Adjust the direction so positive coordinates are in the current drag direction
+ db::DVector d = m_p2 - m_p1;
+ dim = db::DVector (dim.x () * (d.x () < 0 ? -1.0 : 1.0), dim.y () * (d.y () < 0 ? -1.0 : 1.0));
+ } else {
+ dim = db::DVector (fabs (dim.x ()) * 0.5, fabs (dim.y ()) * 0.5);
+ }
+ m_p2 = m_p1 + dim;
+
+ finish_editing (true);
+
+ } catch (...) {
+ }
+
+ }
+}
+
db::Box
BoxService::get_box () const
{
- return db::Box (trans () * m_p1, trans () * m_p2);
+ if (m_centered) {
+ db::DVector d = m_p2 - m_p1;
+ return db::Box (trans () * (m_p1 - d), trans () * (m_p1 + d));
+ } else {
+ return db::Box (trans () * m_p1, trans () * m_p2);
+ }
}
void
@@ -79,10 +115,18 @@ BoxService::update_marker ()
marker->set (get_box (), db::VCplxTrans (1.0 / layout ().dbu ()) * trans ().inverted ());
+ db::DVector d = m_p2 - m_p1;
+ db::DVector dim = db::DVector (fabs (d.x ()), fabs (d.y ())) * (m_centered ? 2.0 : 1.0);
+
view ()->message (std::string ("lx: ") +
- tl::micron_to_string (m_p2.x () - m_p1.x ()) +
+ tl::micron_to_string (dim.x ()) +
std::string (" ly: ") +
- tl::micron_to_string (m_p2.y () - m_p1.y ()));
+ tl::micron_to_string (dim.y ()));
+
+ auto p = toolbox_widget ();
+ if (p) {
+ p->configure (configure_name (), dim.to_string ());
+ }
}
@@ -108,10 +152,14 @@ BoxService::do_mouse_move_inactive (const db::DPoint &p)
void
BoxService::do_mouse_move (const db::DPoint &p)
{
- lay::PointSnapToObjectResult snap_details = snap2_details (p);
+ // snap to square if Ctrl button is pressed
+ bool snap_square = (mouse_buttons () & lay::ControlButton) != 0;
+ bool centered = (mouse_buttons () & lay::ShiftButton) != 0;
+
+ lay::PointSnapToObjectResult snap_details = snap2_details (p, m_p1, snap_square ? lay::AC_DiagonalOnly : lay::AC_Any);
db::DPoint ps = snap_details.snapped_point;
- if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
+ if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject && ! m_centered) {
clear_mouse_cursors ();
@@ -122,12 +170,22 @@ BoxService::do_mouse_move (const db::DPoint &p)
lay::PointSnapToObjectResult snap_details_y = snap2_details (py);
if (snap_details_x.object_snap != lay::PointSnapToObjectResult::NoObject) {
- ps = db::DPoint (snap_details_x.snapped_point.x (), ps.y ());
+ if (snap_square) {
+ double dx = fabs (snap_details_x.snapped_point.x () - m_p1.x ());
+ ps = db::DPoint (snap_details_x.snapped_point.x (), m_p1.y () + (ps.y () < m_p1.y () ? -dx : dx));
+ } else {
+ ps = db::DPoint (snap_details_x.snapped_point.x (), ps.y ());
+ }
mouse_cursor_from_snap_details (snap_details_x, true /*add*/);
}
if (snap_details_y.object_snap != lay::PointSnapToObjectResult::NoObject) {
- ps = db::DPoint (ps.x (), snap_details_y.snapped_point.y ());
+ if (snap_square) {
+ double dy = fabs (snap_details_y.snapped_point.x () - m_p1.y ());
+ ps = db::DPoint (m_p1.x () + (ps.x () < m_p1.x () ? -dy : dy), snap_details_y.snapped_point.y ());
+ } else {
+ ps = db::DPoint (ps.x (), snap_details_y.snapped_point.y ());
+ }
mouse_cursor_from_snap_details (snap_details_y, true /*add*/);
}
@@ -139,6 +197,7 @@ BoxService::do_mouse_move (const db::DPoint &p)
set_cursor (lay::Cursor::cross);
m_p2 = ps;
+ m_centered = centered;
update_marker ();
}
@@ -150,7 +209,7 @@ BoxService::do_mouse_click (const db::DPoint &p)
}
void
-BoxService::do_finish_edit ()
+BoxService::do_finish_edit (bool /*accept*/)
{
deliver_shape (get_box ());
commit_recent ();
diff --git a/src/edt/edt/edtBoxService.h b/src/edt/edt/edtBoxService.h
index c1455eaf9..bed8c30d4 100644
--- a/src/edt/edt/edtBoxService.h
+++ b/src/edt/edt/edtBoxService.h
@@ -36,6 +36,9 @@ class BoxService
: public ShapeEditService
{
public:
+ static const char *configure_name ();
+ static const char *function_name ();
+
BoxService (db::Manager *manager, lay::LayoutViewBase *view);
#if defined(HAVE_QT)
@@ -45,12 +48,14 @@ class BoxService
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
- virtual void do_finish_edit ();
+ virtual void do_finish_edit (bool accept);
virtual void do_cancel_edit ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
+ virtual void function (const std::string &name, const std::string &value);
private:
db::DPoint m_p1, m_p2;
+ bool m_centered;
void update_marker ();
db::Box get_box () const;
diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc
index 416e08238..04a001c6c 100644
--- a/src/edt/edt/edtEditorOptionsPages.cc
+++ b/src/edt/edt/edtEditorOptionsPages.cc
@@ -29,6 +29,7 @@
#include "edtPCellParametersPage.h"
#include "edtConfig.h"
#include "edtService.h"
+#include "edtBoxService.h"
#include "edtEditorOptionsPages.h"
#include "edtPropertiesPageUtils.h"
#include "tlExceptions.h"
@@ -72,7 +73,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
// EditorOptionsGeneric implementation
EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : EditorOptionsPage (view, dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsGeneric ();
mp_ui->setupUi (this);
@@ -215,7 +216,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
// EditorOptionsText implementation
EditorOptionsText::EditorOptionsText (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : lay::EditorOptionsPage (view, dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsText ();
mp_ui->setupUi (this);
@@ -293,7 +294,7 @@ EditorOptionsText::setup (lay::Dispatcher *root)
// EditorOptionsPath implementation
EditorOptionsPath::EditorOptionsPath (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : lay::EditorOptionsPage (view, dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsPath ();
mp_ui->setupUi (this);
@@ -394,7 +395,7 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
// EditorOptionsInst implementation
EditorOptionsInst::EditorOptionsInst (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : lay::EditorOptionsPage (view, dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsInst ();
mp_ui->setupUi (this);
@@ -687,7 +688,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
// EditorOptionsInstPCellParam implementation
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
+ : lay::EditorOptionsPageWidget (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
{
mp_ui = new Ui::EditorOptionsInstPCellParam ();
mp_ui->setupUi (this);
@@ -898,6 +899,179 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector set_label ("w:");
+ mp_layout->addWidget (mp_x_le);
+
+ mp_y_le = new lay::DecoratedLineEdit (this);
+ mp_y_le->set_label ("h:");
+ mp_layout->addWidget (mp_y_le);
+
+ mp_layout->addStretch (1);
+
+ hide ();
+
+ set_toolbox_widget (true);
+ set_transparent (true);
+}
+
+BoxToolboxWidget::~BoxToolboxWidget ()
+{
+ // .. nothing yet ..
+}
+
+std::string
+BoxToolboxWidget::title () const
+{
+ return "Box Options";
+}
+
+void
+BoxToolboxWidget::deactivated ()
+{
+ hide ();
+}
+
+void
+BoxToolboxWidget::commit (lay::Dispatcher *dispatcher)
+{
+ try {
+
+ double dx = 0.0, dy = 0.0;
+
+ tl::from_string (tl::to_string (mp_x_le->text ()), dx);
+ tl::from_string (tl::to_string (mp_y_le->text ()), dy);
+
+ dispatcher->call_function (BoxService::function_name (), db::DVector (dx, dy).to_string ());
+
+ } catch (...) {
+ }
+}
+
+void
+BoxToolboxWidget::configure (const std::string &name, const std::string &value)
+{
+ if (name == BoxService::configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
+
+ try {
+
+ db::DVector mv;
+ tl::from_string (value, mv);
+
+ mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
+ mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
+
+ } catch (...) {
+ }
+
+ }
+}
+
+// ------------------------------------------------------------------
+// Connections toolbox widget (for paths and polygons)
+
+ConnectionToolboxWidget::ConnectionToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher), m_in_commit (false)
+{
+ mp_layout = new QHBoxLayout (this);
+
+ mp_x_le = new lay::DecoratedLineEdit (this);
+ mp_x_le->set_label ("dx:");
+ mp_layout->addWidget (mp_x_le);
+
+ mp_y_le = new lay::DecoratedLineEdit (this);
+ mp_y_le->set_label ("dy:");
+ mp_layout->addWidget (mp_y_le);
+
+ mp_layout->addStretch (1);
+
+ hide ();
+
+ set_toolbox_widget (true);
+ set_transparent (true);
+}
+
+ConnectionToolboxWidget::~ConnectionToolboxWidget ()
+{
+ // .. nothing yet ..
+}
+
+std::string
+ConnectionToolboxWidget::title () const
+{
+ return "Connection Options";
+}
+
+void
+ConnectionToolboxWidget::deactivated ()
+{
+ hide ();
+}
+
+void
+ConnectionToolboxWidget::commit (lay::Dispatcher *dispatcher)
+{
+ m_in_commit = true;
+
+ try {
+
+ double dx = 0.0, dy = 0.0;
+
+ tl::from_string (tl::to_string (mp_x_le->text ()), dx);
+ tl::from_string (tl::to_string (mp_y_le->text ()), dy);
+
+ dispatcher->call_function (ShapeEditService::connection_function_name (), db::DVector (dx, dy).to_string ());
+
+ } catch (...) {
+ }
+
+ m_in_commit = false;
+}
+
+void
+ConnectionToolboxWidget::configure (const std::string &name, const std::string &value)
+{
+ if (name == ShapeEditService::connection_configure_name () &&
+ ((! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) || m_in_commit)) {
+
+ try {
+
+ db::DVector mv;
+ tl::from_string (value, mv);
+
+ mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
+ mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
+
+ } catch (...) {
+ }
+
+ }
+}
+
+// ------------------------------------------------------------------
+// Registrations
+
+// unspecific editor options - used for all plugins that want it
+static tl::RegisteredClass s_factory_generic (new lay::EditorOptionsPageFactory (), 0);
+
+static tl::RegisteredClass s_factory_texts (new lay::EditorOptionsPageFactory ("edt::Service(Texts)"), 0);
+static tl::RegisteredClass s_factory_paths (new lay::EditorOptionsPageFactory ("edt::Service(Paths)"), 0);
+static tl::RegisteredClass s_factory_insts (new lay::EditorOptionsPageFactory ("edt::Service(CellInstances)"), 0);
+static tl::RegisteredClass s_factory_insts_pcell (new lay::EditorOptionsPageFactory ("edt::Service(CellInstances)"), 0);
+
+// toolkit widgets
+static tl::RegisteredClass s_box_tookit_widget_factory (new lay::EditorOptionsPageFactory ("edt::Service(Boxes)"), 0);
+static tl::RegisteredClass s_connection_tookit_widget_factory_paths (new lay::EditorOptionsPageFactory ("edt::Service(Paths)"), 0);
+static tl::RegisteredClass s_connection_tookit_widget_factory_polygons (new lay::EditorOptionsPageFactory ("edt::Service(Polygons)"), 0);
+
}
#endif
diff --git a/src/edt/edt/edtEditorOptionsPages.h b/src/edt/edt/edtEditorOptionsPages.h
index acf94b4f1..92f151883 100644
--- a/src/edt/edt/edtEditorOptionsPages.h
+++ b/src/edt/edt/edtEditorOptionsPages.h
@@ -26,6 +26,7 @@
#define HDR_edtEditorOptionsPages
#include "layEditorOptionsPage.h"
+#include "layEditorOptionsPageWidget.h"
#include
@@ -35,6 +36,7 @@
class QTabWidget;
class QLabel;
+class QHBoxLayout;
namespace Ui
{
@@ -54,6 +56,7 @@ namespace lay
class Dispatcher;
class LayoutViewBase;
class Plugin;
+ class DecoratedLineEdit;
}
namespace edt
@@ -65,7 +68,7 @@ class PCellParametersPage;
* @brief The generic properties page
*/
class EditorOptionsGeneric
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -90,7 +93,7 @@ public slots:
* @brief The text properties page
*/
class EditorOptionsText
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
public:
EditorOptionsText (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
@@ -109,7 +112,7 @@ class EditorOptionsText
* @brief The path properties page
*/
class EditorOptionsPath
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -133,7 +136,7 @@ public slots:
* @brief The instance properties page
*/
class EditorOptionsInst
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -165,7 +168,7 @@ private slots:
* @brief The instance properties page (PCell parameters)
*/
class EditorOptionsInstPCellParam
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -192,6 +195,53 @@ private slots:
virtual void technology_changed (const std::string &);
};
+/**
+ * @brief The toolbox widget for boxes
+ */
+class BoxToolboxWidget
+ : public lay::EditorOptionsPageWidget
+{
+Q_OBJECT
+
+public:
+ BoxToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+ ~BoxToolboxWidget ();
+
+ virtual std::string title () const;
+ virtual int order () const { return 0; }
+ virtual void configure (const std::string &name, const std::string &value);
+ virtual void commit (lay::Dispatcher *root);
+ virtual void deactivated ();
+
+private:
+ QHBoxLayout *mp_layout;
+ lay::DecoratedLineEdit *mp_x_le, *mp_y_le;
+};
+
+/**
+ * @brief The toolbox widget for connections (path, polygon edges)
+ */
+class ConnectionToolboxWidget
+ : public lay::EditorOptionsPageWidget
+{
+Q_OBJECT
+
+public:
+ ConnectionToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+ ~ConnectionToolboxWidget ();
+
+ virtual std::string title () const;
+ virtual int order () const { return 0; }
+ virtual void configure (const std::string &name, const std::string &value);
+ virtual void commit (lay::Dispatcher *root);
+ virtual void deactivated ();
+
+private:
+ QHBoxLayout *mp_layout;
+ lay::DecoratedLineEdit *mp_x_le, *mp_y_le;
+ bool m_in_commit;
+};
+
}
#endif
diff --git a/src/edt/edt/edtInstService.cc b/src/edt/edt/edtInstService.cc
index 3e92d981a..001b87356 100644
--- a/src/edt/edt/edtInstService.cc
+++ b/src/edt/edt/edtInstService.cc
@@ -417,7 +417,7 @@ InstService::do_mouse_click (const db::DPoint &p)
}
void
-InstService::do_finish_edit ()
+InstService::do_finish_edit (bool /*accept*/)
{
try {
diff --git a/src/edt/edt/edtInstService.h b/src/edt/edt/edtInstService.h
index 31fb98e19..4b8ecc155 100644
--- a/src/edt/edt/edtInstService.h
+++ b/src/edt/edt/edtInstService.h
@@ -53,7 +53,7 @@ class InstService
virtual void do_mouse_move (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_mouse_transform (const db::DPoint &p, db::DFTrans trans);
- virtual void do_finish_edit ();
+ virtual void do_finish_edit (bool accept);
virtual void do_cancel_edit ();
virtual bool do_activated ();
#if defined(HAVE_QT)
diff --git a/src/edt/edt/edtMoveTrackerService.cc b/src/edt/edt/edtMoveTrackerService.cc
index 32a7e2cfa..c1b8abc34 100644
--- a/src/edt/edt/edtMoveTrackerService.cc
+++ b/src/edt/edt/edtMoveTrackerService.cc
@@ -133,6 +133,13 @@ MoveTrackerService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_ty
move_cancel (); // formally this functionality fits here
}
+void
+MoveTrackerService::end_move (const db::DVector & /*v*/)
+{
+ call_editor_hooks (m_editor_hooks, &edt::EditorHooks::commit_edit);
+ move_cancel (); // formally this functionality fits here
+}
+
void
MoveTrackerService::edit_cancel ()
{
diff --git a/src/edt/edt/edtMoveTrackerService.h b/src/edt/edt/edtMoveTrackerService.h
index d92d9f3aa..48c18bc08 100644
--- a/src/edt/edt/edtMoveTrackerService.h
+++ b/src/edt/edt/edtMoveTrackerService.h
@@ -68,6 +68,11 @@ class EDT_PUBLIC MoveTrackerService
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
+ /**
+ * @brief Terminate a "move" operation with compulsory move vector
+ */
+ virtual void end_move (const db::DVector &v);
+
/**
* @brief Access to the view object
*/
diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc
index b2eb61acd..b5b8ca700 100644
--- a/src/edt/edt/edtPartialService.cc
+++ b/src/edt/edt/edtPartialService.cc
@@ -26,6 +26,7 @@
#include "laySnap.h"
#include "layFinder.h"
#include "layConverters.h"
+#include "layMove.h"
#include "tlProgress.h"
#include "edtPartialService.h"
#include "edtService.h"
@@ -1096,7 +1097,7 @@ PartialService::PartialService (db::Manager *manager, lay::LayoutViewBase *view,
db::Object (manager),
mp_view (view),
mp_root (root),
- m_dragging (false),
+ m_moving (false),
m_keep_selection (true),
mp_box (0),
m_color (0),
@@ -1406,15 +1407,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
PartialService::transform (const db::DCplxTrans &tr)
{
@@ -1769,7 +1761,7 @@ void
PartialService::edit_cancel ()
{
// stop dragging, clear selection
- m_dragging = false;
+ m_moving = false;
if (mp_box) {
delete mp_box;
@@ -1790,74 +1782,85 @@ PartialService::wheel_event (int /*delta*/, bool /*horizontal*/, const db::DPoin
return false;
}
-bool
-PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
-{
- clear_mouse_cursors ();
-
- if (m_dragging) {
+const int sr_pixels = 8; // TODO: make variable
- set_cursor (lay::Cursor::size_all);
+void
+PartialService::move_impl (const db::DPoint &p)
+{
+ // drag the vertex or edge/segment
+ if (is_single_point_selection () || is_single_edge_selection ()) {
- m_alt_ac = lay::ac_from_buttons (buttons);
+ lay::PointSnapToObjectResult snap_details;
- // drag the vertex or edge/segment
- if (is_single_point_selection () || is_single_edge_selection ()) {
+ // 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
+ 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);;
- lay::PointSnapToObjectResult snap_details;
+ if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
- // 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);
+ m_current = m_start + snap_move (p - m_start);
- if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
+ } else {
- m_current = m_start + snap_move (p - m_start);
+ auto snapped_to_object = snap_details.snapped_point;
+ m_current = snapped_to_object;
- } else {
+ if (snap_details.object_snap != lay::PointSnapToObjectResult::ObjectVertex) {
- auto snapped_to_object = snap_details.snapped_point;
- m_current = snapped_to_object;
-
- if (snap_details.object_snap != lay::PointSnapToObjectResult::ObjectVertex) {
- // 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);
- if (std::abs (snap_details.object_ref.dx ()) > std::abs (snap_details.object_ref.dy ())) {
- m_current.set_x (snapped_to_object_and_grid.x ());
- // project to edge, so we always hit it
- auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (0, 1.0)));
- if (cp.first) {
- m_current.set_y (cp.second.y ());
- }
- } else if (std::abs (snap_details.object_ref.dy ()) > std::abs (snap_details.object_ref.dx ())) {
- m_current.set_y (snapped_to_object_and_grid.y ());
- // project to edge, so we always hit it
- auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (1.0, 0)));
- if (cp.first) {
- m_current.set_x (cp.second.x ());
- }
+ // 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);
+ if (std::abs (snap_details.object_ref.dx ()) > std::abs (snap_details.object_ref.dy ())) {
+ m_current.set_x (snapped_to_object_and_grid.x ());
+ // project to edge, so we always hit it
+ auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (0, 1.0)));
+ if (cp.first) {
+ m_current.set_y (cp.second.y ());
+ }
+ } else if (std::abs (snap_details.object_ref.dy ()) > std::abs (snap_details.object_ref.dx ())) {
+ m_current.set_y (snapped_to_object_and_grid.y ());
+ // project to edge, so we always hit it
+ auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (1.0, 0)));
+ if (cp.first) {
+ m_current.set_x (cp.second.x ());
}
}
- mouse_cursor_from_snap_details (snap_details);
-
}
- } else {
+ mouse_cursor_from_snap_details (snap_details);
- // snap movement to angle and grid without object
- m_current = m_start + snap_move (p - m_start);
- clear_mouse_cursors ();
+ }
+
+ 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);
+ }
}
- selection_to_view ();
+ } else {
- call_editor_hooks (m_editor_hooks, &edt::EditorHooks::begin_edits);
- issue_editor_hook_calls (m_editor_hooks);
- call_editor_hooks (m_editor_hooks, &edt::EditorHooks::end_edits);
+ // snap movement to angle and grid without object
+ m_current = m_start + snap_move (p - m_start);
- m_alt_ac = lay::AC_Global;
+ }
+
+ selection_to_view ();
+}
+
+bool
+PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
+{
+ if (m_moving) {
+
+ // event is handled by the move service
+ return false;
} else if (prio) {
@@ -1916,9 +1919,9 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo
return false;
}
- if (m_dragging) {
+ if (m_moving) {
- // eat events if already dragging
+ // eat events if moving -> handled by move service
return true;
} else if (! mp_box) {
@@ -1964,25 +1967,8 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo
} else {
- // something was selected: start dragging this ..
- m_dragging = true;
- m_keep_selection = true;
-
- if (is_single_point_selection ()) {
- // for a single selected point we use the original point as the start location which
- // allows bringing it to grid
- m_current = m_start = single_selected_point ();
- } else if (is_single_edge_selection ()) {
- // for an edge selection use the point projected to edge as the start location which
- // allows bringing it to grid
- m_current = m_start = projected_to_edge (single_selected_edge (), p);
- } else {
- m_current = m_start = p;
- }
-
- ui ()->grab_mouse (this, true);
-
- open_editor_hooks ();
+ // delegate further actions to move service, which will start a move operation
+ mp_view->move_service ()->start_move ();
}
@@ -2014,43 +2000,9 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
return false;
}
- if (m_dragging) {
-
- m_alt_ac = lay::ac_from_buttons (buttons);
-
- if (m_current != m_start) {
-
- // stop dragging
- ui ()->ungrab_mouse (this);
-
- if (manager ()) {
- manager ()->transaction (tl::to_string (tr ("Partial move")));
- }
+ if (m_moving) {
- // heuristically, if there is just one edge selected: do not confine to the movement
- // angle constraint - the edge usually is confined enough
- db::DTrans move_trans = db::DTrans (m_current - m_start);
-
- transform_selection (move_trans);
-
- if (manager ()) {
- manager ()->commit ();
- }
-
- }
-
- if (! m_keep_selection) {
- m_selection.clear ();
- }
-
- m_dragging = false;
- selection_to_view ();
-
- close_editor_hooks (true);
-
- m_alt_ac = lay::AC_Global;
-
- return true;
+ return false;
} else if (ui ()->mouse_event_viewport ().contains (p)) {
@@ -2143,25 +2095,15 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
}
- // start dragging with that single selection
+ // start dragging with the selection
if (mode == lay::Editable::Replace && ! m_selection.empty ()) {
- m_dragging = true;
- m_keep_selection = ! new_selection;
-
- if (is_single_point_selection ()) {
- // for a single selected point we use the original point as the start location which
- // allows bringing it to grid
- m_current = m_start = single_selected_point ();
- } else if (is_single_edge_selection ()) {
- // for an edge selection use the point projected to edge as the start location which
- // allows bringing it to grid
- m_current = m_start = projected_to_edge (single_selected_edge (), p);
- } else {
- m_current = m_start = p;
- }
+ // delegate further actions to move service, which will start a move operation
+ mp_view->move_service ()->start_move ();
- open_editor_hooks ();
+ // modify the decision to keep the selection (needs to come after the
+ // move service called begin_move)
+ m_keep_selection = ! new_selection;
}
@@ -2197,10 +2139,6 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt
close_editor_hooks (false);
- // stop dragging
- ui ()->ungrab_mouse (this);
- m_dragging = false;
-
partial_select (db::DBox (p, p), lay::Editable::Replace);
if (! m_selection.empty ()) {
@@ -2352,7 +2290,7 @@ PartialService::begin_move (MoveMode mode, const db::DPoint &p, lay::angle_const
m_alt_ac = ac;
- m_dragging = true;
+ m_moving = true;
m_keep_selection = true;
if (is_single_point_selection ()) {
@@ -2432,7 +2370,7 @@ PartialService::snap_marker_to_grid (const db::DVector &v, bool &snapped) const
if (snapped) {
vr += vv;
- return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ());
+ return db::DVector (vr.x () * fabs (snapped_to.x ()), vr.y () * fabs (snapped_to.y ()));
} else {
return db::DVector ();
}
@@ -2452,62 +2390,42 @@ PartialService::snap_move (const db::DVector &v) const
void
PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
{
- if (! m_dragging) {
+ if (! m_moving) {
return;
}
m_alt_ac = ac;
set_cursor (lay::Cursor::size_all);
+ clear_mouse_cursors ();
- // 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 ();
+ move_impl (p);
- }
-
- selection_to_view ();
+ propose_move_transformation (db::DTrans (m_current - m_start), 0);
m_alt_ac = lay::AC_Global;
}
void
-PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
+PartialService::end_move (const db::DVector &v)
{
- if (! m_dragging) {
+ m_current = m_start + v;
+ end_move (db::DPoint (), lay::AC_Any);
+}
+
+void
+PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
+{
+ if (! m_moving) {
return;
}
- m_alt_ac = ac;
-
if (m_current != m_start) {
- // stop dragging
- ui ()->ungrab_mouse (this);
-
if (manager ()) {
manager ()->transaction (tl::to_string (tr ("Partial move")));
}
- // heuristically, if there is just one edge selected: do not confine to the movement
- // angle constraint - the edge usually is confined enough
db::DTrans move_trans = db::DTrans (m_current - m_start);
transform_selection (move_trans);
@@ -2522,7 +2440,7 @@ PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type a
m_selection.clear ();
}
- m_dragging = false;
+ m_moving = false;
selection_to_view ();
clear_mouse_cursors ();
@@ -2608,9 +2526,6 @@ PartialService::del ()
{
std::set needs_cleanup;
- // stop dragging
- ui ()->ungrab_mouse (this);
-
std::map >, std::vector > shapes_to_delete_by_cell;
for (partial_objects::iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
@@ -2703,7 +2618,6 @@ PartialService::del ()
handle_guiding_shape_changes ();
m_selection.clear ();
- m_dragging = false;
selection_to_view ();
close_editor_hooks (false);
@@ -3008,22 +2922,8 @@ PartialService::do_selection_to_view ()
{
// if dragging, establish the current displacement
db::DTrans move_trans;
- if (m_dragging) {
-
- // heuristically, if there is just one edge selected: do not confine to the movement
- // angle constraint - the edge usually is confined enough
- if (m_selection.size () == 1 && ! m_selection.begin ()->first.is_cell_inst () && m_selection.begin ()->second.size () == 3 /*p1,p2,edge*/) {
- move_trans = db::DTrans (m_current - m_start);
- } else {
- // TODO: DTrans should have a ctor that takes a vector
- move_trans = db::DTrans (lay::snap_angle (m_current - m_start, move_ac ()));
- }
-
- // display vector
- view ()->message (std::string ("dx: ") + tl::micron_to_string (move_trans.disp ().x ()) +
- std::string (" dy: ") + tl::micron_to_string (move_trans.disp ().y ()) +
- std::string (" d: ") + tl::micron_to_string (move_trans.disp ().length ()));
-
+ if (m_moving) {
+ move_trans = db::DTrans (m_current - m_start);
}
size_t n_marker = 0;
@@ -3065,7 +2965,7 @@ PartialService::do_selection_to_view ()
std::map new_edges;
std::map new_points;
- if (m_dragging) {
+ if (m_moving) {
create_shift_sets (r->first.shape (), r->second, new_points, new_edges, move_vector);
}
diff --git a/src/edt/edt/edtPartialService.h b/src/edt/edt/edtPartialService.h
index 594c73108..7d3c55d49 100644
--- a/src/edt/edt/edtPartialService.h
+++ b/src/edt/edt/edtPartialService.h
@@ -287,6 +287,11 @@ Q_OBJECT
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
+ /**
+ * @brief Terminate a "move" operation with compulsory move vector
+ */
+ virtual void end_move (const db::DVector &v);
+
/**
* @brief Implement the "select" method at least to clear the selection
*/
@@ -335,7 +340,7 @@ public slots:
// The layout view that this service is attached to
lay::LayoutViewBase *mp_view;
lay::Dispatcher *mp_root;
- bool m_dragging;
+ bool m_moving;
bool m_keep_selection;
db::DPoint m_start, m_current;
db::DPoint m_p1, m_p2;
@@ -381,10 +386,10 @@ public slots:
db::DPoint snap (const db::DPoint &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;
db::DVector snap_marker_to_grid (const db::DVector &v, bool &snapped) 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 &new_points, const std::map &new_edges, const db::ICplxTrans >, const std::vector &tv, bool transient);
void enter_vertices (size_t &nmarker, partial_objects::const_iterator sel, const std::map &new_points, const std::map &new_edges, const db::ICplxTrans >, const std::vector &tv, bool transient);
diff --git a/src/edt/edt/edtPathService.cc b/src/edt/edt/edtPathService.cc
index 65863b591..9ecc36992 100644
--- a/src/edt/edt/edtPathService.cc
+++ b/src/edt/edt/edtPathService.cc
@@ -26,6 +26,7 @@
#include "edtPropertiesPages.h"
#include "layLayoutViewBase.h"
+#include "layEditorOptionsPage.h"
#include "layFinder.h"
namespace edt
@@ -160,13 +161,15 @@ PathService::do_delete ()
}
void
-PathService::do_finish_edit ()
+PathService::do_finish_edit (bool accept)
{
- // one point is reserved for the "current one"
- if (m_points.size () < 3) {
+ // one point is reserved for the "current one" if accept is false
+ if (! accept && ! m_points.empty ()) {
+ m_points.pop_back ();
+ }
+ if (m_points.size () < 2) {
throw tl::Exception (tl::to_string (tr ("A path must have at least 2 points")));
}
- m_points.pop_back ();
deliver_shape (get_path ());
@@ -175,6 +178,32 @@ PathService::do_finish_edit ()
close_editor_hooks (true);
}
+void
+PathService::function (const std::string &name, const std::string &value)
+{
+ if (name == ShapeEditService::connection_function_name ()) {
+
+ try {
+
+ db::DVector dim;
+ tl::from_string (value, dim);
+
+ if (m_points.size () >= 2) {
+
+ m_last = m_points.back () = m_points.end () [-2] + dim;
+ m_points.push_back (m_last);
+
+ update_marker ();
+ update_via ();
+
+ }
+
+ } catch (...) {
+ }
+
+ }
+}
+
void
PathService::update_marker ()
{
@@ -185,12 +214,17 @@ PathService::update_marker ()
marker->set (path, db::VCplxTrans (1.0 / layout ().dbu ()) * trans ().inverted ());
if (m_points.size () >= 2) {
+ db::DVector dim = m_points.back () - m_points.end () [-2];
view ()->message (std::string ("lx: ") +
- tl::micron_to_string (m_points.back ().x () - m_points.end () [-2].x ()) +
+ tl::micron_to_string (dim.x ()) +
std::string (" ly: ") +
- tl::micron_to_string (m_points.back ().y () - m_points.end () [-2].y ()) +
+ tl::micron_to_string (dim.y ()) +
std::string (" l: ") +
- tl::micron_to_string (m_points.back ().distance (m_points.end () [-2])));
+ tl::micron_to_string (dim.length ()));
+ auto tb = toolbox_widget ();
+ if (tb) {
+ tb->configure (ShapeEditService::connection_configure_name (), dim.to_string ());
+ }
}
}
diff --git a/src/edt/edt/edtPathService.h b/src/edt/edt/edtPathService.h
index b7321fa53..507a27f16 100644
--- a/src/edt/edt/edtPathService.h
+++ b/src/edt/edt/edtPathService.h
@@ -47,11 +47,12 @@ class PathService
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual void do_delete ();
- virtual void do_finish_edit ();
+ virtual void do_finish_edit (bool accept);
virtual void do_cancel_edit ();
virtual bool do_activated ();
virtual void via (int dir);
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
+ virtual void function (const std::string &name, const std::string &value);
protected:
bool configure (const std::string &name, const std::string &value);
diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc
index 33fbb341f..1bc60d64a 100644
--- a/src/edt/edt/edtPlugin.cc
+++ b/src/edt/edt/edtPlugin.cc
@@ -21,13 +21,9 @@
*/
-#if defined(HAVE_QT)
-# include "layTipDialog.h"
-# include "layEditorOptionsPages.h"
-#endif
-
#include "layDispatcher.h"
#include "layLayoutViewBase.h"
+#include "layEditorOptionsPage.h"
#include "edtPlugin.h"
#include "edtConfig.h"
#include "edtService.h"
@@ -40,38 +36,19 @@
#include "edtMainService.h"
#include "edtPartialService.h"
#include "edtMoveTrackerService.h"
-#if defined(HAVE_QT)
-# include "edtEditorOptionsPages.h"
-# include "edtRecentConfigurationPage.h"
-#endif
+#include "edtEditorOptionsPages.h"
+#include "edtRecentConfigurationPage.h"
#if defined(HAVE_QT)
# include
# include
# include
+# include "layTipDialog.h"
#endif
namespace edt
{
-#if defined(HAVE_QT)
-edt::RecentConfigurationPage::ConfigurationDescriptor shape_cfg_descriptors[] =
-{
- edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
-};
-#endif
-
-#if defined(HAVE_QT)
-static
-void get_shape_editor_options_pages (std::vector &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
-{
- ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-shape-param",
- &shape_cfg_descriptors[0], &shape_cfg_descriptors[sizeof (shape_cfg_descriptors) / sizeof (shape_cfg_descriptors[0])]));
-}
-#else
-static void get_shape_editor_options_pages () { }
-#endif
-
static
void get_text_options (std::vector < std::pair > &options)
{
@@ -81,27 +58,6 @@ void get_text_options (std::vector < std::pair > &opti
options.push_back (std::pair (cfg_edit_text_valign, "bottom"));
}
-#if defined(HAVE_QT)
-static
-void get_text_editor_options_pages (std::vector &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
-{
- static edt::RecentConfigurationPage::ConfigurationDescriptor text_cfg_descriptors[] =
- {
- edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_string, tl::to_string (tr ("Text")), edt::RecentConfigurationPage::Text),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_size, tl::to_string (tr ("Size")), edt::RecentConfigurationPage::Double),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_halign, tl::to_string (tr ("Hor. align")), edt::RecentConfigurationPage::Text),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_valign, tl::to_string (tr ("Vert. align")), edt::RecentConfigurationPage::Text)
- };
-
- ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param",
- &text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])]));
- ret.push_back (new edt::EditorOptionsText (view, dispatcher));
-}
-#else
-static void get_text_editor_options_pages () { }
-#endif
-
static
void get_path_options (std::vector < std::pair > &options)
{
@@ -111,27 +67,6 @@ void get_path_options (std::vector < std::pair > &opti
options.push_back (std::pair (cfg_edit_path_ext_var_end, "0.0"));
}
-#if defined(HAVE_QT)
-static
-void get_path_editor_options_pages (std::vector &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
-{
- static edt::RecentConfigurationPage::ConfigurationDescriptor path_cfg_descriptors[] =
- {
- edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_width, tl::to_string (tr ("Width")), edt::RecentConfigurationPage::Double),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_type, tl::to_string (tr ("Ends")), edt::RecentConfigurationPage::Int),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_begin, tl::to_string (tr ("Begin ext.")), edt::RecentConfigurationPage::Double),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_end, tl::to_string (tr ("End ext.")), edt::RecentConfigurationPage::Double)
- };
-
- ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param",
- &path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])]));
- ret.push_back (new EditorOptionsPath (view, dispatcher));
-}
-#else
-static void get_path_editor_options_pages () { }
-#endif
-
static
void get_inst_options (std::vector < std::pair > &options)
{
@@ -153,58 +88,17 @@ void get_inst_options (std::vector < std::pair > &opti
options.push_back (std::pair (cfg_edit_show_shapes_of_instances, "true"));
}
-#if defined(HAVE_QT)
-static
-void get_inst_editor_options_pages (std::vector &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
-{
- static edt::RecentConfigurationPage::ConfigurationDescriptor inst_cfg_descriptors[] =
- {
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_lib_name, tl::to_string (tr ("Library")), edt::RecentConfigurationPage::CellLibraryName),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_cell_name, tl::to_string (tr ("Cell")), edt::RecentConfigurationPage::CellDisplayName),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_angle, tl::to_string (tr ("Angle")), edt::RecentConfigurationPage::Double),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_mirror, tl::to_string (tr ("Mirror")), edt::RecentConfigurationPage::Bool),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_scale, tl::to_string (tr ("Scale")), edt::RecentConfigurationPage::Double),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_array, tl::to_string (tr ("Array")), edt::RecentConfigurationPage::ArrayFlag),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_rows, tl::to_string (tr ("Rows")), edt::RecentConfigurationPage::IntIfArray),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_x, tl::to_string (tr ("Row step (x)")), edt::RecentConfigurationPage::DoubleIfArray),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_y, tl::to_string (tr ("Row step (y)")), edt::RecentConfigurationPage::DoubleIfArray),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_columns, tl::to_string (tr ("Columns")), edt::RecentConfigurationPage::IntIfArray),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_x, tl::to_string (tr ("Column step (x)")), edt::RecentConfigurationPage::DoubleIfArray),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_y, tl::to_string (tr ("Column step (y)")), edt::RecentConfigurationPage::DoubleIfArray),
- edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_pcell_parameters, tl::to_string (tr ("PCell parameters")), edt::RecentConfigurationPage::PCellParameters)
- };
-
- ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param",
- &inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])]));
- ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher));
- ret.push_back (new EditorOptionsInst (view, dispatcher));
-}
-#else
-static void get_inst_editor_options_pages () { }
-#endif
-
template
class PluginDeclaration
: public PluginDeclarationBase
{
public:
-#if defined(HAVE_QT)
PluginDeclaration (const std::string &title, const std::string &mouse_mode,
- void (*option_get_f) (std::vector < std::pair > &) = 0,
- void (*pages_f) (std::vector &, lay::LayoutViewBase *, lay::Dispatcher *) = 0)
- : m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f), mp_pages_f (pages_f)
+ void (*option_get_f) (std::vector < std::pair > &) = 0)
+ : m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f)
{
// .. nothing yet ..
}
-#else
- PluginDeclaration (const std::string &title, const std::string &mouse_mode,
- void (*option_get_f) (std::vector < std::pair > &) = 0,
- void (*pages_f) () = 0)
- : m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f), mp_pages_f (pages_f)
- {
- // .. nothing yet ..
- }
-#endif
virtual void get_options (std::vector < std::pair > &options) const
{
@@ -225,19 +119,6 @@ class PluginDeclaration
// .. nothing yet ..
}
-#if defined(HAVE_QT)
- virtual void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *root) const
- {
- if (mp_pages_f != 0) {
- size_t nstart = pages.size ();
- (*mp_pages_f) (pages, view, root);
- while (nstart < pages.size ()) {
- pages [nstart++]->set_plugin_declaration (this);
- }
- }
- }
-#endif
-
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *, lay::LayoutViewBase *view) const
{
Svc *service = new Svc (manager, view);
@@ -266,40 +147,35 @@ class PluginDeclaration
std::string m_mouse_mode;
void (*mp_option_get_f) (std::vector < std::pair > &options);
-#if defined(HAVE_QT)
- void (*mp_pages_f) (std::vector &, lay::LayoutViewBase *, lay::Dispatcher *);
-#else
- void (*mp_pages_f) ();
-#endif
};
static tl::RegisteredClass config_decl1 (
- new edt::PluginDeclaration (tl::to_string (tr ("Polygons")), "polygon:edit_mode\t" + tl::to_string (tr ("Polygon")) + "<:polygon_24px.png>" + tl::to_string (tr ("{Create a polygon}")), 0, &get_shape_editor_options_pages),
+ new edt::PluginDeclaration (tl::to_string (tr ("Polygons")), "polygon:edit_mode\t" + tl::to_string (tr ("Polygon")) + "<:polygon_24px.png>" + tl::to_string (tr ("{Create a polygon}")), 0),
4010,
"edt::Service(Polygons)"
);
static tl::RegisteredClass config_decl2 (
- new edt::PluginDeclaration (tl::to_string (tr ("Boxes")), "box:edit_mode\t" + tl::to_string (tr ("Box")) + "\t<:box_24px.png>" + tl::to_string (tr ("{Create a box}")), 0, &get_shape_editor_options_pages),
+ new edt::PluginDeclaration (tl::to_string (tr ("Boxes")), "box:edit_mode\t" + tl::to_string (tr ("Box")) + "\t<:box_24px.png>" + tl::to_string (tr ("{Create a box}")), 0),
4011,
"edt::Service(Boxes)"
);
static tl::RegisteredClass config_decl3 (
- new edt::PluginDeclaration (tl::to_string (tr ("Texts")), "text:edit_mode\t" + tl::to_string (tr ("Text")) + "\t<:text_24px.png>" + tl::to_string (tr ("{Create a text object}")), &get_text_options, &get_text_editor_options_pages),
+ new edt::PluginDeclaration (tl::to_string (tr ("Texts")), "text:edit_mode\t" + tl::to_string (tr ("Text")) + "\t<:text_24px.png>" + tl::to_string (tr ("{Create a text object}")), &get_text_options),
4012,
"edt::Service(Texts)"
);
static tl::RegisteredClass config_decl4 (
- new edt::PluginDeclaration (tl::to_string (tr ("Paths")), "path:edit_mode\t" + tl::to_string (tr ("Path")) + "\t<:path_24px.png>" + tl::to_string (tr ("{Create a path}")), &get_path_options, &get_path_editor_options_pages),
+ new edt::PluginDeclaration (tl::to_string (tr ("Paths")), "path:edit_mode\t" + tl::to_string (tr ("Path")) + "\t<:path_24px.png>" + tl::to_string (tr ("{Create a path}")), &get_path_options),
4013,
"edt::Service(Paths)"
);
static tl::RegisteredClass config_decl5 (
- new edt::PluginDeclaration (tl::to_string (tr ("Points")), std::string (), 0, &get_shape_editor_options_pages),
+ new edt::PluginDeclaration (tl::to_string (tr ("Points")), std::string (), 0),
4014,
"edt::Service(Points)"
);
static tl::RegisteredClass config_decl6 (
- new edt::PluginDeclaration (tl::to_string (tr ("Instances")), "instance:edit_mode\t" + tl::to_string (tr ("Instance")) + "\t<:instance_24px.png>" + tl::to_string (tr ("{Create a cell instance}")), &get_inst_options, &get_inst_editor_options_pages),
+ new edt::PluginDeclaration (tl::to_string (tr ("Instances")), "instance:edit_mode\t" + tl::to_string (tr ("Instance")) + "\t<:instance_24px.png>" + tl::to_string (tr ("{Create a cell instance}")), &get_inst_options),
4020,
"edt::Service(CellInstances)"
);
@@ -418,15 +294,6 @@ class MainPluginDeclaration
return false;
}
-#if defined(HAVE_QT)
- virtual void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
- {
- // NOTE: we do not set plugin_declaration which makes the page unspecific
- EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher);
- pages.push_back (generic_opt);
- }
-#endif
-
virtual void initialize (lay::Dispatcher *root)
{
lay::Dispatcher *mp = lay::Dispatcher::instance ();
@@ -524,16 +391,6 @@ class PartialPluginDeclaration
// .. nothing yet ..
}
- virtual void get_options (std::vector < std::pair > & /*options*/) const
- {
- // .. nothing yet ..
- }
-
- virtual void get_editor_options_pages (std::vector & /*pages*/, lay::LayoutViewBase * /*view*/, lay::Dispatcher * /*root*/) const
- {
- // .. no specific ones ..
- }
-
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *root, lay::LayoutViewBase *view) const
{
return new edt::PartialService (manager, view, root);
diff --git a/src/edt/edt/edtPointService.cc b/src/edt/edt/edtPointService.cc
index 7c627a5d1..08e3b56f8 100644
--- a/src/edt/edt/edtPointService.cc
+++ b/src/edt/edt/edtPointService.cc
@@ -124,7 +124,7 @@ PointService::do_mouse_click (const db::DPoint &p)
}
void
-PointService::do_finish_edit ()
+PointService::do_finish_edit (bool /*accept*/)
{
deliver_shape (get_point ());
commit_recent ();
diff --git a/src/edt/edt/edtPointService.h b/src/edt/edt/edtPointService.h
index 264336398..0b262a235 100644
--- a/src/edt/edt/edtPointService.h
+++ b/src/edt/edt/edtPointService.h
@@ -45,7 +45,7 @@ class PointService
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
- virtual void do_finish_edit ();
+ virtual void do_finish_edit (bool);
virtual void do_cancel_edit ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
diff --git a/src/edt/edt/edtPolygonService.cc b/src/edt/edt/edtPolygonService.cc
index 3f45639f1..aab0d916f 100644
--- a/src/edt/edt/edtPolygonService.cc
+++ b/src/edt/edt/edtPolygonService.cc
@@ -24,6 +24,7 @@
#include "edtPolygonService.h"
#include "layLayoutViewBase.h"
+#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
@@ -135,13 +136,44 @@ PolygonService::do_mouse_click (const db::DPoint &p)
}
void
-PolygonService::do_finish_edit ()
+PolygonService::do_finish_edit (bool accept)
{
+ if (accept) {
+ // add a dummy point in this case for the current one
+ m_last = m_points.back ();
+ m_points.push_back (db::DPoint ());
+ }
+
deliver_shape (get_polygon (false));
commit_recent ();
close_editor_hooks (true);
}
+void
+PolygonService::function (const std::string &name, const std::string &value)
+{
+ if (name == ShapeEditService::connection_function_name ()) {
+
+ try {
+
+ db::DVector dim;
+ tl::from_string (value, dim);
+
+ if (m_points.size () >= 2) {
+
+ m_last = m_points.back () = m_points.end () [-2] + dim;
+ m_points.push_back (m_last);
+
+ update_marker ();
+
+ }
+
+ } catch (...) {
+ }
+
+ }
+}
+
db::Polygon
PolygonService::get_polygon (bool editing) const
{
@@ -363,12 +395,17 @@ PolygonService::update_marker ()
}
if (m_points.size () >= 2) {
+ db::DVector dim = m_points.back () - m_points [m_points.size () - 2];
view ()->message (std::string ("lx: ") +
- tl::micron_to_string (m_points.back ().x () - m_points.end () [-2].x ()) +
+ tl::micron_to_string (dim.x ()) +
std::string (" ly: ") +
- tl::micron_to_string (m_points.back ().y () - m_points.end () [-2].y ()) +
+ tl::micron_to_string (dim.y ()) +
std::string (" l: ") +
- tl::micron_to_string (m_points.back ().distance (m_points.end () [-2])));
+ tl::micron_to_string (dim.length ()));
+ auto tb = toolbox_widget ();
+ if (tb) {
+ tb->configure (ShapeEditService::connection_configure_name (), dim.to_string ());
+ }
}
// call hooks with new shape
diff --git a/src/edt/edt/edtPolygonService.h b/src/edt/edt/edtPolygonService.h
index 1171a8bab..488d59653 100644
--- a/src/edt/edt/edtPolygonService.h
+++ b/src/edt/edt/edtPolygonService.h
@@ -46,9 +46,10 @@ class PolygonService
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
- virtual void do_finish_edit ();
+ virtual void do_finish_edit (bool);
virtual void do_cancel_edit ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
+ virtual void function (const std::string &name, const std::string &value);
private:
std::vector m_points;
diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc
index c2df2e655..127a385b2 100644
--- a/src/edt/edt/edtRecentConfigurationPage.cc
+++ b/src/edt/edt/edtRecentConfigurationPage.cc
@@ -23,6 +23,7 @@
#if defined(HAVE_QT)
#include "edtRecentConfigurationPage.h"
+#include "edtConfig.h"
#include "layDispatcher.h"
#include "layLayoutViewBase.h"
#include "layLayerTreeModel.h"
@@ -497,6 +498,92 @@ RecentConfigurationPage::config_recent_for_layer (lay::Dispatcher *root, const d
}
}
+// ------------------------------------------------------------------
+// Configurations and registrations
+
+namespace {
+
+class RecentShapeConfigurationPage
+ : public edt::RecentConfigurationPage
+{
+public:
+ RecentShapeConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : edt::RecentConfigurationPage (view, dispatcher, "edit-recent-shape-param")
+ {
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer));
+
+ init ();
+ }
+};
+
+class RecentTextConfigurationPage
+ : public edt::RecentConfigurationPage
+{
+public:
+ RecentTextConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : edt::RecentConfigurationPage (view, dispatcher, "edit-recent-text-param")
+ {
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_string, tl::to_string (tr ("Text")), edt::RecentConfigurationPage::Text));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_size, tl::to_string (tr ("Size")), edt::RecentConfigurationPage::Double));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_halign, tl::to_string (tr ("Hor. align")), edt::RecentConfigurationPage::Text));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_valign, tl::to_string (tr ("Vert. align")), edt::RecentConfigurationPage::Text));
+
+ init ();
+ }
+};
+
+class RecentPathConfigurationPage
+ : public edt::RecentConfigurationPage
+{
+public:
+ RecentPathConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : edt::RecentConfigurationPage (view, dispatcher, "edit-recent-path-param")
+ {
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_width, tl::to_string (tr ("Width")), edt::RecentConfigurationPage::Double));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_type, tl::to_string (tr ("Ends")), edt::RecentConfigurationPage::Int));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_begin, tl::to_string (tr ("Begin ext.")), edt::RecentConfigurationPage::Double));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_end, tl::to_string (tr ("End ext.")), edt::RecentConfigurationPage::Double));
+
+ init ();
+ }
+};
+
+class RecentInstConfigurationPage
+ : public edt::RecentConfigurationPage
+{
+public:
+ RecentInstConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : edt::RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param")
+ {
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_lib_name, tl::to_string (tr ("Library")), edt::RecentConfigurationPage::CellLibraryName));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_cell_name, tl::to_string (tr ("Cell")), edt::RecentConfigurationPage::CellDisplayName));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_angle, tl::to_string (tr ("Angle")), edt::RecentConfigurationPage::Double));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_mirror, tl::to_string (tr ("Mirror")), edt::RecentConfigurationPage::Bool));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_scale, tl::to_string (tr ("Scale")), edt::RecentConfigurationPage::Double));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_array, tl::to_string (tr ("Array")), edt::RecentConfigurationPage::ArrayFlag));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_rows, tl::to_string (tr ("Rows")), edt::RecentConfigurationPage::IntIfArray));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_x, tl::to_string (tr ("Row step (x)")), edt::RecentConfigurationPage::DoubleIfArray));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_y, tl::to_string (tr ("Row step (y)")), edt::RecentConfigurationPage::DoubleIfArray));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_columns, tl::to_string (tr ("Columns")), edt::RecentConfigurationPage::IntIfArray));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_x, tl::to_string (tr ("Column step (x)")), edt::RecentConfigurationPage::DoubleIfArray));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_y, tl::to_string (tr ("Column step (y)")), edt::RecentConfigurationPage::DoubleIfArray));
+ add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_pcell_parameters, tl::to_string (tr ("PCell parameters")), edt::RecentConfigurationPage::PCellParameters));
+
+ init ();
+ }
+};
+
+}
+
+static tl::RegisteredClass s_factory_polygons (new lay::EditorOptionsPageFactory ("edt::Service(Polygons)"), 0);
+static tl::RegisteredClass s_factory_boxes (new lay::EditorOptionsPageFactory ("edt::Service(Boxes)"), 0);
+static tl::RegisteredClass s_factory_points (new lay::EditorOptionsPageFactory ("edt::Service(Points)"), 0);
+static tl::RegisteredClass s_factory_texts (new lay::EditorOptionsPageFactory ("edt::Service(Texts)"), 0);
+static tl::RegisteredClass s_factory_paths (new lay::EditorOptionsPageFactory ("edt::Service(Paths)"), 0);
+static tl::RegisteredClass s_factory_insts (new lay::EditorOptionsPageFactory ("edt::Service(CellInstances)"), 0);
+
}
#endif
diff --git a/src/edt/edt/edtRecentConfigurationPage.h b/src/edt/edt/edtRecentConfigurationPage.h
index bf0777ba5..61edb1778 100644
--- a/src/edt/edt/edtRecentConfigurationPage.h
+++ b/src/edt/edt/edtRecentConfigurationPage.h
@@ -26,7 +26,7 @@
#define HDR_edtRecentConfigurationPage
#include "edtCommon.h"
-#include "layEditorOptionsPage.h"
+#include "layEditorOptionsPageWidget.h"
#include "tlObject.h"
#include "tlDeferredExecution.h"
@@ -48,13 +48,11 @@ namespace edt
class PCellParametersPage;
-class EditorOptionsPages;
-
/**
* @brief The base class for a object properties page
*/
class EDT_PUBLIC RecentConfigurationPage
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -84,11 +82,10 @@ Q_OBJECT
ConfigurationRendering rendering;
};
- template
- RecentConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
- : EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg), dm_update_list (this, &RecentConfigurationPage::update_list)
+ RecentConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name)
+ : EditorOptionsPageWidget (view, dispatcher), m_recent_cfg_name (recent_cfg_name), dm_update_list (this, &RecentConfigurationPage::update_list)
{
- init ();
+ // .. nothing yet ..
}
virtual ~RecentConfigurationPage ();
@@ -100,6 +97,21 @@ Q_OBJECT
virtual void commit_recent (lay::Dispatcher *root);
virtual void config_recent_for_layer (lay::Dispatcher *root, const db::LayerProperties &lp, int cv_index);
+protected:
+ /**
+ * @brief Adds a configuration descriptors
+ * Use this method in the constructor to add descriptors.
+ */
+ void add (const ConfigurationDescriptor &cfg)
+ {
+ m_cfg.push_back (cfg);
+ }
+
+ /**
+ * @brief Initializes the widget after the configuration items have been added
+ */
+ void init ();
+
private slots:
void item_clicked (QTreeWidgetItem *item);
@@ -109,7 +121,6 @@ private slots:
QTreeWidget *mp_tree_widget;
tl::DeferredMethod dm_update_list;
- void init ();
void update_list (const std::list > &stored_values);
void update_list ();
std::list > get_stored_values () const;
diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc
index 83c164472..6b0d918b7 100644
--- a/src/edt/edt/edtService.cc
+++ b/src/edt/edt/edtService.cc
@@ -32,7 +32,7 @@
#include "layLayoutView.h"
#include "laySnap.h"
#include "layConverters.h"
-#include "layEditorOptionsPages.h"
+#include "layEditorOptionsPage.h"
#include "tlProgress.h"
#include "tlTimer.h"
@@ -46,7 +46,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter
db::Object (manager),
mp_view (view),
mp_transient_marker (0),
- m_mouse_in_view (false), m_editing (false), m_immediate (false),
+ m_mouse_buttons (0), m_mouse_in_view (false), m_editing (false), m_immediate (false),
m_selection_maybe_invalid (false),
m_cell_inst_service (false),
m_flags (flags),
@@ -70,7 +70,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
db::Object (manager),
mp_view (view),
mp_transient_marker (0),
- m_mouse_in_view (false), m_editing (false), m_immediate (false),
+ m_mouse_buttons (0), m_mouse_in_view (false), m_editing (false), m_immediate (false),
m_selection_maybe_invalid (false),
m_cell_inst_service (true),
m_flags (db::ShapeIterator::Nothing),
@@ -103,14 +103,21 @@ Service::~Service ()
clear_transient_selection ();
}
-lay::angle_constraint_type
+lay::angle_constraint_type
+Service::alt_ac () const
+{
+ // fetch m_alt_ac (which is set from mouse buttons)
+ return m_alt_ac;
+}
+
+lay::angle_constraint_type
Service::connect_ac () const
{
// m_alt_ac (which is set from mouse buttons) can override the specified connect angle constraint
return m_alt_ac != lay::AC_Global ? m_alt_ac : m_connect_ac;
}
-lay::angle_constraint_type
+lay::angle_constraint_type
Service::move_ac () const
{
// m_alt_ac (which is set from mouse buttons) can override the specified move angle constraint
@@ -290,11 +297,23 @@ Service::snap2 (const db::DPoint &p) const
return snap2_details (p).snapped_point;
}
+lay::PointSnapToObjectResult
+Service::snap2_details (const db::DPoint &p, const db::DPoint &plast, lay::angle_constraint_type ac) const
+{
+ double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (lay::snap_range_pixels ());
+ return lay::obj_snap (m_snap_to_objects ? view () : 0, plast, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, ac, snap_range);
+}
+
+lay::PointSnapToObjectResult
+Service::snap2_details (const db::DPoint &p, const db::DPoint &plast, bool connect) const
+{
+ return snap2_details (p, plast, connect ? connect_ac () : move_ac ());
+}
+
db::DPoint
Service::snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect) const
{
- double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (lay::snap_range_pixels ());
- return lay::obj_snap (m_snap_to_objects ? view () : 0, plast, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, connect ? connect_ac () : move_ac (), snap_range).snapped_point;
+ return snap2_details (p, plast, connect ? connect_ac () : move_ac ()).snapped_point;
}
void
@@ -544,15 +563,20 @@ void
Service::move (const db::DPoint &pu, lay::angle_constraint_type ac)
{
m_alt_ac = ac;
+
if (view ()->is_editable () && m_moving) {
+
db::DPoint ref = snap (m_move_start);
bool snapped = false;
db::DPoint p = ref + snap_marker_to_grid (pu - m_move_start, snapped);
if (! snapped) {
p = ref + snap (pu - m_move_start, false /*move*/);
}
+
move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - ref));
+
}
+
m_alt_ac = lay::AC_Global;
}
@@ -560,28 +584,46 @@ void
Service::move_transform (const db::DPoint &pu, db::DFTrans tr, lay::angle_constraint_type ac)
{
m_alt_ac = ac;
+
if (view ()->is_editable () && m_moving) {
+
db::DPoint ref = snap (m_move_start);
bool snapped = false;
db::DPoint p = ref + snap_marker_to_grid (pu - m_move_start, snapped);
if (! snapped) {
p = ref + snap (pu - m_move_start, false /*move*/);
}
+
move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (tr * m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - ref));
+
}
+
m_alt_ac = lay::AC_Global;
}
-void
-Service::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
+void
+Service::end_move (const db::DVector &v)
+{
+ if (view ()->is_editable () && m_moving) {
+ transform (db::DCplxTrans (db::DTrans (v) * db::DTrans (m_move_trans.fp_trans ())));
+ move_cancel (); // formally this functionality fits here
+ // accept changes to guiding shapes
+ handle_guiding_shape_changes (true);
+ }
+
+ m_alt_ac = lay::AC_Global;
+}
+
+void
+Service::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
{
- m_alt_ac = ac;
if (view ()->is_editable () && m_moving) {
transform (db::DCplxTrans (m_move_trans));
move_cancel (); // formally this functionality fits here
// accept changes to guiding shapes
handle_guiding_shape_changes (true);
}
+
m_alt_ac = lay::AC_Global;
}
@@ -860,6 +902,7 @@ bool
Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
m_mouse_pos = p;
+ m_mouse_buttons = buttons;
if (view ()->is_editable () && prio) {
@@ -896,6 +939,9 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
bool
Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
+ m_mouse_pos = p;
+ m_mouse_buttons = buttons;
+
if (view ()->is_editable () && prio) {
if ((buttons & lay::LeftButton) != 0) {
@@ -910,9 +956,7 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio
} else {
if (do_mouse_click (p)) {
- m_editing = false;
- set_edit_marker (0);
- do_finish_edit ();
+ finish_editing (false);
}
}
@@ -942,14 +986,14 @@ Service::enter_event (bool /*prio*/)
}
bool
-Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio)
+Service::mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
+ m_mouse_pos = p;
+ m_mouse_buttons = buttons;
+
if (m_editing && prio && (buttons & lay::LeftButton) != 0) {
m_alt_ac = lay::ac_from_buttons (buttons);
- do_finish_edit ();
- m_editing = false;
- set_edit_marker (0);
- m_alt_ac = lay::AC_Global;
+ finish_editing (false);
return true;
} else {
return false;
@@ -959,6 +1003,9 @@ Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int button
bool
Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
+ m_mouse_pos = p;
+ m_mouse_buttons = buttons;
+
if (view ()->is_editable () && prio && (buttons & lay::RightButton) != 0 && m_editing) {
m_alt_ac = lay::ac_from_buttons (buttons);
do_mouse_transform (p, db::DFTrans (db::DFTrans::r90));
@@ -975,11 +1022,26 @@ Service::key_event (unsigned int key, unsigned int buttons)
if (view ()->is_editable () && m_editing && buttons == 0 && key == lay::KeyBackspace) {
do_delete ();
return true;
+ } else if (view ()->is_editable () && m_editing && buttons == 0 && (key == lay::KeyEnter || key == lay::KeyReturn)) {
+ m_alt_ac = lay::AC_Global;
+ finish_editing (true);
+ return true;
} else {
return false;
}
}
+void
+Service::finish_editing (bool accept)
+{
+ do_finish_edit (accept);
+
+ m_editing = false;
+ show_toolbox (false);
+ set_edit_marker (0);
+ m_alt_ac = lay::AC_Global;
+}
+
void
Service::activated ()
{
@@ -1682,16 +1744,11 @@ Service::select (const lay::ObjectInstPath &obj, lay::Editable::SelectionMode mo
void
Service::move_markers (const db::DTrans &t)
{
- if (m_move_trans != t) {
+ if (has_selection ()) {
+ propose_move_transformation (t, 0);
+ }
- // display current move vector
- if (has_selection ()) {
- std::string pos = std::string ("dx: ") + tl::micron_to_string (t.disp ().x ()) + " dy: " + tl::micron_to_string (t.disp ().y ());
- if (t.rot () != 0) {
- pos += std::string (" ") + ((const db::DFTrans &) t).to_string ();
- }
- view ()->message (pos);
- }
+ if (m_move_trans != t) {
for (auto r = m_markers.begin (); r != m_markers.end (); ++r) {
@@ -1712,6 +1769,7 @@ void
Service::begin_edit (const db::DPoint &p)
{
do_begin_edit (p);
+ show_toolbox (true);
m_editing = true;
}
@@ -2005,18 +2063,44 @@ Service::handle_guiding_shape_changes (bool commit)
void
Service::commit_recent ()
{
-#if defined(HAVE_QT)
- lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
- if (!eo_pages) {
+ lay::EditorOptionsPageCollection *eo_pages = view ()->editor_options_pages ();
+ if (! eo_pages) {
return;
}
- for (std::vector::const_iterator op = eo_pages->pages ().begin (); op != eo_pages->pages ().end (); ++op) {
+ auto pages = eo_pages->editor_options_pages ();
+ for (auto op = pages.begin (); op != pages.end (); ++op) {
if ((*op)->plugin_declaration () == plugin_declaration ()) {
(*op)->commit_recent (view ());
}
}
-#endif
+}
+
+void
+Service::show_toolbox (bool visible)
+{
+ auto p = toolbox_widget ();
+ if (p) {
+ p->set_visible (visible);
+ }
+}
+
+lay::EditorOptionsPage *
+Service::toolbox_widget ()
+{
+ lay::EditorOptionsPageCollection *eo_pages = view ()->editor_options_pages ();
+ if (! eo_pages) {
+ return 0;
+ }
+
+ auto pages = eo_pages->editor_options_pages (plugin_declaration ());
+ for (auto op = pages.begin (); op != pages.end (); ++op) {
+ if ((*op)->is_toolbox_widget ()) {
+ return *op;
+ }
+ }
+
+ return 0;
}
// -------------------------------------------------------------
diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h
index a791187e5..99a84c0ee 100644
--- a/src/edt/edt/edtService.h
+++ b/src/edt/edt/edtService.h
@@ -190,6 +190,11 @@ class EDT_PUBLIC Service
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
+ /**
+ * @brief Terminate a "move" operation with compulsory move vector
+ */
+ virtual void end_move (const db::DVector &v);
+
/**
* @brief Indicates whether objects are selected
*/
@@ -513,9 +518,12 @@ class EDT_PUBLIC Service
/**
* @brief Reimplemented by the specific implementation of the shape editors
*
- * This method is called when the object is finished
+ * This method is called when the object is finished.
+ *
+ * 'accept' is set to true if triggered by the Enter/Return key, false if triggered by a mouse click.
+ * In the latter case, first the mouse click is delivered and then "do_finish_edit" is called.
*/
- virtual void do_finish_edit () { }
+ virtual void do_finish_edit (bool /*accept*/) { }
/**
* @brief Reimplemented by the specific implementation of the shape editors
@@ -611,6 +619,7 @@ class EDT_PUBLIC Service
db::DPoint snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect = true) const;
protected:
+ lay::angle_constraint_type alt_ac () const;
lay::angle_constraint_type connect_ac () const;
lay::angle_constraint_type move_ac () const;
@@ -644,16 +653,49 @@ class EDT_PUBLIC Service
return m_mouse_pos;
}
+ int mouse_buttons () const
+ {
+ return m_mouse_buttons;
+ }
+
/**
* @brief Commits the current configuration to the recent attributes list
*/
void commit_recent ();
+ /**
+ * @brief Shows the toolbox widget in case one is registered for this plugin
+ */
+ void show_toolbox (bool visible);
+
+ /**
+ * @brief Finishes the edit operation
+ *
+ * Calls do_finish_edit() and terminates the editing operation.
+ * See "do_finish_edit" for an explanation of the "accept" parameter.
+ */
+ void finish_editing (bool accept);
+
+ /**
+ * @brief Gets the toolbox widget or 0 if none is registered
+ */
+ lay::EditorOptionsPage *toolbox_widget ();
+
/**
* @brief Point snapping with detailed return value
*/
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p) const;
+ /**
+ * @brief Point snapping with detailed return value
+ */
+ lay::PointSnapToObjectResult snap2_details (const db::DPoint &p, const db::DPoint &plast, bool connect) const;
+
+ /**
+ * @brief Point snapping with detailed return value and specific angle constraint
+ */
+ lay::PointSnapToObjectResult snap2_details (const db::DPoint &p, const db::DPoint &plast, lay::angle_constraint_type ac) const;
+
private:
friend class EditableSelectionIterator;
@@ -669,9 +711,12 @@ class EDT_PUBLIC Service
// The marker representing the object to be edited
std::vector m_edit_markers;
- // The last mouse position
+ // The last mouse position of the current mouse move/press/click event
db::DPoint m_mouse_pos;
+ // The buttons flag of the current mouse move/press/click event
+ int m_mouse_buttons;
+
// A flag indicating whether the mouse is inside the view
bool m_mouse_in_view;
diff --git a/src/edt/edt/edtShapeService.cc b/src/edt/edt/edtShapeService.cc
index 4c16060cf..71158cb81 100644
--- a/src/edt/edt/edtShapeService.cc
+++ b/src/edt/edt/edtShapeService.cc
@@ -25,21 +25,23 @@
#include "edtPathService.h"
#include "edtPropertiesPages.h"
#include "layLayoutView.h"
+#include "layEditorOptionsPage.h"
#include "dbEdgeProcessor.h"
#include "dbPolygonTools.h"
#if defined(HAVE_QT)
-# include "layTipDialog.h"
+# include "layTipDialog.h"
#endif
-#include "layEditorOptionsPages.h"
-
namespace edt
{
// -----------------------------------------------------------------------------
// ShapeEditService implementation
+const char *ShapeEditService::connection_configure_name () { return "connection-toolkit-widget-value"; }
+const char *ShapeEditService::connection_function_name () { return "connection-toolkit-widget-commit"; }
+
ShapeEditService::ShapeEditService (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIterator::flags_type shape_types)
: edt::Service (manager, view, shape_types),
m_layer (0), m_cv_index (0), mp_cell (0), mp_layout (0), m_combine_mode (CM_Add), m_update_edit_layer_enabled (true)
@@ -76,21 +78,19 @@ ShapeEditService::config_recent_for_layer (const db::LayerProperties &lp, int cv
return;
}
-#if defined(HAVE_QT)
- lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
- if (!eo_pages) {
+ lay::EditorOptionsPageCollection *eo_pages = view ()->editor_options_pages ();
+ if (! eo_pages) {
return;
}
- for (std::vector::const_iterator op = eo_pages->pages ().begin (); op != eo_pages->pages ().end (); ++op) {
+ auto pages = eo_pages->editor_options_pages ();
+ for (auto op = pages.begin (); op != pages.end (); ++op) {
if ((*op)->plugin_declaration () == plugin_declaration ()) {
(*op)->config_recent_for_layer (dispatcher (), lp, cv_index);
}
}
-#endif
}
-
void
ShapeEditService::get_edit_layer ()
{
diff --git a/src/edt/edt/edtShapeService.h b/src/edt/edt/edtShapeService.h
index 4a9e32ead..6b1e75a34 100644
--- a/src/edt/edt/edtShapeService.h
+++ b/src/edt/edt/edtShapeService.h
@@ -37,6 +37,9 @@ class ShapeEditService
: public edt::Service
{
public:
+ static const char *connection_configure_name ();
+ static const char *connection_function_name ();
+
ShapeEditService (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIterator::flags_type shape_types);
protected:
diff --git a/src/edt/edt/edtTextService.cc b/src/edt/edt/edtTextService.cc
index fe3470a51..9734a7af8 100644
--- a/src/edt/edt/edtTextService.cc
+++ b/src/edt/edt/edtTextService.cc
@@ -155,16 +155,11 @@ TextService::get_text () const
}
void
-TextService::do_finish_edit ()
+TextService::do_finish_edit (bool /*accept*/)
{
- get_edit_layer ();
-
- if (manager ()) {
- manager ()->transaction (tl::to_string (tr ("Create text")));
- }
- cell ().shapes (layer ()).insert (get_text ());
- if (manager ()) {
- manager ()->commit ();
+ {
+ db::Transaction transaction (manager (), tl::to_string (tr ("Create text")));
+ cell ().shapes (layer ()).insert (get_text ());
}
commit_recent ();
diff --git a/src/edt/edt/edtTextService.h b/src/edt/edt/edtTextService.h
index 47f7a9645..0badada54 100644
--- a/src/edt/edt/edtTextService.h
+++ b/src/edt/edt/edtTextService.h
@@ -47,7 +47,7 @@ class TextService
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
- virtual void do_finish_edit ();
+ virtual void do_finish_edit (bool);
virtual void do_cancel_edit ();
virtual bool do_activated ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
diff --git a/src/gsi/gsi/gsiClassBase.h b/src/gsi/gsi/gsiClassBase.h
index 6915c00de..8d0c03d5f 100644
--- a/src/gsi/gsi/gsiClassBase.h
+++ b/src/gsi/gsi/gsiClassBase.h
@@ -203,13 +203,29 @@ class GSI_PUBLIC ClassBase
}
/**
- * @brief Iterates all subclasses (end)
+ * @brief Iterates all child classes (end)
*/
tl::weak_collection::const_iterator end_child_classes () const
{
return m_child_classes.end ();
}
+ /**
+ * @brief Iterates all subclasses (begin)
+ */
+ tl::weak_collection::const_iterator begin_subclasses () const
+ {
+ return m_subclasses.begin ();
+ }
+
+ /**
+ * @brief Iterates all subclasses (end)
+ */
+ tl::weak_collection::const_iterator end_subclasses () const
+ {
+ return m_subclasses.end ();
+ }
+
/**
* @brief Iterates all classes present (begin)
*/
diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc
index 9e27d9449..5e410d345 100644
--- a/src/img/img/imgService.cc
+++ b/src/img/img/imgService.cc
@@ -419,6 +419,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
mp_transient_view (0),
m_move_mode (Service::move_none),
m_moved_landmark (0),
+ m_ac (lay::AC_Global),
m_keep_selection_for_move (false),
m_images_visible (true),
m_visibility_cache_valid (false)
@@ -608,12 +609,14 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
double l = catch_distance ();
db::DBox search_dbox = db::DBox (p, p).enlarged (db::DVector (l, l));
+ m_plast = m_p1 = p;
+ m_trans = db::DTrans ();
+ m_ac = lay::AC_Global;
+
// choose move mode
if (mode == lay::Editable::Selected) {
m_move_mode = move_selected;
- m_p1 = p;
- m_trans = db::DTrans ();
selection_to_view ();
for (std::vector ::iterator r = m_selected_image_views.begin (); r != m_selected_image_views.end (); ++r) {
@@ -657,7 +660,6 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
} else if (mode == lay::Editable::Any) {
m_move_mode = move_none;
- m_p1 = p;
double dmin = std::numeric_limits ::max ();
const db::DUserObject *robj = find_image (p, search_dbox, l, dmin);
@@ -705,11 +707,14 @@ Service::move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constra
return;
}
+ db::DTrans tr_new = db::DTrans (p - db::DPoint ()) * db::DTrans (tr) * db::DTrans (m_trans.fp_trans ()) * db::DTrans (db::DPoint () - m_p1);
+
if (m_move_mode == move_all) {
- db::DVector dp = p - db::DPoint ();
+ db::DTrans dt = tr_new * m_trans.inverted ();
- m_current.transform (db::DTrans (dp) * db::DTrans (tr) * db::DTrans (-dp));
+ m_current.transform (dt);
+ m_trans = dt * m_trans;
// display current images' parameters
show_message ();
@@ -718,7 +723,7 @@ Service::move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constra
} else if (m_move_mode == move_selected) {
- m_trans *= db::DTrans (m_p1 - db::DPoint ()) * db::DTrans (tr) * db::DTrans (db::DPoint () - m_p1);
+ m_trans = tr_new;
for (std::vector::iterator r = m_selected_image_views.begin (); r != m_selected_image_views.end (); ++r) {
(*r)->transform_by (db::DCplxTrans (m_trans));
@@ -734,10 +739,25 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
return;
}
+ m_ac = ac;
+
+ do_move (p, ac);
+
+ if (m_move_mode != move_selected) {
+ m_selected_image_views [0]->redraw ();
+ show_message ();
+ }
+
+ propose_move_transformation (m_trans, 2);
+}
+
+void
+Service::do_move (const db::DPoint &p, lay::angle_constraint_type ac)
+{
if (m_move_mode == move_selected) {
- db::DVector dp = p - m_p1;
- m_p1 = p;
+ db::DVector dp = p - m_plast;
+ m_plast = p;
m_trans = db::DTrans (dp) * m_trans;
@@ -747,6 +767,8 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
} else if (m_move_mode == move_landmark) {
+ m_trans = db::DTrans (p - m_p1);
+
std::vector li = m_initial.landmarks ();
for (std::vector ::iterator l = li.begin (); l != li.end (); ++l) {
*l = m_initial.matrix ().trans (*l);
@@ -770,20 +792,20 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
db::adjust_matrix (m, li, lm, adjust, int (m_moved_landmark));
m_current.set_matrix (m * m_initial.matrix ());
- m_selected_image_views [0]->redraw ();
-
} else {
if (m_move_mode == move_all) {
- db::DVector dp = p - m_p1;
- m_p1 = p;
+ db::DVector dp = p - m_plast;
+ m_plast = p;
+ m_trans = db::DTrans (dp) * m_trans;
m_current.transform (db::DTrans (dp));
} else {
m_current = m_initial;
+ m_trans = db::DTrans (p - m_p1);
db::DVector dx (0.5 * m_current.width (), 0.5 * m_current.height ());
db::Matrix3d it = (m_current.matrix () * db::Matrix3d::disp (-dx)).inverted ();
@@ -847,15 +869,6 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
}
- // display current images' parameters
- show_message ();
-
- m_selected_image_views [0]->redraw ();
-
- }
-
- if (m_move_mode != move_selected) {
- show_message ();
}
}
@@ -871,7 +884,14 @@ Service::show_message ()
*/
}
-void
+void
+Service::end_move (const db::DVector &v)
+{
+ do_move (m_p1 + v, m_ac);
+ end_move (db::DPoint (), lay::AC_Any);
+}
+
+void
Service::end_move (const db::DPoint &, lay::angle_constraint_type)
{
if (! m_selected_image_views.empty () && ! m_selected.empty ()) {
diff --git a/src/img/img/imgService.h b/src/img/img/imgService.h
index 9e5d1cc14..aa4ef9975 100644
--- a/src/img/img/imgService.h
+++ b/src/img/img/imgService.h
@@ -359,6 +359,11 @@ class IMG_PUBLIC Service
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
+ /**
+ * @brief Terminate a "move" operation with compulsory move vector
+ */
+ virtual void end_move (const db::DVector &v);
+
/**
* @brief Return the bbox of the selection (reimplementation of lay::Editable interface)
*/
@@ -500,8 +505,10 @@ class IMG_PUBLIC Service
std::set m_selected;
// The previous selection
std::set m_previous_selection;
- // The reference point in move mode
+ // The starting point in move mode
db::DPoint m_p1;
+ // The last reference point in move mode
+ db::DPoint m_plast;
// The image object representing the image being moved as it was before it was moved
img::Object m_initial;
// The image object representing the image being moved
@@ -514,6 +521,8 @@ class IMG_PUBLIC Service
MoveMode m_move_mode;
// The index of the landmark being moved
size_t m_moved_landmark;
+ // The last "angle constraint" (button combination) used in move
+ lay::angle_constraint_type m_ac;
// Flag indicating that we want to keep the selection after the landmark was moved
bool m_keep_selection_for_move;
// Flag indicating whether images are visible
@@ -523,6 +532,8 @@ class IMG_PUBLIC Service
std::map m_visibility_cache;
void show_message ();
+ void do_move (const db::DPoint &p, lay::angle_constraint_type ac);
+
/**
* @brief Select a certain image
diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc
index 43cea0feb..6ece8b5da 100644
--- a/src/lay/lay/layGSIHelpProvider.cc
+++ b/src/lay/lay/layGSIHelpProvider.cc
@@ -993,7 +993,11 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
<< "" << std::endl
<< std::endl;
- os << "" << tl::to_string (QObject::tr ("API reference - Class")) << " " << escape_xml (cls) << "" << std::endl;
+ os << "" << tl::to_string (QObject::tr ("API reference - Class")) << " " << escape_xml (cls);
+ if (class_doc.hidden) {
+ os << " " << tl::to_string (QObject::tr ("[internal]"));
+ }
+ os << "" << std::endl;
os << "module ()) << "\"/>" << std::endl;
os << "" << std::endl;
@@ -1006,13 +1010,15 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "
" << std::endl;
}
+ // Inserts an index
+
os << "" << std::endl;
+ // Produce class doc body
+
+ if (class_doc.hidden && class_doc.alias.empty ()) {
+ os << "
"
+ << tl::to_string (QObject::tr ("Note"))
+ << ": "
+ << tl::to_string (QObject::tr (
+ "This class is an internal class provided for technical reasons - i.e. "
+ "as a placeholder class for argument binding or as an abstract interface. "
+ "You should not instantiate objects of this class directly. "
+ "Instead, use the subclasses listed above. "
+ "Also see there for more documentation and actual incarnations of this class."
+ ))
+ << "
" << std::endl;
+ }
+
os << replace_references (class_doc.doc_html (), cls_obj) << std::endl;
// collect the methods of the class and their hidden base classes
@@ -1116,6 +1179,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "" << std::endl;
return os.str ();
}
+
+ // Produce methods brief descriptions
int n = 0;
int row = 0;
@@ -1190,6 +1255,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "
" << std::endl;
}
+ // Produce static methods brief descriptions
+
any = false;
n = 0;
@@ -1230,6 +1297,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "" << std::endl;
}
+ // Produce protected methods brief descriptions
+
any = false;
n = 0;
@@ -1272,6 +1341,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "" << std::endl;
}
+ // Produce deprecated methods brief descriptions
+
any = false;
n = 0;
@@ -1323,6 +1394,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "" << std::endl;
}
+ // Produce method details
+
n = 0;
os << "