From 989f80e1a657175fce37c04612661224576b4c5c Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 22 Dec 2025 21:02:22 +0100
Subject: [PATCH 01/36] Using floats for Polygon::smooth distance checks, so
that precise measurements are taken
---
src/db/db/dbPolygonTools.cc | 4 +-
src/db/unit_tests/dbPolygonToolsTests.cc | 59 ++++++++++++++++++++++++
2 files changed, 61 insertions(+), 2 deletions(-)
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/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)
{
From c0059959b8d91096da3fe40cf2dbc7f81cdbca40 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 22 Dec 2025 23:09:38 +0100
Subject: [PATCH 02/36] Two small improvements
1. point-like selections use pan-to-selection instead of zoom-to-selection
2. Drawing texts on hidden layers: one warning less about drawing on a hidden layer
---
src/edt/edt/edtTextService.cc | 11 +++--------
src/laybasic/laybasic/layLayoutViewBase.cc | 2 +-
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/src/edt/edt/edtTextService.cc b/src/edt/edt/edtTextService.cc
index fe3470a51..c016b7536 100644
--- a/src/edt/edt/edtTextService.cc
+++ b/src/edt/edt/edtTextService.cc
@@ -157,14 +157,9 @@ TextService::get_text () const
void
TextService::do_finish_edit ()
{
- 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/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc
index 67c07e246..35c60e745 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.cc
+++ b/src/laybasic/laybasic/layLayoutViewBase.cc
@@ -5608,7 +5608,7 @@ LayoutViewBase::paste ()
db::DBox sel_bbox = selection_bbox ();
if (! sel_bbox.empty ()) {
- if (m_paste_display_mode == 1) {
+ if (m_paste_display_mode == 1 || (m_paste_display_mode == 2 && sel_bbox.is_point ())) {
// just make selection visible, i.e. shift window somewhat
pan_center (sel_bbox.center ());
} else if (m_paste_display_mode == 2) {
From c3b6476176d14b85bffb1098f2bcce97cc43e233 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 11 Jan 2026 00:32:03 +0100
Subject: [PATCH 03/36] [consider merging] Bugfix: DRC collect_xyz is available
now also for edge pair layers
---
src/drc/drc/built-in-macros/_drc_layer.rb | 2 +-
testdata/drc/drcSimpleTests_2.drc | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index 44466da10..7bb79f054 100644
--- a/src/drc/drc/built-in-macros/_drc_layer.rb
+++ b/src/drc/drc/built-in-macros/_drc_layer.rb
@@ -1714,7 +1714,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
diff --git a/testdata/drc/drcSimpleTests_2.drc b/testdata/drc/drcSimpleTests_2.drc
index 8973ec5b1..e32bffc1e 100644
--- a/testdata/drc/drcSimpleTests_2.drc
+++ b/testdata/drc/drcSimpleTests_2.drc
@@ -105,8 +105,10 @@ a1.edges.collect_to_region { |p| p.length < 0.8 && p.bbox.enlarged(0.1, 0.1) }.o
a1.edges.collect_to_region { |p| p.length < 0.8 && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(100, 100) }.output(1123, 0)
# edge pair collect
-a1.width(1.5).collect { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1120, 0)
-a1.width(1.5).collect_to_edge_pairs { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1121, 0)
+a1.width(1.5).collect { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1130, 0)
+a1.width(1.5).collect_to_edge_pairs { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1131, 0)
+a1.width(1.5).collect_to_edges { |p| p.transformed(RBA::VCplxTrans::new(1000.0)).first }.output(1132, 0)
+a1.width(1.5).collect_to_region { |p| p.polygon(0.0).transformed(RBA::VCplxTrans::new(1000.0)) }.output(1133, 0)
expect_count(a1.edges, 9, 9, "a1.edges")
expect_count(a1.width(1.5), 5, 5, "a1.width(1.5)")
From b409ed8b449dfd30886ad05020149751ae44afcd Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 11 Jan 2026 01:30:25 +0100
Subject: [PATCH 04/36] Include hidden classes in documentation to avoid
confusion.
---
src/gsi/gsi/gsiClassBase.h | 18 +++++-
src/lay/lay/layGSIHelpProvider.cc | 99 +++++++++++++++++++++++++++----
2 files changed, 103 insertions(+), 14 deletions(-)
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/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 << "" << tl::to_string (QObject::tr ("Description")) << ": " << escape_xml (class_doc.brief_doc) << "
" << std::endl;
+ const gsi::ClassBase *act_cls_obj = real_class (cls_obj);
+
std::vector classes;
- classes.push_back (real_class (cls_obj));
+ classes.push_back (act_cls_obj);
- const gsi::ClassBase *base = real_class (cls_obj)->base ();
+ const gsi::ClassBase *base = act_cls_obj->base ();
if (base) {
- const gsi::ClassBase *last_cls = real_class (cls_obj);
+ const gsi::ClassBase *last_cls = act_cls_obj;
bool all_collected = false;
os << "" << tl::to_string (QObject::tr ("Class hierarchy")) << ": " << make_qualified_name (cls_obj);
@@ -1032,6 +1038,7 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
all_collected = true;
} else if (! all_collected) {
// class needs to be mixed into the parent
+ os << " » name ())) << "\">" << escape_xml (base->name ()) << " " << tl::to_string (QObject::tr ("[internal]")) << "";
classes.push_back (base);
}
@@ -1051,34 +1058,90 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "
" << std::endl;
}
+ // Produce child classes
+
bool any = false;
for (std::vector::const_iterator c = classes.begin (); c != classes.end (); ++c) {
+
for (tl::weak_collection::const_iterator cc = (*c)->begin_child_classes (); cc != (*c)->end_child_classes (); ++cc) {
DocumentationParser &cdoc = cls_documentation (cc.operator-> ());
- if (! cdoc.hidden || ! cdoc.alias.empty ()) {
- if (any) {
- os << ", ";
- } else {
- os << "" << tl::to_string (QObject::tr ("Sub-classes")) << ": ";
- any = true;
- }
-
- os << " ()))) << "\">" << escape_xml (cc->name ()) << "";
+ if (any) {
+ os << ", ";
+ } else {
+ os << "
" << tl::to_string (QObject::tr ("Child classes")) << ": ";
+ any = true;
+ }
+ os << " ())))
+ << "\">"
+ << escape_xml (cc->name ());
+ if (cdoc.hidden && cdoc.alias.empty ()) {
+ os << " " << tl::to_string (QObject::tr ("[internal]"));
}
+ os << "";
+
+ }
+
+ }
+
+ if (any) {
+ os << "
" << std::endl;
+ }
+ // Produce subclasses (parent classes)
+
+ any = false;
+
+ for (tl::weak_collection::const_iterator cc = act_cls_obj->begin_subclasses (); cc != act_cls_obj->end_subclasses (); ++cc) {
+
+ DocumentationParser &cdoc = cls_documentation (cc.operator-> ());
+
+ if (any) {
+ os << ", ";
+ } else {
+ os << "" << tl::to_string (QObject::tr ("Subclasses")) << ": ";
+ any = true;
+ }
+
+ os << " ())))
+ << "\">"
+ << escape_xml (cc->name ());
+ if (cdoc.hidden && cdoc.alias.empty ()) {
+ os << " " << tl::to_string (QObject::tr ("[internal]"));
}
+ os << "";
+
}
if (any) {
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 << "" << tl::to_string (QObject::tr ("Detailed description")) << "
" << std::endl;
From c6faa3e6282b2ca0057c8a24da42243bd12fcab3 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 11 Jan 2026 22:34:52 +0100
Subject: [PATCH 05/36] 'extent_refs' DRC function: enabling for edge pairs and
edges, clarification of documentation
---
src/db/db/gsiDeclDbEdgePairs.cc | 76 +++++++++++++++++++++-
src/db/db/gsiDeclDbEdges.cc | 72 ++++++++++++++++++++
src/doc/doc/about/drc_ref.xml | 2 +-
src/doc/doc/about/drc_ref_drc.xml | 2 +-
src/doc/doc/about/drc_ref_global.xml | 2 +-
src/doc/doc/about/drc_ref_layer.xml | 19 +++---
src/doc/doc/about/drc_ref_netter.xml | 2 +-
src/doc/doc/about/drc_ref_source.xml | 2 +-
src/doc/doc/about/lvs_ref.xml | 2 +-
src/doc/doc/about/lvs_ref_global.xml | 2 +-
src/doc/doc/about/lvs_ref_netter.xml | 2 +-
src/drc/drc/built-in-macros/_drc_layer.rb | 23 ++++---
testdata/drc/drcSimpleTests_2.drc | 6 ++
testdata/drc/drcSimpleTests_au2.gds | Bin 15470 -> 16532 bytes
14 files changed, 183 insertions(+), 29 deletions(-)
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/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.
+
The following table shows a few applications:
diff --git a/src/doc/doc/about/drc_ref_netter.xml b/src/doc/doc/about/drc_ref_netter.xml
index 009b97ce4..0157af89f 100644
--- a/src/doc/doc/about/drc_ref_netter.xml
+++ b/src/doc/doc/about/drc_ref_netter.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/drc_ref_source.xml b/src/doc/doc/about/drc_ref_source.xml
index a746917e3..a3fea2b89 100644
--- a/src/doc/doc/about/drc_ref_source.xml
+++ b/src/doc/doc/about/drc_ref_source.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/lvs_ref.xml b/src/doc/doc/about/lvs_ref.xml
index 58168f012..842f21820 100644
--- a/src/doc/doc/about/lvs_ref.xml
+++ b/src/doc/doc/about/lvs_ref.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/lvs_ref_global.xml b/src/doc/doc/about/lvs_ref_global.xml
index 494ef2f6e..d1121526c 100644
--- a/src/doc/doc/about/lvs_ref_global.xml
+++ b/src/doc/doc/about/lvs_ref_global.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/doc/doc/about/lvs_ref_netter.xml b/src/doc/doc/about/lvs_ref_netter.xml
index 2e1dbd89e..be3e6e538 100644
--- a/src/doc/doc/about/lvs_ref_netter.xml
+++ b/src/doc/doc/about/lvs_ref_netter.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index 7bb79f054..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
@@ -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/testdata/drc/drcSimpleTests_2.drc b/testdata/drc/drcSimpleTests_2.drc
index e32bffc1e..d77afb552 100644
--- a/testdata/drc/drcSimpleTests_2.drc
+++ b/testdata/drc/drcSimpleTests_2.drc
@@ -64,6 +64,12 @@ a1.extent_refs(:lc).sized(0.05).output(1051, 1)
a1.extent_refs(:right_center).sized(0.05).output(1052, 0)
a1.extent_refs(:rc).sized(0.05).output(1052, 1)
a1.extent_refs(0.25, 0.5, 0.5, 0.75).output(1053, 0)
+a1.extent_refs(0.5, 0.5, 0.25, 0.75, as_edges).output(1054, 0)
+a1.extent_refs(0.5, 0.5, 0.25, 0.75, as_boxes).output(1055, 0)
+a1.extents.width(0.8.um).extent_refs(0.5, 0.5, 0.25, 0.75, as_edges).output(1056, 0)
+a1.extents.width(0.8.um).extent_refs(0.5, 0.5, 0.25, 0.75, as_boxes).output(1057, 0)
+a1.extents.width(0.8.um).first_edges.extent_refs(:center, as_edges).output(1058, 0)
+a1.extents.width(0.8.um).first_edges.extent_refs(:center, as_boxes).output(1059, 0)
a1.corners.sized(0.05).output(1060, 0)
a1.corners(-90.0, as_boxes).sized(0.05).output(1061, 0)
diff --git a/testdata/drc/drcSimpleTests_au2.gds b/testdata/drc/drcSimpleTests_au2.gds
index 6996b4a94cd000b4abb3436256b75b93984cdd57..dc6143932356f985339b2cee7e3f98d2253ff3b4 100644
GIT binary patch
delta 608
zcmaD?F{P0)ih+%Ri7A3XhLMT=6$2v!H-i|1JcBYan}LIg&BxP;fkA|s)y}cg-22$_
z50)-F^cT#I3Sp38#i?&&)ITW>P6h@xUM3c~$qo7vatsU%DgXa}-t_XjxxFp_fvJHP_u5ES#38QA!kfKJpAU
Date: Sun, 11 Jan 2026 23:46:11 +0100
Subject: [PATCH 06/36] Pressing Ctrl key while drawing a box forces it into a
square
---
src/edt/edt/edtBoxService.cc | 19 ++++++++++++++++---
src/edt/edt/edtService.cc | 27 +++++++++++++++++++++++----
src/edt/edt/edtService.h | 11 +++++++++++
src/laybasic/laybasic/laySnap.cc | 12 +++++++++---
src/laybasic/laybasic/laySnap.h | 2 +-
5 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/src/edt/edt/edtBoxService.cc b/src/edt/edt/edtBoxService.cc
index 8b1cdd173..a8554c43b 100644
--- a/src/edt/edt/edtBoxService.cc
+++ b/src/edt/edt/edtBoxService.cc
@@ -108,7 +108,10 @@ 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 = alt_ac () == lay::AC_Diagonal;
+
+ 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) {
@@ -122,12 +125,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*/);
}
diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc
index 83c164472..ff098ac94 100644
--- a/src/edt/edt/edtService.cc
+++ b/src/edt/edt/edtService.cc
@@ -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
diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h
index a791187e5..09bb56e96 100644
--- a/src/edt/edt/edtService.h
+++ b/src/edt/edt/edtService.h
@@ -611,6 +611,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;
@@ -654,6 +655,16 @@ class EDT_PUBLIC Service
*/
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;
diff --git a/src/laybasic/laybasic/laySnap.cc b/src/laybasic/laybasic/laySnap.cc
index 8578e84dd..c7f02b351 100644
--- a/src/laybasic/laybasic/laySnap.cc
+++ b/src/laybasic/laybasic/laySnap.cc
@@ -188,9 +188,11 @@ snap_angle (const db::DVector &in, lay::angle_constraint_type ac, db::DVector *s
std::vector ref_dir;
if (ac != lay::AC_Any) {
ref_dir.reserve (4);
- ref_dir.push_back (db::DVector (1.0, 0));
- ref_dir.push_back (db::DVector (0, 1.0));
- if (ac == lay::AC_Diagonal) {
+ if (ac != lay::AC_DiagonalOnly) {
+ ref_dir.push_back (db::DVector (1.0, 0));
+ ref_dir.push_back (db::DVector (0, 1.0));
+ }
+ if (ac == lay::AC_Diagonal || ac == lay::AC_DiagonalOnly) {
ref_dir.push_back (db::DVector (-1.0, 1.0));
ref_dir.push_back (db::DVector (1.0, 1.0));
}
@@ -963,6 +965,10 @@ make_cutlines (lay::angle_constraint_type snap_mode, const db::DPoint &p1, std::
cutlines.push_back (db::DEdge (p1, p1 + db::DVector (1.0, 0.0)));
cutlines.push_back (db::DEdge (p1, p1 + db::DVector (1.0, 1.0)));
cutlines.push_back (db::DEdge (p1, p1 + db::DVector (1.0, -1.0)));
+ } else if (snap_mode == lay::AC_DiagonalOnly) {
+ cutlines.reserve (2);
+ cutlines.push_back (db::DEdge (p1, p1 + db::DVector (1.0, 1.0)));
+ cutlines.push_back (db::DEdge (p1, p1 + db::DVector (1.0, -1.0)));
}
}
diff --git a/src/laybasic/laybasic/laySnap.h b/src/laybasic/laybasic/laySnap.h
index 51f209633..cfa63ae9b 100644
--- a/src/laybasic/laybasic/laySnap.h
+++ b/src/laybasic/laybasic/laySnap.h
@@ -53,7 +53,7 @@ namespace lay
* Vertical: vertical only
* Global: use global setting (templates and ruler specific setting only)
*/
- enum angle_constraint_type { AC_Any = 0, AC_Diagonal, AC_Ortho, AC_Horizontal, AC_Vertical, AC_Global, AC_NumModes };
+ enum angle_constraint_type { AC_Any = 0, AC_Diagonal, AC_DiagonalOnly, AC_Ortho, AC_Horizontal, AC_Vertical, AC_Global, AC_NumModes };
/**
* @brief snap a coordinate value to a unit grid
From c738cf72552737dac7d4a86caa22a5cba3f26203 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 12 Jan 2026 15:45:17 +0100
Subject: [PATCH 07/36] WIP
---
src/edt/edt/edtEditorOptionsPages.cc | 10 +-
src/edt/edt/edtEditorOptionsPages.h | 10 +-
src/edt/edt/edtPlugin.cc | 17 +--
src/edt/edt/edtRecentConfigurationPage.h | 6 +-
src/edt/edt/edtService.cc | 9 +-
src/edt/edt/edtShapeService.cc | 18 +--
src/lay/lay/layMainWindow.cc | 2 +-
src/laybasic/laybasic/gsiDeclLayPlugin.cc | 1 -
.../laybasic/gsiDeclLayPluginFactory.cc | 2 -
src/laybasic/laybasic/layEditorOptionsPage.cc | 136 ++++++++++--------
src/laybasic/laybasic/layEditorOptionsPage.h | 77 +++++++---
src/laybasic/laybasic/layEditorServiceBase.cc | 35 +----
src/laybasic/laybasic/layEditorServiceBase.h | 2 -
src/laybasic/laybasic/layLayoutViewBase.h | 34 ++++-
src/laybasic/laybasic/layMove.cc | 55 +++++++
src/laybasic/laybasic/laybasic.pro | 2 -
src/layui/layui/layui.pro | 2 -
.../layview}/layEditorOptionsFrame.cc | 5 +-
.../layview}/layEditorOptionsFrame.h | 8 +-
.../layview}/layEditorOptionsPages.cc | 106 +++++++++-----
.../layview}/layEditorOptionsPages.h | 44 +++---
src/layview/layview/layLayoutView_qt.cc | 34 ++++-
src/layview/layview/layLayoutView_qt.h | 27 +++-
src/layview/layview/layview.pro | 4 +
24 files changed, 405 insertions(+), 241 deletions(-)
rename src/{layui/layui => layview/layview}/layEditorOptionsFrame.cc (95%)
rename src/{layui/layui => layview/layview}/layEditorOptionsFrame.h (91%)
rename src/{laybasic/laybasic => layview/layview}/layEditorOptionsPages.cc (78%)
rename src/{laybasic/laybasic => layview/layview}/layEditorOptionsPages.h (66%)
diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc
index 416e08238..a51a7c45e 100644
--- a/src/edt/edt/edtEditorOptionsPages.cc
+++ b/src/edt/edt/edtEditorOptionsPages.cc
@@ -72,7 +72,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 +215,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 +293,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 +394,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 +687,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);
diff --git a/src/edt/edt/edtEditorOptionsPages.h b/src/edt/edt/edtEditorOptionsPages.h
index acf94b4f1..5080c2dfe 100644
--- a/src/edt/edt/edtEditorOptionsPages.h
+++ b/src/edt/edt/edtEditorOptionsPages.h
@@ -65,7 +65,7 @@ class PCellParametersPage;
* @brief The generic properties page
*/
class EditorOptionsGeneric
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -90,7 +90,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 +109,7 @@ class EditorOptionsText
* @brief The path properties page
*/
class EditorOptionsPath
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -133,7 +133,7 @@ public slots:
* @brief The instance properties page
*/
class EditorOptionsInst
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
@@ -165,7 +165,7 @@ private slots:
* @brief The instance properties page (PCell parameters)
*/
class EditorOptionsInstPCellParam
- : public lay::EditorOptionsPage
+ : public lay::EditorOptionsPageWidget
{
Q_OBJECT
diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc
index 33fbb341f..1062bc71a 100644
--- a/src/edt/edt/edtPlugin.cc
+++ b/src/edt/edt/edtPlugin.cc
@@ -21,13 +21,10 @@
*/
-#if defined(HAVE_QT)
-# include "layTipDialog.h"
-# include "layEditorOptionsPages.h"
-#endif
-
#include "layDispatcher.h"
#include "layLayoutViewBase.h"
+#include "layEditorOptionsPage.h"
+#include "layTipDialog.h"
#include "edtPlugin.h"
#include "edtConfig.h"
#include "edtService.h"
@@ -40,10 +37,8 @@
#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
@@ -65,7 +60,7 @@ edt::RecentConfigurationPage::ConfigurationDescriptor shape_cfg_descriptors[] =
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",
+ ret.push_back (new edt::RecentConfigurationPage (view, dispatcher, "edit-recent-shape-param",
&shape_cfg_descriptors[0], &shape_cfg_descriptors[sizeof (shape_cfg_descriptors) / sizeof (shape_cfg_descriptors[0])]));
}
#else
@@ -94,7 +89,7 @@ void get_text_editor_options_pages (std::vector &ret,
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",
+ ret.push_back (new edt::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));
}
diff --git a/src/edt/edt/edtRecentConfigurationPage.h b/src/edt/edt/edtRecentConfigurationPage.h
index bf0777ba5..dd6ff0e96 100644
--- a/src/edt/edt/edtRecentConfigurationPage.h
+++ b/src/edt/edt/edtRecentConfigurationPage.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
@@ -86,7 +84,7 @@ Q_OBJECT
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)
+ : EditorOptionsPageWidget (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg), dm_update_list (this, &RecentConfigurationPage::update_list)
{
init ();
}
diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc
index ff098ac94..ededabe19 100644
--- a/src/edt/edt/edtService.cc
+++ b/src/edt/edt/edtService.cc
@@ -2024,18 +2024,17 @@ 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
}
// -------------------------------------------------------------
diff --git a/src/edt/edt/edtShapeService.cc b/src/edt/edt/edtShapeService.cc
index 4c16060cf..4b95ee300 100644
--- a/src/edt/edt/edtShapeService.cc
+++ b/src/edt/edt/edtShapeService.cc
@@ -25,15 +25,11 @@
#include "edtPathService.h"
#include "edtPropertiesPages.h"
#include "layLayoutView.h"
+#include "layEditorOptionsPage.h"
+#include "layTipDialog.h"
#include "dbEdgeProcessor.h"
#include "dbPolygonTools.h"
-#if defined(HAVE_QT)
-# include "layTipDialog.h"
-#endif
-
-#include "layEditorOptionsPages.h"
-
namespace edt
{
@@ -76,21 +72,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/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc
index 75a73dd16..5fa135a1c 100644
--- a/src/lay/lay/layMainWindow.cc
+++ b/src/lay/lay/layMainWindow.cc
@@ -1722,7 +1722,7 @@ MainWindow::update_editor_options_dock ()
eo_visible = pd_sel->editable_enabled ();
}
if (current_view () && eo_visible) {
- lay::EditorOptionsPages *eo_pages = current_view ()->editor_options_pages ();
+ lay::EditorOptionsPageCollection *eo_pages = current_view ()->editor_options_pages ();
if (! eo_pages || ! eo_pages->has_content ()) {
eo_visible = false;
}
diff --git a/src/laybasic/laybasic/gsiDeclLayPlugin.cc b/src/laybasic/laybasic/gsiDeclLayPlugin.cc
index ef3d696dc..ae83521cb 100644
--- a/src/laybasic/laybasic/gsiDeclLayPlugin.cc
+++ b/src/laybasic/laybasic/gsiDeclLayPlugin.cc
@@ -25,7 +25,6 @@
#include "gsiDecl.h"
#include "gsiDeclBasic.h"
#include "gsiEnums.h"
-#include "layEditorOptionsPages.h"
#include "layCursor.h"
#include "layEditorUtils.h"
#include "layConverters.h"
diff --git a/src/laybasic/laybasic/gsiDeclLayPluginFactory.cc b/src/laybasic/laybasic/gsiDeclLayPluginFactory.cc
index 85f0541bf..38cb0a17d 100644
--- a/src/laybasic/laybasic/gsiDeclLayPluginFactory.cc
+++ b/src/laybasic/laybasic/gsiDeclLayPluginFactory.cc
@@ -28,8 +28,6 @@
#include "gsiDeclLayConfigPage.h"
#include "gsiDeclLayPlugin.h"
-#include "layEditorOptionsPages.h"
-
namespace gsi
{
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index 0efde1109..e489bc1d8 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -20,11 +20,8 @@
*/
-#if defined(HAVE_QT)
-
#include "tlInternational.h"
#include "layEditorOptionsPage.h"
-#include "layEditorOptionsPages.h"
#include "layLayoutViewBase.h"
#include "tlExceptions.h"
@@ -38,13 +35,13 @@ namespace lay
// EditorOptionsPage implementation
EditorOptionsPage::EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
+ : mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), m_toolbox_widget (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
{
- attach_events ();
+ init (view, dispatcher);
}
EditorOptionsPage::EditorOptionsPage ()
- : QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
+ : mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), m_toolbox_widget (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
{
// .. nothing yet ..
}
@@ -62,57 +59,6 @@ EditorOptionsPage::init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
attach_events ();
}
-void
-EditorOptionsPage::edited ()
-{
- apply (dispatcher ());
-}
-
-static bool is_parent_widget (QWidget *w, QWidget *parent)
-{
- while (w && w != parent) {
- w = dynamic_cast (w->parent ());
- }
- return w == parent;
-}
-
-bool
-EditorOptionsPage::focusNextPrevChild (bool next)
-{
- bool res = QWidget::focusNextPrevChild (next);
-
- // Stop making the focus leave the page - this way we can jump back to the
- // view on "enter"
- if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
- focusWidget ()->setFocus ();
- }
-
- return res;
-}
-
-void
-EditorOptionsPage::keyPressEvent (QKeyEvent *event)
-{
-BEGIN_PROTECTED
- if (! is_modal_page () && event->modifiers () == Qt::NoModifier && event->key () == Qt::Key_Return) {
- // The Return key on a non-modal page commits the values and gives back the focus
- // to the view
- apply (dispatcher ());
- view ()->set_focus ();
- event->accept ();
- } else {
- QWidget::keyPressEvent (event);
- }
-END_PROTECTED
-}
-
-void
-EditorOptionsPage::set_focus ()
-{
- setFocus (Qt::TabFocusReason);
- QWidget::focusNextPrevChild (true);
-}
-
int
EditorOptionsPage::show ()
{
@@ -153,7 +99,7 @@ EditorOptionsPage::on_technology_changed ()
}
void
-EditorOptionsPage::set_owner (EditorOptionsPages *owner)
+EditorOptionsPage::set_owner (EditorOptionsPageCollection *owner)
{
if (mp_owner) {
mp_owner->unregister_page (this);
@@ -172,6 +118,80 @@ EditorOptionsPage::activate (bool active)
}
}
+#if defined(HAVE_QT)
+
+// ------------------------------------------------------------------
+// EditorOptionsPage implementation
+
+EditorOptionsPageWidget::EditorOptionsPageWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : QWidget (0), EditorOptionsPage (view, dispatcher)
+{
+ init (view, dispatcher);
+}
+
+EditorOptionsPageWidget::EditorOptionsPageWidget ()
+ : QWidget (0), EditorOptionsPage ()
+{
+ // .. nothing yet ..
+}
+
+EditorOptionsPageWidget::~EditorOptionsPageWidget ()
+{
+ set_owner (0);
+}
+
+void
+EditorOptionsPageWidget::edited ()
+{
+ apply (dispatcher ());
+}
+
+static bool is_parent_widget (QWidget *w, QWidget *parent)
+{
+ while (w && w != parent) {
+ w = dynamic_cast (w->parent ());
+ }
+ return w == parent;
+}
+
+bool
+EditorOptionsPageWidget::focusNextPrevChild (bool next)
+{
+ bool res = QWidget::focusNextPrevChild (next);
+
+ // Stop making the focus leave the page - this way we can jump back to the
+ // view on "enter"
+ if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
+ focusWidget ()->setFocus ();
+ }
+
+ return res;
+}
+
+void
+EditorOptionsPageWidget::keyPressEvent (QKeyEvent *event)
+{
+BEGIN_PROTECTED
+ if (! is_modal_page () && event->modifiers () == Qt::NoModifier && event->key () == Qt::Key_Return) {
+ // The Return key on a non-modal page commits the values and gives back the focus
+ // to the view
+ apply (dispatcher ());
+ view ()->set_focus ();
+ event->accept ();
+ } else {
+ QWidget::keyPressEvent (event);
+ }
+END_PROTECTED
+}
+
+void
+EditorOptionsPageWidget::set_focus ()
+{
+ setFocus (Qt::TabFocusReason);
+ QWidget::focusNextPrevChild (true);
}
#endif
+
+}
+
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h
index 33b9fc1d3..33a553034 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.h
+++ b/src/laybasic/laybasic/layEditorOptionsPage.h
@@ -20,8 +20,6 @@
*/
-#if defined(HAVE_QT)
-
#ifndef HDR_layEditorOptionsPage
#define HDR_layEditorOptionsPage
@@ -29,7 +27,9 @@
#include "tlObject.h"
-#include
+#if defined(HAVE_QT)
+# include
+#endif
namespace db
{
@@ -44,16 +44,34 @@ class Dispatcher;
class LayoutViewBase;
class Plugin;
class CellView;
-class EditorOptionsPages;
+class EditorOptionsPage;
+class EditorOptionsPageWidget;
+
+/**
+ * @brief An interface managing a collection of EditorOptionPage objects
+ */
+class LAYBASIC_PUBLIC EditorOptionsPageCollection
+{
+public:
+ virtual ~EditorOptionsPageCollection () { }
+
+ virtual void unregister_page (EditorOptionsPage *page) = 0;
+ virtual bool has_content () const = 0;
+ virtual bool has_modal_content () const = 0;
+ virtual void make_page_current (EditorOptionsPage *page) = 0;
+ virtual void activate_page (EditorOptionsPage *page) = 0;
+ virtual void activate (const lay::Plugin *plugin) = 0;
+ virtual bool exec_modal (EditorOptionsPage *page) = 0;
+ virtual std::vector editor_options_pages (const lay::PluginDeclaration *plugin) = 0;
+ virtual std::vector editor_options_pages () = 0;
+};
/**
* @brief The base class for a object properties page
*/
class LAYBASIC_PUBLIC EditorOptionsPage
- : public QWidget, public tl::Object
+ : public tl::Object
{
-Q_OBJECT
-
public:
EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
EditorOptionsPage ();
@@ -65,17 +83,21 @@ Q_OBJECT
virtual void setup (lay::Dispatcher * /*root*/) { }
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
virtual void config_recent_for_layer (lay::Dispatcher * /*root*/, const db::LayerProperties & /*lp*/, int /*cv_index*/) { }
+ virtual void set_focus () { }
+ virtual EditorOptionsPageWidget *widget () { return 0; }
bool is_focus_page () const { return m_focus_page; }
void set_focus_page (bool f) { m_focus_page = f; }
- void set_focus ();
bool is_modal_page () const { return m_modal_page; }
void set_modal_page (bool f) { m_modal_page = f; }
+ bool is_toolbox_widget () const { return m_toolbox_widget; }
+ void set_toolbox_widget (bool f) { m_toolbox_widget = f; }
+
bool active () const { return m_active; }
void activate (bool active);
- void set_owner (EditorOptionsPages *owner);
+ void set_owner (EditorOptionsPageCollection *owner);
/**
* @brief Shows the editor page
@@ -98,21 +120,15 @@ Q_OBJECT
return mp_view;
}
-protected slots:
- void edited ();
-
protected:
virtual void active_cellview_changed () { }
virtual void technology_changed (const std::string & /*tech*/) { }
- virtual bool focusNextPrevChild (bool next);
- virtual void keyPressEvent (QKeyEvent *event);
-
private:
- EditorOptionsPages *mp_owner;
+ EditorOptionsPageCollection *mp_owner;
bool m_active;
bool m_focus_page;
- bool m_modal_page;
+ bool m_modal_page, m_toolbox_widget;
const lay::PluginDeclaration *mp_plugin_declaration;
lay::Dispatcher *mp_dispatcher;
lay::LayoutViewBase *mp_view;
@@ -122,8 +138,33 @@ protected slots:
void attach_events ();
};
+#if defined(HAVE_QT)
+/**
+ * @brief The base class for a object properties page
+ */
+class LAYBASIC_PUBLIC EditorOptionsPageWidget
+ : public QWidget, public EditorOptionsPage
+{
+Q_OBJECT
+
+public:
+ EditorOptionsPageWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+ EditorOptionsPageWidget ();
+ virtual ~EditorOptionsPageWidget ();
+
+ virtual void set_focus ();
+ virtual EditorOptionsPageWidget *widget () { return this; }
+
+protected slots:
+ void edited ();
+
+protected:
+ virtual bool focusNextPrevChild (bool next);
+ virtual void keyPressEvent (QKeyEvent *event);
+};
+#endif // defined(HAVE_QT)
+
}
#endif
-#endif // defined(HAVE_QT)
diff --git a/src/laybasic/laybasic/layEditorServiceBase.cc b/src/laybasic/laybasic/layEditorServiceBase.cc
index 9be73bf37..a3ae88baf 100644
--- a/src/laybasic/laybasic/layEditorServiceBase.cc
+++ b/src/laybasic/laybasic/layEditorServiceBase.cc
@@ -22,7 +22,6 @@
#include "layEditorServiceBase.h"
#include "layEditorOptionsPage.h"
-#include "layEditorOptionsPages.h"
#include "layViewport.h"
#include "layLayoutViewBase.h"
#include "laybasicConfig.h"
@@ -345,22 +344,14 @@ EditorServiceBase::activated ()
m_active = true;
}
-#if defined(HAVE_QT)
-
std::vector
EditorServiceBase::editor_options_pages ()
{
- lay::EditorOptionsPages *eo_pages = mp_view->editor_options_pages ();
+ lay::EditorOptionsPageCollection *eo_pages = mp_view->editor_options_pages ();
if (!eo_pages) {
return std::vector ();
} else {
- std::vector pages;
- for (auto p = eo_pages->pages ().begin (); p != eo_pages->pages ().end (); ++p) {
- if ((*p)->plugin_declaration () == plugin_declaration ()) {
- pages.push_back (*p);
- }
- }
- return pages;
+ return eo_pages->editor_options_pages (plugin_declaration ());
}
}
@@ -402,26 +393,4 @@ EditorServiceBase::show_error (tl::Exception &ex)
QMessageBox::critical (ui ()->widget (), tr ("Error"), tl::to_qstring (ex.msg ()));
}
-#else
-
-bool
-EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
-{
- return false;
-}
-
-void
-EditorServiceBase::show_error (tl::Exception &ex)
-{
- tl::error << ex.msg ();
-}
-
-int
-EditorServiceBase::focus_page_open ()
-{
- return 0;
-}
-
-#endif
-
}
diff --git a/src/laybasic/laybasic/layEditorServiceBase.h b/src/laybasic/laybasic/layEditorServiceBase.h
index d23b37755..641aac92f 100644
--- a/src/laybasic/laybasic/layEditorServiceBase.h
+++ b/src/laybasic/laybasic/layEditorServiceBase.h
@@ -272,7 +272,6 @@ class LAYBASIC_PUBLIC EditorServiceBase
*/
virtual int focus_page_open ();
-#if defined(HAVE_QT)
/**
* @brief Gets the editor options pages associated with this plugin
*/
@@ -282,7 +281,6 @@ class LAYBASIC_PUBLIC EditorServiceBase
* @brief Gets the focus page or 0 if there is none
*/
lay::EditorOptionsPage *focus_page ();
-#endif
private:
// The marker representing the mouse cursor
diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h
index bc40922b1..1423ec49b 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.h
+++ b/src/laybasic/laybasic/layLayoutViewBase.h
@@ -77,11 +77,12 @@ class MouseTracker;
class ZoomService;
class SelectionService;
class MoveService;
+class EditorOptionsPage;
+class EditorOptionsPageCollection;
#if defined(HAVE_QT)
class LayerControlPanel;
class HierarchyControlPanel;
-class EditorOptionsPages;
#endif
/**
@@ -351,6 +352,33 @@ class LAYBASIC_PUBLIC LayoutViewBase :
// the base implementation does nothing
}
+ /**
+ * @brief Removes a notification
+ */
+ virtual void remove_notification (const LayoutViewNotification & /*notification*/)
+ {
+ // the base implementation does nothing
+ }
+
+ /**
+ * @brief Shows or hides a toolbox widget with the given name
+ *
+ * Initially toolbox widgets are invisible. They are made visible
+ * by using this method.
+ */
+ virtual void show_toolbox_widget (const std::string & /*name*/, bool /*visible*/)
+ {
+ // the base implementation does nothing
+ }
+
+ /**
+ * @brief Adds an editor options page as a toolbox widget
+ */
+ virtual void add_toolbox_widget (lay::EditorOptionsPage * /*toolbox_widget*/)
+ {
+ // the base implementation does nothing
+ }
+
/**
* @brief Gets the explicit title string of the view
*
@@ -1899,15 +1927,15 @@ class LAYBASIC_PUBLIC LayoutViewBase :
{
return 0;
}
+#endif
/**
* @brief Gets the editor options page
*/
- virtual lay::EditorOptionsPages *editor_options_pages ()
+ virtual lay::EditorOptionsPageCollection *editor_options_pages ()
{
return 0;
}
-#endif
/**
* @brief Get the current viewport
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index a2a6ba96c..671b7cc69 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -27,6 +27,13 @@
#include "laySelector.h"
#include "laybasicConfig.h"
+#if defined(HAVE_QT)
+# include "layEditorOptionsPage.h"
+# include
+# include
+# include
+#endif
+
namespace lay
{
@@ -369,6 +376,47 @@ MoveService::finish ()
// ----------------------------------------------------------------------------
+#if defined(HAVE_QT)
+namespace {
+
+class MoveToolboxPage
+ : public lay::EditorOptionsPageWidget
+{
+public:
+ MoveToolboxPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : lay::EditorOptionsPageWidget (view, dispatcher)
+ {
+ mp_layout = new QHBoxLayout (this);
+
+ mp_x_le = new QLineEdit (this);
+ mp_layout->addWidget (mp_x_le);
+ mp_y_le = new QLineEdit (this);
+ mp_layout->addWidget (mp_y_le);
+ mp_layout->addStretch (1);
+
+ // @@@
+
+ set_toolbox_widget (true);
+ }
+
+ virtual std::string title () const
+ {
+ return "Move Options";
+ }
+
+ virtual int order () const
+ {
+ return 0;
+ }
+
+private:
+ QHBoxLayout *mp_layout;
+ QLineEdit *mp_x_le, *mp_y_le;
+};
+
+}
+#endif
+
class MoveServiceDeclaration
: public lay::PluginDeclaration
{
@@ -383,6 +431,13 @@ class MoveServiceDeclaration
{
return new MoveService (view);
}
+
+#if defined(HAVE_QT)
+ virtual void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
+ {
+ pages.push_back (new MoveToolboxPage (view, dispatcher));
+ }
+#endif
};
static tl::RegisteredClass move_service_decl (new MoveServiceDeclaration (), -970, "laybasic::MoveServicePlugin");
diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro
index 5ba3943e7..85c921ff0 100644
--- a/src/laybasic/laybasic/laybasic.pro
+++ b/src/laybasic/laybasic/laybasic.pro
@@ -42,7 +42,6 @@ SOURCES += \
gsiDeclLayPluginFactory.cc \
layAbstractMenu.cc \
layEditorOptionsPage.cc \
- layEditorOptionsPages.cc \
layEditorUtils.cc \
layLayoutViewConfig.cc \
layMargin.cc \
@@ -100,7 +99,6 @@ HEADERS += \
gsiDeclLayEditorOptionsPage.h \
gsiDeclLayPlugin.h \
layEditorOptionsPage.h \
- layEditorOptionsPages.h \
layEditorUtils.h \
layMargin.h \
laybasicConfig.h \
diff --git a/src/layui/layui/layui.pro b/src/layui/layui/layui.pro
index cf30329d0..2fb51d0d9 100644
--- a/src/layui/layui/layui.pro
+++ b/src/layui/layui/layui.pro
@@ -103,7 +103,6 @@ SOURCES = \
layEditLineStylesForm.cc \
layEditStippleWidget.cc \
layEditStipplesForm.cc \
- layEditorOptionsFrame.cc \
layFileDialog.cc \
layGenericSyntaxHighlighter.cc \
layHierarchyControlPanel.cc \
@@ -161,7 +160,6 @@ HEADERS = \
layEditLineStylesForm.h \
layEditStippleWidget.h \
layEditStipplesForm.h \
- layEditorOptionsFrame.h \
layFileDialog.h \
layGenericSyntaxHighlighter.h \
layHierarchyControlPanel.h \
diff --git a/src/layui/layui/layEditorOptionsFrame.cc b/src/layview/layview/layEditorOptionsFrame.cc
similarity index 95%
rename from src/layui/layui/layEditorOptionsFrame.cc
rename to src/layview/layview/layEditorOptionsFrame.cc
index 2967605a7..135d34bcb 100644
--- a/src/layui/layui/layEditorOptionsFrame.cc
+++ b/src/layview/layview/layEditorOptionsFrame.cc
@@ -20,8 +20,6 @@
*/
-#if defined(HAVE_QT)
-
#include "layEditorOptionsFrame.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
@@ -64,11 +62,10 @@ EditorOptionsFrame::populate (LayoutViewBase *view)
delete mp_pages;
}
- mp_pages = new lay::EditorOptionsPages (this, prop_dialog_pages, view);
+ mp_pages = new lay::EditorOptionsPages (this, view, prop_dialog_pages);
layout ()->addWidget (mp_pages);
setFocusProxy (mp_pages);
}
}
-#endif
diff --git a/src/layui/layui/layEditorOptionsFrame.h b/src/layview/layview/layEditorOptionsFrame.h
similarity index 91%
rename from src/layui/layui/layEditorOptionsFrame.h
rename to src/layview/layview/layEditorOptionsFrame.h
index b33989423..1ea107ccb 100644
--- a/src/layui/layui/layEditorOptionsFrame.h
+++ b/src/layview/layview/layEditorOptionsFrame.h
@@ -20,12 +20,10 @@
*/
-#if defined(HAVE_QT)
-
#ifndef HDR_layEditorOptionsFrame
#define HDR_layEditorOptionsFrame
-#include "layuiCommon.h"
+#include "layviewCommon.h"
#include
namespace lay
@@ -34,7 +32,7 @@ namespace lay
class EditorOptionsPages;
class LayoutViewBase;
-class LAYUI_PUBLIC EditorOptionsFrame
+class LAYVIEW_PUBLIC EditorOptionsFrame
: public QFrame
{
public:
@@ -55,5 +53,3 @@ class LAYUI_PUBLIC EditorOptionsFrame
}
#endif
-
-#endif // defined(HAVE_QT)
diff --git a/src/laybasic/laybasic/layEditorOptionsPages.cc b/src/layview/layview/layEditorOptionsPages.cc
similarity index 78%
rename from src/laybasic/laybasic/layEditorOptionsPages.cc
rename to src/layview/layview/layEditorOptionsPages.cc
index 994369917..976872f9f 100644
--- a/src/laybasic/laybasic/layEditorOptionsPages.cc
+++ b/src/layview/layview/layEditorOptionsPages.cc
@@ -20,8 +20,6 @@
*/
-#if defined(HAVE_QT)
-
#include "tlInternational.h"
#include "layEditorOptionsPages.h"
#include "tlExceptions.h"
@@ -51,8 +49,8 @@ struct EOPCompareOp
}
};
-EditorOptionsPages::EditorOptionsPages (QWidget *parent, const std::vector &pages, lay::Dispatcher *dispatcher)
- : QFrame (parent), mp_dispatcher (dispatcher)
+EditorOptionsPages::EditorOptionsPages (QWidget *parent, lay::LayoutViewBase *view, const std::vector &pages)
+ : QFrame (parent), mp_view (view)
{
mp_modal_pages = new EditorOptionsModalPages (this);
@@ -63,9 +61,14 @@ EditorOptionsPages::EditorOptionsPages (QWidget *parent, const std::vectorsetSizePolicy (QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored));
ly1->addWidget (mp_pages);
- m_pages = pages;
- for (std::vector ::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
- (*p)->set_owner (this);
+ for (auto p = pages.begin (); p != pages.end (); ++p) {
+ m_pages.push_back (*p);
+ }
+
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (! p->is_toolbox_widget ()) {
+ p->set_owner (this);
+ }
}
update (0);
@@ -91,11 +94,39 @@ EditorOptionsPages::focusInEvent (QFocusEvent * /*event*/)
}
}
+const tl::weak_collection &
+EditorOptionsPages::pages () const
+{
+ return m_pages;
+}
+
+std::vector
+EditorOptionsPages::editor_options_pages (const lay::PluginDeclaration *plugin_declaration)
+{
+ std::vector pages;
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->plugin_declaration () == plugin_declaration) {
+ pages.push_back (const_cast (p.operator-> ()));
+ }
+ }
+ return pages;
+}
+
+std::vector
+EditorOptionsPages::editor_options_pages ()
+{
+ std::vector pages;
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ pages.push_back (const_cast (p.operator-> ()));
+ }
+ return pages;
+}
+
bool
EditorOptionsPages::has_content () const
{
- for (std::vector ::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
- if ((*p)->active () && ! (*p)->is_modal_page ()) {
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->active () && ! p->is_modal_page () && ! p->is_toolbox_widget ()) {
return true;
}
}
@@ -105,8 +136,8 @@ EditorOptionsPages::has_content () const
bool
EditorOptionsPages::has_modal_content () const
{
- for (std::vector ::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
- if ((*p)->active () && (*p)->is_modal_page ()) {
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->active () && p->is_modal_page () && ! p->is_toolbox_widget ()) {
return true;
}
}
@@ -122,7 +153,7 @@ EditorOptionsPages::exec_modal (EditorOptionsPage *page)
// found the page - make it current and show the dialog
mp_modal_pages->set_current_index (i);
- page->setup (mp_dispatcher);
+ page->setup (mp_view);
page->set_focus ();
return mp_modal_pages->exec () != 0;
@@ -138,25 +169,19 @@ EditorOptionsPages::activate (const lay::Plugin *plugin)
{
for (auto op = m_pages.begin (); op != m_pages.end (); ++op) {
bool is_active = false;
- if ((*op)->plugin_declaration () == 0) {
+ if (op->plugin_declaration () == 0) {
is_active = (plugin && plugin->plugin_declaration ()->enable_catchall_editor_options_pages ());
- } else if (plugin && plugin->plugin_declaration () == (*op)->plugin_declaration ()) {
+ } else if (plugin && plugin->plugin_declaration () == op->plugin_declaration ()) {
is_active = true;
}
- (*op)->activate (is_active);
+ op->activate (is_active);
}
}
void
EditorOptionsPages::unregister_page (lay::EditorOptionsPage *page)
{
- std::vector pages;
- for (std::vector ::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
- if (*p != page) {
- pages.push_back (*p);
- }
- }
- m_pages = pages;
+ m_pages.erase (page);
update (0);
}
@@ -164,9 +189,9 @@ void
EditorOptionsPages::make_page_current (lay::EditorOptionsPage *page)
{
for (int i = 0; i < mp_pages->count (); ++i) {
- if (mp_pages->widget (i) == page) {
+ if (mp_pages->widget (i) == page->widget ()) {
mp_pages->setCurrentIndex (i);
- page->setup (mp_dispatcher);
+ page->setup (mp_view);
page->set_focus ();
break;
}
@@ -178,7 +203,7 @@ EditorOptionsPages::activate_page (lay::EditorOptionsPage *page)
{
try {
if (page->active ()) {
- page->setup (mp_dispatcher);
+ page->setup (mp_view);
}
} catch (...) {
// catch any errors related to configuration file errors etc.
@@ -190,7 +215,12 @@ EditorOptionsPages::activate_page (lay::EditorOptionsPage *page)
void
EditorOptionsPages::update (lay::EditorOptionsPage *page)
{
- std::vector sorted_pages = m_pages;
+ std::vector sorted_pages;
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->widget ()) {
+ sorted_pages.push_back (p->widget ());
+ }
+ }
std::sort (sorted_pages.begin (), sorted_pages.end (), EOPCompareOp ());
if (! page && m_pages.size () > 0) {
@@ -208,9 +238,11 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
int index = -1;
int modal_index = -1;
- for (std::vector ::iterator p = sorted_pages.begin (); p != sorted_pages.end (); ++p) {
+ for (auto p = sorted_pages.begin (); p != sorted_pages.end (); ++p) {
if ((*p)->active ()) {
- if (! (*p)->is_modal_page ()) {
+ if ((*p)->is_toolbox_widget ()) {
+ mp_view->add_toolbox_widget (*p);
+ } else if (! (*p)->is_modal_page ()) {
if ((*p) == page) {
index = mp_pages->count ();
}
@@ -250,9 +282,9 @@ EditorOptionsPages::setup ()
{
BEGIN_PROTECTED
- for (std::vector ::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
- if ((*p)->active ()) {
- (*p)->setup (mp_dispatcher);
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->active ()) {
+ p->setup (mp_view);
}
}
@@ -267,10 +299,10 @@ END_PROTECTED_W (this)
void
EditorOptionsPages::do_apply (bool modal)
{
- for (std::vector ::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
- if ((*p)->active () && modal == (*p)->is_modal_page ()) {
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->active () && modal == p->is_modal_page ()) {
// NOTE: we apply to the root dispatcher, so other dispatchers (views) get informed too.
- (*p)->apply (mp_dispatcher->dispatcher ());
+ p->apply (mp_view->dispatcher ());
}
}
}
@@ -349,7 +381,7 @@ EditorOptionsModalPages::set_current_index (int index)
}
void
-EditorOptionsModalPages::add_page (EditorOptionsPage *page)
+EditorOptionsModalPages::add_page (EditorOptionsPageWidget *page)
{
if (! mp_single_page) {
if (mp_pages->count () == 0) {
@@ -388,7 +420,7 @@ EditorOptionsModalPages::remove_page (int index)
mp_pages->removeTab (index);
if (mp_pages->count () == 1) {
mp_pages->hide ();
- mp_single_page = dynamic_cast (mp_pages->widget (0));
+ mp_single_page = dynamic_cast (mp_pages->widget (0));
mp_pages->removeTab (0);
mp_single_page->setParent (mp_single_page_frame);
mp_single_page_frame->layout ()->addWidget (mp_single_page);
@@ -445,5 +477,3 @@ END_PROTECTED
}
}
-
-#endif
diff --git a/src/laybasic/laybasic/layEditorOptionsPages.h b/src/layview/layview/layEditorOptionsPages.h
similarity index 66%
rename from src/laybasic/laybasic/layEditorOptionsPages.h
rename to src/layview/layview/layEditorOptionsPages.h
index 7ce48559c..4eac5cb7b 100644
--- a/src/laybasic/laybasic/layEditorOptionsPages.h
+++ b/src/layview/layview/layEditorOptionsPages.h
@@ -20,14 +20,14 @@
*/
-#if defined(HAVE_QT)
-
#ifndef HDR_layEditorOptionsPages
#define HDR_layEditorOptionsPages
-#include "laybasicCommon.h"
+#include "layviewCommon.h"
#include "layEditorOptionsPage.h"
+#include "tlObjectCollection.h"
+
#include
#include
@@ -50,29 +50,27 @@ class EditorOptionsModalPages;
/**
* @brief The object properties tab widget
*/
-class LAYBASIC_PUBLIC EditorOptionsPages
- : public QFrame
+class LAYVIEW_PUBLIC EditorOptionsPages
+ : public QFrame, public lay::EditorOptionsPageCollection
{
Q_OBJECT
public:
- EditorOptionsPages (QWidget *parent, const std::vector &pages, lay::Dispatcher *root);
+ EditorOptionsPages (QWidget *parent, lay::LayoutViewBase *view, const std::vector &pages);
~EditorOptionsPages ();
- void unregister_page (lay::EditorOptionsPage *page);
- void activate_page (lay::EditorOptionsPage *page);
- void activate (const lay::Plugin *plugin);
- void focusInEvent (QFocusEvent *event);
- void make_page_current (lay::EditorOptionsPage *page);
- bool exec_modal (lay::EditorOptionsPage *page);
+ virtual void unregister_page (lay::EditorOptionsPage *page);
+ virtual bool has_content () const;
+ virtual bool has_modal_content () const;
+ virtual void activate_page (lay::EditorOptionsPage *page);
+ virtual void make_page_current (lay::EditorOptionsPage *page);
+ virtual bool exec_modal (lay::EditorOptionsPage *page);
+ virtual std::vector editor_options_pages (const lay::PluginDeclaration *plugin_declaration);
+ virtual std::vector editor_options_pages ();
+ virtual void activate (const lay::Plugin *plugin);
- const std::vector &pages () const
- {
- return m_pages;
- }
+ const tl::weak_collection &pages () const;
- bool has_content () const;
- bool has_modal_content () const;
void do_apply (bool modal);
public slots:
@@ -80,12 +78,13 @@ public slots:
void setup ();
private:
- std::vector m_pages;
- lay::Dispatcher *mp_dispatcher;
+ tl::weak_collection m_pages;
+ lay::LayoutViewBase *mp_view;
QTabWidget *mp_pages;
EditorOptionsModalPages *mp_modal_pages;
void update (lay::EditorOptionsPage *page);
+ void focusInEvent (QFocusEvent *event);
};
/**
@@ -103,7 +102,7 @@ Q_OBJECT
int count ();
int current_index ();
void set_current_index (int index);
- void add_page (EditorOptionsPage *page);
+ void add_page (EditorOptionsPageWidget *page);
void remove_page (int index);
EditorOptionsPage *widget (int index);
@@ -116,7 +115,7 @@ private slots:
EditorOptionsPages *mp_parent;
QTabWidget *mp_pages;
QFrame *mp_single_page_frame;
- EditorOptionsPage *mp_single_page;
+ EditorOptionsPageWidget *mp_single_page;
QDialogButtonBox *mp_button_box;
void update_title ();
@@ -126,4 +125,3 @@ private slots:
#endif
-#endif // defined(HAVE_QT)
diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc
index 2b74c67c8..d1f43c998 100644
--- a/src/layview/layview/layLayoutView_qt.cc
+++ b/src/layview/layview/layLayoutView_qt.cc
@@ -190,6 +190,13 @@ LayoutViewWidget::~LayoutViewWidget ()
delete view;
}
+void
+LayoutViewWidget::add_toolbox_widget (lay::EditorOptionsPageWidget *toolbox_widget)
+{
+ toolbox_widget->setParent (this);
+ mp_layout->insertWidget (0, toolbox_widget);
+}
+
void
LayoutViewWidget::add_notification (const LayoutViewNotification ¬ificaton)
{
@@ -461,6 +468,22 @@ LayoutView::add_notification (const LayoutViewNotification ¬ification)
}
}
+void
+LayoutView::remove_notification (const LayoutViewNotification ¬ification)
+{
+ if (mp_widget) {
+ mp_widget->remove_notification (notification);
+ }
+}
+
+void
+LayoutView::add_toolbox_widget (lay::EditorOptionsPage *toolbox_widget)
+{
+ if (mp_widget && toolbox_widget->widget ()) {
+ mp_widget->add_toolbox_widget (toolbox_widget->widget ());
+ }
+}
+
bool
LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken)
{
@@ -655,7 +678,7 @@ QWidget *LayoutView::widget ()
return mp_widget;
}
-void LayoutView::close()
+void LayoutView::close ()
{
close_event ();
close_event.clear ();
@@ -758,7 +781,7 @@ LayoutView::do_change_active_cellview ()
dm_setup_editor_option_pages ();
}
-lay::EditorOptionsPages *LayoutView::editor_options_pages ()
+lay::EditorOptionsPageCollection *LayoutView::editor_options_pages ()
{
if (! mp_editor_options_frame) {
return 0;
@@ -770,9 +793,10 @@ lay::EditorOptionsPages *LayoutView::editor_options_pages ()
void LayoutView::do_setup_editor_options_pages ()
{
// initialize the editor option pages
- lay::EditorOptionsPages *eo_pages = editor_options_pages ();
+ lay::EditorOptionsPageCollection *eo_pages = editor_options_pages ();
if (eo_pages) {
- 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) {
(*op)->setup (this);
}
}
@@ -1613,7 +1637,7 @@ LayoutView::mode (int m)
void
LayoutView::activate_editor_option_pages ()
{
- lay::EditorOptionsPages *eo_pages = editor_options_pages ();
+ lay::EditorOptionsPageCollection *eo_pages = editor_options_pages ();
if (eo_pages) {
eo_pages->activate (active_plugin ());
}
diff --git a/src/layview/layview/layLayoutView_qt.h b/src/layview/layview/layLayoutView_qt.h
index 548e13012..7cb72ac60 100644
--- a/src/layview/layview/layLayoutView_qt.h
+++ b/src/layview/layview/layLayoutView_qt.h
@@ -89,6 +89,7 @@ class Browser;
class ColorButton;
class ConfigureAction;
class EditorOptionsPages;
+class EditorOptionsPageWidget;
class PropertiesDialog;
/**
@@ -154,6 +155,19 @@ class LAYVIEW_PUBLIC LayoutView
*/
virtual void add_notification (const LayoutViewNotification ¬ification);
+ /**
+ * @brief Removes a notification
+ */
+ virtual void remove_notification (const LayoutViewNotification ¬ification);
+
+ /**
+ * @brief Adds a toolbox widget
+ *
+ * This will take ownership over the EditorOptionsPage object until
+ * it is re-parented.
+ */
+ virtual void add_toolbox_widget (EditorOptionsPage *toolbox_widget);
+
/**
* @brief Gets the widget object that view is embedded in
*/
@@ -376,7 +390,7 @@ class LAYVIEW_PUBLIC LayoutView
/**
* @brief Gets the editor options pages
*/
- virtual lay::EditorOptionsPages *editor_options_pages ();
+ virtual lay::EditorOptionsPageCollection *editor_options_pages ();
/**
* @brief Gets the layer control panel
@@ -750,6 +764,8 @@ Q_OBJECT
/**
* @brief Adds a notification
+ *
+ * Notifications are banners that pop up at the top of the view canvas.
*/
void add_notification (const LayoutViewNotification ¬ification);
@@ -758,6 +774,15 @@ Q_OBJECT
*/
void remove_notification (const LayoutViewNotification ¬ification);
+ /**
+ * @brief Adds a tool box widget
+ *
+ * Toolbox widgets are EditorOptionsPage widgets that are placed
+ * at the top of the view canvas instead of being put into
+ * the editor options panel.
+ */
+ void add_toolbox_widget (lay::EditorOptionsPageWidget *toolbox_widget);
+
/**
* @brief Gets the LayoutView embedded into this widget
*/
diff --git a/src/layview/layview/layview.pro b/src/layview/layview/layview.pro
index 4fd39c63e..3d5ab457a 100644
--- a/src/layview/layview/layview.pro
+++ b/src/layview/layview/layview.pro
@@ -10,11 +10,15 @@ RESOURCES = \
SOURCES = \
layGridNet.cc \
+ layEditorOptionsFrame.cc \
+ layEditorOptionsPages.cc \
layviewForceLink.cc \
gsiDeclLayAdditional.cc \
HEADERS = \
layGridNet.h \
+ layEditorOptionsFrame.h \
+ layEditorOptionsPages.h \
layLayoutView.h \
layviewForceLink.h \
From 0b9a0c3af1933d2faa3b2d204c60fb6eba8fccfe Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 12 Jan 2026 17:05:38 +0100
Subject: [PATCH 08/36] WIP, e.g. avoiding sticky selection when aborting
'move' by chosing a different mode
---
src/laybasic/laybasic/layEditorOptionsPage.cc | 19 ++++++++++
src/laybasic/laybasic/layEditorOptionsPage.h | 7 ++++
src/laybasic/laybasic/layLayoutViewBase.h | 11 ------
src/laybasic/laybasic/layMove.cc | 36 +++++++++++++++++--
src/laybasic/laybasic/layMove.h | 1 +
src/layview/layview/layEditorOptionsFrame.cc | 8 ++---
src/layview/layview/layEditorOptionsPages.cc | 17 +++++----
src/layview/layview/layEditorOptionsPages.h | 3 +-
8 files changed, 76 insertions(+), 26 deletions(-)
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index e489bc1d8..cee43ea82 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -31,6 +31,14 @@
namespace lay
{
+// ------------------------------------------------------------------
+// EditorOptionsPageCollection implementation
+
+EditorOptionsPageCollection::EditorOptionsPageCollection ()
+{
+ // .. nothing yet ..
+}
+
// ------------------------------------------------------------------
// EditorOptionsPage implementation
@@ -115,6 +123,11 @@ EditorOptionsPage::activate (bool active)
if (mp_owner) {
mp_owner->activate_page (this);
}
+ if (m_active) {
+ activated ();
+ } else {
+ deactivated ();
+ }
}
}
@@ -191,6 +204,12 @@ EditorOptionsPageWidget::set_focus ()
QWidget::focusNextPrevChild (true);
}
+void
+EditorOptionsPageWidget::set_visible (bool visible)
+{
+ setVisible (visible);
+}
+
#endif
}
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h
index 33a553034..b4a541e40 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.h
+++ b/src/laybasic/laybasic/layEditorOptionsPage.h
@@ -53,6 +53,7 @@ class EditorOptionsPageWidget;
class LAYBASIC_PUBLIC EditorOptionsPageCollection
{
public:
+ EditorOptionsPageCollection ();
virtual ~EditorOptionsPageCollection () { }
virtual void unregister_page (EditorOptionsPage *page) = 0;
@@ -64,6 +65,7 @@ class LAYBASIC_PUBLIC EditorOptionsPageCollection
virtual bool exec_modal (EditorOptionsPage *page) = 0;
virtual std::vector editor_options_pages (const lay::PluginDeclaration *plugin) = 0;
virtual std::vector editor_options_pages () = 0;
+ virtual lay::EditorOptionsPage *page_with_name (const std::string &name) = 0;
};
/**
@@ -79,11 +81,13 @@ class LAYBASIC_PUBLIC EditorOptionsPage
virtual std::string title () const = 0;
virtual int order () const = 0;
+ virtual const char *name () const { return 0; }
virtual void apply (lay::Dispatcher * /*root*/) { }
virtual void setup (lay::Dispatcher * /*root*/) { }
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
virtual void config_recent_for_layer (lay::Dispatcher * /*root*/, const db::LayerProperties & /*lp*/, int /*cv_index*/) { }
virtual void set_focus () { }
+ virtual void set_visible (bool /*visible*/) { }
virtual EditorOptionsPageWidget *widget () { return 0; }
bool is_focus_page () const { return m_focus_page; }
@@ -123,6 +127,8 @@ class LAYBASIC_PUBLIC EditorOptionsPage
protected:
virtual void active_cellview_changed () { }
virtual void technology_changed (const std::string & /*tech*/) { }
+ virtual void activated () { }
+ virtual void deactivated () { }
private:
EditorOptionsPageCollection *mp_owner;
@@ -153,6 +159,7 @@ Q_OBJECT
virtual ~EditorOptionsPageWidget ();
virtual void set_focus ();
+ virtual void set_visible (bool visible);
virtual EditorOptionsPageWidget *widget () { return this; }
protected slots:
diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h
index 1423ec49b..63c2c3fe4 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.h
+++ b/src/laybasic/laybasic/layLayoutViewBase.h
@@ -360,17 +360,6 @@ class LAYBASIC_PUBLIC LayoutViewBase :
// the base implementation does nothing
}
- /**
- * @brief Shows or hides a toolbox widget with the given name
- *
- * Initially toolbox widgets are invisible. They are made visible
- * by using this method.
- */
- virtual void show_toolbox_widget (const std::string & /*name*/, bool /*visible*/)
- {
- // the base implementation does nothing
- }
-
/**
* @brief Adds an editor options page as a toolbox widget
*/
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 671b7cc69..e3866e04d 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -37,6 +37,8 @@
namespace lay
{
+const char *move_editor_options_name = "move-editor-options";
+
// -------------------------------------------------------------
// MoveService implementation
@@ -62,7 +64,11 @@ MoveService::deactivated ()
EditorServiceBase::deactivated ();
m_shift = db::DPoint ();
mp_editables->clear_transient_selection ();
- drag_cancel ();
+
+ if (m_dragging) {
+ // we don't just call drag_cancel() - this way avoids pending selections with the wrong coordinates
+ mp_view->edit_cancel ();
+ }
}
bool
@@ -127,6 +133,15 @@ MoveService::key_event (unsigned int key, unsigned int buttons)
}
}
+void
+MoveService::show_toolbox (bool visible)
+{
+ lay::EditorOptionsPage *op = mp_view->editor_options_pages () ? mp_view->editor_options_pages ()->page_with_name (move_editor_options_name) : 0;
+ if (op) {
+ op->set_visible (visible);
+ }
+}
+
int
MoveService::focus_page_open ()
{
@@ -320,6 +335,8 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_
m_dragging = true;
m_dragging_transient = drag_transient;
+
+ show_toolbox (true);
ui ()->grab_mouse (this, false);
m_shift = db::DPoint ();
@@ -332,7 +349,9 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_
m_dragging = false;
+ show_toolbox (false);
ui ()->ungrab_mouse (this);
+
mp_editables->end_move (p, ac_from_buttons (buttons), mp_transaction.release ());
if (m_dragging_transient) {
@@ -350,6 +369,7 @@ MoveService::drag_cancel ()
{
m_shift = db::DPoint ();
if (m_dragging) {
+ show_toolbox (false);
ui ()->ungrab_mouse (this);
m_dragging = false;
}
@@ -394,8 +414,7 @@ class MoveToolboxPage
mp_layout->addWidget (mp_y_le);
mp_layout->addStretch (1);
- // @@@
-
+ hide ();
set_toolbox_widget (true);
}
@@ -404,11 +423,21 @@ class MoveToolboxPage
return "Move Options";
}
+ virtual const char *name () const
+ {
+ return move_editor_options_name;
+ }
+
virtual int order () const
{
return 0;
}
+ virtual void deactivated ()
+ {
+ hide ();
+ }
+
private:
QHBoxLayout *mp_layout;
QLineEdit *mp_x_le, *mp_y_le;
@@ -436,6 +465,7 @@ class MoveServiceDeclaration
virtual void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
{
pages.push_back (new MoveToolboxPage (view, dispatcher));
+ pages.back ()->set_plugin_declaration (this);
}
#endif
};
diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h
index a8cd8cdb9..9fdfaf357 100644
--- a/src/laybasic/laybasic/layMove.h
+++ b/src/laybasic/laybasic/layMove.h
@@ -57,6 +57,7 @@ class LAYBASIC_PUBLIC MoveService :
virtual void drag_cancel ();
virtual void deactivated ();
int focus_page_open ();
+ void show_toolbox (bool visible);
bool handle_click (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction);
diff --git a/src/layview/layview/layEditorOptionsFrame.cc b/src/layview/layview/layEditorOptionsFrame.cc
index 135d34bcb..bd71de541 100644
--- a/src/layview/layview/layEditorOptionsFrame.cc
+++ b/src/layview/layview/layEditorOptionsFrame.cc
@@ -49,12 +49,12 @@ EditorOptionsFrame::~EditorOptionsFrame ()
void
EditorOptionsFrame::populate (LayoutViewBase *view)
{
- std::vector prop_dialog_pages;
+ std::vector editor_options_pages;
for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) {
- cls->get_editor_options_pages (prop_dialog_pages, view, view->dispatcher ());
+ cls->get_editor_options_pages (editor_options_pages, view, view->dispatcher ());
}
- for (std::vector::const_iterator op = prop_dialog_pages.begin (); op != prop_dialog_pages.end (); ++op) {
+ for (std::vector::const_iterator op = editor_options_pages.begin (); op != editor_options_pages.end (); ++op) {
(*op)->activate (false);
}
@@ -62,7 +62,7 @@ EditorOptionsFrame::populate (LayoutViewBase *view)
delete mp_pages;
}
- mp_pages = new lay::EditorOptionsPages (this, view, prop_dialog_pages);
+ mp_pages = new lay::EditorOptionsPages (this, view, editor_options_pages);
layout ()->addWidget (mp_pages);
setFocusProxy (mp_pages);
}
diff --git a/src/layview/layview/layEditorOptionsPages.cc b/src/layview/layview/layEditorOptionsPages.cc
index 976872f9f..ebcca5323 100644
--- a/src/layview/layview/layEditorOptionsPages.cc
+++ b/src/layview/layview/layEditorOptionsPages.cc
@@ -94,12 +94,6 @@ EditorOptionsPages::focusInEvent (QFocusEvent * /*event*/)
}
}
-const tl::weak_collection &
-EditorOptionsPages::pages () const
-{
- return m_pages;
-}
-
std::vector
EditorOptionsPages::editor_options_pages (const lay::PluginDeclaration *plugin_declaration)
{
@@ -185,6 +179,17 @@ EditorOptionsPages::unregister_page (lay::EditorOptionsPage *page)
update (0);
}
+lay::EditorOptionsPage *
+EditorOptionsPages::page_with_name (const std::string &name)
+{
+ for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
+ if (p->name () && name == p->name ()) {
+ return p.operator-> ();
+ }
+ }
+ return 0;
+}
+
void
EditorOptionsPages::make_page_current (lay::EditorOptionsPage *page)
{
diff --git a/src/layview/layview/layEditorOptionsPages.h b/src/layview/layview/layEditorOptionsPages.h
index 4eac5cb7b..2e0bc100f 100644
--- a/src/layview/layview/layEditorOptionsPages.h
+++ b/src/layview/layview/layEditorOptionsPages.h
@@ -68,8 +68,7 @@ Q_OBJECT
virtual std::vector editor_options_pages (const lay::PluginDeclaration *plugin_declaration);
virtual std::vector editor_options_pages ();
virtual void activate (const lay::Plugin *plugin);
-
- const tl::weak_collection &pages () const;
+ virtual lay::EditorOptionsPage *page_with_name (const std::string &name);
void do_apply (bool modal);
From 67790c0ce71e5bfb89f23e82755113bd521fb8fe Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 12 Jan 2026 19:32:29 +0100
Subject: [PATCH 09/36] WIP
---
src/laybasic/laybasic/gsiDeclLayPlugin.cc | 21 ++++++
src/laybasic/laybasic/gsiDeclLayPlugin.h | 2 +
src/laybasic/laybasic/layEditorOptionsPage.cc | 11 ++-
src/laybasic/laybasic/layEditorServiceBase.cc | 6 ++
src/laybasic/laybasic/layEditorServiceBase.h | 5 ++
src/laybasic/laybasic/layMove.cc | 42 +++++++++---
src/laybasic/laybasic/layMove.h | 1 -
src/laybasic/laybasic/layViewObject.cc | 68 +++++++++++++------
src/laybasic/laybasic/layViewObject.h | 21 +++++-
9 files changed, 143 insertions(+), 34 deletions(-)
diff --git a/src/laybasic/laybasic/gsiDeclLayPlugin.cc b/src/laybasic/laybasic/gsiDeclLayPlugin.cc
index ae83521cb..d3e1d6f5a 100644
--- a/src/laybasic/laybasic/gsiDeclLayPlugin.cc
+++ b/src/laybasic/laybasic/gsiDeclLayPlugin.cc
@@ -415,6 +415,16 @@ PluginImpl::key_event (unsigned int key, unsigned int buttons)
}
}
+bool
+PluginImpl::shortcut_override_event (unsigned int key, unsigned int buttons)
+{
+ if (f_shortcut_override_event.can_issue ()) {
+ return f_shortcut_override_event.issue (&lay::ViewService::shortcut_override_event, key, buttons);
+ } else {
+ return lay::EditorServiceBase::shortcut_override_event (key, buttons);
+ }
+}
+
bool
PluginImpl::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
@@ -728,6 +738,17 @@ Class decl_Plugin (decl_PluginBase, "lay", "Plugin",
"@param buttons A combination of the constants in the \\ButtonState class which codes both the mouse buttons and the key modifiers (.e. ShiftButton etc).\n"
"@return True to terminate dispatcher\n"
) +
+ callback ("shortcut_override_event", &gsi::PluginImpl::shortcut_override_event, &gsi::PluginImpl::f_shortcut_override_event, gsi::arg ("key"), gsi::arg ("buttons"),
+ "@brief Allows overriding keyboard shortcuts for this plugin\n"
+ "If the implementation returns true, the given key is not handled by the shortcut system, but rather\n"
+ "passed to 'key_event' the usual way.\n"
+ "\n"
+ "@param key The Qt key code of the key that was pressed\n"
+ "@param buttons A combination of the constants in the \\ButtonState class which codes both the mouse buttons and the key modifiers (.e. ShiftButton etc).\n"
+ "@return True to request 'key_event' handling\n"
+ "\n"
+ "This method has been introduced in version 0.30.5."
+ ) +
callback ("mouse_button_pressed_event", &gsi::PluginImpl::mouse_press_event_noref, &gsi::PluginImpl::f_mouse_press_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
"@brief Handles the mouse button pressed event\n"
"This method will called by the view when a button is pressed on the mouse.\n"
diff --git a/src/laybasic/laybasic/gsiDeclLayPlugin.h b/src/laybasic/laybasic/gsiDeclLayPlugin.h
index c1a442633..8bc0e3eb9 100644
--- a/src/laybasic/laybasic/gsiDeclLayPlugin.h
+++ b/src/laybasic/laybasic/gsiDeclLayPlugin.h
@@ -62,6 +62,7 @@ class PluginImpl
virtual void config_finalize_impl ();
virtual void config_finalize ();
virtual bool key_event (unsigned int key, unsigned int buttons);
+ virtual bool shortcut_override_event (unsigned int key, unsigned int buttons);
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio) ;
bool mouse_press_event_noref (db::DPoint p, unsigned int buttons, bool prio);
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
@@ -116,6 +117,7 @@ class PluginImpl
gsi::Callback f_configure;
gsi::Callback f_config_finalize;
gsi::Callback f_key_event;
+ gsi::Callback f_shortcut_override_event;
gsi::Callback f_mouse_press_event;
gsi::Callback f_mouse_click_event;
gsi::Callback f_mouse_double_click_event;
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index cee43ea82..291d815db 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -70,7 +70,9 @@ EditorOptionsPage::init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
int
EditorOptionsPage::show ()
{
- if (mp_owner && m_active) {
+ if (! m_active) {
+ return -1;
+ } else if (mp_owner) {
if (! is_modal_page ()) {
mp_owner->make_page_current (this);
return -1;
@@ -78,6 +80,7 @@ EditorOptionsPage::show ()
return mp_owner->exec_modal (this) ? 1 : 0;
}
} else {
+ set_focus ();
return -1;
}
}
@@ -200,8 +203,10 @@ END_PROTECTED
void
EditorOptionsPageWidget::set_focus ()
{
- setFocus (Qt::TabFocusReason);
- QWidget::focusNextPrevChild (true);
+ if (isVisible ()) {
+ setFocus (Qt::TabFocusReason);
+ QWidget::focusNextPrevChild (true);
+ }
}
void
diff --git a/src/laybasic/laybasic/layEditorServiceBase.cc b/src/laybasic/laybasic/layEditorServiceBase.cc
index a3ae88baf..0783817ba 100644
--- a/src/laybasic/laybasic/layEditorServiceBase.cc
+++ b/src/laybasic/laybasic/layEditorServiceBase.cc
@@ -379,6 +379,12 @@ EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
}
}
+bool
+EditorServiceBase::shortcut_override_event (unsigned int key, unsigned int buttons)
+{
+ return is_active () && key == Qt::Key_Tab && buttons == 0 && focus_page ();
+}
+
int
EditorServiceBase::focus_page_open ()
{
diff --git a/src/laybasic/laybasic/layEditorServiceBase.h b/src/laybasic/laybasic/layEditorServiceBase.h
index 641aac92f..86441aadc 100644
--- a/src/laybasic/laybasic/layEditorServiceBase.h
+++ b/src/laybasic/laybasic/layEditorServiceBase.h
@@ -185,6 +185,11 @@ class LAYBASIC_PUBLIC EditorServiceBase
*/
virtual bool key_event (unsigned int /*key*/, unsigned int /*buttons*/);
+ /**
+ * @brief Shortcut override event handler
+ */
+ virtual bool shortcut_override_event (unsigned int /*key*/, unsigned int /*buttons*/);
+
/**
* @brief Mouse press event handler
*/
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index e3866e04d..0664a4bc9 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -30,6 +30,7 @@
#if defined(HAVE_QT)
# include "layEditorOptionsPage.h"
# include
+# include // @@@
# include
# include
#endif
@@ -142,16 +143,6 @@ MoveService::show_toolbox (bool visible)
}
}
-int
-MoveService::focus_page_open ()
-{
- // This method is called on "Tab" by "key_event". "fp" is null as we don't have a focus page registered.
- if (is_active () && dispatcher ()) {
- dispatcher ()->menu_activated ("cm_sel_move");
- }
- return 0;
-}
-
bool
MoveService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
@@ -415,6 +406,8 @@ class MoveToolboxPage
mp_layout->addStretch (1);
hide ();
+
+ set_focus_page (true);
set_toolbox_widget (true);
}
@@ -438,6 +431,35 @@ class MoveToolboxPage
hide ();
}
+ virtual void keyPressEvent (QKeyEvent *event)
+ {
+ if (event->key () == Qt::Key_Escape) {
+ tl::info << "@@@ Escape!";
+ view ()->set_focus ();
+ } else if (event->key () == Qt::Key_Enter || event->key () == Qt::Key_Return) {
+ tl::info << "@@@ Accept!";
+ view ()->set_focus ();
+ }
+ QWidget::keyPressEvent (event);
+ }
+
+ virtual bool event (QEvent *event)
+ {
+ if (event->type () == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = dynamic_cast (event);
+ if (ke->key () == Qt::Key_Escape ||
+ ke->key () == Qt::Key_Tab ||
+ ke->key () == Qt::Key_Enter ||
+ ke->key () == Qt::Key_Return ||
+ ke->key () == Qt::Key_Backtab) {
+ // accept the shortcut override event for some keys, so we can handle
+ // it in keyPressEvent
+ ke->accept ();
+ }
+ }
+ return QWidget::event (event);
+ }
+
private:
QHBoxLayout *mp_layout;
QLineEdit *mp_x_le, *mp_y_le;
diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h
index 9fdfaf357..635c25f31 100644
--- a/src/laybasic/laybasic/layMove.h
+++ b/src/laybasic/laybasic/layMove.h
@@ -56,7 +56,6 @@ class LAYBASIC_PUBLIC MoveService :
virtual bool key_event (unsigned int key, unsigned int buttons);
virtual void drag_cancel ();
virtual void deactivated ();
- int focus_page_open ();
void show_toolbox (bool visible);
bool handle_click (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction);
diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc
index 488ff5fbb..44094faf6 100644
--- a/src/laybasic/laybasic/layViewObject.cc
+++ b/src/laybasic/laybasic/layViewObject.cc
@@ -257,6 +257,37 @@ class ViewObjectQWidget : public QWidget
END_PROTECTED
}
+ bool event (QEvent *e)
+ {
+ if (e->type () == QEvent::MaxUser) {
+
+ // GTF probe event
+ // record the contents (the screenshot) as ASCII text
+ mp_view->gtf_probe ();
+
+ e->accept ();
+ return true;
+
+ } else if (e->type () == QEvent::ShortcutOverride) {
+
+ BEGIN_PROTECTED
+ QKeyEvent *ke = dynamic_cast (e);
+ if (ke) {
+ unsigned int buttons = qt_to_buttons (Qt::MouseButtons (), ke->modifiers ());
+ if (mp_view->send_shortcut_override_event ((unsigned int) ke->key (), buttons)) {
+ e->accept ();
+ return true;
+ }
+ }
+ END_PROTECTED
+
+ return false;
+
+ } else {
+ return QWidget::event (e);
+ }
+ }
+
DragDropDataBase *get_drag_drop_data (const QMimeData *data)
{
if (! data || ! data->hasFormat (QString::fromUtf8 (drag_drop_mime_type ()))) {
@@ -481,24 +512,6 @@ class ViewObjectQWidget : public QWidget
END_PROTECTED
}
-#if defined(HAVE_QT)
- bool event (QEvent *e)
- {
- if (e->type () == QEvent::MaxUser) {
-
- // GTF probe event
- // record the contents (the screenshot) as ASCII text
- mp_view->gtf_probe ();
-
- e->accept ();
- return true;
-
- } else {
- return QWidget::event (e);
- }
- }
-#endif
-
private:
ViewObjectUI *mp_view;
};
@@ -674,7 +687,7 @@ ViewObjectUI::realize_cursor ()
#endif
}
-void
+bool
ViewObjectUI::send_key_press_event (unsigned int key, unsigned int buttons)
{
bool done = false;
@@ -685,6 +698,23 @@ ViewObjectUI::send_key_press_event (unsigned int key, unsigned int buttons)
if (! done) {
key_event (key, buttons);
}
+
+ return done;
+}
+
+bool
+ViewObjectUI::send_shortcut_override_event(unsigned int key, unsigned int buttons)
+{
+ bool done = false;
+ if (mp_active_service) {
+ done = (mp_active_service->enabled () && mp_active_service->shortcut_override_event (key, buttons));
+ }
+
+ if (! done) {
+ key_event (key, buttons);
+ }
+
+ return done;
}
void
diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h
index 6ef9b691e..2c680e268 100644
--- a/src/laybasic/laybasic/layViewObject.h
+++ b/src/laybasic/laybasic/layViewObject.h
@@ -125,6 +125,17 @@ class LAYBASIC_PUBLIC ViewService
*/
virtual bool key_event (unsigned int /*key*/, unsigned int /*buttons*/) { return false; }
+ /**
+ * @brief Handler for the shortcut override event
+ *
+ * This method will be called by the ViewObjectWidget object to
+ * ask if a plugin wants to consume a key event.
+ *
+ * If the implementation returns true, the key is passed through "key_event". Otherwise
+ * it is handled by the shortcut system.
+ */
+ virtual bool shortcut_override_event (unsigned int /*key*/, unsigned int /*buttons*/) { return false; }
+
#if defined(HAVE_QT)
/**
* @brief The drag enter event
@@ -1023,7 +1034,15 @@ class LAYBASIC_PUBLIC ViewObjectUI :
/**
* @brief External entry point for key press event generation
*/
- void send_key_press_event (unsigned int key, unsigned int buttons);
+ bool send_key_press_event(unsigned int key, unsigned int buttons);
+
+ /**
+ * @brief External entry point for ShortcutOverride event handling
+ *
+ * Editables may return true to indicate that they want to consume the given key
+ * sequence through "key_pressed" instead of being handled by Qt's shortcut system.
+ */
+ bool send_shortcut_override_event(unsigned int key, unsigned int buttons);
/**
* @brief External entry point for mouse move event generation
From 8add404adcef1aa2c9744edec5c3738d4586621f Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 12 Jan 2026 21:00:24 +0100
Subject: [PATCH 10/36] WIP
---
.../laybasic/gsiDeclLayEditorOptionsPage.cc | 31 +++++++++++++++
.../laybasic/gsiDeclLayEditorOptionsPage.h | 3 ++
src/laybasic/laybasic/layEditorOptionsPage.cc | 39 +++++++++++++++++--
src/laybasic/laybasic/layEditorOptionsPage.h | 7 +++-
src/laybasic/laybasic/layEditorServiceBase.cc | 12 ++++--
src/laybasic/laybasic/layMove.cc | 27 ++-----------
6 files changed, 87 insertions(+), 32 deletions(-)
diff --git a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
index 7a63b0df5..1d2d335fd 100644
--- a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
@@ -73,6 +73,10 @@ Class decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWid
) +
method ("setup", &lay::EditorOptionsPage::setup, gsi::arg ("dispatcher"),
"@brief Transfers data from the configuration to the page\n"
+ ) +
+ method ("cancel", &lay::EditorOptionsPage::cancel,
+ "@brief Gets called when the Escape key is pressed on a non-modal page\n"
+ "This method has been introduced in version 0.30.6."
),
"@brief The plugin framework's editor options page base class\n"
"\n"
@@ -111,6 +115,11 @@ static void setup_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
ep->lay::EditorOptionsPage::setup (root);
}
+static void cancel_fb (EditorOptionsPageImpl *ep)
+{
+ ep->lay::EditorOptionsPage::cancel ();
+}
+
void
EditorOptionsPageImpl::apply_impl (lay::Dispatcher *root)
{
@@ -143,6 +152,22 @@ EditorOptionsPageImpl::setup (lay::Dispatcher *root)
}
}
+void
+EditorOptionsPageImpl::cancel_impl ()
+{
+ lay::EditorOptionsPage::cancel ();
+}
+
+void
+EditorOptionsPageImpl::cancel ()
+{
+ if (f_cancel.can_issue ()) {
+ f_cancel.issue (&EditorOptionsPageImpl::cancel_impl);
+ } else {
+ EditorOptionsPageImpl::cancel_impl ();
+ }
+}
+
EditorOptionsPageImpl *new_editor_options_page (const std::string &title, int index)
{
return new EditorOptionsPageImpl (title, index);
@@ -173,6 +198,12 @@ Class decl_EditorOptionsPage (decl_EditorOptionsPageBase,
"In this method, you should transfer all configuration data to the widgets.\n"
"Use \\Dispatcher#get_config on the dispatcher object ('dispatcher' argument) to get a configuration parameter "
"and set the editing widget's state accordingly.\n"
+ ) +
+ // prevents infinite recursion
+ method_ext ("cancel", &cancel_fb, "@hide") +
+ callback ("cancel", &EditorOptionsPageImpl::cancel, &EditorOptionsPageImpl::f_cancel,
+ "@brief Reimplement this method to receive Escape key events for the page\n"
+ "This method has been added in version 0.30.6.\n"
),
"@brief The plugin framework's editor options page\n"
"\n"
diff --git a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
index 0e1598898..c679b0d0e 100644
--- a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
+++ b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
@@ -53,9 +53,11 @@ class EditorOptionsPageImpl
void call_edited ();
virtual void apply (lay::Dispatcher *root);
virtual void setup (lay::Dispatcher *root);
+ virtual void cancel ();
gsi::Callback f_apply;
gsi::Callback f_setup;
+ gsi::Callback f_cancel;
private:
tl::weak_ptr mp_view;
@@ -65,6 +67,7 @@ class EditorOptionsPageImpl
void apply_impl (lay::Dispatcher *root);
void setup_impl (lay::Dispatcher *root);
+ void cancel_impl ();
};
}
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index 291d815db..44bd772f1 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -188,10 +188,17 @@ void
EditorOptionsPageWidget::keyPressEvent (QKeyEvent *event)
{
BEGIN_PROTECTED
- if (! is_modal_page () && event->modifiers () == Qt::NoModifier && event->key () == Qt::Key_Return) {
- // The Return key on a non-modal page commits the values and gives back the focus
- // to the view
- apply (dispatcher ());
+ if (! is_modal_page () &&
+ event->modifiers () == Qt::NoModifier &&
+ (event->key () == Qt::Key_Return || event->key () == Qt::Key_Enter || event->key () == Qt::Key_Escape)) {
+ if (event->key () == Qt::Key_Escape) {
+ // The Escape key creates a call to cancel()
+ cancel ();
+ } else {
+ // The Return key on a non-modal page commits the values and gives back the focus
+ // to the view
+ apply (dispatcher ());
+ }
view ()->set_focus ();
event->accept ();
} else {
@@ -200,6 +207,24 @@ BEGIN_PROTECTED
END_PROTECTED
}
+bool
+EditorOptionsPageWidget::event (QEvent *event)
+{
+ if (event->type () == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = dynamic_cast (event);
+ if (ke->key () == Qt::Key_Escape ||
+ ke->key () == Qt::Key_Tab ||
+ ke->key () == Qt::Key_Enter ||
+ ke->key () == Qt::Key_Return ||
+ ke->key () == Qt::Key_Backtab) {
+ // accept the shortcut override event for some keys, so we can handle
+ // it in keyPressEvent
+ ke->accept ();
+ }
+ }
+ return QWidget::event (event);
+}
+
void
EditorOptionsPageWidget::set_focus ()
{
@@ -215,6 +240,12 @@ EditorOptionsPageWidget::set_visible (bool visible)
setVisible (visible);
}
+bool
+EditorOptionsPageWidget::is_visible () const
+{
+ return isVisible ();
+}
+
#endif
}
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h
index b4a541e40..20cfb81c1 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.h
+++ b/src/laybasic/laybasic/layEditorOptionsPage.h
@@ -83,13 +83,16 @@ class LAYBASIC_PUBLIC EditorOptionsPage
virtual int order () const = 0;
virtual const char *name () const { return 0; }
virtual void apply (lay::Dispatcher * /*root*/) { }
+ virtual void cancel () { }
virtual void setup (lay::Dispatcher * /*root*/) { }
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
virtual void config_recent_for_layer (lay::Dispatcher * /*root*/, const db::LayerProperties & /*lp*/, int /*cv_index*/) { }
virtual void set_focus () { }
- virtual void set_visible (bool /*visible*/) { }
virtual EditorOptionsPageWidget *widget () { return 0; }
+ virtual bool is_visible () const { return false; }
+ virtual void set_visible (bool /*visible*/) { }
+
bool is_focus_page () const { return m_focus_page; }
void set_focus_page (bool f) { m_focus_page = f; }
@@ -159,6 +162,7 @@ Q_OBJECT
virtual ~EditorOptionsPageWidget ();
virtual void set_focus ();
+ virtual bool is_visible () const;
virtual void set_visible (bool visible);
virtual EditorOptionsPageWidget *widget () { return this; }
@@ -168,6 +172,7 @@ protected slots:
protected:
virtual bool focusNextPrevChild (bool next);
virtual void keyPressEvent (QKeyEvent *event);
+ virtual bool event (QEvent *event);
};
#endif // defined(HAVE_QT)
diff --git a/src/laybasic/laybasic/layEditorServiceBase.cc b/src/laybasic/laybasic/layEditorServiceBase.cc
index 0783817ba..e56116965 100644
--- a/src/laybasic/laybasic/layEditorServiceBase.cc
+++ b/src/laybasic/laybasic/layEditorServiceBase.cc
@@ -369,9 +369,9 @@ EditorServiceBase::focus_page ()
}
bool
-EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
+EditorServiceBase::key_event (unsigned int key, unsigned int /*buttons*/)
{
- if (is_active () && key == Qt::Key_Tab && buttons == 0) {
+ if (is_active () && (key == Qt::Key_Tab || key == Qt::Key_Backtab)) {
focus_page_open ();
return true;
} else {
@@ -380,9 +380,13 @@ EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
}
bool
-EditorServiceBase::shortcut_override_event (unsigned int key, unsigned int buttons)
+EditorServiceBase::shortcut_override_event (unsigned int key, unsigned int /*buttons*/)
{
- return is_active () && key == Qt::Key_Tab && buttons == 0 && focus_page ();
+ auto fp = focus_page ();
+ return is_active ()
+ && (key == Qt::Key_Tab || key == Qt::Key_Backtab)
+ && fp
+ && (fp->is_modal_page () || fp->is_visible ());
}
int
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 0664a4bc9..80e63b68d 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -431,33 +431,14 @@ class MoveToolboxPage
hide ();
}
- virtual void keyPressEvent (QKeyEvent *event)
+ virtual void apply (lay::Dispatcher * /*dispatcher*/)
{
- if (event->key () == Qt::Key_Escape) {
- tl::info << "@@@ Escape!";
- view ()->set_focus ();
- } else if (event->key () == Qt::Key_Enter || event->key () == Qt::Key_Return) {
- tl::info << "@@@ Accept!";
- view ()->set_focus ();
- }
- QWidget::keyPressEvent (event);
+ tl::info << "@@@ Accept!";
}
- virtual bool event (QEvent *event)
+ virtual void cancel ()
{
- if (event->type () == QEvent::ShortcutOverride) {
- QKeyEvent *ke = dynamic_cast (event);
- if (ke->key () == Qt::Key_Escape ||
- ke->key () == Qt::Key_Tab ||
- ke->key () == Qt::Key_Enter ||
- ke->key () == Qt::Key_Return ||
- ke->key () == Qt::Key_Backtab) {
- // accept the shortcut override event for some keys, so we can handle
- // it in keyPressEvent
- ke->accept ();
- }
- }
- return QWidget::event (event);
+ tl::info << "@@@ Escape!";
}
private:
From 15a5f7f7c2fe812ba14aff8642b537fefacd21c6 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 13 Jan 2026 02:13:13 +0100
Subject: [PATCH 11/36] WIP
---
src/edt/edt/edtPartialService.cc | 4 ---
.../laybasic/gsiDeclLayEditorOptionsPage.cc | 26 ++++++++++++++
.../laybasic/gsiDeclLayEditorOptionsPage.h | 7 ++--
src/laybasic/laybasic/layDispatcher.cc | 8 +++++
src/laybasic/laybasic/layDispatcher.h | 9 +++++
src/laybasic/laybasic/layEditorOptionsPage.cc | 12 ++++---
src/laybasic/laybasic/layEditorOptionsPage.h | 2 ++
src/laybasic/laybasic/layMove.cc | 36 ++++++++++++++++---
src/laybasic/laybasic/layMove.h | 1 +
src/laybasic/laybasic/layPlugin.cc | 9 +++++
src/laybasic/laybasic/layPlugin.h | 18 ++++++++++
src/laybasic/laybasic/laySnap.h | 3 +-
src/layview/layview/layEditorOptionsPages.cc | 4 +--
13 files changed, 119 insertions(+), 20 deletions(-)
diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc
index b2eb61acd..ac480c732 100644
--- a/src/edt/edt/edtPartialService.cc
+++ b/src/edt/edt/edtPartialService.cc
@@ -2027,8 +2027,6 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
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);
@@ -2506,8 +2504,6 @@ PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type a
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);
diff --git a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
index 1d2d335fd..de8619a37 100644
--- a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
@@ -77,6 +77,10 @@ Class decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWid
method ("cancel", &lay::EditorOptionsPage::cancel,
"@brief Gets called when the Escape key is pressed on a non-modal page\n"
"This method has been introduced in version 0.30.6."
+ ) +
+ method ("commit", &lay::EditorOptionsPage::commit,
+ "@brief Gets called when the Enter key is pressed on a non-modal page\n"
+ "This method has been introduced in version 0.30.6."
),
"@brief The plugin framework's editor options page base class\n"
"\n"
@@ -168,6 +172,22 @@ EditorOptionsPageImpl::cancel ()
}
}
+void
+EditorOptionsPageImpl::commit_impl (lay::Dispatcher *root)
+{
+ lay::EditorOptionsPage::commit (root);
+}
+
+void
+EditorOptionsPageImpl::commit (lay::Dispatcher *root)
+{
+ if (f_commit.can_issue ()) {
+ f_commit.issue (&EditorOptionsPageImpl::commit_impl, root);
+ } else {
+ EditorOptionsPageImpl::commit_impl (root);
+ }
+}
+
EditorOptionsPageImpl *new_editor_options_page (const std::string &title, int index)
{
return new EditorOptionsPageImpl (title, index);
@@ -204,6 +224,12 @@ Class decl_EditorOptionsPage (decl_EditorOptionsPageBase,
callback ("cancel", &EditorOptionsPageImpl::cancel, &EditorOptionsPageImpl::f_cancel,
"@brief Reimplement this method to receive Escape key events for the page\n"
"This method has been added in version 0.30.6.\n"
+ ) +
+ // prevents infinite recursion
+ method_ext ("commit", &commit_fb, gsi::arg ("dispatcher"), "@hide") +
+ callback ("commit", &EditorOptionsPageImpl::commit, &EditorOptionsPageImpl::f_commit, gsi::arg ("dispatcher"),
+ "@brief Reimplement this method to receive Enter key events for the page\n"
+ "This method has been added in version 0.30.6.\n"
),
"@brief The plugin framework's editor options page\n"
"\n"
diff --git a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
index c679b0d0e..8a8ee1b84 100644
--- a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
+++ b/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
@@ -53,11 +53,13 @@ class EditorOptionsPageImpl
void call_edited ();
virtual void apply (lay::Dispatcher *root);
virtual void setup (lay::Dispatcher *root);
- virtual void cancel ();
+ virtual void cancel (lay::Dispatcher *root);
+ virtual void commit ();
gsi::Callback f_apply;
gsi::Callback f_setup;
gsi::Callback f_cancel;
+ gsi::Callback f_commit;
private:
tl::weak_ptr mp_view;
@@ -67,7 +69,8 @@ class EditorOptionsPageImpl
void apply_impl (lay::Dispatcher *root);
void setup_impl (lay::Dispatcher *root);
- void cancel_impl ();
+ void cancel_impl (lay::Dispatcher *root);
+ void commit_impl ();
};
}
diff --git a/src/laybasic/laybasic/layDispatcher.cc b/src/laybasic/laybasic/layDispatcher.cc
index b3a1f3b66..2bfdc02d7 100644
--- a/src/laybasic/laybasic/layDispatcher.cc
+++ b/src/laybasic/laybasic/layDispatcher.cc
@@ -103,6 +103,14 @@ Dispatcher::config_finalize ()
}
}
+void
+Dispatcher::function (const std::string &symbol, const std::string &args)
+{
+ if (mp_delegate) {
+ mp_delegate->function (symbol, args);
+ }
+}
+
// Writing and Reading of configuration
diff --git a/src/laybasic/laybasic/layDispatcher.h b/src/laybasic/laybasic/layDispatcher.h
index ab30f9ee3..a94ff0acb 100644
--- a/src/laybasic/laybasic/layDispatcher.h
+++ b/src/laybasic/laybasic/layDispatcher.h
@@ -87,6 +87,14 @@ class LAYBASIC_PUBLIC DispatcherDelegate
// .. this implementation does nothing ..
}
+ /**
+ * @brief Generic function call
+ */
+ virtual void function (const std::string & /*symbol*/, const std::string & /*args*/)
+ {
+ // .. this implementation does nothing ..
+ }
+
/**
* @brief Receives configuration events
*/
@@ -250,6 +258,7 @@ class LAYBASIC_PUBLIC Dispatcher
// capture the configuration events so we can change the value of the configuration actions
virtual bool configure (const std::string &name, const std::string &value);
virtual void config_finalize ();
+ virtual void function (const std::string &symbol, const std::string &args);
private:
Dispatcher (const Dispatcher &);
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index 44bd772f1..739f27c07 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -72,6 +72,9 @@ EditorOptionsPage::show ()
{
if (! m_active) {
return -1;
+ } else if (m_toolbox_widget) {
+ set_focus ();
+ return -1;
} else if (mp_owner) {
if (! is_modal_page ()) {
mp_owner->make_page_current (this);
@@ -80,7 +83,6 @@ EditorOptionsPage::show ()
return mp_owner->exec_modal (this) ? 1 : 0;
}
} else {
- set_focus ();
return -1;
}
}
@@ -123,10 +125,10 @@ EditorOptionsPage::activate (bool active)
{
if (m_active != active) {
m_active = active;
- if (mp_owner) {
- mp_owner->activate_page (this);
- }
if (m_active) {
+ if (mp_owner) {
+ mp_owner->activate_page (this);
+ }
activated ();
} else {
deactivated ();
@@ -197,7 +199,7 @@ BEGIN_PROTECTED
} else {
// The Return key on a non-modal page commits the values and gives back the focus
// to the view
- apply (dispatcher ());
+ commit (dispatcher ());
}
view ()->set_focus ();
event->accept ();
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h
index 20cfb81c1..f1d1fa12d 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.h
+++ b/src/laybasic/laybasic/layEditorOptionsPage.h
@@ -84,7 +84,9 @@ class LAYBASIC_PUBLIC EditorOptionsPage
virtual const char *name () const { return 0; }
virtual void apply (lay::Dispatcher * /*root*/) { }
virtual void cancel () { }
+ virtual void commit (lay::Dispatcher * /*root*/) { }
virtual void setup (lay::Dispatcher * /*root*/) { }
+ virtual void configure (const std::string & /*name*/, const std::string & /*value*/) { }
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
virtual void config_recent_for_layer (lay::Dispatcher * /*root*/, const db::LayerProperties & /*lp*/, int /*cv_index*/) { }
virtual void set_focus () { }
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 80e63b68d..9cf61e9d8 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -30,7 +30,6 @@
#if defined(HAVE_QT)
# include "layEditorOptionsPage.h"
# include
-# include // @@@
# include
# include
#endif
@@ -38,7 +37,9 @@
namespace lay
{
-const char *move_editor_options_name = "move-editor-options";
+const std::string move_editor_options_name ("move-editor-options");
+const std::string move_function_name ("move-execute");
+const std::string move_distance_setter_name ("move-distance");
// -------------------------------------------------------------
// MoveService implementation
@@ -86,6 +87,19 @@ MoveService::configure (const std::string &name, const std::string &value)
return false; // not taken
}
+void
+MoveService::function (const std::string &name, const std::string &value)
+{
+ if (name == move_function_name) {
+ try {
+ db::DVector s;
+ tl::from_string (value, s);
+ tl::info << "@@@ move " << s.to_string ();
+ } catch (...) {
+ }
+ }
+}
+
bool
MoveService::key_event (unsigned int key, unsigned int buttons)
{
@@ -418,7 +432,7 @@ class MoveToolboxPage
virtual const char *name () const
{
- return move_editor_options_name;
+ return move_editor_options_name.c_str ();
}
virtual int order () const
@@ -431,9 +445,21 @@ class MoveToolboxPage
hide ();
}
- virtual void apply (lay::Dispatcher * /*dispatcher*/)
+ virtual void commit (lay::Dispatcher *dispatcher)
{
- tl::info << "@@@ Accept!";
+ tl::info << "@@@ Commit!";
+
+ 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 (move_function_name, db::DVector (dx, dy).to_string ());
+
+ } catch (...) {
+ }
}
virtual void cancel ()
diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h
index 635c25f31..8ba7d6e4a 100644
--- a/src/laybasic/laybasic/layMove.h
+++ b/src/laybasic/laybasic/layMove.h
@@ -43,6 +43,7 @@ class LAYBASIC_PUBLIC MoveService :
bool start_move (db::Transaction *transaction = 0, bool transient_selection = false);
bool configure (const std::string &name, const std::string &value);
+ void function (const std::string &name, const std::string &value);
void finish ();
void cancel ();
diff --git a/src/laybasic/laybasic/layPlugin.cc b/src/laybasic/laybasic/layPlugin.cc
index 48a29f9cd..3b35d2e54 100644
--- a/src/laybasic/laybasic/layPlugin.cc
+++ b/src/laybasic/laybasic/layPlugin.cc
@@ -523,6 +523,15 @@ Plugin::do_config_set (const std::string &name, const std::string &value, bool f
return false;
}
+void
+Plugin::call_function (const std::string &symbol, const std::string &args)
+{
+ function (symbol, args);
+ for (tl::weak_collection::iterator c = m_children.begin (); c != m_children.end (); ++c) {
+ c->call_function (symbol, args);
+ }
+}
+
// ---------------------------------------------------------------------------------------------------
// Menu item generators
diff --git a/src/laybasic/laybasic/layPlugin.h b/src/laybasic/laybasic/layPlugin.h
index 2d5ee32d4..730b42772 100644
--- a/src/laybasic/laybasic/layPlugin.h
+++ b/src/laybasic/laybasic/layPlugin.h
@@ -744,6 +744,13 @@ class LAYBASIC_PUBLIC Plugin
// .. this implementation does nothing ..
}
+ /**
+ * @brief Generic function call
+ *
+ * This method calls "function" on this plugin and all the children.
+ */
+ virtual void call_function (const std::string &symbol, const std::string &args);
+
#if defined(HAVE_QT)
/**
* @brief Return the lay::Browser interface if this object has one
@@ -859,6 +866,17 @@ class LAYBASIC_PUBLIC Plugin
// .. the default implementation does nothing ..
}
+ /**
+ * @brief Implements a generic function call
+ *
+ * This method can be used to establish a communication between a properties page and
+ * a plugin for example.
+ */
+ virtual void function (const std::string & /*symbol*/, const std::string & /*args*/)
+ {
+ // .. this implementation does nothing ..
+ }
+
private:
Plugin (const Plugin &);
Plugin &operator= (const Plugin &);
diff --git a/src/laybasic/laybasic/laySnap.h b/src/laybasic/laybasic/laySnap.h
index cfa63ae9b..6bd43e9be 100644
--- a/src/laybasic/laybasic/laySnap.h
+++ b/src/laybasic/laybasic/laySnap.h
@@ -49,11 +49,12 @@ namespace lay
* Any: no angle constraint
* Diagonal: vertical, horizontal and 45 degree diagonals
* Ortho: vertical and horizontal
+ * DiagonalOnly: 45 degree diagonals, not vertically or horizontally
* Horizontal: horizontal only
* Vertical: vertical only
* Global: use global setting (templates and ruler specific setting only)
*/
- enum angle_constraint_type { AC_Any = 0, AC_Diagonal, AC_DiagonalOnly, AC_Ortho, AC_Horizontal, AC_Vertical, AC_Global, AC_NumModes };
+ enum angle_constraint_type { AC_Any = 0, AC_Diagonal, AC_Ortho, AC_DiagonalOnly, AC_Horizontal, AC_Vertical, AC_Global, AC_NumModes };
/**
* @brief snap a coordinate value to a unit grid
diff --git a/src/layview/layview/layEditorOptionsPages.cc b/src/layview/layview/layEditorOptionsPages.cc
index ebcca5323..a36190106 100644
--- a/src/layview/layview/layEditorOptionsPages.cc
+++ b/src/layview/layview/layEditorOptionsPages.cc
@@ -66,9 +66,7 @@ EditorOptionsPages::EditorOptionsPages (QWidget *parent, lay::LayoutViewBase *vi
}
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
- if (! p->is_toolbox_widget ()) {
- p->set_owner (this);
- }
+ p->set_owner (this);
}
update (0);
From 18ef4a12e246460f3c1b1e40f3ec2419cd348472 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 13 Jan 2026 09:21:41 +0100
Subject: [PATCH 12/36] Allowing use of arrow keys for move
---
src/laybasic/laybasic/layMove.cc | 15 +++++++++++++++
src/laybasic/laybasic/layMove.h | 1 +
2 files changed, 16 insertions(+)
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 9cf61e9d8..ae677b3ff 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -148,6 +148,21 @@ MoveService::key_event (unsigned int key, unsigned int buttons)
}
}
+bool
+MoveService::shortcut_override_event (unsigned int key, unsigned int buttons)
+{
+ if (! m_dragging) {
+ if (int (key) == lay::KeyDown ||
+ int (key) == lay::KeyLeft ||
+ int (key) == lay::KeyUp ||
+ int (key) == lay::KeyRight) {
+ return true;
+ }
+ }
+
+ return lay::EditorServiceBase::shortcut_override_event (key, buttons);
+}
+
void
MoveService::show_toolbox (bool visible)
{
diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h
index 8ba7d6e4a..b487a22d8 100644
--- a/src/laybasic/laybasic/layMove.h
+++ b/src/laybasic/laybasic/layMove.h
@@ -55,6 +55,7 @@ class LAYBASIC_PUBLIC MoveService :
virtual bool mouse_release_event (const db::DPoint &p, unsigned int /*buttons*/, bool prio);
virtual bool wheel_event (int delta, bool horizontal, const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool key_event (unsigned int key, unsigned int buttons);
+ virtual bool shortcut_override_event (unsigned int key, unsigned int buttons);
virtual void drag_cancel ();
virtual void deactivated ();
void show_toolbox (bool visible);
From cabcde3bf582534ddf7520b63c83774a36c62ab6 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 13 Jan 2026 10:08:57 +0100
Subject: [PATCH 13/36] [consider merging] Fixing strange snapping behavior on
partial move at 45 degree directions
---
src/edt/edt/edtPartialService.cc | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc
index ac480c732..d8e5d59cb 100644
--- a/src/edt/edt/edtPartialService.cc
+++ b/src/edt/edt/edtPartialService.cc
@@ -2430,7 +2430,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 ();
}
@@ -3006,14 +3006,7 @@ PartialService::do_selection_to_view ()
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 ()));
- }
+ move_trans = db::DTrans (m_current - m_start);
// display vector
view ()->message (std::string ("dx: ") + tl::micron_to_string (move_trans.disp ().x ()) +
From ee622fc10402bbfa5434281af156609fb59e4d01 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 13 Jan 2026 12:54:10 +0100
Subject: [PATCH 14/36] WIP
---
src/ant/ant/antService.cc | 7 ++++-
src/edt/edt/edtPartialService.cc | 2 ++
src/edt/edt/edtService.cc | 23 ++++++++------
src/img/img/imgService.cc | 1 +
src/laybasic/laybasic/layEditable.cc | 40 +++++++++++++++++++++--
src/laybasic/laybasic/layEditable.h | 47 +++++++++++++++++++++++++++-
src/laybasic/laybasic/layMove.cc | 38 +++++++++++++++++++++-
7 files changed, 144 insertions(+), 14 deletions(-)
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index 6f6c0e556..b7ead8384 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -1598,6 +1598,8 @@ 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 ();
+ bool indicate_ruler_as_message = true;
+
if (m_move_mode == MoveP1) {
m_current.seg_p1 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
@@ -1653,6 +1655,9 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
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);
+ indicate_ruler_as_message = false;
+
snap_rulers (ac_eff);
for (std::vector::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
@@ -1661,7 +1666,7 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
}
- if (m_move_mode != MoveSelected) {
+ if (indicate_ruler_as_message) {
show_message ();
}
}
diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc
index d8e5d59cb..d80a08bcd 100644
--- a/src/edt/edt/edtPartialService.cc
+++ b/src/edt/edt/edtPartialService.cc
@@ -2481,6 +2481,8 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
}
+ propose_move_transformation (db::DTrans (m_current - m_start), 0);
+
selection_to_view ();
m_alt_ac = lay::AC_Global;
diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc
index ededabe19..a044dd441 100644
--- a/src/edt/edt/edtService.cc
+++ b/src/edt/edt/edtService.cc
@@ -563,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;
}
@@ -579,15 +584,20 @@ 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;
}
@@ -1701,16 +1711,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) {
diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc
index 9e27d9449..ce0b06961 100644
--- a/src/img/img/imgService.cc
+++ b/src/img/img/imgService.cc
@@ -740,6 +740,7 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
m_p1 = p;
m_trans = db::DTrans (dp) * m_trans;
+ propose_move_transformation (m_trans, 2);
for (std::vector::iterator r = m_selected_image_views.begin (); r != m_selected_image_views.end (); ++r) {
(*r)->transform_by (db::DCplxTrans (m_trans));
diff --git a/src/laybasic/laybasic/layEditable.cc b/src/laybasic/laybasic/layEditable.cc
index 60fd18a19..49060757a 100644
--- a/src/laybasic/laybasic/layEditable.cc
+++ b/src/laybasic/laybasic/layEditable.cc
@@ -47,7 +47,7 @@ struct first_of_pair_cmp_f
// Editable implementation
Editable::Editable (lay::Editables *editables)
- : mp_editables (editables)
+ : mp_editables (editables), m_move_transformation_priority (-1)
{
if (editables) {
editables->m_editables.push_back (this);
@@ -75,6 +75,20 @@ Editable::~Editable ()
}
}
+void
+Editable::reset_proposed_move_transformation ()
+{
+ m_move_transformation = db::DTrans ();
+ m_move_transformation_priority = -1;
+}
+
+void
+Editable::propose_move_transformation (const db::DTrans &t, unsigned int priority)
+{
+ m_move_transformation = t;
+ m_move_transformation_priority = priority;
+}
+
// ----------------------------------------------------------------
// Editables implementation
@@ -490,6 +504,9 @@ Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
cancel_edits ();
clear_previous_selection ();
+ m_move_start = p;
+ m_move_transform = db::DFTrans ();
+
m_move_selection = false;
m_any_move_operation = false;
@@ -567,19 +584,38 @@ Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
}
}
-void
+std::pair
Editables::move (const db::DPoint &p, lay::angle_constraint_type ac)
{
+ int move_transformation_priority = -1;
+ db::DTrans move_transformation (p - m_move_start);
+ move_transformation *= db::DTrans (m_move_transform);
+
m_any_move_operation = true;
+
for (iterator e = begin (); e != end (); ++e) {
+
+ e->reset_proposed_move_transformation ();
+
e->move (p, ac);
+
+ auto pmv = e->proposed_move_transformation ();
+ if (move_transformation_priority < 0 || (pmv.first >= 0 && pmv.first <= move_transformation_priority)) {
+ move_transformation_priority = pmv.first;
+ move_transformation = pmv.second;
+ }
+
}
+
+ return std::make_pair (move_transformation_priority, move_transformation);
}
void
Editables::move_transform (const db::DPoint &p, db::DFTrans t, lay::angle_constraint_type ac)
{
m_any_move_operation = true;
+ m_move_transform *= t;
+
for (iterator e = begin (); e != end (); ++e) {
e->move_transform (p, t, ac);
}
diff --git a/src/laybasic/laybasic/layEditable.h b/src/laybasic/laybasic/layEditable.h
index cb696600c..9722e2ff3 100644
--- a/src/laybasic/laybasic/layEditable.h
+++ b/src/laybasic/laybasic/layEditable.h
@@ -405,13 +405,48 @@ class LAYBASIC_PUBLIC Editable
}
protected:
+ friend class lay::Editables;
+
Editables *editables ()
{
return mp_editables;
}
+ /**
+ * @brief Resets the proposed move transformation
+ *
+ * You should not need to call this method from an Editable implementation.
+ */
+ void reset_proposed_move_transformation ();
+
+ /**
+ * @brief Proposes a move transformation
+ *
+ * On "move", the Editable can propose an actual move transformation that
+ * may differ from the actual move distance due to implementation-specific
+ * snapping.
+ *
+ * This method proposes a move transformation with a given priority. The
+ * Editable with the lowest priority value wins.
+ */
+ void propose_move_transformation (const db::DTrans &mv, unsigned int priority);
+
+ /**
+ * @brief Gets the proposed move transformation and priority
+ *
+ * @return A pair with (priority, transformation)
+ *
+ * The returned priority is negative if not priority was set.
+ */
+ std::pair proposed_move_transformation () const
+ {
+ return std::make_pair (m_move_transformation_priority, m_move_transformation);
+ }
+
private:
Editables *mp_editables;
+ int m_move_transformation_priority;
+ db::DTrans m_move_transformation;
};
/**
@@ -551,8 +586,16 @@ class LAYBASIC_PUBLIC Editables
/**
* @brief Continue "move" operation
+ *
+ * The return value is the "proposed move transformation", i.e. a representative
+ * one used for the actual move. As every interface may decide about the
+ * actual move transformation (due to specific snapping to objects etc.), the
+ * return value many be ambiguous and should be used for information purposes
+ * only.
+ *
+ * @return A pair (priority, transformation) where priority is negative if no vector was proposed
*/
- void move (const db::DPoint &p, lay::angle_constraint_type ac);
+ std::pair move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Transform during a move operation
@@ -678,6 +721,8 @@ class LAYBASIC_PUBLIC Editables
tl::shared_collection m_editables;
std::set m_enabled;
+ db::DPoint m_move_start;
+ db::DFTrans m_move_transform;
bool m_move_selection;
bool m_any_move_operation;
db::DBox m_last_selected_point;
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index ae677b3ff..08310c798 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -180,7 +180,26 @@ MoveService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool p
if (m_dragging) {
set_cursor (lay::Cursor::size_all);
- mp_editables->move (p, ac_from_buttons (buttons));
+ auto pmv = mp_editables->move (p, ac_from_buttons (buttons));
+
+ // display the proposed move transformation
+ if (pmv.first >= 0) {
+
+ std::string pos = std::string ("dx: ") + tl::micron_to_string (pmv.second.disp ().x ()) + " dy: " + tl::micron_to_string (pmv.second.disp ().y ());
+ if (pmv.second.rot () != 0) {
+ pos += std::string (" ") + ((const db::DFTrans &) pmv.second).to_string ();
+ }
+ mp_view->message (pos);
+
+ lay::EditorOptionsPage *toolbox_widget = 0;
+ if (mp_view->editor_options_pages ()) {
+ toolbox_widget = mp_view->editor_options_pages ()->page_with_name (move_editor_options_name);
+ }
+ if (toolbox_widget) {
+ toolbox_widget->configure (move_distance_setter_name, pmv.second.disp ().to_string ());
+ }
+
+ }
} else if (prio) {
@@ -477,6 +496,23 @@ class MoveToolboxPage
}
}
+ virtual void configure (const std::string &name, const std::string &value)
+ {
+ if (name == move_distance_setter_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::to_string (mv.x ())));
+ mp_y_le->setText (tl::to_qstring (tl::to_string (mv.y ())));
+
+ } catch (...) {
+ }
+ }
+ }
+
virtual void cancel ()
{
tl::info << "@@@ Escape!";
From c2aa597022b6ec45a26a7ae2dfbec0b66f88ac11 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 13 Jan 2026 16:21:59 +0100
Subject: [PATCH 15/36] WIP
---
src/ant/ant/antService.cc | 7 ++++++
src/ant/ant/antService.h | 5 +++++
src/edt/edt/edtMoveTrackerService.cc | 7 ++++++
src/edt/edt/edtMoveTrackerService.h | 5 +++++
src/edt/edt/edtPartialService.cc | 11 +++++++---
src/edt/edt/edtPartialService.h | 5 +++++
src/edt/edt/edtService.cc | 19 +++++++++++++---
src/edt/edt/edtService.h | 5 +++++
src/img/img/imgService.cc | 9 +++++++-
src/img/img/imgService.h | 5 +++++
src/laybasic/laybasic/layEditable.cc | 33 +++++++++++++++++++++++++++-
src/laybasic/laybasic/layEditable.h | 20 +++++++++++++++++
src/laybasic/laybasic/layMove.cc | 29 +++++++++++++++---------
13 files changed, 142 insertions(+), 18 deletions(-)
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index b7ead8384..2a66becba 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -1681,6 +1681,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)
{
diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h
index 13086eeb4..f270ff914 100644
--- a/src/ant/ant/antService.h
+++ b/src/ant/ant/antService.h
@@ -347,6 +347,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)
*/
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 d80a08bcd..0e4210ff7 100644
--- a/src/edt/edt/edtPartialService.cc
+++ b/src/edt/edt/edtPartialService.cc
@@ -2489,14 +2489,19 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
}
void
-PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
+PartialService::end_move (const db::DVector &v)
+{
+ 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_dragging) {
return;
}
- m_alt_ac = ac;
-
if (m_current != m_start) {
// stop dragging
diff --git a/src/edt/edt/edtPartialService.h b/src/edt/edt/edtPartialService.h
index 594c73108..e124c2dda 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
*/
diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc
index a044dd441..7c546c220 100644
--- a/src/edt/edt/edtService.cc
+++ b/src/edt/edt/edtService.cc
@@ -601,16 +601,29 @@ Service::move_transform (const db::DPoint &pu, db::DFTrans tr, lay::angle_constr
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;
}
diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h
index 09bb56e96..814e4db93 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
*/
diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc
index ce0b06961..7d84f281b 100644
--- a/src/img/img/imgService.cc
+++ b/src/img/img/imgService.cc
@@ -872,7 +872,14 @@ Service::show_message ()
*/
}
-void
+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)
{
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..0d3d27092 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)
*/
diff --git a/src/laybasic/laybasic/layEditable.cc b/src/laybasic/laybasic/layEditable.cc
index 49060757a..1e532f800 100644
--- a/src/laybasic/laybasic/layEditable.cc
+++ b/src/laybasic/laybasic/layEditable.cc
@@ -621,7 +621,38 @@ Editables::move_transform (const db::DPoint &p, db::DFTrans t, lay::angle_constr
}
}
-void
+void
+Editables::end_move (const db::DVector &v, db::Transaction *transaction)
+{
+ std::unique_ptr trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (tr ("Move"))));
+
+ if (m_any_move_operation) {
+
+ trans_holder->open ();
+
+ // this dummy operation will update the screen:
+ if (manager ()) {
+ manager ()->queue (this, new db::Op ());
+ }
+
+ for (iterator e = begin (); e != end (); ++e) {
+ e->end_move (v);
+ }
+
+ // clear the selection that was set previously
+ if (m_move_selection) {
+ clear_selection ();
+ }
+
+ } else {
+
+ trans_holder->cancel ();
+ edit_cancel ();
+
+ }
+}
+
+void
Editables::end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction)
{
std::unique_ptr trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (tr ("Move"))));
diff --git a/src/laybasic/laybasic/layEditable.h b/src/laybasic/laybasic/layEditable.h
index 9722e2ff3..f57c1f141 100644
--- a/src/laybasic/laybasic/layEditable.h
+++ b/src/laybasic/laybasic/layEditable.h
@@ -326,6 +326,16 @@ class LAYBASIC_PUBLIC Editable
// .. by default, nothing is implemented ..
}
+ /**
+ * @brief Terminate a "move" operation with compulsory shift vector
+ *
+ * @param v The move distance to be applied
+ */
+ virtual void end_move (const db::DVector & /*v*/)
+ {
+ // .. by default, nothing is implemented ..
+ }
+
/**
* @brief Cancel any pending operations
*
@@ -610,6 +620,16 @@ class LAYBASIC_PUBLIC Editables
*/
void end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction = 0);
+ /**
+ * @brief End "move" operation with given vector
+ *
+ * If a transaction is given, the operation will be appended to this pending transaction
+ * The Editables object takes ownership over the Transaction object.
+ *
+ * The vector is supposed to be taken "as is" and no snapping shall be applied.
+ */
+ void end_move (const db::DVector &v, db::Transaction *transaction = 0);
+
/**
* @brief Indicates how many objects are selected.
*
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 08310c798..0adad09d3 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -91,12 +91,28 @@ void
MoveService::function (const std::string &name, const std::string &value)
{
if (name == move_function_name) {
+
try {
+
db::DVector s;
tl::from_string (value, s);
- tl::info << "@@@ move " << s.to_string ();
+
+ m_dragging = false;
+
+ show_toolbox (false);
+ ui ()->ungrab_mouse (this);
+
+ mp_editables->end_move (s, mp_transaction.release ());
+
+ if (m_dragging_transient) {
+ mp_editables->clear_selection ();
+ }
+
+ drag_cancel ();
+
} catch (...) {
}
+
}
}
@@ -481,8 +497,6 @@ class MoveToolboxPage
virtual void commit (lay::Dispatcher *dispatcher)
{
- tl::info << "@@@ Commit!";
-
try {
double dx = 0.0, dy = 0.0;
@@ -505,19 +519,14 @@ class MoveToolboxPage
db::DVector mv;
tl::from_string (value, mv);
- mp_x_le->setText (tl::to_qstring (tl::to_string (mv.x ())));
- mp_y_le->setText (tl::to_qstring (tl::to_string (mv.y ())));
+ 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 (...) {
}
}
}
- virtual void cancel ()
- {
- tl::info << "@@@ Escape!";
- }
-
private:
QHBoxLayout *mp_layout;
QLineEdit *mp_x_le, *mp_y_le;
From e058c47c0220734d3a09842a896e5c2fc4355830 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 13 Jan 2026 18:29:32 +0100
Subject: [PATCH 16/36] WIP
---
src/edt/edt/edtEditorOptionsPages.h | 1 +
src/edt/edt/edtRecentConfigurationPage.h | 2 +-
src/laybasic/laybasic/layEditorOptionsPage.cc | 134 ++------------
src/laybasic/laybasic/layEditorOptionsPage.h | 58 +++---
src/laybasic/laybasic/layMove.cc | 98 +---------
src/laybasic/laybasic/layMove.h | 4 +
src/layui/layui/layWidgets.cc | 87 ++++++---
src/layui/layui/layWidgets.h | 17 ++
.../layview/layEditorOptionsPageWidget.cc | 171 ++++++++++++++++++
.../layview/layEditorOptionsPageWidget.h | 70 +++++++
src/layview/layview/layEditorOptionsPages.cc | 1 +
src/layview/layview/layLayoutView_qt.cc | 1 +
.../layview/layMoveEditorOptionsPage.cc | 117 ++++++++++++
.../layview/layMoveEditorOptionsPage.h | 59 ++++++
src/layview/layview/layview.pro | 4 +
15 files changed, 561 insertions(+), 263 deletions(-)
create mode 100644 src/layview/layview/layEditorOptionsPageWidget.cc
create mode 100644 src/layview/layview/layEditorOptionsPageWidget.h
create mode 100644 src/layview/layview/layMoveEditorOptionsPage.cc
create mode 100644 src/layview/layview/layMoveEditorOptionsPage.h
diff --git a/src/edt/edt/edtEditorOptionsPages.h b/src/edt/edt/edtEditorOptionsPages.h
index 5080c2dfe..c2056e2c9 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
diff --git a/src/edt/edt/edtRecentConfigurationPage.h b/src/edt/edt/edtRecentConfigurationPage.h
index dd6ff0e96..5e53d2ec6 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"
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index 739f27c07..c3955809d 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -23,14 +23,28 @@
#include "tlInternational.h"
#include "layEditorOptionsPage.h"
#include "layLayoutViewBase.h"
+#include "tlClassRegistry.h"
#include "tlExceptions.h"
-#include
-#include
-
namespace lay
{
+// ------------------------------------------------------------------
+// EditorOptionsFactoryBase implementation
+
+lay::EditorOptionsPage *
+EditorOptionsPageFactoryBase::create_page_by_name (const std::string &name, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+{
+ auto reg = tl::Registrar::get_instance ();
+ for (auto i = reg->begin (); i != reg->end (); ++i) {
+ if (i.current_name () == name) {
+ return i->create_page (view, dispatcher);
+ }
+ }
+
+ return 0;
+}
+
// ------------------------------------------------------------------
// EditorOptionsPageCollection implementation
@@ -136,119 +150,5 @@ EditorOptionsPage::activate (bool active)
}
}
-#if defined(HAVE_QT)
-
-// ------------------------------------------------------------------
-// EditorOptionsPage implementation
-
-EditorOptionsPageWidget::EditorOptionsPageWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : QWidget (0), EditorOptionsPage (view, dispatcher)
-{
- init (view, dispatcher);
-}
-
-EditorOptionsPageWidget::EditorOptionsPageWidget ()
- : QWidget (0), EditorOptionsPage ()
-{
- // .. nothing yet ..
-}
-
-EditorOptionsPageWidget::~EditorOptionsPageWidget ()
-{
- set_owner (0);
-}
-
-void
-EditorOptionsPageWidget::edited ()
-{
- apply (dispatcher ());
-}
-
-static bool is_parent_widget (QWidget *w, QWidget *parent)
-{
- while (w && w != parent) {
- w = dynamic_cast (w->parent ());
- }
- return w == parent;
-}
-
-bool
-EditorOptionsPageWidget::focusNextPrevChild (bool next)
-{
- bool res = QWidget::focusNextPrevChild (next);
-
- // Stop making the focus leave the page - this way we can jump back to the
- // view on "enter"
- if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
- focusWidget ()->setFocus ();
- }
-
- return res;
-}
-
-void
-EditorOptionsPageWidget::keyPressEvent (QKeyEvent *event)
-{
-BEGIN_PROTECTED
- if (! is_modal_page () &&
- event->modifiers () == Qt::NoModifier &&
- (event->key () == Qt::Key_Return || event->key () == Qt::Key_Enter || event->key () == Qt::Key_Escape)) {
- if (event->key () == Qt::Key_Escape) {
- // The Escape key creates a call to cancel()
- cancel ();
- } else {
- // The Return key on a non-modal page commits the values and gives back the focus
- // to the view
- commit (dispatcher ());
- }
- view ()->set_focus ();
- event->accept ();
- } else {
- QWidget::keyPressEvent (event);
- }
-END_PROTECTED
-}
-
-bool
-EditorOptionsPageWidget::event (QEvent *event)
-{
- if (event->type () == QEvent::ShortcutOverride) {
- QKeyEvent *ke = dynamic_cast (event);
- if (ke->key () == Qt::Key_Escape ||
- ke->key () == Qt::Key_Tab ||
- ke->key () == Qt::Key_Enter ||
- ke->key () == Qt::Key_Return ||
- ke->key () == Qt::Key_Backtab) {
- // accept the shortcut override event for some keys, so we can handle
- // it in keyPressEvent
- ke->accept ();
- }
- }
- return QWidget::event (event);
-}
-
-void
-EditorOptionsPageWidget::set_focus ()
-{
- if (isVisible ()) {
- setFocus (Qt::TabFocusReason);
- QWidget::focusNextPrevChild (true);
- }
-}
-
-void
-EditorOptionsPageWidget::set_visible (bool visible)
-{
- setVisible (visible);
-}
-
-bool
-EditorOptionsPageWidget::is_visible () const
-{
- return isVisible ();
-}
-
-#endif
-
}
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h
index f1d1fa12d..1b0e604a2 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.h
+++ b/src/laybasic/laybasic/layEditorOptionsPage.h
@@ -27,10 +27,6 @@
#include "tlObject.h"
-#if defined(HAVE_QT)
-# include
-#endif
-
namespace db
{
struct LayerProperties;
@@ -149,34 +145,48 @@ class LAYBASIC_PUBLIC EditorOptionsPage
void attach_events ();
};
-#if defined(HAVE_QT)
/**
- * @brief The base class for a object properties page
+ * @brief A basic factory class for editor options pages
+ *
+ * We will use it later to provide a registration-based specialized factory
+ * for Qt-enabled option pages, which we should not link here.
*/
-class LAYBASIC_PUBLIC EditorOptionsPageWidget
- : public QWidget, public EditorOptionsPage
+class LAYBASIC_PUBLIC EditorOptionsPageFactoryBase
{
-Q_OBJECT
-
public:
- EditorOptionsPageWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
- EditorOptionsPageWidget ();
- virtual ~EditorOptionsPageWidget ();
+ EditorOptionsPageFactoryBase () { }
+ virtual ~EditorOptionsPageFactoryBase () { }
- virtual void set_focus ();
- virtual bool is_visible () const;
- virtual void set_visible (bool visible);
- virtual EditorOptionsPageWidget *widget () { return this; }
+ virtual lay::EditorOptionsPage *create_page (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) = 0;
-protected slots:
- void edited ();
+ static lay::EditorOptionsPage *create_page_by_name (const std::string &name, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+};
-protected:
- virtual bool focusNextPrevChild (bool next);
- virtual void keyPressEvent (QKeyEvent *event);
- virtual bool event (QEvent *event);
+/**
+ * @brief A specialized editor options page factory class for a specific type
+ *
+ * Register the factory using:
+ *
+ * #include "tlClassRegistry.h"
+ * static tl::RegisteredClass s_factory (new lay::EditorOptionsPageFactory (), 0, "MyClass");
+ *
+ * Later you can create a page from "MyName" using
+ *
+ * page = EditorOptionsPageFactoryBase::create_page_by_name ("MyClass", view, dispatcher);
+ */
+template
+class LAYBASIC_PUBLIC_TEMPLATE EditorOptionsPageFactory
+ : public EditorOptionsPageFactoryBase
+{
+public:
+ EditorOptionsPageFactory () { }
+ virtual ~EditorOptionsPageFactory () { }
+
+ virtual lay::EditorOptionsPage *create_page (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ {
+ return new T (view, dispatcher);
+ }
};
-#endif // defined(HAVE_QT)
}
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 0adad09d3..56087a660 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -37,9 +37,9 @@
namespace lay
{
-const std::string move_editor_options_name ("move-editor-options");
-const std::string move_function_name ("move-execute");
-const std::string move_distance_setter_name ("move-distance");
+LAYBASIC_PUBLIC std::string move_editor_options_name ("move-editor-options");
+LAYBASIC_PUBLIC std::string move_function_name ("move-execute");
+LAYBASIC_PUBLIC std::string move_distance_setter_name ("move-distance");
// -------------------------------------------------------------
// MoveService implementation
@@ -451,90 +451,6 @@ MoveService::finish ()
// ----------------------------------------------------------------------------
-#if defined(HAVE_QT)
-namespace {
-
-class MoveToolboxPage
- : public lay::EditorOptionsPageWidget
-{
-public:
- MoveToolboxPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
- : lay::EditorOptionsPageWidget (view, dispatcher)
- {
- mp_layout = new QHBoxLayout (this);
-
- mp_x_le = new QLineEdit (this);
- mp_layout->addWidget (mp_x_le);
- mp_y_le = new QLineEdit (this);
- mp_layout->addWidget (mp_y_le);
- mp_layout->addStretch (1);
-
- hide ();
-
- set_focus_page (true);
- set_toolbox_widget (true);
- }
-
- virtual std::string title () const
- {
- return "Move Options";
- }
-
- virtual const char *name () const
- {
- return move_editor_options_name.c_str ();
- }
-
- virtual int order () const
- {
- return 0;
- }
-
- virtual void deactivated ()
- {
- hide ();
- }
-
- virtual void 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 (move_function_name, db::DVector (dx, dy).to_string ());
-
- } catch (...) {
- }
- }
-
- virtual void configure (const std::string &name, const std::string &value)
- {
- if (name == move_distance_setter_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 (...) {
- }
- }
- }
-
-private:
- QHBoxLayout *mp_layout;
- QLineEdit *mp_x_le, *mp_y_le;
-};
-
-}
-#endif
-
class MoveServiceDeclaration
: public lay::PluginDeclaration
{
@@ -550,13 +466,13 @@ class MoveServiceDeclaration
return new MoveService (view);
}
-#if defined(HAVE_QT)
virtual void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
{
- pages.push_back (new MoveToolboxPage (view, dispatcher));
- pages.back ()->set_plugin_declaration (this);
+ lay::EditorOptionsPage *page = lay::EditorOptionsPageFactoryBase::create_page_by_name (move_editor_options_name, view, dispatcher);
+ if (page) {
+ pages.push_back (page);
+ }
}
-#endif
};
static tl::RegisteredClass move_service_decl (new MoveServiceDeclaration (), -970, "laybasic::MoveServicePlugin");
diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h
index b487a22d8..b2c08f306 100644
--- a/src/laybasic/laybasic/layMove.h
+++ b/src/laybasic/laybasic/layMove.h
@@ -31,6 +31,10 @@
namespace lay {
+LAYBASIC_PUBLIC extern std::string move_editor_options_name;
+LAYBASIC_PUBLIC extern std::string move_function_name;
+LAYBASIC_PUBLIC extern std::string move_distance_setter_name;
+
class LayoutViewBase;
class LAYBASIC_PUBLIC MoveService :
diff --git a/src/layui/layui/layWidgets.cc b/src/layui/layui/layWidgets.cc
index d05eeef6b..e2264921e 100644
--- a/src/layui/layui/layWidgets.cc
+++ b/src/layui/layui/layWidgets.cc
@@ -1473,6 +1473,9 @@ DecoratedLineEdit::DecoratedLineEdit (QWidget *parent)
mp_clear_label->setCursor (Qt::ArrowCursor);
mp_clear_label->setPixmap (QString::fromUtf8 (":/clear_edit_16px@2x.png"));
+ mp_front_label = new QLabel (this);
+ mp_front_label->hide ();
+
QMargins margins = textMargins ();
m_default_left_margin = margins.left ();
m_default_right_margin = margins.right ();
@@ -1535,43 +1538,57 @@ bool DecoratedLineEdit::focusNextPrevChild (bool next)
return QLineEdit::focusNextPrevChild (next);
}
-void DecoratedLineEdit::set_clear_button_enabled (bool en)
+void DecoratedLineEdit::set_margins ()
{
- if (en != m_clear_button_enabled) {
+ int right_margin = m_default_right_margin;
+ int left_margin = m_default_left_margin;
- m_clear_button_enabled = en;
- mp_clear_label->setVisible (en);
+ // right parts
+ if (m_clear_button_enabled) {
+ right_margin += mp_clear_label->sizeHint ().width () + le_decoration_space;
+ }
- QMargins margins = textMargins ();
- if (! en) {
- margins.setRight (m_default_right_margin);
- } else {
- margins.setRight (m_default_right_margin + mp_clear_label->sizeHint ().width () + le_decoration_space);
- }
- setTextMargins (margins);
+ // left parts
+ if (! m_label.empty ()) {
+ left_margin += mp_front_label->sizeHint ().width () + le_decoration_space;
+ }
+ if (m_options_button_enabled) {
+ left_margin += mp_options_label->sizeHint ().width () + le_decoration_space;
+ }
- resizeEvent (0);
+ QMargins margins = textMargins ();
+ margins.setRight (right_margin);
+ margins.setLeft (left_margin);
+ setTextMargins (margins);
+
+ resizeEvent (0);
+}
+void DecoratedLineEdit::set_clear_button_enabled (bool en)
+{
+ if (en != m_clear_button_enabled) {
+ m_clear_button_enabled = en;
+ mp_clear_label->setVisible (en);
+ set_margins ();
}
}
void DecoratedLineEdit::set_options_button_enabled (bool en)
{
if (en != m_options_button_enabled) {
-
m_options_button_enabled = en;
mp_options_label->setVisible (en);
+ set_margins ();
+ }
+}
- QMargins margins = textMargins ();
- if (! en) {
- margins.setLeft (m_default_left_margin);
- } else {
- margins.setLeft (m_default_left_margin + mp_options_label->sizeHint ().width () + le_decoration_space);
- }
- setTextMargins (margins);
-
- resizeEvent (0);
-
+void DecoratedLineEdit::set_label (const std::string &label)
+{
+ if (label != m_label) {
+ m_label = label;
+ mp_front_label->setVisible (! label.empty ());
+ mp_front_label->setText (tl::to_qstring (label));
+ set_margins ();
}
}
@@ -1621,17 +1638,27 @@ void DecoratedLineEdit::mousePressEvent (QMouseEvent *event)
void DecoratedLineEdit::resizeEvent (QResizeEvent *event)
{
int fw = hasFrame () ? le_frame_width : 0;
+ QRect r = geometry ();
- if (m_clear_button_enabled) {
- QSize label_size = mp_clear_label->sizeHint ();
- QRect r = geometry ();
- mp_clear_label->setGeometry (r.width () - fw - label_size.width (), 0, label_size.width (), r.height ());
- }
+ int left = fw, right = r.width () - fw;
if (m_options_button_enabled) {
QSize label_size = mp_options_label->sizeHint ();
- QRect r = geometry ();
- mp_options_label->setGeometry (fw, 0, label_size.width (), r.height ());
+ mp_options_label->setGeometry (left, 0, label_size.width (), r.height ());
+ left += label_size.width () + le_decoration_space;
+ }
+
+ if (! m_label.empty ()) {
+ QSize label_size = mp_front_label->sizeHint ();
+ mp_front_label->setGeometry (left, 0, label_size.width (), r.height ());
+ left += label_size.width () + le_decoration_space;
+ }
+
+ if (m_clear_button_enabled) {
+ QSize label_size = mp_clear_label->sizeHint ();
+ right -= label_size.width ();
+ mp_clear_label->setGeometry (right, 0, label_size.width (), r.height ());
+ right -= le_decoration_space;
}
QLineEdit::resizeEvent (event);
diff --git a/src/layui/layui/layWidgets.h b/src/layui/layui/layWidgets.h
index ccba0d32c..f3e667020 100644
--- a/src/layui/layui/layWidgets.h
+++ b/src/layui/layui/layWidgets.h
@@ -566,6 +566,19 @@ Q_OBJECT
return m_tab_signal_enabled;
}
+ /**
+ * @brief Sets a label in front of the line edit
+ */
+ void set_label (const std::string &label);
+
+ /**
+ * @brief Gets the label
+ */
+ const std::string &label () const
+ {
+ return m_label;
+ }
+
signals:
void options_button_clicked ();
void esc_pressed ();
@@ -588,8 +601,12 @@ Q_OBJECT
bool m_tab_signal_enabled;
QLabel *mp_options_label;
QLabel *mp_clear_label;
+ QLabel *mp_front_label;
QMenu *mp_options_menu;
int m_default_left_margin, m_default_right_margin;
+ std::string m_label;
+
+ void set_margins ();
};
/**
diff --git a/src/layview/layview/layEditorOptionsPageWidget.cc b/src/layview/layview/layEditorOptionsPageWidget.cc
new file mode 100644
index 000000000..34914c61c
--- /dev/null
+++ b/src/layview/layview/layEditorOptionsPageWidget.cc
@@ -0,0 +1,171 @@
+
+/*
+
+ 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
+
+*/
+
+#include "layEditorOptionsPageWidget.h"
+#include "layLayoutViewBase.h"
+#include "tlExceptions.h"
+
+#include
+#include
+
+namespace lay
+{
+
+// ------------------------------------------------------------------
+// EditorOptionsPageWidget implementation
+
+EditorOptionsPageWidget::EditorOptionsPageWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+ : QWidget (0), EditorOptionsPage (view, dispatcher), m_is_transparent (false)
+{
+ init (view, dispatcher);
+}
+
+EditorOptionsPageWidget::EditorOptionsPageWidget ()
+ : QWidget (0), EditorOptionsPage ()
+{
+ // .. nothing yet ..
+}
+
+EditorOptionsPageWidget::~EditorOptionsPageWidget ()
+{
+ set_owner (0);
+}
+
+void
+EditorOptionsPageWidget::edited ()
+{
+ apply (dispatcher ());
+}
+
+static bool is_parent_widget (QWidget *w, QWidget *parent)
+{
+ while (w && w != parent) {
+ w = dynamic_cast (w->parent ());
+ }
+ return w == parent;
+}
+
+bool
+EditorOptionsPageWidget::focusNextPrevChild (bool next)
+{
+ bool res = QWidget::focusNextPrevChild (next);
+
+ // Stop making the focus leave the page - this way we can jump back to the
+ // view on "enter"
+ if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
+ focusWidget ()->setFocus ();
+ }
+
+ return res;
+}
+
+void
+EditorOptionsPageWidget::keyPressEvent (QKeyEvent *event)
+{
+BEGIN_PROTECTED
+ if (! is_modal_page () &&
+ event->modifiers () == Qt::NoModifier &&
+ (event->key () == Qt::Key_Return || event->key () == Qt::Key_Enter || event->key () == Qt::Key_Escape)) {
+ if (event->key () == Qt::Key_Escape) {
+ // The Escape key creates a call to cancel()
+ cancel ();
+ } else {
+ // The Return key on a non-modal page commits the values and gives back the focus
+ // to the view
+ commit (dispatcher ());
+ }
+ view ()->set_focus ();
+ event->accept ();
+ } else {
+ QWidget::keyPressEvent (event);
+ }
+END_PROTECTED
+}
+
+bool
+EditorOptionsPageWidget::event (QEvent *event)
+{
+ if (event->type () == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = dynamic_cast (event);
+ if (ke->key () == Qt::Key_Escape ||
+ ke->key () == Qt::Key_Tab ||
+ ke->key () == Qt::Key_Enter ||
+ ke->key () == Qt::Key_Return ||
+ ke->key () == Qt::Key_Backtab) {
+ // accept the shortcut override event for some keys, so we can handle
+ // it in keyPressEvent
+ ke->accept ();
+ }
+ }
+ return QWidget::event (event);
+}
+
+void
+EditorOptionsPageWidget::resizeEvent (QResizeEvent *e)
+{
+ // makes the widget transparent
+ // see https://stackoverflow.com/questions/27855137/how-to-disable-the-delivery-of-mouse-events-to-the-widget-but-not-its-children-i
+ if (e) {
+ QWidget::resizeEvent (e);
+ }
+
+ if (m_is_transparent) {
+ QRegion reg (frameGeometry ());
+ reg -= QRegion (geometry ());
+ reg += childrenRegion ();
+ setMask (reg);
+ } else {
+ clearMask ();
+ }
+}
+
+void
+EditorOptionsPageWidget::set_transparent (bool f)
+{
+ if (f != m_is_transparent) {
+ m_is_transparent = f;
+ resizeEvent (0);
+ }
+}
+
+void
+EditorOptionsPageWidget::set_focus ()
+{
+ if (isVisible ()) {
+ setFocus (Qt::TabFocusReason);
+ QWidget::focusNextPrevChild (true);
+ }
+}
+
+void
+EditorOptionsPageWidget::set_visible (bool visible)
+{
+ setVisible (visible);
+}
+
+bool
+EditorOptionsPageWidget::is_visible () const
+{
+ return isVisible ();
+}
+
+}
diff --git a/src/layview/layview/layEditorOptionsPageWidget.h b/src/layview/layview/layEditorOptionsPageWidget.h
new file mode 100644
index 000000000..65c7bd314
--- /dev/null
+++ b/src/layview/layview/layEditorOptionsPageWidget.h
@@ -0,0 +1,70 @@
+
+/*
+
+ 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
+
+*/
+
+#ifndef HDR_layEditorOptionsPageWidget
+#define HDR_layEditorOptionsPageWidget
+
+#include
+
+#include "layviewCommon.h"
+#include "layEditorOptionsPage.h"
+
+namespace lay
+{
+
+/**
+ * @brief The base class for a object properties page
+ */
+class LAYVIEW_PUBLIC EditorOptionsPageWidget
+ : public QWidget, public EditorOptionsPage
+{
+Q_OBJECT
+
+public:
+ EditorOptionsPageWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+ EditorOptionsPageWidget ();
+ virtual ~EditorOptionsPageWidget ();
+
+ virtual void set_focus ();
+ virtual bool is_visible () const;
+ virtual void set_visible (bool visible);
+ virtual EditorOptionsPageWidget *widget () { return this; }
+
+ void set_transparent (bool f);
+ bool is_transparent () const { return m_is_transparent; }
+
+protected slots:
+ void edited ();
+
+protected:
+ virtual bool focusNextPrevChild (bool next);
+ virtual void keyPressEvent (QKeyEvent *event);
+ virtual void resizeEvent (QResizeEvent *e);
+ virtual bool event (QEvent *event);
+
+ bool m_is_transparent;
+};
+
+}
+
+#endif
+
diff --git a/src/layview/layview/layEditorOptionsPages.cc b/src/layview/layview/layEditorOptionsPages.cc
index a36190106..4c33c1c83 100644
--- a/src/layview/layview/layEditorOptionsPages.cc
+++ b/src/layview/layview/layEditorOptionsPages.cc
@@ -22,6 +22,7 @@
#include "tlInternational.h"
#include "layEditorOptionsPages.h"
+#include "layEditorOptionsPageWidget.h"
#include "tlExceptions.h"
#include "layPlugin.h"
#include "layLayoutViewBase.h"
diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc
index d1f43c998..894da7c33 100644
--- a/src/layview/layview/layLayoutView_qt.cc
+++ b/src/layview/layview/layLayoutView_qt.cc
@@ -76,6 +76,7 @@
#include "layBookmarksView.h"
#include "layEditorOptionsFrame.h"
#include "layEditorOptionsPages.h"
+#include "layEditorOptionsPageWidget.h"
#include "layUtils.h"
#include "layPropertiesDialog.h"
#include "layQtTools.h"
diff --git a/src/layview/layview/layMoveEditorOptionsPage.cc b/src/layview/layview/layMoveEditorOptionsPage.cc
new file mode 100644
index 000000000..7b79ba97f
--- /dev/null
+++ b/src/layview/layview/layMoveEditorOptionsPage.cc
@@ -0,0 +1,117 @@
+
+/*
+
+ 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
+
+*/
+
+#include "layMoveEditorOptionsPage.h"
+#include "layWidgets.h"
+#include "layDispatcher.h"
+
+#include
+#include
+
+namespace lay
+{
+
+MoveEditorOptionsPage::MoveEditorOptionsPage (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_layout->addStretch (1);
+
+ hide ();
+
+ set_focus_page (true);
+ set_toolbox_widget (true);
+ set_transparent (true);
+}
+
+std::string
+MoveEditorOptionsPage::title () const
+{
+ return "Move Options";
+}
+
+const char *
+MoveEditorOptionsPage::name () const
+{
+ return move_editor_options_name.c_str ();
+}
+
+int
+MoveEditorOptionsPage::order () const
+{
+ return 0;
+}
+
+void
+MoveEditorOptionsPage::deactivated ()
+{
+ hide ();
+}
+
+void
+MoveEditorOptionsPage::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 (move_function_name, db::DVector (dx, dy).to_string ());
+
+ } catch (...) {
+ }
+}
+
+void
+MoveEditorOptionsPage::configure (const std::string &name, const std::string &value)
+{
+ if (name == move_distance_setter_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 (...) {
+ }
+
+ }
+}
+
+// registers the factory for the move plugin
+static tl::RegisteredClass s_factory (new lay::EditorOptionsPageFactory (), 0, move_editor_options_name.c_str ());
+
+}
diff --git a/src/layview/layview/layMoveEditorOptionsPage.h b/src/layview/layview/layMoveEditorOptionsPage.h
new file mode 100644
index 000000000..21bf6f28c
--- /dev/null
+++ b/src/layview/layview/layMoveEditorOptionsPage.h
@@ -0,0 +1,59 @@
+
+/*
+
+ 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
+
+*/
+
+#ifndef HDR_layMoveEditorOptionsPage
+#define HDR_layMoveEditorOptionsPage
+
+#include "layviewCommon.h"
+#include "layEditorOptionsPageWidget.h"
+#include "layMove.h"
+
+class QHBoxLayout;
+
+namespace lay {
+ class DecoratedLineEdit;
+}
+
+namespace lay {
+
+class MoveEditorOptionsPage
+ : public lay::EditorOptionsPageWidget
+{
+public:
+ MoveEditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+
+ virtual std::string title () const;
+ virtual const char *name () const;
+ virtual int order () const;
+ virtual void deactivated ();
+ virtual void commit (lay::Dispatcher *dispatcher);
+ virtual void configure (const std::string &name, const std::string &value);
+
+private:
+ QHBoxLayout *mp_layout;
+ lay::DecoratedLineEdit *mp_x_le, *mp_y_le;
+};
+
+}
+
+#endif
+
diff --git a/src/layview/layview/layview.pro b/src/layview/layview/layview.pro
index 3d5ab457a..3d20f19e6 100644
--- a/src/layview/layview/layview.pro
+++ b/src/layview/layview/layview.pro
@@ -9,17 +9,21 @@ DEFINES += MAKE_LAYVIEW_LIBRARY
RESOURCES = \
SOURCES = \
+ layEditorOptionsPageWidget.cc \
layGridNet.cc \
layEditorOptionsFrame.cc \
layEditorOptionsPages.cc \
+ layMoveEditorOptionsPage.cc \
layviewForceLink.cc \
gsiDeclLayAdditional.cc \
HEADERS = \
+ layEditorOptionsPageWidget.h \
layGridNet.h \
layEditorOptionsFrame.h \
layEditorOptionsPages.h \
layLayoutView.h \
+ layMoveEditorOptionsPage.h \
layviewForceLink.h \
!equals(HAVE_QT, "0") {
From cca73a8ebbf73fd6e86deace6ee9406d009305b7 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 14 Jan 2026 00:27:53 +0100
Subject: [PATCH 17/36] WIP, some refactoring and bug fixing. Move toolkit
widget works
---
src/laybasic/laybasic/layMove.cc | 1 +
src/laybasic/laybasic/laybasic.pro | 4 ----
.../laybasic => layview/layview}/gsiDeclLayConfigPage.cc | 0
.../laybasic => layview/layview}/gsiDeclLayConfigPage.h | 0
.../layview}/gsiDeclLayEditorOptionsPage.cc | 2 +-
.../layview}/gsiDeclLayEditorOptionsPage.h | 4 ++--
src/layview/layview/layEditorOptionsPages.cc | 3 ++-
src/layview/layview/layview.pro | 4 ++++
8 files changed, 10 insertions(+), 8 deletions(-)
rename src/{laybasic/laybasic => layview/layview}/gsiDeclLayConfigPage.cc (100%)
rename src/{laybasic/laybasic => layview/layview}/gsiDeclLayConfigPage.h (100%)
rename src/{laybasic/laybasic => layview/layview}/gsiDeclLayEditorOptionsPage.cc (98%)
rename src/{laybasic/laybasic => layview/layview}/gsiDeclLayEditorOptionsPage.h (94%)
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 56087a660..5b759162c 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -470,6 +470,7 @@ class MoveServiceDeclaration
{
lay::EditorOptionsPage *page = lay::EditorOptionsPageFactoryBase::create_page_by_name (move_editor_options_name, view, dispatcher);
if (page) {
+ page->set_plugin_declaration (this);
pages.push_back (page);
}
}
diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro
index 85c921ff0..7a870fa69 100644
--- a/src/laybasic/laybasic/laybasic.pro
+++ b/src/laybasic/laybasic/laybasic.pro
@@ -36,8 +36,6 @@ SOURCES += \
gsiDeclLayTextInfo.cc \
gsiDeclLayTlAdded.cc \
gsiDeclLayRdbAdded.cc \
- gsiDeclLayConfigPage.cc \
- gsiDeclLayEditorOptionsPage.cc \
gsiDeclLayPlugin.cc \
gsiDeclLayPluginFactory.cc \
layAbstractMenu.cc \
@@ -95,8 +93,6 @@ SOURCES += \
layUtils.cc \
HEADERS += \
- gsiDeclLayConfigPage.h \
- gsiDeclLayEditorOptionsPage.h \
gsiDeclLayPlugin.h \
layEditorOptionsPage.h \
layEditorUtils.h \
diff --git a/src/laybasic/laybasic/gsiDeclLayConfigPage.cc b/src/layview/layview/gsiDeclLayConfigPage.cc
similarity index 100%
rename from src/laybasic/laybasic/gsiDeclLayConfigPage.cc
rename to src/layview/layview/gsiDeclLayConfigPage.cc
diff --git a/src/laybasic/laybasic/gsiDeclLayConfigPage.h b/src/layview/layview/gsiDeclLayConfigPage.h
similarity index 100%
rename from src/laybasic/laybasic/gsiDeclLayConfigPage.h
rename to src/layview/layview/gsiDeclLayConfigPage.h
diff --git a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc b/src/layview/layview/gsiDeclLayEditorOptionsPage.cc
similarity index 98%
rename from src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
rename to src/layview/layview/gsiDeclLayEditorOptionsPage.cc
index de8619a37..112bb5444 100644
--- a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.cc
+++ b/src/layview/layview/gsiDeclLayEditorOptionsPage.cc
@@ -30,7 +30,7 @@
namespace gsi
{
-Class decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWidget) "lay", "EditorOptionsPageBase",
+Class decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWidget) "lay", "EditorOptionsPageBase",
method ("view", &lay::EditorOptionsPage::view,
"@brief Gets the view object this page is associated with\n"
) +
diff --git a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h b/src/layview/layview/gsiDeclLayEditorOptionsPage.h
similarity index 94%
rename from src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
rename to src/layview/layview/gsiDeclLayEditorOptionsPage.h
index 8a8ee1b84..972e27070 100644
--- a/src/laybasic/laybasic/gsiDeclLayEditorOptionsPage.h
+++ b/src/layview/layview/gsiDeclLayEditorOptionsPage.h
@@ -28,14 +28,14 @@
#include "gsiDecl.h"
#include "gsiDeclBasic.h"
-#include "layEditorOptionsPage.h"
+#include "layEditorOptionsPageWidget.h"
#include "layLayoutViewBase.h"
namespace gsi
{
class EditorOptionsPageImpl
- : public lay::EditorOptionsPage, public gsi::ObjectBase
+ : public lay::EditorOptionsPageWidget, public gsi::ObjectBase
{
public:
EditorOptionsPageImpl (const std::string &title, int index);
diff --git a/src/layview/layview/layEditorOptionsPages.cc b/src/layview/layview/layEditorOptionsPages.cc
index 4c33c1c83..48eca6d81 100644
--- a/src/layview/layview/layEditorOptionsPages.cc
+++ b/src/layview/layview/layEditorOptionsPages.cc
@@ -98,7 +98,8 @@ EditorOptionsPages::editor_options_pages (const lay::PluginDeclaration *plugin_d
{
std::vector pages;
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
- if (p->plugin_declaration () == plugin_declaration) {
+ if (p->plugin_declaration () == plugin_declaration ||
+ (p->plugin_declaration () == 0 && plugin_declaration->enable_catchall_editor_options_pages ())) {
pages.push_back (const_cast (p.operator-> ()));
}
}
diff --git a/src/layview/layview/layview.pro b/src/layview/layview/layview.pro
index 3d20f19e6..0a450c59c 100644
--- a/src/layview/layview/layview.pro
+++ b/src/layview/layview/layview.pro
@@ -9,6 +9,8 @@ DEFINES += MAKE_LAYVIEW_LIBRARY
RESOURCES = \
SOURCES = \
+ gsiDeclLayEditorOptionsPage.cc \
+ gsiDeclLayConfigPage.cc \
layEditorOptionsPageWidget.cc \
layGridNet.cc \
layEditorOptionsFrame.cc \
@@ -18,6 +20,8 @@ SOURCES = \
gsiDeclLayAdditional.cc \
HEADERS = \
+ gsiDeclLayEditorOptionsPage.h \
+ gsiDeclLayConfigPage.h \
layEditorOptionsPageWidget.h \
layGridNet.h \
layEditorOptionsFrame.h \
From 6666b2b68cf257967a6681fca56aeac1394a122e Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 14 Jan 2026 02:37:26 +0100
Subject: [PATCH 18/36] Implementing 'diagonal only' for rulers
---
src/ant/ant/RulerConfigPage3.ui | 20 +--
src/ant/ant/RulerConfigPage4.ui | 5 +
src/ant/ant/antConfig.cc | 41 ------
src/ant/ant/antConfig.h | 6 -
src/ant/ant/antConfigPage.cc | 8 +-
src/ant/ant/antObject.cc | 5 +-
src/ant/ant/antPlugin.cc | 2 +-
src/ant/ant/antService.cc | 2 +-
src/ant/ant/antTemplate.cc | 5 +-
src/ant/ant/gsiDeclAnt.cc | 6 +
src/edt/edt/edtPartialService.cc | 145 ++++++++++------------
src/edt/edt/edtPartialService.h | 2 +-
src/laybasic/laybasic/gsiDeclLayPlugin.cc | 4 +
src/laybasic/laybasic/layConverters.cc | 16 +++
14 files changed, 127 insertions(+), 140 deletions(-)
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 @@
0
0
665
- 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_rb
ruler_diag_rb
ruler_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/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/antObject.cc b/src/ant/ant/antObject.cc
index 9ce86eed3..de4af2cee 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"
@@ -713,7 +714,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 +818,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 2a66becba..188b092f0 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -1134,7 +1134,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) {
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/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc
index 0e4210ff7..260eb0f81 100644
--- a/src/edt/edt/edtPartialService.cc
+++ b/src/edt/edt/edtPartialService.cc
@@ -1406,15 +1406,6 @@ PartialService::snap (const db::DVector &v_org) const
}
}
-const int sr_pixels = 8; // TODO: make variable
-
-lay::PointSnapToObjectResult
-PartialService::snap2 (const db::DPoint &p) const
-{
- double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
- return lay::obj_snap (m_snap_to_objects ? view () : 0, m_start, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, move_ac (), snap_range);
-}
-
void
PartialService::transform (const db::DCplxTrans &tr)
{
@@ -1790,68 +1781,90 @@ 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 {
+
+ // snap movement to angle and grid without object
+ m_current = m_start + snap_move (p - m_start);
+
+ }
+
+ selection_to_view ();
+}
+
+bool
+PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
+{
+ clear_mouse_cursors ();
+
+ if (m_dragging) {
+
+ set_cursor (lay::Cursor::size_all);
+
+ m_alt_ac = lay::ac_from_buttons (buttons);
+
+ move_impl (p);
call_editor_hooks (m_editor_hooks, &edt::EditorHooks::begin_edits);
issue_editor_hook_calls (m_editor_hooks);
@@ -2457,34 +2470,12 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
m_alt_ac = ac;
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);
propose_move_transformation (db::DTrans (m_current - m_start), 0);
- selection_to_view ();
-
m_alt_ac = lay::AC_Global;
}
diff --git a/src/edt/edt/edtPartialService.h b/src/edt/edt/edtPartialService.h
index e124c2dda..03c909494 100644
--- a/src/edt/edt/edtPartialService.h
+++ b/src/edt/edt/edtPartialService.h
@@ -386,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/laybasic/laybasic/gsiDeclLayPlugin.cc b/src/laybasic/laybasic/gsiDeclLayPlugin.cc
index d3e1d6f5a..502aec1a3 100644
--- a/src/laybasic/laybasic/gsiDeclLayPlugin.cc
+++ b/src/laybasic/laybasic/gsiDeclLayPlugin.cc
@@ -1092,6 +1092,10 @@ gsi::Enum decl_AngleConstraintType ("lay", "AngleCon
gsi::enum_const ("AC_Diagonal", lay::AC_Diagonal,
"@brief Specifies to use multiples of 45 degree.\n"
) +
+ gsi::enum_const ("AC_DiagonalOnly", lay::AC_DiagonalOnly,
+ "@brief Specifies to use 45 degree or 135 degree only.\n"
+ "This variant has been introduced in version 0.30.6."
+ ) +
gsi::enum_const ("AC_Ortho", lay::AC_Ortho,
"@brief Specifies to use multiples of 90 degree.\n"
) +
diff --git a/src/laybasic/laybasic/layConverters.cc b/src/laybasic/laybasic/layConverters.cc
index 7fe116af9..9bc42592a 100644
--- a/src/laybasic/laybasic/layConverters.cc
+++ b/src/laybasic/laybasic/layConverters.cc
@@ -87,8 +87,16 @@ ACConverter::to_string (const lay::angle_constraint_type &m)
return "any";
} else if (m == lay::AC_Diagonal) {
return "diagonal";
+ } else if (m == lay::AC_DiagonalOnly) {
+ return "diagonal_only";
} 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 "";
}
@@ -102,8 +110,16 @@ ACConverter::from_string (const std::string &tt, lay::angle_constraint_type &m)
m = lay::AC_Any;
} else if (t == "diagonal") {
m = lay::AC_Diagonal;
+ } else if (t == "diagonal_only") {
+ m = lay::AC_DiagonalOnly;
} 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;
}
From ca9a3198f5e63444aacfde76c4862a36e3976bb0 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 14 Jan 2026 12:48:51 +0100
Subject: [PATCH 19/36] WIP: some refactoring
---
src/edt/edt/edtEditorOptionsPages.cc | 11 ++
src/edt/edt/edtPlugin.cc | 154 +-----------------
src/edt/edt/edtRecentConfigurationPage.cc | 87 ++++++++++
src/edt/edt/edtRecentConfigurationPage.h | 23 ++-
src/laybasic/laybasic/layEditorOptionsPage.cc | 16 --
src/laybasic/laybasic/layEditorOptionsPage.h | 34 +++-
src/laybasic/laybasic/layMove.cc | 9 -
src/laybasic/laybasic/layPlugin.cc | 52 ++++++
src/laybasic/laybasic/layPlugin.h | 28 +++-
src/laybasic/laybasic/laybasic.pro | 2 -
.../layview}/gsiDeclLayPlugin.cc | 0
.../layview}/gsiDeclLayPluginFactory.cc | 0
src/layview/layview/layEditorOptionsFrame.cc | 1 +
src/layview/layview/layEditorOptionsPages.cc | 28 +++-
src/layview/layview/layEditorOptionsPages.h | 1 +
.../layview/layMoveEditorOptionsPage.cc | 4 +-
src/layview/layview/layview.pro | 4 +-
17 files changed, 255 insertions(+), 199 deletions(-)
rename src/{laybasic/laybasic => layview/layview}/gsiDeclLayPlugin.cc (100%)
rename src/{laybasic/laybasic => layview/layview}/gsiDeclLayPluginFactory.cc (100%)
diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc
index a51a7c45e..c7cb4b6ad 100644
--- a/src/edt/edt/edtEditorOptionsPages.cc
+++ b/src/edt/edt/edtEditorOptionsPages.cc
@@ -898,6 +898,17 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector 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);
+
}
#endif
diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc
index 1062bc71a..b287c5f7b 100644
--- a/src/edt/edt/edtPlugin.cc
+++ b/src/edt/edt/edtPlugin.cc
@@ -49,24 +49,6 @@
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 edt::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)
{
@@ -76,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 edt::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)
{
@@ -106,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)
{
@@ -148,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
{
@@ -220,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);
@@ -261,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)"
);
@@ -413,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 ();
@@ -519,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/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 5e53d2ec6..61edb1778 100644
--- a/src/edt/edt/edtRecentConfigurationPage.h
+++ b/src/edt/edt/edtRecentConfigurationPage.h
@@ -82,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)
- : EditorOptionsPageWidget (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 ();
@@ -98,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);
@@ -107,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/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc
index c3955809d..c7cf47e96 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.cc
+++ b/src/laybasic/laybasic/layEditorOptionsPage.cc
@@ -29,22 +29,6 @@
namespace lay
{
-// ------------------------------------------------------------------
-// EditorOptionsFactoryBase implementation
-
-lay::EditorOptionsPage *
-EditorOptionsPageFactoryBase::create_page_by_name (const std::string &name, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
-{
- auto reg = tl::Registrar::get_instance ();
- for (auto i = reg->begin (); i != reg->end (); ++i) {
- if (i.current_name () == name) {
- return i->create_page (view, dispatcher);
- }
- }
-
- return 0;
-}
-
// ------------------------------------------------------------------
// EditorOptionsPageCollection implementation
diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h
index 1b0e604a2..23d1cce26 100644
--- a/src/laybasic/laybasic/layEditorOptionsPage.h
+++ b/src/laybasic/laybasic/layEditorOptionsPage.h
@@ -154,12 +154,29 @@ class LAYBASIC_PUBLIC EditorOptionsPage
class LAYBASIC_PUBLIC EditorOptionsPageFactoryBase
{
public:
- EditorOptionsPageFactoryBase () { }
+ EditorOptionsPageFactoryBase (const char *plugin_name)
+ : m_plugin_name (plugin_name)
+ {
+ // .. nothing yet ..
+ }
+
+ EditorOptionsPageFactoryBase ()
+ : m_plugin_name ()
+ {
+ // .. nothing yet ..
+ }
+
virtual ~EditorOptionsPageFactoryBase () { }
+ const std::string &plugin_name () const
+ {
+ return m_plugin_name;
+ }
+
virtual lay::EditorOptionsPage *create_page (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) = 0;
- static lay::EditorOptionsPage *create_page_by_name (const std::string &name, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
+private:
+ std::string m_plugin_name;
};
/**
@@ -179,7 +196,18 @@ class LAYBASIC_PUBLIC_TEMPLATE EditorOptionsPageFactory
: public EditorOptionsPageFactoryBase
{
public:
- EditorOptionsPageFactory () { }
+ EditorOptionsPageFactory (const char *plugin_name)
+ : EditorOptionsPageFactoryBase (plugin_name)
+ {
+ // .. nothing yet ..
+ }
+
+ EditorOptionsPageFactory ()
+ : EditorOptionsPageFactoryBase ()
+ {
+ // .. nothing yet ..
+ }
+
virtual ~EditorOptionsPageFactory () { }
virtual lay::EditorOptionsPage *create_page (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc
index 5b759162c..1cba6c18e 100644
--- a/src/laybasic/laybasic/layMove.cc
+++ b/src/laybasic/laybasic/layMove.cc
@@ -465,15 +465,6 @@ class MoveServiceDeclaration
{
return new MoveService (view);
}
-
- virtual void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
- {
- lay::EditorOptionsPage *page = lay::EditorOptionsPageFactoryBase::create_page_by_name (move_editor_options_name, view, dispatcher);
- if (page) {
- page->set_plugin_declaration (this);
- pages.push_back (page);
- }
- }
};
static tl::RegisteredClass move_service_decl (new MoveServiceDeclaration (), -970, "laybasic::MoveServicePlugin");
diff --git a/src/laybasic/laybasic/layPlugin.cc b/src/laybasic/laybasic/layPlugin.cc
index 3b35d2e54..40a0b77f8 100644
--- a/src/laybasic/laybasic/layPlugin.cc
+++ b/src/laybasic/laybasic/layPlugin.cc
@@ -30,6 +30,7 @@
#include "layPlugin.h"
#include "layDispatcher.h"
+#include "layEditorOptionsPage.h"
#include "tlExceptions.h"
#include "tlClassRegistry.h"
@@ -317,6 +318,57 @@ PluginDeclaration::register_plugin ()
}
}
+std::string
+PluginDeclaration::name () const
+{
+ auto plugin_reg = tl::Registrar::get_instance ();
+ for (auto i = plugin_reg->begin (); i != plugin_reg->end (); ++i) {
+ if (i.operator-> () == this) {
+ return i.current_name ();
+ }
+ }
+
+ return std::string ();
+}
+
+void
+PluginDeclaration::get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
+{
+ std::string n = name ();
+ if (n.empty ()) {
+ return;
+ }
+
+ auto reg = tl::Registrar::get_instance ();
+ for (auto i = reg->begin (); i != reg->end (); ++i) {
+ lay::EditorOptionsPage *page = 0;
+ if (i->plugin_name () == n) {
+ page = i->create_page (view, dispatcher);
+ if (page) {
+ page->set_plugin_declaration (this);
+ }
+ }
+ if (page) {
+ pages.push_back (page);
+ }
+ }
+}
+
+void
+PluginDeclaration::get_catchall_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
+{
+ auto reg = tl::Registrar::get_instance ();
+ for (auto i = reg->begin (); i != reg->end (); ++i) {
+ lay::EditorOptionsPage *page = 0;
+ if (i->plugin_name ().empty ()) {
+ page = i->create_page (view, dispatcher);
+ if (page) {
+ pages.push_back (page);
+ }
+ }
+ }
+}
+
// ----------------------------------------------------------------
// Plugin implementation
diff --git a/src/laybasic/laybasic/layPlugin.h b/src/laybasic/laybasic/layPlugin.h
index 730b42772..9964ea7f3 100644
--- a/src/laybasic/laybasic/layPlugin.h
+++ b/src/laybasic/laybasic/layPlugin.h
@@ -170,6 +170,14 @@ Q_OBJECT
*/
virtual ~PluginDeclaration ();
+ /**
+ * @brief Gets the name under which the declaration was registered
+ *
+ * This is the name used in tl::RegisteredClass.
+ * If the plugin declaration is not registered, an empty string is returned.
+ */
+ std::string name () const;
+
/**
* @brief This method is supposed to deliver the option names available
*
@@ -323,7 +331,6 @@ Q_OBJECT
return false;
}
-#if defined(HAVE_QT)
/**
* @brief Gets the editor options pages
*
@@ -331,11 +338,21 @@ Q_OBJECT
* and these will be shown in tabs inside this widget.
*
* The new pages are returned in the "pages" vector. The layout view will take ownership of these pages.
+ *
+ * The default implementation collects pages registered through editor options page factories.
*/
- virtual void get_editor_options_pages (std::vector & /*pages*/, lay::LayoutViewBase * /*view*/, lay::Dispatcher * /*dispatcher*/) const
- {
- // .. no pages in the default implementation ..
- }
+ void get_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const;
+
+ /**
+ * @brief Gets the "catchall" editor options pages
+ *
+ * These are editor options pages not associated with a specific plugin.
+ *
+ * The new pages are returned in the "pages" vector. The layout view will take ownership of these pages.
+ *
+ * The implementation collects pages registered through editor options page factories.
+ */
+ static void get_catchall_editor_options_pages (std::vector &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
/**
* @brief Gets a value indicating whether "catchall" editor options pages shall be included
@@ -348,7 +365,6 @@ Q_OBJECT
{
return true;
}
-#endif
/**
* @brief Tells if the plugin implements a "lay::ViewService" active mouse mode
diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro
index 7a870fa69..9ff979b2e 100644
--- a/src/laybasic/laybasic/laybasic.pro
+++ b/src/laybasic/laybasic/laybasic.pro
@@ -36,8 +36,6 @@ SOURCES += \
gsiDeclLayTextInfo.cc \
gsiDeclLayTlAdded.cc \
gsiDeclLayRdbAdded.cc \
- gsiDeclLayPlugin.cc \
- gsiDeclLayPluginFactory.cc \
layAbstractMenu.cc \
layEditorOptionsPage.cc \
layEditorUtils.cc \
diff --git a/src/laybasic/laybasic/gsiDeclLayPlugin.cc b/src/layview/layview/gsiDeclLayPlugin.cc
similarity index 100%
rename from src/laybasic/laybasic/gsiDeclLayPlugin.cc
rename to src/layview/layview/gsiDeclLayPlugin.cc
diff --git a/src/laybasic/laybasic/gsiDeclLayPluginFactory.cc b/src/layview/layview/gsiDeclLayPluginFactory.cc
similarity index 100%
rename from src/laybasic/laybasic/gsiDeclLayPluginFactory.cc
rename to src/layview/layview/gsiDeclLayPluginFactory.cc
diff --git a/src/layview/layview/layEditorOptionsFrame.cc b/src/layview/layview/layEditorOptionsFrame.cc
index bd71de541..91a640eeb 100644
--- a/src/layview/layview/layEditorOptionsFrame.cc
+++ b/src/layview/layview/layEditorOptionsFrame.cc
@@ -53,6 +53,7 @@ EditorOptionsFrame::populate (LayoutViewBase *view)
for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) {
cls->get_editor_options_pages (editor_options_pages, view, view->dispatcher ());
}
+ lay::PluginDeclaration::get_catchall_editor_options_pages (editor_options_pages, view, view->dispatcher ());
for (std::vector::const_iterator op = editor_options_pages.begin (); op != editor_options_pages.end (); ++op) {
(*op)->activate (false);
diff --git a/src/layview/layview/layEditorOptionsPages.cc b/src/layview/layview/layEditorOptionsPages.cc
index 48eca6d81..904ac825e 100644
--- a/src/layview/layview/layEditorOptionsPages.cc
+++ b/src/layview/layview/layEditorOptionsPages.cc
@@ -51,7 +51,7 @@ struct EOPCompareOp
};
EditorOptionsPages::EditorOptionsPages (QWidget *parent, lay::LayoutViewBase *view, const std::vector &pages)
- : QFrame (parent), mp_view (view)
+ : QFrame (parent), mp_view (view), m_update_enabled (true)
{
mp_modal_pages = new EditorOptionsModalPages (this);
@@ -161,15 +161,25 @@ EditorOptionsPages::exec_modal (EditorOptionsPage *page)
void
EditorOptionsPages::activate (const lay::Plugin *plugin)
{
+ m_update_enabled = false;
+
for (auto op = m_pages.begin (); op != m_pages.end (); ++op) {
+
bool is_active = false;
if (op->plugin_declaration () == 0) {
is_active = (plugin && plugin->plugin_declaration ()->enable_catchall_editor_options_pages ());
} else if (plugin && plugin->plugin_declaration () == op->plugin_declaration ()) {
is_active = true;
}
+
+ BEGIN_PROTECTED
op->activate (is_active);
+ END_PROTECTED
+
}
+
+ m_update_enabled = true;
+ update (0);
}
void
@@ -220,6 +230,13 @@ EditorOptionsPages::activate_page (lay::EditorOptionsPage *page)
void
EditorOptionsPages::update (lay::EditorOptionsPage *page)
{
+ if (! m_update_enabled) {
+ return;
+ }
+
+ int index = mp_pages->currentIndex ();
+ int modal_index = -1;
+
std::vector sorted_pages;
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
if (p->widget ()) {
@@ -228,10 +245,6 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
}
std::sort (sorted_pages.begin (), sorted_pages.end (), EOPCompareOp ());
- if (! page && m_pages.size () > 0) {
- page = m_pages.back ();
- }
-
while (mp_pages->count () > 0) {
mp_pages->removeTab (0);
}
@@ -240,9 +253,6 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
mp_modal_pages->remove_page (0);
}
- int index = -1;
- int modal_index = -1;
-
for (auto p = sorted_pages.begin (); p != sorted_pages.end (); ++p) {
if ((*p)->active ()) {
if ((*p)->is_toolbox_widget ()) {
@@ -264,7 +274,7 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
}
if (index < 0) {
- index = mp_pages->currentIndex ();
+ index = 0;
}
if (index >= int (mp_pages->count ())) {
index = mp_pages->count () - 1;
diff --git a/src/layview/layview/layEditorOptionsPages.h b/src/layview/layview/layEditorOptionsPages.h
index 2e0bc100f..8a279352a 100644
--- a/src/layview/layview/layEditorOptionsPages.h
+++ b/src/layview/layview/layEditorOptionsPages.h
@@ -81,6 +81,7 @@ public slots:
lay::LayoutViewBase *mp_view;
QTabWidget *mp_pages;
EditorOptionsModalPages *mp_modal_pages;
+ bool m_update_enabled;
void update (lay::EditorOptionsPage *page);
void focusInEvent (QFocusEvent *event);
diff --git a/src/layview/layview/layMoveEditorOptionsPage.cc b/src/layview/layview/layMoveEditorOptionsPage.cc
index 7b79ba97f..0e1db8650 100644
--- a/src/layview/layview/layMoveEditorOptionsPage.cc
+++ b/src/layview/layview/layMoveEditorOptionsPage.cc
@@ -111,7 +111,7 @@ MoveEditorOptionsPage::configure (const std::string &name, const std::string &va
}
}
-// registers the factory for the move plugin
-static tl::RegisteredClass