From b8263d25296caeddb0ac80c5a5ac78d2cdaec23f Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Thu, 22 Sep 2022 21:17:51 +0200
Subject: [PATCH 01/54] Fixed #1159 (valgrind error)
---
src/tl/tl/tlString.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tl/tl/tlString.cc b/src/tl/tl/tlString.cc
index 178020c61..bb2a14dad 100644
--- a/src/tl/tl/tlString.cc
+++ b/src/tl/tl/tlString.cc
@@ -256,7 +256,7 @@ std::string to_lower_case (const std::string &s)
std::string to_local (const std::string &s)
{
- std::unique_ptr buffer (new char [MB_CUR_MAX]); // MB_CUR_MAX isn't a constant
+ std::unique_ptr buffer (new char [MB_CUR_MAX]); // MB_CUR_MAX isn't a constant
std::string ls;
std::wstring ws = to_wstring (s);
From 4236360620bf64eb5189a3183af6e734ea8c7135 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Fri, 23 Sep 2022 22:00:33 +0200
Subject: [PATCH 02/54] Added doc and icon to dependencies.
---
src/klayout.pro | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/klayout.pro b/src/klayout.pro
index 897d5b516..8c29c0b11 100644
--- a/src/klayout.pro
+++ b/src/klayout.pro
@@ -112,7 +112,7 @@ equals(HAVE_RUBY, "1") {
plugins.depends += lay
- klayout_main.depends += plugins $$MAIN_DEPENDS
+ klayout_main.depends += doc icons plugins $$MAIN_DEPENDS
} else {
From 293f26ddc0bce77f959f6cd13ad792148f97445e Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 25 Sep 2022 00:35:59 +0200
Subject: [PATCH 03/54] WIP: multiple tech stacks for net tracer, first steps
---
.../net_tracer/db_plugin/dbNetTracerIO.cc | 46 +-
.../net_tracer/db_plugin/dbNetTracerIO.h | 104 +++-
.../net_tracer/db_plugin/dbNetTracerPlugin.cc | 41 +-
.../db_plugin/gsiDeclDbNetTracer.cc | 95 +++-
.../NetTracerTechComponentEditor.ui | 450 +++++++-----------
...O.cc => layNetTracerConnectivityEditor.cc} | 66 ++-
...rIO.h => layNetTracerConnectivityEditor.h} | 24 +-
.../lay_plugin/layNetTracerDialog.cc | 2 +-
.../lay_plugin/layNetTracerPlugin.cc | 2 +-
.../net_tracer/lay_plugin/lay_plugin.pro | 7 +-
.../net_tracer/unit_tests/dbNetTracerTests.cc | 46 +-
.../net_tracer/unit_tests/dbTraceAllNets.cc | 26 +-
12 files changed, 495 insertions(+), 414 deletions(-)
rename src/plugins/tools/net_tracer/lay_plugin/{layNetTracerIO.cc => layNetTracerConnectivityEditor.cc} (92%)
rename src/plugins/tools/net_tracer/lay_plugin/{layNetTracerIO.h => layNetTracerConnectivityEditor.h} (75%)
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.cc
index 2da4268f5..8aa4697b9 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.cc
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.cc
@@ -182,9 +182,9 @@ NetTracerLayerExpressionInfo::compile (const std::string &s)
}
NetTracerLayerExpression *
-NetTracerLayerExpressionInfo::get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set &used_symbols) const
+NetTracerLayerExpressionInfo::get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerConnectivity &tech, const std::set &used_symbols) const
{
- for (NetTracerTechnologyComponent::const_symbol_iterator s = tech.begin_symbols (); s != tech.end_symbols (); ++s) {
+ for (NetTracerConnectivity::const_symbol_iterator s = tech.begin_symbols (); s != tech.end_symbols (); ++s) {
if (s->symbol ().log_equal (lp)) {
std::set us = used_symbols;
if (! us.insert (s->symbol ().to_string ()).second) {
@@ -204,14 +204,14 @@ NetTracerLayerExpressionInfo::get_expr (const db::LayerProperties &lp, const db:
}
NetTracerLayerExpression *
-NetTracerLayerExpressionInfo::get (const db::Layout &layout, const NetTracerTechnologyComponent &tech) const
+NetTracerLayerExpressionInfo::get (const db::Layout &layout, const NetTracerConnectivity &tech) const
{
std::set us;
return get (layout, tech, us);
}
NetTracerLayerExpression *
-NetTracerLayerExpressionInfo::get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set &used_symbols) const
+NetTracerLayerExpressionInfo::get (const db::Layout &layout, const NetTracerConnectivity &tech, const std::set &used_symbols) const
{
NetTracerLayerExpression *e = 0;
@@ -252,7 +252,7 @@ NetTracerConnectionInfo::NetTracerConnectionInfo (const NetTracerLayerExpression
// .. nothing yet ..
}
-static int get_layer_id (const NetTracerLayerExpressionInfo &e, const db::Layout &layout, const NetTracerTechnologyComponent &tech, NetTracerData *data)
+static int get_layer_id (const NetTracerLayerExpressionInfo &e, const db::Layout &layout, const NetTracerConnectivity &tech, NetTracerData *data)
{
std::unique_ptr expr_in (NetTracerLayerExpressionInfo::compile (e.to_string ()).get (layout, tech));
int l = expr_in->alias_for ();
@@ -266,7 +266,7 @@ static int get_layer_id (const NetTracerLayerExpressionInfo &e, const db::Layout
}
NetTracerConnection
-NetTracerConnectionInfo::get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, NetTracerData &data) const
+NetTracerConnectionInfo::get (const db::Layout &layout, const NetTracerConnectivity &tech, NetTracerData &data) const
{
int la = get_layer_id (m_la, layout, tech, &data);
int lb = get_layer_id (m_lb, layout, tech, &data);
@@ -490,30 +490,40 @@ NetTracerNet::define_layer (unsigned int l, const db::LayerProperties &lp, const
NetTracerTechnologyComponent::NetTracerTechnologyComponent ()
: db::TechnologyComponent (net_tracer_component_name (), tl::to_string (tr ("Connectivity")))
+{
+ // .. nothing yet ..
+}
+
+// -----------------------------------------------------------------------------------
+// NetTracerConnectivity implementation
+
+NetTracerConnectivity::NetTracerConnectivity ()
{
// .. nothing yet ..
}
-NetTracerTechnologyComponent::NetTracerTechnologyComponent (const NetTracerTechnologyComponent &d)
- : db::TechnologyComponent (net_tracer_component_name (), tl::to_string (tr ("Connectivity")))
+NetTracerConnectivity::NetTracerConnectivity (const NetTracerConnectivity &d)
{
- m_connections = d.m_connections;
- m_symbols = d.m_symbols;
+ operator= (d);
}
-NetTracerTechnologyComponent &NetTracerTechnologyComponent::operator= (const NetTracerTechnologyComponent &d)
+NetTracerConnectivity &NetTracerConnectivity::operator= (const NetTracerConnectivity &d)
{
- m_connections = d.m_connections;
- m_symbols = d.m_symbols;
+ if (this != &d) {
+ m_connections = d.m_connections;
+ m_symbols = d.m_symbols;
+ m_name = d.m_name;
+ m_description = d.m_description;
+ }
return *this;
}
NetTracerData
-NetTracerTechnologyComponent::get_tracer_data (const db::Layout &layout) const
+NetTracerConnectivity::get_tracer_data (const db::Layout &layout) const
{
// test run on the expressions to verify their syntax
int n = 1;
- for (NetTracerTechnologyComponent::const_iterator c = begin (); c != end (); ++c, ++n) {
+ for (NetTracerConnectivity::const_iterator c = begin (); c != end (); ++c, ++n) {
if (c->layer_a ().to_string ().empty ()) {
throw tl::Exception (tl::to_string (tr ("Missing first layer specification on connectivity specification #%d")), n);
}
@@ -523,7 +533,7 @@ NetTracerTechnologyComponent::get_tracer_data (const db::Layout &layout) const
}
n = 1;
- for (NetTracerTechnologyComponent::const_symbol_iterator s = begin_symbols (); s != end_symbols (); ++s, ++n) {
+ for (NetTracerConnectivity::const_symbol_iterator s = begin_symbols (); s != end_symbols (); ++s, ++n) {
if (s->symbol ().to_string ().empty ()) {
throw tl::Exception (tl::to_string (tr ("Missing symbol name on symbol specification #%d")), n);
}
@@ -540,12 +550,12 @@ NetTracerTechnologyComponent::get_tracer_data (const db::Layout &layout) const
NetTracerData data;
// register a logical layer for each original one as alias and one for each expression with a new ID
- for (db::NetTracerTechnologyComponent::const_symbol_iterator s = begin_symbols (); s != end_symbols (); ++s) {
+ for (db::NetTracerConnectivity::const_symbol_iterator s = begin_symbols (); s != end_symbols (); ++s) {
db::NetTracerLayerExpression *expr = db::NetTracerLayerExpressionInfo::compile (s->expression ()).get (layout, *this);
data.register_logical_layer (expr, s->symbol ().to_string ().c_str ());
}
- for (db::NetTracerTechnologyComponent::const_iterator c = begin (); c != end (); ++c) {
+ for (db::NetTracerConnectivity::const_iterator c = begin (); c != end (); ++c) {
data.add_connection (c->get (layout, *this, data));
}
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
index b0f760256..82dedb2c1 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
@@ -32,7 +32,7 @@
namespace db
{
-class NetTracerTechnologyComponent;
+class NetTracerConnectivity;
DB_PLUGIN_PUBLIC std::string net_tracer_component_name ();
@@ -57,7 +57,7 @@ public:
return m_expression;
}
- NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerTechnologyComponent &tech) const;
+ NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerConnectivity &tech) const;
private:
std::string m_expression;
@@ -70,8 +70,8 @@ private:
static NetTracerLayerExpressionInfo parse_mult (tl::Extractor &ex);
static NetTracerLayerExpressionInfo parse_atomic (tl::Extractor &ex);
- NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set &used_symbols) const;
- NetTracerLayerExpression *get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set &used_symbols) const;
+ NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerConnectivity &tech, const std::set &used_symbols) const;
+ NetTracerLayerExpression *get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerConnectivity &tech, const std::set &used_symbols) const;
};
class DB_PLUGIN_PUBLIC NetTracerConnectionInfo
@@ -81,7 +81,7 @@ public:
NetTracerConnectionInfo (const NetTracerLayerExpressionInfo &la, const NetTracerLayerExpressionInfo &lb);
NetTracerConnectionInfo (const NetTracerLayerExpressionInfo &la, const NetTracerLayerExpressionInfo &via, const NetTracerLayerExpressionInfo &lb);
- NetTracerConnection get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, NetTracerData &data) const;
+ NetTracerConnection get (const db::Layout &layout, const NetTracerConnectivity &tech, NetTracerData &data) const;
std::string to_string () const;
void parse (tl::Extractor &ex);
@@ -357,8 +357,7 @@ private:
void define_layer (unsigned int l, const db::LayerProperties &lp, const db::LayerProperties &lp_representative);
};
-class DB_PLUGIN_PUBLIC NetTracerTechnologyComponent
- : public db::TechnologyComponent
+class DB_PLUGIN_PUBLIC NetTracerConnectivity
{
public:
typedef std::vector::const_iterator const_iterator;
@@ -366,9 +365,29 @@ public:
typedef std::vector::const_iterator const_symbol_iterator;
typedef std::vector::iterator symbol_iterator;
- NetTracerTechnologyComponent ();
- NetTracerTechnologyComponent (const NetTracerTechnologyComponent &d);
- NetTracerTechnologyComponent &operator= (const NetTracerTechnologyComponent &d);
+ NetTracerConnectivity ();
+ NetTracerConnectivity (const NetTracerConnectivity &d);
+ NetTracerConnectivity &operator= (const NetTracerConnectivity &d);
+
+ const std::string &name () const
+ {
+ return m_name;
+ }
+
+ void set_name (const std::string &n)
+ {
+ m_name = n;
+ }
+
+ const std::string &description () const
+ {
+ return m_description;
+ }
+
+ void set_description (const std::string &d)
+ {
+ m_description = d;
+ }
const_iterator begin () const
{
@@ -458,14 +477,73 @@ public:
NetTracerData get_tracer_data (const db::Layout &layout) const;
- db::TechnologyComponent *clone () const
+private:
+ std::vector m_connections;
+ std::vector m_symbols;
+ std::string m_name, m_description;
+};
+
+class DB_PLUGIN_PUBLIC NetTracerTechnologyComponent
+ : public db::TechnologyComponent
+{
+public:
+ typedef std::vector::const_iterator const_iterator;
+ typedef std::vector::iterator iterator;
+
+ NetTracerTechnologyComponent ();
+
+ size_t size () const
+ {
+ return m_connectivity.size ();
+ }
+
+ void push_back (const db::NetTracerConnectivity &c)
+ {
+ m_connectivity.push_back (c);
+ }
+
+ void clear ()
+ {
+ m_connectivity.clear ();
+ }
+
+ void erase (iterator i)
+ {
+ m_connectivity.erase (i);
+ }
+
+ void insert (iterator i, const db::NetTracerConnectivity &c)
+ {
+ m_connectivity.insert (i, c);
+ }
+
+ const_iterator begin () const
+ {
+ return m_connectivity.begin ();
+ }
+
+ const_iterator end () const
+ {
+ return m_connectivity.begin ();
+ }
+
+ iterator begin ()
+ {
+ return m_connectivity.begin ();
+ }
+
+ iterator end ()
+ {
+ return m_connectivity.begin ();
+ }
+
+ db::NetTracerTechnologyComponent *clone () const
{
return new NetTracerTechnologyComponent (*this);
}
private:
- std::vector m_connections;
- std::vector m_symbols;
+ std::vector m_connectivity;
};
}
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
index d0793d4be..4c5632c23 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
@@ -65,6 +65,33 @@ namespace tl
};
}
+namespace
+{
+
+template
+struct FallbackXMLWriteAdapator
+{
+ FallbackXMLWriteAdapator (void (db::NetTracerConnectivity::*member) (const Value &))
+ : mp_member (member)
+ {
+ // .. nothing yet ..
+ }
+
+ void operator () (db::NetTracerTechnologyComponent &owner, tl::XMLReaderState &reader) const
+ {
+ if (owner.size () == 0) {
+ owner.push_back (db::NetTracerConnectivity ());
+ }
+ tl::XMLObjTag tag;
+ ((*owner.begin ()).*mp_member) (*reader.back (tag));
+ }
+
+private:
+ void (db::NetTracerConnectivity::*mp_member) (const Value &);
+};
+
+}
+
namespace db
{
@@ -86,8 +113,18 @@ public:
virtual tl::XMLElementBase *xml_element () const
{
return new db::TechnologyComponentXMLElement (net_tracer_component_name (),
- tl::make_member ((NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::begin, (NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::end, &NetTracerTechnologyComponent::add, "connection") +
- tl::make_member ((NetTracerTechnologyComponent::const_symbol_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::begin_symbols, (NetTracerTechnologyComponent::const_symbol_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::end_symbols, &NetTracerTechnologyComponent::add_symbol, "symbols")
+ // Fallback readers for migrating pre-0.28 setups to 0.28
+ tl::XMLMember, FallbackXMLWriteAdapator , tl::XMLStdConverter > (
+ tl::XMLMemberDummyReadAdaptor (),
+ FallbackXMLWriteAdapator (&NetTracerConnectivity::add), "connection") +
+ tl::XMLMember, FallbackXMLWriteAdapator , tl::XMLStdConverter > (
+ tl::XMLMemberDummyReadAdaptor (),
+ FallbackXMLWriteAdapator (&NetTracerConnectivity::add_symbol), "symbols") +
+ // 0.28 definitions
+ tl::make_element ((NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::begin, (NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::end, (void (NetTracerTechnologyComponent::*) (const NetTracerConnectivity &)) &NetTracerTechnologyComponent::push_back, "connectivity",
+ tl::make_member ((NetTracerConnectivity::const_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::begin, (NetTracerConnectivity::const_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::end, &NetTracerConnectivity::add, "connection") +
+ tl::make_member ((NetTracerConnectivity::const_symbol_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::begin_symbols, (NetTracerConnectivity::const_symbol_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::end_symbols, &NetTracerConnectivity::add_symbol, "symbols")
+ )
);
}
};
diff --git a/src/plugins/tools/net_tracer/db_plugin/gsiDeclDbNetTracer.cc b/src/plugins/tools/net_tracer/db_plugin/gsiDeclDbNetTracer.cc
index ff1f6b5a0..e14be4dcf 100644
--- a/src/plugins/tools/net_tracer/db_plugin/gsiDeclDbNetTracer.cc
+++ b/src/plugins/tools/net_tracer/db_plugin/gsiDeclDbNetTracer.cc
@@ -32,14 +32,14 @@ namespace gsi
// -----------------------------------------------------------------------------------
// GSI binding
-static void def_connection2 (db::NetTracerTechnologyComponent *tech, const std::string &la, const std::string &lb)
+static void def_connection2 (db::NetTracerConnectivity *tech, const std::string &la, const std::string &lb)
{
db::NetTracerLayerExpressionInfo la_info = db::NetTracerLayerExpressionInfo::compile (la);
db::NetTracerLayerExpressionInfo lb_info = db::NetTracerLayerExpressionInfo::compile (lb);
tech->add (db::NetTracerConnectionInfo (la_info, lb_info));
}
-static void def_connection3 (db::NetTracerTechnologyComponent *tech, const std::string &la, const std::string &via, const std::string &lb)
+static void def_connection3 (db::NetTracerConnectivity *tech, const std::string &la, const std::string &via, const std::string &lb)
{
db::NetTracerLayerExpressionInfo la_info = db::NetTracerLayerExpressionInfo::compile (la);
db::NetTracerLayerExpressionInfo via_info = db::NetTracerLayerExpressionInfo::compile (via);
@@ -47,14 +47,26 @@ static void def_connection3 (db::NetTracerTechnologyComponent *tech, const std::
tech->add (db::NetTracerConnectionInfo (la_info, via_info, lb_info));
}
-static void def_symbol (db::NetTracerTechnologyComponent *tech, const std::string &name, const std::string &expr)
+static void def_symbol (db::NetTracerConnectivity *tech, const std::string &name, const std::string &expr)
{
tech->add_symbol (db::NetTracerSymbolInfo (db::LayerProperties (name), expr));
}
-gsi::Class &decl_dbTechnologyComponent ();
-
-gsi::Class decl_NetTracerTechnology (decl_dbTechnologyComponent (), "db", "NetTracerTechnology",
+gsi::Class decl_NetTracerConnectivity ("db", "NetTracerConnectivity",
+ gsi::method ("name", &db::NetTracerConnectivity::name,
+ "@brief Gets the name of the connectivty definition\n"
+ "The name is an optional string defining the formal name for this definition.\n"
+ ) +
+ gsi::method ("name=", &db::NetTracerConnectivity::set_name, gsi::arg ("n"),
+ "@brief Sets the name of the connectivty definition\n"
+ ) +
+ gsi::method ("description", &db::NetTracerConnectivity::description,
+ "@brief Gets the description text of the connectivty definition\n"
+ "The description is an optional string giving a human-readable description for this definition."
+ ) +
+ gsi::method ("description=", &db::NetTracerConnectivity::set_description, gsi::arg ("d"),
+ "@brief Sets the description of the connectivty definition\n"
+ ) +
gsi::method_ext ("connection", &def_connection2, gsi::arg("a"), gsi::arg("b"),
"@brief Defines a connection between two materials\n"
"See the class description for details about this method."
@@ -68,7 +80,7 @@ gsi::Class decl_NetTracerTechnology (decl_dbTe
"Defines a sub-expression to be used in further symbols or material expressions. "
"For the detailed notation of the expression see the description of the net tracer feature."
),
- "@brief A technology description for the net tracer\n"
+ "@brief A connectivity description for the net tracer\n"
"\n"
"This object represents the technology description for the net tracer (represented by the \\NetTracer class).\n"
"A technology description basically consists of connection declarations.\n"
@@ -83,16 +95,17 @@ gsi::Class decl_NetTracerTechnology (decl_dbTe
"\n"
"For details about the expressions see the description of the net tracer feature.\n"
"\n"
- "This class has been introduced in version 0.25.\n"
+ "This class has been introduced in version 0.28 and replaces the 'NetTracerTechnology' class which "
+ "has been generalized.\n"
);
-static void trace1 (db::NetTracer *net_tracer, const db::NetTracerTechnologyComponent &tech, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer)
+static void trace1 (db::NetTracer *net_tracer, const db::NetTracerConnectivity &tech, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer)
{
db::NetTracerData tracer_data = tech.get_tracer_data (layout);
net_tracer->trace (layout, cell, start_point, start_layer, tracer_data);
}
-static void trace2 (db::NetTracer *net_tracer, const db::NetTracerTechnologyComponent &tech, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer, const db::Point &stop_point, unsigned int stop_layer)
+static void trace2 (db::NetTracer *net_tracer, const db::NetTracerConnectivity &tech, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer, const db::Point &stop_point, unsigned int stop_layer)
{
db::NetTracerData tracer_data = tech.get_tracer_data (layout);
net_tracer->trace (layout, cell, start_point, start_layer, stop_point, stop_layer, tracer_data);
@@ -106,7 +119,31 @@ static db::NetTracerData get_tracer_data_from_tech (const std::string &tech_name
const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
tl_assert (tech_component != 0);
- return tech_component->get_tracer_data (layout);
+ if (tech_component->size () < 1) {
+ throw tl::Exception (tl::to_string (tr ("No connectivity setup exists for technology '%s'")), tech_name);
+ }
+ if (tech_component->size () > 1) {
+ throw tl::Exception (tl::to_string (tr ("Multiple connectivity setups exist for technology '%s' - specify a name")), tech_name);
+ }
+
+ return tech_component->begin ()->get_tracer_data (layout);
+}
+
+static db::NetTracerData get_tracer_data_from_tech (const std::string &tech_name, const std::string &name, const db::Layout &layout)
+{
+ const db::Technology *tech = db::Technologies::instance ()->technology_by_name (tech_name);
+ tl_assert (tech != 0);
+
+ const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
+ tl_assert (tech_component != 0);
+
+ for (auto t = tech_component->begin (); t != tech_component->end (); ++t) {
+ if (t->name () == name) {
+ return t->get_tracer_data (layout);
+ }
+ }
+
+ throw tl::Exception (tl::to_string (tr ("No connectivity setup exists with name '%s' for technology '%s'")), name, tech_name);
}
static void trace1_tn (db::NetTracer *net_tracer, const std::string &tech, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer)
@@ -115,12 +152,24 @@ static void trace1_tn (db::NetTracer *net_tracer, const std::string &tech, const
net_tracer->trace (layout, cell, start_point, start_layer, tracer_data);
}
+static void trace1_tn2 (db::NetTracer *net_tracer, const std::string &tech, const std::string &name, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer)
+{
+ db::NetTracerData tracer_data = get_tracer_data_from_tech (tech, name, layout);
+ net_tracer->trace (layout, cell, start_point, start_layer, tracer_data);
+}
+
static void trace2_tn (db::NetTracer *net_tracer, const std::string &tech, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer, const db::Point &stop_point, unsigned int stop_layer)
{
db::NetTracerData tracer_data = get_tracer_data_from_tech (tech, layout);
net_tracer->trace (layout, cell, start_point, start_layer, stop_point, stop_layer, tracer_data);
}
+static void trace2_tn2 (db::NetTracer *net_tracer, const std::string &tech, const std::string &name, const db::Layout &layout, const db::Cell &cell, const db::Point &start_point, unsigned int start_layer, const db::Point &stop_point, unsigned int stop_layer)
+{
+ db::NetTracerData tracer_data = get_tracer_data_from_tech (tech, name, layout);
+ net_tracer->trace (layout, cell, start_point, start_layer, stop_point, stop_layer, tracer_data);
+}
+
gsi::Class decl_NetElement ("db", "NetElement",
gsi::method ("trans", &db::NetTracerShape::trans,
"@brief Gets the transformation to apply for rendering the shape in the original top cell\n"
@@ -178,7 +227,7 @@ gsi::Class decl_NetTracer ("db", "NetTracer",
"A path extraction version is provided as well which will extract one (the presumably shortest) path between two "
"points.\n"
"\n"
- "@param tech The technology definition\n"
+ "@param tech The connectivity definition\n"
"@param layout The layout on which to run the extraction\n"
"@param cell The cell on which to run the extraction (child cells will be included)\n"
"@param start_point The start point from which to start extraction of the net\n"
@@ -194,7 +243,7 @@ gsi::Class decl_NetTracer ("db", "NetTracer",
"\n"
"This version runs a path extraction and will deliver elements forming one path leading from the start to the end point.\n"
"\n"
- "@param tech The technology definition\n"
+ "@param tech The connectivity definition\n"
"@param layout The layout on which to run the extraction\n"
"@param cell The cell on which to run the extraction (child cells will be included)\n"
"@param start_point The start point from which to start extraction of the net\n"
@@ -205,13 +254,31 @@ gsi::Class decl_NetTracer ("db", "NetTracer",
gsi::method_ext ("trace", &trace1_tn, gsi::arg ("tech"), gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("start_point"), gsi::arg ("start_layer"),
"@brief Runs a net extraction taking a predefined technology\n"
"This method behaves identical as the version with a technology object, except that it will look for a technology "
- "with the given name to obtain the extraction setup."
+ "with the given name to obtain the extraction setup.\n"
+ "The technology is looked up by technology name. A version of this method exists where it is possible "
+ "to specify the name of the particular connectivity to use in case there are multiple definitions available."
+ ) +
+ gsi::method_ext ("trace", &trace1_tn2, gsi::arg ("tech"), gsi::arg ("connectivity_name"), gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("start_point"), gsi::arg ("start_layer"),
+ "@brief Runs a net extraction taking a predefined technology\n"
+ "This method behaves identical as the version with a technology object, except that it will look for a technology "
+ "with the given name to obtain the extraction setup. "
+ "This version allows specifying the name of the connecvitiy setup.\n"
+ "\n"
+ "This method variant has been introduced in version 0.28."
) +
gsi::method_ext ("trace", &trace2_tn, gsi::arg ("tech"), gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("start_point"), gsi::arg ("start_layer"), gsi::arg ("stop_point"), gsi::arg ("stop_layer"),
"@brief Runs a path extraction taking a predefined technology\n"
"This method behaves identical as the version with a technology object, except that it will look for a technology "
"with the given name to obtain the extraction setup."
) +
+ gsi::method_ext ("trace", &trace2_tn2, gsi::arg ("tech"), gsi::arg ("connectivity_name"), gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("start_point"), gsi::arg ("start_layer"), gsi::arg ("stop_point"), gsi::arg ("stop_layer"),
+ "@brief Runs a path extraction taking a predefined technology\n"
+ "This method behaves identical as the version with a technology object, except that it will look for a technology "
+ "with the given name to obtain the extraction setup."
+ "This version allows specifying the name of the connecvitiy setup.\n"
+ "\n"
+ "This method variant has been introduced in version 0.28."
+ ) +
gsi::iterator ("each_element", &db::NetTracer::begin, &db::NetTracer::end,
"@brief Iterates over the elements found during extraction\n"
"The elements are available only after the extraction has been performed."
diff --git a/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui b/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
index 188969569..8ee37634a 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
+++ b/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
@@ -1,7 +1,8 @@
-
+
+
NetTracerTechComponentEditor
-
-
+
+
0
0
@@ -9,324 +10,221 @@
449
-
+
Form
-
-
- 9
-
-
- 6
-
+
-
-
-
- Qt::Vertical
+
+
+ Qt::Horizontal
-
-
+
+
QFrame::NoFrame
-
+
QFrame::Raised
-
-
+
+
0
-
- 6
+
+ 0
- -
-
-
- QFrame::NoFrame
+
+ 0
+
+
+ 0
+
+ -
+
+
+ ...
-
- QFrame::Raised
+
+
+ :/down_16px.png :/down_16px.png
-
-
- 0
-
-
- 6
-
- -
-
-
- <html>Connectivity (<a href="int:/about/connectivity.xml">See here for details</a>)</html>
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
- -
-
-
+ -
+
+
+ ...
+
+
+
+ :/del_16px.png :/del_16px.png
+
+
+ Del
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/up_16px.png :/up_16px.png
+
+
+
+ -
+
+
QFrame::NoFrame
-
+
QFrame::Raised
-
-
- 0
+
+
+ -
+
+
+
+ true
+
+
+
+ Double-click to edit text
+
+
+
+ -
+
+
+
+ 0
+ 1
+
+
+
+
+ Name
-
- 6
+
+
+
+ Description
- -
-
-
- ...
-
-
- :/down_16px.png
-
-
-
- -
-
-
- ...
-
-
- :/del_16px.png
-
-
- Del
-
-
-
- -
-
-
- QAbstractItemView::AllEditTriggers
-
-
- true
-
-
- QAbstractItemView::SelectRows
-
-
- 3
-
-
-
-
-
-
- -
-
-
- ...
-
-
- :/add_16px.png
-
-
- Return
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 131
-
-
-
-
- -
-
-
- ...
-
-
- :/up_16px.png
-
-
-
-
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 157
+ 20
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/add_16px.png :/add_16px.png
+
+
+ Return
+
+
+
+ -
+
+
+ Technology Stacks
+
-
-
+
+
+
+ 1
+ 0
+
+
+
QFrame::NoFrame
-
+
QFrame::Raised
-
-
+
+
0
-
- 6
+
+ 0
+
+
+ 0
+
+
+ 0
-
-
-
- QFrame::NoFrame
+
+
+ Connectivity
-
- QFrame::Raised
-
-
-
- 0
-
-
- 6
-
- -
-
-
- <html>Computed and symbolic layers (<a href="int:/about/symbolic_layers.xml">See here for details</a>)</html>
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
- QFrame::NoFrame
+
+
+
+ 0
+ 1
+
-
- QFrame::Raised
-
-
-
- 0
-
-
- 6
-
- -
-
-
- ...
-
-
- :/down_16px.png
-
-
-
- -
-
-
- ...
-
-
- :/del_16px.png
-
-
- Del
-
-
-
- -
-
-
- QAbstractItemView::AllEditTriggers
-
-
- true
-
-
- QAbstractItemView::SelectRows
-
-
- 2
-
-
-
-
-
- -
-
-
- ...
-
-
- :/add_16px.png
-
-
- Return
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 131
-
-
-
-
- -
-
-
- ...
-
-
- :/up_16px.png
-
-
-
-
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 0
+
+
+
+
-
+
+
+ lay::NetTracerConnectivityEditor
+ QWidget
+ layNetTracerConnectivityEditor.h
+ 1
+
+
+
+
+
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerIO.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc
similarity index 92%
rename from src/plugins/tools/net_tracer/lay_plugin/layNetTracerIO.cc
rename to src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc
index 752e9dabb..83e935546 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerIO.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc
@@ -21,7 +21,7 @@
*/
-#include "layNetTracerIO.h"
+#include "layNetTracerConnectivityEditor.h"
#include "layNetTracerConfig.h"
#include "layConfigurationDialog.h"
@@ -56,7 +56,7 @@ class NetTracerConnectivityColumnDelegate
: public QItemDelegate
{
public:
- NetTracerConnectivityColumnDelegate (QWidget *parent, db::NetTracerTechnologyComponent *data)
+ NetTracerConnectivityColumnDelegate (QWidget *parent, db::NetTracerConnectivity *data)
: QItemDelegate (parent), mp_data (data)
{
// .. nothing yet ..
@@ -148,7 +148,7 @@ public:
}
private:
- db::NetTracerTechnologyComponent *mp_data;
+ db::NetTracerConnectivity *mp_data;
};
// -----------------------------------------------------------------------------------------
@@ -158,7 +158,7 @@ class NetTracerConnectivitySymbolColumnDelegate
: public QItemDelegate
{
public:
- NetTracerConnectivitySymbolColumnDelegate (QWidget *parent, db::NetTracerTechnologyComponent *data)
+ NetTracerConnectivitySymbolColumnDelegate (QWidget *parent, db::NetTracerConnectivity *data)
: QItemDelegate (parent), mp_data (data)
{
// .. nothing yet ..
@@ -262,16 +262,16 @@ public:
}
private:
- db::NetTracerTechnologyComponent *mp_data;
+ db::NetTracerConnectivity *mp_data;
};
// -----------------------------------------------------------------------------------
// NetTracerTechComponentEditor implementation
-NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
- : TechnologyComponentEditor (parent)
+NetTracerConnectivityEditor::NetTracerConnectivityEditor (QWidget *parent)
+ : QWidget (parent)
{
- Ui::NetTracerTechComponentEditor::setupUi (this);
+ Ui::NetTracerConnectivityEditor::setupUi (this);
connect (add_conductor_pb, SIGNAL (clicked ()), this, SLOT (add_clicked ()));
connect (del_conductor_pb, SIGNAL (clicked ()), this, SLOT (del_clicked ()));
@@ -293,26 +293,16 @@ NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
symbol_table->verticalHeader ()->hide ();
}
-void
-NetTracerTechComponentEditor::commit ()
+const db::NetTracerConnectivity &
+NetTracerConnectivityEditor::get_connectiviy ()
{
- db::NetTracerTechnologyComponent *data = dynamic_cast (tech_component ());
- if (! data) {
- return;
- }
-
- *data = m_data;
+ return m_data;
}
void
-NetTracerTechComponentEditor::setup ()
+NetTracerConnectivityEditor::set_connectivity (const db::NetTracerConnectivity &data)
{
- db::NetTracerTechnologyComponent *data = dynamic_cast (tech_component ());
- if (! data) {
- return;
- }
-
- m_data = *data;
+ m_data = data;
for (int c = 0; c < 3; ++c) {
if (connectivity_table->itemDelegateForColumn (c) != 0) {
@@ -332,7 +322,7 @@ NetTracerTechComponentEditor::setup ()
}
void
-NetTracerTechComponentEditor::add_clicked ()
+NetTracerConnectivityEditor::add_clicked ()
{
// removes focus from the tree view - commits the data
add_conductor_pb->setFocus ();
@@ -351,7 +341,7 @@ NetTracerTechComponentEditor::add_clicked ()
}
void
-NetTracerTechComponentEditor::del_clicked ()
+NetTracerConnectivityEditor::del_clicked ()
{
// removes focus from the tree view - commits the data
del_conductor_pb->setFocus ();
@@ -374,7 +364,7 @@ NetTracerTechComponentEditor::del_clicked ()
}
void
-NetTracerTechComponentEditor::move_up_clicked ()
+NetTracerConnectivityEditor::move_up_clicked ()
{
// removes focus from the tree view - commits the data
move_conductor_up_pb->setFocus ();
@@ -391,7 +381,7 @@ NetTracerTechComponentEditor::move_up_clicked ()
connectivity_table->setCurrentIndex (QModelIndex ());
int n = 0;
- for (db::NetTracerTechnologyComponent::iterator l = m_data.begin (); l != m_data.end (); ++l, ++n) {
+ for (db::NetTracerConnectivity::iterator l = m_data.begin (); l != m_data.end (); ++l, ++n) {
if (selected_rows.find (n + 1) != selected_rows.end () && selected_rows.find (n) == selected_rows.end ()) {
std::swap (m_data.begin () [n + 1], m_data.begin () [n]);
selected_rows.erase (n + 1);
@@ -415,7 +405,7 @@ NetTracerTechComponentEditor::move_up_clicked ()
}
void
-NetTracerTechComponentEditor::move_down_clicked ()
+NetTracerConnectivityEditor::move_down_clicked ()
{
// removes focus from the tree view - commits the data
move_conductor_down_pb->setFocus ();
@@ -432,7 +422,7 @@ NetTracerTechComponentEditor::move_down_clicked ()
connectivity_table->setCurrentIndex (QModelIndex ());
int n = int (m_data.size ());
- for (db::NetTracerTechnologyComponent::iterator l = m_data.end (); l != m_data.begin (); ) {
+ for (db::NetTracerConnectivity::iterator l = m_data.end (); l != m_data.begin (); ) {
--l;
--n;
if (selected_rows.find (n - 1) != selected_rows.end () && selected_rows.find (n) == selected_rows.end ()) {
@@ -458,7 +448,7 @@ NetTracerTechComponentEditor::move_down_clicked ()
}
void
-NetTracerTechComponentEditor::symbol_add_clicked ()
+NetTracerConnectivityEditor::symbol_add_clicked ()
{
// removes focus from the tree view - commits the data
add_symbol_pb->setFocus ();
@@ -477,7 +467,7 @@ NetTracerTechComponentEditor::symbol_add_clicked ()
}
void
-NetTracerTechComponentEditor::symbol_del_clicked ()
+NetTracerConnectivityEditor::symbol_del_clicked ()
{
// removes focus from the tree view - commits the data
del_symbol_pb->setFocus ();
@@ -500,7 +490,7 @@ NetTracerTechComponentEditor::symbol_del_clicked ()
}
void
-NetTracerTechComponentEditor::symbol_move_up_clicked ()
+NetTracerConnectivityEditor::symbol_move_up_clicked ()
{
// removes focus from the tree view - commits the data
move_symbol_up_pb->setFocus ();
@@ -517,7 +507,7 @@ NetTracerTechComponentEditor::symbol_move_up_clicked ()
symbol_table->setCurrentIndex (QModelIndex ());
int n = 0;
- for (db::NetTracerTechnologyComponent::symbol_iterator l = m_data.begin_symbols (); l != m_data.end_symbols (); ++l, ++n) {
+ for (db::NetTracerConnectivity::symbol_iterator l = m_data.begin_symbols (); l != m_data.end_symbols (); ++l, ++n) {
if (selected_rows.find (n + 1) != selected_rows.end () && selected_rows.find (n) == selected_rows.end ()) {
std::swap (m_data.begin_symbols () [n + 1], m_data.begin_symbols () [n]);
selected_rows.erase (n + 1);
@@ -541,7 +531,7 @@ NetTracerTechComponentEditor::symbol_move_up_clicked ()
}
void
-NetTracerTechComponentEditor::symbol_move_down_clicked ()
+NetTracerConnectivityEditor::symbol_move_down_clicked ()
{
// removes focus from the tree view - commits the data
move_symbol_down_pb->setFocus ();
@@ -558,7 +548,7 @@ NetTracerTechComponentEditor::symbol_move_down_clicked ()
symbol_table->setCurrentIndex (QModelIndex ());
int n = int (m_data.symbols ());
- for (db::NetTracerTechnologyComponent::symbol_iterator l = m_data.end_symbols (); l != m_data.begin_symbols (); ) {
+ for (db::NetTracerConnectivity::symbol_iterator l = m_data.end_symbols (); l != m_data.begin_symbols (); ) {
--l;
--n;
if (selected_rows.find (n - 1) != selected_rows.end () && selected_rows.find (n) == selected_rows.end ()) {
@@ -584,7 +574,7 @@ NetTracerTechComponentEditor::symbol_move_down_clicked ()
}
void
-NetTracerTechComponentEditor::update ()
+NetTracerConnectivityEditor::update ()
{
QStringList labels;
int n;
@@ -600,7 +590,7 @@ NetTracerTechComponentEditor::update ()
connectivity_table->setHorizontalHeaderLabels (labels);
n = 0;
- for (db::NetTracerTechnologyComponent::iterator l = m_data.begin (); l != m_data.end (); ++l, ++n) {
+ for (db::NetTracerConnectivity::iterator l = m_data.begin (); l != m_data.end (); ++l, ++n) {
for (int c = 0; c < 3; ++c) {
@@ -652,7 +642,7 @@ NetTracerTechComponentEditor::update ()
symbol_table->setHorizontalHeaderLabels (labels);
n = 0;
- for (db::NetTracerTechnologyComponent::symbol_iterator l = m_data.begin_symbols (); l != m_data.end_symbols (); ++l, ++n) {
+ for (db::NetTracerConnectivity::symbol_iterator l = m_data.begin_symbols (); l != m_data.end_symbols (); ++l, ++n) {
for (int c = 0; c < 2; ++c) {
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerIO.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h
similarity index 75%
rename from src/plugins/tools/net_tracer/lay_plugin/layNetTracerIO.h
rename to src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h
index fcb48e989..64377b4a1 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerIO.h
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h
@@ -22,10 +22,10 @@
-#ifndef HDR_layNetTracerIO
-#define HDR_layNetTracerIO
+#ifndef HDR_layNetTracerConnectivityEditor
+#define HDR_layNetTracerConnectivityEditor
-#include "ui_NetTracerTechComponentEditor.h"
+#include "ui_NetTracerConnectivityEditor.h"
#include "dbNetTracer.h"
#include "dbNetTracerIO.h"
@@ -42,25 +42,23 @@
namespace db
{
- class NetTracerTechnologyComponent;
+ class NetTracerConnectivity;
}
namespace lay
{
-class FileDialog;
-
-class NetTracerTechComponentEditor
- : public lay::TechnologyComponentEditor,
- public Ui::NetTracerTechComponentEditor
+class NetTracerConnectivityEditor
+ : public QWidget,
+ public Ui::NetTracerConnectivityEditor
{
Q_OBJECT
public:
- NetTracerTechComponentEditor (QWidget *parent);
+ NetTracerConnectivityEditor (QWidget *parent);
- void commit ();
- void setup ();
+ void set_connectivity (const db::NetTracerConnectivity &data);
+ const db::NetTracerConnectivity &get_connectiviy();
public slots:
void add_clicked ();
@@ -73,7 +71,7 @@ public slots:
void symbol_move_down_clicked ();
private:
- db::NetTracerTechnologyComponent m_data;
+ db::NetTracerConnectivity m_data;
void update ();
};
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
index d33a14748..454f58330 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
@@ -290,7 +290,7 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat
if (! tech) {
return false;
}
- const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
+ const db::NetTracerConnectivity *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
if (! tech_component) {
return false;
}
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc
index 7cc918cd9..d4aa6d75a 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc
@@ -22,7 +22,7 @@
#include "dbNetTracerIO.h"
-#include "layNetTracerIO.h"
+#include "layNetTracerTechComponentEditor.h"
#include "layNetTracerDialog.h"
#include "layNetTracerConfig.h"
diff --git a/src/plugins/tools/net_tracer/lay_plugin/lay_plugin.pro b/src/plugins/tools/net_tracer/lay_plugin/lay_plugin.pro
index 7f05e1cc4..1216f559a 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/lay_plugin.pro
+++ b/src/plugins/tools/net_tracer/lay_plugin/lay_plugin.pro
@@ -14,17 +14,20 @@ LIBS += -L$$DESTDIR/../db_plugins -lnet_tracer
HEADERS = \
layNetTracerConfig.h \
+ layNetTracerConnectivityEditor.h \
layNetTracerDialog.h \
- layNetTracerIO.h \
+ layNetTracerTechComponentEditor.h
SOURCES = \
layNetTracerConfig.cc \
+ layNetTracerConnectivityEditor.cc \
layNetTracerDialog.cc \
layNetTracerPlugin.cc \
- layNetTracerIO.cc \
+ layNetTracerTechComponentEditor.cc
FORMS = \
NetTracerConfigPage.ui \
+ NetTracerConnectivityEditor.ui \
NetTracerDialog.ui \
NetTracerTechComponentEditor.ui \
diff --git a/src/plugins/tools/net_tracer/unit_tests/dbNetTracerTests.cc b/src/plugins/tools/net_tracer/unit_tests/dbNetTracerTests.cc
index 52375e61f..e0fa275a5 100644
--- a/src/plugins/tools/net_tracer/unit_tests/dbNetTracerTests.cc
+++ b/src/plugins/tools/net_tracer/unit_tests/dbNetTracerTests.cc
@@ -76,21 +76,21 @@ static db::NetTracerShape find_shape (const db::Layout &layout, const db::Cell &
}
#endif
-static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout, const db::Cell &cell, const db::NetTracerTechnologyComponent &tc, unsigned int l_start, const db::Point &p_start)
+static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout, const db::Cell &cell, const db::NetTracerConnectivity &tc, unsigned int l_start, const db::Point &p_start)
{
db::NetTracerData tracer_data = tc.get_tracer_data (layout);
tracer.trace (layout, cell, p_start, l_start, tracer_data);
return db::NetTracerNet (tracer, db::ICplxTrans (), layout, cell.cell_index (), std::string (), std::string (), tracer_data);
}
-static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout, const db::Cell &cell, const db::NetTracerTechnologyComponent &tc, unsigned int l_start, const db::Point &p_start, unsigned int l_stop, const db::Point &p_stop)
+static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout, const db::Cell &cell, const db::NetTracerConnectivity &tc, unsigned int l_start, const db::Point &p_start, unsigned int l_stop, const db::Point &p_stop)
{
db::NetTracerData tracer_data = tc.get_tracer_data (layout);
tracer.trace (layout, cell, p_start, l_start, p_stop, l_stop, tracer_data);
return db::NetTracerNet (tracer, db::ICplxTrans (), layout, cell.cell_index (), std::string (), std::string (), tracer_data);
}
-void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerTechnologyComponent &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const std::string &file_au, const char *net_name = 0, size_t depth = 0)
+void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerConnectivity &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const std::string &file_au, const char *net_name = 0, size_t depth = 0)
{
db::Manager m (false);
@@ -130,7 +130,7 @@ void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracer
db::compare_layouts (_this, layout_net, fn, db::WriteOAS);
}
-void run_test2 (tl::TestBase *_this, const std::string &file, const db::NetTracerTechnologyComponent &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const db::LayerProperties &lp_stop, const db::Point &p_stop, const std::string &file_au, const char *net_name = 0)
+void run_test2 (tl::TestBase *_this, const std::string &file, const db::NetTracerConnectivity &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const db::LayerProperties &lp_stop, const db::Point &p_stop, const std::string &file_au, const char *net_name = 0)
{
db::Manager m (false);
@@ -169,7 +169,7 @@ TEST(1)
std::string file = "t1.oas.gz";
std::string file_au = "t1_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME");
@@ -180,7 +180,7 @@ TEST(1b)
std::string file = "t1.oas.gz";
std::string file_au = "t1b_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
// point is off net ...
@@ -192,7 +192,7 @@ TEST(1c)
std::string file = "t1.oas.gz";
std::string file_au = "t1_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add_symbol (symbol ("a", "1/0"));
tc.add_symbol (symbol ("c", "cc"));
tc.add_symbol (symbol ("cc", "3/0"));
@@ -206,7 +206,7 @@ TEST(1d)
std::string file = "t1.oas.gz";
std::string file_au = "t1d_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "10/0", "11/0"));
// some layers are non-existing
@@ -218,7 +218,7 @@ TEST(2)
std::string file = "t2.oas.gz";
std::string file_au = "t2_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
run_test2 (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), db::LayerProperties (3, 0), db::Point (4000, -20000), file_au, "THE_NAME");
@@ -229,7 +229,7 @@ TEST(3)
std::string file = "t3.oas.gz";
std::string file_au = "t3_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
std::string msg;
@@ -246,7 +246,7 @@ TEST(4)
std::string file = "t4.oas.gz";
std::string file_au = "t4_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "");
@@ -257,7 +257,7 @@ TEST(4b)
std::string file = "t4.oas.gz";
std::string file_au = "t4b_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "3/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME");
@@ -268,7 +268,7 @@ TEST(5)
std::string file = "t5.oas.gz";
std::string file_au = "t5_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0*10/0", "2/0", "3/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME");
@@ -279,7 +279,7 @@ TEST(5b)
std::string file = "t5.oas.gz";
std::string file_au = "t5b_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0*10/0", "3/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME");
@@ -290,7 +290,7 @@ TEST(5c)
std::string file = "t5.oas.gz";
std::string file_au = "t5c_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0-11/0", "3/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "");
@@ -301,7 +301,7 @@ TEST(5d)
std::string file = "t5.oas.gz";
std::string file_au = "t5d_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0-12/0", "2/0", "3/0-12/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME");
@@ -312,7 +312,7 @@ TEST(5e)
std::string file = "t5.oas.gz";
std::string file_au = "t5e_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0-12/0", "2/0", "3/0-12/0"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME");
@@ -323,7 +323,7 @@ TEST(5f)
std::string file = "t5.oas.gz";
std::string file_au = "t5f_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add_symbol (symbol ("x", "3-14"));
tc.add (connection ("10-13", "x"));
tc.add (connection ("x", "2", "1+13"));
@@ -336,7 +336,7 @@ TEST(6)
std::string file = "t6.oas.gz";
std::string file_au = "t6_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1-10", "2", "3"));
tc.add (connection ("3", "4", "5"));
@@ -348,7 +348,7 @@ TEST(6b)
std::string file = "t6.oas.gz";
std::string file_au = "t6b_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1-10", "2", "3"));
tc.add (connection ("3", "4", "5"));
@@ -360,7 +360,7 @@ TEST(7)
std::string file = "t7.oas.gz";
std::string file_au = "t7_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("15", "14", "2-7"));
tc.add (connection ("15", "14", "7"));
@@ -373,7 +373,7 @@ TEST(8)
std::string file = "t8.oas.gz";
std::string file_au = "t8_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("15", "14", "7"));
run_test (_this, file, tc, db::LayerProperties (15, 0), db::Point (4000, 10000), file_au, "");
@@ -384,7 +384,7 @@ TEST(9)
std::string file = "t9.oas.gz";
std::string file_au = "t9_net.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add_symbol (symbol ("a", "8-12"));
tc.add_symbol (symbol ("b", "a+7"));
tc.add_symbol (symbol ("c", "15*26"));
diff --git a/src/plugins/tools/net_tracer/unit_tests/dbTraceAllNets.cc b/src/plugins/tools/net_tracer/unit_tests/dbTraceAllNets.cc
index 53b674871..2ed796f0c 100644
--- a/src/plugins/tools/net_tracer/unit_tests/dbTraceAllNets.cc
+++ b/src/plugins/tools/net_tracer/unit_tests/dbTraceAllNets.cc
@@ -50,7 +50,7 @@ static db::NetTracerSymbolInfo symbol (const std::string &s, const std::string &
return db::NetTracerSymbolInfo (s, e);
}
-void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerTechnologyComponent &tc, const std::string &file_au)
+void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerConnectivity &tc, const std::string &file_au)
{
db::Manager m (false);
@@ -93,7 +93,7 @@ TEST(1)
std::string file = "t1.oas.gz";
std::string file_au = "t1_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
run_test (_this, file, tc, file_au);
@@ -104,7 +104,7 @@ TEST(1c)
std::string file = "t1.oas.gz";
std::string file_au = "t1_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add_symbol (symbol ("a", "1/0"));
tc.add_symbol (symbol ("c", "cc"));
tc.add_symbol (symbol ("cc", "3/0"));
@@ -118,7 +118,7 @@ TEST(1d)
std::string file = "t1.oas.gz";
std::string file_au = "t1d_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "10/0", "11/0"));
// some layers are non-existing
@@ -130,7 +130,7 @@ TEST(4)
std::string file = "t4.oas.gz";
std::string file_au = "t4_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0", "3/0"));
run_test (_this, file, tc, file_au);
@@ -141,7 +141,7 @@ TEST(4b)
std::string file = "t4.oas.gz";
std::string file_au = "t4b_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "3/0"));
run_test (_this, file, tc, file_au);
@@ -152,7 +152,7 @@ TEST(5)
std::string file = "t5.oas.gz";
std::string file_au = "t5_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0*10/0", "2/0", "3/0"));
run_test (_this, file, tc, file_au);
@@ -163,7 +163,7 @@ TEST(5b)
std::string file = "t5.oas.gz";
std::string file_au = "t5b_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0*10/0", "3/0"));
run_test (_this, file, tc, file_au);
@@ -174,7 +174,7 @@ TEST(5c)
std::string file = "t5.oas.gz";
std::string file_au = "t5c_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0", "2/0-11/0", "3/0"));
run_test (_this, file, tc, file_au);
@@ -185,7 +185,7 @@ TEST(5d)
std::string file = "t5.oas.gz";
std::string file_au = "t5d_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1/0-12/0", "2/0", "3/0-12/0"));
run_test (_this, file, tc, file_au);
@@ -196,7 +196,7 @@ TEST(5f)
std::string file = "t5.oas.gz";
std::string file_au = "t5f_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add_symbol (symbol ("x", "3-14"));
tc.add (connection ("10-13", "x"));
tc.add (connection ("x", "2", "1+13"));
@@ -209,7 +209,7 @@ TEST(6)
std::string file = "t6.oas.gz";
std::string file_au = "t6_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("1-10", "2", "3"));
tc.add (connection ("3", "4", "5"));
@@ -221,7 +221,7 @@ TEST(7)
std::string file = "t7.oas.gz";
std::string file_au = "t7_all_nets.oas.gz";
- db::NetTracerTechnologyComponent tc;
+ db::NetTracerConnectivity tc;
tc.add (connection ("15", "14", "2-7"));
tc.add (connection ("15", "14", "7"));
From 40786d13e0818581a5622c2f94860f45e8e95e0b Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 25 Sep 2022 00:36:29 +0200
Subject: [PATCH 04/54] WIP: added missing files
---
.../lay_plugin/NetTracerConnectivityEditor.ui | 343 ++++++++++++++++++
.../layNetTracerTechComponentEditor.cc | 310 ++++++++++++++++
.../layNetTracerTechComponentEditor.h | 81 +++++
3 files changed, 734 insertions(+)
create mode 100644 src/plugins/tools/net_tracer/lay_plugin/NetTracerConnectivityEditor.ui
create mode 100644 src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
create mode 100644 src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
diff --git a/src/plugins/tools/net_tracer/lay_plugin/NetTracerConnectivityEditor.ui b/src/plugins/tools/net_tracer/lay_plugin/NetTracerConnectivityEditor.ui
new file mode 100644
index 000000000..62af9ff85
--- /dev/null
+++ b/src/plugins/tools/net_tracer/lay_plugin/NetTracerConnectivityEditor.ui
@@ -0,0 +1,343 @@
+
+
+ NetTracerConnectivityEditor
+
+
+
+ 0
+ 0
+ 572
+ 449
+
+
+
+ Form
+
+
+
+ 6
+
+
+ 9
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 6
+
+
+ 0
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 6
+
+
+ 0
+
+ -
+
+
+ <html>Connectivity (<a href="int:/about/connectivity.xml">See here for details</a>)</html>
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 6
+
+ -
+
+
+ ...
+
+
+
+ :/down_16px.png :/down_16px.png
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/del_16px.png :/del_16px.png
+
+
+ Del
+
+
+
+ -
+
+
+ QAbstractItemView::AllEditTriggers
+
+
+ true
+
+
+ QAbstractItemView::SelectRows
+
+
+ 3
+
+
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/add_16px.png :/add_16px.png
+
+
+ Return
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 131
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/up_16px.png :/up_16px.png
+
+
+
+
+
+
+
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 6
+
+
+ 0
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 6
+
+
+ 0
+
+ -
+
+
+ <html>Computed and symbolic layers (<a href="int:/about/symbolic_layers.xml">See here for details</a>)</html>
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 6
+
+ -
+
+
+ ...
+
+
+
+ :/down_16px.png :/down_16px.png
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/del_16px.png :/del_16px.png
+
+
+ Del
+
+
+
+ -
+
+
+ QAbstractItemView::AllEditTriggers
+
+
+ true
+
+
+ QAbstractItemView::SelectRows
+
+
+ 2
+
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/add_16px.png :/add_16px.png
+
+
+ Return
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 131
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/up_16px.png :/up_16px.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
new file mode 100644
index 000000000..3d8293d78
--- /dev/null
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
@@ -0,0 +1,310 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2022 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 "layNetTracerTechComponentEditor.h"
+#include "layNetTracerConfig.h"
+
+#include "layConfigurationDialog.h"
+#include "laybasicConfig.h"
+#include "layConverters.h"
+#include "layFinder.h"
+#include "layLayoutView.h"
+#include "layTechSetupDialog.h"
+#include "layFileDialog.h"
+#include "layQtTools.h"
+#include "tlExceptions.h"
+#include "tlXMLWriter.h"
+#include "tlUtils.h"
+#include "gsiDecl.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace lay
+{
+
+// @@@ TODO: edit on double-click
+
+// -----------------------------------------------------------------------------------
+// NetTracerTechComponentEditor implementation
+
+NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
+ : TechnologyComponentEditor (parent)
+{
+ Ui::NetTracerTechComponentEditor::setupUi (this);
+
+ connect (add_pb, SIGNAL (clicked ()), this, SLOT (add_clicked ()));
+ connect (del_pb, SIGNAL (clicked ()), this, SLOT (del_clicked ()));
+ connect (move_up_pb, SIGNAL (clicked ()), this, SLOT (move_up_clicked ()));
+ connect (move_down_pb, SIGNAL (clicked ()), this, SLOT (move_down_clicked ()));
+
+ stack_tree->header ()->setHighlightSections (false);
+ stack_tree->header ()->setStretchLastSection (true);
+
+ connect (stack_tree, SIGNAL (currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT (current_item_changed(QTreeWidgetItem *, QTreeWidgetItem *)));
+ connect (stack_tree, SIGNAL (itemChanged(QTreeWidgetItem *, int)), this, SLOT (item_changed(QTreeWidgetItem *, int)));
+}
+
+void
+NetTracerTechComponentEditor::commit ()
+{
+ db::NetTracerTechnologyComponent *data = dynamic_cast (tech_component ());
+ if (! data) {
+ return;
+ }
+
+ *data = m_data;
+}
+
+void
+NetTracerTechComponentEditor::setup ()
+{
+ db::NetTracerTechnologyComponent *data = dynamic_cast (tech_component ());
+ if (! data) {
+ return;
+ }
+
+ m_data = *data;
+
+ if (m_data.size () == 0) {
+ m_data.push_back (db::NetTracerConnectivity ());
+ }
+
+ update ();
+}
+
+void
+NetTracerTechComponentEditor::item_changed (QTreeWidgetItem *item, int column)
+{
+ int row = stack_tree->indexOfTopLevelItem (item);
+ if (row >= 0 && row < int (m_data.size ())) {
+ if (column == 0) {
+ std::string n = tl::to_string (item->data (column, Qt::EditRole));
+ m_data.begin ()[row].set_name (n);
+ if (n.empty ()) {
+ item->setData (column, Qt::DisplayRole, tr ("(default)"));
+ } else {
+ item->setData (column, Qt::DisplayRole, tl::to_qstring (n));
+ }
+ }
+ if (column == 1) {
+ m_data.begin ()[row].set_description (tl::to_string (item->data (column, Qt::EditRole)));
+ }
+ }
+}
+
+void
+NetTracerTechComponentEditor::current_item_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous)
+{
+ commit_current (previous);
+
+ int row = current ? stack_tree->indexOfTopLevelItem (current) : -1;
+ if (row < 0 || row >= int (m_data.size ())) {
+ connectivity_editor_widget->set_connectivity (db::NetTracerConnectivity ());
+ connectivity_editor_widget->hide ();
+ } else {
+ connectivity_editor_widget->set_connectivity (m_data.begin ()[row]);
+ connectivity_editor_widget->show ();
+ }
+}
+
+void
+NetTracerTechComponentEditor::commit_current ()
+{
+ commit_current (stack_tree->currentItem ());
+}
+
+void
+NetTracerTechComponentEditor::commit_current (QTreeWidgetItem *current)
+{
+ int row = current ? stack_tree->indexOfTopLevelItem (current) : -1;
+ if (row >= 0 && row < int (m_data.size ())) {
+ m_data.begin () [row] = connectivity_editor_widget->get_connectiviy ();
+ }
+}
+
+void
+NetTracerTechComponentEditor::add_clicked ()
+{
+ // removes focus from the tree view - commits the data
+ add_pb->setFocus ();
+ commit_current ();
+
+ int row = stack_tree->currentItem () ? stack_tree->indexOfTopLevelItem (stack_tree->currentItem ()) : -1;
+ if (row < 0) {
+ m_data.push_back (db::NetTracerConnectivity ());
+ row = int (m_data.size () - 1);
+ } else {
+ row += 1;
+ m_data.insert (m_data.begin () + row, db::NetTracerConnectivity ());
+ }
+
+ update ();
+ stack_tree->setCurrentItem (stack_tree->topLevelItem (row));
+}
+
+void
+NetTracerTechComponentEditor::del_clicked ()
+{
+ // removes focus from the tree view - commits the data
+ del_pb->setFocus ();
+ commit_current ();
+
+ std::set selected_rows;
+ QModelIndexList selected_indices = stack_tree->selectionModel ()->selectedIndexes ();
+ for (auto i = selected_indices.begin (); i != selected_indices.end (); ++i) {
+ selected_rows.insert (i->row ());
+ }
+
+ stack_tree->setCurrentIndex (QModelIndex ());
+
+ int offset = 0;
+ for (std::set::const_iterator r = selected_rows.begin (); r != selected_rows.end (); ++r) {
+ m_data.erase (m_data.begin () + (*r - offset));
+ ++offset;
+ }
+
+ update ();
+}
+
+void
+NetTracerTechComponentEditor::move_up_clicked ()
+{
+ // removes focus from the tree view - commits the data
+ move_up_pb->setFocus ();
+ commit_current ();
+
+ std::set selected_rows;
+ QModelIndexList selected_indices = stack_tree->selectionModel ()->selectedIndexes ();
+ for (auto i = selected_indices.begin (); i != selected_indices.end (); ++i) {
+ selected_rows.insert (i->row ());
+ }
+
+ QTreeWidgetItem *current = stack_tree->currentItem ();
+ int n_current = current ? current->data (0, Qt::UserRole).toInt () : -1;
+
+ stack_tree->setCurrentIndex (QModelIndex ());
+
+ int n = 0;
+ for (db::NetTracerTechnologyComponent::iterator l = m_data.begin (); l != m_data.end (); ++l, ++n) {
+ if (selected_rows.find (n + 1) != selected_rows.end () && selected_rows.find (n) == selected_rows.end ()) {
+ std::swap (m_data.begin () [n + 1], m_data.begin () [n]);
+ selected_rows.erase (n + 1);
+ selected_rows.insert (n);
+ if (n_current == n + 1) {
+ n_current = n;
+ }
+ }
+ }
+
+ update ();
+
+ // select the new items
+ for (std::set ::const_iterator s = selected_rows.begin (); s != selected_rows.end (); ++s) {
+ stack_tree->selectionModel ()->select (stack_tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ }
+
+ if (n_current >= 0) {
+ stack_tree->selectionModel ()->select (stack_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
+ }
+}
+
+void
+NetTracerTechComponentEditor::move_down_clicked ()
+{
+ // removes focus from the tree view - commits the data
+ move_down_pb->setFocus ();
+ commit_current ();
+
+ std::set selected_rows;
+ QModelIndexList selected_indices = stack_tree->selectionModel ()->selectedIndexes ();
+ for (auto i = selected_indices.begin (); i != selected_indices.end (); ++i) {
+ selected_rows.insert (i->row ());
+ }
+
+ QTreeWidgetItem *current = stack_tree->currentItem ();
+ int n_current = current ? current->data (0, Qt::UserRole).toInt () : -1;
+
+ stack_tree->setCurrentIndex (QModelIndex ());
+
+ int n = int (m_data.size ());
+ for (db::NetTracerTechnologyComponent::iterator l = m_data.end (); l != m_data.begin (); ) {
+ --l;
+ --n;
+ if (selected_rows.find (n - 1) != selected_rows.end () && selected_rows.find (n) == selected_rows.end ()) {
+ std::swap (m_data.begin () [n - 1], m_data.begin () [n]);
+ selected_rows.erase (n - 1);
+ selected_rows.insert (n);
+ if (n_current == n - 1) {
+ n_current = n;
+ }
+ }
+ }
+
+ update ();
+
+ // select the new items
+ for (std::set ::const_iterator s = selected_rows.begin (); s != selected_rows.end (); ++s) {
+ stack_tree->selectionModel ()->select (stack_tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ }
+
+ if (n_current >= 0) {
+ stack_tree->selectionModel ()->select (stack_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
+ }
+}
+
+void
+NetTracerTechComponentEditor::update ()
+{
+ stack_tree->clear ();
+ stack_tree->clearSelection ();
+
+ int n = 0;
+ for (db::NetTracerTechnologyComponent::iterator l = m_data.begin (); l != m_data.end (); ++l, ++n) {
+
+ QTreeWidgetItem *item = new QTreeWidgetItem (stack_tree);
+ item->setFlags (item->flags () | Qt::ItemIsEditable);
+
+ if (l->name ().empty ()) {
+ item->setData (0, Qt::DisplayRole, QVariant (tr ("(default)")));
+ } else {
+ item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (l->name ())));
+ }
+ item->setData (0, Qt::EditRole, QVariant (tl::to_qstring (l->name ())));
+ item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (l->description ())));
+
+ item->setData (0, Qt::UserRole, QVariant (n));
+
+ }
+
+ current_item_changed (0, 0);
+}
+
+}
+
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
new file mode 100644
index 000000000..db802fe6b
--- /dev/null
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
@@ -0,0 +1,81 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2022 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_layNetTracerTechComponentEditor
+#define HDR_layNetTracerTechComponentEditor
+
+#include "ui_NetTracerTechComponentEditor.h"
+
+#include "dbNetTracer.h"
+#include "dbNetTracerIO.h"
+#include "dbTechnology.h"
+
+#include "layNetTracerConfig.h"
+#include "layBrowser.h"
+#include "layPlugin.h"
+#include "layViewObject.h"
+#include "layMarker.h"
+#include "layTechnology.h"
+
+#include "tlObject.h"
+
+namespace db
+{
+ class NetTracerTechnologyComponent;
+}
+
+namespace lay
+{
+
+class NetTracerTechComponentEditor
+ : public lay::TechnologyComponentEditor,
+ public Ui::NetTracerTechComponentEditor
+{
+Q_OBJECT
+
+public:
+ NetTracerTechComponentEditor (QWidget *parent);
+
+ void commit ();
+ void setup ();
+
+public slots:
+ void add_clicked ();
+ void del_clicked ();
+ void move_up_clicked ();
+ void move_down_clicked ();
+ void current_item_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous);
+ void item_changed (QTreeWidgetItem *item, int column);
+private:
+ db::NetTracerTechnologyComponent m_data;
+
+ void update ();
+ void commit_current (QTreeWidgetItem *current);
+ void commit_current ();
+};
+
+}
+
+#endif
+
From 2505ebb9a3c407b4c54963aa1af241d2674e5eb2 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 25 Sep 2022 10:53:23 +0200
Subject: [PATCH 05/54] WIP: some debugging
---
.../net_tracer/db_plugin/dbNetTracerIO.h | 2 +-
.../NetTracerTechComponentEditor.ui | 3 +
.../layNetTracerTechComponentEditor.cc | 113 ++++++++++++++----
3 files changed, 91 insertions(+), 27 deletions(-)
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
index 82dedb2c1..422584323 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
@@ -534,7 +534,7 @@ public:
iterator end ()
{
- return m_connectivity.begin ();
+ return m_connectivity.end ();
}
db::NetTracerTechnologyComponent *clone () const
diff --git a/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui b/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
index 8ee37634a..825513c9f 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
+++ b/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
@@ -105,6 +105,9 @@
1
+
+ false
+
Name
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
index 3d8293d78..cfe49d8d4 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
@@ -49,7 +49,83 @@
namespace lay
{
-// @@@ TODO: edit on double-click
+// -----------------------------------------------------------------------------------------
+// NetTracerTechComponentColumnDelegate definition and implementation
+
+class NetTracerTechComponentColumnDelegate
+ : public QItemDelegate
+{
+public:
+ NetTracerTechComponentColumnDelegate (QWidget *parent, db::NetTracerTechnologyComponent *data)
+ : QItemDelegate (parent), mp_data (data)
+ {
+ // .. nothing yet ..
+ }
+
+ QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
+ {
+ return new QLineEdit (parent);
+ }
+
+ void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & /*index*/) const
+ {
+ editor->setGeometry(option.rect);
+ }
+
+ void setEditorData (QWidget *widget, const QModelIndex &index) const
+ {
+ QLineEdit *editor = dynamic_cast (widget);
+ if (editor) {
+ int n = index.model ()->data (index, Qt::UserRole).toInt ();
+ if (mp_data->size () > size_t (n)) {
+ if (index.column () == 0) {
+ std::string name = mp_data->begin () [n].name ();
+ editor->setText (tl::to_qstring (name));
+ editor->setPlaceholderText (tr ("(default)"));
+ } else if (index.column () == 1) {
+ editor->setText (tl::to_qstring (mp_data->begin () [n].description ()));
+ }
+ }
+ }
+ }
+
+ void setModelData (QWidget *widget, QAbstractItemModel *model, const QModelIndex &index) const
+ {
+ QLineEdit *editor = dynamic_cast (widget);
+ if (editor) {
+
+ int n = model->data (index, Qt::UserRole).toInt ();
+ if (mp_data->size () > size_t (n)) {
+
+ std::string text = tl::to_string (editor->text ());
+ if (index.column () == 0 && text.empty ()) {
+ model->setData (index, QVariant (tr ("(default)")), Qt::DisplayRole);
+ } else {
+ model->setData (index, QVariant (tl::to_qstring (text)), Qt::DisplayRole);
+ }
+
+ if (index.column () == 0) {
+ mp_data->begin () [n].set_name (text);
+ } else if (index.column () == 1) {
+ mp_data->begin () [n].set_description (text);
+ }
+
+ }
+
+ }
+ }
+
+ QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ QWidget *editor = createEditor (0, option, index);
+ QSize size = editor->sizeHint ();
+ delete editor;
+ return size - QSize (2, 2);
+ }
+
+private:
+ db::NetTracerTechnologyComponent *mp_data;
+};
// -----------------------------------------------------------------------------------
// NetTracerTechComponentEditor implementation
@@ -68,7 +144,6 @@ NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
stack_tree->header ()->setStretchLastSection (true);
connect (stack_tree, SIGNAL (currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT (current_item_changed(QTreeWidgetItem *, QTreeWidgetItem *)));
- connect (stack_tree, SIGNAL (itemChanged(QTreeWidgetItem *, int)), this, SLOT (item_changed(QTreeWidgetItem *, int)));
}
void
@@ -96,27 +171,10 @@ NetTracerTechComponentEditor::setup ()
m_data.push_back (db::NetTracerConnectivity ());
}
- update ();
-}
+ stack_tree->setItemDelegateForColumn (0, new NetTracerTechComponentColumnDelegate (stack_tree, &m_data));
+ stack_tree->setItemDelegateForColumn (1, new NetTracerTechComponentColumnDelegate (stack_tree, &m_data));
-void
-NetTracerTechComponentEditor::item_changed (QTreeWidgetItem *item, int column)
-{
- int row = stack_tree->indexOfTopLevelItem (item);
- if (row >= 0 && row < int (m_data.size ())) {
- if (column == 0) {
- std::string n = tl::to_string (item->data (column, Qt::EditRole));
- m_data.begin ()[row].set_name (n);
- if (n.empty ()) {
- item->setData (column, Qt::DisplayRole, tr ("(default)"));
- } else {
- item->setData (column, Qt::DisplayRole, tl::to_qstring (n));
- }
- }
- if (column == 1) {
- m_data.begin ()[row].set_description (tl::to_string (item->data (column, Qt::EditRole)));
- }
- }
+ update ();
}
void
@@ -291,19 +349,22 @@ NetTracerTechComponentEditor::update ()
QTreeWidgetItem *item = new QTreeWidgetItem (stack_tree);
item->setFlags (item->flags () | Qt::ItemIsEditable);
- if (l->name ().empty ()) {
+ std::string name = l->name ();
+ if (name.empty ()) {
item->setData (0, Qt::DisplayRole, QVariant (tr ("(default)")));
} else {
- item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (l->name ())));
+ item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (name)));
}
- item->setData (0, Qt::EditRole, QVariant (tl::to_qstring (l->name ())));
item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (l->description ())));
item->setData (0, Qt::UserRole, QVariant (n));
}
- current_item_changed (0, 0);
+ if (! stack_tree->currentItem () && stack_tree->topLevelItemCount () > 0) {
+ stack_tree->setCurrentItem (stack_tree->topLevelItem (0));
+ }
+ current_item_changed (stack_tree->currentItem (), 0);
}
}
From 8919916da91ba9f92cf594fbaee569e8675c23ab Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 25 Sep 2022 11:22:45 +0200
Subject: [PATCH 06/54] WIP: some debugging
---
.../tools/net_tracer/db_plugin/dbNetTracerPlugin.cc | 2 ++
.../lay_plugin/layNetTracerConnectivityEditor.cc | 10 +++++++---
.../lay_plugin/layNetTracerConnectivityEditor.h | 2 +-
.../lay_plugin/layNetTracerTechComponentEditor.cc | 2 +-
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
index 4c5632c23..ed67acd05 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
@@ -122,6 +122,8 @@ public:
FallbackXMLWriteAdapator (&NetTracerConnectivity::add_symbol), "symbols") +
// 0.28 definitions
tl::make_element ((NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::begin, (NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::end, (void (NetTracerTechnologyComponent::*) (const NetTracerConnectivity &)) &NetTracerTechnologyComponent::push_back, "connectivity",
+ tl::make_member (&NetTracerConnectivity::name, &NetTracerConnectivity::set_name, "name") +
+ tl::make_member (&NetTracerConnectivity::description, &NetTracerConnectivity::set_description, "description") +
tl::make_member ((NetTracerConnectivity::const_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::begin, (NetTracerConnectivity::const_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::end, &NetTracerConnectivity::add, "connection") +
tl::make_member ((NetTracerConnectivity::const_symbol_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::begin_symbols, (NetTracerConnectivity::const_symbol_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::end_symbols, &NetTracerConnectivity::add_symbol, "symbols")
)
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc
index 83e935546..5458327ec 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.cc
@@ -293,10 +293,14 @@ NetTracerConnectivityEditor::NetTracerConnectivityEditor (QWidget *parent)
symbol_table->verticalHeader ()->hide ();
}
-const db::NetTracerConnectivity &
-NetTracerConnectivityEditor::get_connectiviy ()
+void
+NetTracerConnectivityEditor::get_connectivity (db::NetTracerConnectivity &data)
{
- return m_data;
+ std::string name = data.name ();
+ std::string description = data.description ();
+ data = m_data;
+ data.set_name (name);
+ data.set_description (description);
}
void
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h
index 64377b4a1..beed78303 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerConnectivityEditor.h
@@ -58,7 +58,7 @@ public:
NetTracerConnectivityEditor (QWidget *parent);
void set_connectivity (const db::NetTracerConnectivity &data);
- const db::NetTracerConnectivity &get_connectiviy();
+ void get_connectivity (db::NetTracerConnectivity &);
public slots:
void add_clicked ();
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
index cfe49d8d4..662f5e235 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
@@ -203,7 +203,7 @@ NetTracerTechComponentEditor::commit_current (QTreeWidgetItem *current)
{
int row = current ? stack_tree->indexOfTopLevelItem (current) : -1;
if (row >= 0 && row < int (m_data.size ())) {
- m_data.begin () [row] = connectivity_editor_widget->get_connectiviy ();
+ connectivity_editor_widget->get_connectivity (m_data.begin () [row]);
}
}
From 511f55d4da5dc7a5f273ae289e6afcc9039f0e30 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 25 Sep 2022 16:33:23 +0200
Subject: [PATCH 07/54] WIP: refined solution - some bug fixes, XML file is
backward compatible now
---
src/icons/icons.qrc | 2 +
src/icons/images/clone_16px.png | Bin 0 -> 411 bytes
src/icons/images/clone_16px@2x.png | Bin 0 -> 673 bytes
src/icons/svg/clone_16px.svg | 93 +++++++++++++
src/lay/lay/TechSetupDialog.ui | 38 ++++--
.../net_tracer/db_plugin/dbNetTracerIO.h | 12 +-
.../net_tracer/db_plugin/dbNetTracerPlugin.cc | 100 +++++++++++---
.../NetTracerTechComponentEditor.ui | 129 ++++++++++++------
.../layNetTracerTechComponentEditor.cc | 70 +++++++++-
.../layNetTracerTechComponentEditor.h | 1 +
10 files changed, 363 insertions(+), 82 deletions(-)
create mode 100644 src/icons/images/clone_16px.png
create mode 100644 src/icons/images/clone_16px@2x.png
create mode 100644 src/icons/svg/clone_16px.svg
diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc
index 1ff153d1a..79bdffc17 100644
--- a/src/icons/icons.qrc
+++ b/src/icons/icons.qrc
@@ -52,6 +52,8 @@
images/clear_edit_16px@2x.png
images/clearbreakpoints_16px.png
images/clearbreakpoints_16px@2x.png
+ images/clone_16px.png
+ images/clone_16px@2x.png
images/cm_add_24px.png
images/cm_add_24px@2x.png
images/cm_diff_24px.png
diff --git a/src/icons/images/clone_16px.png b/src/icons/images/clone_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..9cc80dafca4b3a574bb8326eda5241d9af4da530
GIT binary patch
literal 411
zcmV;M0c8G(P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10VqjC
zK~y-6jgvvj!Y~kpKW&?UH_|Q)^-@9+{(m8ODMcvlMZAKWW@yJv4KYP(!jLy&EO!C-sY;CvuR2^sXQwA~S
zndHD=t@RT#0LGYbbJulv@5AzDvtb-ZhG8&3mIK}M`8)$v(=>a4s;a_*_nzDB7HU=H
z@pyzfpVGXFh_-FJozhOp9#u71&a%t{!~7w2$K&w~RKPwaP}Ox^*Z;HD2y}s9uEbiq
zeP{CaJe&KQ6Q`c?M<%i77z=_plPT@sIi6pAWB&D9zW|1Rw#^etyaE6K002ovPDHLk
FV1i_-w`>3a
literal 0
HcmV?d00001
diff --git a/src/icons/images/clone_16px@2x.png b/src/icons/images/clone_16px@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac31d6e31712520d648df356ed7a1cdab0613080
GIT binary patch
literal 673
zcmV;S0$%-zP)o
z3eg}c7qhWboP9C&+OrE>KFI>S!|Z5w{@=0(hBQszX{|pAAwDKaa%YMWLc~du{FYKa
zdY<=(%UQ(Z0*L4ffUae}U%v1Ea4CR=h#rV&qLg|DkeV)~)H4xHi0HvJzp#k81AxtD
z^S&;iux31>CZy{h27|%b@A-WGx
G;x^;n+`aW4ePzu`ZE{n+<`h4i$xy*qA2Qz
zVYnNOM&AK^0MIy;Z_j2
zngB1;3Y>Yn6;Tv9#hX+R13(yt>`YurA$M%@ffaymrc)rB3H
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lay/lay/TechSetupDialog.ui b/src/lay/lay/TechSetupDialog.ui
index 71b39a402..999b2810b 100644
--- a/src/lay/lay/TechSetupDialog.ui
+++ b/src/lay/lay/TechSetupDialog.ui
@@ -108,6 +108,9 @@
-
+
+ Add technology
+
...
@@ -116,12 +119,15 @@
:/add_16px.png :/add_16px.png
- true
+ false
-
+
+ Delete technology
+
...
@@ -130,33 +136,37 @@
:/clear_16px.png :/clear_16px.png
- true
+ false
-
-
+
+
+ Rename technology
+
+
+ Rename
+
+
+
+ :/rename_16px@2x.png :/rename_16px@2x.png
+
+
+
+ -
+
Qt::Horizontal
-
- QSizePolicy::Expanding
-
- 141
+ 40
20
- -
-
-
- Rename
-
-
-
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
index 422584323..451d2cf3f 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerIO.h
@@ -435,6 +435,16 @@ public:
m_symbols.clear ();
}
+ void clear_connections ()
+ {
+ m_connections.clear ();
+ }
+
+ void clear_symbols ()
+ {
+ m_symbols.clear ();
+ }
+
void erase (iterator p)
{
m_connections.erase (p);
@@ -524,7 +534,7 @@ public:
const_iterator end () const
{
- return m_connectivity.begin ();
+ return m_connectivity.end ();
}
iterator begin ()
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
index ed67acd05..e9b442f7b 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc
@@ -68,26 +68,94 @@ namespace tl
namespace
{
-template
-struct FallbackXMLWriteAdapator
+static const db::NetTracerConnectivity *
+get_default (const db::NetTracerTechnologyComponent &tc)
{
- FallbackXMLWriteAdapator (void (db::NetTracerConnectivity::*member) (const Value &))
- : mp_member (member)
+ for (auto d = tc.begin (); d != tc.end (); ++d) {
+ if (d->name ().empty ()) {
+ return d.operator-> ();
+ }
+ }
+
+ if (tc.begin () != tc.end ()) {
+ return tc.begin ().operator-> ();
+ } else {
+ return 0;
+ }
+}
+
+template
+struct FallbackXMLWriteAdaptor
+{
+ FallbackXMLWriteAdaptor (void (db::NetTracerConnectivity::*member) (const Value &), void (db::NetTracerConnectivity::*clear) ())
+ : mp_member (member), mp_clear (clear), mp_stack (0)
{
// .. nothing yet ..
}
void operator () (db::NetTracerTechnologyComponent &owner, tl::XMLReaderState &reader) const
{
- if (owner.size () == 0) {
- owner.push_back (db::NetTracerConnectivity ());
+ if (! mp_stack) {
+ mp_stack = const_cast (get_default (owner));
+ if (! mp_stack) {
+ owner.push_back (db::NetTracerConnectivity ());
+ mp_stack = (owner.end () - 1).operator-> ();
+ }
+ (mp_stack->*mp_clear) ();
}
+
tl::XMLObjTag tag;
- ((*owner.begin ()).*mp_member) (*reader.back (tag));
+ (mp_stack->*mp_member) (*reader.back (tag));
}
private:
void (db::NetTracerConnectivity::*mp_member) (const Value &);
+ void (db::NetTracerConnectivity::*mp_clear) ();
+ mutable db::NetTracerConnectivity *mp_stack;
+};
+
+template
+struct FallbackXMLReadAdaptor
+{
+ typedef tl::pass_by_ref_tag tag;
+
+ FallbackXMLReadAdaptor (Iter (db::NetTracerConnectivity::*begin) () const, Iter (db::NetTracerConnectivity::*end) () const)
+ : mp_begin (begin), mp_end (end)
+ {
+ // .. nothing yet ..
+ }
+
+ Value operator () () const
+ {
+ return *m_iter;
+ }
+
+ bool at_end () const
+ {
+ return m_iter == m_end;
+ }
+
+ void start (const db::NetTracerTechnologyComponent &parent)
+ {
+ const db::NetTracerConnectivity *tn = get_default (parent);
+ if (! tn) {
+ m_iter = Iter ();
+ m_end = Iter ();
+ } else {
+ m_iter = (tn->*mp_begin) ();
+ m_end = (tn->*mp_end) ();
+ }
+ }
+
+ void next ()
+ {
+ ++m_iter;
+ }
+
+private:
+ Iter (db::NetTracerConnectivity::*mp_begin) () const;
+ Iter (db::NetTracerConnectivity::*mp_end) () const;
+ Iter m_iter, m_end;
};
}
@@ -113,20 +181,20 @@ public:
virtual tl::XMLElementBase *xml_element () const
{
return new db::TechnologyComponentXMLElement (net_tracer_component_name (),
- // Fallback readers for migrating pre-0.28 setups to 0.28
- tl::XMLMember, FallbackXMLWriteAdapator , tl::XMLStdConverter > (
- tl::XMLMemberDummyReadAdaptor (),
- FallbackXMLWriteAdapator (&NetTracerConnectivity::add), "connection") +
- tl::XMLMember, FallbackXMLWriteAdapator , tl::XMLStdConverter > (
- tl::XMLMemberDummyReadAdaptor (),
- FallbackXMLWriteAdapator (&NetTracerConnectivity::add_symbol), "symbols") +
// 0.28 definitions
- tl::make_element ((NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::begin, (NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::end, (void (NetTracerTechnologyComponent::*) (const NetTracerConnectivity &)) &NetTracerTechnologyComponent::push_back, "connectivity",
+ tl::make_element ((NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::begin, (NetTracerTechnologyComponent::const_iterator (NetTracerTechnologyComponent::*) () const) &NetTracerTechnologyComponent::end, (void (NetTracerTechnologyComponent::*) (const NetTracerConnectivity &)) &NetTracerTechnologyComponent::push_back, "stack",
tl::make_member (&NetTracerConnectivity::name, &NetTracerConnectivity::set_name, "name") +
tl::make_member (&NetTracerConnectivity::description, &NetTracerConnectivity::set_description, "description") +
tl::make_member ((NetTracerConnectivity::const_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::begin, (NetTracerConnectivity::const_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::end, &NetTracerConnectivity::add, "connection") +
tl::make_member ((NetTracerConnectivity::const_symbol_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::begin_symbols, (NetTracerConnectivity::const_symbol_iterator (NetTracerConnectivity::*) () const) &NetTracerConnectivity::end_symbols, &NetTracerConnectivity::add_symbol, "symbols")
- )
+ ) +
+ // Fallback readers for migrating pre-0.28 setups to 0.28 and backward compatibility
+ tl::XMLMember, FallbackXMLWriteAdaptor , tl::XMLStdConverter > (
+ FallbackXMLReadAdaptor (&NetTracerConnectivity::begin, &NetTracerConnectivity::end),
+ FallbackXMLWriteAdaptor (&NetTracerConnectivity::add, &NetTracerConnectivity::clear_connections), "connection") +
+ tl::XMLMember, FallbackXMLWriteAdaptor , tl::XMLStdConverter > (
+ FallbackXMLReadAdaptor (&NetTracerConnectivity::begin_symbols, &NetTracerConnectivity::end_symbols),
+ FallbackXMLWriteAdaptor (&NetTracerConnectivity::add_symbol, &NetTracerConnectivity::clear_symbols), "symbols")
);
}
};
diff --git a/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui b/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
index 825513c9f..15e3a6e16 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
+++ b/src/plugins/tools/net_tracer/lay_plugin/NetTracerTechComponentEditor.ui
@@ -20,6 +20,12 @@
Qt::Horizontal
+
+
+ 0
+ 0
+
+
QFrame::NoFrame
@@ -39,8 +45,11 @@
0
- -
+
-
+
+ Move selected stacks up
+
...
@@ -50,32 +59,24 @@
- -
-
+ -
+
+
+ Add new stack
+
...
- :/del_16px.png :/del_16px.png
+ :/add_16px.png :/add_16px.png
- Del
+ Return
- -
-
-
- ...
-
-
-
- :/up_16px.png :/up_16px.png
-
-
-
- -
+
-
QFrame::NoFrame
@@ -85,19 +86,7 @@
- -
-
-
-
- true
-
-
-
- Double-click to edit text
-
-
-
- -
+
-
@@ -105,9 +94,18 @@
1
+
+ Qt::ActionsContextMenu
+
+
+ QAbstractItemView::ExtendedSelection
+
false
+
+ true
+
Name
@@ -120,7 +118,50 @@
- -
+
-
+
+
+ Remove selected stacks
+
+
+ ...
+
+
+
+ :/del_16px.png :/del_16px.png
+
+
+ Del
+
+
+
+ -
+
+
+ Move selected stacks down
+
+
+ ...
+
+
+
+ :/up_16px.png :/up_16px.png
+
+
+
+ -
+
+
+
+ true
+
+
+
+ Double-click to edit text
+
+
+
+ -
Qt::Horizontal
@@ -133,24 +174,24 @@
- -
-
+ -
+
+
+ Technology Stacks
+
+
+
+ -
+
+
+ Clone current stack
+
...
- :/add_16px.png :/add_16px.png
-
-
- Return
-
-
-
- -
-
-
- Technology Stacks
+ :/clone_16px.png :/clone_16px.png
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
index 662f5e235..f2c19f968 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
@@ -135,8 +135,20 @@ NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
{
Ui::NetTracerTechComponentEditor::setupUi (this);
+ QAction *action;
+ action = new QAction (QObject::tr ("Add Stack"), this);
+ connect (action, SIGNAL (triggered ()), this, SLOT (add_clicked ()));
+ stack_tree->addAction (action);
+ action = new QAction (QObject::tr ("Delete Selected Stacks"), this);
+ connect (action, SIGNAL (triggered ()), this, SLOT (delete_clicked ()));
+ stack_tree->addAction (action);
+ action = new QAction (QObject::tr ("Duplicate Stack"), this);
+ connect (action, SIGNAL (triggered ()), this, SLOT (clone_clicked ()));
+ stack_tree->addAction (action);
+
connect (add_pb, SIGNAL (clicked ()), this, SLOT (add_clicked ()));
connect (del_pb, SIGNAL (clicked ()), this, SLOT (del_clicked ()));
+ connect (clone_pb, SIGNAL (clicked ()), this, SLOT (clone_clicked ()));
connect (move_up_pb, SIGNAL (clicked ()), this, SLOT (move_up_clicked ()));
connect (move_down_pb, SIGNAL (clicked ()), this, SLOT (move_down_clicked ()));
@@ -154,6 +166,7 @@ NetTracerTechComponentEditor::commit ()
return;
}
+ commit_current ();
*data = m_data;
}
@@ -175,6 +188,11 @@ NetTracerTechComponentEditor::setup ()
stack_tree->setItemDelegateForColumn (1, new NetTracerTechComponentColumnDelegate (stack_tree, &m_data));
update ();
+
+ if (stack_tree->topLevelItemCount () > 0) {
+ stack_tree->setCurrentItem (stack_tree->topLevelItem (0));
+ }
+ current_item_changed (stack_tree->currentItem (), 0);
}
void
@@ -207,7 +225,47 @@ NetTracerTechComponentEditor::commit_current (QTreeWidgetItem *current)
}
}
-void
+static std::string
+new_name (const db::NetTracerTechnologyComponent &data)
+{
+ for (int i = 1; ; ++i) {
+ std::string n = "STACK" + tl::to_string (i);
+ bool found = false;
+ for (auto d = data.begin (); d != data.end () && ! found; ++d) {
+ found = (d->name () == n);
+ }
+ if (! found) {
+ return n;
+ }
+ }
+
+ return std::string ();
+}
+
+void
+NetTracerTechComponentEditor::clone_clicked ()
+{
+ // removes focus from the tree view - commits the data
+ add_pb->setFocus ();
+ commit_current ();
+
+ int row = stack_tree->currentItem () ? stack_tree->indexOfTopLevelItem (stack_tree->currentItem ()) : -1;
+ if (row < 0) {
+ m_data.push_back (db::NetTracerConnectivity ());
+ row = int (m_data.size () - 1);
+ } else {
+ row += 1;
+ m_data.insert (m_data.begin () + row, db::NetTracerConnectivity ());
+ m_data.begin ()[row] = m_data.begin ()[row - 1];
+ }
+
+ m_data.begin ()[row].set_name (new_name (m_data));
+
+ update ();
+ stack_tree->setCurrentItem (stack_tree->topLevelItem (row));
+}
+
+void
NetTracerTechComponentEditor::add_clicked ()
{
// removes focus from the tree view - commits the data
@@ -223,6 +281,8 @@ NetTracerTechComponentEditor::add_clicked ()
m_data.insert (m_data.begin () + row, db::NetTracerConnectivity ());
}
+ m_data.begin ()[row].set_name (new_name (m_data));
+
update ();
stack_tree->setCurrentItem (stack_tree->topLevelItem (row));
}
@@ -355,16 +415,12 @@ NetTracerTechComponentEditor::update ()
} else {
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (name)));
}
- item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (l->description ())));
-
item->setData (0, Qt::UserRole, QVariant (n));
- }
+ item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (l->description ())));
+ item->setData (1, Qt::UserRole, QVariant (n));
- if (! stack_tree->currentItem () && stack_tree->topLevelItemCount () > 0) {
- stack_tree->setCurrentItem (stack_tree->topLevelItem (0));
}
- current_item_changed (stack_tree->currentItem (), 0);
}
}
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
index db802fe6b..475b81e84 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
@@ -62,6 +62,7 @@ public:
public slots:
void add_clicked ();
+ void clone_clicked ();
void del_clicked ();
void move_up_clicked ();
void move_down_clicked ();
From 7b4b345cf429ff25174fb87e32c6a500a5c282e3 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 25 Sep 2022 19:10:30 +0200
Subject: [PATCH 08/54] Multiple stacks for net tracer - finished selection box
in net tracer dialog
---
.../laybasic/gsiDeclLayLayoutViewBase.cc | 8 +
src/laybasic/laybasic/layLayoutViewBase.cc | 2 +
src/laybasic/laybasic/layLayoutViewBase.h | 8 +
.../net_tracer/lay_plugin/NetTracerDialog.ui | 155 ++++++++++--------
.../lay_plugin/layNetTracerDialog.cc | 86 +++++++++-
.../lay_plugin/layNetTracerDialog.h | 5 +
.../layNetTracerTechComponentEditor.cc | 13 +-
7 files changed, 194 insertions(+), 83 deletions(-)
diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc
index dc10d5ba7..cef7e30bf 100644
--- a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc
+++ b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc
@@ -1631,6 +1631,14 @@ LAYBASIC_PUBLIC Class decl_LayoutViewBase ("lay", "LayoutVi
"Before version 0.25 this event was based on the observer pattern obsolete now. The corresponding methods "
"(add_cellview_observer/remove_cellview_observer) have been removed in 0.25.\n"
) +
+ gsi::event ("on_apply_technology", static_cast (lay::LayoutViewBase::*)> (&lay::LayoutViewBase::apply_technology_event), gsi::arg ("cellview_index"),
+ "@brief An event indicating that a cellview has requested a new technology\n"
+ "\n"
+ "If the technology of a cellview is changed, this event is triggered.\n"
+ "The integer parameter of this event will indicate the cellview that has changed.\n"
+ "\n"
+ "This event has been introduced in version 0.28.\n"
+ ) +
gsi::event ("on_file_open", static_cast (&lay::LayoutViewBase::file_open_event),
"@brief An event indicating that a file was opened\n"
"\n"
diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc
index 57c00aa38..e2ec59bce 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.cc
+++ b/src/laybasic/laybasic/layLayoutViewBase.cc
@@ -2314,6 +2314,8 @@ LayoutViewBase::signal_apply_technology (lay::LayoutHandle *layout_handle)
}
+ apply_technology_event (int (i));
+
}
}
diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h
index 5837c042d..d34426ce8 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.h
+++ b/src/laybasic/laybasic/layLayoutViewBase.h
@@ -677,6 +677,14 @@ public:
*/
tl::event cellview_changed_event;
+ /**
+ * @brief A event signalling that one cellview has requested a new technology
+ *
+ * This event is triggered if a cellview has requested a new technology.
+ * The argument is the index of the cellview that received the new technology.
+ */
+ tl::event apply_technology_event;
+
/**
* @brief An event signalling that a file has been loaded.
*
diff --git a/src/plugins/tools/net_tracer/lay_plugin/NetTracerDialog.ui b/src/plugins/tools/net_tracer/lay_plugin/NetTracerDialog.ui
index 823a74505..8a2669a57 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/NetTracerDialog.ui
+++ b/src/plugins/tools/net_tracer/lay_plugin/NetTracerDialog.ui
@@ -29,24 +29,14 @@
6
- -
+
-
Qt::Horizontal
- -
-
-
- Configure
-
-
- false
-
-
-
- -
+
-
@@ -67,7 +57,7 @@ Select one or multiple nets and choose "Export" to export the selected
- -
+
-
@@ -196,60 +186,7 @@ Select one or multiple nets and choose "Export" to export the selected
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 5
- 20
-
-
-
-
- -
-
-
- Trace depth:
-
-
-
- -
-
-
- Close
-
-
-
- -
-
-
-
- 1
- 0
-
-
-
-
-
-
-
- -
-
-
- Layer Stack
-
-
- false
-
-
-
- -
+
-
@@ -332,7 +269,6 @@ Select one or multiple nets and choose "Export" to export the selected
12
- 75
true
@@ -477,7 +413,23 @@ p, li { white-space: pre-wrap; }
- -
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 5
+ 20
+
+
+
+
+ -
@@ -488,7 +440,6 @@ p, li { white-space: pre-wrap; }
12
- 75
false
true
@@ -498,14 +449,54 @@ p, li { white-space: pre-wrap; }
- -
+
-
+
+
+
+ 0
+ 0
+
+
+
+ QComboBox::AdjustToContents
+
+
+
+ -
+
+
+ Layer Stack
+
+
+ false
+
+
+
+ -
+
+
+ Configure
+
+
+ false
+
+
+
+ -
+
+
+ Close
+
+
+
+ -
shapes
- -
+
-
@@ -521,6 +512,26 @@ p, li { white-space: pre-wrap; }
+ -
+
+
+ Trace depth:
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
index 454f58330..654212b30 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
@@ -92,7 +92,9 @@ NetTracerDialog::NetTracerDialog (lay::Dispatcher *root, LayoutViewBase *view)
view->layer_list_changed_event.add (this, &NetTracerDialog::layer_list_changed);
+ attach_events ();
update_info ();
+ update_list_of_stacks ();
}
NetTracerDialog::~NetTracerDialog ()
@@ -101,6 +103,69 @@ NetTracerDialog::~NetTracerDialog ()
clear_nets ();
}
+void
+NetTracerDialog::attach_events ()
+{
+ detach_from_all_events ();
+
+ mp_view->layer_list_changed_event.add (this, &NetTracerDialog::layer_list_changed);
+
+ db::Technologies::instance ()->technology_changed_event.add (this, &NetTracerDialog::update_list_of_stacks_with_technology);
+ db::Technologies::instance ()->technologies_changed_event.add (this, &NetTracerDialog::update_list_of_stacks);
+
+ mp_view->cellviews_changed_event.add (this, &NetTracerDialog::update_list_of_stacks);
+ mp_view->apply_technology_event.add (this, &NetTracerDialog::update_list_of_stacks_with_cellview);
+}
+
+void
+NetTracerDialog::update_list_of_stacks_with_technology (db::Technology *)
+{
+ update_list_of_stacks ();
+}
+
+void
+NetTracerDialog::update_list_of_stacks_with_cellview (int)
+{
+ update_list_of_stacks ();
+}
+
+void
+NetTracerDialog::update_list_of_stacks ()
+{
+ QString current_name = stack_selector->currentText ();
+
+ std::set names;
+ for (unsigned int cvi = 0; cvi < mp_view->cellviews (); ++cvi) {
+ const db::Technology *tech = mp_view->cellview (cvi)->technology ();
+ if (tech) {
+ const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
+ if (tech_component) {
+ for (auto d = tech_component->begin (); d != tech_component->end (); ++d) {
+ names.insert (tl::to_qstring (d->name ()));
+ }
+ }
+ }
+ }
+
+ stack_selector->clear ();
+
+ int current_index = 0;
+ int i = 0;
+ for (auto n = names.begin (); n != names.end (); ++n, ++i) {
+ if (n->isEmpty ()) {
+ stack_selector->addItem (tr ("(default)"), QVariant (*n));
+ } else {
+ stack_selector->addItem (*n, QVariant (*n));
+ }
+ if (*n == current_name) {
+ current_index = i;
+ }
+ }
+
+ stack_selector->setVisible (stack_selector->count () >= 2);
+ stack_selector->setCurrentIndex (current_index);
+}
+
void
NetTracerDialog::clear_nets ()
{
@@ -290,14 +355,27 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat
if (! tech) {
return false;
}
- const db::NetTracerConnectivity *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
+
+ const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
if (! tech_component) {
return false;
}
- // Set up the net tracer environment
- data = tech_component->get_tracer_data (cv->layout ());
+ std::string stack_name = tl::to_string (stack_selector->itemData (stack_selector->currentIndex ()).toString ());
+ const db::NetTracerConnectivity *connectivity = 0;
+ for (auto d = tech_component->begin (); d != tech_component->end () && ! connectivity; ++d) {
+ if (d->name () == stack_name) {
+ connectivity = d.operator-> ();
+ }
+ }
+
+ if (! connectivity) {
+ return false;
+ }
+
+ // Set up the net tracer environment
+ data = connectivity->get_tracer_data (cv->layout ());
return true;
}
@@ -545,6 +623,7 @@ NetTracerDialog::configure (const std::string &name, const std::string &value)
update_highlights ();
adjust_view ();
update_info ();
+ update_list_of_stacks ();
}
return taken;
@@ -1243,6 +1322,7 @@ BEGIN_PROTECTED
lay::TechComponentSetupDialog dialog (this, &tech, db::net_tracer_component_name ());
if (dialog.exec ()) {
*db::Technologies::instance ()->technology_by_name (tech.name ()) = tech;
+ update_list_of_stacks ();
}
END_PROTECTED
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h
index b777d32e7..f439f4af6 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h
@@ -112,6 +112,11 @@ private:
void commit ();
size_t get_trace_depth ();
+ void attach_events ();
+ void update_list_of_stacks_with_technology (db::Technology *);
+ void update_list_of_stacks_with_cellview (int);
+ void update_list_of_stacks ();
+
void update_highlights ();
void adjust_view ();
void clear_markers ();
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
index f2c19f968..22f69020f 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.cc
@@ -300,8 +300,6 @@ NetTracerTechComponentEditor::del_clicked ()
selected_rows.insert (i->row ());
}
- stack_tree->setCurrentIndex (QModelIndex ());
-
int offset = 0;
for (std::set::const_iterator r = selected_rows.begin (); r != selected_rows.end (); ++r) {
m_data.erase (m_data.begin () + (*r - offset));
@@ -309,6 +307,7 @@ NetTracerTechComponentEditor::del_clicked ()
}
update ();
+ stack_tree->setCurrentItem (0);
}
void
@@ -345,11 +344,10 @@ NetTracerTechComponentEditor::move_up_clicked ()
// select the new items
for (std::set ::const_iterator s = selected_rows.begin (); s != selected_rows.end (); ++s) {
- stack_tree->selectionModel ()->select (stack_tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ stack_tree->topLevelItem (*s)->setSelected (true);
}
-
if (n_current >= 0) {
- stack_tree->selectionModel ()->select (stack_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
+ stack_tree->setCurrentItem (stack_tree->topLevelItem (n_current), 0, QItemSelectionModel::Current);
}
}
@@ -389,11 +387,10 @@ NetTracerTechComponentEditor::move_down_clicked ()
// select the new items
for (std::set ::const_iterator s = selected_rows.begin (); s != selected_rows.end (); ++s) {
- stack_tree->selectionModel ()->select (stack_tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ stack_tree->topLevelItem (*s)->setSelected (true);
}
-
if (n_current >= 0) {
- stack_tree->selectionModel ()->select (stack_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
+ stack_tree->setCurrentItem (stack_tree->topLevelItem (n_current), 0, QItemSelectionModel::Current);
}
}
From d1b7cd1f8f61894971e3d041ca5f3ed3f12f2e64 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 26 Sep 2022 23:37:22 +0200
Subject: [PATCH 09/54] WIP: first steps towards multi-segment rulers
---
src/ant/ant/RulerPropertiesPage.ui | 1154 ++++++++++++++++------------
src/ant/ant/antObject.cc | 288 +++++--
src/ant/ant/antObject.h | 128 ++-
src/ant/ant/antPropertiesPage.cc | 194 ++++-
src/ant/ant/antPropertiesPage.h | 10 +-
src/ant/ant/antService.cc | 74 +-
src/ant/ant/gsiDeclAnt.cc | 85 +-
7 files changed, 1280 insertions(+), 653 deletions(-)
diff --git a/src/ant/ant/RulerPropertiesPage.ui b/src/ant/ant/RulerPropertiesPage.ui
index 5e4497bbd..567287ddc 100644
--- a/src/ant/ant/RulerPropertiesPage.ui
+++ b/src/ant/ant/RulerPropertiesPage.ui
@@ -13,10 +13,7 @@
Form
-
-
- 6
-
+
9
@@ -29,7 +26,7 @@
9
- -
+
-
QFrame::NoFrame
@@ -53,13 +50,95 @@
6
- -
-
+ -
+
- Second point (x/y)
+ X label format
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 5
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Label format
+
+
+
+ -
+
+
+ Y label format
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 5
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
-
@@ -67,173 +146,31 @@
- -
-
+ -
+
- <html>(See <a href="int:/manual/ruler_properties.xml">here</a> for a description of the properties)</html>
+ Outline
- -
-
+ -
+
+
+ -
+
... position
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 5
-
-
-
-
- -
-
-
- -
-
- -
-
- Diagonal
-
-
- -
-
- Horizonal and vertical (in this order)
-
-
- -
-
- Diagonal plus horizonal and vertical (triangle)
-
-
- -
-
- Vertical and horizonal (in this order)
-
-
- -
-
- Diagonal plus vertical and horizontal (triangle)
-
-
- -
-
- Box
-
-
- -
-
- Ellipse
-
-
-
-
- -
-
+ -
+
- d =
+ ... position
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 5
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 456
- 16
-
-
-
-
- -
-
- -
-
- Ruler
-
-
- -
-
- Arrow at end
-
-
- -
-
- Arrow at start
-
-
- -
-
- Arrow at both ends
-
-
- -
-
- Plain line
-
-
- -
-
- Cross at end
-
-
- -
-
- Cross at start
-
-
- -
-
- Cross at both ends
-
-
-
-
- -
-
-
-
- 1
- 0
-
-
-
-
- -
-
-
- Delta (x/y)
-
-
-
- -
+
-
QFrame::NoFrame
@@ -378,42 +315,176 @@
- -
-
+ -
+
+ -
+
+ Diagonal
+
+
+ -
+
+ Horizonal and vertical (in this order)
+
+
+ -
+
+ Diagonal plus horizonal and vertical (triangle)
+
+
+ -
+
+ Vertical and horizonal (in this order)
+
+
+ -
+
+ Diagonal plus vertical and horizontal (triangle)
+
+
+ -
+
+ Box
+
+
+ -
+
+ Ellipse
+
+
+
+
+ -
+
+ -
+
+ Ruler
+
+
+ -
+
+ Arrow at end
+
+
+ -
+
+ Arrow at start
+
+
+ -
+
+ Arrow at both ends
+
+
+ -
+
+ Plain line
+
+
+ -
+
+ Cross at end
+
+
+ -
+
+ Cross at start
+
+
+ -
+
+ Cross at both ends
+
+
+
+
+ -
+
+
+ <html>(See <a href="int:/manual/ruler_properties.xml">here</a> for a description of the properties)</html>
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Sans Serif
+ 12
+ false
+ true
+ false
+ false
+
+
+
+ Ruler Properties
+
+
+
+ -
+
- Qt::Horizontal
+ Qt::Vertical
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 5
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 5
+
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
- -
-
-
- x =
-
-
-
- -
-
-
- Label format
-
-
-
- -
-
-
- Length
-
-
-
- -
-
-
- Outline
-
-
-
- -
+
-
QFrame::NoFrame
@@ -524,210 +595,7 @@
- -
-
-
-
- 1
- 0
-
-
-
- true
-
-
-
- -
-
-
-
- 1
- 0
-
-
-
- true
-
-
-
- -
-
-
- First point (x/y)
-
-
-
- -
-
-
-
- 1
- 0
-
-
-
-
- -
-
-
- y =
-
-
-
- -
-
-
- QFrame::NoFrame
-
-
- QFrame::Raised
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
- Swap points
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 10
- 20
-
-
-
-
- -
-
-
- Snap to layout:
-
-
-
- -
-
-
- P1
-
-
- false
-
-
-
- -
-
-
- P2
-
-
- false
-
-
-
- -
-
-
- Both (auto-measure)
-
-
- false
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 5
-
-
-
-
- -
-
-
- y =
-
-
-
- -
-
-
- -
-
-
-
- 1
- 0
-
-
-
- true
-
-
-
- -
-
-
-
- 1
- 0
-
-
-
-
- -
-
-
- ... position
-
-
-
- -
-
-
- -
+
-
QFrame::NoFrame
@@ -838,98 +706,429 @@
- -
-
+ -
+
... position
- -
-
-
- x =
-
-
-
- -
-
+ -
+
-
- 1
- 0
-
-
-
-
- -
-
-
- Y label format
-
-
-
- -
-
-
- X label format
-
-
-
- -
-
-
- y =
-
-
-
- -
-
-
- x =
-
-
-
- -
-
-
-
+
0
- 0
+ 1
-
-
- Sans Serif
- 12
- 75
- false
- true
- false
- false
-
+
+
+ 0
+ 100
+
-
- Ruler Properties
+
+ 1
+
+
+ Single
+
+
+ -
+
+
+ First point (x/y)
+
+
+
+ -
+
+
+ x =
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+ y =
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 558
+ 157
+
+
+
+
+
+
+
+
+ Line
+
+
+ -
+
+
+ y =
+
+
+
+ -
+
+
+ First point (x/y)
+
+
+
+ -
+
+
+ d =
+
+
+
+ -
+
+
+ y =
+
+
+
+ -
+
+
+ y =
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+ true
+
+
+
+ -
+
+
+ Length
+
+
+
+ -
+
+
+ x =
+
+
+
+ -
+
+
+ Delta (x/y)
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+ Second point (x/y)
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+ x =
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ x =
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 0
+ 30
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ Swap points
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 5
+ 20
+
+
+
+
+ -
+
+
+ Snap to layout
+
+
+
+ -
+
+
+ P1
+
+
+ false
+
+
+
+ -
+
+
+ P2
+
+
+ false
+
+
+
+ -
+
+
+ Both (auto-measure)
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ Multi-Segment
+
+
+ -
+
+
+ false
+
+
+ true
+
+
+
+ x
+
+
+
+
+ y
+
+
+
+
+
+
+
+
+ Text edit
+
+
+ -
+
+
+ false
+
+
+
+
+
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 0
-
-
-
-
@@ -937,13 +1136,6 @@
fmt_y_le
style_cb
outline_cb
- x1
- y1
- x2
- y2
- dx
- dy
- dd
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index 43bdf736b..5603de0d8 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -33,7 +33,7 @@ namespace ant
{
Object::Object ()
- : m_p1 (), m_p2 (), m_id (-1),
+ : m_id (-1),
m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"),
m_style (STY_ruler), m_outline (OL_diag),
m_snap (true), m_angle_constraint (lay::AC_Global),
@@ -45,8 +45,8 @@ Object::Object ()
// .. nothing yet ..
}
-Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint)
- : m_p1 (p1), m_p2 (p2), m_id (id),
+Object::Object (const db::DPoint &_p1, const db::DPoint &_p2, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint)
+ : m_id (id),
m_fmt_x (fmt_x), m_fmt_y (fmt_y), m_fmt (fmt),
m_style (style), m_outline (outline),
m_snap (snap), m_angle_constraint (angle_constraint),
@@ -55,11 +55,25 @@ Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const std::s
m_xlabel_xalign (AL_auto), m_xlabel_yalign (AL_auto),
m_ylabel_xalign (AL_auto), m_ylabel_yalign (AL_auto)
{
- // .. nothing else ..
+ p1 (_p1);
+ p2 (_p2);
}
-Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::Template &t)
- : m_p1 (p1), m_p2 (p2), m_id (id),
+Object::Object (const Object::point_list &pts, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint)
+ : m_id (id),
+ m_fmt_x (fmt_x), m_fmt_y (fmt_y), m_fmt (fmt),
+ m_style (style), m_outline (outline),
+ m_snap (snap), m_angle_constraint (angle_constraint),
+ m_main_position (POS_auto),
+ m_main_xalign (AL_auto), m_main_yalign (AL_auto),
+ m_xlabel_xalign (AL_auto), m_xlabel_yalign (AL_auto),
+ m_ylabel_xalign (AL_auto), m_ylabel_yalign (AL_auto)
+{
+ set_points (pts);
+}
+
+Object::Object (const db::DPoint &_p1, const db::DPoint &_p2, int id, const ant::Template &t)
+ : m_id (id),
m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()),
m_style (t.style ()), m_outline (t.outline ()),
m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()),
@@ -69,11 +83,26 @@ Object::Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::T
m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()),
m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ())
{
- // .. nothing else ..
+ p1 (_p1);
+ p2 (_p2);
+}
+
+Object::Object (const Object::point_list &pts, int id, const ant::Template &t)
+ : m_id (id),
+ m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()),
+ m_style (t.style ()), m_outline (t.outline ()),
+ m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()),
+ m_category (t.category ()),
+ m_main_position (t.main_position ()),
+ m_main_xalign (t.main_xalign ()), m_main_yalign (t.main_yalign ()),
+ m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()),
+ m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ())
+{
+ set_points (pts);
}
Object::Object (const ant::Object &d)
- : m_p1 (d.m_p1), m_p2 (d.m_p2), m_id (d.m_id),
+ : m_points (d.m_points), m_id (d.m_id),
m_fmt_x (d.m_fmt_x), m_fmt_y (d.m_fmt_y), m_fmt (d.m_fmt),
m_style (d.m_style), m_outline (d.m_outline),
m_snap (d.m_snap), m_angle_constraint (d.m_angle_constraint),
@@ -90,8 +119,7 @@ Object &
Object::operator= (const ant::Object &d)
{
if (this != &d) {
- m_p1 = d.m_p1;
- m_p2 = d.m_p2;
+ m_points = d.m_points;
m_id = d.m_id;
m_fmt_x = d.m_fmt_x;
m_fmt_y = d.m_fmt_y;
@@ -119,11 +147,8 @@ Object::operator< (const ant::Object &b) const
if (m_id != b.m_id) {
return m_id < b.m_id;
}
- if (m_p1 != b.m_p1) {
- return m_p1 < b.m_p1;
- }
- if (m_p2 != b.m_p2) {
- return m_p2 < b.m_p2;
+ if (m_points != b.m_points) {
+ return m_points < b.m_points;
}
if (m_fmt_x != b.m_fmt_x) {
return m_fmt_x < b.m_fmt_x;
@@ -187,7 +212,7 @@ Object::equals (const db::DUserObjectBase *d) const
bool
Object::operator== (const ant::Object &d) const
{
- return m_p1 == d.m_p1 && m_p2 == d.m_p2 && m_id == d.m_id &&
+ return m_points == d.m_points && m_id == d.m_id &&
m_fmt_x == d.m_fmt_x && m_fmt_y == d.m_fmt_y && m_fmt == d.m_fmt &&
m_style == d.m_style && m_outline == d.m_outline &&
m_snap == d.m_snap && m_angle_constraint == d.m_angle_constraint &&
@@ -199,6 +224,87 @@ Object::operator== (const ant::Object &d) const
;
}
+void
+Object::set_points (const point_list &points)
+{
+ point_list new_points;
+ auto p = points.begin ();
+ while (p != points.end ()) {
+ auto pp = p + 1;
+ while (pp != points.end () && *pp == *p) {
+ ++pp;
+ }
+ new_points.push_back (*p);
+ p = pp;
+ }
+
+ if (m_points != new_points) {
+ m_points = new_points;
+ property_changed ();
+ }
+}
+
+db::DPoint
+Object::seg_p1 (size_t seg_index) const
+{
+ if (seg_index < m_points.size ()) {
+ return m_points[seg_index];
+ } else if (m_points.empty ()) {
+ return db::DPoint ();
+ } else {
+ return m_points.back ();
+ }
+}
+
+db::DPoint
+Object::seg_p2 (size_t seg_index) const
+{
+ if (seg_index + 1 < m_points.size ()) {
+ return m_points[seg_index + 1];
+ } else if (m_points.empty ()) {
+ return db::DPoint ();
+ } else {
+ return m_points.back ();
+ }
+}
+
+void
+Object::p1 (const db::DPoint &p)
+{
+ if (! p1 ().equal (p)) {
+ if (m_points.size () < 1) {
+ m_points.push_back (p);
+ } else {
+ m_points.front () = p;
+ // makes sure there is only one point if p1 == p2
+ if (m_points.size () == 2 && m_points.back () == m_points.front ()) {
+ m_points.pop_back ();
+ }
+ }
+ property_changed ();
+ }
+}
+
+void
+Object::p2 (const db::DPoint &p)
+{
+ if (! p2 ().equal (p)) {
+ if (m_points.size () < 2) {
+ if (m_points.empty ()) {
+ m_points.push_back (db::DPoint ());
+ }
+ m_points.push_back (p);
+ } else {
+ m_points.back () = p;
+ }
+ // makes sure there is only one point if p1 == p2
+ if (m_points.size () == 2 && m_points.back () == m_points.front ()) {
+ m_points.pop_back ();
+ }
+ property_changed ();
+ }
+}
+
bool
Object::less (const db::DUserObjectBase *d) const
{
@@ -226,7 +332,11 @@ Object::clone () const
db::DBox
Object::box () const
{
- return db::DBox (m_p1, m_p2);
+ db::DBox bx;
+ for (auto d = m_points.begin (); d != m_points.end (); ++d) {
+ bx += *d;
+ }
+ return bx;
}
class AnnotationEval
@@ -245,38 +355,12 @@ private:
db::DFTrans m_trans;
};
-static double
-delta_x (const Object &obj, const db::DFTrans &t)
-{
- double dx = ((t * obj.p2 ()).x () - (t * obj.p1 ()).x ());
-
- // avoid "almost 0" outputs
- if (fabs (dx) < 1e-5 /*micron*/) {
- dx = 0;
- }
-
- return dx;
-}
-
-static double
-delta_y (const Object &obj, const db::DFTrans &t)
-{
- double dy = ((t * obj.p2 ()).y () - (t * obj.p1 ()).y ());
-
- // avoid "almost 0" outputs
- if (fabs (dy) < 1e-5 /*micron*/) {
- dy = 0;
- }
-
- return dy;
-}
-
class AnnotationEvalFunction
: public tl::EvalFunction
{
public:
- AnnotationEvalFunction (char function, const AnnotationEval *eval)
- : m_function (function), mp_eval (eval)
+ AnnotationEvalFunction (char function, const AnnotationEval *eval, size_t index)
+ : m_function (function), mp_eval (eval), m_index (index)
{
// .. nothing yet ..
}
@@ -301,36 +385,73 @@ public:
} else if (m_function == 'Y') {
out = delta_y (obj, trans);
} else if (m_function == 'U') {
- out = (trans * obj.p1 ()).x ();
+ out = (trans * p1 (obj)).x ();
} else if (m_function == 'V') {
- out = (trans * obj.p1 ()).y ();
+ out = (trans * p1 (obj)).y ();
} else if (m_function == 'P') {
- out = (trans * obj.p2 ()).x ();
+ out = (trans * p2 (obj)).x ();
} else if (m_function == 'Q') {
- out = (trans * obj.p2 ()).y ();
+ out = (trans * p2 (obj)).y ();
} else {
out = tl::Variant ();
}
}
+ db::DPoint p1 (const Object &obj) const
+ {
+ return obj.seg_p1 (m_index);
+ }
+
+ db::DPoint p2 (const Object &obj) const
+ {
+ return obj.seg_p2 (m_index);
+ }
+
+ double
+ delta_x (const Object &obj, const db::DFTrans &t) const
+ {
+ double dx = ((t * p2 (obj)).x () - (t * p1 (obj)).x ());
+
+ // avoid "almost 0" outputs
+ if (fabs (dx) < 1e-5 /*micron*/) {
+ dx = 0;
+ }
+
+ return dx;
+ }
+
+ double
+ delta_y (const Object &obj, const db::DFTrans &t) const
+ {
+ double dy = ((t * p2 (obj)).y () - (t * p1 (obj)).y ());
+
+ // avoid "almost 0" outputs
+ if (fabs (dy) < 1e-5 /*micron*/) {
+ dy = 0;
+ }
+
+ return dy;
+ }
+
private:
char m_function;
const AnnotationEval *mp_eval;
+ size_t m_index;
};
std::string
-Object::formatted (const std::string &fmt, const db::DFTrans &t) const
+Object::formatted (const std::string &fmt, const db::DFTrans &t, size_t index) const
{
AnnotationEval eval (*this, t);
- eval.define_function ("L", new AnnotationEvalFunction('L', &eval)); // manhattan length
- eval.define_function ("D", new AnnotationEvalFunction('D', &eval)); // euclidian distance
- eval.define_function ("X", new AnnotationEvalFunction('X', &eval)); // x delta
- eval.define_function ("Y", new AnnotationEvalFunction('Y', &eval)); // y delta
- eval.define_function ("U", new AnnotationEvalFunction('U', &eval)); // p1.x
- eval.define_function ("V", new AnnotationEvalFunction('V', &eval)); // p1.y
- eval.define_function ("P", new AnnotationEvalFunction('P', &eval)); // p2.x
- eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval)); // p2.y
- eval.define_function ("A", new AnnotationEvalFunction('A', &eval)); // area mm2
+ eval.define_function ("L", new AnnotationEvalFunction('L', &eval, index)); // manhattan length
+ eval.define_function ("D", new AnnotationEvalFunction('D', &eval, index)); // euclidian distance
+ eval.define_function ("X", new AnnotationEvalFunction('X', &eval, index)); // x delta
+ eval.define_function ("Y", new AnnotationEvalFunction('Y', &eval, index)); // y delta
+ eval.define_function ("U", new AnnotationEvalFunction('U', &eval, index)); // p1.x
+ eval.define_function ("V", new AnnotationEvalFunction('V', &eval, index)); // p1.y
+ eval.define_function ("P", new AnnotationEvalFunction('P', &eval, index)); // p2.x
+ eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval, index)); // p2.y
+ eval.define_function ("A", new AnnotationEvalFunction('A', &eval, index)); // area mm2
return eval.interpolate (fmt);
}
@@ -343,6 +464,9 @@ Object::class_name () const
void
Object::from_string (const char *s, const char * /*base_dir*/)
{
+ m_points.clear ();
+ point_list new_points;
+
tl::Extractor ex (s);
while (! ex.at_end ()) {
@@ -408,6 +532,14 @@ Object::from_string (const char *s, const char * /*base_dir*/)
p.set_y (q);
p2 (p);
+ } else if (ex.test ("pt=")) {
+
+ double x = 0.0, y = 0.0;
+ ex.read (x);
+ ex.expect (":");
+ ex.read (y);
+ new_points.push_back (db::DPoint (x, y));
+
} else if (ex.test ("position=")) {
std::string s;
@@ -518,6 +650,10 @@ Object::from_string (const char *s, const char * /*base_dir*/)
ex.test (",");
}
+
+ if (! new_points.empty ()) {
+ set_points (new_points);
+ }
}
std::string
@@ -529,18 +665,28 @@ Object::to_string () const
r += tl::to_string (id ());
r += ",";
- r += "x1=";
- r += tl::to_string (p1 ().x ());
- r += ",";
- r += "y1=";
- r += tl::to_string (p1 ().y ());
- r += ",";
- r += "x2=";
- r += tl::to_string (p2 ().x ());
- r += ",";
- r += "y2=";
- r += tl::to_string (p2 ().y ());
- r += ",";
+ if (m_points.size () > 2) {
+ for (auto p = m_points.begin (); p != m_points.end (); ++p) {
+ r += "pt=";
+ r += tl::to_string (p->x ());
+ r += ":";
+ r += tl::to_string (p->y ());
+ r += ",";
+ }
+ } else {
+ r += "x1=";
+ r += tl::to_string (p1 ().x ());
+ r += ",";
+ r += "y1=";
+ r += tl::to_string (p1 ().y ());
+ r += ",";
+ r += "x2=";
+ r += tl::to_string (p2 ().x ());
+ r += ",";
+ r += "y2=";
+ r += tl::to_string (p2 ().y ());
+ r += ",";
+ }
r += "category=";
r += tl::to_word_or_quoted_string (category ());
diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h
index 3fe1422a8..6358417c0 100644
--- a/src/ant/ant/antObject.h
+++ b/src/ant/ant/antObject.h
@@ -50,6 +50,7 @@ class ANT_PUBLIC Object
{
public:
typedef db::coord_traits coord_traits;
+ typedef std::vector point_list;
/**
* @brief The ruler style
@@ -109,11 +110,21 @@ public:
*/
Object (const db::DPoint &p1, const db::DPoint &p2, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint);
+ /**
+ * @brief Parametrized constructor and a list of points
+ */
+ Object (const point_list &points, int id, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint);
+
/**
* @brief Parametrized constructor from a template
*/
Object (const db::DPoint &p1, const db::DPoint &p2, int id, const ant::Template &d);
+ /**
+ * @brief Parametrized constructor from a template and a list of points
+ */
+ Object (const point_list &points, int id, const ant::Template &d);
+
/**
* @brief Copy constructor
*/
@@ -185,8 +196,9 @@ public:
*/
virtual void transform (const db::DCplxTrans &t)
{
- m_p1 = t * m_p1;
- m_p2 = t * m_p2;
+ for (auto p = m_points.begin (); p != m_points.end (); ++p) {
+ *p = t * *p;
+ }
property_changed ();
}
@@ -195,8 +207,9 @@ public:
*/
virtual void transform (const db::DTrans &t)
{
- m_p1 = t * m_p1;
- m_p2 = t * m_p2;
+ for (auto p = m_points.begin (); p != m_points.end (); ++p) {
+ *p = t * *p;
+ }
property_changed ();
}
@@ -205,8 +218,9 @@ public:
*/
virtual void transform (const db::DFTrans &t)
{
- m_p1 = t * m_p1;
- m_p2 = t * m_p2;
+ for (auto p = m_points.begin (); p != m_points.end (); ++p) {
+ *p = t * *p;
+ }
property_changed ();
}
@@ -224,10 +238,11 @@ public:
/**
* @brief Moves the object by the given distance
*/
- Object &move (const db::DVector &p)
+ Object &move (const db::DVector &d)
{
- m_p1 += p;
- m_p2 += p;
+ for (auto p = m_points.begin (); p != m_points.end (); ++p) {
+ *p += d;
+ }
return *this;
}
@@ -265,42 +280,71 @@ public:
}
/**
- * @brief Gets the first definition point
+ * @brief Gets the ruler's definition points
*/
- const db::DPoint &p1 () const
+ const point_list &points () const
{
- return m_p1;
+ return m_points;
+ }
+
+ /**
+ * @brief Sets the ruler's definition points
+ */
+ void set_points (const point_list &points);
+
+ /**
+ * @brief Gets the first point of the indicated segment
+ */
+ db::DPoint seg_p1 (size_t seg_index) const;
+
+ /**
+ * @brief Gets the second point of the indicated segment
+ */
+ db::DPoint seg_p2 (size_t seg_index) const;
+
+ /**
+ * @brief Gets the number of segments
+ *
+ * The number of segments is at least 1 for backward compatibility.
+ */
+ size_t segments () const
+ {
+ return m_points.size () < 2 ? 1 : m_points.size () - 1;
+ }
+
+ /**
+ * @brief Gets the first definition point
+ *
+ * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval.
+ */
+ db::DPoint p1 () const
+ {
+ return seg_p1 (0);
}
/**
* @brief Gets the second definition point
+ *
+ * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval.
*/
- const db::DPoint &p2 () const
+ db::DPoint p2 () const
{
- return m_p2;
+ return seg_p2 (0);
}
/**
* @brief Sets the first definition point
+ *
+ * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval.
*/
- void p1 (const db::DPoint &p)
- {
- if (!m_p1.equal (p)) {
- m_p1 = p;
- property_changed ();
- }
- }
+ void p1 (const db::DPoint &p);
/**
* @brief Sets the second definition point
+ *
+ * This method is provided for backward compatibility. Use the point list accessor for generic point retrieval.
*/
- void p2 (const db::DPoint &p)
- {
- if (!m_p2.equal (p)) {
- m_p2 = p;
- property_changed ();
- }
- }
+ void p2 (const db::DPoint &p);
/**
* @brief Gets the ID of the annotation object
@@ -619,52 +663,52 @@ public:
/**
* @brief Gets the formatted text for the x label
*/
- std::string text_x () const
+ std::string text_x (size_t index) const
{
- return formatted (m_fmt_x, db::DFTrans ());
+ return formatted (m_fmt_x, db::DFTrans (), index);
}
/**
* @brief Gets the formatted text for the y label
*/
- std::string text_y () const
+ std::string text_y (size_t index) const
{
- return formatted (m_fmt_y, db::DFTrans ());
+ return formatted (m_fmt_y, db::DFTrans (), index);
}
/**
* @brief Gets the formatted text for the main label
*/
- std::string text () const
+ std::string text (size_t index) const
{
- return formatted (m_fmt, db::DFTrans ());
+ return formatted (m_fmt, db::DFTrans (), index);
}
/**
* @brief Gets the formatted text for the x label
* @param t The transformation to apply to the vector before producing the text
*/
- std::string text_x (const db::DFTrans &t) const
+ std::string text_x (size_t index, const db::DFTrans &t) const
{
- return formatted (m_fmt_x, t);
+ return formatted (m_fmt_x, t, index);
}
/**
* @brief Gets the formatted text for the y label
* @param t The transformation to apply to the vector before producing the text
*/
- std::string text_y (const db::DFTrans &t) const
+ std::string text_y (size_t index, const db::DFTrans &t) const
{
- return formatted (m_fmt_y, t);
+ return formatted (m_fmt_y, t, index);
}
/**
* @brief Gets the formatted text for the main label
* @param t The transformation to apply to the vector before producing the text
*/
- std::string text (const db::DFTrans &t) const
+ std::string text (size_t index, const db::DFTrans &t) const
{
- return formatted (m_fmt, t);
+ return formatted (m_fmt, t, index);
}
/**
@@ -695,7 +739,7 @@ protected:
virtual void property_changed ();
private:
- db::DPoint m_p1, m_p2;
+ point_list m_points;
int m_id;
std::string m_fmt_x;
std::string m_fmt_y;
@@ -710,7 +754,7 @@ private:
alignment_type m_xlabel_xalign, m_xlabel_yalign;
alignment_type m_ylabel_xalign, m_ylabel_yalign;
- std::string formatted (const std::string &fmt, const db::DFTrans &trans) const;
+ std::string formatted (const std::string &fmt, const db::DFTrans &trans, size_t index) const;
};
}
diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc
index b381c9c11..7b81af0f0 100644
--- a/src/ant/ant/antPropertiesPage.cc
+++ b/src/ant/ant/antPropertiesPage.cc
@@ -25,6 +25,7 @@
#include "antPropertiesPage.h"
#include "layLayoutViewBase.h"
#include "layQtTools.h"
+#include "tlException.h"
namespace ant
{
@@ -33,7 +34,7 @@ namespace ant
// PropertiesPage implementation
PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWidget *parent)
- : lay::PropertiesPage (parent, manager, rulers), mp_rulers (rulers), m_enable_cb_callback (true)
+ : lay::PropertiesPage (parent, manager, rulers), mp_rulers (rulers), m_enable_cb_callback (true), m_in_text_changed (false)
{
mp_rulers->get_selection (m_selection);
m_pos = m_selection.begin ();
@@ -56,8 +57,10 @@ PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWid
connect (fmt_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (fmt_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (fmt_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
+ connect (x0, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x2, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
+ connect (y0, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (y1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (y2, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
@@ -71,6 +74,8 @@ PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWid
connect (ylabel_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (ylabel_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
+ connect (points_edit, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
+
} else {
fmt_le->setReadOnly (true);
@@ -172,6 +177,80 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
p2 = db::DPoint (dx2, dy2);
}
+void
+PropertiesPage::get_point (db::DPoint &p)
+{
+ double dx = 0.0, dy = 0.0;
+ bool has_error = false;
+
+ try {
+ tl::from_string_ext (tl::to_string (x0->text ()), dx);
+ lay::indicate_error (x0, (tl::Exception *) 0);
+ } catch (tl::Exception &ex) {
+ lay::indicate_error (x0, &ex);
+ has_error = true;
+ }
+
+ try {
+ tl::from_string_ext (tl::to_string (y0->text ()), dy);
+ lay::indicate_error (y0, (tl::Exception *) 0);
+ } catch (tl::Exception &ex) {
+ lay::indicate_error (y0, &ex);
+ has_error = true;
+ }
+
+ if (has_error) {
+ throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields")));
+ }
+
+ p = db::DPoint (dx, dy);
+}
+
+void
+PropertiesPage::get_points (ant::Object::point_list &points)
+{
+ std::string coordinates = tl::to_string (points_edit->toPlainText ());
+ points.clear ();
+
+ try {
+
+ tl::Extractor ex (coordinates.c_str ());
+ while (! ex.at_end ()) {
+ double x = 0.0, y = 0.0;
+ ex.read (x);
+ ex.test (",");
+ ex.read (y);
+ ex.test (";");
+ ex.test (",");
+ points.push_back (db::DPoint (x, y));
+ }
+
+ lay::indicate_error (points_edit, (tl::Exception *) 0);
+
+ } catch (tl::Exception &ex) {
+ lay::indicate_error (points_edit, &ex);
+ throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields")));
+ }
+}
+
+void
+PropertiesPage::text_changed ()
+{
+ if (m_in_text_changed) {
+ return;
+ }
+
+ try {
+ m_in_text_changed = true;
+ update_with (get_object ());
+ emit edited ();
+ m_in_text_changed = false;
+ } catch (...) {
+ m_in_text_changed = false;
+ // ignore exceptions - the edit field will be highlighted anyway
+ }
+}
+
void
PropertiesPage::snap_to_layout_clicked ()
{
@@ -296,32 +375,74 @@ void
PropertiesPage::update ()
{
mp_rulers->highlight (std::distance (m_selection.begin (), m_pos));
+ update_with (current ());
+}
- fmt_le->setText (tl::to_qstring (current ().fmt ()));
- fmt_x_le->setText (tl::to_qstring (current ().fmt_x ()));
- fmt_y_le->setText (tl::to_qstring (current ().fmt_y ()));
- style_cb->setCurrentIndex (current ().style ());
- outline_cb->setCurrentIndex (current ().outline ());
+void
+PropertiesPage::update_with (const ant::Object &obj)
+{
+ fmt_le->setText (tl::to_qstring (obj.fmt ()));
+ fmt_x_le->setText (tl::to_qstring (obj.fmt_x ()));
+ fmt_y_le->setText (tl::to_qstring (obj.fmt_y ()));
+ style_cb->setCurrentIndex (obj.style ());
+ outline_cb->setCurrentIndex (obj.outline ());
- x1->setText (tl::to_qstring (tl::micron_to_string (current ().p1 ().x ())));
+ main_position->setCurrentIndex (obj.main_position ());
+ main_xalign->setCurrentIndex (obj.main_xalign ());
+ main_yalign->setCurrentIndex (obj.main_yalign ());
+ xlabel_xalign->setCurrentIndex (obj.xlabel_xalign ());
+ xlabel_yalign->setCurrentIndex (obj.xlabel_yalign ());
+ ylabel_xalign->setCurrentIndex (obj.ylabel_xalign ());
+ ylabel_yalign->setCurrentIndex (obj.ylabel_yalign ());
+
+ int tab = 2;
+ if (obj.points ().size () == 1) {
+ tab = 0;
+ } else if (obj.points ().size () == 2) {
+ tab = 1;
+ }
+
+ segments_tab->setTabEnabled (0, tab == 0);
+ segments_tab->setTabEnabled (1, tab == 1);
+
+ if (! m_in_text_changed) {
+ segments_tab->setCurrentIndex (tab);
+ }
+
+ point_list->clear ();
+ for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
+ QTreeWidgetItem *item = new QTreeWidgetItem (point_list);
+ item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (tl::to_string (p->x ()))));
+ item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (tl::to_string (p->y ()))));
+ }
+
+ if (! m_in_text_changed) {
+ std::string text;
+ for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
+ text += tl::to_string (p->x ());
+ text += ", ";
+ text += tl::to_string (p->y ());
+ text += "\n";
+ }
+ points_edit->setPlainText (tl::to_qstring (text));
+ }
+
+ x0->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().x ())));
+ x0->setCursorPosition (0);
+ y0->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().y ())));
+ y0->setCursorPosition (0);
+
+ x1->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().x ())));
x1->setCursorPosition (0);
- x2->setText (tl::to_qstring (tl::micron_to_string (current ().p2 ().x ())));
+ x2->setText (tl::to_qstring (tl::micron_to_string (obj.p2 ().x ())));
x2->setCursorPosition (0);
- y1->setText (tl::to_qstring (tl::micron_to_string (current ().p1 ().y ())));
+ y1->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().y ())));
y1->setCursorPosition (0);
- y2->setText (tl::to_qstring (tl::micron_to_string (current ().p2 ().y ())));
+ y2->setText (tl::to_qstring (tl::micron_to_string (obj.p2 ().y ())));
y2->setCursorPosition (0);
- main_position->setCurrentIndex (current ().main_position ());
- main_xalign->setCurrentIndex (current ().main_xalign ());
- main_yalign->setCurrentIndex (current ().main_yalign ());
- xlabel_xalign->setCurrentIndex (current ().xlabel_xalign ());
- xlabel_yalign->setCurrentIndex (current ().xlabel_yalign ());
- ylabel_xalign->setCurrentIndex (current ().ylabel_xalign ());
- ylabel_yalign->setCurrentIndex (current ().ylabel_yalign ());
-
- double sx = (current ().p2 ().x () - current ().p1 ().x ());
- double sy = (current ().p2 ().y () - current ().p1 ().y ());
+ double sx = (obj.p2 ().x () - obj.p1 ().x ());
+ double sy = (obj.p2 ().y () - obj.p1 ().y ());
dx->setText (tl::to_qstring (tl::micron_to_string (sx)));
dx->setCursorPosition (0);
dy->setText (tl::to_qstring (tl::micron_to_string (sy)));
@@ -339,9 +460,13 @@ PropertiesPage::readonly ()
void
PropertiesPage::apply ()
{
- // only adjust the values if the text has changed
- db::DPoint p1, p2;
- get_points (p1, p2);
+ mp_rulers->change_ruler (*m_pos, get_object ());
+}
+
+ant::Object
+PropertiesPage::get_object ()
+{
+ ant::Object ruler;
std::string fmt = tl::to_string (fmt_le->text ());
std::string fmt_x = tl::to_string (fmt_x_le->text ());
@@ -349,7 +474,26 @@ PropertiesPage::apply ()
Object::style_type style = Object::style_type (style_cb->currentIndex ());
Object::outline_type outline = Object::outline_type (outline_cb->currentIndex ());
- ant::Object ruler (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
+ if (segments_tab->currentIndex () == 0 || segments_tab->currentIndex () == 1) {
+
+ db::DPoint p1, p2;
+ if (segments_tab->currentIndex () == 0) {
+ get_points (p1, p2);
+ } else {
+ get_point (p1);
+ p2 = p1;
+ }
+
+ ruler = ant::Object (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
+
+ } else if (segments_tab->currentIndex () == 2 || segments_tab->currentIndex () == 3) {
+
+ ant::Object::point_list points;
+ get_points (points);
+
+ ruler = ant::Object (points, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
+
+ }
ruler.set_main_position (Object::position_type (main_position->currentIndex ()));
ruler.set_main_xalign (Object::alignment_type (main_xalign->currentIndex ()));
@@ -361,7 +505,7 @@ PropertiesPage::apply ()
ruler.set_category (current ().category ());
- mp_rulers->change_ruler (*m_pos, ruler);
+ return ruler;
}
}
diff --git a/src/ant/ant/antPropertiesPage.h b/src/ant/ant/antPropertiesPage.h
index 8e50f4dc4..26e351e2d 100644
--- a/src/ant/ant/antPropertiesPage.h
+++ b/src/ant/ant/antPropertiesPage.h
@@ -52,20 +52,26 @@ public:
virtual void update ();
virtual void leave ();
virtual bool readonly ();
- virtual void apply ();
+ virtual void apply ();
private slots:
void swap_points_clicked ();
void snap_to_layout_clicked ();
+ void text_changed ();
private:
std::vector m_selection;
std::vector ::iterator m_pos;
ant::Service *mp_rulers;
bool m_enable_cb_callback;
+ bool m_in_text_changed;
const ant::Object ¤t () const;
- void get_points(db::DPoint &p1, db::DPoint &p2);
+ void get_points (db::DPoint &p1, db::DPoint &p2);
+ void get_point (db::DPoint &p);
+ void get_points (ant::Object::point_list &points);
+ void update_with (const ant::Object &obj);
+ ant::Object get_object ();
};
}
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index b7a4f55a9..a93c05885 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -570,21 +570,23 @@ draw_ellipse (const db::DPoint &q1,
}
void
-draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
+draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
+ db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index);
+
// round the starting point, shift both, and round the end point
- std::pair v = lay::snap (trans * ruler.p1 (), trans * ruler.p2 ());
+ std::pair v = lay::snap (trans * p1, trans * p2);
db::DPoint q1 = v.first;
db::DPoint q2 = v.second;
bool xy_swapped = ((trans.rot () % 2) != 0);
- double lu = ruler.p1 ().double_distance (ruler.p2 ());
+ double lu = p1.double_distance (p2);
int min_tick_spc = int (0.5 + 20 / renderer.resolution ()); // min tick spacing in canvas units
double mu = double (min_tick_spc) / trans.ctrans (1.0);
if (ruler.outline () == Object::OL_diag) {
draw_ruler (q1, q2, lu, mu, sel, q2.x () < q1.x (), ruler.style (), bitmap, renderer);
- draw_text (q1, q2, lu, ruler.text (), q2.x () < q1.x (), ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+ draw_text (q1, q2, lu, ruler.text (index), q2.x () < q1.x (), ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
}
if ((!xy_swapped && (ruler.outline () == Object::OL_xy || ruler.outline () == Object::OL_diag_xy)) ||
@@ -594,12 +596,12 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay
if (ruler.outline () == Object::OL_diag_xy || ruler.outline () == Object::OL_diag_yx) {
draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer);
- draw_text (q1, q2, lu, ruler.text (), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+ draw_text (q1, q2, lu, ruler.text (index), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
}
draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer);
- draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
+ draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer);
- draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
+ draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
}
@@ -610,12 +612,12 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay
if (ruler.outline () == Object::OL_diag_xy || ruler.outline () == Object::OL_diag_yx) {
draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer);
- draw_text (q1, q2, lu, ruler.text (), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+ draw_text (q1, q2, lu, ruler.text (index), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
}
draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer);
- draw_text (q1, db::DPoint (q1.x (), q2.y ()), lu, ruler.text_y (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
+ draw_text (q1, db::DPoint (q1.x (), q2.y ()), lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer);
- draw_text (db::DPoint (q1.x (), q2.y ()), q2, lu, ruler.text_x (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
+ draw_text (db::DPoint (q1.x (), q2.y ()), q2, lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
}
@@ -624,34 +626,43 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay
bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer);
- draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
+ draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer);
- draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
+ draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, !r, ruler.style (), bitmap, renderer);
draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer);
- draw_text (q1, q2, lu, ruler.text (), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+ draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
} else if (ruler.outline () == Object::OL_ellipse) {
bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
- draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
- draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
- draw_text (q1, q2, lu, ruler.text (), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+ draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
+ draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
+ draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
draw_ellipse (q1, q2, lu, sel, bitmap, renderer);
}
}
-static bool
-is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance)
+void
+draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
+ for (size_t index = 0; index < ruler.segments (); ++index) {
+ draw_ruler_segment (ruler, index, trans, sel, bitmap, renderer);
+ }
+}
+
+static bool
+is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, double enl, double &distance)
+{
+ db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index);
+ db::DBox b (p1, p2);
+
if (ruler.outline () == ant::Object::OL_ellipse) {
// special handling of the (non-degenerated) ellipse case
- db::DBox b (ruler.p1 (), ruler.p2 ());
-
if (b.height () > 1e-6 && b.width () > 1e-6) {
double dx = (pos.x () - b.center ().x ()) / (b.width () * 0.5);
@@ -674,8 +685,6 @@ is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double
}
- db::DBox b (ruler.p1 (), ruler.p2 ());
-
// enlarge this box by some pixels
b.enlarge (db::DVector (enl, enl));
@@ -717,10 +726,23 @@ is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double
return false;
}
+static bool
+is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance)
+{
+ bool any = false;
+ for (size_t index = 0; index < ruler.segments (); ++index) {
+ // NOTE: we check *all* since distance is updated herein.
+ if (is_selected (ruler, index, pos, enl, distance)) {
+ any = true;
+ }
+ }
+ return any;
+}
+
static bool
is_selected (const ant::Object &ruler, const db::DBox &box, double /*enl*/)
{
- return (box.contains (ruler.p1 ()) && box.contains (ruler.p2 ()));
+ return ruler.box ().inside (box);
}
@@ -2180,7 +2202,11 @@ Service::display_status (bool transient)
if (! transient) {
msg = tl::to_string (tr ("selected: "));
}
- msg += tl::sprintf (tl::to_string (tr ("annotation(d=%s x=%s y=%s)")), ruler->text (), ruler->text_x (), ruler->text_y ());
+ if (ruler->segments () > 1) {
+ msg += tl::sprintf (tl::to_string (tr ("annotation(d=%s x=%s y=%s ...)")), ruler->text (0), ruler->text_x (0), ruler->text_y (0));
+ } else {
+ msg += tl::sprintf (tl::to_string (tr ("annotation(d=%s x=%s y=%s)")), ruler->text (0), ruler->text_x (0), ruler->text_y (0));
+ }
view ()->message (msg);
}
diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc
index a1284d3ff..949cb5c09 100644
--- a/src/ant/ant/gsiDeclAnt.cc
+++ b/src/ant/ant/gsiDeclAnt.cc
@@ -236,6 +236,13 @@ static AnnotationRef create_measure_ruler (lay::LayoutViewBase *view, const db::
}
}
+static AnnotationRef *ant_from_s (const std::string &s)
+{
+ std::unique_ptr aref (new AnnotationRef ());
+ aref->from_string (s.c_str ());
+ return aref.release ();
+}
+
static int get_style (const AnnotationRef *obj)
{
return int (obj->style ());
@@ -704,27 +711,80 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"\n"
"This method has been introduced in version 0.25."
) +
- gsi::method ("p1", (const db::DPoint & (AnnotationRef::*) () const) &AnnotationRef::p1,
+ gsi::method ("points", &AnnotationRef::points,
+ "@brief Gets the points of the ruler\n"
+ "A single-segmented ruler has two points. Rulers with more points "
+ "have more segments correspondingly. Note that the point list may have one point "
+ "only (single-point ruler) or may even be empty.\n"
+ "\n"
+ "Use \\points= to set the segment points. Use \\segments to get the number of "
+ "segments and \\seg_p1 and \\seg_p2 to get the first and second point of one segment.\n"
+ "\n"
+ "Multi-segmented rulers have been introduced in version 0.28"
+ ) +
+ gsi::method ("points=", &AnnotationRef::set_points, gsi::arg ("points"),
+ "@brief Sets the points for a (potentially) multi-segmented ruler\n"
+ "See \\points for a description of multi-segmented rulers. "
+ "The list of points passed to this method is cleaned from duplicates before being "
+ "stored inside the ruler.\n"
+ "\n"
+ "This method has been introduced in version 0.28."
+ ) +
+ gsi::method ("segments", &AnnotationRef::segments,
+ "@brief Gets the number of segments.\n"
+ "This method returns the number of segments the ruler is made up. Even though the "
+ "ruler can be one or even zero points, the number of segments is at least 1.\n"
+ "\n"
+ "This method has been introduced in version 0.28."
+ ) +
+ gsi::method ("seg_p1", &AnnotationRef::seg_p1, gsi::arg ("segment_index"),
+ "@brief Gets the first point of the given segment.\n"
+ "The segment is indicated by the segment index which is a number between 0 and \\segments-1.\n"
+ "\n"
+ "This method has been introduced in version 0.28."
+ ) +
+ gsi::method ("seg_p2", &AnnotationRef::seg_p2, gsi::arg ("segment_index"),
+ "@brief Gets the second point of the given segment.\n"
+ "The segment is indicated by the segment index which is a number between 0 and \\segments-1.\n"
+ "The second point of a segment is also the first point of the following segment if there is one.\n"
+ "\n"
+ "This method has been introduced in version 0.28."
+ ) +
+ gsi::method ("p1", (db::DPoint (AnnotationRef::*) () const) &AnnotationRef::p1,
"@brief Gets the first point of the ruler or marker\n"
"The points of the ruler or marker are always given in micron units in floating-point "
"coordinates.\n"
+ "\n"
+ "This method is provided for backward compatibility. Starting with version 0.28, rulers can "
+ "be multi-segmented. Use \\points or \\seg_p1 to retrieve the points of the ruler segments.\n"
+ "\n"
"@return The first point\n"
) +
- gsi::method ("p2", (const db::DPoint & (AnnotationRef::*) () const) &AnnotationRef::p2,
+ gsi::method ("p2", (db::DPoint (AnnotationRef::*) () const) &AnnotationRef::p2,
"@brief Gets the second point of the ruler or marker\n"
"The points of the ruler or marker are always given in micron units in floating-point "
"coordinates.\n"
+ "\n"
+ "This method is provided for backward compatibility. Starting with version 0.28, rulers can "
+ "be multi-segmented. Use \\points or \\seg_p1 to retrieve the points of the ruler segments.\n"
+ "\n"
"@return The second point\n"
) +
gsi::method ("p1=", (void (AnnotationRef::*) (const db::DPoint &)) &AnnotationRef::p1, gsi::arg ("point"),
"@brief Sets the first point of the ruler or marker\n"
"The points of the ruler or marker are always given in micron units in floating-point "
"coordinates.\n"
+ "\n"
+ "This method is provided for backward compatibility. Starting with version 0.28, rulers can "
+ "be multi-segmented. Use \\points= to specify the ruler segments.\n"
) +
gsi::method ("p2=", (void (AnnotationRef::*) (const db::DPoint &)) &AnnotationRef::p2, gsi::arg ("point"),
"@brief Sets the second point of the ruler or marker\n"
"The points of the ruler or marker are always given in micron units in floating-point "
"coordinates.\n"
+ "\n"
+ "This method is provided for backward compatibility. Starting with version 0.28, rulers can "
+ "be multi-segmented. Use \\points= to specify the ruler segments.\n"
) +
gsi::method ("box", &AnnotationRef::box,
"@brief Gets the bounding box of the object (not including text)\n"
@@ -924,14 +984,17 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"@brief Returns the angle constraint attribute\n"
"See \\angle_constraint= for a more detailed description."
) +
- gsi::method ("text_x", (std::string (AnnotationRef::*)() const) &AnnotationRef::text_x,
- "@brief Returns the formatted text for the x-axis label"
+ gsi::method ("text_x", (std::string (AnnotationRef::*)(size_t index) const) &AnnotationRef::text_x, gsi::arg ("index", 0),
+ "@brief Returns the formatted text for the x-axis label\n"
+ "The index parameter indicates which segment to use (0 is the first one). It has been added in version 0.28.\n"
) +
- gsi::method ("text_y", (std::string (AnnotationRef::*)() const) &AnnotationRef::text_y,
- "@brief Returns the formatted text for the y-axis label"
+ gsi::method ("text_y", (std::string (AnnotationRef::*)(size_t index) const) &AnnotationRef::text_y, gsi::arg ("index", 0),
+ "@brief Returns the formatted text for the y-axis label\n"
+ "The index parameter indicates which segment to use (0 is the first one). It has been added in version 0.28.\n"
) +
- gsi::method ("text", (std::string (AnnotationRef::*)() const) &AnnotationRef::text,
- "@brief Returns the formatted text for the main label"
+ gsi::method ("text", (std::string (AnnotationRef::*)(size_t index) const) &AnnotationRef::text, gsi::arg ("index", 0),
+ "@brief Returns the formatted text for the main label\n"
+ "The index parameter indicates which segment to use (0 is the first one). It has been added in version 0.28.\n"
) +
gsi::method ("id", (int (AnnotationRef::*)() const) &AnnotationRef::id,
"@brief Returns the annotation's ID"
@@ -953,6 +1016,12 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"\n"
"This method was introduced in version 0.19."
) +
+ gsi::constructor ("from_s", &ant_from_s, gsi::arg ("s"),
+ "@brief Creates a ruler from a string representation\n"
+ "This function creates a ruler from the string returned by \\to_s.\n"
+ "\n"
+ "This method was introduced in version 0.28."
+ ) +
gsi::method ("==", &AnnotationRef::operator==, gsi::arg ("other"),
"@brief Equality operator\n"
) +
From 1c8a99fa269a8906d24764a345606422f3604f36 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 26 Sep 2022 23:52:32 +0200
Subject: [PATCH 10/54] WIP: some bug fixing
---
src/ant/ant/antPropertiesPage.cc | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc
index 7b81af0f0..035755297 100644
--- a/src/ant/ant/antPropertiesPage.cc
+++ b/src/ant/ant/antPropertiesPage.cc
@@ -402,9 +402,6 @@ PropertiesPage::update_with (const ant::Object &obj)
tab = 1;
}
- segments_tab->setTabEnabled (0, tab == 0);
- segments_tab->setTabEnabled (1, tab == 1);
-
if (! m_in_text_changed) {
segments_tab->setCurrentIndex (tab);
}
@@ -412,19 +409,23 @@ PropertiesPage::update_with (const ant::Object &obj)
point_list->clear ();
for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
QTreeWidgetItem *item = new QTreeWidgetItem (point_list);
- item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (tl::to_string (p->x ()))));
- item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (tl::to_string (p->y ()))));
+ item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (tl::micron_to_string (p->x ()))));
+ item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (tl::micron_to_string (p->y ()))));
}
if (! m_in_text_changed) {
+
std::string text;
for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
- text += tl::to_string (p->x ());
+ text += tl::micron_to_string (p->x ());
text += ", ";
- text += tl::to_string (p->y ());
+ text += tl::micron_to_string (p->y ());
text += "\n";
}
+
+ QSignalBlocker blocker (points_edit);
points_edit->setPlainText (tl::to_qstring (text));
+
}
x0->setText (tl::to_qstring (tl::micron_to_string (obj.p1 ().x ())));
@@ -477,7 +478,7 @@ PropertiesPage::get_object ()
if (segments_tab->currentIndex () == 0 || segments_tab->currentIndex () == 1) {
db::DPoint p1, p2;
- if (segments_tab->currentIndex () == 0) {
+ if (segments_tab->currentIndex () == 1) {
get_points (p1, p2);
} else {
get_point (p1);
From 79102d399e468d08fa3c033aaf71f949be228b86 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 27 Sep 2022 22:56:34 +0200
Subject: [PATCH 11/54] WIP: enhancements, debugging of multi-segment rulers
setup
---
src/ant/ant/antObject.cc | 8 +-
src/ant/ant/antObject.h | 2 +-
src/ant/ant/antPropertiesPage.cc | 146 +++++++++++++++++++------------
src/ant/ant/antPropertiesPage.h | 6 +-
src/ant/ant/antService.cc | 104 ++++++++++++++--------
5 files changed, 171 insertions(+), 95 deletions(-)
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index 5603de0d8..1dedd9281 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -247,7 +247,9 @@ Object::set_points (const point_list &points)
db::DPoint
Object::seg_p1 (size_t seg_index) const
{
- if (seg_index < m_points.size ()) {
+ if (seg_index == std::numeric_limits::max ()) {
+ return p1 ();
+ } else if (seg_index < m_points.size ()) {
return m_points[seg_index];
} else if (m_points.empty ()) {
return db::DPoint ();
@@ -259,7 +261,9 @@ Object::seg_p1 (size_t seg_index) const
db::DPoint
Object::seg_p2 (size_t seg_index) const
{
- if (seg_index + 1 < m_points.size ()) {
+ if (seg_index == std::numeric_limits::max ()) {
+ return p2 ();
+ } else if (seg_index + 1 < m_points.size ()) {
return m_points[seg_index + 1];
} else if (m_points.empty ()) {
return db::DPoint ();
diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h
index 6358417c0..7304c5bed 100644
--- a/src/ant/ant/antObject.h
+++ b/src/ant/ant/antObject.h
@@ -329,7 +329,7 @@ public:
*/
db::DPoint p2 () const
{
- return seg_p2 (0);
+ return seg_p2 (segments () - 1);
}
/**
diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc
index 035755297..7e55c2afc 100644
--- a/src/ant/ant/antPropertiesPage.cc
+++ b/src/ant/ant/antPropertiesPage.cc
@@ -30,11 +30,39 @@
namespace ant
{
+// -------------------------------------------------------------------------
+// A ruler that tells us if he was modified
+
+class RulerWithModifiedProperty
+ : public ant::Object
+{
+public:
+ RulerWithModifiedProperty ()
+ : ant::Object (), m_modified (false)
+ {
+ // .. nothing yet ..
+ }
+
+ bool is_modified () const
+ {
+ return m_modified;
+ }
+
+protected:
+ void property_changed ()
+ {
+ m_modified = true;
+ ant::Object::property_changed ();
+ }
+
+ bool m_modified;
+};
+
// -------------------------------------------------------------------------
// PropertiesPage implementation
PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWidget *parent)
- : lay::PropertiesPage (parent, manager, rulers), mp_rulers (rulers), m_enable_cb_callback (true), m_in_text_changed (false)
+ : lay::PropertiesPage (parent, manager, rulers), mp_rulers (rulers), m_enable_cb_callback (true), m_in_something_changed (false)
{
mp_rulers->get_selection (m_selection);
m_pos = m_selection.begin ();
@@ -54,27 +82,27 @@ PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWid
if (! readonly ()) {
- connect (fmt_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (fmt_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (fmt_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (x0, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (x1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (x2, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (y0, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (y1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
- connect (y2, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
+ connect (fmt_le, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (fmt_x_le, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (fmt_y_le, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (x0, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (x1, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (x2, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (y0, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (y1, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
+ connect (y2, SIGNAL (editingFinished ()), this, SLOT (something_changed ()));
- connect (style_cb, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (outline_cb, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (main_position, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (main_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (main_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (xlabel_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (xlabel_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (ylabel_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
- connect (ylabel_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
+ connect (style_cb, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (outline_cb, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (main_position, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (main_xalign, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (main_yalign, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (xlabel_xalign, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (xlabel_yalign, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (ylabel_xalign, SIGNAL (activated (int)), this, SLOT (something_changed ()));
+ connect (ylabel_yalign, SIGNAL (activated (int)), this, SLOT (something_changed ()));
- connect (points_edit, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
+ connect (points_edit, SIGNAL (textChanged ()), this, SLOT (something_changed ()));
} else {
@@ -234,19 +262,28 @@ PropertiesPage::get_points (ant::Object::point_list &points)
}
void
-PropertiesPage::text_changed ()
+PropertiesPage::something_changed ()
{
- if (m_in_text_changed) {
+ if (m_in_something_changed) {
return;
}
try {
- m_in_text_changed = true;
- update_with (get_object ());
- emit edited ();
- m_in_text_changed = false;
+
+ m_in_something_changed = true;
+
+ RulerWithModifiedProperty obj;
+ obj.ant::Object::operator= (current ());
+ get_object (obj);
+ if (obj.is_modified ()) {
+ update_with (obj);
+ emit edited ();
+ }
+
+ m_in_something_changed = false;
+
} catch (...) {
- m_in_text_changed = false;
+ m_in_something_changed = false;
// ignore exceptions - the edit field will be highlighted anyway
}
}
@@ -395,16 +432,20 @@ PropertiesPage::update_with (const ant::Object &obj)
ylabel_xalign->setCurrentIndex (obj.ylabel_xalign ());
ylabel_yalign->setCurrentIndex (obj.ylabel_yalign ());
- int tab = 2;
- if (obj.points ().size () == 1) {
- tab = 0;
- } else if (obj.points ().size () == 2) {
- tab = 1;
- }
-
- if (! m_in_text_changed) {
- segments_tab->setCurrentIndex (tab);
+ // change tabs if required
+ if (segments_tab->currentIndex () == 1) {
+ if (obj.points ().size () > 2 || obj.points ().size () == 0) {
+ segments_tab->setCurrentIndex (2);
+ }
+ } else if (segments_tab->currentIndex () == 0) {
+ if (obj.points ().size () > 2 || obj.points ().size () == 0) {
+ segments_tab->setCurrentIndex (2);
+ } else if (obj.points ().size () > 1) {
+ segments_tab->setCurrentIndex (1);
+ }
}
+ segments_tab->setTabEnabled (0, obj.points ().size () == 1);
+ segments_tab->setTabEnabled (1, obj.points ().size () <= 2 && obj.points ().size () > 0);
point_list->clear ();
for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
@@ -413,7 +454,7 @@ PropertiesPage::update_with (const ant::Object &obj)
item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (tl::micron_to_string (p->y ()))));
}
- if (! m_in_text_changed) {
+ if (! m_in_something_changed || segments_tab->currentIndex () != 3) {
std::string text;
for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
@@ -461,14 +502,13 @@ PropertiesPage::readonly ()
void
PropertiesPage::apply ()
{
- mp_rulers->change_ruler (*m_pos, get_object ());
+ ant::Object obj;
+ get_object (obj);
+ mp_rulers->change_ruler (*m_pos, obj);
}
-ant::Object
-PropertiesPage::get_object ()
+void PropertiesPage::get_object(ant::Object &obj)
{
- ant::Object ruler;
-
std::string fmt = tl::to_string (fmt_le->text ());
std::string fmt_x = tl::to_string (fmt_x_le->text ());
std::string fmt_y = tl::to_string (fmt_y_le->text ());
@@ -485,28 +525,26 @@ PropertiesPage::get_object ()
p2 = p1;
}
- ruler = ant::Object (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
+ obj = ant::Object (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
} else if (segments_tab->currentIndex () == 2 || segments_tab->currentIndex () == 3) {
ant::Object::point_list points;
get_points (points);
- ruler = ant::Object (points, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
+ obj = ant::Object (points, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
}
- ruler.set_main_position (Object::position_type (main_position->currentIndex ()));
- ruler.set_main_xalign (Object::alignment_type (main_xalign->currentIndex ()));
- ruler.set_main_yalign (Object::alignment_type (main_yalign->currentIndex ()));
- ruler.set_xlabel_xalign (Object::alignment_type (xlabel_xalign->currentIndex ()));
- ruler.set_xlabel_yalign (Object::alignment_type (xlabel_yalign->currentIndex ()));
- ruler.set_ylabel_xalign (Object::alignment_type (ylabel_xalign->currentIndex ()));
- ruler.set_ylabel_yalign (Object::alignment_type (ylabel_yalign->currentIndex ()));
+ obj.set_main_position (Object::position_type (main_position->currentIndex ()));
+ obj.set_main_xalign (Object::alignment_type (main_xalign->currentIndex ()));
+ obj.set_main_yalign (Object::alignment_type (main_yalign->currentIndex ()));
+ obj.set_xlabel_xalign (Object::alignment_type (xlabel_xalign->currentIndex ()));
+ obj.set_xlabel_yalign (Object::alignment_type (xlabel_yalign->currentIndex ()));
+ obj.set_ylabel_xalign (Object::alignment_type (ylabel_xalign->currentIndex ()));
+ obj.set_ylabel_yalign (Object::alignment_type (ylabel_yalign->currentIndex ()));
- ruler.set_category (current ().category ());
-
- return ruler;
+ obj.set_category (current ().category ());
}
}
diff --git a/src/ant/ant/antPropertiesPage.h b/src/ant/ant/antPropertiesPage.h
index 26e351e2d..1f1ead4da 100644
--- a/src/ant/ant/antPropertiesPage.h
+++ b/src/ant/ant/antPropertiesPage.h
@@ -57,21 +57,21 @@ public:
private slots:
void swap_points_clicked ();
void snap_to_layout_clicked ();
- void text_changed ();
+ void something_changed ();
private:
std::vector m_selection;
std::vector ::iterator m_pos;
ant::Service *mp_rulers;
bool m_enable_cb_callback;
- bool m_in_text_changed;
+ bool m_in_something_changed;
const ant::Object ¤t () const;
void get_points (db::DPoint &p1, db::DPoint &p2);
void get_point (db::DPoint &p);
void get_points (ant::Object::point_list &points);
void update_with (const ant::Object &obj);
- ant::Object get_object ();
+ void get_object (ant::Object &obj);
};
}
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index a93c05885..ffd1e22cb 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -113,6 +113,8 @@ tick_spacings (double d, double min_d, int &minor_ticks, double &ticks)
* @param pos The position where to draw the text
* @param bitmap The bitmap to draw the ruler on
* @param renderer The renderer object
+ * @param first_segment True, if we're drawing the first segment
+ * @param last_segment True, if we're drawing the last segment
*/
void
draw_ruler (const db::DPoint &q1,
@@ -123,7 +125,9 @@ draw_ruler (const db::DPoint &q1,
bool right,
ant::Object::style_type style,
lay::CanvasPlane *bitmap,
- lay::Renderer &renderer)
+ lay::Renderer &renderer,
+ bool first_segment,
+ bool last_segment)
{
double arrow_width = 8 / renderer.resolution ();
double arrow_length = 12 / renderer.resolution ();
@@ -189,12 +193,16 @@ draw_ruler (const db::DPoint &q1,
db::DVector qw = qq * (sel_width * 0.5);
db::DVector dq1, dq2;
- if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_start) {
+ if (! first_segment) {
+ // no start indicator if not first segment
+ } else if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_start) {
dq1 = qu * (arrow_length - 1);
} else if (style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_start) {
dq1 = qu * (sel_width * 0.5);
}
- if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_end) {
+ if (! last_segment) {
+ // no end indicator if not last segment
+ } else if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_end) {
dq2 = qu * -(arrow_length - 1);
} else if (style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_end) {
dq2 = qu * -(sel_width * 0.5);
@@ -212,7 +220,11 @@ draw_ruler (const db::DPoint &q1,
}
- if (style == ant::Object::STY_arrow_end || style == ant::Object::STY_arrow_both) {
+ if (! last_segment) {
+
+ // no end indicator if not last segment
+
+ } else if (style == ant::Object::STY_arrow_end || style == ant::Object::STY_arrow_both) {
db::DPolygon p;
db::DPoint points[] = {
@@ -239,7 +251,11 @@ draw_ruler (const db::DPoint &q1,
}
- if (style == ant::Object::STY_arrow_start || style == ant::Object::STY_arrow_both) {
+ if (! first_segment) {
+
+ // no start indicator if not first segment
+
+ } else if (style == ant::Object::STY_arrow_start || style == ant::Object::STY_arrow_both) {
db::DPolygon p;
db::DPoint points[] = {
@@ -572,6 +588,9 @@ draw_ellipse (const db::DPoint &q1,
void
draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
+ bool last_segment = (index == ruler.segments () - 1 || index == std::numeric_limits::max ());
+ bool first_segment = (index == 0 || index == std::numeric_limits::max ());
+
db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index);
// round the starting point, shift both, and round the end point
@@ -585,7 +604,7 @@ draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans
double mu = double (min_tick_spc) / trans.ctrans (1.0);
if (ruler.outline () == Object::OL_diag) {
- draw_ruler (q1, q2, lu, mu, sel, q2.x () < q1.x (), ruler.style (), bitmap, renderer);
+ draw_ruler (q1, q2, lu, mu, sel, q2.x () < q1.x (), ruler.style (), bitmap, renderer, first_segment, last_segment);
draw_text (q1, q2, lu, ruler.text (index), q2.x () < q1.x (), ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
}
@@ -595,12 +614,12 @@ draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans
bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
if (ruler.outline () == Object::OL_diag_xy || ruler.outline () == Object::OL_diag_yx) {
- draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer);
+ draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer, first_segment, last_segment);
draw_text (q1, q2, lu, ruler.text (index), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
}
- draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer);
+ draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer, false, false);
draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
- draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer);
+ draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer, false, false);
draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
}
@@ -611,12 +630,12 @@ draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans
bool r = (q2.x () > q1.x ()) ^ (q2.y () > q1.y ());
if (ruler.outline () == Object::OL_diag_xy || ruler.outline () == Object::OL_diag_yx) {
- draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer);
+ draw_ruler (q1, q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer, first_segment, last_segment);
draw_text (q1, q2, lu, ruler.text (index), !r, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
}
- draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer);
+ draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer, false, false);
draw_text (q1, db::DPoint (q1.x (), q2.y ()), lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
- draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer);
+ draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer, false, false);
draw_text (db::DPoint (q1.x (), q2.y ()), q2, lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
}
@@ -625,12 +644,12 @@ draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans
bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
- draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer);
+ draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer, true, true);
draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
- draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer);
+ draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer, true, true);
draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
- draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, !r, ruler.style (), bitmap, renderer);
- draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer);
+ draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, !r, ruler.style (), bitmap, renderer, true, true);
+ draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer, true, true);
draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
} else if (ruler.outline () == Object::OL_ellipse) {
@@ -649,18 +668,29 @@ draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans
void
draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
- for (size_t index = 0; index < ruler.segments (); ++index) {
- draw_ruler_segment (ruler, index, trans, sel, bitmap, renderer);
+ if (ruler.outline () == Object::OL_box || ruler.outline () == Object::OL_ellipse) {
+
+ draw_ruler_segment (ruler, std::numeric_limits::max (), trans, sel, bitmap, renderer);
+
+ } else {
+
+ // other styles support segments, so paint them individually
+ for (size_t index = 0; index < ruler.segments (); ++index) {
+ draw_ruler_segment (ruler, index, trans, sel, bitmap, renderer);
+ }
+
}
}
static bool
is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, double enl, double &distance)
{
+ ant::Object::outline_type outline = ruler.outline ();
+
db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index);
db::DBox b (p1, p2);
- if (ruler.outline () == ant::Object::OL_ellipse) {
+ if (outline == ant::Object::OL_ellipse) {
// special handling of the (non-degenerated) ellipse case
if (b.height () > 1e-6 && b.width () > 1e-6) {
@@ -695,24 +725,24 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
db::DEdge edges[4];
unsigned int nedges = 0;
- if (ruler.outline () == ant::Object::OL_diag ||
- ruler.outline () == ant::Object::OL_diag_xy ||
- ruler.outline () == ant::Object::OL_diag_yx) {
- edges [nedges++] = db::DEdge (ruler.p1 (), ruler.p2 ());
+ if (outline == ant::Object::OL_diag ||
+ outline == ant::Object::OL_diag_xy ||
+ outline == ant::Object::OL_diag_yx) {
+ edges [nedges++] = db::DEdge (p1, p2);
}
- if (ruler.outline () == ant::Object::OL_xy ||
- ruler.outline () == ant::Object::OL_diag_xy ||
- ruler.outline () == ant::Object::OL_box ||
- ruler.outline () == ant::Object::OL_ellipse) {
- edges [nedges++] = db::DEdge (ruler.p1 (), db::DPoint (ruler.p2 ().x (), ruler.p1 ().y ()));
- edges [nedges++] = db::DEdge (db::DPoint (ruler.p2 ().x (), ruler.p1 ().y ()), ruler.p2 ());
+ if (outline == ant::Object::OL_xy ||
+ outline == ant::Object::OL_diag_xy ||
+ outline == ant::Object::OL_box ||
+ outline == ant::Object::OL_ellipse) {
+ edges [nedges++] = db::DEdge (p1, db::DPoint (p2.x (), p1.y ()));
+ edges [nedges++] = db::DEdge (db::DPoint (p2.x (), p1.y ()), p2);
}
- if (ruler.outline () == ant::Object::OL_yx ||
- ruler.outline () == ant::Object::OL_diag_yx ||
- ruler.outline () == ant::Object::OL_box ||
- ruler.outline () == ant::Object::OL_ellipse) {
- edges [nedges++] = db::DEdge (ruler.p1 (), db::DPoint (ruler.p1 ().x (), ruler.p2 ().y ()));
- edges [nedges++] = db::DEdge (db::DPoint (ruler.p1 ().x (), ruler.p2 ().y ()), ruler.p2 ());
+ if (outline == ant::Object::OL_yx ||
+ outline == ant::Object::OL_diag_yx ||
+ outline == ant::Object::OL_box ||
+ outline == ant::Object::OL_ellipse) {
+ edges [nedges++] = db::DEdge (p1, db::DPoint (p1.x (), p2.y ()));
+ edges [nedges++] = db::DEdge (db::DPoint (p1.x (), p2.y ()), p2);
}
for (unsigned int i = 0; i < nedges; ++i) {
@@ -729,6 +759,10 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
static bool
is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance)
{
+ if (ruler.outline () == ant::Object::OL_box || ruler.outline () == ant::Object::OL_ellipse) {
+ return is_selected (ruler, std::numeric_limits::max (), pos, enl, distance);
+ }
+
bool any = false;
for (size_t index = 0; index < ruler.segments (); ++index) {
// NOTE: we check *all* since distance is updated herein.
From 8cbe5a235959d4a259616e0292ef2c42c91539ff Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 28 Sep 2022 00:37:37 +0200
Subject: [PATCH 12/54] WIP: debugging, first implementation of new templates
---
src/ant/ant/RulerConfigPage4.ui | 20 +++++--
src/ant/ant/antConfig.cc | 8 +++
src/ant/ant/antObject.h | 8 +++
src/ant/ant/antPlugin.cc | 50 ++++++++++++++--
src/ant/ant/antService.cc | 102 ++++++++++++++++++++++++--------
src/ant/ant/antService.h | 6 ++
src/ant/ant/antTemplate.h | 12 +++-
src/ant/ant/gsiDeclAnt.cc | 26 +++++++-
8 files changed, 195 insertions(+), 37 deletions(-)
diff --git a/src/ant/ant/RulerConfigPage4.ui b/src/ant/ant/RulerConfigPage4.ui
index ac380684e..649d18d44 100644
--- a/src/ant/ant/RulerConfigPage4.ui
+++ b/src/ant/ant/RulerConfigPage4.ui
@@ -89,7 +89,7 @@
...
-
+
:/up_16px.png :/up_16px.png
@@ -103,7 +103,7 @@
...
-
+
:/add_16px.png :/add_16px.png
@@ -117,7 +117,7 @@
...
-
+
:/del_16px.png :/del_16px.png
@@ -131,7 +131,7 @@
...
-
+
:/down_16px.png :/down_16px.png
@@ -833,6 +833,16 @@
Auto measure (points will be set automatically)
+ -
+
+ Angle measurement (three mouse clicks)
+
+
+ -
+
+ Multi-segment (finish with double click)
+
+
-
@@ -866,7 +876,7 @@
t_snap_cbx
-
+
diff --git a/src/ant/ant/antConfig.cc b/src/ant/ant/antConfig.cc
index 78356a41b..250945a98 100644
--- a/src/ant/ant/antConfig.cc
+++ b/src/ant/ant/antConfig.cc
@@ -239,6 +239,10 @@ RulerModeConverter::to_string (ant::Template::ruler_mode_type m)
return "single_click";
} else if (m == ant::Template::RulerAutoMetric) {
return "auto_metric";
+ } else if (m == ant::Template::RulerMultiSegment) {
+ return "multi_segment";
+ } else if (m == ant::Template::RulerAngle) {
+ return "angle";
} else {
return "normal";
}
@@ -254,6 +258,10 @@ RulerModeConverter::from_string (const std::string &s, ant::Template::ruler_mode
a = ant::Template::RulerSingleClick;
} else if (t == "auto_metric") {
a = ant::Template::RulerAutoMetric;
+ } else if (t == "multi_segment") {
+ a = ant::Template::RulerMultiSegment;
+ } else if (t == "angle") {
+ a = ant::Template::RulerAngle;
} else {
a = ant::Template::RulerNormal;
}
diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h
index 7304c5bed..60752449d 100644
--- a/src/ant/ant/antObject.h
+++ b/src/ant/ant/antObject.h
@@ -292,6 +292,14 @@ public:
*/
void set_points (const point_list &points);
+ /**
+ * @brief Sets the ruler's definition points without cleaning
+ */
+ void set_points_exact (const point_list &points)
+ {
+ m_points = points;
+ }
+
/**
* @brief Gets the first point of the indicated segment
*/
diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc
index fda6d5b8a..74918b24c 100644
--- a/src/ant/ant/antPlugin.cc
+++ b/src/ant/ant/antPlugin.cc
@@ -68,12 +68,18 @@ static std::vector make_standard_templates ()
templates.push_back (ant::Template (tl::to_string (tr ("Ruler")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_ruler"));
+ templates.push_back (ant::Template (tl::to_string (tr ("Multi-ruler")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_multi_ruler"));
+ templates.back ().set_mode (ant::Template::RulerMultiSegment);
+
templates.push_back (ant::Template (tl::to_string (tr ("Cross")), "", "", "$U,$V", ant::Object::STY_cross_both, ant::Object::OL_diag, true, lay::AC_Global, "_cross"));
templates.back ().set_mode (ant::Template::RulerSingleClick);
templates.push_back (ant::Template (tl::to_string (tr ("Measure")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_measure"));
templates.back ().set_mode (ant::Template::RulerAutoMetric);
+ templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_diag, true, lay::AC_Global, "_angle"));
+ templates.back ().set_mode (ant::Template::RulerAngle);
+
templates.push_back (ant::Template (tl::to_string (tr ("Ellipse")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_ellipse, true, lay::AC_Global, std::string ()));
templates.push_back (ant::Template (tl::to_string (tr ("Box")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_box, true, lay::AC_Global, std::string ()));
@@ -197,14 +203,50 @@ PluginDeclaration::initialized (lay::Dispatcher *root)
// Check if we already have templates (initial setup)
// NOTE: this is not done by using a default value for the configuration item but dynamically.
// This provides a migration path from earlier versions (not having templates) to recent ones.
- bool any_templates = false;
- for (std::vector::iterator i = m_templates.begin (); ! any_templates && i != m_templates.end (); ++i) {
- any_templates = ! i->category ().empty ();
+ std::map cat_names;
+ for (auto i = m_templates.begin (); i != m_templates.end (); ++i) {
+ if (! i->category ().empty ()) {
+ cat_names.insert (std::make_pair (i->category (), i.operator-> ()));
+ }
}
- if (! any_templates) {
+ bool any_missing = false;
+ auto std_templates = make_standard_templates ();
+ for (auto t = std_templates.begin (); ! any_missing && t != std_templates.end (); ++t) {
+ if (! t->category ().empty () && cat_names.find (t->category ()) == cat_names.end ()) {
+ any_missing = true;
+ }
+ }
+
+ if (cat_names.empty ()) {
+
+ // full initial configuration
root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ()));
root->config_end ();
+
+ } else if (any_missing) {
+
+ // some standard templates are missing - add them now (migration path for later versions)
+ decltype (m_templates) new_templates;
+ for (auto t = std_templates.begin (); t != std_templates.end (); ++t) {
+ if (! t->category ().empty ()) {
+ auto tt = cat_names.find (t->category ());
+ if (tt != cat_names.end ()) {
+ new_templates.push_back (*tt->second);
+ } else {
+ new_templates.push_back (*t);
+ }
+ }
+ }
+ for (auto i = m_templates.begin (); i != m_templates.end (); ++i) {
+ if (i->category ().empty ()) {
+ new_templates.push_back (*i);
+ }
+ }
+
+ root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (new_templates));
+ root->config_end ();
+
}
}
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index ffd1e22cb..fb76bc076 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -1560,11 +1560,52 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio
return mouse_click_event (p, buttons, prio);
}
-bool
+void
+Service::finish_drawing ()
+{
+ // create the ruler object
+
+ // begin the transaction
+ if (manager ()) {
+ tl_assert (! manager ()->transacting ());
+ manager ()->transaction (tl::to_string (tr ("Create ruler")));
+ }
+
+ show_message ();
+
+ insert_ruler (ant::Object (m_current.points (), 0, current_template ()), true);
+
+ // stop dragging
+ drag_cancel ();
+ clear_transient_selection ();
+
+ // end the transaction
+ if (manager ()) {
+ manager ()->commit ();
+ }
+}
+
+bool
+Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio)
+{
+ if (m_drawing && prio && (buttons & lay::LeftButton) != 0) {
+
+ // ends the current ruler (specifically in multi-segment mode)
+ finish_drawing ();
+ return true;
+
+ }
+
+ return false;
+}
+
+bool
Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
if (prio && (buttons & lay::LeftButton) != 0) {
+ const ant::Template &tpl = current_template ();
+
if (! m_drawing) {
// cancel any edit operations so far
@@ -1577,8 +1618,6 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
// and clear surplus rulers
reduce_rulers (m_max_number_of_rulers - 1);
- const ant::Template &tpl = current_template ();
-
// create and start dragging the ruler
if (tpl.mode () == ant::Template::RulerSingleClick) {
@@ -1648,7 +1687,13 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
m_p1 = snap1 (p, m_obj_snap && tpl.snap ()).second;
- m_current = ant::Object (m_p1, m_p1, 0, tpl);
+ // NOTE: generating the ruler this way makes sure we have two points
+ ant::Object::point_list pts;
+ m_current = ant::Object (pts, 0, tpl);
+ pts.push_back (m_p1);
+ pts.push_back (m_p1);
+ m_current.set_points_exact (pts);
+
show_message ();
if (mp_active_ruler) {
@@ -1662,29 +1707,29 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
}
+ } else if (tpl.mode () == ant::Template::RulerMultiSegment || tpl.mode () == ant::Template::RulerAngle) {
+
+ ant::Object::point_list pts = m_current.points ();
+ tl_assert (! pts.empty ());
+
+ if (tpl.mode () == ant::Template::RulerAngle && pts.size () == 3) {
+
+ finish_drawing ();
+
+ } else {
+
+ // add a new point
+ m_p1 = pts.back ();
+
+ pts.push_back (m_p1);
+ m_current.set_points_exact (pts);
+
+ }
+
} else {
- // create the ruler object
+ finish_drawing ();
- // begin the transaction
- if (manager ()) {
- tl_assert (! manager ()->transacting ());
- manager ()->transaction (tl::to_string (tr ("Create ruler")));
- }
-
- show_message ();
-
- insert_ruler (ant::Object (m_current.p1 (), m_current.p2 (), 0, current_template ()), true);
-
- // stop dragging
- drag_cancel ();
- clear_transient_selection ();
-
- // end the transaction
- if (manager ()) {
- manager ()->commit ();
- }
-
}
return true;
@@ -1731,7 +1776,14 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
set_cursor (lay::Cursor::cross);
- m_current.p2 (snap2 (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)).second);
+ // NOTE: we use the direct access path so we do not encounter cleanup by the p1 and p2 setters
+ // otherwise we risk manipulating p1 too.
+ ant::Object::point_list pts = m_current.points ();
+ if (! pts.empty ()) {
+ pts.back () = snap2 (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)).second;
+ }
+ m_current.set_points_exact (pts);
+
mp_active_ruler->redraw ();
show_message ();
diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h
index 6b4c5be9d..5d55af179 100644
--- a/src/ant/ant/antService.h
+++ b/src/ant/ant/antService.h
@@ -566,6 +566,7 @@ private:
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
+ virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual void deactivated ();
/**
@@ -585,6 +586,11 @@ private:
*/
void reduce_rulers (int num);
+ /**
+ * @brief Finishes drawing mode and creates the ruler
+ */
+ void finish_drawing ();
+
/**
* @brief Delete the selected rulers
*
diff --git a/src/ant/ant/antTemplate.h b/src/ant/ant/antTemplate.h
index 0d8b921f5..6b1bbbf8b 100644
--- a/src/ant/ant/antTemplate.h
+++ b/src/ant/ant/antTemplate.h
@@ -62,7 +62,17 @@ public:
/**
* @brief The ruler is auto-metric: a single click will place a ruler and the ruler will extend to the next adjacent structures
*/
- RulerAutoMetric = 2
+ RulerAutoMetric = 2,
+
+ /**
+ * @brief The ruler an angle type (two segments, three mouse clicks) for angle and circle radius measurements
+ */
+ RulerAngle = 3,
+
+ /**
+ * @brief The ruler is a multi-segment type
+ */
+ RulerMultiSegment = 4
};
/**
diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc
index 949cb5c09..24b3d47ca 100644
--- a/src/ant/ant/gsiDeclAnt.cc
+++ b/src/ant/ant/gsiDeclAnt.cc
@@ -432,6 +432,16 @@ static int ruler_mode_auto_metric ()
return ant::Template::RulerAutoMetric;
}
+static int ruler_mode_angle ()
+{
+ return ant::Template::RulerAngle;
+}
+
+static int ruler_mode_multi_segment ()
+{
+ return ant::Template::RulerMultiSegment;
+}
+
static void register_annotation_template (const ant::Object &a, const std::string &title, int mode)
{
ant::Template t = ant::Template::from_object (a, title, mode);
@@ -503,16 +513,28 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
) +
gsi::method ("RulerModeSingleClick", &gsi::ruler_mode_single_click,
"@brief Specifies single-click ruler mode for the \\register_template method\n"
- "In single click-mode, a ruler can be placed with a single click and p1 will be == p2."
+ "In single click-mode, a ruler can be placed with a single click and p1 will be == p2.\n"
"\n"
"This constant has been introduced in version 0.25"
) +
gsi::method ("RulerModeAutoMetric", &gsi::ruler_mode_auto_metric,
"@brief Specifies auto-metric ruler mode for the \\register_template method\n"
- "In auto-metric mode, a ruler can be placed with a single click and p1/p2 will be determined from the neighborhood."
+ "In auto-metric mode, a ruler can be placed with a single click and p1/p2 will be determined from the neighborhood.\n"
"\n"
"This constant has been introduced in version 0.25"
) +
+ gsi::method ("RulerAngle", &gsi::ruler_mode_angle,
+ "@brief Specifies angle ruler mode for the \\register_template method\n"
+ "In angle ruler mode, two segments are created for angle and circle radius measurements. Three mouse clicks are required.\n"
+ "\n"
+ "This constant has been introduced in version 0.28"
+ ) +
+ gsi::method ("RulerMultiSegment", &gsi::ruler_mode_multi_segment,
+ "@brief Specifies multi-segment mode\n"
+ "In multi-segment mode, multiple segments can be created. The ruler is finished with a double click.\n"
+ "\n"
+ "This constant has been introduced in version 0.28"
+ ) +
gsi::method ("StyleRuler|#style_ruler", &gsi::style_ruler,
"@brief Gets the ruler style code for use the \\style method\n"
"When this style is specified, the annotation will show a ruler with "
From d2d321c35bb6d21db8f4471d7b4a537128cb16ea Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 28 Sep 2022 21:16:47 +0200
Subject: [PATCH 13/54] WIP: point editing of multi-segment rulers
---
src/ant/ant/antObject.cc | 84 ++++++++++++++++++++++++++++++++-------
src/ant/ant/antObject.h | 25 ++++++++++--
src/ant/ant/antService.cc | 82 ++++++++++++++++++++++----------------
src/ant/ant/antService.h | 2 +
4 files changed, 140 insertions(+), 53 deletions(-)
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index 1dedd9281..510ce87a3 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -32,6 +32,24 @@
namespace ant
{
+static void
+clean_points_impl (ant::Object::point_list &points)
+{
+ auto wp = points.begin ();
+ auto p = points.begin ();
+ while (p != points.end ()) {
+ auto pp = p + 1;
+ while (pp != points.end () && *pp == *p) {
+ ++pp;
+ }
+ *wp++ = *p;
+ p = pp;
+ }
+
+ points.erase (wp, points.end ());
+}
+
+
Object::Object ()
: m_id (-1),
m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"),
@@ -88,7 +106,7 @@ Object::Object (const db::DPoint &_p1, const db::DPoint &_p2, int id, const ant:
}
Object::Object (const Object::point_list &pts, int id, const ant::Template &t)
- : m_id (id),
+ : m_points (pts), m_id (id),
m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()),
m_style (t.style ()), m_outline (t.outline ()),
m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()),
@@ -98,7 +116,7 @@ Object::Object (const Object::point_list &pts, int id, const ant::Template &t)
m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()),
m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ())
{
- set_points (pts);
+ clean_points_impl (m_points);
}
Object::Object (const ant::Object &d)
@@ -224,22 +242,36 @@ Object::operator== (const ant::Object &d) const
;
}
+void
+Object::clean_points ()
+{
+ auto new_points = m_points;
+ clean_points_impl (new_points);
+ set_points_exact (std::move (new_points));
+}
+
void
Object::set_points (const point_list &points)
{
- point_list new_points;
- auto p = points.begin ();
- while (p != points.end ()) {
- auto pp = p + 1;
- while (pp != points.end () && *pp == *p) {
- ++pp;
- }
- new_points.push_back (*p);
- p = pp;
- }
+ auto new_points = points;
+ clean_points_impl (new_points);
+ set_points_exact (std::move (new_points));
+}
- if (m_points != new_points) {
- m_points = new_points;
+void
+Object::set_points_exact (const point_list &points)
+{
+ if (m_points != points) {
+ m_points = points;
+ property_changed ();
+ }
+}
+
+void
+Object::set_points_exact (point_list &&points)
+{
+ if (m_points != points) {
+ m_points.swap (points);
property_changed ();
}
}
@@ -272,6 +304,30 @@ Object::seg_p2 (size_t seg_index) const
}
}
+void
+Object::seg_p1 (size_t seg_index, const db::DPoint &p)
+{
+ if (seg_index == std::numeric_limits::max ()) {
+ p1 (p);
+ } else if (seg_index < m_points.size ()) {
+ m_points[seg_index] = p;
+ } else if (! m_points.empty ()) {
+ m_points.back () = p;
+ }
+}
+
+void
+Object::seg_p2 (size_t seg_index, const db::DPoint &p)
+{
+ if (seg_index == std::numeric_limits::max ()) {
+ p2 (p);
+ } else if (seg_index + 1 < m_points.size ()) {
+ m_points[seg_index + 1] = p;
+ } else if (! m_points.empty ()) {
+ m_points.back () = p;
+ }
+}
+
void
Object::p1 (const db::DPoint &p)
{
diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h
index 60752449d..6fd478c7a 100644
--- a/src/ant/ant/antObject.h
+++ b/src/ant/ant/antObject.h
@@ -295,10 +295,17 @@ public:
/**
* @brief Sets the ruler's definition points without cleaning
*/
- void set_points_exact (const point_list &points)
- {
- m_points = points;
- }
+ void set_points_exact (const point_list &points);
+
+ /**
+ * @brief Sets the ruler's definition points without cleaning (move semantics)
+ */
+ void set_points_exact (point_list &&points);
+
+ /**
+ * @brief Cleans the point list
+ */
+ void clean_points ();
/**
* @brief Gets the first point of the indicated segment
@@ -310,6 +317,16 @@ public:
*/
db::DPoint seg_p2 (size_t seg_index) const;
+ /**
+ * @brief Sets the first point of the indicated segment
+ */
+ void seg_p1 (size_t seg_index, const db::DPoint &p);
+
+ /**
+ * @brief Sets the second point of the indicated segment
+ */
+ void seg_p2 (size_t seg_index, const db::DPoint &p);
+
/**
* @brief Gets the number of segments
*
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index fb76bc076..ffcf88a06 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -858,6 +858,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
mp_transient_ruler (0),
m_drawing (false), m_current (),
m_move_mode (MoveNone),
+ m_seg_index (0),
m_current_template (0)
{
mp_view->annotations_changed_event.add (this, &Service::annotations_changed);
@@ -1074,29 +1075,28 @@ Service::insert_ruler (const ant::Object &ruler, bool limit_number)
return new_id;
}
-/**
- * @brief Helper function to determine which move mode to choose given a certain search box and ant::Object
- */
static bool
-dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1)
+dragging_what_seg (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1, size_t index)
{
+ ant::Object::outline_type outline = robj->outline ();
+
db::DPoint p12, p21;
bool has_p12 = false, has_p21 = false;
- db::DPoint p11 = robj->p1 (), p22 = robj->p2 ();
+ db::DPoint p11 = robj->seg_p1 (index), p22 = robj->seg_p2 (index);
db::DPoint c = p11 + (p22 - p11) * 0.5;
-
- if (robj->outline () == ant::Object::OL_xy || robj->outline () == ant::Object::OL_diag_xy || robj->outline () == ant::Object::OL_box) {
- p12 = db::DPoint (robj->p2 ().x (), robj->p1 ().y ());
+
+ if (outline == ant::Object::OL_xy || outline== ant::Object::OL_diag_xy || outline == ant::Object::OL_box) {
+ p12 = db::DPoint (p22.x (), p11.y ());
has_p12 = true;
}
- if (robj->outline () == ant::Object::OL_yx || robj->outline () == ant::Object::OL_diag_yx || robj->outline () == ant::Object::OL_box) {
- p21 = db::DPoint (robj->p1 ().x (), robj->p2 ().y ());
+ if (outline == ant::Object::OL_yx || outline == ant::Object::OL_diag_yx || outline == ant::Object::OL_box) {
+ p21 = db::DPoint (p11.x (), p22.y ());
has_p21 = true;
}
-
- if (robj->outline () == ant::Object::OL_ellipse) {
+
+ if (outline == ant::Object::OL_ellipse) {
db::DVector d = (p22 - p11) * 0.5;
p12 = c + db::DVector (d.x (), -d.y ());
p21 = c + db::DVector (-d.x (), d.y ());
@@ -1106,7 +1106,7 @@ dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Servic
// HINT: this was implemented returning a std::pair, but
// I was not able to get it to work in gcc 4.1.2 in -O3 mode ...
-
+
if (search_dbox.contains (p11)) {
p1 = p11;
mode = ant::Service::MoveP1;
@@ -1147,18 +1147,28 @@ dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Servic
mode = ant::Service::MoveP2Y;
return true;
}
- if ((robj->outline () == ant::Object::OL_diag || robj->outline () == ant::Object::OL_diag_xy || robj->outline () == ant::Object::OL_diag_yx)
- && db::DEdge (p11, p22).distance_abs (search_dbox.center ()) <= search_dbox.width () * 0.5) {
- p1 = search_dbox.center ();
- mode = ant::Service::MoveRuler;
- return true;
+
+ return false;
+}
+
+/**
+ * @brief Helper function to determine which move mode to choose given a certain search box and ant::Object
+ */
+static bool
+dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1, size_t &index)
+{
+ ant::Object::outline_type outline = robj->outline ();
+
+ if (outline == ant::Object::OL_box || outline == ant::Object::OL_ellipse) {
+ index = std::numeric_limits::max ();
+ return dragging_what_seg (robj, search_dbox, mode, p1, index);
}
- if ((robj->outline () == ant::Object::OL_box || robj->outline () == ant::Object::OL_ellipse) && search_dbox.inside (db::DBox (p11, p22))) {
- p1 = search_dbox.center ();
- mode = ant::Service::MoveRuler;
- return true;
+
+ for (index = 0; index < robj->segments (); ++index) {
+ if (dragging_what_seg (robj, search_dbox, mode, p1, index)) {
+ return true;
+ }
}
-
return false;
}
@@ -1185,6 +1195,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
} else if (mode == lay::Editable::Partial) {
m_move_mode = MoveNone;
+ m_seg_index = 0;
// compute search box
double l = catch_distance ();
@@ -1216,7 +1227,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
const ant::Object *robj = dynamic_cast ((*ri).ptr ());
if (robj && (! robj_min || robj == robj_min)) {
- if (dragging_what (robj, search_dbox, m_move_mode, m_p1) && m_move_mode != MoveRuler) {
+ if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index) && m_move_mode != MoveRuler) {
// found anything: make the moved ruler the selection
clear_selection ();
@@ -1273,7 +1284,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
const ant::Object *robj = dynamic_cast ((*r).ptr ());
if (robj && (! robj_min || robj == robj_min)) {
- if (dragging_what (robj, search_dbox, m_move_mode, m_p1)) {
+ if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index)) {
// found anything: make the moved ruler the selection
clear_selection ();
@@ -1340,50 +1351,50 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
if (m_move_mode == MoveP1) {
- m_current.p1 (snap2 (m_p1, p, &m_current, ac).second);
+ m_current.seg_p1 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second);
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2) {
- m_current.p2 (snap2 (m_p1, p, &m_current, ac).second);
+ m_current.seg_p2 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second);
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP12) {
db::DPoint p12 = snap2 (m_p1, p, &m_current, ac).second;
- m_current.p1 (db::DPoint (m_current.p1 ().x(), p12.y ()));
- m_current.p2 (db::DPoint (p12.x (), m_current.p2 ().y ()));
+ m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), p12.y ()));
+ m_current.seg_p2 (m_seg_index, db::DPoint (p12.x (), m_current.seg_p2 (m_seg_index).y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP21) {
db::DPoint p21 = snap2 (m_p1, p, &m_current, ac).second;
- m_current.p1 (db::DPoint (p21.x (), m_current.p1 ().y ()));
- m_current.p2 (db::DPoint (m_current.p2 ().x(), p21.y ()));
+ m_current.seg_p1 (m_seg_index, db::DPoint (p21.x (), m_current.seg_p1 (m_seg_index).y ()));
+ m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), p21.y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP1X) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
- m_current.p1 (db::DPoint (pc.x (), m_current.p1 ().y ()));
+ m_current.seg_p1 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p1 (m_seg_index).y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2X) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
- m_current.p2 (db::DPoint (pc.x (), m_current.p2 ().y ()));
+ m_current.seg_p2 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p2 (m_seg_index).y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP1Y) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
- m_current.p1 (db::DPoint (m_current.p1 ().x (), pc.y ()));
+ m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), pc.y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2Y) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
- m_current.p2 (db::DPoint (m_current.p2 ().x (), pc.y ()));
+ m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), pc.y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveRuler) {
@@ -1474,6 +1485,7 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
} else if (m_move_mode != MoveNone) {
// replace the ruler that was moved
+ m_current.clean_points ();
mp_view->annotation_shapes ().replace (m_selected.begin ()->first, db::DUserObject (new ant::Object (m_current)));
annotation_changed_event (m_current.id ());
diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h
index 5d55af179..a36bf6884 100644
--- a/src/ant/ant/antService.h
+++ b/src/ant/ant/antService.h
@@ -545,6 +545,8 @@ private:
ant::Object m_original;
// The current move mode
MoveMode m_move_mode;
+ // The currently moving segment
+ size_t m_seg_index;
// The ruler template
std::vector m_ruler_templates;
unsigned int m_current_template;
From 8415e075ada329563b485c81e1ff2fa5b064ab30 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 28 Sep 2022 23:58:34 +0200
Subject: [PATCH 14/54] WIP: angle measurement ruler, radius measurement one.
Needs improvement
---
src/ant/ant/RulerConfigPage4.ui | 10 ++
src/ant/ant/RulerPropertiesPage.ui | 10 ++
src/ant/ant/antConfig.cc | 12 +-
src/ant/ant/antObject.h | 4 +-
src/ant/ant/antPlugin.cc | 7 +-
src/ant/ant/antService.cc | 278 +++++++++++++++++++++++------
src/ant/ant/antTemplate.h | 2 +-
src/ant/ant/gsiDeclAnt.cc | 66 ++++---
8 files changed, 306 insertions(+), 83 deletions(-)
diff --git a/src/ant/ant/RulerConfigPage4.ui b/src/ant/ant/RulerConfigPage4.ui
index 649d18d44..7e2c2365c 100644
--- a/src/ant/ant/RulerConfigPage4.ui
+++ b/src/ant/ant/RulerConfigPage4.ui
@@ -574,6 +574,16 @@
Ellipse
+ -
+
+ Angle measurement
+
+
+ -
+
+ Radius measurement
+
+
-
diff --git a/src/ant/ant/RulerPropertiesPage.ui b/src/ant/ant/RulerPropertiesPage.ui
index 567287ddc..28451b680 100644
--- a/src/ant/ant/RulerPropertiesPage.ui
+++ b/src/ant/ant/RulerPropertiesPage.ui
@@ -352,6 +352,16 @@
Ellipse
+ -
+
+ Angle measurement
+
+
+ -
+
+ Radius measurement
+
+
-
diff --git a/src/ant/ant/antConfig.cc b/src/ant/ant/antConfig.cc
index 250945a98..ed5230023 100644
--- a/src/ant/ant/antConfig.cc
+++ b/src/ant/ant/antConfig.cc
@@ -136,6 +136,10 @@ OutlineConverter::to_string (ant::Object::outline_type o)
return "box";
} else if (o == ant::Object::OL_ellipse) {
return "ellipse";
+ } else if (o == ant::Object::OL_radius) {
+ return "radius";
+ } else if (o == ant::Object::OL_angle) {
+ return "angle";
} else {
return "";
}
@@ -159,6 +163,10 @@ OutlineConverter::from_string (const std::string &s, ant::Object::outline_type &
o = ant::Object::OL_box;
} else if (t == "ellipse") {
o = ant::Object::OL_ellipse;
+ } else if (t == "radius") {
+ o = ant::Object::OL_radius;
+ } else if (t == "angle") {
+ o = ant::Object::OL_angle;
} else {
o = ant::Object::OL_diag;
}
@@ -241,7 +249,7 @@ RulerModeConverter::to_string (ant::Template::ruler_mode_type m)
return "auto_metric";
} else if (m == ant::Template::RulerMultiSegment) {
return "multi_segment";
- } else if (m == ant::Template::RulerAngle) {
+ } else if (m == ant::Template::RulerThreeClicks) {
return "angle";
} else {
return "normal";
@@ -261,7 +269,7 @@ RulerModeConverter::from_string (const std::string &s, ant::Template::ruler_mode
} else if (t == "multi_segment") {
a = ant::Template::RulerMultiSegment;
} else if (t == "angle") {
- a = ant::Template::RulerAngle;
+ a = ant::Template::RulerThreeClicks;
} else {
a = ant::Template::RulerNormal;
}
diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h
index 6fd478c7a..e225ce593 100644
--- a/src/ant/ant/antObject.h
+++ b/src/ant/ant/antObject.h
@@ -77,8 +77,10 @@ public:
* OL_diag_yx: both OL_diag and OL_yx
* OL_box: draw a box defined by start and end point
* OL_ellipse: draws an ellipse with p1 and p2 defining the extension (style is ignored)
+ * OL_angle: an angle measurement ruler (first vs. last segment)
+ * OL_radius: a radius measurement ruler
*/
- enum outline_type { OL_diag = 0, OL_xy = 1, OL_diag_xy = 2, OL_yx = 3, OL_diag_yx = 4, OL_box = 5, OL_ellipse = 6 };
+ enum outline_type { OL_diag = 0, OL_xy = 1, OL_diag_xy = 2, OL_yx = 3, OL_diag_yx = 4, OL_box = 5, OL_ellipse = 6, OL_angle = 7, OL_radius = 8 };
/**
* @brief The position type of the main label
diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc
index 74918b24c..7175b11c9 100644
--- a/src/ant/ant/antPlugin.cc
+++ b/src/ant/ant/antPlugin.cc
@@ -77,8 +77,11 @@ static std::vector
make_standard_templates ()
templates.push_back (ant::Template (tl::to_string (tr ("Measure")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_measure"));
templates.back ().set_mode (ant::Template::RulerAutoMetric);
- templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_diag, true, lay::AC_Global, "_angle"));
- templates.back ().set_mode (ant::Template::RulerAngle);
+ templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_angle, true, lay::AC_Global, "_angle"));
+ templates.back ().set_mode (ant::Template::RulerThreeClicks);
+
+ templates.push_back (ant::Template (tl::to_string (tr ("Radius")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_radius, true, lay::AC_Global, "_radius"));
+ templates.back ().set_mode (ant::Template::RulerThreeClicks);
templates.push_back (ant::Template (tl::to_string (tr ("Ellipse")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_ellipse, true, lay::AC_Global, std::string ()));
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index ffcf88a06..cee1d246e 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -503,9 +503,12 @@ draw_text (const db::DPoint &q1,
*
* @param q1 The first point in pixel space
* @param q2 The second point in pixel space
+ * @param length_u The "typical dimension" - used to simplify for very small ellipses
* @param sel True to draw ruler in "selected" mode
* @param bitmap The bitmap to draw the ruler on
* @param renderer The renderer object
+ * @param start_angle The starting angle (in radians)
+ * @param stop_angle The stop angle (in radians)
*/
void
draw_ellipse (const db::DPoint &q1,
@@ -513,7 +516,9 @@ draw_ellipse (const db::DPoint &q1,
double length_u,
bool sel,
lay::CanvasPlane *bitmap,
- lay::Renderer &renderer)
+ lay::Renderer &renderer,
+ double start_angle = 0.0,
+ double stop_angle = 2.0 * M_PI)
{
double sel_width = 2 / renderer.resolution ();
@@ -532,7 +537,7 @@ draw_ellipse (const db::DPoint &q1,
} else {
- int npoints = 200;
+ int npoints = int (floor (200 * abs (stop_angle - start_angle) / (2.0 * M_PI)));
// produce polygon stuff
@@ -540,43 +545,29 @@ draw_ellipse (const db::DPoint &q1,
double ry = fabs ((q2 - q1).y () * 0.5);
db::DPoint c = q1 + (q2 - q1) * 0.5;
- db::DPolygon p;
-
- std::vector pts;
- pts.reserve (npoints);
-
if (sel) {
rx += sel_width * 0.5;
ry += sel_width * 0.5;
}
- double da = M_PI * 2.0 / double (npoints);
- for (int i = 0; i < npoints; ++i) {
- double a = da * i;
+ std::vector pts;
+ pts.reserve (npoints + 1);
+
+ double da = fabs (stop_angle - start_angle) / double (npoints);
+ for (int i = 0; i < npoints + 1; ++i) {
+ double a = da * i + start_angle;
pts.push_back (c + db::DVector (rx * cos (a), ry * sin (a)));
}
- p.assign_hull (pts.begin (), pts.end ());
-
if (sel) {
- pts.clear ();
-
- rx -= sel_width;
- ry -= sel_width;
- for (int i = 0; i < npoints; ++i) {
- double a = da * i;
- pts.push_back (c + db::DVector (rx * cos (a), ry * sin (a)));
- }
-
- p.insert_hole (pts.begin (), pts.end ());
-
+ db::DPath p (pts.begin (), pts.end (), sel_width);
renderer.draw (p, bitmap, bitmap, 0, 0);
} else {
- for (db::DPolygon::polygon_edge_iterator e = p.begin_edge (); ! e.at_end (); ++e) {
- renderer.draw (*e, 0, bitmap, 0, 0);
+ for (size_t i = 0; i + 1 < pts.size (); ++i) {
+ renderer.draw (db::DEdge (pts [i], pts [i + 1]), 0, bitmap, 0, 0);
}
}
@@ -639,52 +630,236 @@ draw_ruler_segment (const ant::Object &ruler, size_t index, const db::DCplxTrans
draw_text (db::DPoint (q1.x (), q2.y ()), q2, lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
}
+}
- if (ruler.outline () == Object::OL_box) {
+void
+draw_ruler_box (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
+{
+ db::DPoint p1 = ruler.p1 (), p2 = ruler.p2 ();
- bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
+ // round the starting point, shift both, and round the end point
+ std::pair v = lay::snap (trans * p1, trans * p2);
+ db::DPoint q1 = v.first;
+ db::DPoint q2 = v.second;
- draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer, true, true);
- draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
- draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer, true, true);
- draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
- draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, !r, ruler.style (), bitmap, renderer, true, true);
- draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer, true, true);
- draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+ double lu = p1.double_distance (p2);
+ int min_tick_spc = int (0.5 + 20 / renderer.resolution ()); // min tick spacing in canvas units
+ double mu = double (min_tick_spc) / trans.ctrans (1.0);
- } else if (ruler.outline () == Object::OL_ellipse) {
+ bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
- bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
+ size_t index = std::numeric_limits::max ();
+ draw_ruler (q1, db::DPoint (q2.x (), q1.y ()), lu, mu, sel, r, ruler.style (), bitmap, renderer, true, true);
+ draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
+ draw_ruler (db::DPoint (q2.x (), q1.y ()), q2, lu, mu, sel, r, ruler.style (), bitmap, renderer, true, true);
+ draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ruler.style (), ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
+ draw_ruler (q1, db::DPoint (q1.x (), q2.y ()), lu, mu, sel, !r, ruler.style (), bitmap, renderer, true, true);
+ draw_ruler (db::DPoint (q1.x (), q2.y ()), q2, lu, mu, sel, !r, ruler.style (), bitmap, renderer, true, true);
+ draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+}
- draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
- draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
- draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+void
+draw_ruler_ellipse (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
+{
+ db::DPoint p1 = ruler.p1 (), p2 = ruler.p2 ();
- draw_ellipse (q1, q2, lu, sel, bitmap, renderer);
+ // round the starting point, shift both, and round the end point
+ std::pair v = lay::snap (trans * p1, trans * p2);
+ db::DPoint q1 = v.first;
+ db::DPoint q2 = v.second;
+
+ double lu = p1.double_distance (p2);
+
+ bool r = (q2.x () > q1.x ()) ^ (q2.y () < q1.y ());
+
+ size_t index = std::numeric_limits::max ();
+ draw_text (q1, db::DPoint (q2.x (), q1.y ()), lu, ruler.text_x (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.xlabel_xalign (), ruler.xlabel_yalign (), bitmap, renderer);
+ draw_text (db::DPoint (q2.x (), q1.y ()), q2, lu, ruler.text_y (index, trans.fp_trans ()), r, ant::Object::STY_none, ant::Object::POS_center, ruler.ylabel_xalign (), ruler.ylabel_yalign (), bitmap, renderer);
+ draw_text (q1, q2, lu, ruler.text (index), !r, ant::Object::STY_none, ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+
+ draw_ellipse (q1, q2, lu, sel, bitmap, renderer);
+}
+
+bool
+compute_interpolating_circle (const ant::Object::point_list &points, double &radius, db::DPoint ¢er, double &start_angle, double &stop_angle)
+{
+ if (points.size () < 2) {
+ return false;
+ }
+
+ double d = points.back ().distance (points.front ()) * 0.5;
+ if (d < db::epsilon) {
+ return false;
+ }
+
+ db::DVector n = points.back () - points.front ();
+ db::DPoint m = points.front () + n * 0.5;
+ n = db::DVector (n.y (), -n.x ()) * (1.0 / d);
+
+ double nom = 0.0;
+ double div = 0.0;
+
+ for (size_t i = 1; i + 1 < points.size (); ++i) {
+ db::DVector p = points [i] - m;
+ double pn = db::sprod (p, n);
+ div += pn * pn;
+ nom += pn * (p.sq_double_length () - d * d);
+ }
+
+ if (div < db::epsilon) {
+ return false;
+ }
+
+ double l = 0.5 * nom / div;
+ radius = sqrt (l * l + d * d);
+ center = m + n * l;
+
+ double a = atan2 (-n.y (), -n.x ());
+ double da = atan2 (d, l);
+
+ if (fabs (l) < db::epsilon) {
+
+ start_angle = 0.0;
+ stop_angle = M_PI * 2.0;
+
+ } else if (l < 0.0) {
+
+ start_angle = a + da;
+ stop_angle = start_angle + 2.0 * (M_PI - da);
+
+ } else {
+
+ start_angle = a - da;
+ stop_angle = a + da;
+
+ }
+
+ while (stop_angle < start_angle - db::epsilon) {
+ stop_angle += M_PI * 2.0;
+ }
+
+ return true;
+}
+
+void
+draw_ruler_radius (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
+{
+ // draw crosses for the support points
+ for (auto p = ruler.points ().begin (); p != ruler.points ().end (); ++p) {
+ ant::Object supp (*p, *p, 0, std::string (), std::string (), std::string (), ant::Object::STY_cross_start, ant::Object::OL_diag, false, lay::AC_Global);
+ draw_ruler_segment (supp, 0, trans, sel, bitmap, renderer);
+ }
+
+ double radius = 0.0;
+ double start_angle = 0.0, stop_angle = 0.0;
+ db::DPoint center;
+
+ // circle interpolation
+ if (compute_interpolating_circle (ruler.points (), radius, center, start_angle, stop_angle)) {
+
+ // draw circle segment
+ db::DVector rr (radius, radius);
+ std::pair v = lay::snap (trans * (center - rr), trans * (center + rr));
+ draw_ellipse (v.first, v.second, radius * 2.0, sel, bitmap, renderer, start_angle, stop_angle);
+
+ double a = 0.5 * (start_angle + stop_angle);
+ db::DPoint rc = center + db::DVector (cos (a), sin (a)) * radius;
+
+ // draw a center marker
+ ant::Object center_loc (center, center, 0, std::string (), ruler.fmt_x (), ruler.fmt_y (), ant::Object::STY_cross_start, ant::Object::OL_diag, false, lay::AC_Global);
+ draw_ruler_segment (center_loc, 0, trans, sel, bitmap, renderer);
+
+ // draw the radius ruler
+ ant::Object radius (center, rc, 0, ruler.fmt (), std::string (), std::string (), ruler.style (), ruler.outline (), false, lay::AC_Global);
+ draw_ruler_segment (radius, 0, trans, sel, bitmap, renderer);
}
}
+void
+draw_ruler_angle (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
+{
+ // draw segments in diag mode
+ ant::Object basic = ruler;
+ basic.outline (ant::Object::OL_diag);
+ draw_ruler_segment (basic, 0, trans, sel, bitmap, renderer);
+ if (basic.segments () > 1) {
+ draw_ruler_segment (basic, basic.segments () - 1, trans, sel, bitmap, renderer);
+ }
+
+ if (ruler.points ().size () < 3) {
+ return;
+ }
+
+ db::DPoint p1 = ruler.p1 (), p2 = ruler.p2 ();
+
+ db::DVector pc;
+ for (size_t i = 1; i + 1 < ruler.points ().size (); ++i) {
+ pc += ruler.points ()[i] - db::DPoint ();
+ }
+ db::DPoint center = db::DPoint () + pc * (1.0 / double (ruler.points ().size () - 2));
+
+ db::DVector v1 (p1 - center);
+ if (v1.double_length () < db::epsilon) {
+ return;
+ }
+
+ db::DVector v2 (p2 - center);
+ if (v2.double_length () < db::epsilon) {
+ return;
+ }
+
+ double radius = std::min (v1.double_length (), v2.double_length ());
+
+ v1 *= 1.0 / v1.double_length ();
+ v2 *= 1.0 / v2.double_length ();
+
+ if (db::vprod_sign (v1, v2) == 0) {
+ return;
+ }
+
+ double start_angle = 0.0, stop_angle = 0.0;
+ start_angle = atan2 (v1.y (), v1.x ());
+ stop_angle = atan2 (v2.y (), v2.x ());
+
+ if (db::vprod_sign (v1, v2) < 0) {
+ std::swap (start_angle, stop_angle);
+ }
+
+ while (stop_angle < start_angle - db::epsilon) {
+ stop_angle += M_PI * 2.0;
+ }
+
+ db::DVector rr (radius * 0.9, radius * 0.9);
+ std::pair v = lay::snap (trans * (center - rr), trans * (center + rr));
+ draw_ellipse (v.first, v.second, radius * 2.0, sel, bitmap, renderer, start_angle, stop_angle);
+
+ // @@@ TODO: draw text, apply styles to circle segments? ...
+}
+
void
draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
- if (ruler.outline () == Object::OL_box || ruler.outline () == Object::OL_ellipse) {
-
- draw_ruler_segment (ruler, std::numeric_limits::max (), trans, sel, bitmap, renderer);
-
+ if (ruler.outline () == Object::OL_box) {
+ draw_ruler_box (ruler, trans, sel, bitmap, renderer);
+ } else if (ruler.outline () == Object::OL_ellipse) {
+ draw_ruler_ellipse (ruler, trans, sel, bitmap, renderer);
+ } else if (ruler.outline () == Object::OL_angle) {
+ draw_ruler_angle (ruler, trans, sel, bitmap, renderer);
+ } else if (ruler.outline () == Object::OL_radius) {
+ draw_ruler_radius (ruler, trans, sel, bitmap, renderer);
} else {
-
- // other styles support segments, so paint them individually
+ // other outline styles support segments, so paint them individually
for (size_t index = 0; index < ruler.segments (); ++index) {
draw_ruler_segment (ruler, index, trans, sel, bitmap, renderer);
}
-
}
}
static bool
is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, double enl, double &distance)
{
+// @@@ angle, radius
ant::Object::outline_type outline = ruler.outline ();
db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index);
@@ -759,7 +934,7 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
static bool
is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance)
{
- if (ruler.outline () == ant::Object::OL_box || ruler.outline () == ant::Object::OL_ellipse) {
+ if (ruler.outline () == ant::Object::OL_box || ruler.outline () == ant::Object::OL_ellipse || ruler.outline () == ant::Object::OL_angle || ruler.outline () == ant::Object::OL_radius) {
return is_selected (ruler, std::numeric_limits::max (), pos, enl, distance);
}
@@ -1078,6 +1253,7 @@ Service::insert_ruler (const ant::Object &ruler, bool limit_number)
static bool
dragging_what_seg (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1, size_t index)
{
+// @@@ radius, angle
ant::Object::outline_type outline = robj->outline ();
db::DPoint p12, p21;
@@ -1159,7 +1335,7 @@ dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Servic
{
ant::Object::outline_type outline = robj->outline ();
- if (outline == ant::Object::OL_box || outline == ant::Object::OL_ellipse) {
+ if (outline == ant::Object::OL_box || outline == ant::Object::OL_ellipse || outline == ant::Object::OL_angle || outline == ant::Object::OL_radius) {
index = std::numeric_limits::max ();
return dragging_what_seg (robj, search_dbox, mode, p1, index);
}
@@ -1719,12 +1895,12 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
}
- } else if (tpl.mode () == ant::Template::RulerMultiSegment || tpl.mode () == ant::Template::RulerAngle) {
+ } else if (tpl.mode () == ant::Template::RulerMultiSegment || tpl.mode () == ant::Template::RulerThreeClicks) {
ant::Object::point_list pts = m_current.points ();
tl_assert (! pts.empty ());
- if (tpl.mode () == ant::Template::RulerAngle && pts.size () == 3) {
+ if (tpl.mode () == ant::Template::RulerThreeClicks && pts.size () == 3) {
finish_drawing ();
diff --git a/src/ant/ant/antTemplate.h b/src/ant/ant/antTemplate.h
index 6b1bbbf8b..ab561a5e8 100644
--- a/src/ant/ant/antTemplate.h
+++ b/src/ant/ant/antTemplate.h
@@ -67,7 +67,7 @@ public:
/**
* @brief The ruler an angle type (two segments, three mouse clicks) for angle and circle radius measurements
*/
- RulerAngle = 3,
+ RulerThreeClicks = 3,
/**
* @brief The ruler is a multi-segment type
diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc
index 24b3d47ca..032190b48 100644
--- a/src/ant/ant/gsiDeclAnt.cc
+++ b/src/ant/ant/gsiDeclAnt.cc
@@ -48,6 +48,8 @@ static int outline_yx () { return int (ant::Object::OL_yx); }
static int outline_diag_yx () { return int (ant::Object::OL_diag_yx); }
static int outline_box () { return int (ant::Object::OL_box); }
static int outline_ellipse () { return int (ant::Object::OL_ellipse); }
+static int outline_angle () { return int (ant::Object::OL_angle); }
+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); }
@@ -432,9 +434,9 @@ static int ruler_mode_auto_metric ()
return ant::Template::RulerAutoMetric;
}
-static int ruler_mode_angle ()
+static int ruler_mode_three_clicks ()
{
- return ant::Template::RulerAngle;
+ return ant::Template::RulerThreeClicks;
}
static int ruler_mode_multi_segment ()
@@ -523,9 +525,9 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"\n"
"This constant has been introduced in version 0.25"
) +
- gsi::method ("RulerAngle", &gsi::ruler_mode_angle,
- "@brief Specifies angle ruler mode for the \\register_template method\n"
- "In angle ruler mode, two segments are created for angle and circle radius measurements. Three mouse clicks are required.\n"
+ gsi::method ("RulerThreeClicks", &gsi::ruler_mode_three_clicks,
+ "@brief Specifies three-click ruler mode for the \\register_template method\n"
+ "In this ruler mode, two segments are created for angle and circle radius measurements. Three mouse clicks are required.\n"
"\n"
"This constant has been introduced in version 0.28"
) +
@@ -535,58 +537,58 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"\n"
"This constant has been introduced in version 0.28"
) +
- gsi::method ("StyleRuler|#style_ruler", &gsi::style_ruler,
+ gsi::method ("StyleRuler", &gsi::style_ruler,
"@brief Gets the ruler style code for use the \\style method\n"
"When this style is specified, the annotation will show a ruler with "
"some ticks at distances indicating a decade of units and a suitable "
"subdivision into minor ticks at intervals of 1, 2 or 5 units."
) +
- gsi::method ("StyleArrowEnd|#style_arrow_end", &gsi::style_arrow_end,
+ gsi::method ("StyleArrowEnd", &gsi::style_arrow_end,
"@brief Gets the end arrow style code for use the \\style method\n"
"When this style is specified, an arrow is drawn pointing from the start to the end point."
) +
- gsi::method ("StyleArrowStart|#style_arrow_start", &gsi::style_arrow_start,
+ gsi::method ("StyleArrowStart", &gsi::style_arrow_start,
"@brief Gets the start arrow style code for use the \\style method\n"
"When this style is specified, an arrow is drawn pointing from the end to the start point."
) +
- gsi::method ("StyleArrowBoth|#style_arrow_both", &gsi::style_arrow_both,
+ gsi::method ("StyleArrowBoth", &gsi::style_arrow_both,
"@brief Gets the both arrow ends style code for use the \\style method\n"
"When this style is specified, a two-headed arrow is drawn."
) +
- gsi::method ("StyleLine|#style_line", &gsi::style_line,
+ gsi::method ("StyleLine", &gsi::style_line,
"@brief Gets the line style code for use with the \\style method\n"
"When this style is specified, a plain line is drawn."
) +
- gsi::method ("StyleCrossStart|#style_cross_start", &gsi::style_cross_start,
+ gsi::method ("StyleCrossStart", &gsi::style_cross_start,
"@brief Gets the line style code for use with the \\style method\n"
"When this style is specified, a cross is drawn at the start point.\n"
"\n"
"This constant has been added in version 0.26."
) +
- gsi::method ("StyleCrossEnd|#style_cross_end", &gsi::style_cross_end,
+ gsi::method ("StyleCrossEnd", &gsi::style_cross_end,
"@brief Gets the line style code for use with the \\style method\n"
"When this style is specified, a cross is drawn at the end point.\n"
"\n"
"This constant has been added in version 0.26."
) +
- gsi::method ("StyleCrossBoth|#style_cross_both", &gsi::style_cross_both,
+ gsi::method ("StyleCrossBoth", &gsi::style_cross_both,
"@brief Gets the line style code for use with the \\style method\n"
"When this style is specified, a cross is drawn at both points.\n"
"\n"
"This constant has been added in version 0.26."
) +
- gsi::method ("OutlineDiag|#outline_diag", &gsi::outline_diag,
+ gsi::method ("OutlineDiag", &gsi::outline_diag,
"@brief Gets the diagonal output code for use with the \\outline method\n"
"When this outline style is specified, a line connecting start and "
"end points in the given style (ruler, arrow or plain line) is drawn."
) +
- gsi::method ("OutlineXY|#outline_xy", &gsi::outline_xy,
+ gsi::method ("OutlineXY", &gsi::outline_xy,
"@brief Gets the xy outline code for use with the \\outline method\n"
"When this outline style is specified, two lines are drawn: one horizontal from left "
"to right and attached to the end of that a line from the bottom to the top. The lines "
"are drawn in the specified style (see \\style method)."
) +
- gsi::method ("OutlineDiagXY|#outline_diag_xy", &gsi::outline_diag_xy,
+ gsi::method ("OutlineDiagXY", &gsi::outline_diag_xy,
"@brief Gets the xy plus diagonal outline code for use with the \\outline method\n"
"@brief outline_xy code used by the \\outline method\n"
"When this outline style is specified, three lines are drawn: one horizontal from left "
@@ -594,53 +596,65 @@ gsi::Class decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"is drawn connecting the start and end points directly. The lines "
"are drawn in the specified style (see \\style method)."
) +
- gsi::method ("OutlineYX|#outline_yx", &gsi::outline_yx ,
+ gsi::method ("OutlineYX", &gsi::outline_yx ,
"@brief Gets the yx outline code for use with the \\outline method\n"
"When this outline style is specified, two lines are drawn: one vertical from bottom "
"to top and attached to the end of that a line from the left to the right. The lines "
"are drawn in the specified style (see \\style method)."
) +
- gsi::method ("OutlineDiagYX|#outline_diag_yx", &gsi::outline_diag_yx ,
+ gsi::method ("OutlineDiagYX", &gsi::outline_diag_yx ,
"@brief Gets the yx plus diagonal outline code for use with the \\outline method\n"
"When this outline style is specified, three lines are drawn: one vertical from bottom "
"to top and attached to the end of that a line from the left to the right. Another line "
"is drawn connecting the start and end points directly. The lines "
"are drawn in the specified style (see \\style method)."
) +
- gsi::method ("OutlineBox|#outline_box", &gsi::outline_box,
+ gsi::method ("OutlineBox", &gsi::outline_box,
"@brief Gets the box outline code for use with the \\outline method\n"
"When this outline style is specified, a box is drawn with the corners specified by the "
"start and end point. All box edges are drawn in the style specified with the \\style "
"attribute."
) +
- gsi::method ("OutlineEllipse|#outline_ellipse", &gsi::outline_ellipse,
+ gsi::method ("OutlineEllipse", &gsi::outline_ellipse,
"@brief Gets the ellipse outline code for use with the \\outline method\n"
"When this outline style is specified, an ellipse is drawn with the extensions specified by the "
"start and end point. The contour drawn as a line.\n"
"\n"
"This constant has been introduced in version 0.26."
) +
- gsi::method ("AngleAny|#angle_any", &gsi::angle_any,
+ gsi::method ("OutlineAngle", &gsi::outline_angle,
+ "@brief Gets the angle measurement ruler outline code for use with the \\outline method\n"
+ "When this outline style is specified, the ruler is drawn to indicate the angle between the first and last segment.\n"
+ "\n"
+ "This constant has been introduced in version 0.28."
+ ) +
+ gsi::method ("OutlineRadius", &gsi::outline_radius,
+ "@brief Gets the radius measurement ruler outline code for use with the \\outline method\n"
+ "When this outline style is specified, the ruler is drawn to indicate a radius defined by at least three points of the ruler.\n"
+ "\n"
+ "This constant has been introduced in version 0.28."
+ ) +
+ gsi::method ("AngleAny", &gsi::angle_any,
"@brief Gets the any angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, all angles will be allowed."
) +
- gsi::method ("AngleDiagonal|#angle_diagonal", &gsi::angle_diagonal,
+ gsi::method ("AngleDiagonal", &gsi::angle_diagonal,
"@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 ("AngleOrtho|#angle_ortho", &gsi::angle_ortho,
+ 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."
) +
- gsi::method ("AngleHorizontal|#angle_horizontal", &gsi::angle_horizontal,
+ gsi::method ("AngleHorizontal", &gsi::angle_horizontal,
"@brief Gets the horizontal angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only horizontal rulers are allowed."
) +
- gsi::method ("AngleVertical|#angle_vertical", &gsi::angle_vertical,
+ gsi::method ("AngleVertical", &gsi::angle_vertical,
"@brief Gets the vertical angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only vertical rulers are allowed."
) +
- gsi::method ("AngleGlobal|#angle_global", &gsi::angle_global,
+ gsi::method ("AngleGlobal", &gsi::angle_global,
"@brief Gets the global angle code for use with the \\angle_constraint method.\n"
"This code will tell the ruler or marker to use the angle constraint defined globally."
) +
From 996f0d75e51db4f50497832ba82f268e31e1e5d2 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 00:43:23 +0200
Subject: [PATCH 15/54] WIP: debugging of angle ruler, display options
implemented
---
src/ant/ant/antObject.cc | 125 +++++++++++++++++
src/ant/ant/antObject.h | 20 +++
src/ant/ant/antPlugin.cc | 4 +-
src/ant/ant/antService.cc | 276 ++++++++++++++++++--------------------
4 files changed, 276 insertions(+), 149 deletions(-)
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index 510ce87a3..b17a8cef3 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -452,6 +452,22 @@ public:
out = (trans * p2 (obj)).x ();
} else if (m_function == 'Q') {
out = (trans * p2 (obj)).y ();
+ } else if (m_function == 'R') {
+ double r, a1, a2;
+ db::DPoint c;
+ if (obj.compute_interpolating_circle (r, c, a1, a2)) {
+ out = tl::Variant (r);
+ } else {
+ out = tl::Variant ();
+ }
+ } else if (m_function == 'G') {
+ double r, a1, a2;
+ db::DPoint c;
+ if (obj.compute_angle_parameters (r, c, a1, a2)) {
+ out = tl::Variant ((a2 - a1) * 180.0 / M_PI);
+ } else {
+ out = tl::Variant ();
+ }
} else {
out = tl::Variant ();
}
@@ -512,6 +528,8 @@ Object::formatted (const std::string &fmt, const db::DFTrans &t, size_t index) c
eval.define_function ("P", new AnnotationEvalFunction('P', &eval, index)); // p2.x
eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval, index)); // p2.y
eval.define_function ("A", new AnnotationEvalFunction('A', &eval, index)); // area mm2
+ eval.define_function ("R", new AnnotationEvalFunction('R', &eval, index)); // radius (if applicable)
+ eval.define_function ("G", new AnnotationEvalFunction('G', &eval, index)); // angle (if applicable)
return eval.interpolate (fmt);
}
@@ -808,6 +826,113 @@ Object::to_string () const
return r;
}
+bool
+Object::compute_interpolating_circle (double &radius, db::DPoint ¢er, double &start_angle, double &stop_angle) const
+{
+ if (m_points.size () < 2) {
+ return false;
+ }
+
+ double d = m_points.back ().distance (m_points.front ()) * 0.5;
+ if (d < db::epsilon) {
+ return false;
+ }
+
+ db::DVector n = m_points.back () - m_points.front ();
+ db::DPoint m = m_points.front () + n * 0.5;
+ n = db::DVector (n.y (), -n.x ()) * (1.0 / d);
+
+ double nom = 0.0;
+ double div = 0.0;
+
+ for (size_t i = 1; i + 1 < m_points.size (); ++i) {
+ db::DVector p = m_points [i] - m;
+ double pn = db::sprod (p, n);
+ div += pn * pn;
+ nom += pn * (p.sq_double_length () - d * d);
+ }
+
+ if (div < db::epsilon) {
+ return false;
+ }
+
+ double l = 0.5 * nom / div;
+ radius = sqrt (l * l + d * d);
+ center = m + n * l;
+
+ double a = atan2 (-n.y (), -n.x ());
+ double da = atan2 (d, l);
+
+ if (fabs (l) < db::epsilon) {
+
+ start_angle = 0.0;
+ stop_angle = M_PI * 2.0;
+
+ } else if (l < 0.0) {
+
+ start_angle = a + da;
+ stop_angle = start_angle + 2.0 * (M_PI - da);
+
+ } else {
+
+ start_angle = a - da;
+ stop_angle = a + da;
+
+ }
+
+ while (stop_angle < start_angle - db::epsilon) {
+ stop_angle += M_PI * 2.0;
+ }
+
+ return true;
+}
+
+bool
+Object::compute_angle_parameters (double &radius, db::DPoint ¢er, double &start_angle, double &stop_angle) const
+{
+ if (m_points.size () < 3) {
+ return false;
+ }
+
+ db::DPoint p1 = m_points.front (), p2 = m_points.back ();
+
+ db::DVector pc;
+ for (size_t i = 1; i + 1 < m_points.size (); ++i) {
+ pc += m_points[i] - db::DPoint ();
+ }
+ center = db::DPoint () + pc * (1.0 / double (m_points.size () - 2));
+
+ db::DVector v1 (p1 - center);
+ if (v1.double_length () < db::epsilon) {
+ return false;
+ }
+
+ db::DVector v2 (p2 - center);
+ if (v2.double_length () < db::epsilon) {
+ return false;
+ }
+
+ radius = std::min (v1.double_length (), v2.double_length ());
+
+ v1 *= 1.0 / v1.double_length ();
+ v2 *= 1.0 / v2.double_length ();
+
+ if (db::vprod_sign (v1, v2) == 0) {
+ return false;
+ }
+
+ start_angle = 0.0;
+ stop_angle = 0.0;
+ start_angle = atan2 (v1.y (), v1.x ());
+ stop_angle = atan2 (v2.y (), v2.x ());
+
+ while (stop_angle < start_angle - db::epsilon) {
+ stop_angle += M_PI * 2.0;
+ }
+
+ return true;
+}
+
void
Object::property_changed ()
{
diff --git a/src/ant/ant/antObject.h b/src/ant/ant/antObject.h
index e225ce593..5bcb800ed 100644
--- a/src/ant/ant/antObject.h
+++ b/src/ant/ant/antObject.h
@@ -759,6 +759,26 @@ public:
*/
virtual std::string to_string () const;
+ /**
+ * @brief Computes the parameters for an angle ruler
+ * @param radius Returns the radius
+ * @param center Returns the center point
+ * @param start_angle Returns the start angle (in radians)
+ * @param stop_angle Returns the stop angle (in radians)
+ * @return True, if the ruler represents an angle measurement
+ */
+ bool compute_angle_parameters (double &radius, db::DPoint ¢er, double &start_angle, double &stop_angle) const;
+
+ /**
+ * @brief Computes the parameters for a radius ruler
+ * @param radius Returns the radius
+ * @param center Returns the center point
+ * @param start_angle Returns the start angle (in radians)
+ * @param stop_angle Returns the stop angle (in radians)
+ * @return True, if the ruler represents an angle measurement
+ */
+ bool compute_interpolating_circle (double &radius, db::DPoint ¢er, double &start_angle, double &stop_angle) const;
+
protected:
/**
* @brief A notification method that is called when a property of the annotation has changed
diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc
index 7175b11c9..f95d9ca08 100644
--- a/src/ant/ant/antPlugin.cc
+++ b/src/ant/ant/antPlugin.cc
@@ -77,10 +77,10 @@ static std::vector make_standard_templates ()
templates.push_back (ant::Template (tl::to_string (tr ("Measure")), "$X", "$Y", "$D", ant::Object::STY_ruler, ant::Object::OL_diag, true, lay::AC_Global, "_measure"));
templates.back ().set_mode (ant::Template::RulerAutoMetric);
- templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_angle, true, lay::AC_Global, "_angle"));
+ templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "", "", "$(sprintf('%.5g',G))°", ant::Object::STY_line, ant::Object::OL_angle, true, lay::AC_Global, "_angle"));
templates.back ().set_mode (ant::Template::RulerThreeClicks);
- templates.push_back (ant::Template (tl::to_string (tr ("Radius")), "$X", "$Y", "$D", ant::Object::STY_line, ant::Object::OL_radius, true, lay::AC_Global, "_radius"));
+ templates.push_back (ant::Template (tl::to_string (tr ("Radius")), "", "", "$R", ant::Object::STY_line, ant::Object::OL_radius, true, lay::AC_Global, "_radius"));
templates.back ().set_mode (ant::Template::RulerThreeClicks);
templates.push_back (ant::Template (tl::to_string (tr ("Ellipse")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_ellipse, true, lay::AC_Global, std::string ()));
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index cee1d246e..362ffe7ea 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -127,7 +127,8 @@ draw_ruler (const db::DPoint &q1,
lay::CanvasPlane *bitmap,
lay::Renderer &renderer,
bool first_segment,
- bool last_segment)
+ bool last_segment,
+ bool no_line = false)
{
double arrow_width = 8 / renderer.resolution ();
double arrow_length = 12 / renderer.resolution ();
@@ -161,12 +162,14 @@ draw_ruler (const db::DPoint &q1,
// normal and unit vector
double len = q1.double_distance (q2);
- if ((style == ant::Object::STY_arrow_end || style == ant::Object::STY_arrow_start) && len < double (arrow_length) * 1.2) {
- arrow_length = len / 1.2;
- arrow_width = arrow_length * 2.0 / 3.0;
- } else if (style == ant::Object::STY_arrow_both && len < double (arrow_length) * 2.4) {
- arrow_length = len / 2.4;
- arrow_width = arrow_length * 2.0 / 3.0;
+ if (! no_line && len < double (arrow_length) * 2.4) {
+ if ((style == ant::Object::STY_arrow_end || style == ant::Object::STY_arrow_start)) {
+ arrow_length = len / 1.2;
+ arrow_width = arrow_length * 2.0 / 3.0;
+ } else if (style == ant::Object::STY_arrow_both) {
+ arrow_length = len / 2.4;
+ arrow_width = arrow_length * 2.0 / 3.0;
+ }
}
db::DVector qq (q2.y () - q1.y (), q1.x () - q2.x ());
@@ -186,38 +189,46 @@ draw_ruler (const db::DPoint &q1,
qu = db::DVector (1.0, 0.0);
}
- // produce polygon stuff
+ // produce line in selected and unselected mode
- if (sel && style != ant::Object::STY_none) {
+ if (! no_line && style != ant::Object::STY_none) {
+
+ if (sel) {
+
+ db::DVector qw = qq * (sel_width * 0.5);
+
+ db::DVector dq1, dq2;
+ if (! first_segment) {
+ // no start indicator if not first segment
+ } else if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_start) {
+ dq1 = qu * (arrow_length - 1);
+ } else if (style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_start) {
+ dq1 = qu * (sel_width * 0.5);
+ }
+ if (! last_segment) {
+ // no end indicator if not last segment
+ } else if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_end) {
+ dq2 = qu * -(arrow_length - 1);
+ } else if (style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_end) {
+ dq2 = qu * -(sel_width * 0.5);
+ }
+
+ db::DPolygon p;
+ db::DPoint points[] = {
+ db::DPoint (q1 + dq1 + qw),
+ db::DPoint (q2 + dq2 + qw),
+ db::DPoint (q2 + dq2 - qw),
+ db::DPoint (q1 + dq1 - qw),
+ };
+ p.assign_hull (points, points + sizeof (points) / sizeof (points [0]));
+ renderer.draw (p, bitmap, bitmap, 0, 0);
+
+ } else {
+
+ renderer.draw (db::DEdge (q1, q2), 0, bitmap, 0, 0);
- db::DVector qw = qq * (sel_width * 0.5);
-
- db::DVector dq1, dq2;
- if (! first_segment) {
- // no start indicator if not first segment
- } else if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_start) {
- dq1 = qu * (arrow_length - 1);
- } else if (style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_start) {
- dq1 = qu * (sel_width * 0.5);
- }
- if (! last_segment) {
- // no end indicator if not last segment
- } else if (style == ant::Object::STY_arrow_both || style == ant::Object::STY_arrow_end) {
- dq2 = qu * -(arrow_length - 1);
- } else if (style == ant::Object::STY_cross_both || style == ant::Object::STY_cross_end) {
- dq2 = qu * -(sel_width * 0.5);
}
- db::DPolygon p;
- db::DPoint points[] = {
- db::DPoint (q1 + dq1 + qw),
- db::DPoint (q2 + dq2 + qw),
- db::DPoint (q2 + dq2 - qw),
- db::DPoint (q1 + dq1 - qw),
- };
- p.assign_hull (points, points + sizeof (points) / sizeof (points [0]));
- renderer.draw (p, bitmap, bitmap, 0, 0);
-
}
if (! last_segment) {
@@ -282,12 +293,6 @@ draw_ruler (const db::DPoint &q1,
}
- // produce edge and text stuff
-
- if (! sel && style != ant::Object::STY_none) {
- renderer.draw (db::DEdge (q1, q2), 0, bitmap, 0, 0);
- }
-
// create three tick vectors in tv_text, tv_short and tv_long
double tf = tick_length;
@@ -680,67 +685,6 @@ draw_ruler_ellipse (const ant::Object &ruler, const db::DCplxTrans &trans, bool
draw_ellipse (q1, q2, lu, sel, bitmap, renderer);
}
-bool
-compute_interpolating_circle (const ant::Object::point_list &points, double &radius, db::DPoint ¢er, double &start_angle, double &stop_angle)
-{
- if (points.size () < 2) {
- return false;
- }
-
- double d = points.back ().distance (points.front ()) * 0.5;
- if (d < db::epsilon) {
- return false;
- }
-
- db::DVector n = points.back () - points.front ();
- db::DPoint m = points.front () + n * 0.5;
- n = db::DVector (n.y (), -n.x ()) * (1.0 / d);
-
- double nom = 0.0;
- double div = 0.0;
-
- for (size_t i = 1; i + 1 < points.size (); ++i) {
- db::DVector p = points [i] - m;
- double pn = db::sprod (p, n);
- div += pn * pn;
- nom += pn * (p.sq_double_length () - d * d);
- }
-
- if (div < db::epsilon) {
- return false;
- }
-
- double l = 0.5 * nom / div;
- radius = sqrt (l * l + d * d);
- center = m + n * l;
-
- double a = atan2 (-n.y (), -n.x ());
- double da = atan2 (d, l);
-
- if (fabs (l) < db::epsilon) {
-
- start_angle = 0.0;
- stop_angle = M_PI * 2.0;
-
- } else if (l < 0.0) {
-
- start_angle = a + da;
- stop_angle = start_angle + 2.0 * (M_PI - da);
-
- } else {
-
- start_angle = a - da;
- stop_angle = a + da;
-
- }
-
- while (stop_angle < start_angle - db::epsilon) {
- stop_angle += M_PI * 2.0;
- }
-
- return true;
-}
-
void
draw_ruler_radius (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
@@ -755,7 +699,7 @@ draw_ruler_radius (const ant::Object &ruler, const db::DCplxTrans &trans, bool s
db::DPoint center;
// circle interpolation
- if (compute_interpolating_circle (ruler.points (), radius, center, start_angle, stop_angle)) {
+ if (ruler.compute_interpolating_circle (radius, center, start_angle, stop_angle)) {
// draw circle segment
db::DVector rr (radius, radius);
@@ -779,62 +723,100 @@ draw_ruler_radius (const ant::Object &ruler, const db::DCplxTrans &trans, bool s
void
draw_ruler_angle (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay::CanvasPlane *bitmap, lay::Renderer &renderer)
{
- // draw segments in diag mode
- ant::Object basic = ruler;
- basic.outline (ant::Object::OL_diag);
- draw_ruler_segment (basic, 0, trans, sel, bitmap, renderer);
- if (basic.segments () > 1) {
- draw_ruler_segment (basic, basic.segments () - 1, trans, sel, bitmap, renderer);
+ // draw guiding segments in diag/plain line mode
+
+ for (int p = 0; p < 2; ++p) {
+
+ auto p1 = (p == 0 ? ruler.p1 () : ruler.seg_p1 (ruler.segments () - 1));
+ auto p2 = (p == 0 ? ruler.seg_p2 (0) : ruler.p2 ());
+
+ auto v = lay::snap (trans * p1, trans * p2);
+ auto q1 = v.first;
+ auto q2 = v.second;
+
+ double lu = p1.double_distance (p2);
+
+ draw_ruler (q1, q2, lu, 0.0, sel, false, ant::Object::STY_line, bitmap, renderer, true, true);
+
}
- if (ruler.points ().size () < 3) {
+ double radius = 0.0, start_angle = 0.0, stop_angle = 0.0;
+ db::DPoint center;
+
+ if (! ruler.compute_angle_parameters (radius, center, start_angle, stop_angle)) {
return;
}
- db::DPoint p1 = ruler.p1 (), p2 = ruler.p2 ();
+ double circle_radius = 0.9 * radius;
- db::DVector pc;
- for (size_t i = 1; i + 1 < ruler.points ().size (); ++i) {
- pc += ruler.points ()[i] - db::DPoint ();
- }
- db::DPoint center = db::DPoint () + pc * (1.0 / double (ruler.points ().size () - 2));
+ // draw decorations at start/end
+
+ for (int p = 0; p < 2; ++p) {
+
+ double a = (p == 0 ? start_angle : stop_angle);
+
+ db::DPoint p1 = center + db::DVector (cos (a), sin (a)) * circle_radius;
+
+ auto v = lay::snap (trans * p1, trans * p1);
+ db::DVector vn = db::DVector (-sin (a), cos (a));
+ auto q1 = v.first + vn * (p == 0 ? 0.0 : -1.0);
+ auto q2 = v.second + vn * (p == 0 ? 1.0 : 0.0);
+
+ double lu = abs (circle_radius * (stop_angle - start_angle));
+
+ draw_ruler (q1, q2, lu, 0.0, sel, false, ruler.style (), bitmap, renderer, p == 0, p != 0, true);
- db::DVector v1 (p1 - center);
- if (v1.double_length () < db::epsilon) {
- return;
}
- db::DVector v2 (p2 - center);
- if (v2.double_length () < db::epsilon) {
- return;
- }
-
- double radius = std::min (v1.double_length (), v2.double_length ());
-
- v1 *= 1.0 / v1.double_length ();
- v2 *= 1.0 / v2.double_length ();
-
- if (db::vprod_sign (v1, v2) == 0) {
- return;
- }
-
- double start_angle = 0.0, stop_angle = 0.0;
- start_angle = atan2 (v1.y (), v1.x ());
- stop_angle = atan2 (v2.y (), v2.x ());
-
- if (db::vprod_sign (v1, v2) < 0) {
- std::swap (start_angle, stop_angle);
- }
-
- while (stop_angle < start_angle - db::epsilon) {
- stop_angle += M_PI * 2.0;
- }
-
- db::DVector rr (radius * 0.9, radius * 0.9);
+ db::DVector rr (circle_radius, circle_radius);
std::pair v = lay::snap (trans * (center - rr), trans * (center + rr));
draw_ellipse (v.first, v.second, radius * 2.0, sel, bitmap, renderer, start_angle, stop_angle);
- // @@@ TODO: draw text, apply styles to circle segments? ...
+ if (ruler.style () == ant::Object::STY_ruler) {
+
+ // draw ticks if required - minor at 5 degree, major at 10 degree
+
+ double tick_length = 8 / renderer.resolution ();
+
+ double da = 5.0 / 180.0 * M_PI;
+ unsigned int major_ticks = 2;
+
+ double n = floor (db::epsilon + std::min (2 * M_PI, stop_angle - start_angle) / da);
+ unsigned int ticks = (unsigned int) std::max (1.0, n);
+
+ for (unsigned int i = 0; i <= ticks; ++i) {
+
+ double l = tick_length * ((i % major_ticks) == 0 ? 1.0 : 0.5);
+
+ double a = start_angle + i * da;
+ db::DVector tv (cos (a), sin (a));
+ db::DPoint p1 = center + tv * circle_radius;
+
+ auto v = lay::snap (trans * p1, trans * p1);
+ auto q1 = v.first;
+ auto q2 = v.second + tv * l;
+
+ renderer.draw (db::DEdge (q1, q2), 0, bitmap, 0, 0);
+
+ }
+
+ }
+
+ {
+ double ta = 0.5 * (stop_angle + start_angle);
+
+ db::DPoint tp = center + db::DVector (cos (ta), sin (ta)) * circle_radius;
+ db::DVector tv = db::DVector (-sin (ta), cos (ta));
+
+ auto v = lay::snap (trans * tp, trans * tp);
+ auto q1 = v.first + tv;
+ auto q2 = v.second - tv;
+
+ double lu = abs (circle_radius * (stop_angle - start_angle));
+
+ draw_text (q1, q2, lu, ruler.text (0), false, ruler.style (), ruler.main_position (), ruler.main_xalign (), ruler.main_yalign (), bitmap, renderer);
+
+ }
}
void
From 1057c0f268e11001174bf01c205b7dde4e7f630f Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 01:38:18 +0200
Subject: [PATCH 16/54] WIP: debugging of radius rulers
---
src/ant/ant/antObject.cc | 12 ++----------
src/ant/ant/antPlugin.cc | 3 ++-
src/ant/ant/antService.cc | 9 ++++++++-
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index b17a8cef3..4969bc613 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -452,14 +452,6 @@ public:
out = (trans * p2 (obj)).x ();
} else if (m_function == 'Q') {
out = (trans * p2 (obj)).y ();
- } else if (m_function == 'R') {
- double r, a1, a2;
- db::DPoint c;
- if (obj.compute_interpolating_circle (r, c, a1, a2)) {
- out = tl::Variant (r);
- } else {
- out = tl::Variant ();
- }
} else if (m_function == 'G') {
double r, a1, a2;
db::DPoint c;
@@ -528,7 +520,6 @@ Object::formatted (const std::string &fmt, const db::DFTrans &t, size_t index) c
eval.define_function ("P", new AnnotationEvalFunction('P', &eval, index)); // p2.x
eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval, index)); // p2.y
eval.define_function ("A", new AnnotationEvalFunction('A', &eval, index)); // area mm2
- eval.define_function ("R", new AnnotationEvalFunction('R', &eval, index)); // radius (if applicable)
eval.define_function ("G", new AnnotationEvalFunction('G', &eval, index)); // angle (if applicable)
return eval.interpolate (fmt);
}
@@ -840,7 +831,7 @@ Object::compute_interpolating_circle (double &radius, db::DPoint ¢er, double
db::DVector n = m_points.back () - m_points.front ();
db::DPoint m = m_points.front () + n * 0.5;
- n = db::DVector (n.y (), -n.x ()) * (1.0 / d);
+ n = db::DVector (n.y (), -n.x ()) * (0.5 / d);
double nom = 0.0;
double div = 0.0;
@@ -872,6 +863,7 @@ Object::compute_interpolating_circle (double &radius, db::DPoint ¢er, double
start_angle = a + da;
stop_angle = start_angle + 2.0 * (M_PI - da);
+ std::swap (start_angle, stop_angle); // @@@
} else {
diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc
index f95d9ca08..3545deb40 100644
--- a/src/ant/ant/antPlugin.cc
+++ b/src/ant/ant/antPlugin.cc
@@ -80,8 +80,9 @@ static std::vector make_standard_templates ()
templates.push_back (ant::Template (tl::to_string (tr ("Angle")), "", "", "$(sprintf('%.5g',G))°", ant::Object::STY_line, ant::Object::OL_angle, true, lay::AC_Global, "_angle"));
templates.back ().set_mode (ant::Template::RulerThreeClicks);
- templates.push_back (ant::Template (tl::to_string (tr ("Radius")), "", "", "$R", ant::Object::STY_line, ant::Object::OL_radius, true, lay::AC_Global, "_radius"));
+ templates.push_back (ant::Template (tl::to_string (tr ("Radius")), "", "", "R=$D", ant::Object::STY_arrow_end, ant::Object::OL_radius, true, lay::AC_Global, "_radius"));
templates.back ().set_mode (ant::Template::RulerThreeClicks);
+ templates.back ().set_main_position (ant::Object::POS_center);
templates.push_back (ant::Template (tl::to_string (tr ("Ellipse")), "W=$(abs(X))", "H=$(abs(Y))", "", ant::Object::STY_line, ant::Object::OL_ellipse, true, lay::AC_Global, std::string ()));
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index 362ffe7ea..41be56346 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -709,12 +709,19 @@ draw_ruler_radius (const ant::Object &ruler, const db::DCplxTrans &trans, bool s
double a = 0.5 * (start_angle + stop_angle);
db::DPoint rc = center + db::DVector (cos (a), sin (a)) * radius;
+#if 0
// draw a center marker
ant::Object center_loc (center, center, 0, std::string (), ruler.fmt_x (), ruler.fmt_y (), ant::Object::STY_cross_start, ant::Object::OL_diag, false, lay::AC_Global);
draw_ruler_segment (center_loc, 0, trans, sel, bitmap, renderer);
+#endif
// draw the radius ruler
- ant::Object radius (center, rc, 0, ruler.fmt (), std::string (), std::string (), ruler.style (), ruler.outline (), false, lay::AC_Global);
+ ant::Object radius = ruler;
+ radius.outline (ant::Object::OL_diag);
+ ant::Object::point_list pts;
+ pts.push_back (center);
+ pts.push_back (rc);
+ radius.set_points (pts);
draw_ruler_segment (radius, 0, trans, sel, bitmap, renderer);
}
From 1660a72b5a158679546a3e6c40fe6f3165c39f48 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 01:45:47 +0200
Subject: [PATCH 17/54] WIP: restored logo on 'About' page
---
src/lay/lay/HelpAboutDialog.ui | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lay/lay/HelpAboutDialog.ui b/src/lay/lay/HelpAboutDialog.ui
index 69753802a..07b329094 100644
--- a/src/lay/lay/HelpAboutDialog.ui
+++ b/src/lay/lay/HelpAboutDialog.ui
@@ -137,7 +137,7 @@
- :/logo@2x.png
+ :/logo.png
From 069c3e64474f1abafc3cd52471ff3acba29b1fcc Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 12:39:05 +0200
Subject: [PATCH 18/54] WIP: proper selection of angle and radius rulers
---
src/ant/ant/antObject.cc | 9 ++++--
src/ant/ant/antService.cc | 58 +++++++++++++++++++++++++++++----------
2 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/src/ant/ant/antObject.cc b/src/ant/ant/antObject.cc
index 4969bc613..41d750642 100644
--- a/src/ant/ant/antObject.cc
+++ b/src/ant/ant/antObject.cc
@@ -861,9 +861,8 @@ Object::compute_interpolating_circle (double &radius, db::DPoint ¢er, double
} else if (l < 0.0) {
- start_angle = a + da;
- stop_angle = start_angle + 2.0 * (M_PI - da);
- std::swap (start_angle, stop_angle); // @@@
+ stop_angle = a + da;
+ start_angle = stop_angle + 2.0 * (M_PI - da);
} else {
@@ -918,6 +917,10 @@ Object::compute_angle_parameters (double &radius, db::DPoint ¢er, double &st
start_angle = atan2 (v1.y (), v1.x ());
stop_angle = atan2 (v2.y (), v2.x ());
+ if (db::vprod_sign (v1, v2) < 0) {
+ std::swap (stop_angle, start_angle);
+ }
+
while (stop_angle < start_angle - db::epsilon) {
stop_angle += M_PI * 2.0;
}
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index 41be56346..cb48588f9 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -44,6 +44,8 @@
namespace ant
{
+double angle_ruler_radius_factor = 0.9;
+
// -------------------------------------------------------------
// Convert buttons to an angle constraint
@@ -544,17 +546,10 @@ draw_ellipse (const db::DPoint &q1,
int npoints = int (floor (200 * abs (stop_angle - start_angle) / (2.0 * M_PI)));
- // produce polygon stuff
-
double rx = fabs ((q2 - q1).x () * 0.5);
double ry = fabs ((q2 - q1).y () * 0.5);
db::DPoint c = q1 + (q2 - q1) * 0.5;
- if (sel) {
- rx += sel_width * 0.5;
- ry += sel_width * 0.5;
- }
-
std::vector pts;
pts.reserve (npoints + 1);
@@ -754,7 +749,7 @@ draw_ruler_angle (const ant::Object &ruler, const db::DCplxTrans &trans, bool se
return;
}
- double circle_radius = 0.9 * radius;
+ double circle_radius = angle_ruler_radius_factor * radius;
// draw decorations at start/end
@@ -845,10 +840,38 @@ draw_ruler (const ant::Object &ruler, const db::DCplxTrans &trans, bool sel, lay
}
}
+static bool
+is_selected_by_circle_segment (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance)
+{
+ double r = 0.0, a1 = 0.0, a2 = 0.0;
+ db::DPoint c;
+
+ bool good;
+ if (ruler.outline () == ant::Object::OL_angle) {
+ good = ruler.compute_angle_parameters (r, c, a1, a2);
+ r *= angle_ruler_radius_factor;
+ } else {
+ good = ruler.compute_interpolating_circle (r, c, a1, a2);
+ }
+ if (good && fabs (pos.distance (c) - r) < enl) {
+
+ double a = atan2 ((pos - c).y (), (pos - c).x ()) - 2 * M_PI;
+ while (a < a1 - db::epsilon) {
+ a += 2 * M_PI;
+ }
+ if (a < a2 + db::epsilon) {
+ distance = std::min (distance, fabs (pos.distance (c) - r));
+ return true;
+ }
+
+ }
+
+ return false;
+}
+
static bool
is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, double enl, double &distance)
{
-// @@@ angle, radius
ant::Object::outline_type outline = ruler.outline ();
db::DPoint p1 = ruler.seg_p1 (index), p2 = ruler.seg_p2 (index);
@@ -868,7 +891,7 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
db::DPoint ref = b.center () + db::DVector (dx * b.width () * 0.5 / dd, dy * b.height () * 0.5 / dd);
double d = ref.distance (pos);
if (d < enl) {
- distance = d;
+ distance = std::min (distance, d);
return true;
}
}
@@ -890,6 +913,8 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
unsigned int nedges = 0;
if (outline == ant::Object::OL_diag ||
+ outline == ant::Object::OL_angle ||
+ outline == ant::Object::OL_radius ||
outline == ant::Object::OL_diag_xy ||
outline == ant::Object::OL_diag_yx) {
edges [nedges++] = db::DEdge (p1, p2);
@@ -912,7 +937,7 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
for (unsigned int i = 0; i < nedges; ++i) {
double d = edges [i].distance_abs (pos);
if (d <= enl) {
- distance = d;
+ distance = std::min (distance, d);
return true;
}
}
@@ -923,11 +948,15 @@ is_selected (const ant::Object &ruler, size_t index, const db::DPoint &pos, doub
static bool
is_selected (const ant::Object &ruler, const db::DPoint &pos, double enl, double &distance)
{
- if (ruler.outline () == ant::Object::OL_box || ruler.outline () == ant::Object::OL_ellipse || ruler.outline () == ant::Object::OL_angle || ruler.outline () == ant::Object::OL_radius) {
+ distance = std::numeric_limits::max ();
+ bool any = false;
+
+ if (ruler.outline () == ant::Object::OL_box || ruler.outline () == ant::Object::OL_ellipse) {
return is_selected (ruler, std::numeric_limits::max (), pos, enl, distance);
+ } else if (ruler.outline () == ant::Object::OL_angle || ruler.outline () == ant::Object::OL_radius) {
+ any = is_selected_by_circle_segment (ruler, pos, enl, distance);
}
- bool any = false;
for (size_t index = 0; index < ruler.segments (); ++index) {
// NOTE: we check *all* since distance is updated herein.
if (is_selected (ruler, index, pos, enl, distance)) {
@@ -1242,7 +1271,6 @@ Service::insert_ruler (const ant::Object &ruler, bool limit_number)
static bool
dragging_what_seg (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1, size_t index)
{
-// @@@ radius, angle
ant::Object::outline_type outline = robj->outline ();
db::DPoint p12, p21;
@@ -1324,7 +1352,7 @@ dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Servic
{
ant::Object::outline_type outline = robj->outline ();
- if (outline == ant::Object::OL_box || outline == ant::Object::OL_ellipse || outline == ant::Object::OL_angle || outline == ant::Object::OL_radius) {
+ if (outline == ant::Object::OL_box || outline == ant::Object::OL_ellipse) {
index = std::numeric_limits::max ();
return dragging_what_seg (robj, search_dbox, mode, p1, index);
}
From eedfc7c00f4764014e7a42d5932832b4a94dd9a8 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 13:04:25 +0200
Subject: [PATCH 19/54] Doc update, tests for new annotation features
---
src/doc/doc/manual/ruler_properties.xml | 1 +
testdata/ruby/antTest.rb | 233 +++++++++++++++++-------
2 files changed, 170 insertions(+), 64 deletions(-)
diff --git a/src/doc/doc/manual/ruler_properties.xml b/src/doc/doc/manual/ruler_properties.xml
index d889bd883..a1ffed576 100644
--- a/src/doc/doc/manual/ruler_properties.xml
+++ b/src/doc/doc/manual/ruler_properties.xml
@@ -76,6 +76,7 @@
X: The horizontal extension of the ruler in micron units.
Y: The vertical extension of the ruler in micron units.
A: The area enclosed by the ruler (if it was a box) in square millimeters.
+ G: The angle enclosed by the first and last segment of the ruler (used for angle measurement rulers).
diff --git a/testdata/ruby/antTest.rb b/testdata/ruby/antTest.rb
index 357cebe98..34677cd68 100644
--- a/testdata/ruby/antTest.rb
+++ b/testdata/ruby/antTest.rb
@@ -37,6 +37,19 @@ def annot_obj( p1, p2, fmt, fmt_x, fmt_y, style, outline, snap, ac )
return a
end
+def annot_obj2( pts, fmt, fmt_x, fmt_y, style, outline, snap, ac )
+ a = RBA::Annotation::new
+ a.points = pts
+ a.fmt = fmt
+ a.fmt_x = fmt_x
+ a.fmt_y = fmt_y
+ a.style = style
+ a.outline = outline
+ a.snap = snap
+ a.angle_constraint = ac
+ return a
+end
+
class RBA::Annotation
def style_to_s(s)
if s == StyleRuler
@@ -72,6 +85,12 @@ class RBA::Annotation
"diag_yx"
elsif s == OutlineBox
"diag_box"
+ elsif s == OutlineEllipse
+ "ellipse"
+ elsif s == OutlineAngle
+ "angle"
+ elsif s == OutlineRadius
+ "radius"
else
""
end
@@ -119,7 +138,7 @@ class RBA::Annotation
""
end
end
- def to_s
+ def to_s_debug
s = "p1=" + p1.to_s + ", p2=" + p2.to_s + ", fmt=" + fmt + ", fmt_x=" + fmt_x + ", fmt_y=" + fmt_y +
", style=" + self.style_to_s(style) + ", outline=" + self.outline_to_s(outline) + ", snap=" + snap?.to_s + ", ac=" + self.ac_to_s(angle_constraint)
if category != ""
@@ -160,13 +179,52 @@ class Ant_TestClass < TestBase
end
a = RBA::Annotation::new
- assert_equal( a.to_s, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global" )
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global" )
+
+ a.outline = RBA::Annotation::OutlineXY
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=xy, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineDiagXY
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag_xy, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineYX
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=yx, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineDiagYX
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag_yx, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineBox
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag_box, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineEllipse
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=ellipse, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineAngle
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=angle, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineRadius
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=radius, snap=true, ac=global" )
+ a.outline = RBA::Annotation::OutlineDiag
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global" )
+
+ a.style = RBA::Annotation::StyleArrowEnd
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=arrow_end, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleArrowStart
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=arrow_start, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleArrowBoth
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=arrow_both, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleLine
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=line, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleCrossEnd
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=cross_end, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleCrossStart
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=cross_start, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleCrossBoth
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=cross_both, outline=diag, snap=true, ac=global" )
+ a.style = RBA::Annotation::StyleRuler
+ assert_equal( a.to_s_debug, "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global" )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+
+ a = annot_obj2( [ RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ) ], "a", "b", "c", 1, 2, false, 3 )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
b = a.dup
- assert_equal( b.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( b.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
a = RBA::Annotation::new
assert_equal( a == b, false )
@@ -177,10 +235,10 @@ class Ant_TestClass < TestBase
assert_equal( a != b, false )
c = a.transformed( RBA::DTrans::new( RBA::DPoint::new( 10.0, 20.0 ) ) )
- assert_equal( c.to_s, "p1=11,22, p2=13,24, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( c.to_s_debug, "p1=11,22, p2=13,24, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
c = a.transformed_cplx( RBA::DCplxTrans::new( RBA::DTrans::new( RBA::DPoint::new( 11.0, 22.0 ) ) ) )
- assert_equal( c.to_s, "p1=12,24, p2=14,26, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( c.to_s_debug, "p1=12,24, p2=14,26, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
a.fmt = "X=$X,Y=$Y,D=$D,A=$A,P=$P,Q=$Q,U=$U,V=$V"
a.fmt_x = "$(X*1000)+$(Y*1e3)"
@@ -189,199 +247,199 @@ class Ant_TestClass < TestBase
assert_equal( a.text_y, "c" )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.category = "abc"
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, category=abc" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, category=abc" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_position = RBA::Annotation::PositionP1
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_position=p1" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_position=p1" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_position = RBA::Annotation::PositionP2
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_position=p2" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_position=p2" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_position = RBA::Annotation::PositionCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_position=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_position=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_xalign = RBA::Annotation::AlignCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_xalign=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_xalign=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_xalign = RBA::Annotation::AlignLeft
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_xalign=down" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_xalign=down" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_xalign = RBA::Annotation::AlignRight
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_xalign=up" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_xalign=up" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_yalign = RBA::Annotation::AlignCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_yalign=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_yalign=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_yalign = RBA::Annotation::AlignLeft
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_yalign=down" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_yalign=down" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.main_yalign = RBA::Annotation::AlignRight
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_yalign=up" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, main_yalign=up" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.xlabel_xalign = RBA::Annotation::AlignCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_xalign=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_xalign=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.xlabel_xalign = RBA::Annotation::AlignLeft
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_xalign=down" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_xalign=down" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.xlabel_xalign = RBA::Annotation::AlignRight
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_xalign=up" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_xalign=up" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.xlabel_yalign = RBA::Annotation::AlignCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_yalign=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_yalign=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.xlabel_yalign = RBA::Annotation::AlignLeft
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_yalign=down" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_yalign=down" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.xlabel_yalign = RBA::Annotation::AlignRight
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_yalign=up" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, xlabel_yalign=up" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.ylabel_xalign = RBA::Annotation::AlignCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_xalign=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_xalign=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.ylabel_xalign = RBA::Annotation::AlignLeft
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_xalign=down" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_xalign=down" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.ylabel_xalign = RBA::Annotation::AlignRight
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_xalign=up" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_xalign=up" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.ylabel_yalign = RBA::Annotation::AlignCenter
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_yalign=center" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_yalign=center" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.ylabel_yalign = RBA::Annotation::AlignLeft
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_yalign=down" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_yalign=down" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
- assert_equal( a.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
aa = a.dup
aa.ylabel_yalign = RBA::Annotation::AlignRight
- assert_equal( aa.to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_yalign=up" )
+ assert_equal( aa.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal, ylabel_yalign=up" )
assert_equal( a == aa, false )
a = aa.dup
assert_equal( a == aa, true )
@@ -421,10 +479,10 @@ class Ant_TestClass < TestBase
assert_equal( a.is_valid?, true )
assert_equal( lv.annotation( -1 ).is_valid?, false )
assert_equal( lv.annotation( a.id ).is_valid?, true )
- assert_equal( lv.annotation( a.id ).to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
+ assert_equal( lv.annotation( a.id ).to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global;p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
id = nil
@@ -445,19 +503,19 @@ class Ant_TestClass < TestBase
assert_equal( asc, 1 )
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global;p1=1,2, p2=3,4, fmt=u, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
lv.erase_annotation(id)
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global" )
lv.clear_annotations
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "" )
mw.close_all
@@ -483,25 +541,25 @@ class Ant_TestClass < TestBase
lv.insert_annotation( a )
arr = []
- lv.each_annotation { |x| arr.push( x.to_s ) }
+ lv.each_annotation { |x| arr.push( x.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global;p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
a.fmt = "u"
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global;p1=1,2, p2=3,4, fmt=u, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
a.delete
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global" )
a0.delete
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "" )
a0 = RBA::Annotation::new
@@ -511,19 +569,19 @@ class Ant_TestClass < TestBase
lv.insert_annotation( a )
arr = []
- lv.each_annotation { |x| arr.push( x.to_s ) }
+ lv.each_annotation { |x| arr.push( x.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=$D, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global;p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
lv.each_annotation { |x| x.fmt = "q" }
arr = []
- lv.each_annotation { |x| arr.push( x.to_s ) }
+ lv.each_annotation { |x| arr.push( x.to_s_debug ) }
assert_equal( arr.join( ";" ), "p1=0,0, p2=0,0, fmt=q, fmt_x=$X, fmt_y=$Y, style=ruler, outline=diag, snap=true, ac=global;p1=1,2, p2=3,4, fmt=q, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal" )
lv.each_annotation { |x| x.delete }
arr = []
- lv.each_annotation { |a| arr.push( a.to_s ) }
+ lv.each_annotation { |a| arr.push( a.to_s_debug ) }
assert_equal( arr.join( ";" ), "" )
mw.close_all
@@ -551,14 +609,14 @@ class Ant_TestClass < TestBase
arr = []
lv.each_annotation_selected { |a| arr.push(a) }
assert_equal(arr.size, 1)
- assert_equal(arr[0].to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
+ assert_equal(arr[0].to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
arr[0].p1 = RBA::DPoint::new(11, 12)
arr = []
lv.each_annotation_selected { |a| arr.push(a) }
assert_equal(arr.size, 1)
- assert_equal(arr[0].to_s, "p1=11,12, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
+ assert_equal(arr[0].to_s_debug, "p1=11,12, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
mw.close_all
@@ -601,6 +659,53 @@ class Ant_TestClass < TestBase
end
+ # multi-segment rulers
+ def test_6
+
+ a = annot_obj2( [ RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ) ], "a", "b", "c", 1, 2, false, 3)
+ assert_equal(a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
+ assert_equal(a.to_s, "id=-1,x1=1,y1=2,x2=3,y2=4,category='',fmt=a,fmt_x=b,fmt_y=c,position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=arrow_end,outline=diag_xy,snap=false,angle_constraint=horizontal")
+ aa = RBA::Annotation::from_s(a.to_s)
+ assert_equal(aa.to_s, a. to_s)
+
+ a = annot_obj2( [ RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 1.5, 2.5 ), RBA::DPoint::new( 3.0, 4.0 ) ], "a", "b", "c", 1, 2, false, 3)
+ assert_equal(a.to_s_debug, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
+ assert_equal(a.to_s, "id=-1,pt=1:2,pt=1.5:2.5,pt=3:4,category='',fmt=a,fmt_x=b,fmt_y=c,position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=arrow_end,outline=diag_xy,snap=false,angle_constraint=horizontal")
+ assert_equal(a.segments, 2)
+ assert_equal(a.seg_p1(0).to_s, "1,2")
+ assert_equal(a.seg_p2(0).to_s, "1.5,2.5")
+ assert_equal(a.seg_p1(1).to_s, "1.5,2.5")
+ assert_equal(a.seg_p2(1).to_s, "3,4")
+ a.fmt_x = "$X"
+ a.fmt_y = "$(Y*2)"
+ a.fmt = "$D"
+ assert_equal(a.text_x(0), "0.5")
+ assert_equal(a.text_x(1), "1.5")
+ assert_equal(a.text_y(0), "1")
+ assert_equal(a.text_y(1), "3")
+ assert_equal(a.text(0), "0.70710678")
+ assert_equal(a.text(1), "2.1213203")
+ aa = RBA::Annotation::from_s(a.to_s)
+ assert_equal(aa.to_s, a. to_s)
+
+ assert_equal(a.points.collect { |p| p.to_s }.join(";"), "1,2;1.5,2.5;3,4")
+
+ a.p1 = RBA::DPoint::new(1.1, 2.1)
+ assert_equal(a.points.collect { |p| p.to_s }.join(";"), "1.1,2.1;1.5,2.5;3,4")
+
+ a.p2 = RBA::DPoint::new(3.1, 4.1)
+ assert_equal(a.points.collect { |p| p.to_s }.join(";"), "1.1,2.1;1.5,2.5;3.1,4.1")
+
+ a.points = [ RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 2.0, 3.0 ) ]
+ assert_equal(a.points.collect { |p| p.to_s }.join(";"), "1,2;2,3")
+ assert_equal(a.segments, 1)
+
+ a.points = [ RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 1.0, 2.0 ) ]
+ assert_equal(a.points.collect { |p| p.to_s }.join(";"), "1,2")
+ assert_equal(a.segments, 1)
+
+ end
+
end
load("test_epilogue.rb")
From 4e4f316b71715010dc427caf239ecd8765a49ec4 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 13:33:53 +0200
Subject: [PATCH 20/54] Updated doc.
---
src/doc/doc/manual/measure.xml | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/src/doc/doc/manual/measure.xml b/src/doc/doc/manual/measure.xml
index 836557ac3..06df213fc 100644
--- a/src/doc/doc/manual/measure.xml
+++ b/src/doc/doc/manual/measure.xml
@@ -5,6 +5,7 @@
Doing Measurements
+
A measurement can be performed by clicking on the ruler icon in the
@@ -23,6 +24,32 @@
is attached perpendicular to the edge next to the initial point.
+
+ You can mark a position with a single click by selecting the "Cross"
+ ruler type. Clicking at a location will place such a ruler. The ruler
+ shows the x and y coordinate.
+
+
+
+ The "Multi-Ruler" allows concatenating multiple rulers into a single
+ object. Click and the first point to start such a ruler. Then click
+ on more points to add new segments to the ruler. Each segment is shown
+ as an individual ruler with tick marks and a length. Finish the sequence
+ with a double-click.
+
+
+
+ The "Angle" ruler allows angle measurements. Three clicks are required
+ to define a "V" like arrangement of two rulers. The angle enclosed by the two lines forming the "V"
+ is shown in the ruler.
+
+
+
+ Another special ruler, the "Radius" ruler is also a three-click type.
+ Specify three points to define a circle. The ruler shows the radius
+ of this circle and the circle outline.
+
+
Rulers can be configured in manifold ways. Use "Rulers And Annotations Setup"
in the "Edit" menu to open the ruler configuration dialog.
@@ -52,7 +79,7 @@
Rulers can be moved by selecting "Move" mode with the speedbar buttons
- in the toolbar or "Move" from the "Mode" submenu in the "Edit" menu. Then
+ in the toolbar or "Move" from the "Mode" sub-menu in the "Edit" menu. Then
left-click and drag the ruler or the ruler end point that should be changed.
From 00e78eb76c9a0085015a6c86b9db9068c927681a Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 16:24:05 +0200
Subject: [PATCH 21/54] Highres mode config option - display utilizes full
pixel density
---
src/ant/ant/antService.cc | 17 ++++----
src/laybasic/laybasic/layLayoutCanvas.cc | 41 +++++++++++++++-----
src/laybasic/laybasic/layLayoutCanvas.h | 9 ++++-
src/laybasic/laybasic/layLayoutViewBase.cc | 7 ++++
src/laybasic/laybasic/layLayoutViewConfig.cc | 1 +
src/laybasic/laybasic/layViewObject.h | 2 +-
src/laybasic/laybasic/laybasicConfig.h | 1 +
src/layui/layui/LayoutViewConfigPage7.ui | 20 ++++++++--
src/layui/layui/layLayoutViewConfigPages.cc | 5 +++
9 files changed, 81 insertions(+), 22 deletions(-)
diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc
index cb48588f9..49c3bca93 100644
--- a/src/ant/ant/antService.cc
+++ b/src/ant/ant/antService.cc
@@ -32,6 +32,7 @@
#include "laybasicConfig.h"
#include "layConverters.h"
#include "layLayoutCanvas.h"
+#include "layFixedFont.h"
#if defined(HAVE_QT)
# include "layProperties.h"
#endif
@@ -45,6 +46,8 @@ namespace ant
{
double angle_ruler_radius_factor = 0.9;
+double ruler_tick_length = 8.0;
+double ruler_arrow_width = 8.0;
// -------------------------------------------------------------
// Convert buttons to an angle constraint
@@ -132,8 +135,8 @@ draw_ruler (const db::DPoint &q1,
bool last_segment,
bool no_line = false)
{
- double arrow_width = 8 / renderer.resolution ();
- double arrow_length = 12 / renderer.resolution ();
+ double arrow_width = ruler_arrow_width / renderer.resolution ();
+ double arrow_length = 1.5 * arrow_width;
double sel_width = 2 / renderer.resolution ();
if (length_u < 1e-5 /*micron*/ && style != ant::Object::STY_cross_both && style != ant::Object::STY_cross_end && style != ant::Object::STY_cross_start) {
@@ -152,7 +155,7 @@ draw_ruler (const db::DPoint &q1,
} else {
// compute the tick distribution
- double tick_length = (style == ant::Object::STY_ruler ? 8 : 0) / renderer.resolution ();
+ double tick_length = (style == ant::Object::STY_ruler ? ruler_tick_length : 0) / renderer.resolution ();
double ticks = -1.0;
int minor_ticks = -1;
@@ -363,8 +366,8 @@ draw_text (const db::DPoint &q1,
return;
}
- double arrow_width = 8 / renderer.resolution ();
- double arrow_length = 12 / renderer.resolution ();
+ double arrow_width = ruler_arrow_width / renderer.resolution ();
+ double arrow_length = 1.5 * arrow_width;
// Currently, "auto" means p2.
if (pos == ant::Object::POS_auto) {
@@ -383,7 +386,7 @@ draw_text (const db::DPoint &q1,
} else {
// compute the tick distribution
- double tick_length = (style == ant::Object::STY_ruler ? 8 : 0) / renderer.resolution ();
+ double tick_length = (style == ant::Object::STY_ruler ? ruler_tick_length : 0) / renderer.resolution ();
// normal and unit vector
@@ -778,7 +781,7 @@ draw_ruler_angle (const ant::Object &ruler, const db::DCplxTrans &trans, bool se
// draw ticks if required - minor at 5 degree, major at 10 degree
- double tick_length = 8 / renderer.resolution ();
+ double tick_length = ruler_tick_length / renderer.resolution ();
double da = 5.0 / 180.0 * M_PI;
unsigned int major_ticks = 2;
diff --git a/src/laybasic/laybasic/layLayoutCanvas.cc b/src/laybasic/laybasic/layLayoutCanvas.cc
index 0a65906bf..ad89580fa 100644
--- a/src/laybasic/laybasic/layLayoutCanvas.cc
+++ b/src/laybasic/laybasic/layLayoutCanvas.cc
@@ -281,6 +281,7 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view)
mp_image_fg (0),
m_background (0), m_foreground (0), m_active (0),
m_oversampling (1),
+ m_hrm (false),
m_need_redraw (false),
m_redraw_clearing (false),
m_redraw_force_update (true),
@@ -330,18 +331,28 @@ LayoutCanvas::~LayoutCanvas ()
#if defined(HAVE_QT) && QT_VERSION >= 0x050000
double
-LayoutCanvas::dpr ()
+LayoutCanvas::dpr () const
{
return widget () ? widget ()->devicePixelRatio () : 1.0;
}
#else
double
-LayoutCanvas::dpr ()
+LayoutCanvas::dpr () const
{
return 1.0;
}
#endif
+double
+LayoutCanvas::resolution () const
+{
+ if (m_hrm) {
+ return 1.0 / m_oversampling;
+ } else {
+ return 1.0 / (m_oversampling * dpr ());
+ }
+}
+
#if defined(HAVE_QT)
void
LayoutCanvas::init_ui (QWidget *parent)
@@ -407,6 +418,16 @@ LayoutCanvas::set_oversampling (unsigned int os)
}
}
+void
+LayoutCanvas::set_highres_mode (bool hrm)
+{
+ if (hrm != m_hrm) {
+ m_image_cache.clear ();
+ m_hrm = hrm;
+ do_redraw_all ();
+ }
+}
+
void
LayoutCanvas::set_colors (tl::Color background, tl::Color foreground, tl::Color active)
{
@@ -477,7 +498,7 @@ LayoutCanvas::prepare_drawing ()
{
if (m_need_redraw) {
- BitmapViewObjectCanvas::set_size (m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling * dpr ()));
+ BitmapViewObjectCanvas::set_size (m_viewport_l.width (), m_viewport_l.height (), resolution ());
if (! mp_image ||
(unsigned int) mp_image->width () != m_viewport_l.width () ||
@@ -513,7 +534,7 @@ LayoutCanvas::prepare_drawing ()
++c;
}
- mp_redraw_thread->commit (m_layers, m_viewport_l, 1.0 / double (m_oversampling * dpr ()));
+ mp_redraw_thread->commit (m_layers, m_viewport_l, resolution ());
if (tl::verbosity () >= 20) {
tl::info << "Restored image from cache";
@@ -563,7 +584,7 @@ LayoutCanvas::prepare_drawing ()
}
if (m_redraw_clearing) {
- mp_redraw_thread->start (mp_view->synchronous () ? 0 : mp_view->drawing_workers (), m_layers, m_viewport_l, 1.0 / double (m_oversampling * dpr ()), m_redraw_force_update);
+ mp_redraw_thread->start (mp_view->synchronous () ? 0 : mp_view->drawing_workers (), m_layers, m_viewport_l, resolution (), m_redraw_force_update);
} else {
mp_redraw_thread->restart (m_need_redraw_layer);
}
@@ -634,7 +655,7 @@ LayoutCanvas::paint_event ()
}
// render the main bitmaps
- to_image (scaled_view_ops (m_oversampling * dpr ()), dither_pattern (), line_styles (), m_oversampling * dpr (), background_color (), foreground_color (), active_color (), this, *mp_image, m_viewport_l.width (), m_viewport_l.height ());
+ to_image (scaled_view_ops (1.0 / resolution ()), dither_pattern (), line_styles (), 1.0 / resolution (), background_color (), foreground_color (), active_color (), this, *mp_image, m_viewport_l.width (), m_viewport_l.height ());
if (mp_image_fg) {
delete mp_image_fg;
@@ -664,7 +685,7 @@ LayoutCanvas::paint_event ()
if (fg_bitmaps () > 0) {
tl::PixelBuffer full_image (*mp_image);
- bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), m_oversampling * dpr (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
+ bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), 1.0 / resolution (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
// render the foreground parts ..
if (m_oversampling == 1) {
@@ -711,7 +732,7 @@ LayoutCanvas::paint_event ()
full_image.set_transparent (true);
full_image.fill (0);
- bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), m_oversampling * dpr (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
+ bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), 1.0 / resolution (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
// render the foreground parts ..
if (m_oversampling == 1) {
@@ -986,13 +1007,13 @@ LayoutCanvas::screenshot ()
tl::PixelBuffer img (m_viewport.width (), m_viewport.height ());
img.fill (m_background);
- DetachedViewObjectCanvas vo_canvas (background_color (), foreground_color (), active_color (), m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling * dpr ()), &img);
+ DetachedViewObjectCanvas vo_canvas (background_color (), foreground_color (), active_color (), m_viewport_l.width (), m_viewport_l.height (), resolution (), &img);
// and paint the background objects. It uses "img" to paint on.
do_render_bg (m_viewport_l, vo_canvas);
// paint the layout bitmaps
- to_image (scaled_view_ops (m_oversampling * dpr ()), dither_pattern (), line_styles (), m_oversampling * dpr (), background_color (), foreground_color (), active_color (), this, *vo_canvas.bg_image (), m_viewport_l.width (), m_viewport_l.height ());
+ to_image (scaled_view_ops (1.0 / resolution ()), dither_pattern (), line_styles (), 1.0 / resolution (), background_color (), foreground_color (), active_color (), this, *vo_canvas.bg_image (), m_viewport_l.width (), m_viewport_l.height ());
// subsample current image to provide the background for the foreground objects
vo_canvas.make_background ();
diff --git a/src/laybasic/laybasic/layLayoutCanvas.h b/src/laybasic/laybasic/layLayoutCanvas.h
index ae4f58da2..32100c05d 100644
--- a/src/laybasic/laybasic/layLayoutCanvas.h
+++ b/src/laybasic/laybasic/layLayoutCanvas.h
@@ -256,6 +256,11 @@ public:
*/
void set_oversampling (unsigned int os);
+ /**
+ * @brief Set high-resolution mode (utilize full DPI on high-DPI displays)
+ */
+ void set_highres_mode (bool hrm);
+
/**
* @brief Sets the depth of the image cache
*/
@@ -380,6 +385,7 @@ private:
lay::LineStyles m_line_styles;
std::map > m_scaled_view_ops;
unsigned int m_oversampling;
+ bool m_hrm;
double m_gamma;
bool m_need_redraw;
@@ -417,7 +423,8 @@ private:
void do_redraw_all (bool force_redraw = true);
void prepare_drawing ();
- double dpr ();
+ double dpr () const;
+ virtual double resolution () const;
const std::vector &scaled_view_ops (unsigned int lw);
};
diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc
index e2ec59bce..4852504d7 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.cc
+++ b/src/laybasic/laybasic/layLayoutViewBase.cc
@@ -780,6 +780,13 @@ LayoutViewBase::configure (const std::string &name, const std::string &value)
mp_canvas->set_oversampling (os);
return true;
+ } else if (name == cfg_highres_mode) {
+
+ bool hrm = false;
+ tl::from_string (value, hrm);
+ mp_canvas->set_highres_mode (hrm);
+ return true;
+
} else if (name == cfg_image_cache_size) {
int sz = 0;
diff --git a/src/laybasic/laybasic/layLayoutViewConfig.cc b/src/laybasic/laybasic/layLayoutViewConfig.cc
index 3d9f5878b..9ed60be0d 100644
--- a/src/laybasic/laybasic/layLayoutViewConfig.cc
+++ b/src/laybasic/laybasic/layLayoutViewConfig.cc
@@ -107,6 +107,7 @@ public:
options.push_back (std::pair (cfg_drop_small_cells_value, "10"));
options.push_back (std::pair (cfg_array_border_instances, "false"));
options.push_back (std::pair (cfg_bitmap_oversampling, "1"));
+ options.push_back (std::pair (cfg_highres_mode, "false"));
options.push_back (std::pair (cfg_image_cache_size, "1"));
options.push_back (std::pair (cfg_default_font_size, "0"));
options.push_back (std::pair (cfg_color_palette, lay::ColorPalette ().to_string ()));
diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h
index 34e7207c6..f14c36cdd 100644
--- a/src/laybasic/laybasic/layViewObject.h
+++ b/src/laybasic/laybasic/layViewObject.h
@@ -966,7 +966,7 @@ public:
/**
* @brief Gets the QWidget representing this canvas visually in Qt
*/
- QWidget *widget ()
+ QWidget *widget () const
{
return mp_widget;
}
diff --git a/src/laybasic/laybasic/laybasicConfig.h b/src/laybasic/laybasic/laybasicConfig.h
index 0b84bf38f..ff816a0d8 100644
--- a/src/laybasic/laybasic/laybasicConfig.h
+++ b/src/laybasic/laybasic/laybasicConfig.h
@@ -120,6 +120,7 @@ static const std::string cfg_reader_options_show_always ("reader-options-show-al
static const std::string cfg_tip_window_hidden ("tip-window-hidden");
static const std::string cfg_bitmap_oversampling ("bitmap-oversampling");
+static const std::string cfg_highres_mode ("highres-mode");
static const std::string cfg_image_cache_size ("image-cache-size");
static const std::string cfg_default_font_size ("default-font-size");
diff --git a/src/layui/layui/LayoutViewConfigPage7.ui b/src/layui/layui/LayoutViewConfigPage7.ui
index ae9b834a9..c5f922f10 100644
--- a/src/layui/layui/LayoutViewConfigPage7.ui
+++ b/src/layui/layui/LayoutViewConfigPage7.ui
@@ -7,7 +7,7 @@
0
0
791
- 385
+ 403
@@ -32,7 +32,7 @@
-
- Oversampling
+ Display Quality
@@ -53,7 +53,14 @@
-
- Use oversampling:
+ Oversampling mode
+
+
+
+ -
+
+
+ High resolution mode utilizes the full pixel density on high-DPI displays. Features may look small but rich in details.
@@ -99,6 +106,13 @@
+ -
+
+
+ High resolution mode enabled
+
+
+
diff --git a/src/layui/layui/layLayoutViewConfigPages.cc b/src/layui/layui/layLayoutViewConfigPages.cc
index ab8406b8e..84ff043fa 100644
--- a/src/layui/layui/layLayoutViewConfigPages.cc
+++ b/src/layui/layui/layLayoutViewConfigPages.cc
@@ -1476,6 +1476,10 @@ LayoutViewConfigPage7::setup (lay::Dispatcher *root)
root->config_get (cfg_bitmap_oversampling, oversampling);
mp_ui->oversampling->setCurrentIndex (oversampling - 1);
+ bool highres_mode = false;
+ root->config_get (cfg_highres_mode, highres_mode);
+ mp_ui->highres_mode->setChecked (highres_mode);
+
int default_font_size = 0;
root->config_get (cfg_default_font_size, default_font_size);
mp_ui->default_font_size->setCurrentIndex (default_font_size);
@@ -1499,6 +1503,7 @@ void
LayoutViewConfigPage7::commit (lay::Dispatcher *root)
{
root->config_set (cfg_bitmap_oversampling, mp_ui->oversampling->currentIndex () + 1);
+ root->config_set (cfg_highres_mode, mp_ui->highres_mode->isChecked ());
root->config_set (cfg_default_font_size, mp_ui->default_font_size->currentIndex ());
root->config_set (cfg_global_trans, db::DCplxTrans (db::DFTrans (mp_ui->global_trans->currentIndex ())).to_string ());
root->config_set (cfg_initial_hier_depth, mp_ui->def_depth->value ());
From 1bff5c1ac3857a333ac74d93127d57555512e4e5 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 19:20:06 +0200
Subject: [PATCH 22/54] WIP: layer icons now follow oversampling and
high-resolution mode, new GSI method to fetch layer icon:
LayoutView#icon_for_layer
---
src/edt/edt/edtMainService.cc | 1 +
.../laybasic/gsiDeclLayLayoutViewBase.cc | 11 ++
src/laybasic/laybasic/layLayoutCanvas.cc | 143 +-------------
src/laybasic/laybasic/layLayoutCanvas.h | 18 +-
src/laybasic/laybasic/layLayoutViewBase.cc | 176 ++++++++++++++++++
src/laybasic/laybasic/layLayoutViewBase.h | 12 ++
src/layui/layui/layLayerControlPanel.cc | 20 ++
src/layui/layui/layLayerControlPanel.h | 12 ++
src/layui/layui/layLayerTreeModel.cc | 167 +----------------
src/layui/layui/layLayerTreeModel.h | 6 +-
src/layview/layview/layLayoutView_qt.cc | 14 ++
src/tl/tl/tlPixelBuffer.cc | 136 ++++++++++++++
src/tl/tl/tlPixelBuffer.h | 22 +++
13 files changed, 434 insertions(+), 304 deletions(-)
diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc
index f2a91af17..0f97e0166 100644
--- a/src/edt/edt/edtMainService.cc
+++ b/src/edt/edt/edtMainService.cc
@@ -30,6 +30,7 @@
#include "laySelector.h"
#include "layFinder.h"
#include "layLayerProperties.h"
+#include "laybasicConfig.h"
#include "tlProgress.h"
#include "edtPlugin.h"
#include "edtMainService.h"
diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc
index cef7e30bf..db6c1c5d5 100644
--- a/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc
+++ b/src/laybasic/laybasic/gsiDeclLayLayoutViewBase.cc
@@ -1603,6 +1603,17 @@ LAYBASIC_PUBLIC Class decl_LayoutViewBase ("lay", "LayoutVi
"Returns an array of \\LayerPropertiesIterator objects pointing to the currently selected layers. "
"If no layer view is selected currently, an empty array is returned.\n"
) +
+ gsi::method ("icon_for_layer", &lay::LayoutViewBase::icon_for_layer, gsi::arg ("iter"), gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("dpr"), gsi::arg ("di_off", 0), gsi::arg ("no_state", false),
+ "@brief Creates an icon pixmap for the given layer.\n"
+ "\n"
+ "The icon will have size w times h pixels multiplied by the device pixel ratio (dpr). The dpr is "
+ "The number of physical pixels per logical pixels on high-DPI displays.\n"
+ "\n"
+ "'di_off' will shift the dither pattern by the given number of (physical) pixels. "
+ "If 'no_state' is true, the icon will not reflect visibility or validity states but rather the display style.\n"
+ "\n"
+ "This method has been introduced in version 0.28."
+ ) +
gsi::event ("on_active_cellview_changed", static_cast (&lay::LayoutViewBase::active_cellview_changed_event),
"@brief An event indicating that the active cellview has changed\n"
"\n"
diff --git a/src/laybasic/laybasic/layLayoutCanvas.cc b/src/laybasic/laybasic/layLayoutCanvas.cc
index ad89580fa..4ae778d95 100644
--- a/src/laybasic/laybasic/layLayoutCanvas.cc
+++ b/src/laybasic/laybasic/layLayoutCanvas.cc
@@ -131,137 +131,6 @@ std::string ImageCacheEntry::to_string () const
// ----------------------------------------------------------------------------
-static void
-blowup (const tl::PixelBuffer &src, tl::PixelBuffer &dest, unsigned int os)
-{
- unsigned int ymax = src.height ();
- unsigned int xmax = src.width ();
-
- for (unsigned int y = 0; y < ymax; ++y) {
- for (unsigned int i = 0; i < os; ++i) {
- const uint32_t *psrc = (const uint32_t *) src.scan_line (y);
- uint32_t *pdest = (uint32_t *) dest.scan_line (y * os + i);
- for (unsigned int x = 0; x < xmax; ++x) {
- for (unsigned int j = 0; j < os; ++j) {
- *pdest++ = *psrc;
- }
- ++psrc;
- }
- }
- }
-}
-
-static void
-subsample (const tl::PixelBuffer &src, tl::PixelBuffer &dest, unsigned int os, double g)
-{
- // TODO: this is probably not compatible with the endianess of SPARC ..
-
- // LUT's for combining the RGB channels
-
- // forward transformation table
- unsigned short lut1[256];
- for (unsigned int i = 0; i < 256; ++i) {
- double f = (65536 / (os * os)) - 1;
- lut1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + pow (i / 255.0, g) * f)));
- }
-
- // backward transformation table
- unsigned char lut2[65536];
- for (unsigned int i = 0; i < 65536; ++i) {
- double f = os * os * ((65536 / (os * os)) - 1);
- lut2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + pow (i / f, 1.0 / g) * 255.0)));
- }
-
- // LUT's for alpha channel
-
- // forward transformation table
- unsigned short luta1[256];
- for (unsigned int i = 0; i < 256; ++i) {
- double f = (65536 / (os * os)) - 1;
- luta1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + (i / 255.0) * f)));
- }
-
- // backward transformation table
- unsigned char luta2[65536];
- for (unsigned int i = 0; i < 65536; ++i) {
- double f = os * os * ((65536 / (os * os)) - 1);
- luta2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + (i / f) * 255.0)));
- }
-
- unsigned int ymax = dest.height ();
- unsigned int xmax = dest.width ();
-
- unsigned short *buffer = new unsigned short[xmax * 4];
-
- for (unsigned int y = 0; y < ymax; ++y) {
-
- {
-
- const unsigned char *psrc = (const unsigned char *) src.scan_line (y * os);
- unsigned short *pdest = buffer;
-
- for (unsigned int x = 0; x < xmax; ++x) {
-
- pdest[0] = lut1[psrc[0]];
- pdest[1] = lut1[psrc[1]];
- pdest[2] = lut1[psrc[2]];
- pdest[3] = luta1[psrc[3]];
- psrc += 4;
-
- for (unsigned int j = os; j > 1; j--) {
- pdest[0] += lut1[psrc[0]];
- pdest[1] += lut1[psrc[1]];
- pdest[2] += lut1[psrc[2]];
- pdest[3] += luta1[psrc[3]];
- psrc += 4;
- }
-
- pdest += 4;
-
- }
-
- }
-
- for (unsigned int i = 1; i < os; ++i) {
-
- const unsigned char *psrc = (const unsigned char *) src.scan_line (y * os + i);
- unsigned short *pdest = buffer;
-
- for (unsigned int x = 0; x < xmax; ++x) {
-
- for (unsigned int j = os; j > 0; j--) {
- pdest[0] += lut1[psrc[0]];
- pdest[1] += lut1[psrc[1]];
- pdest[2] += lut1[psrc[2]];
- pdest[3] += luta1[psrc[3]];
- psrc += 4;
- }
-
- pdest += 4;
-
- }
-
- }
-
- {
-
- unsigned char *pdest = (unsigned char *) dest.scan_line (y);
- const unsigned short *psrc = buffer;
-
- for (unsigned int x = 0; x < xmax; ++x) {
- *pdest++ = lut2[*psrc++];
- *pdest++ = lut2[*psrc++];
- *pdest++ = lut2[*psrc++];
- *pdest++ = luta2[*psrc++];
- }
-
- }
-
- }
-
- delete[] buffer;
-}
-
void
invert (unsigned char *data, unsigned int width, unsigned int height)
{
@@ -693,7 +562,7 @@ LayoutCanvas::paint_event ()
} else {
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
subsampled_image.set_transparent (mp_image->transparent ());
- subsample (full_image, subsampled_image, m_oversampling, m_gamma);
+ full_image.subsample (subsampled_image, m_oversampling, m_gamma);
*mp_image_fg = subsampled_image;
}
@@ -705,7 +574,7 @@ LayoutCanvas::paint_event ()
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
subsampled_image.set_transparent (mp_image->transparent ());
- subsample (*mp_image, subsampled_image, m_oversampling, m_gamma);
+ mp_image->subsample (subsampled_image, m_oversampling, m_gamma);
*mp_image_fg = subsampled_image;
}
@@ -744,7 +613,7 @@ LayoutCanvas::paint_event ()
} else {
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
subsampled_image.set_transparent (true);
- subsample (full_image, subsampled_image, m_oversampling, m_gamma);
+ full_image.subsample (subsampled_image, m_oversampling, m_gamma);
QImage img = subsampled_image.to_image ();
#if QT_VERSION >= 0x050000
img.setDevicePixelRatio (dpr ());
@@ -820,9 +689,9 @@ public:
{
if (mp_image_l) {
unsigned int os = mp_image_l->width () / width;
- blowup (*mp_image, *mp_image_l, os);
+ mp_image->blowup (*mp_image_l, os);
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, 1.0 / resolution (), mp_image_l, mp_image_l->width (), mp_image_l->height (), false, 0);
- subsample (*mp_image_l, *mp_image, os, m_gamma);
+ mp_image_l->subsample (*mp_image, os, m_gamma);
} else {
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, 1.0 / resolution (), mp_image, width, height, false, 0);
}
@@ -833,7 +702,7 @@ public:
{
if (mp_image_l && mp_image->width () > 0) {
unsigned int os = mp_image_l->width () / mp_image->width ();
- subsample (*mp_image_l, *mp_image, os, m_gamma);
+ mp_image_l->subsample (*mp_image, os, m_gamma);
}
}
diff --git a/src/laybasic/laybasic/layLayoutCanvas.h b/src/laybasic/laybasic/layLayoutCanvas.h
index 32100c05d..d73f614b2 100644
--- a/src/laybasic/laybasic/layLayoutCanvas.h
+++ b/src/laybasic/laybasic/layLayoutCanvas.h
@@ -257,10 +257,26 @@ public:
void set_oversampling (unsigned int os);
/**
- * @brief Set high-resolution mode (utilize full DPI on high-DPI displays)
+ * @brief Gets the oversampling factor
+ */
+ unsigned int oversampling () const
+ {
+ return m_oversampling;
+ }
+
+ /**
+ * @brief Set high resolution mode (utilize full DPI on high-DPI displays)
*/
void set_highres_mode (bool hrm);
+ /**
+ * @brief Gets the high resolution mode flag
+ */
+ bool highres_mode () const
+ {
+ return m_hrm;
+ }
+
/**
* @brief Sets the depth of the image cache
*/
diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc
index 4852504d7..dc176a9e5 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.cc
+++ b/src/laybasic/laybasic/layLayoutViewBase.cc
@@ -36,6 +36,7 @@
#include "tlExceptions.h"
#include "tlDeferredExecution.h"
#include "layLayoutViewBase.h"
+#include "layBitmapsToImage.h"
#include "layViewOp.h"
#include "layViewObject.h"
#include "layConverters.h"
@@ -1527,6 +1528,181 @@ LayoutViewBase::set_selected_layers (const std::vector view_ops;
+ view_ops.push_back (view_op);
+
+ std::vector pbitmaps;
+ pbitmaps.push_back (&bitmap);
+
+ lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, dpr, pimage, width, height, false, 0);
+}
+
+tl::PixelBuffer
+LayoutViewBase::icon_for_layer (const LayerPropertiesConstIterator &iter, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state)
+{
+ int oversampling = canvas () ? canvas ()->oversampling () : 1;
+ double gamma = 2.0;
+
+ bool hrm = canvas () ? canvas ()->highres_mode () : false;
+ double dpr_drawing = oversampling * (hrm ? 1.0 : dpr);
+
+ h = std::max ((unsigned int) 16, h) * oversampling * dpr + 0.5;
+ w = std::max ((unsigned int) 16, w) * oversampling * dpr + 0.5;
+
+ tl::color_t def_color = 0x808080;
+ tl::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
+ tl::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
+
+ tl::PixelBuffer image (w, h);
+ image.set_transparent (true);
+ image.fill (background_color ().rgb ());
+
+ // upper scanline is a dummy one
+ tl::color_t *sl0 = (uint32_t *) image.scan_line (0);
+ for (size_t i = 0; i < w; ++i) {
+ *sl0++ = 0;
+ }
+
+ lay::Bitmap fill (w, h, 1.0);
+ lay::Bitmap frame (w, h, 1.0);
+ lay::Bitmap text (w, h, 1.0);
+ lay::Bitmap vertex (w, h, 1.0);
+
+ unsigned int wp = w - 1;
+
+ if (! no_state && ! iter->visible (true)) {
+
+ wp = w / 4;
+
+ // Show the arrow if it is invisible also locally.
+ if (! iter->visible (false)) {
+
+ unsigned int aw = h / 4;
+ unsigned int ap = w / 2 - 1;
+ for (unsigned int i = 0; i <= aw; ++i) {
+ text.fill (h / 2 - 1 - i, ap, ap + aw - i + 1);
+ text.fill (h / 2 - 1 + i, ap, ap + aw - i + 1);
+ }
+
+ }
+
+ }
+
+ if (! no_state && no_stipples ()) {
+ // Show a partial stipple pattern only for "no stipple" mode
+ for (unsigned int i = 1; i < h - 2; ++i) {
+ fill.fill (i, w - 1 - w / 4, w);
+ }
+ } else {
+ for (unsigned int i = 1; i < h - 2; ++i) {
+ fill.fill (i, w - 1 - wp, w);
+ }
+ }
+
+ int lw = iter->width (true);
+ if (lw < 0) {
+ // default line width is 0 for parents and 1 for leafs
+ lw = iter->has_children () ? 0 : 1;
+ }
+ lw = lw * dpr_drawing + 0.5;
+
+ int p0 = lw / 2;
+ p0 = std::max (0, std::min (int (w / 4 - 1), p0));
+
+ int p1 = (lw - 1) / 2;
+ p1 = std::max (0, std::min (int (w / 4 - 1), p1));
+
+ int p0x = p0, p1x = p1;
+ unsigned int ddx = 0;
+ unsigned int ddy = h - 2 - p1 - p0;
+ if (iter->xfill (true)) {
+ ddx = wp - p0 - p1 - 1;
+ }
+ unsigned int d = ddx / 2;
+
+ frame.fill (p0, w - 1 - (wp - p1), w);
+ frame.fill (h - 2 - p1, w - 1 - (wp - p1), w);
+
+ for (unsigned int i = p0; i < h - 2; ++i) {
+
+ frame.fill (i, w - 1 - p0, w - p0);
+ frame.fill (i, w - 1 - (wp - p1), w - (wp - p1));
+ frame.fill (i, w - 1 - p0x, w - p0x);
+ frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
+
+ while (d < ddx) {
+ d += ddy;
+ frame.fill (i, w - 1 - p0x, w - p0x);
+ frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
+ ++p0x;
+ ++p1x;
+ }
+
+ if (d >= ddx) {
+ d -= ddx;
+ }
+
+ }
+
+ if (! no_state && ! iter->valid (true)) {
+
+ unsigned int bp = w - 1 - ((w * 7) / 8 - 1);
+ unsigned int be = bp + h / 2;
+ unsigned int bw = h / 4 - 1;
+ unsigned int by = h / 2 - 1;
+
+ for (unsigned int i = 0; i < bw + 2; ++i) {
+ fill.clear (by - i, bp - 1, be);
+ fill.clear (by + i, bp - 1, be);
+ }
+
+ for (unsigned int i = 0; i < bw; ++i) {
+ text.fill (by - i, bp + bw - i - 1, bp + bw - i + 1);
+ text.fill (by - i - 1, bp + bw - i - 1, bp + bw - i + 1);
+ text.fill (by - i, bp + bw + i, bp + bw + i + 2);
+ text.fill (by - i - 1, bp + bw + i, bp + bw + i + 2);
+ text.fill (by + i, bp + bw - i - 1, bp + bw - i + 1);
+ text.fill (by + i + 1, bp + bw - i - 1, bp + bw - i + 1);
+ text.fill (by + i, bp + bw + i, bp + bw + i + 2);
+ text.fill (by + i + 1, bp + bw + i, bp + bw + i + 2);
+ }
+
+ }
+
+ vertex.fill (h / 2 - 1, w - 1 - wp / 2, w - wp / 2);
+
+ lay::ViewOp::Mode mode = lay::ViewOp::Copy;
+
+ // create fill
+ single_bitmap_to_image (lay::ViewOp (fill_color, mode, 0, iter->eff_dither_pattern (true), di_off), fill, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
+ // create frame
+ if (lw == 0) {
+ single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0 /*solid line*/, 2 /*dotted*/, 0), frame, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
+ } else {
+ single_bitmap_to_image (lay::ViewOp (frame_color, mode, iter->eff_line_style (true), 0, 0, lay::ViewOp::Rect, lw), frame, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
+ }
+ // create text
+ single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
+ // create vertex
+ single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
+
+ if (oversampling > 1) {
+ tl::PixelBuffer subsampled (image.width () / oversampling, image.height () / oversampling);
+ image.subsample (subsampled, oversampling, gamma);
+ return subsampled;
+ } else {
+ return image;
+ }
+}
+
void
LayoutViewBase::merge_dither_pattern (lay::LayerPropertiesList &props)
{
diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h
index d34426ce8..9f7b188d5 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.h
+++ b/src/laybasic/laybasic/layLayoutViewBase.h
@@ -581,6 +581,18 @@ public:
*/
virtual std::vector selected_layers () const;
+ /**
+ * @brief Gets a pixmap representing the given layer
+ *
+ * @param iter indicates the layer
+ * @param w The width in logical pixels of the generated pixmap (will be multiplied by dpr)
+ * @param h The height in logical pixels of the generated pixmap (will be multiplied by dpr)
+ * @param dpr The device pixel ratio (number of image pixes per logical pixel)
+ * @param di_off The dither pattern offset (used for animation)
+ * @param no_state If true, the state will not be indicated
+ */
+ tl::PixelBuffer icon_for_layer (const lay::LayerPropertiesConstIterator &iter, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state);
+
/**
* @brief Sets the layers that are selected in the layer browser
*/
diff --git a/src/layui/layui/layLayerControlPanel.cc b/src/layui/layui/layLayerControlPanel.cc
index 5b1ff584c..1ff0370c8 100644
--- a/src/layui/layui/layLayerControlPanel.cc
+++ b/src/layui/layui/layLayerControlPanel.cc
@@ -208,6 +208,8 @@ LayerControlPanel::LayerControlPanel (lay::LayoutViewBase *view, db::Manager *ma
m_hidden_flags_need_update (true),
m_in_update (false),
m_phase (0),
+ m_oversampling (1),
+ m_hrm (false),
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
m_no_stipples (false)
{
@@ -1712,6 +1714,24 @@ LayerControlPanel::set_phase (int phase)
}
}
+void
+LayerControlPanel::set_highres_mode (bool hrm)
+{
+ if (m_hrm != hrm) {
+ m_hrm = hrm;
+ m_do_update_content_dm ();
+ }
+}
+
+void
+LayerControlPanel::set_oversampling (int os)
+{
+ if (m_oversampling != os) {
+ m_oversampling = os;
+ m_do_update_content_dm ();
+ }
+}
+
static void
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent)
{
diff --git a/src/layui/layui/layLayerControlPanel.h b/src/layui/layui/layLayerControlPanel.h
index 93aad12b6..87920ff57 100644
--- a/src/layui/layui/layLayerControlPanel.h
+++ b/src/layui/layui/layLayerControlPanel.h
@@ -208,6 +208,16 @@ public:
*/
void set_phase (int phase);
+ /**
+ * @brief Sets highres mode
+ */
+ void set_highres_mode (bool hrm);
+
+ /**
+ * @brief Sets oversampling mode
+ */
+ void set_oversampling (int os);
+
/**
* @brief Tell, if the model has been updated already (true) or if it is still under construction (false)
*/
@@ -347,6 +357,8 @@ private:
bool m_in_update;
std::vector m_new_sel;
int m_phase;
+ int m_oversampling;
+ bool m_hrm;
tl::DeferredMethod m_do_update_content_dm;
std::set m_expanded;
bool m_no_stipples;
diff --git a/src/layui/layui/layLayerTreeModel.cc b/src/layui/layui/layLayerTreeModel.cc
index fe3f1a97f..b2a284a11 100644
--- a/src/layui/layui/layLayerTreeModel.cc
+++ b/src/layui/layui/layLayerTreeModel.cc
@@ -24,7 +24,6 @@
#include "layLayerTreeModel.h"
#include "layLayoutViewBase.h"
-#include "layBitmapsToImage.h"
#include "dbLayoutUtils.h"
#include "tlLog.h"
#include "tlTimer.h"
@@ -182,7 +181,8 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned
LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutViewBase *view)
: QAbstractItemModel (parent),
mp_parent (parent), mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0),
- m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false)
+ m_phase ((unsigned int) -1),
+ m_test_shapes_in_view (false), m_hide_empty_layers (false)
{
// .. nothing yet ..
}
@@ -620,170 +620,11 @@ LayerTreeModel::empty_within_view_predicate (const QModelIndex &index) const
}
}
-/**
- * @brief A helper function to create an image from a single bitmap
- */
-static void
-single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap,
- tl::PixelBuffer *pimage, const lay::DitherPattern &dither_pattern, const lay::LineStyles &line_styles,
- double dpr, unsigned int width, unsigned int height)
-{
- std::vector view_ops;
- view_ops.push_back (view_op);
-
- std::vector pbitmaps;
- pbitmaps.push_back (&bitmap);
-
- lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, dpr, pimage, width, height, false, 0);
-}
-
-LAYUI_PUBLIC
QIcon
LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, lay::LayoutViewBase *view, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state)
{
- h = std::max ((unsigned int) 16, h) * dpr + 0.5;
- w = std::max ((unsigned int) 16, w) * dpr + 0.5;
-
- tl::color_t def_color = 0x808080;
- tl::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
- tl::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
-
- tl::PixelBuffer image (w, h);
- image.set_transparent (true);
- image.fill (view->background_color ().rgb ());
-
- // upper scanline is a dummy one
- uint32_t *sl0 = (uint32_t *) image.scan_line (0);
- uint32_t transparent = QColor (Qt::transparent).rgba ();
- for (size_t i = 0; i < w; ++i) {
- *sl0++ = transparent;
- }
-
- // TODO: adjust the resolution according to the oversampling mode
- lay::Bitmap fill (w, h, 1.0);
- lay::Bitmap frame (w, h, 1.0);
- lay::Bitmap text (w, h, 1.0);
- lay::Bitmap vertex (w, h, 1.0);
-
- unsigned int wp = w - 1;
-
- if (! no_state && ! iter->visible (true)) {
-
- wp = w / 4;
-
- // Show the arrow if it is invisible also locally.
- if (! iter->visible (false)) {
-
- unsigned int aw = h / 4;
- unsigned int ap = w / 2 - 1;
- for (unsigned int i = 0; i <= aw; ++i) {
- text.fill (h / 2 - 1 - i, ap, ap + aw - i + 1);
- text.fill (h / 2 - 1 + i, ap, ap + aw - i + 1);
- }
-
- }
-
- }
-
- if (! no_state && view->no_stipples ()) {
- // Show a partial stipple pattern only for "no stipple" mode
- for (unsigned int i = 1; i < h - 2; ++i) {
- fill.fill (i, w - 1 - w / 4, w);
- }
- } else {
- for (unsigned int i = 1; i < h - 2; ++i) {
- fill.fill (i, w - 1 - wp, w);
- }
- }
-
- int lw = iter->width (true);
- if (lw < 0) {
- // default line width is 0 for parents and 1 for leafs
- lw = iter->has_children () ? 0 : 1;
- }
- lw = lw * dpr + 0.5;
-
- int p0 = lw / 2;
- p0 = std::max (0, std::min (int (w / 4 - 1), p0));
-
- int p1 = (lw - 1) / 2;
- p1 = std::max (0, std::min (int (w / 4 - 1), p1));
-
- int p0x = p0, p1x = p1;
- unsigned int ddx = 0;
- unsigned int ddy = h - 2 - p1 - p0;
- if (iter->xfill (true)) {
- ddx = wp - p0 - p1 - 1;
- }
- unsigned int d = ddx / 2;
-
- frame.fill (p0, w - 1 - (wp - p1), w);
- frame.fill (h - 2 - p1, w - 1 - (wp - p1), w);
-
- for (unsigned int i = p0; i < h - 2; ++i) {
-
- frame.fill (i, w - 1 - p0, w - p0);
- frame.fill (i, w - 1 - (wp - p1), w - (wp - p1));
- frame.fill (i, w - 1 - p0x, w - p0x);
- frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
-
- while (d < ddx) {
- d += ddy;
- frame.fill (i, w - 1 - p0x, w - p0x);
- frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
- ++p0x;
- ++p1x;
- }
-
- if (d >= ddx) {
- d -= ddx;
- }
-
- }
-
- if (! no_state && ! iter->valid (true)) {
-
- unsigned int bp = w - 1 - ((w * 7) / 8 - 1);
- unsigned int be = bp + h / 2;
- unsigned int bw = h / 4 - 1;
- unsigned int by = h / 2 - 1;
-
- for (unsigned int i = 0; i < bw + 2; ++i) {
- fill.clear (by - i, bp - 1, be);
- fill.clear (by + i, bp - 1, be);
- }
-
- for (unsigned int i = 0; i < bw; ++i) {
- text.fill (by - i, bp + bw - i - 1, bp + bw - i + 1);
- text.fill (by - i - 1, bp + bw - i - 1, bp + bw - i + 1);
- text.fill (by - i, bp + bw + i, bp + bw + i + 2);
- text.fill (by - i - 1, bp + bw + i, bp + bw + i + 2);
- text.fill (by + i, bp + bw - i - 1, bp + bw - i + 1);
- text.fill (by + i + 1, bp + bw - i - 1, bp + bw - i + 1);
- text.fill (by + i, bp + bw + i, bp + bw + i + 2);
- text.fill (by + i + 1, bp + bw + i, bp + bw + i + 2);
- }
-
- }
-
- vertex.fill (h / 2 - 1, w - 1 - wp / 2, w - wp / 2);
-
- lay::ViewOp::Mode mode = lay::ViewOp::Copy;
-
- // create fill
- single_bitmap_to_image (lay::ViewOp (fill_color, mode, 0, iter->eff_dither_pattern (true), di_off), fill, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
- // create frame
- if (lw == 0) {
- single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0 /*solid line*/, 2 /*dotted*/, 0), frame, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
- } else {
- single_bitmap_to_image (lay::ViewOp (frame_color, mode, iter->eff_line_style (true), 0, 0, lay::ViewOp::Rect, lw), frame, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
- }
- // create text
- single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
- // create vertex
- single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
-
- QPixmap pixmap = QPixmap::fromImage (image.to_image ());
+ tl::PixelBuffer px = view->icon_for_layer (iter, w, h, dpr, di_off, no_state);
+ QPixmap pixmap = QPixmap::fromImage (px.to_image ());
#if QT_VERSION >= 0x050000
pixmap.setDevicePixelRatio (dpr);
#endif
diff --git a/src/layui/layui/layLayerTreeModel.h b/src/layui/layui/layLayerTreeModel.h
index 902166bdd..fbd548814 100644
--- a/src/layui/layui/layLayerTreeModel.h
+++ b/src/layui/layui/layLayerTreeModel.h
@@ -123,17 +123,17 @@ public:
QModelIndex index (lay::LayerPropertiesConstIterator iter, int column) const;
/**
- * @brief Convert a QModelIndex to an iterator
+ * @brief Converts a QModelIndex to an iterator
*/
lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const;
/**
- * @brief Get a flag indicating that an entry is hidden
+ * @brief Gets a flag indicating that an entry is hidden
*/
bool is_hidden (const QModelIndex &index) const;
/**
- * @brief Set the animation phase
+ * @brief Sets the animation phase
*/
void set_phase (unsigned int ph);
diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc
index e25e42ebb..f99154707 100644
--- a/src/layview/layview/layLayoutView_qt.cc
+++ b/src/layview/layview/layLayoutView_qt.cc
@@ -731,6 +731,20 @@ LayoutView::update_menu (lay::LayoutView *view, lay::AbstractMenu &menu)
bool
LayoutView::configure (const std::string &name, const std::string &value)
{
+ if (name == cfg_bitmap_oversampling) {
+
+ int os = 1;
+ tl::from_string (value, os);
+ mp_control_panel->set_oversampling (os);
+
+ } else if (name == cfg_highres_mode) {
+
+ bool hrm = false;
+ tl::from_string (value, hrm);
+ mp_control_panel->set_highres_mode (hrm);
+
+ }
+
if (LayoutViewBase::configure (name, value)) {
return true;
}
diff --git a/src/tl/tl/tlPixelBuffer.cc b/src/tl/tl/tlPixelBuffer.cc
index 0c8566ad8..4accba4df 100644
--- a/src/tl/tl/tlPixelBuffer.cc
+++ b/src/tl/tl/tlPixelBuffer.cc
@@ -29,6 +29,7 @@
#endif
#include
+#include
namespace tl
{
@@ -358,6 +359,141 @@ PixelBuffer::diff (const PixelBuffer &other) const
return res;
}
+void
+PixelBuffer::blowup (tl::PixelBuffer &dest, unsigned int os)
+{
+ tl_assert (dest.width () == width () * os);
+ tl_assert (dest.height () == height () * os);
+
+ unsigned int ymax = height ();
+ unsigned int xmax = width ();
+
+ for (unsigned int y = 0; y < ymax; ++y) {
+ for (unsigned int i = 0; i < os; ++i) {
+ const uint32_t *psrc = (const uint32_t *) scan_line (y);
+ uint32_t *pdest = (uint32_t *) dest.scan_line (y * os + i);
+ for (unsigned int x = 0; x < xmax; ++x) {
+ for (unsigned int j = 0; j < os; ++j) {
+ *pdest++ = *psrc;
+ }
+ ++psrc;
+ }
+ }
+ }
+}
+
+void
+PixelBuffer::subsample (tl::PixelBuffer &dest, unsigned int os, double g)
+{
+ // TODO: this is probably not compatible with the endianess of SPARC ..
+
+ // LUT's for combining the RGB channels
+
+ // forward transformation table
+ unsigned short lut1[256];
+ for (unsigned int i = 0; i < 256; ++i) {
+ double f = (65536 / (os * os)) - 1;
+ lut1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + pow (i / 255.0, g) * f)));
+ }
+
+ // backward transformation table
+ unsigned char lut2[65536];
+ for (unsigned int i = 0; i < 65536; ++i) {
+ double f = os * os * ((65536 / (os * os)) - 1);
+ lut2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + pow (i / f, 1.0 / g) * 255.0)));
+ }
+
+ // LUT's for alpha channel
+
+ // forward transformation table
+ unsigned short luta1[256];
+ for (unsigned int i = 0; i < 256; ++i) {
+ double f = (65536 / (os * os)) - 1;
+ luta1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + (i / 255.0) * f)));
+ }
+
+ // backward transformation table
+ unsigned char luta2[65536];
+ for (unsigned int i = 0; i < 65536; ++i) {
+ double f = os * os * ((65536 / (os * os)) - 1);
+ luta2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + (i / f) * 255.0)));
+ }
+
+ unsigned int ymax = dest.height ();
+ unsigned int xmax = dest.width ();
+
+ unsigned short *buffer = new unsigned short[xmax * 4];
+
+ for (unsigned int y = 0; y < ymax; ++y) {
+
+ {
+
+ const unsigned char *psrc = (const unsigned char *) scan_line (y * os);
+ unsigned short *pdest = buffer;
+
+ for (unsigned int x = 0; x < xmax; ++x) {
+
+ pdest[0] = lut1[psrc[0]];
+ pdest[1] = lut1[psrc[1]];
+ pdest[2] = lut1[psrc[2]];
+ pdest[3] = luta1[psrc[3]];
+ psrc += 4;
+
+ for (unsigned int j = os; j > 1; j--) {
+ pdest[0] += lut1[psrc[0]];
+ pdest[1] += lut1[psrc[1]];
+ pdest[2] += lut1[psrc[2]];
+ pdest[3] += luta1[psrc[3]];
+ psrc += 4;
+ }
+
+ pdest += 4;
+
+ }
+
+ }
+
+ for (unsigned int i = 1; i < os; ++i) {
+
+ const unsigned char *psrc = (const unsigned char *) scan_line (y * os + i);
+ unsigned short *pdest = buffer;
+
+ for (unsigned int x = 0; x < xmax; ++x) {
+
+ for (unsigned int j = os; j > 0; j--) {
+ pdest[0] += lut1[psrc[0]];
+ pdest[1] += lut1[psrc[1]];
+ pdest[2] += lut1[psrc[2]];
+ pdest[3] += luta1[psrc[3]];
+ psrc += 4;
+ }
+
+ pdest += 4;
+
+ }
+
+ }
+
+ {
+
+ unsigned char *pdest = (unsigned char *) dest.scan_line (y);
+ const unsigned short *psrc = buffer;
+
+ for (unsigned int x = 0; x < xmax; ++x) {
+ *pdest++ = lut2[*psrc++];
+ *pdest++ = lut2[*psrc++];
+ *pdest++ = lut2[*psrc++];
+ *pdest++ = luta2[*psrc++];
+ }
+
+ }
+
+ }
+
+ delete[] buffer;
+}
+
+
#if defined(HAVE_PNG)
PixelBuffer
diff --git a/src/tl/tl/tlPixelBuffer.h b/src/tl/tl/tlPixelBuffer.h
index 62b6206f3..0f48d91fb 100644
--- a/src/tl/tl/tlPixelBuffer.h
+++ b/src/tl/tl/tlPixelBuffer.h
@@ -257,6 +257,28 @@ public:
*/
PixelBuffer diff (const PixelBuffer &other) const;
+ /**
+ * @brief Subsamples the image and puts the subsampled image into the destination image
+ *
+ * @param dest Where the subsampled image goes to
+ * @param os The subsampling factor
+ * @param g The gamma value for color interpolation
+ *
+ * The dimension of the destination image must be set to the corresponding fraction of
+ * self's dimension.
+ */
+ void subsample (tl::PixelBuffer &dest, unsigned int os, double g);
+
+ /**
+ * @brief Scales the image into the given destination image
+ *
+ * @param dest Where the scaled image goes to
+ * @param os The scaling factor
+ *
+ * The destination images dimension must have been set of self's dimension times os.
+ */
+ void blowup (tl::PixelBuffer &dest, unsigned int os);
+
/**
* @brief Gets the texts
*
From e4830b98b3713fcfea65358f8e8561085e19bbd4 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 19:52:12 +0200
Subject: [PATCH 23/54] Small bugfixes
---
src/layui/layui/layLayerTreeModel.cc | 4 ++--
src/layui/layui/layLayoutViewConfigPages.cc | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/layui/layui/layLayerTreeModel.cc b/src/layui/layui/layLayerTreeModel.cc
index b2a284a11..61aadcfec 100644
--- a/src/layui/layui/layLayerTreeModel.cc
+++ b/src/layui/layui/layLayerTreeModel.cc
@@ -623,8 +623,8 @@ LayerTreeModel::empty_within_view_predicate (const QModelIndex &index) const
QIcon
LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, lay::LayoutViewBase *view, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state)
{
- tl::PixelBuffer px = view->icon_for_layer (iter, w, h, dpr, di_off, no_state);
- QPixmap pixmap = QPixmap::fromImage (px.to_image ());
+ QImage img = view->icon_for_layer (iter, w, h, dpr, di_off, no_state).to_image_copy ();
+ QPixmap pixmap = QPixmap::fromImage (std::move (img));
#if QT_VERSION >= 0x050000
pixmap.setDevicePixelRatio (dpr);
#endif
diff --git a/src/layui/layui/layLayoutViewConfigPages.cc b/src/layui/layui/layLayoutViewConfigPages.cc
index 84ff043fa..609c3df59 100644
--- a/src/layui/layui/layLayoutViewConfigPages.cc
+++ b/src/layui/layui/layLayoutViewConfigPages.cc
@@ -888,10 +888,10 @@ LayoutViewConfigPage4::update ()
#endif
QPainter painter (&img);
- painter.setPen (QPen (palette ().color (QPalette::Active, QPalette::Text), 1.0 / dpr));
- painter.setBrush (QBrush (color));
- QRectF r (0, 0, w - painter.pen ().widthF (), h - painter.pen ().widthF ());
- painter.drawRect (r);
+ QRectF r (0.0, 0.0, w, h);
+ painter.fillRect (r, QBrush (palette ().color (QPalette::Active, QPalette::ButtonText)));
+ r = QRectF (1.0, 1.0, w - 2.0, h - 2.0);
+ painter.fillRect (r, QBrush (color));
painter.setFont (font ());
painter.setPen (QPen (text_color));
painter.drawText (r, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, text);
From 914ad98858f3c425fadc009e04f2483b4648c21c Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 21:59:34 +0200
Subject: [PATCH 24/54] Ruler edge marker is now visible also for scaling > 1
---
src/laybasic/laybasic/layEditorServiceBase.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/laybasic/laybasic/layEditorServiceBase.cc b/src/laybasic/laybasic/layEditorServiceBase.cc
index da500822b..1eca0e107 100644
--- a/src/laybasic/laybasic/layEditorServiceBase.cc
+++ b/src/laybasic/laybasic/layEditorServiceBase.cc
@@ -160,7 +160,7 @@ protected:
ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, solid_style, 0, 0, lay::ViewOp::Rect, lw, 0);
lay::CanvasPlane *arrow_plane = canvas.plane (ops);
- ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, m_solid ? solid_style : dashed_style, 1, 0, lay::ViewOp::Rect, lw, 0);
+ ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, m_solid ? solid_style : dashed_style, 0, 0, lay::ViewOp::Rect, lw, 0);
lay::CanvasPlane *edge_plane = canvas.plane (ops);
lay::Renderer &r = canvas.renderer ();
From 3b6ef57ddcda7874b822a72b04a04f20f7930d1b Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 1 Oct 2022 23:22:36 +0200
Subject: [PATCH 25/54] Cross size in marked mode now scales with resolution
---
src/laybasic/laybasic/layBitmapsToImage.cc | 143 ++++++++++++++-------
src/laybasic/laybasic/layLayoutViewBase.cc | 2 +-
2 files changed, 95 insertions(+), 50 deletions(-)
diff --git a/src/laybasic/laybasic/layBitmapsToImage.cc b/src/laybasic/laybasic/layBitmapsToImage.cc
index 17e062233..b4cc038f1 100644
--- a/src/laybasic/laybasic/layBitmapsToImage.cc
+++ b/src/laybasic/laybasic/layBitmapsToImage.cc
@@ -311,15 +311,22 @@ render_scanline_cross (const uint32_t *dp, unsigned int ds, const lay::Bitmap *p
return;
}
- if (pixels > 15) {
- pixels = 15;
+ // NOTE: hardcoded bar/width ratio for crosses.
+ unsigned int lw = std::min ((unsigned int) 6, pixels / 9);
+
+ const int max_pixels = 31;
+ if (pixels > max_pixels) {
+ pixels = max_pixels;
}
const uint32_t *dm = dp;
unsigned int px1 = (pixels - 1) / 2;
unsigned int px2 = (pixels - 1) - px1;
- const uint32_t *ps[16];
+ unsigned int spx1 = (lw - 1) / 2;
+ unsigned int spx2 = (lw - 1) - spx1;
+
+ const uint32_t *ps[max_pixels + 1];
for (unsigned int p = 0; p < pixels; ++p) {
if (y + p < px1) {
ps[p] = pbitmap->scanline (0);
@@ -330,56 +337,94 @@ render_scanline_cross (const uint32_t *dp, unsigned int ds, const lay::Bitmap *p
}
}
- uint32_t d, dd = 0, dn;
- dn = *(ps[px1]++);
+ uint32_t *dpp = data;
+ for (unsigned int i = (w + lay::wordlen - 1) / lay::wordlen; i > 0; --i) {
+ *dpp++ = 0;
+ }
- unsigned int x = w;
- while (true) {
+ for (unsigned int o = 0; o < pixels; ++o) {
- d = dn;
+ dpp = data;
- dn = 0;
- if (x > lay::wordlen) {
- dn = *(ps[px1]++);
- }
-
- uint32_t d0 = d;
- if (d0 != 0) {
- for (unsigned int p = 1; p <= px1; ++p) {
- d |= (d0 >> p);
- }
- for (unsigned int p = 1; p <= px2; ++p) {
- d |= (d0 << p);
- }
- }
- if (dn != 0) {
- for (unsigned int p = 1; p <= px1; ++p) {
- d |= (dn << (32 - p));
- }
- }
- if (dd != 0) {
- for (unsigned int p = 1; p <= px2; ++p) {
- d |= (dd >> (32 - p));
- }
- }
- for (unsigned int p = 0; p < px1; ++p) {
- d |= *(ps[p]++);
- }
- for (unsigned int p = px1 + 1; p < pixels; ++p) {
- d |= *(ps[p]++);
- }
-
- dd = d0;
-
- *data++ = d & *dm++;
- if (dm == dp + ds) {
- dm = dp;
- }
-
- if (x > lay::wordlen) {
- x -= lay::wordlen;
+ unsigned int bpx1 = 0, bpx2 = 0;
+ if (o >= px1 - spx1 && o <= px1 + spx2) {
+ bpx1 = px1;
+ bpx2 = px2;
} else {
- break;
+ bpx1 = spx1;
+ bpx2 = spx2;
+ }
+
+ if (bpx1 > 0 || bpx2 > 0) {
+
+ uint32_t d, dd = 0, dn;
+ dn = *(ps[o]++);
+
+ unsigned int x = w;
+ while (true) {
+
+ d = dn;
+
+ dn = 0;
+ if (x > lay::wordlen) {
+ dn = *(ps[o]++);
+ }
+
+ uint32_t d0 = d;
+ if (d0 != 0) {
+ for (unsigned int p = 1; p <= bpx1; ++p) {
+ d |= (d0 >> p);
+ }
+ for (unsigned int p = 1; p <= bpx2; ++p) {
+ d |= (d0 << p);
+ }
+ }
+ if (dn != 0) {
+ for (unsigned int p = 1; p <= bpx1; ++p) {
+ d |= (dn << (32 - p));
+ }
+ }
+ if (dd != 0) {
+ for (unsigned int p = 1; p <= bpx2; ++p) {
+ d |= (dd >> (32 - p));
+ }
+ }
+
+ dd = d0;
+
+ *dpp++ |= d & *dm++;
+ if (dm == dp + ds) {
+ dm = dp;
+ }
+
+ if (x > lay::wordlen) {
+ x -= lay::wordlen;
+ } else {
+ break;
+ }
+
+ }
+
+ } else {
+
+ unsigned int x = w;
+ while (true) {
+
+ uint32_t d = *(ps[o]++);
+
+ *dpp++ |= d & *dm++;
+ if (dm == dp + ds) {
+ dm = dp;
+ }
+
+ if (x > lay::wordlen) {
+ x -= lay::wordlen;
+ } else {
+ break;
+ }
+
+ }
+
}
}
diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc
index dc176a9e5..b6051a571 100644
--- a/src/laybasic/laybasic/layLayoutViewBase.cc
+++ b/src/laybasic/laybasic/layLayoutViewBase.cc
@@ -1692,7 +1692,7 @@ LayoutViewBase::icon_for_layer (const LayerPropertiesConstIterator &iter, unsign
// create text
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
// create vertex
- single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
+ single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? int (9 * dpr_drawing + 0.5) : 0), vertex, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
if (oversampling > 1) {
tl::PixelBuffer subsampled (image.width () / oversampling, image.height () / oversampling);
From 2c96cc2a411f4e3687b16e5bb3c88f90852b141e Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 2 Oct 2022 19:33:21 +0200
Subject: [PATCH 26/54] Salt package installation/uninstallation even and
hooks.
---
src/doc/doc/about/packages.xml | 23 +++++++++++++++++++
src/lay/lay/gsiDeclLayApplication.cc | 9 ++++++++
src/lay/lay/layApplication.cc | 10 +++++++++
src/lay/lay/layApplication.h | 10 ++++++++-
src/lay/lay/laySalt.cc | 33 +++++++++++++++++++++++++++-
src/lay/lay/laySaltController.cc | 13 ++++++++---
src/lay/lay/laySaltController.h | 11 ++++++++++
7 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/src/doc/doc/about/packages.xml b/src/doc/doc/about/packages.xml
index 2b9c3daec..a2b7dad60 100644
--- a/src/doc/doc/about/packages.xml
+++ b/src/doc/doc/about/packages.xml
@@ -209,4 +209,27 @@
subversion equivalent.
+ Installation Hooks
+
+
+ Scripts can register an event through which
+ indicates that packages have been installed or uninstalled.
+
+
+
+ Packages itself can supply special scripts which are executed after a package was installed
+ or before a package is uninstalled:
+
+
+
+ _install.lym : if present, this script is executed after the package is installed.
+ _uninstall.lym : if present, this script is executed before the package is uninstalled.
+
+
+
+ Both scripts need to be stored in the same location as "grain.xml" and have to use
+ "lym" format. This is the generic XML script format KLayout employs as an interpreter-agnostic
+ script representation.
+
+
diff --git a/src/lay/lay/gsiDeclLayApplication.cc b/src/lay/lay/gsiDeclLayApplication.cc
index fbf23517b..f59e77244 100644
--- a/src/lay/lay/gsiDeclLayApplication.cc
+++ b/src/lay/lay/gsiDeclLayApplication.cc
@@ -24,6 +24,7 @@
#include "layMainWindow.h"
#include "laySignalHandler.h"
#include "gsiDecl.h"
+#include "gsiSignals.h"
#include "tlArch.h"
#if defined(HAVE_QTBINDINGS)
@@ -243,6 +244,14 @@ static gsi::Methods application_methods ()
"\n"
"There is exactly one instance of the application. This instance can be obtained with this "
"method."
+ ) +
+ event ("on_salt_changed", &C::salt_changed_event,
+ "@brief This event is triggered when the package status changes.\n"
+ "\n"
+ "Register to this event if you are interested in package changes - i.e. installation or removal of packages or "
+ "package updates.\n"
+ "\n"
+ "This event has been introduced in version 0.28."
)
;
}
diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc
index 5aee10b73..707416e5a 100644
--- a/src/lay/lay/layApplication.cc
+++ b/src/lay/lay/layApplication.cc
@@ -672,6 +672,8 @@ ApplicationBase::init_app ()
}
}
+ sc->salt_changed_event.add (this, &ApplicationBase::salt_changed);
+
}
if (tc) {
@@ -852,6 +854,14 @@ ApplicationBase::add_macro_category (const std::string &name, const std::string
}
}
+void
+ApplicationBase::salt_changed ()
+{
+BEGIN_PROTECTED_SILENT
+ salt_changed_event ();
+END_PROTECTED_SILENT
+}
+
ApplicationBase::~ApplicationBase ()
{
tl::set_ui_exception_handlers (0, 0, 0);
diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h
index 6b42e1318..79cf507fb 100644
--- a/src/lay/lay/layApplication.h
+++ b/src/lay/lay/layApplication.h
@@ -26,6 +26,7 @@
#include "layCommon.h"
#include "layBusy.h"
+#include "tlEvents.h"
#include
#include
@@ -76,7 +77,7 @@ class LayoutView;
* and one for the GUI version (derived from QApplication).
*/
class LAY_PUBLIC ApplicationBase
- : public gsi::ObjectBase
+ : public gsi::ObjectBase, public tl::Object
{
public:
/**
@@ -313,6 +314,11 @@ public:
*/
void init_app ();
+ /**
+ * @brief An event indicating that the package collection has changed
+ */
+ tl::Event salt_changed_event;
+
/**
* @brief Gets the QApplication object
* This method will return non-null only if a GUI-enabled application is present.
@@ -376,6 +382,8 @@ private:
// in order to maintain a valid MainWindow reference for ruby scripts and Ruby's GC all the time.
gsi::Interpreter *mp_ruby_interpreter;
gsi::Interpreter *mp_python_interpreter;
+
+ void salt_changed ();
};
/**
diff --git a/src/lay/lay/laySalt.cc b/src/lay/lay/laySalt.cc
index 6c47c949b..45313074d 100644
--- a/src/lay/lay/laySalt.cc
+++ b/src/lay/lay/laySalt.cc
@@ -26,6 +26,7 @@
#include "tlLog.h"
#include "tlInternational.h"
#include "tlWebDAV.h"
+#include "lymMacro.h"
#include
#include
@@ -281,6 +282,21 @@ Salt::remove_grain (const SaltGrain &grain)
QString name = tl::to_qstring (grain.name ());
tl::info << QObject::tr ("Removing package '%1' ..").arg (name);
+
+ // Execute "_uninstall.lym" if it exists
+ try {
+ QFile uninstall_lym (QDir (tl::to_qstring (grain.path ())).absoluteFilePath (tl::to_qstring ("_uninstall.lym")));
+ if (uninstall_lym.exists ()) {
+ lym::Macro uninstall;
+ uninstall.load_from (tl::to_string (uninstall_lym.fileName ()));
+ uninstall.set_file_path (tl::to_string (uninstall_lym.fileName ()));
+ uninstall.run ();
+ }
+ } catch (tl::Exception &ex) {
+ // Errors in the uninstallation script are only logged, but do not prevent uninstallation
+ tl::error << ex.msg ();
+ }
+
bool res = remove_from_collection (m_root, grain.name ());
if (res) {
tl::info << QObject::tr ("Package '%1' removed.").arg (name);
@@ -493,10 +509,25 @@ Salt::create_grain (const SaltGrain &templ, SaltGrain &target, double timeout, t
if (res) {
- tl::info << QObject::tr ("Package '%1' installed").arg (tl::to_qstring (target.name ()));
target.set_installed_time (QDateTime::currentDateTime ());
target.save ();
+ // Execute "_install.lym" if it exists
+ try {
+ QFile install_lym (QDir (tl::to_qstring (target.path ())).absoluteFilePath (tl::to_qstring ("_install.lym")));
+ if (install_lym.exists ()) {
+ lym::Macro install;
+ install.load_from (tl::to_string (install_lym.fileName ()));
+ install.set_file_path (tl::to_string (install_lym.fileName ()));
+ install.run ();
+ }
+ } catch (tl::Exception &ex) {
+ // Errors in the installation script are only logged, but do not prevent installation
+ tl::error << ex.msg ();
+ }
+
+ tl::info << QObject::tr ("Package '%1' installed").arg (tl::to_qstring (target.name ()));
+
// NOTE: this is a bit brute force .. we could as well try to insert the new grain into the existing structure
refresh ();
diff --git a/src/lay/lay/laySaltController.cc b/src/lay/lay/laySaltController.cc
index bfc5af1b2..17967733e 100644
--- a/src/lay/lay/laySaltController.cc
+++ b/src/lay/lay/laySaltController.cc
@@ -58,13 +58,13 @@ SaltController::initialized (lay::Dispatcher * /*root*/)
connect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
}
- connect (&m_salt, SIGNAL (collections_changed ()), this, SIGNAL (salt_changed ()));
+ connect (&m_salt, SIGNAL (collections_changed ()), this, SLOT (emit_salt_changed ()));
}
void
SaltController::uninitialize (lay::Dispatcher * /*root*/)
{
- disconnect (&m_salt, SIGNAL (collections_changed ()), this, SIGNAL (salt_changed ()));
+ disconnect (&m_salt, SIGNAL (collections_changed ()), this, SLOT (emit_salt_changed ()));
if (m_file_watcher) {
disconnect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
@@ -168,7 +168,7 @@ void
SaltController::sync_files ()
{
tl::log << tl::to_string (tr ("Detected file system change in packages - updating"));
- emit salt_changed ();
+ emit_salt_changed ();
}
bool
@@ -242,6 +242,13 @@ SaltController::file_watcher_triggered ()
dm_sync_files ();
}
+void
+SaltController::emit_salt_changed ()
+{
+ salt_changed_event ();
+ emit salt_changed ();
+}
+
void
SaltController::set_salt_mine_url (const std::string &url)
{
diff --git a/src/lay/lay/laySaltController.h b/src/lay/lay/laySaltController.h
index f660039a6..e2a9fa0fb 100644
--- a/src/lay/lay/laySaltController.h
+++ b/src/lay/lay/laySaltController.h
@@ -29,6 +29,7 @@
#include "laySalt.h"
#include "tlFileSystemWatcher.h"
#include "tlDeferredExecution.h"
+#include "tlEvents.h"
#include
#include
@@ -171,6 +172,11 @@ public:
return m_salt;
}
+ /**
+ * @brief Event-style version of "salt_changed"
+ */
+ tl::Event salt_changed_event;
+
/**
* @brief Gets the singleton instance for this object
*/
@@ -182,6 +188,11 @@ private slots:
*/
void file_watcher_triggered ();
+ /**
+ * @brief Emits a salt_changed event + signal
+ */
+ void emit_salt_changed ();
+
signals:
/**
* @brief This signal is emitted if the salt changed
From 0c73b11f9b21d55f30ed47c00705c1a70e72d77a Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 3 Oct 2022 22:02:13 +0200
Subject: [PATCH 27/54] Added a convenience version for
GenericDeviceExtractor#define_terminal which takes terminal and layer names
---
src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 45 ++++++++++++++++++++
testdata/lvs/res_combine3.lvs | 4 +-
2 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
index 2bf9b60d2..bb5d379eb 100644
--- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
+++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
@@ -295,6 +295,30 @@ Class decl_dbNetlistDeviceExtractor ("db", "DeviceEx
"This class has been introduced in version 0.26."
);
+template
+static void
+define_terminal_by_names (GenericDeviceExtractor *extractor, db::Device *device, const std::string &terminal_name, const std::string &layer_name, const Shape &shape)
+{
+ if (! extractor->device_class ()) {
+ throw tl::Exception (tl::to_string (tr ("No device class registered yet")));
+ }
+
+ size_t terminal_id = extractor->device_class ()->terminal_id_for_name (terminal_name);
+
+ size_t layer_id = std::numeric_limits::max ();
+ for (auto l = extractor->begin_layer_definitions (); l != extractor->end_layer_definitions (); ++l) {
+ if (l->name == layer_name) {
+ layer_id = l->index;
+ }
+ }
+
+ if (layer_id == std::numeric_limits::max ()) {
+ throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + layer_name);
+ }
+
+ extractor->define_terminal (device, terminal_id, layer_id, shape);
+}
+
Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceExtractor, "db", "GenericDeviceExtractor",
gsi::callback ("setup", &GenericDeviceExtractor::setup, &GenericDeviceExtractor::cb_setup,
"@brief Sets up the extractor.\n"
@@ -392,6 +416,27 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This version produces a point-like terminal. Note that the point is\n"
"specified in database units.\n"
) +
+ gsi::method_ext ("define_terminal", &define_terminal_by_names,
+ gsi::arg ("device"), gsi::arg ("terminal_name"), gsi::arg ("layer_name"), gsi::arg ("shape"),
+ "@brief Defines a device terminal using names for terminal and layer.\n"
+ "\n"
+ "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n"
+ "It has been introduced in version 0.28."
+ ) +
+ gsi::method_ext ("define_terminal", &define_terminal_by_names,
+ gsi::arg ("device"), gsi::arg ("terminal_name"), gsi::arg ("layer_name"), gsi::arg ("shape"),
+ "@brief Defines a device terminal using names for terminal and layer.\n"
+ "\n"
+ "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n"
+ "It has been introduced in version 0.28."
+ ) +
+ gsi::method_ext ("define_terminal", &define_terminal_by_names,
+ gsi::arg ("device"), gsi::arg ("terminal_name"), gsi::arg ("layer_name"), gsi::arg ("point"),
+ "@brief Defines a device terminal using names for terminal and layer.\n"
+ "\n"
+ "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n"
+ "It has been introduced in version 0.28."
+ ) +
gsi::method ("dbu", &GenericDeviceExtractor::dbu,
"@brief Gets the database unit\n"
) +
diff --git a/testdata/lvs/res_combine3.lvs b/testdata/lvs/res_combine3.lvs
index e0ebec331..c609c0824 100644
--- a/testdata/lvs/res_combine3.lvs
+++ b/testdata/lvs/res_combine3.lvs
@@ -67,8 +67,8 @@ class ResistorExtractor < RBA::GenericDeviceExtractor
device.set_parameter(RBA::DeviceClassResistor::PARAM_L, l)
device.set_parameter(RBA::DeviceClassResistor::PARAM_P, 2*l+2*w)
device.set_parameter(RBA::DeviceClassResistor::PARAM_W, w)
- define_terminal(device, RBA::DeviceClassResistor::TERMINAL_A, 0, terminals[0]);
- define_terminal(device, RBA::DeviceClassResistor::TERMINAL_B, 0, terminals[1]);
+ define_terminal(device, "A", "C", terminals[0]);
+ define_terminal(device, "B", "C", terminals[1]);
end
end
end
From 774b00841705e169e681dc0138e1e9fed042d871 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 5 Oct 2022 21:45:22 +0200
Subject: [PATCH 28/54] Fixed a build error
---
.../net_tracer/lay_plugin/layNetTracerTechComponentEditor.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
index 475b81e84..df7a60cc7 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerTechComponentEditor.h
@@ -67,7 +67,7 @@ public slots:
void move_up_clicked ();
void move_down_clicked ();
void current_item_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous);
- void item_changed (QTreeWidgetItem *item, int column);
+
private:
db::NetTracerTechnologyComponent m_data;
From ddff1f564f8273b40acfe2837401244e9a4783bd Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 5 Oct 2022 23:50:43 +0200
Subject: [PATCH 29/54] Provide high-res version of logo
---
src/icons/icons.qrc | 1 +
src/icons/images/logo.png | Bin 73051 -> 58289 bytes
src/icons/images/logo@2x.png | Bin 0 -> 177262 bytes
src/lay/lay/layViewWidgetStack.cc | 8 +++++++-
4 files changed, 8 insertions(+), 1 deletion(-)
create mode 100755 src/icons/images/logo@2x.png
diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc
index 79bdffc17..a855b907b 100644
--- a/src/icons/icons.qrc
+++ b/src/icons/icons.qrc
@@ -117,6 +117,7 @@
images/left_16px.png
images/left_16px@2x.png
images/logo.png
+ images/logo@2x.png
images/lt_31px.png
images/lt_31px@2x.png
images/m0_24px.png
diff --git a/src/icons/images/logo.png b/src/icons/images/logo.png
index 4451152f6422fdc159579036cb43c756534a3228..422deaeb61c2cfdbe1454454a0ffe11825e2b21b 100644
GIT binary patch
literal 58289
zcmcF~WmgbHT0TAH+L;6l-=KmoW3sFT;0HFRS@|zLt
z|5}~Zq{RR=Q^d#rYjhTq)j;?Ud=N|{{wpIoNJ%;WhyO3Ed~KfkkAioRRg{E3K!U}k
zW~?`|VE?a*%0*J!Mcu*N#ofrs44|T{$)slFNzTs9%?xH{1v9(aJD8hWnOGUw{&3mT
z`Hx@ofBfPOc6Mg=E&w$%ds8zfatR|BGd^-QFdG{aE0_t)NzTT~$Ii{i!J&(!Vr%4L
z?%-s{NAAJHWyrZVYh~~1!DM0Yiu7MUj#jp2PJHAR3=BwB2y&SK069QbLR7;e
z`>fNm!&J+4^L4$S!1~Xl+vaMLt{5;8BU1zmfxvbcLc^-u2g(hNwR?*+$*s@nc-r6J
zr5HWrbvqmIB)vh2#6|!Sfr}I;&Jcs`Xn=5ttd?h)wrrY9|9GmokzNCXBwpm|TM5-cL1L^}P;lw%MMj{I+a7>KZX|nZc
zSF(rP5f@dpRN$uvaPHuJYo2E}b*ma1HSi24bg2B_qNk%f8%k_z#9%Gl099+c-W
ziy%YuSWLrFJT9+}L1G)U@Eev8aX&7<70}W`;5_6a~|8)BkE79dQvio&e|2c%*KuU
zbj0bt2vQg6=V`73pf45
z&DPdr1z+Tp7(pDtB;ura)%SXAC{l}i6y%{g0Wz0cCr4imK!pTa?(^*KxiZ5S!F?h4
zxh$d{iD^Xx(c9t|DftPVNoWjL5axw_!jz5@DM6T|N+kdNcbP)3hc-L$ecMs^$EvZN
z5TK!Tv{cpLktG)=O)J$B_j}X<^G(XQGJ0Ml>jd~xIP?X6e--4Q`T~n
z-Cn+|U_0j5Yhi<``FW~nB5%UI*w2&W`qgvQX8ye{^34~Xe=GMMWFy)Ayy1_ehm0F?
z$5U+))H^<5ioD&C+C+6UkfMGS1|j^rg0`0hd3dNZ!f$)#(DIxrWkJdd7)Lf$qIH1U
zf-dY@GHcZ%8Up-*TfL%$VCUMM)$vNqQs%IEr{#P$ejl2-&n7
z*d0h!emanAR=mYZz|ast#}no!ya_H8&L{#mf}-ot7?+G4gA#@{7XI9^I~u4*1J>aR
z;hk7vXz(Sq<}i(_!tz-TbxFm(&jYP1
zaZRgXbKmw#s8}eRHT!&Rt~a7u-0_AHmNueo;b;K74vsuABe
znKpRDlP5KMw8^j?;mQWvxhWBpVnhI`v0wG2ov-SNPjRp#Qc_=_pY&_XRBJbT%;7ra
zlDWzAj!A5FBTNu)BLh;V^)q|SDTa(>uS3uAw({9S$`VBGL<(xBaoRzmf@=E?1C9$O
zmc;S>19QtFxX3iSnElm?N-+XypUbCsHczYZgOjg#|64*+Yh$NqyBWQ+@(!57VJU
zo#;oUB;tfiR7A^!BaSRnCmwR89IA`fdW7fv(|$ltP+%PS~OI?D2lvDx)>TEWuDR96B8#F
zi1jPSjVI=SF>jB!1(lf?8z)s;t{#QKhN&*oa*!8MX4fxZN>I{0!ij!iY69ho3@+Qy
z--vC;q@?$taf64ILER5L(;xF)vd`yvzEW%Zi-WrsafJbEx(#cIytGDL?$9^%^3!_3
z@@Il3p#w$9-z`uUbz?Xidc*_zCU5Qz$e(iR?&z);mAcumGY&QjQi=Z%h_lCcvmATF
zV!ep<}Z`5B)c(MD++`3xZaKDQasDjQLZ_^hmFh`s{HxdQ~VXfp%3TQNB;mVDvCC
zpUD7NA`;FLYJUO&B>3|~21S%J$QDQ=@=aC)gIFC+ynB$U&r|>cUfFwc3>`OoI2p|R
zpfUZ?*oEl%-tA#~*2Gxdr{*!zNiklv_q?$kJNWwR>EyZ7%YRMbxq6Tb^Kb}c)0@`t
z#Dq}=@YQ~H^8sdu{4I@gYR9YUhId=1qs3+LC8uycl9wT&+$z9tnldc2(1b-w0ijgp
z*$C#-hoNrCfpCm172;<)D}Vb+VZh&b>0%k($$RER8uJ)0G?*}jk!zPhb7;;XW!c=R
z1bt87fTa!FihB&6h76;s+#9h0TF`cNzakEan}y6_NJID(nrUJxQQ>gUd}mMbPhW_V
z2V-C0_Wa-OQ0tePlZ%TdP}>^!GN^Br`raqD>alM0Mjvz76K^Xq>qv<;1%%N~QTC*g
zar2Kv&Ly5n3X|gqh-&$uy>lr@*HRpJe6hkVefm&-qsM;zREdFB#dtK>OO7YLUrzsL
zlR-C@CqJru4%3g)p;|&_4B(6625J1mrLDtjW{><5lk>U?IMc3a91E2M<&;p4v{fgA
zH>!)JfYO`j&ruNI_$IYfkA06RQAJ>`Gm#XkLJWv<(`3$;mCrNV@0-(9G`>~uQqmym
z3*n7-Z7VagJEL8ms%dH=$KD1~j|DM-QnD}sASv1K_WiCMHjM!BnTQrC6c=_#bUAf~
zmAuG<#xMPr;c0Wp0fRUDFiq<+-loTc-$YdoE2F#ozt%6!e)ijsV*!gfcdhgv>5{
zNmTkokeo)m8q_Xi4eL@!@|@Nf#@Y;zkcq&W5_77zIWa6|md==Q%och9uR^LQ(i9=a
z5w?N)N)Q$S)z%N`4awGr*lh!0m%iChpetD+V=gOQc^r6Th1yqBDwT!Gysz$1C;7pNh7PKi`;VB8eABSttpNk8Ozq*-ozvh
zK=mW-*Sb*){O>>a1WWQEDwG-#n2uwZmQq+cE?ER%%c2fu32G>UBm9?+26(&bLxb_t
z!j$+fSu-*8=6LBvY)zvt40b;HGUDsf$fV$Zcy;W0;ni{|GTQ}ej8ra`a3(`V;wVzE
z?FOw8a2N7;-1`Rq9h8Tu{#WM}JMnGeP{r-8Zy}qzIR`HUJNL1;;dZDsKa2rtl{IPb
zixJSC65BSVXgV1li%PCZvs`<)$^3&V3uE05VJa6vCuJUs-<20%y0b!83)HBi6~;ps
z84%LGLalTpd3=;CRB{)tMP52sLp>22YuLh3((Vs{G560k3nyX;k#U@RWJ$Zv|02+#
z{wu82%KoCuyQCs6m~i_G;6$%zE+}Zhkmj-@SoeklMNwJ*3+M`4U)vfMx+1bJ^RJ1%
zoQ9U*+wi}WmVckY$WhlFjP_w;wd+3L);cLm=j)rCq!VngDiVFM?yAmGs
ze-7eW1FBLEa!{b&>k5xFQ#R?dm@T^;7};y9Oi80XxEoP(aG!5I^pfrO`Ievbj=obM
z)!#YtdtVOi0Z|GY;5z9fmV)%c?jObdYJ8UW&{VJfT0~(LSBT7L^cBi<
zy8#IykQ7%QEb%$iLXTPNsHB@$q!%Sw`4`>Fa>-7nOR|)RIlu`Z-wl{p~<
zdif-7I|f(FX1#MW$%TD(cSF^FjM|vA>{|UMHk%lcr@l)LW8`a40QqFFw@%1R)l!ij
z#(-c<>R@>$IFQm)Z}e}XMlOX^?Q#M%i`kA$c+DeJOKmKAfh;na>FP_p(ugk~D!x=Y{roB787Tq$%gVd?pVd&UCm{X=
zF25UJZw$#KV{%rZW3Hg8kxuM8SEuqyBXM!9VsP~`9ZM1_{(vidld8lvDg#OVC;NJH
zP+1gB#<3dK_fHfEi!&gQgN#djj0nj<1PAs`z7a9{9GTQ&?(Mk=kaZ}_!jQD5{WF|Z
z*;nOgF?fecIs9#ytedTdao?q*G{tP^-i`*6=e%?8O89drF&7=}u*U-K5O&tx0Jl5B
z7-2%ci>xZZk0x|b_eCC#Tze$puqe?V3t#vjjKx4OF9#M#?6sh9WR)y<|Fqy!76S9k
zto>|IGRYH57~Bj+2=e?kA^`(kA)K2}S%xnH8V6srdwiC_K@
z!J!nPM$%W#Pl^c$Rz>Wh4jbm>XaBsexDpQu1>w#Rjo;Q|QgcONLISZI
zqkzAfiV`&PYkv7?b7Qe;P|7mIgnLQ2?$8Cx4oa6%cM*s<;a@x6|jBWzof9d+wR2$ANRZrhy3MvVLS7}0xvq5Q9t(KW^(_{yir(4
zr#3b8L^FbJlFShG`=dY*{z5GECC(gXH}DtY?6_dL)Rq^R6mv)#WN+VyoA%Fr{`1!L
z-pJq@>Zy;cBh0s*oH%4c%oA!L2^95LjKpzLu%rS^VG7;LOltMZ>(tL`wH21@k8Vp06ZnfM@&V59DKB
zFtzFHp7X9uM|CrF1ce9+(9O*t=QdyS&rKxeUS7~nhM1y#`6Fkj1R#le`2*V4UpBe5
z9p6o##nLa6-;!OHM5Yrh%3{Dvv%vBzuaJg}_mAu;9E`d;pe0cKJMy(98{S}x94#qI
zkK4ZBsZbI2@Ud3HZ+yS|ue}{NpG%w1OSPW8Cbec}c66JEC%E7)>>ao!Qs`6n{xMt(
z2Y6D_k_AD~eC0(XJOv;rebhc8eJWji#oO_QegNL!-rt{#O
zukc<@YMkYON_>iow$jOX6TtK-ZhIzg!W&Y>%
zyfb|7B{p?ATK~l%s~t*3xSENBgX}WVybO3BUAxri6m9t>KHx_UO!rrAMP*40*WUol
z|E|dufpZA7n+#I)8e7asUOs{W#^N|LW_rN
zZ*smgml$>P+mF)DhY3Kh1X5oGX8Mi41wCM*tT#4iHu#q3l?0enw8dBVg7Ym=*XdA}
zjBl0A1qif!-^7W39Ed^{Z~?SnOXUUG(h>_Y=5^{Hds>o-oQTRDmYE6xD9Gp=YoC}|
z3GMa7p24bD4FESWUt|K=Zt|c4q@t-;7{`v;cZ~2DB+ZyYWYt^uBLmvJws%Poae|BE;oqL3Kt1rmwnga0zgqv1U_HP0;hHG^@x-{>
zCf(e`pfyjY-4SR0!)FV*OZCexZg$PQZy{u!%fz;G6Um#qFmLkcr&Mes@!j~Ug(3OB
z^1%3VT2e&%P4>zd)Q*JyS!Et#$%lo!e|_-1O&2$Mg@bzS9G^%EBjo)wxlm4wOp1?1
zD9!#9>z56}(A7des$AL00-HHXoAH{FSq%uBNV%+kQ${)wREUG00@QN!f;QTj8=s+0
z!A~I`59@Ge%$8{4hlI->EXj7L`_)oRv4jiI4Y*g|S=|~hoZXt_xV=uqUC6|)0*VxgxCe_c)7nI~fG43?S<@;Z$_VTKvo7k|?Q7fe*0QlXXJvk1+zfY;e
z5LVgtfDmcatZIUy*>X(BAI*u-Tkg@K$KAN1$IkEn%ugoMa%qIc}NYgX`ZK_k!uIP+y_
zb=SA^8OXF*54Xkbx0mpv+_5P-reR`)T{)NcrVnu|jp%r%v9#JN@J#KD~o%$Ul0K^`7|tOKL7!Cq5!=k5nYqn*rDc{DgcpSY?_)s!Eg_*P)1#VTd_M
z`_;p8k1sk7L{UmDL)L?`*O7=h;uHy^52&0^X&{yhKYp+jzSS~dYx#9hFjKzpmrcRi
zYLGN`P>GXdSqP
zp=2k`3v>G=ee+=j3D2@QV09kq0YPo&c)e7T5DQL`m
zKpkyDSN;s0B?*FW6?=ZirZ=)TuTz~0_~Wv{B?ws=Jz_)b<_(a5&b2xx&2gRaOh}#;
zC=6&W!cANa?c{+4$Lhv)kcT~?O$v+d|ipx$ab;Tp}K4;7}
zKt*wx!a60*rMYhI)cR~pE_WJ>(*m{I@igrd5llG(Du54OktnUeR+MFEuYspgc2ZcM
zVS<27kAHvb)9{<#0)n7C+k!jjM*r}Su0>2NnM!oHwqj+w&QEn_6xyWckuE9~0d(|#
zz)k3+D=nd}D)0h47jDSnPmT~_V6N{%(WdBtIrJP$zV3??|WE6#=mT`&*FEGW^%Uj6E0`9pdpP)ozQyA_#4+CaQ
z{J+GCj{@{0A{(1IaR2G2tjNK{uTfvl8;`4gi
z#8$QERsF`EhH-GxZwsn@ZD_1%{BxfwcyEMr&+W$7Y;*EFxn{=@#7sy_VMRDX5Dyln
ze^>xaB=~}7kZwLL&1+*Luz2sQu#0#^RIC|ZvPp?&!CXC3C9{3Jg>>&fdx!FZ)}ibb
z`wvKV{`nH=L_p=V!+L-^-K2UD^&nCw=Yb^UT;=S@N2mESVwAzQ%&0Q6p}F2|@L`t{
zUjp!qVc4G67TE_@!~5B9l3;J%>#n)l@bc;c5TrkCQ|(DUfXk22JU8Z%a2=^Ub~sxs
zHjy{03NfO06XxV6u4W{hDA>
zY}2-saXCxdUidqDua1>V+nS`2CK2N+%P*j~NH6by`TczF>pTSODL04D**HZe7gY_1
zG5N2vqt5gSGG;vx^Yq>~@1`J7(sMU|vSfNPz1TmQfq1tY*`9)oSKs;Z>vvxW{LXXb
zD&*Ebl1&v_m$rqTmRliK1f|ZoRscVkF3;G#>ab40d`0Zc+o@(_x~DhxZJ`N5SO^m-
z6m}W%ak@`TclSkFWevfcu@f~TBQV;J+qMhXyg}uFZL|E&$n)Xn>2SKe+zx|WCw1#L
z$e*3m^yO4!LsdNSvvuEfftNRGC`MPp{UHvn+z1Gz3X?A5}qpFf?6>CDi+xE&~#Q%Cn9OR@D`<8s%I=
z+zQ&NN;dj)(O$NSk`VCSANqKu2Y-9{J6k#TrJM(9re8i~kE@yk$Jow%hfoEDo)Q`d
zfn>T`epXUN9rl&-!Y%03!rkbOhVG%FfZeHL5^gzZrb`xB1|9bisUX331vlb`c-Zrm
zoec$YK3MmG$$Oa)hok3P;-hI2%8fxtjaV?zL&)559UfUj;eDiKS?=YRR0!aN0pPTB
zop7H0A@pH_qn##SLo~-;St^AEtU>EXuxe$ilK9LJ1sHlhtM912Q;WVn3M9^n=6cgV
zdSA9#!jBVP$MI%^1a`FWBE+q$uM_
z{t#HI%Tl64@udZ~6C(ciwDO$NuN=2m#!KwQf3^;5+b<>UqBVb${C^@@PdNT<1ga{)i+5ooAILVU|HYAK$@TQftMNolE*i
z@8SqFLzZ{EZE7YXmv22bbg0Rp7#$tKh4B^0oP}>p%QfIm_HiU1l~Taxg|vOdcjt%(
z{X*@|%r#KMwZ(`}fx376cXu!k_K)VFzu1f>jGR+&RmcsL=(t>W`#1Ok>;Eqo0JEju
z2)X^%OWT|A%&Q~O>WfP6)Me;CLxD5J9)JEatkL&>mL?aW7+>8DQ#v%PtyMyET6MZ?
zIR;t?Nr%cn(Cj9OD3WqyL0?n9)iHI(kq1E3G?U~*1DZQ#_k1V#PT0&jUox!*+8=4`
z_)cV(H%VAw*{Vaku)Jfudd%Q+Pzlf)7ADq#{VsYp9Kwqn
z60Sb4_^Fw|NNiZZf{+*aax5^e$zD(_E6Bt+_fX1z7$ol7i|tS%9N4REYa@ukEaI$x
zv7`yqM_NDZyjxuga!@91g4;?nbdogSdY)h@&IExF()z=CP`Ve(AWleciXI9MQ!-
z))u);W31Sdq1(Jd1K9zMIB(GuRfCAaZSbr$#5Kb1)p9SD>Dx6gofLJq$;Aw{{rKGX9>)gAh_4H
zmjG|pfo`Z&3=l)Z65mt2OhgRh;r)=|O$)*qx
zG#CYjJ>}20>b?G?ULLJ?XL#%hsHQqYNC7^LNDDbdQOJxr#1vFi
z)RP_@877$_>)B#1=ew$7uX(#7SA_E0mP{K;vCmS{od2qeBdKKc+JIR~l$4Zk-bU&`
z!7gh4$lEk3J?2y1u59iip-=jo>L~fjB);w81hYYH+!AqLlf@Q_@(Md*h6H-Nn3y$xH?CUVnE-3slum!k
z^Ln>wRDxY!pX2hKiZ-Yi?s~}5c`Owtb%ERZ>^N>{ZOoddXV(oanh*%R#c7MV9AlTp
z;~M>QxHAkt>b6df8?c5TV~4sywV0Q6K4TMPKTo}!@nh^%8F`WL8m&fUr96wiLAJ6S
zlYGWZ0p5Yw8~@BBW}zuI$Ugpia2XtV
zpglv1F|gu^{=81A!@(CFhb86KJm`y=6VrVvU7ZaS3D1qvGADE+&1W8KA`dRrQUpB1
zVb)wi8OpE(nULAO)!zYqgf$9|l{a_{U|l3Akd)XnDfMA7Uq5^~sQ$}2+L53kd^$|Y
zD{?DwTsM#pzkl)j2yvh(Ow+FwP&!I4F}AkpbR#Ufws+sp9y+Y`h%*Ym3+S{!-yYU2
zZ3LqzXc}OTuk=!>{{24)VC{cqIKls;Lw+YtNvYkX$w_{@!{u%=*f%33$73DjAYktV
zZ|{LVrS+dPJ7v+zINYZ1=Z4TbzZgJlq)`)r