Merge remote-tracking branch 'origin/master' into master-mac-qt6

This commit is contained in:
Kazunari Sekigawa 2022-10-27 06:22:15 +09:00
commit 40b845693c
108 changed files with 6359 additions and 2453 deletions

View File

@ -89,7 +89,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<iconset resource="../../icons/icons.qrc">
<normaloff>:/up_16px.png</normaloff>:/up_16px.png</iconset>
</property>
</widget>
@ -103,7 +103,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<iconset resource="../../icons/icons.qrc">
<normaloff>:/add_16px.png</normaloff>:/add_16px.png</iconset>
</property>
</widget>
@ -117,7 +117,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<iconset resource="../../icons/icons.qrc">
<normaloff>:/del_16px.png</normaloff>:/del_16px.png</iconset>
</property>
</widget>
@ -131,7 +131,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<iconset resource="../../icons/icons.qrc">
<normaloff>:/down_16px.png</normaloff>:/down_16px.png</iconset>
</property>
</widget>
@ -574,6 +574,16 @@
<string>Ellipse</string>
</property>
</item>
<item>
<property name="text">
<string>Angle measurement</string>
</property>
</item>
<item>
<property name="text">
<string>Radius measurement</string>
</property>
</item>
</widget>
</item>
<item row="7" column="0">
@ -833,6 +843,16 @@
<string>Auto measure (points will be set automatically)</string>
</property>
</item>
<item>
<property name="text">
<string>Angle measurement (three mouse clicks)</string>
</property>
</item>
<item>
<property name="text">
<string>Multi-segment (finish with double click)</string>
</property>
</item>
</widget>
</item>
<item row="9" column="0">
@ -866,7 +886,7 @@
<tabstop>t_snap_cbx</tabstop>
</tabstops>
<resources>
<include location="../../lay/lay/layResources.qrc"/>
<include location="../../icons/icons.qrc"/>
</resources>
<connections/>
</ui>

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
@ -239,6 +247,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::RulerThreeClicks) {
return "angle";
} else {
return "normal";
}
@ -254,6 +266,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::RulerThreeClicks;
} else {
a = ant::Template::RulerNormal;
}

View File

@ -32,8 +32,26 @@
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_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 +63,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 +73,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 +101,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_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 ()),
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 ())
{
clean_points_impl (m_points);
}
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 +137,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 +165,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 +230,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 +242,129 @@ 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)
{
auto new_points = points;
clean_points_impl (new_points);
set_points_exact (std::move (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 ();
}
}
db::DPoint
Object::seg_p1 (size_t seg_index) const
{
if (seg_index == std::numeric_limits<size_t>::max ()) {
return p1 ();
} else 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 == std::numeric_limits<size_t>::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 ();
} else {
return m_points.back ();
}
}
void
Object::seg_p1 (size_t seg_index, const db::DPoint &p)
{
if (seg_index == std::numeric_limits<size_t>::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<size_t>::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)
{
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 +392,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 +415,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 +445,82 @@ 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 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 ();
}
}
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
eval.define_function ("G", new AnnotationEvalFunction('G', &eval, index)); // angle (if applicable)
return eval.interpolate (fmt);
}
@ -343,6 +533,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 +601,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 +719,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 +734,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 ());
@ -602,6 +817,117 @@ Object::to_string () const
return r;
}
bool
Object::compute_interpolating_circle (double &radius, db::DPoint &center, 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 ()) * (0.5 / 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) {
stop_angle = a + da;
start_angle = stop_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 &center, 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 ());
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;
}
return true;
}
void
Object::property_changed ()
{

View File

@ -50,6 +50,7 @@ class ANT_PUBLIC Object
{
public:
typedef db::coord_traits<coord_type> coord_traits;
typedef std::vector<db::DPoint> point_list;
/**
* @brief The ruler style
@ -76,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
@ -109,11 +112,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 +198,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 +209,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 +220,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 +240,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 +282,96 @@ 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 Sets the ruler's definition points without cleaning
*/
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
*/
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 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
*
* 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 (segments () - 1);
}
/**
* @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 +690,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);
}
/**
@ -688,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 &center, 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 &center, double &start_angle, double &stop_angle) const;
protected:
/**
* @brief A notification method that is called when a property of the annotation has changed
@ -695,7 +786,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 +801,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;
};
}

View File

@ -68,12 +68,22 @@ static std::vector<ant::Template> 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")), "", "", "$(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=$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 ()));
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 +207,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<ant::Template>::iterator i = m_templates.begin (); ! any_templates && i != m_templates.end (); ++i) {
any_templates = ! i->category ().empty ();
std::map<std::string, const ant::Template *> 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 ();
}
}

View File

@ -30,14 +30,42 @@
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)
: 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 ();
m_index = 0;
setupUi (this);
@ -54,23 +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 (x1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x2, 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 (something_changed ()));
} else {
@ -94,18 +126,6 @@ PropertiesPage::~PropertiesPage ()
mp_rulers->restore_highlights ();
}
void
PropertiesPage::back ()
{
m_pos = m_selection.end ();
}
void
PropertiesPage::front ()
{
m_pos = m_selection.begin ();
}
void
PropertiesPage::swap_points_clicked ()
{
@ -173,6 +193,89 @@ 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::something_changed ()
{
if (m_in_something_changed) {
return;
}
try {
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_something_changed = false;
// ignore exceptions - the edit field will be highlighted anyway
}
}
void
PropertiesPage::snap_to_layout_clicked ()
{
@ -259,32 +362,61 @@ PropertiesPage::snap_to_layout_clicked ()
const ant::Object &
PropertiesPage::current () const
{
const ant::Object *ruler = dynamic_cast <const ant::Object *> ((*m_pos)->ptr ());
const ant::Object *ruler = dynamic_cast <const ant::Object *> (m_selection [m_index]->ptr ());
return *ruler;
}
bool
PropertiesPage::at_begin () const
size_t
PropertiesPage::count () const
{
return (m_pos == m_selection.begin ());
return m_selection.size ();
}
bool
PropertiesPage::at_end () const
void
PropertiesPage::select_entries (const std::vector<size_t> &entries)
{
return (m_pos == m_selection.end ());
tl_assert (entries.size () == 1);
m_index = entries.front ();
}
void
PropertiesPage::operator-- ()
std::string
PropertiesPage::description (size_t entry) const
{
--m_pos;
const ant::Object *obj = dynamic_cast <const ant::Object *> (m_selection [entry]->ptr ());
if (! obj) {
return std::string ("nil");
}
std::string d = tl::to_string (tr ("Ruler"));
if (! obj->category ().empty ()) {
std::string cat = obj->category ();
// category is "_ruler" for example. Turn in into "Ruler".
if (cat.size () >= 2 && cat [0] == '_') {
cat = tl::to_upper_case (std::string (cat.begin () + 1, cat.begin () + 2)) + std::string (cat.begin () + 2, cat.end ());
}
d += "[" + cat + "]";
}
if (obj->points ().size () > 3) {
d += tl::sprintf (tl::to_string (tr ("(%d points)")), obj->points ().size ());
} else {
d += "(";
for (auto p = obj->points ().begin (); p != obj->points ().end (); ++p) {
if (p != obj->points ().begin ()) {
d += ";";
}
d += p->to_string ();
}
d += ")";
}
return d;
}
void
PropertiesPage::operator++ ()
std::string
PropertiesPage::description () const
{
++m_pos;
return tl::to_string (tr ("Rulers and Annotations"));
}
void
@ -296,33 +428,80 @@ PropertiesPage::leave ()
void
PropertiesPage::update ()
{
mp_rulers->highlight (std::distance (m_selection.begin (), m_pos));
mp_rulers->highlight (m_index);
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 ());
// 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) {
QTreeWidgetItem *item = new QTreeWidgetItem (point_list);
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_something_changed || segments_tab->currentIndex () != 3) {
std::string text;
for (auto p = obj.points ().begin (); p != obj.points ().end (); ++p) {
text += tl::micron_to_string (p->x ());
text += ", ";
text += tl::micron_to_string (p->y ());
text += "\n";
}
lay::SignalBlocker blocker (points_edit);
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)));
@ -340,29 +519,49 @@ PropertiesPage::readonly ()
void
PropertiesPage::apply ()
{
// only adjust the values if the text has changed
db::DPoint p1, p2;
get_points (p1, p2);
ant::Object obj;
get_object (obj);
mp_rulers->change_ruler (m_selection [m_index], obj);
}
void PropertiesPage::get_object(ant::Object &obj)
{
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 ());
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) {
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 ()));
db::DPoint p1, p2;
if (segments_tab->currentIndex () == 1) {
get_points (p1, p2);
} else {
get_point (p1);
p2 = p1;
}
ruler.set_category (current ().category ());
obj = ant::Object (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
mp_rulers->change_ruler (*m_pos, ruler);
} else if (segments_tab->currentIndex () == 2 || segments_tab->currentIndex () == 3) {
ant::Object::point_list points;
get_points (points);
obj = ant::Object (points, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
}
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 ()));
obj.set_category (current ().category ());
}
}

View File

@ -43,29 +43,33 @@ public:
PropertiesPage (ant::Service *rulers, db::Manager *manager, QWidget *parent);
~PropertiesPage ();
virtual void back ();
virtual void front ();
virtual bool at_begin () const;
virtual bool at_end () const;
virtual void operator-- ();
virtual void operator++ ();
virtual size_t count () const;
virtual void select_entries (const std::vector<size_t> &entries);
virtual std::string description (size_t entry) const;
virtual std::string description () const;
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 something_changed ();
private:
std::vector <ant::Service::obj_iterator> m_selection;
std::vector <ant::Service::obj_iterator>::iterator m_pos;
size_t m_index;
ant::Service *mp_rulers;
bool m_enable_cb_callback;
bool m_in_something_changed;
const ant::Object &current () 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);
void get_object (ant::Object &obj);
};
}

File diff suppressed because it is too large Load Diff

View File

@ -350,7 +350,7 @@ public:
/**
* @brief Create the properties page
*/
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
/**
@ -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<ant::Template> m_ruler_templates;
unsigned int m_current_template;
@ -566,6 +568,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 +588,11 @@ private:
*/
void reduce_rulers (int num);
/**
* @brief Finishes drawing mode and creates the ruler
*/
void finish_drawing ();
/**
* @brief Delete the selected rulers
*

View File

@ -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
*/
RulerThreeClicks = 3,
/**
* @brief The ruler is a multi-segment type
*/
RulerMultiSegment = 4
};
/**

View File

@ -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); }
@ -236,6 +238,13 @@ static AnnotationRef create_measure_ruler (lay::LayoutViewBase *view, const db::
}
}
static AnnotationRef *ant_from_s (const std::string &s)
{
std::unique_ptr<AnnotationRef> aref (new AnnotationRef ());
aref->from_string (s.c_str ());
return aref.release ();
}
static int get_style (const AnnotationRef *obj)
{
return int (obj->style ());
@ -425,6 +434,16 @@ static int ruler_mode_auto_metric ()
return ant::Template::RulerAutoMetric;
}
static int ruler_mode_three_clicks ()
{
return ant::Template::RulerThreeClicks;
}
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);
@ -496,68 +515,80 @@ gsi::Class<AnnotationRef> 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 ("StyleRuler|#style_ruler", &gsi::style_ruler,
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"
) +
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", &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 "
@ -565,53 +596,65 @@ gsi::Class<AnnotationRef> 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."
) +
@ -704,27 +747,80 @@ gsi::Class<AnnotationRef> 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 +1020,17 @@ gsi::Class<AnnotationRef> 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 +1052,12 @@ gsi::Class<AnnotationRef> 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"
) +

View File

@ -1366,10 +1366,38 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters<db::NetShape>
perimeter = ap_collector.perimeter ();
}
namespace {
class AntennaShapeGenerator
: public PolygonSink
{
public:
AntennaShapeGenerator (db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id)
: PolygonSink (), mp_layout (layout), mp_shapes (&shapes), m_prop_id (prop_id)
{ }
virtual void put (const db::Polygon &polygon)
{
if (m_prop_id != 0) {
mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id));
} else {
mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ()));
}
}
private:
db::Layout *mp_layout;
db::Shapes *mp_shapes;
db::properties_id_type m_prop_id;
};
}
static db::Point
get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes)
get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id)
{
db::Point ref;
bool any_ref = false;
db::EdgeProcessor ep;
// count vertices and reserve space
@ -1386,7 +1414,10 @@ get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::c
db::PolygonRef::polygon_edge_iterator e = pr.begin_edge ();
if (! e.at_end ()) {
// pick one reference point for the label
ref = (*e).p1 ();
if (! any_ref && (*e).p1 () < ref) {
ref = (*e).p1 ();
any_ref = true;
}
ep.insert (pr, ++p);
}
} else {
@ -1394,7 +1425,7 @@ get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::c
}
}
db::ShapeGenerator sg (shapes);
db::AntennaShapeGenerator sg (layout, shapes, prop_id);
db::PolygonGenerator pg (sg, false);
db::SimpleMerge op;
ep.process (pg, op);
@ -1402,52 +1433,67 @@ get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::c
return ref;
}
static std::string
create_antenna_msg (double agate, db::Polygon::area_type agate_int, double gate_area_factor, db::Polygon::perimeter_type pgate_int, double gate_perimeter_factor,
double ametal, db::Polygon::area_type ametal_int, double metal_area_factor, db::Polygon::perimeter_type pmetal_int, double metal_perimeter_factor,
const std::vector<std::pair<const db::Region *, double> > &diodes,
const std::vector<db::Polygon::area_type> &adiodes_int,
double r, double ratio, double dbu)
static std::vector<std::pair<std::string, tl::Variant> >
create_antenna_values (double agate, db::Polygon::area_type agate_int, double gate_area_factor, db::Polygon::perimeter_type pgate_int, double gate_perimeter_factor,
double ametal, db::Polygon::area_type ametal_int, double metal_area_factor, db::Polygon::perimeter_type pmetal_int, double metal_perimeter_factor,
const std::vector<std::pair<const db::Region *, double> > &diodes,
const std::vector<db::Polygon::area_type> &adiodes_int,
double r, double ratio, double dbu)
{
std::string msg;
msg += tl::sprintf ("agate_eff: %.12g, ", agate);
if (fabs (gate_area_factor) > 1e-6) {
msg += tl::sprintf ("agate: %.12g, agate_factor: %.12g, ", agate_int * dbu * dbu, gate_area_factor);
std::vector<std::pair<std::string, tl::Variant> > values;
if (fabs (gate_area_factor - 1.0) <= db::epsilon && fabs (gate_perimeter_factor) <= db::epsilon) {
values.push_back (std::make_pair ("agate", agate));
} else {
if (fabs (gate_area_factor) > db::epsilon) {
values.push_back (std::make_pair ("agate", agate_int * dbu * dbu));
values.push_back (std::make_pair ("agate_factor", gate_area_factor));
}
if (fabs (gate_perimeter_factor) > db::epsilon) {
values.push_back (std::make_pair ("pgate", pgate_int * dbu));
values.push_back (std::make_pair ("pgate_factor", gate_perimeter_factor));
}
values.push_back (std::make_pair ("agate_eff", agate));
}
if (fabs (gate_perimeter_factor) > 1e-6) {
msg += tl::sprintf ("pgate: %.12g, pgate_factor: %.12g, ", pgate_int * dbu * dbu, gate_perimeter_factor);
}
msg += tl::sprintf ("ametal_eff: %.12g, ", ametal);
if (fabs (metal_area_factor) > 1e-6) {
msg += tl::sprintf ("ametal: %.12g, ametal_factor: %.12g, ", ametal_int * dbu * dbu, metal_area_factor);
}
if (fabs (metal_perimeter_factor) > 1e-6) {
msg += tl::sprintf ("pmetal: %.12g, pmetal_factor: %.12g, ", pmetal_int * dbu * dbu, metal_perimeter_factor);
if (fabs (metal_area_factor - 1.0) <= db::epsilon && fabs (metal_perimeter_factor) <= db::epsilon) {
values.push_back (std::make_pair ("ametal", ametal));
} else {
if (fabs (metal_area_factor) > db::epsilon) {
values.push_back (std::make_pair ("ametal", ametal_int * dbu * dbu));
values.push_back (std::make_pair ("ametal_factor", metal_area_factor));
}
if (fabs (metal_perimeter_factor) > db::epsilon) {
values.push_back (std::make_pair ("pmetal", pmetal_int * dbu));
values.push_back (std::make_pair ("pmetal_factor", metal_perimeter_factor));
}
values.push_back (std::make_pair ("ametal_eff", ametal));
}
if (! adiodes_int.empty ()) {
msg += "adiodes: [";
std::vector<tl::Variant> v;
v.reserve (adiodes_int.size ());
for (auto d = adiodes_int.begin (); d != adiodes_int.end (); ++d) {
if (d != adiodes_int.begin ()) {
msg += ", ";
}
msg += tl::sprintf ("%.12g", *d * dbu * dbu);
v.push_back (*d * dbu * dbu);
}
msg += "], ";
values.push_back (std::make_pair ("adiodes", tl::Variant (v)));
}
if (! diodes.empty ()) {
msg += "diode_factors: [";
std::vector<tl::Variant> v;
v.reserve (diodes.size ());
for (auto d = diodes.begin (); d != diodes.end (); ++d) {
if (d != diodes.begin ()) {
msg += ", ";
}
msg += tl::sprintf ("%.12g", d->second);
v.push_back (d->second);
}
msg += "], ";
values.push_back (std::make_pair ("diode_factors", tl::Variant (v)));
}
msg += tl::sprintf ("ratio: %.12g, ", ametal / agate);
msg += tl::sprintf ("max_ratio_eff: %.12g, ", r);
msg += tl::sprintf ("max_ratio: %.12g", ratio);
return msg;
values.push_back (std::make_pair ("ratio", ametal / agate));
if (ratio > db::epsilon) {
if (fabs (r / ratio - 1.0) < db::epsilon) {
values.push_back (std::make_pair ("max_ratio", ratio));
} else {
values.push_back (std::make_pair ("max_ratio_eff", r));
values.push_back (std::make_pair ("max_ratio", ratio));
}
}
return values;
}
db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes, db::Texts *values)
@ -1538,25 +1584,50 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a
}
if (tl::verbosity () >= 50) {
tl::info << "cell [" << ly.cell_name (*cid) << "]: " <<
create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor,
ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor,
diodes, adiodes_int, r, ratio, dbu);
std::vector<std::pair<std::string, tl::Variant> > antenna_values =
create_antenna_values (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor,
ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor,
diodes, adiodes_int, r, ratio, dbu);
tl::info << "cell [" << ly.cell_name (*cid) << "]: ";
for (auto v = antenna_values.begin (); v != antenna_values.end (); ++v) {
tl::info << " " << v->first << ": " << v->second.to_string ();
}
}
if (ametal / agate > r + db::epsilon) {
db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ());
db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), shapes);
std::vector<std::pair<std::string, tl::Variant> > antenna_values =
create_antenna_values (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor,
ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor,
diodes, adiodes_int, r, ratio, dbu);
db::properties_id_type prop_id = 0;
if (! values) {
db::PropertiesRepository::properties_set ps;
for (auto v = antenna_values.begin (); v != antenna_values.end (); ++v) {
ps.insert (std::make_pair (ly.properties_repository ().prop_name_id (v->first), v->second));
}
prop_id = ly.properties_repository ().properties_id (ps);
}
db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), &ly, shapes, prop_id);
if (values) {
// generate a data string with the details of the antenna computation (intentionally like JSON)
std::string msg = create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor,
ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor,
diodes, adiodes_int, r, ratio, dbu);
db::Shapes &shapesv = ly.cell (*cid).shapes (dlv.layer ());
std::string msg;
for (auto v = antenna_values.begin (); v != antenna_values.end (); ++v) {
if (v != antenna_values.begin ()) {
msg += ", ";
}
msg += v->first;
msg += ": ";
msg += v->second.to_string ();
}
shapesv.insert (db::Text (msg, db::Trans (ref - db::Point ())));
}

View File

@ -4370,6 +4370,17 @@ Class<db::Instance> decl_Instance ("db", "Instance",
// ---------------------------------------------------------------
// db::ParentInstRep binding (to "ParentInstArray")
static db::DCellInstArray
dinst (const db::ParentInstRep *parent_inst)
{
const db::Instances *instances = parent_inst->child_inst ().instances ();
if (! instances || ! instances->layout ()) {
return db::DCellInstArray ();
}
return cell_inst_array_defs<db::CellInstArray>::transform_array (parent_inst->inst (), db::CplxTrans (instances->layout ()->dbu ()));
}
Class<db::ParentInstRep> decl_ParentInstArray ("db", "ParentInstArray",
method ("parent_cell_index", &db::ParentInstRep::parent_cell_index,
"@brief Gets the index of the parent cell\n"
@ -4381,6 +4392,11 @@ Class<db::ParentInstRep> decl_ParentInstArray ("db", "ParentInstArray",
) +
method ("inst", &db::ParentInstRep::inst,
"@brief Compute the inverse instance by which the parent is seen from the child\n"
) +
method_ext ("dinst", &dinst,
"@brief Compute the inverse instance by which the parent is seen from the child in micrometer units\n"
"\n"
"This convenience method has been introduced in version 0.28."
),
"@brief A parent instance\n"
"\n"

View File

@ -295,6 +295,30 @@ Class<db::NetlistDeviceExtractor> decl_dbNetlistDeviceExtractor ("db", "DeviceEx
"This class has been introduced in version 0.26."
);
template <class Shape>
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<size_t>::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<size_t>::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<GenericDeviceExtractor> 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<GenericDeviceExtractor> 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<db::Polygon>,
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<db::Box>,
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<db::Point>,
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"
) +

View File

@ -209,4 +209,27 @@
subversion equivalent.
</p>
<h2>Installation Hooks</h2>
<p>
Scripts can register an event through <class_doc href="Application#on_salt_changed"/> which
indicates that packages have been installed or uninstalled.
</p>
<p>
Packages itself can supply special scripts which are executed after a package was installed
or before a package is uninstalled:
</p>
<ul>
<li><tt>_install.lym</tt>: if present, this script is executed after the package is installed.</li>
<li><tt>_uninstall.lym</tt>: if present, this script is executed before the package is uninstalled.</li>
</ul>
<p>
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.
</p>
</doc>

View File

@ -5,6 +5,7 @@
<title>Doing Measurements</title>
<keyword name="Rulers"/>
<keyword name="Measure"/>
<p>
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.
</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
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.
<p>
<p>
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.
</p>
<p>
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 @@
<p>
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.
</p>

View File

@ -76,6 +76,7 @@
<li><b>X:</b> The horizontal extension of the ruler in micron units.</li>
<li><b>Y:</b> The vertical extension of the ruler in micron units.</li>
<li><b>A:</b> The area enclosed by the ruler (if it was a box) in square millimeters.</li>
<li><b>G:</b> The angle enclosed by the first and last segment of the ruler (used for angle measurement rulers).</li>
</ul>
</doc>

View File

@ -61,7 +61,6 @@ InstPropertiesPage::InstPropertiesPage (edt::Service *service, db::Manager *mana
for (edt::Service::obj_iterator s = service->selection ().begin (); s != service->selection ().end (); ++s) {
m_selection_ptrs.push_back (s);
}
m_index = 0;
m_prop_id = 0;
mp_service->clear_highlights ();
@ -156,6 +155,10 @@ get_cell_or_pcell_ids_by_name (const db::Layout *layout, const std::string &name
void
InstPropertiesPage::browse_cell ()
{
if (m_indexes.empty ()) {
return;
}
BEGIN_PROTECTED
// find the layout the cell has to be looked up: that is either the layout of the current instance or
@ -166,7 +169,7 @@ BEGIN_PROTECTED
lib = lib_cbx->current_library ();
layout = &lib->layout ();
} else {
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
layout = &cv->layout ();
}
@ -207,8 +210,12 @@ END_PROTECTED
void
InstPropertiesPage::show_props ()
{
if (m_indexes.empty ()) {
return;
}
lay::UserPropertiesForm props_form (this);
if (props_form.show (mp_service->view (), m_selection_ptrs [m_index]->cv_index (), m_prop_id)) {
if (props_form.show (mp_service->view (), m_selection_ptrs [m_indexes.front ()]->cv_index (), m_prop_id)) {
emit edited ();
}
}
@ -226,43 +233,67 @@ InstPropertiesPage::display_mode_changed (bool)
update ();
}
void
InstPropertiesPage::back ()
size_t
InstPropertiesPage::count () const
{
m_index = (unsigned int) m_selection_ptrs.size ();
return m_selection_ptrs.size ();
}
void
InstPropertiesPage::front ()
void
InstPropertiesPage::select_entries (const std::vector<size_t> &entries)
{
m_index = 0;
m_indexes = entries;
}
bool
InstPropertiesPage::at_begin () const
std::string
InstPropertiesPage::description (size_t entry) const
{
return (m_index == 0);
std::string d;
edt::Service::obj_iterator pos = m_selection_ptrs [entry];
if (! pos->is_cell_inst ()) {
return d;
}
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
double dbu = cv->layout ().dbu ();
db::Layout *def_layout = &cv->layout ();
db::cell_index_type def_cell_index = pos->back ().inst_ptr.cell_index ();
std::pair<db::Library *, db::cell_index_type> dl = def_layout->defining_library (def_cell_index);
if (dl.first) {
def_layout = &dl.first->layout ();
def_cell_index = dl.second;
}
std::pair<bool, db::pcell_id_type> pci = def_layout->is_pcell_instance (def_cell_index);
if (pci.first && def_layout->pcell_declaration (pci.second)) {
d += def_layout->pcell_header (pci.second)->get_name ();
} else {
d += def_layout->cell_name (def_cell_index);
}
db::ICplxTrans t (pos->back ().inst_ptr.complex_trans ());
db::DCplxTrans dt = db::CplxTrans (dbu) * t * db::CplxTrans (dbu).inverted ();
db::Vector rowv, columnv;
unsigned long rows, columns;
if (pos->back ().inst_ptr.is_regular_array (rowv, columnv, rows, columns)) {
d += tl::sprintf ("(%s; array %dx%d)", dt.to_string (true), rows, columns);
} else {
d += tl::sprintf ("(%s)", dt.to_string (true));
}
return d;
}
bool
InstPropertiesPage::at_end () const
std::string
InstPropertiesPage::description () const
{
return (m_index == m_selection_ptrs.size ());
return tl::to_string (tr ("Instances"));
}
void
InstPropertiesPage::operator-- ()
{
--m_index;
}
void
InstPropertiesPage::operator++ ()
{
++m_index;
}
void
void
InstPropertiesPage::leave ()
{
mp_service->clear_highlights ();
@ -271,10 +302,14 @@ InstPropertiesPage::leave ()
void
InstPropertiesPage::update ()
{
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
if (m_indexes.empty ()) {
return;
}
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
tl_assert (pos->is_cell_inst ());
mp_service->highlight (m_index);
mp_service->highlight (m_indexes);
m_enable_cb_callback = false;
dbu_cb->setChecked (mp_service->view ()->dbu_coordinates ());
@ -382,7 +417,11 @@ InstPropertiesPage::update ()
void
InstPropertiesPage::show_cell ()
{
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
if (m_indexes.empty ()) {
return;
}
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
lay::CellView::unspecific_cell_path_type path (mp_service->view ()->cellview (pos->cv_index ()).combined_unspecific_path ());
for (lay::ObjectInstPath::iterator p = pos->begin (); p != pos->end (); ++p) {
@ -395,8 +434,12 @@ InstPropertiesPage::show_cell ()
void
InstPropertiesPage::show_inst ()
{
if (m_indexes.empty ()) {
return;
}
InstantiationForm inst_form (this);
inst_form.show (mp_service->view (), *m_selection_ptrs [m_index]);
inst_form.show (mp_service->view (), *m_selection_ptrs [m_indexes.front ()]);
}
bool
@ -408,12 +451,14 @@ InstPropertiesPage::readonly ()
ChangeApplicator *
InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & /*inst*/, double dbu)
{
tl_assert (! m_indexes.empty ());
bool has_error = false;
bool has_pcell_error = false;
std::unique_ptr<CombinedChangeApplicator> appl (new CombinedChangeApplicator ());
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
bool du = dbu_cb->isChecked ();
@ -707,13 +752,17 @@ InstPropertiesPage::recompute_selection_ptrs (const std::vector<lay::ObjectInstP
void
InstPropertiesPage::do_apply (bool current_only, bool relative)
{
if (m_indexes.empty ()) {
return;
}
lay::LayerState layer_state = mp_service->view ()->layer_snapshot ();
unsigned int cv_index = m_selection_ptrs [m_index]->cv_index ();
unsigned int cv_index = m_selection_ptrs [m_indexes.front ()]->cv_index ();
std::unique_ptr<ChangeApplicator> applicator;
{
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
tl_assert (pos->is_cell_inst ());
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
@ -741,7 +790,7 @@ InstPropertiesPage::do_apply (bool current_only, bool relative)
// But it avoids issues with duplicate selections of the same instance which may happen when
// an instance is selected multiple times through different hierarchy branches.
db::Instance current = m_selection_ptrs [m_index]->back ().inst_ptr;
db::Instance current = m_selection_ptrs [m_indexes.front ()]->back ().inst_ptr;
std::vector<lay::ObjectInstPath> new_sel;
new_sel.reserve (m_selection_ptrs.size ());
@ -755,9 +804,10 @@ InstPropertiesPage::do_apply (bool current_only, bool relative)
try {
for (std::vector<edt::Service::obj_iterator>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
for (auto ii = m_indexes.begin (); ii != m_indexes.end (); ++ii) {
edt::Service::obj_iterator pos = *p;
size_t index = *ii;
edt::Service::obj_iterator pos = m_selection_ptrs [*ii];
// only update objects from the same layout - this is not practical limitation but saves a lot of effort for
// managing different property id's etc.
@ -790,8 +840,6 @@ InstPropertiesPage::do_apply (bool current_only, bool relative)
if (new_inst != pos->back ().inst_ptr) {
size_t index = p - m_selection_ptrs.begin ();
// change selection to new instance
new_sel[index].back ().inst_ptr = new_inst;
@ -844,6 +892,10 @@ InstPropertiesPage::apply_to_all (bool relative)
void
InstPropertiesPage::update_pcell_parameters ()
{
if (m_indexes.empty ()) {
return;
}
db::Layout *layout;
// find the layout the cell has to be looked up: that is either the layout of the current instance or
@ -854,7 +906,7 @@ InstPropertiesPage::update_pcell_parameters ()
} else {
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
layout = &cv->layout ();
@ -878,7 +930,7 @@ InstPropertiesPage::update_pcell_parameters ()
std::vector<tl::Variant> parameters;
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
db::Cell &cell = cv->layout ().cell (pos->cell_index ());
std::pair<bool, db::pcell_id_type> pci = cell.is_pcell_instance (pos->back ().inst_ptr);

View File

@ -47,12 +47,10 @@ public:
InstPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
~InstPropertiesPage ();
virtual void back ();
virtual void front ();
virtual bool at_begin () const;
virtual bool at_end () const;
virtual void operator-- ();
virtual void operator++ ();
virtual size_t count () const;
virtual void select_entries (const std::vector<size_t> &entries);
virtual std::string description (size_t entry) const;
virtual std::string description () const;
virtual void leave ();
private:
@ -61,7 +59,7 @@ private:
protected:
std::vector<edt::Service::obj_iterator> m_selection_ptrs;
unsigned int m_index;
std::vector<size_t> m_indexes;
edt::Service *mp_service;
bool m_enable_cb_callback;
db::properties_id_type m_prop_id;

View File

@ -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"

View File

@ -43,15 +43,14 @@ namespace edt
// -------------------------------------------------------------------------
// ShapePropertiesPage implementation
ShapePropertiesPage::ShapePropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
ShapePropertiesPage::ShapePropertiesPage (const std::string &description, edt::Service *service, db::Manager *manager, QWidget *parent)
: lay::PropertiesPage (parent, manager, service),
mp_service (service), m_enable_cb_callback (true)
m_description (description), mp_service (service), m_enable_cb_callback (true)
{
m_selection_ptrs.reserve (service->selection ().size ());
for (edt::Service::obj_iterator s = service->selection ().begin (); s != service->selection ().end (); ++s) {
m_selection_ptrs.push_back (s);
}
m_index = 0;
m_prop_id = 0;
mp_service->clear_highlights ();
}
@ -73,43 +72,78 @@ ShapePropertiesPage::setup ()
m_enable_cb_callback = true;
}
void
ShapePropertiesPage::back ()
size_t
ShapePropertiesPage::count () const
{
m_index = (unsigned int) m_selection_ptrs.size ();
return m_selection_ptrs.size ();
}
void
ShapePropertiesPage::front ()
void
ShapePropertiesPage::select_entries (const std::vector<size_t> &entries)
{
m_index = 0;
m_indexes = entries;
}
bool
ShapePropertiesPage::at_begin () const
lay::LayoutViewBase *
ShapePropertiesPage::view () const
{
return (m_index == 0);
return mp_service->view ();
}
bool
ShapePropertiesPage::at_end () const
const db::Shape &
ShapePropertiesPage::shape (size_t entry) const
{
return (m_index == m_selection_ptrs.size ());
return m_selection_ptrs [entry]->shape ();
}
void
ShapePropertiesPage::operator-- ()
double
ShapePropertiesPage::dbu (size_t entry) const
{
--m_index;
unsigned int cv_index = m_selection_ptrs [entry]->cv_index ();
return view ()->cellview (cv_index)->layout ().dbu ();
}
void
ShapePropertiesPage::operator++ ()
std::string
ShapePropertiesPage::description (size_t entry) const
{
++m_index;
unsigned int cv_index = m_selection_ptrs [entry]->cv_index ();
unsigned int layer = m_selection_ptrs [entry]->layer ();
if (view ()->cellview (cv_index).is_valid ()) {
const db::LayerProperties &lp = view ()->cellview (cv_index)->layout ().get_properties (layer);
if (view ()->cellviews () > 1) {
return lp.to_string () + "@" + tl::to_string (cv_index + 1);
} else {
return lp.to_string ();
}
}
return std::string ();
}
void
QIcon
ShapePropertiesPage::icon (size_t entry, int w, int h) const
{
int cv_index = m_selection_ptrs [entry]->cv_index ();
int layer = m_selection_ptrs [entry]->layer ();
auto *view = mp_service->view ();
for (auto lp = view->begin_layers (view->current_layer_list ()); ! lp.at_end (); ++lp) {
const lay::LayerPropertiesNode *ln = lp.operator-> ();
if (ln->cellview_index () == cv_index && ln->layer_index () == layer) {
return QIcon (QPixmap::fromImage (view->icon_for_layer (lp, w, h).to_image ()));
}
}
return QIcon ();
}
std::string
ShapePropertiesPage::description () const
{
return m_description;
}
void
ShapePropertiesPage::leave ()
{
mp_service->clear_highlights ();
@ -130,8 +164,8 @@ ShapePropertiesPage::abs_trans () const
db::ICplxTrans
ShapePropertiesPage::trans () const
{
if (abs_trans ()) {
return m_selection_ptrs[m_index]->trans ();
if (abs_trans () && ! m_indexes.empty ()) {
return m_selection_ptrs[m_indexes.front ()]->trans ();
} else {
return db::ICplxTrans ();
}
@ -154,7 +188,7 @@ END_PROTECTED
void
ShapePropertiesPage::update ()
{
mp_service->highlight (m_index);
mp_service->highlight (m_indexes);
update_shape ();
}
@ -179,12 +213,16 @@ ShapePropertiesPage::recompute_selection_ptrs (const std::vector<lay::ObjectInst
void
ShapePropertiesPage::do_apply (bool current_only, bool relative)
{
if (m_indexes.empty ()) {
return;
}
std::unique_ptr<ChangeApplicator> applicator;
unsigned int cv_index = m_selection_ptrs [m_index]->cv_index ();
unsigned int cv_index = m_selection_ptrs [m_indexes.front ()]->cv_index ();
{
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
tl_assert (! pos->is_cell_inst ());
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
@ -213,7 +251,7 @@ ShapePropertiesPage::do_apply (bool current_only, bool relative)
// But it avoids issues with duplicate selections of the same shape which may happen when
// a shape is selected multiple times through different hierarchy branches.
db::Shape current = m_selection_ptrs [m_index]->shape ();
db::Shape current = m_selection_ptrs [m_indexes.front ()]->shape ();
std::vector<lay::ObjectInstPath> new_sel;
new_sel.reserve (m_selection_ptrs.size ());
@ -227,11 +265,10 @@ ShapePropertiesPage::do_apply (bool current_only, bool relative)
try {
for (std::vector<edt::Service::obj_iterator>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
for (auto i = m_indexes.begin (); i != m_indexes.end (); ++i) {
size_t index = p - m_selection_ptrs.begin ();
edt::Service::obj_iterator pos = *p;
size_t index = *i;
edt::Service::obj_iterator pos = m_selection_ptrs [*i];
// only update objects from the same layout - this is not practical limitation but saves a lot of effort for
// managing different property id's etc.
@ -329,7 +366,11 @@ ShapePropertiesPage::apply_to_all (bool relative)
void
ShapePropertiesPage::update_shape ()
{
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
if (m_indexes.empty ()) {
return;
}
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
double dbu = cv->layout ().dbu ();
@ -361,15 +402,23 @@ ShapePropertiesPage::update_shape ()
void
ShapePropertiesPage::show_inst ()
{
if (m_indexes.empty ()) {
return;
}
InstantiationForm inst_form (this);
inst_form.show (mp_service->view (), *m_selection_ptrs [m_index]);
inst_form.show (mp_service->view (), *m_selection_ptrs [m_indexes.front ()]);
}
void
ShapePropertiesPage::show_props ()
{
if (m_indexes.empty ()) {
return;
}
lay::UserPropertiesForm props_form (this);
if (props_form.show (mp_service->view (), m_selection_ptrs [m_index]->cv_index (), m_prop_id)) {
if (props_form.show (mp_service->view (), m_selection_ptrs [m_indexes.front ()]->cv_index (), m_prop_id)) {
emit edited ();
}
}
@ -384,7 +433,7 @@ ShapePropertiesPage::readonly ()
// PolygonPropertiesPage implementation
PolygonPropertiesPage::PolygonPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent), m_in_text_changed (false)
: ShapePropertiesPage (tl::to_string (tr ("Polygons")), service, manager, parent), m_in_text_changed (false)
{
setupUi (this);
setup ();
@ -405,7 +454,34 @@ PolygonPropertiesPage::PolygonPropertiesPage (edt::Service *service, db::Manager
}
}
void
static size_t count_polygon_points (const db::Shape &sh)
{
size_t n = 0;
for (auto pt = sh.begin_hull (); pt != sh.end_hull (); ++pt) {
++n;
}
return n;
}
std::string
PolygonPropertiesPage::description (size_t entry) const
{
const db::Shape &sh = shape (entry);
size_t npts = count_polygon_points (sh);
if (sh.holes () == 0 && npts > 4) {
return ShapePropertiesPage::description (entry) + " - " + tl::sprintf (tl::to_string (tr ("Polygon(%d points)")), npts);
} else if (sh.holes () > 0) {
return ShapePropertiesPage::description (entry) + " - " + tl::sprintf (tl::to_string (tr ("Polygon(%d points, %d holes)")), npts, sh.holes ());
} else {
db::Polygon poly;
sh.polygon (poly);
db::CplxTrans dbu_trans (dbu (entry));
return ShapePropertiesPage::description (entry) + " - " + tl::sprintf (tl::to_string (tr ("Polygon%s")), (dbu_trans * poly).to_string ());
}
}
void
PolygonPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{
layer_lbl->setText (tl::to_qstring (lname));
@ -536,7 +612,7 @@ PolygonPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Sha
static bool s_coordinateMode = true;
BoxPropertiesPage::BoxPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent),
: ShapePropertiesPage (tl::to_string (tr ("Boxes")), service, manager, parent),
m_recursion_sentinel (false), m_tab_index (0), m_dbu (1.0), m_lr_swapped (false), m_tb_swapped (false)
{
setupUi (this);
@ -573,6 +649,14 @@ BoxPropertiesPage::BoxPropertiesPage (edt::Service *service, db::Manager *manage
connect (prop_pb, SIGNAL (clicked ()), this, SLOT (show_props ()));
}
std::string
BoxPropertiesPage::description (size_t entry) const
{
const db::Shape &sh = shape (entry);
db::CplxTrans dbu_trans (dbu (entry));
return ShapePropertiesPage::description (entry) + " - " + tl::sprintf (tl::to_string (tr ("Box%s")), (dbu_trans * sh.box ()).to_string ());
}
void
BoxPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{
@ -773,7 +857,7 @@ BoxPropertiesPage::changed ()
// TextPropertiesPage implementation
TextPropertiesPage::TextPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent)
: ShapePropertiesPage (tl::to_string (tr ("Texts")), service, manager, parent)
{
setupUi (this);
setup ();
@ -804,7 +888,17 @@ TextPropertiesPage::TextPropertiesPage (edt::Service *service, db::Manager *mana
}
}
void
std::string
TextPropertiesPage::description (size_t entry) const
{
const db::Shape &sh = shape (entry);
db::Text text;
sh.text (text);
db::CplxTrans dbu_trans (dbu (entry));
return ShapePropertiesPage::description (entry) + " - " + tl::sprintf (tl::to_string (tr ("Text%s")), (dbu_trans * text).to_string ());
}
void
TextPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{
layer_lbl->setText (tl::to_qstring (lname));
@ -907,7 +1001,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
// PathPropertiesPage implementation
PathPropertiesPage::PathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent), m_in_text_changed (false)
: ShapePropertiesPage (tl::to_string (tr ("Paths")), service, manager, parent), m_in_text_changed (false)
{
setupUi (this);
setup ();
@ -928,6 +1022,34 @@ PathPropertiesPage::PathPropertiesPage (edt::Service *service, db::Manager *mana
round_cb->setEnabled (false);
}
static size_t count_path_points (const db::Shape &sh)
{
size_t n = 0;
for (auto pt = sh.begin_point (); pt != sh.end_point (); ++pt) {
++n;
}
return n;
}
static std::string path_description (const db::Shape &sh, double dbu)
{
size_t npts = count_path_points (sh);
if (npts > 4) {
return tl::sprintf (tl::to_string (tr ("Path(%d points, w=%.12g)")), npts, sh.path_width () * dbu);
} else {
db::CplxTrans dbu_trans (dbu);
db::Path path;
sh.path (path);
return tl::sprintf (tl::to_string (tr ("Path%s")), (dbu_trans * path).to_string ());
}
}
std::string
PathPropertiesPage::description (size_t entry) const
{
return ShapePropertiesPage::description (entry) + " - " + path_description (shape (entry), dbu (entry));
}
void
PathPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{
@ -974,7 +1096,7 @@ PathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
// EditablePathPropertiesPage implementation
EditablePathPropertiesPage::EditablePathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent), m_in_text_changed (false)
: ShapePropertiesPage (tl::to_string (tr ("Paths")), service, manager, parent), m_in_text_changed (false)
{
setupUi (this);
setup ();
@ -1026,6 +1148,12 @@ EditablePathPropertiesPage::text_changed ()
m_in_text_changed = false;
}
std::string
EditablePathPropertiesPage::description (size_t entry) const
{
return ShapePropertiesPage::description (entry) + " - " + path_description (shape (entry), dbu (entry));
}
void
EditablePathPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{

View File

@ -46,15 +46,14 @@ class ShapePropertiesPage
Q_OBJECT
public:
ShapePropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
ShapePropertiesPage (const std::string &description, edt::Service *service, db::Manager *manager, QWidget *parent);
~ShapePropertiesPage ();
virtual void back ();
virtual void front ();
virtual bool at_begin () const;
virtual bool at_end () const;
virtual void operator-- ();
virtual void operator++ ();
virtual size_t count () const;
virtual void select_entries (const std::vector<size_t> &entries);
virtual std::string description (size_t entry) const;
virtual QIcon icon (size_t entry, int w, int h) const;
virtual std::string description () const;
virtual void leave ();
protected:
@ -69,8 +68,9 @@ private:
void recompute_selection_ptrs (const std::vector<lay::ObjectInstPath> &new_sel);
protected:
std::string m_description;
std::vector<edt::Service::obj_iterator> m_selection_ptrs;
unsigned int m_index;
std::vector<size_t> m_indexes;
edt::Service *mp_service;
bool m_enable_cb_callback;
db::properties_id_type m_prop_id;
@ -83,6 +83,9 @@ protected:
bool abs_trans () const;
db::ICplxTrans trans () const;
void setup ();
lay::LayoutViewBase *view () const;
const db::Shape &shape (size_t entry) const;
double dbu (size_t entry) const;
public slots:
void show_inst ();
@ -101,6 +104,7 @@ Q_OBJECT
public:
PolygonPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
virtual std::string description (size_t entry) const;
virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname);
virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu);
@ -124,6 +128,7 @@ Q_OBJECT
public:
BoxPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
virtual std::string description (size_t entry) const;
virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname);
virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu);
@ -153,6 +158,7 @@ Q_OBJECT
public:
TextPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
virtual std::string description (size_t entry) const;
virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname);
virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu);
@ -170,6 +176,7 @@ Q_OBJECT
public:
PathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
virtual std::string description (size_t entry) const;
virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname);
virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu);
@ -190,6 +197,7 @@ Q_OBJECT
public:
EditablePathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent);
virtual std::string description (size_t entry) const;
virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname);
virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu);

View File

@ -77,6 +77,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter
m_hier_copy_mode (-1),
m_indicate_secondary_selection (false),
m_seq (0),
m_highlights_selected (false),
dm_selection_to_view (this, &edt::Service::do_selection_to_view)
{
mp_view->geom_changed_event.add (this, &edt::Service::selection_to_view);
@ -97,6 +98,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
m_hier_copy_mode (-1),
m_indicate_secondary_selection (false),
m_seq (0),
m_highlights_selected (false),
dm_selection_to_view (this, &edt::Service::do_selection_to_view)
{
mp_view->geom_changed_event.add (this, &edt::Service::selection_to_view);
@ -271,28 +273,36 @@ Service::configure (const std::string &name, const std::string &value)
void
Service::clear_highlights ()
{
for (std::vector<lay::ViewObject *>::iterator r = m_markers.begin (); r != m_markers.end (); ++r) {
(*r)->visible (false);
}
m_highlights_selected = true;
m_selected_highlights.clear ();
apply_highlights ();
}
void
Service::restore_highlights ()
{
for (std::vector<lay::ViewObject *>::iterator r = m_markers.begin (); r != m_markers.end (); ++r) {
(*r)->visible (true);
}
m_highlights_selected = false;
m_selected_highlights.clear ();
apply_highlights ();
}
void
Service::highlight (unsigned int n)
void
Service::highlight (const std::vector<size_t> &n)
{
m_highlights_selected = true;
m_selected_highlights = std::set<size_t> (n.begin (), n.end ());
apply_highlights ();
}
void
Service::apply_highlights ()
{
for (std::vector<lay::ViewObject *>::iterator r = m_markers.begin (); r != m_markers.end (); ++r) {
(*r)->visible (n-- == 0);
(*r)->visible (! m_highlights_selected || m_selected_highlights.find (r - m_markers.begin ()) != m_selected_highlights.end ());
}
}
void
void
Service::cut ()
{
if (has_selection () && view ()->is_editable ()) {
@ -1597,6 +1607,8 @@ Service::do_selection_to_view ()
}
}
apply_highlights ();
}
void

View File

@ -105,10 +105,10 @@ public:
*/
void restore_highlights ();
/**
* @brief Highlight a certain object
/**
* @brief Highlights a group of objects
*/
void highlight (unsigned int n);
void highlight (const std::vector<size_t> &n);
/**
* @brief "delete" operation
@ -616,6 +616,10 @@ private:
bool m_indicate_secondary_selection;
unsigned long m_seq;
// selective highlights
bool m_highlights_selected;
std::set<size_t> m_selected_highlights;
// Deferred method to update the selection
tl::DeferredMethod<edt::Service> dm_selection_to_view;
@ -646,6 +650,11 @@ private:
*/
void display_status (bool transient);
/**
* @brief Apply highlight selection
*/
void apply_highlights ();
private:
void copy_selected (unsigned int inst_mode);
};

View File

@ -381,10 +381,12 @@ PolygonService::PolygonService (db::Manager *manager, lay::LayoutViewBase *view)
}
#if defined(HAVE_QT)
lay::PropertiesPage *
PolygonService::properties_page (db::Manager *manager, QWidget *parent)
std::vector<lay::PropertiesPage *>
PolygonService::properties_pages (db::Manager *manager, QWidget *parent)
{
return new edt::PolygonPropertiesPage (this, manager, parent);
std::vector<lay::PropertiesPage *> pages;
pages.push_back (new edt::PolygonPropertiesPage (this, manager, parent));
return pages;
}
#endif
@ -712,10 +714,12 @@ BoxService::BoxService (db::Manager *manager, lay::LayoutViewBase *view)
}
#if defined(HAVE_QT)
lay::PropertiesPage *
BoxService::properties_page (db::Manager *manager, QWidget *parent)
std::vector<lay::PropertiesPage *>
BoxService::properties_pages (db::Manager *manager, QWidget *parent)
{
return new edt::BoxPropertiesPage (this, manager, parent);
std::vector<lay::PropertiesPage *> pages;
pages.push_back (new edt::BoxPropertiesPage (this, manager, parent));
return pages;
}
#endif
@ -812,10 +816,12 @@ TextService::~TextService ()
}
#if defined(HAVE_QT)
lay::PropertiesPage *
TextService::properties_page (db::Manager *manager, QWidget *parent)
std::vector<lay::PropertiesPage *>
TextService::properties_pages (db::Manager *manager, QWidget *parent)
{
return new edt::TextPropertiesPage (this, manager, parent);
std::vector<lay::PropertiesPage *> pages;
pages.push_back (new edt::TextPropertiesPage (this, manager, parent));
return pages;
}
#endif
@ -1004,14 +1010,16 @@ PathService::~PathService ()
}
#if defined(HAVE_QT)
lay::PropertiesPage *
PathService::properties_page (db::Manager *manager, QWidget *parent)
std::vector<lay::PropertiesPage *>
PathService::properties_pages (db::Manager *manager, QWidget *parent)
{
std::vector<lay::PropertiesPage *> pages;
if (view ()->is_editable ()) {
return new edt::EditablePathPropertiesPage (this, manager, parent);
pages.push_back (new edt::EditablePathPropertiesPage (this, manager, parent));
} else {
return new edt::PathPropertiesPage (this, manager, parent);
pages.push_back (new edt::PathPropertiesPage (this, manager, parent));
}
return pages;
}
#endif
@ -1246,10 +1254,12 @@ InstService::InstService (db::Manager *manager, lay::LayoutViewBase *view)
}
#if defined(HAVE_QT)
lay::PropertiesPage *
InstService::properties_page (db::Manager *manager, QWidget *parent)
std::vector<lay::PropertiesPage *>
InstService::properties_pages (db::Manager *manager, QWidget *parent)
{
return new edt::InstPropertiesPage (this, manager, parent);
std::vector<lay::PropertiesPage *> pages;
pages.push_back (new edt::InstPropertiesPage (this, manager, parent));
return pages;
}
#endif

View File

@ -90,7 +90,7 @@ public:
PolygonService (db::Manager *manager, lay::LayoutViewBase *view);
#if defined(HAVE_QT)
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
virtual void do_delete ();
virtual void do_begin_edit (const db::DPoint &p);
@ -123,7 +123,7 @@ public:
BoxService (db::Manager *manager, lay::LayoutViewBase *view);
#if defined(HAVE_QT)
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_move (const db::DPoint &p);
@ -151,7 +151,7 @@ public:
~TextService ();
#if defined(HAVE_QT)
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_transform (const db::DPoint &p, db::DFTrans trans);
@ -185,7 +185,7 @@ public:
~PathService ();
#if defined(HAVE_QT)
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_move (const db::DPoint &p);
@ -223,7 +223,7 @@ public:
InstService (db::Manager *manager, lay::LayoutViewBase *view);
#if defined(HAVE_QT)
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);

View File

@ -52,6 +52,8 @@
<file alias="clear_edit_16px@2x.png">images/clear_edit_16px@2x.png</file>
<file alias="clearbreakpoints_16px.png">images/clearbreakpoints_16px.png</file>
<file alias="clearbreakpoints_16px@2x.png">images/clearbreakpoints_16px@2x.png</file>
<file alias="clone_16px.png">images/clone_16px.png</file>
<file alias="clone_16px@2x.png">images/clone_16px@2x.png</file>
<file alias="cm_add_24px.png">images/cm_add_24px.png</file>
<file alias="cm_add_24px@2x.png">images/cm_add_24px@2x.png</file>
<file alias="cm_diff_24px.png">images/cm_diff_24px.png</file>
@ -115,6 +117,7 @@
<file alias="left_16px.png">images/left_16px.png</file>
<file alias="left_16px@2x.png">images/left_16px@2x.png</file>
<file alias="logo.png">images/logo.png</file>
<file alias="logo@2x.png">images/logo@2x.png</file>
<file alias="lt_31px.png">images/lt_31px.png</file>
<file alias="lt_31px@2x.png">images/lt_31px@2x.png</file>
<file alias="m0_24px.png">images/m0_24px.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 57 KiB

BIN
src/icons/images/logo@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
version="1.1"
id="svg1011"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="clone_16px.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1013"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="px"
showgrid="true"
units="px"
inkscape:snap-nodes="true"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-others="false"
inkscape:zoom="34.576923"
inkscape:cx="2.6173526"
inkscape:cy="10.006674"
inkscape:window-width="1846"
inkscape:window-height="1016"
inkscape:window-x="74"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
width="16px">
<inkscape:grid
type="xygrid"
id="grid1074"
spacingx="0.13229167"
spacingy="0.13229167"
empspacing="2" />
</sodipodi:namedview>
<defs
id="defs1008">
<linearGradient
id="linearGradient3600">
<stop
style="stop-color:#ff9f3f;stop-opacity:1;"
offset="0"
id="stop3602" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3604" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#fdfdfd;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5"
d="M 0.92604171,2.3812501 V 1.9843751 H 1.9843751 V 0.92604171 h 0.79375 V 1.9843751 h 1.0583333 v 0.79375 H 2.7781251 v 1.0583333 h -0.79375 V 2.7781251 H 0.92604171 Z"
id="path828" />
<path
style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:#808080;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.92604171,2.3812501 V 1.9843751 H 1.9843751 V 0.92604171 h 0.79375 V 1.9843751 h 1.0583333 v 0.79375 H 2.7781251 v 1.0583333 h -0.79375 V 2.7781251 H 0.92604171 Z"
id="path830" />
<path
style="fill:none;fill-rule:evenodd;stroke:#fdfdfd;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5"
d="M 0.39687504,1.8520834 V 1.4552084 H 1.4552084 V 0.39687504 h 0.79375 V 1.4552084 h 1.0583333 v 0.79375 H 2.2489584 v 1.0583333 h -0.79375 V 2.2489584 H 0.39687504 Z"
id="path3331" />
<rect
style="fill:none;stroke:#865b26;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3596"
width="4.2333326"
height="4.2333331"
x="3.3333333e-07"
y="3.3333333e-07"
inkscape:export-filename="/home/matthias/klayout/master/src/lay/lay/images/back.png"
inkscape:export-xdpi="27.093315"
inkscape:export-ydpi="27.093315" />
<path
style="fill:#404040;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.39687504,1.8520834 V 1.4552084 H 1.4552084 V 0.39687504 h 0.79375 V 1.4552084 h 1.0583333 v 0.79375 H 2.2489584 v 1.0583333 h -0.79375 V 2.2489584 H 0.39687504 Z"
id="path2830" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -44,7 +44,7 @@ PropertiesPage::PropertiesPage (img::Service *service, db::Manager *manager, QWi
: lay::PropertiesPage (parent, manager, service), mp_service (service), mp_direct_image (0)
{
mp_service->get_selection (m_selection);
m_pos = m_selection.begin ();
m_index = 0;
mp_service->clear_highlights ();
@ -107,10 +107,12 @@ PropertiesPage::init ()
colors->set_color (std::make_pair (QColor (), QColor ()));
colors->setEnabled (false);
value_le->setEnabled (false);
connect (browse_pb, SIGNAL (clicked ()), this, SLOT (browse ()));
connect (colors, SIGNAL (color_changed (std::pair<QColor, QColor>)), false_color_control, SLOT (set_current_color (std::pair<QColor, QColor>)));
connect (false_color_control, SIGNAL (selection_changed (std::pair<QColor, QColor>)), colors, SLOT (set_color (std::pair<QColor, QColor>)));
connect (false_color_control, SIGNAL (selection_changed (std::pair<QColor, QColor>)), this, SLOT (color_mapping_changed ()));
connect (false_color_control, SIGNAL (color_mapping_changed ()), this, SLOT (color_mapping_changed ()));
connect (brightness_slider, SIGNAL (valueChanged (int)), this, SLOT (brightness_slider_changed (int)));
@ -154,44 +156,40 @@ PropertiesPage::invalidate ()
}
}
void
PropertiesPage::back ()
size_t
PropertiesPage::count () const
{
m_pos = m_selection.end ();
return m_selection.size ();
}
void
PropertiesPage::select_entries (const std::vector<size_t> &entries)
{
tl_assert (entries.size () == 1);
m_index = entries.front ();
invalidate ();
}
void
PropertiesPage::front ()
std::string
PropertiesPage::description (size_t entry) const
{
m_pos = m_selection.begin ();
invalidate ();
const img::Object *obj = dynamic_cast <const img::Object *> (m_selection [entry]->ptr ());
if (! obj) {
return std::string ("nil");
}
std::string d = tl::to_string (tr ("Image"));
if (! obj->filename ().empty ()) {
d += "[" + tl::filename (obj->filename ()) + "]";
}
d += tl::sprintf ("(%dx%d)", obj->width (), obj->height ());
return d;
}
bool
PropertiesPage::at_begin () const
std::string
PropertiesPage::description () const
{
return (m_pos == m_selection.begin ());
}
bool
PropertiesPage::at_end () const
{
return (m_pos == m_selection.end ());
}
void
PropertiesPage::operator-- ()
{
--m_pos;
invalidate ();
}
void
PropertiesPage::operator++ ()
{
++m_pos;
invalidate ();
return tl::to_string (tr ("Images"));
}
void
@ -378,11 +376,11 @@ PropertiesPage::update ()
if (mp_service) {
mp_service->highlight (std::distance (m_selection.begin (), m_pos));
mp_service->highlight (m_index);
// create a local copy in which we can apply modifications
if (! mp_direct_image) {
const img::Object *image = dynamic_cast <const img::Object *> ((*m_pos)->ptr ());
const img::Object *image = dynamic_cast <const img::Object *> (m_selection [m_index]->ptr ());
mp_direct_image = new img::Object (*image);
}
@ -908,7 +906,7 @@ PropertiesPage::apply ()
mp_direct_image->set_data_mapping (dm);
if (mp_service) {
mp_service->change_image (*m_pos, *mp_direct_image);
mp_service->change_image (m_selection [m_index], *mp_direct_image);
}
}

View File

@ -50,12 +50,10 @@ public:
PropertiesPage (QWidget *parent);
~PropertiesPage ();
virtual void back ();
virtual void front ();
virtual bool at_begin () const;
virtual bool at_end () const;
virtual void operator-- ();
virtual void operator++ ();
virtual size_t count () const;
virtual void select_entries (const std::vector<size_t> &entries);
virtual std::string description (size_t entry) const;
virtual std::string description () const;
virtual void update ();
virtual void leave ();
virtual bool readonly ();
@ -91,7 +89,7 @@ private slots:
private:
std::vector <img::Service::obj_iterator> m_selection;
std::vector <img::Service::obj_iterator>::iterator m_pos;
size_t m_index;
img::Service *mp_service;
img::Object *mp_direct_image;
bool m_no_signals;

View File

@ -1377,10 +1377,12 @@ Service::display_status (bool transient)
}
#if defined(HAVE_QT)
lay::PropertiesPage *
Service::properties_page (db::Manager *manager, QWidget *parent)
std::vector<lay::PropertiesPage *>
Service::properties_pages (db::Manager *manager, QWidget *parent)
{
return new img::PropertiesPage (this, manager, parent);
std::vector<lay::PropertiesPage *> pages;
pages.push_back (new img::PropertiesPage (this, manager, parent));
return pages;
}
#endif

View File

@ -373,7 +373,7 @@ public:
/**
* @brief Create the properties page
*/
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager *manager, QWidget *parent);
#endif
/**

View File

@ -63,8 +63,8 @@ TwoColorWidget::TwoColorWidget (QWidget *parent)
mp_lock->setIconSize (QSize (16, 16));
QIcon icon;
icon.addFile (":/locked_16.png", QSize (), QIcon::Normal, QIcon::On);
icon.addFile (":/unlocked_16.png", QSize (), QIcon::Normal, QIcon::Off);
icon.addFile (":/locked_16px.png", QSize (), QIcon::Normal, QIcon::On);
icon.addFile (":/unlocked_16px.png", QSize (), QIcon::Normal, QIcon::Off);
mp_lock->setIcon (icon);
connect (mp_left, SIGNAL (color_changed (QColor)), this, SLOT (lcolor_changed (QColor)));

View File

@ -137,7 +137,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../icons/icons.qrc">:/logo@2x.png</pixmap>
<pixmap resource="../../icons/icons.qrc">:/logo.png</pixmap>
</property>
</widget>
</item>

View File

@ -171,7 +171,7 @@ p, li { white-space: pre-wrap; }
</property>
<property name="icon">
<iconset>
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="autoDefault">
<bool>true</bool>
@ -280,7 +280,7 @@ p, li { white-space: pre-wrap; }
</property>
<property name="icon">
<iconset>
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="autoDefault">
<bool>true</bool>
@ -454,7 +454,7 @@ p, li { white-space: pre-wrap; }
</property>
<property name="icon">
<iconset>
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="autoDefault">
<bool>true</bool>
@ -642,7 +642,7 @@ p, li { white-space: pre-wrap; }
</property>
<property name="icon">
<iconset>
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="autoDefault">
<bool>true</bool>

View File

@ -108,6 +108,9 @@
</property>
<item>
<widget class="QToolButton" name="add_pb">
<property name="toolTip">
<string>Add technology</string>
</property>
<property name="text">
<string>...</string>
</property>
@ -116,12 +119,15 @@
<normaloff>:/add_16px.png</normaloff>:/add_16px.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="delete_pb">
<property name="toolTip">
<string>Delete technology</string>
</property>
<property name="text">
<string>...</string>
</property>
@ -130,33 +136,37 @@
<normaloff>:/clear_16px.png</normaloff>:/clear_16px.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer>
<widget class="QToolButton" name="rename_pb">
<property name="toolTip">
<string>Rename technology</string>
</property>
<property name="text">
<string>Rename</string>
</property>
<property name="icon">
<iconset resource="../../icons/icons.qrc">
<normaloff>:/rename_16px@2x.png</normaloff>:/rename_16px@2x.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>141</width>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="rename_pb">
<property name="text">
<string>Rename</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -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<C> ("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."
)
;
}

View File

@ -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);

View File

@ -26,6 +26,7 @@
#include "layCommon.h"
#include "layBusy.h"
#include "tlEvents.h"
#include <QApplication>
#include <QEventLoop>
@ -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 ();
};
/**

View File

@ -26,6 +26,7 @@
#include "tlLog.h"
#include "tlInternational.h"
#include "tlWebDAV.h"
#include "lymMacro.h"
#include <QFileInfo>
#include <QDir>
@ -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 ();

View File

@ -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)
{

View File

@ -29,6 +29,7 @@
#include "laySalt.h"
#include "tlFileSystemWatcher.h"
#include "tlDeferredExecution.h"
#include "tlEvents.h"
#include <vector>
#include <string>
@ -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

View File

@ -35,7 +35,13 @@ ViewWidgetStack::ViewWidgetStack (QWidget *parent, const char *name)
mp_bglabel = new QLabel (this);
mp_bglabel->setAutoFillBackground (true);
mp_bglabel->setText (QObject::tr ("<html><body><p><img src=\":/logo.png\"/></p><p>Use File/Open to open a layout</p></body></html>"));
std::string logo = "logo.png";
#if QT_VERSION >= 0x50000
if (devicePixelRatio () >= 2.0) {
logo = "logo@2x.png";
}
#endif
mp_bglabel->setText (QObject::tr ("<html><body><p><img src=\":/%1\" width=\"256\" height=\"256\"/></p><p>Use File/Open to open a layout</p></body></html>").arg (tl::to_qstring (logo)));
mp_bglabel->setAlignment (Qt::AlignVCenter | Qt::AlignHCenter);
mp_bglabel->show ();
}

View File

@ -1603,6 +1603,17 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> 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<tl::Event (lay::LayoutViewBase::*)> (&lay::LayoutViewBase::active_cellview_changed_event),
"@brief An event indicating that the active cellview has changed\n"
"\n"
@ -1631,6 +1642,14 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> 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<tl::event<int> (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<tl::Event (lay::LayoutViewBase::*)> (&lay::LayoutViewBase::file_open_event),
"@brief An event indicating that a file was opened\n"
"\n"

View File

@ -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::max (std::min ((unsigned int) 6, pixels / 9), (unsigned int) 1);
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;
}
}
}
}

View File

@ -368,9 +368,9 @@ public:
* by the caller. The return value is 0 if the Editable object does
* not support a properties page.
*/
virtual lay::PropertiesPage *properties_page (db::Manager * /*manager*/, QWidget * /*parent*/)
virtual std::vector<lay::PropertiesPage *> properties_pages (db::Manager * /*manager*/, QWidget * /*parent*/)
{
return 0;
return std::vector<lay::PropertiesPage *> ();
}
#endif

View File

@ -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 ();

View File

@ -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)
{
@ -281,6 +150,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),
@ -328,19 +198,15 @@ LayoutCanvas::~LayoutCanvas ()
clear_fg_bitmaps ();
}
#if defined(HAVE_QT) && QT_VERSION >= 0x050000
double
LayoutCanvas::dpr ()
LayoutCanvas::resolution () const
{
return widget () ? widget ()->devicePixelRatio () : 1.0;
if (m_hrm) {
return 1.0 / m_oversampling;
} else {
return 1.0 / (m_oversampling * dpr ());
}
}
#else
double
LayoutCanvas::dpr ()
{
return 1.0;
}
#endif
#if defined(HAVE_QT)
void
@ -407,6 +273,26 @@ 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 ();
}
}
double
LayoutCanvas::dpr () const
{
#if defined(HAVE_QT) && QT_VERSION >= 0x50000
return widget () ? widget ()->devicePixelRatio () : 1.0;
#else
return 1.0;
#endif
}
void
LayoutCanvas::set_colors (tl::Color background, tl::Color foreground, tl::Color active)
{
@ -477,7 +363,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 +399,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 +449,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 +520,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 +550,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) {
@ -672,7 +558,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;
}
@ -684,7 +570,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;
}
@ -711,7 +597,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) {
@ -723,7 +609,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 ());
@ -799,9 +685,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);
}
@ -812,7 +698,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);
}
}
@ -986,13 +872,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 ();

View File

@ -256,6 +256,32 @@ public:
*/
void set_oversampling (unsigned int os);
/**
* @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 Gets the default device pixel ratio for this canvas
*/
double dpr () const;
/**
* @brief Sets the depth of the image cache
*/
@ -380,6 +406,7 @@ private:
lay::LineStyles m_line_styles;
std::map<unsigned int, std::vector <lay::ViewOp> > m_scaled_view_ops;
unsigned int m_oversampling;
bool m_hrm;
double m_gamma;
bool m_need_redraw;
@ -417,7 +444,7 @@ private:
void do_redraw_all (bool force_redraw = true);
void prepare_drawing ();
double dpr ();
virtual double resolution () const;
const std::vector<ViewOp> &scaled_view_ops (unsigned int lw);
};

View File

@ -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"
@ -780,6 +781,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;
@ -1520,6 +1528,185 @@ LayoutViewBase::set_selected_layers (const std::vector<lay::LayerPropertiesConst
}
}
/**
* @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 <lay::ViewOp> view_ops;
view_ops.push_back (view_op);
std::vector <lay::Bitmap *> 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)
{
if (dpr < 0.0) {
dpr = canvas ()->dpr ();
}
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) ? 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);
image.subsample (subsampled, oversampling, gamma);
return subsampled;
} else {
return image;
}
}
void
LayoutViewBase::merge_dither_pattern (lay::LayerPropertiesList &props)
{
@ -2314,6 +2501,8 @@ LayoutViewBase::signal_apply_technology (lay::LayoutHandle *layout_handle)
}
apply_technology_event (int (i));
}
}

View File

@ -581,6 +581,18 @@ public:
*/
virtual std::vector<lay::LayerPropertiesConstIterator> 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) - negative values mean auto-detect
* @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 = -1.0, unsigned int di_off = 0, bool no_state = false);
/**
* @brief Sets the layers that are selected in the layer browser
*/
@ -677,6 +689,14 @@ public:
*/
tl::event<int> 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<int> apply_technology_event;
/**
* @brief An event signalling that a file has been loaded.
*

View File

@ -107,6 +107,7 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_drop_small_cells_value, "10"));
options.push_back (std::pair<std::string, std::string> (cfg_array_border_instances, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_bitmap_oversampling, "1"));
options.push_back (std::pair<std::string, std::string> (cfg_highres_mode, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_image_cache_size, "1"));
options.push_back (std::pair<std::string, std::string> (cfg_default_font_size, "0"));
options.push_back (std::pair<std::string, std::string> (cfg_color_palette, lay::ColorPalette ().to_string ()));

View File

@ -29,6 +29,7 @@
#include "layEditable.h"
#include <QFrame>
#include <QIcon>
namespace db
{
@ -69,80 +70,54 @@ public:
virtual ~PropertiesPage ();
/**
* @brief Move the current pointer to the end of the selected objects list
*
* Must be implemented by the Editable function and must set the
* selected object pointer to past-the-end of the list. at_end () must
* return true after this.
* @brief Gets the number of entries represented by this page
*/
virtual void back () = 0;
virtual size_t count () const = 0;
/**
* @brief A helper function for the dialog that additionally reports
* if there are any elements in the selection
* @brief Selects the entries with the given indexes
*
* If multiple indexes are selected, the properties page shows
* all items with different values as "leave as is". Items with
* same value are shown with the given value.
*/
bool back_checked ()
virtual void select_entries (const std::vector<size_t> &entries) = 0;
/**
* @brief Convenience function to select a specific entry
*/
void select_entry (size_t entry)
{
back ();
return ! at_begin ();
std::vector<size_t> entries;
entries.push_back (entry);
select_entries (entries);
}
/**
* @brief Move the current pointer to the beginning of the selected objects list
*
* Must be implemented by the Editable function and must set the
* selected object pointer to the beginning of the list. at_begin () must
* return true after this.
* This method must return true, if there are any elements in the selection
* - i.e. operator++ () will be successful afterwards.
* @brief Gets a description text for the nth entry
*/
virtual void front () = 0;
virtual std::string description (size_t entry) const = 0;
/**
* @brief A helper function for the dialog that additionally reports
* if there are any elements in the selection
* @brief Gets the icon for the nth entry
*/
bool front_checked ()
virtual QIcon icon (size_t /*entry*/, int /*w*/, int /*h*/) const
{
front ();
return ! at_end ();
return QIcon ();
}
/**
* @brief Tell if the current object references the first one
*
* Must be implemented by the Editable function and must return
* true if the current object is the first one - i.e. if an
* operator-- would render the status invalid.
* If no object is referenced, this method and at_end () must return true.
* @brief Gets a description text for the whole group
*/
virtual bool at_begin () const = 0;
virtual std::string description () const = 0;
/**
* @brief Tell if the current object references past the last one
*
* If the current object pointer is past the end of the selected
* object space,
* @brief Gets the icon associated with the whole group
*/
virtual bool at_end () const = 0;
/**
* @brief Step one element back
*
* This method is supposed to move the current pointer one position
* back. If at_begin () was true before, the result may be unpredictable.
* The dialog will call update () to update the display accordingly.
*/
virtual void operator-- () = 0;
/**
* @brief Advance one element
*
* This method is supposed to move the current pointer one position
* forward. If at_end () was true before, the result may be unpredictable.
* The dialog will call update () to update the display accordingly.
*/
virtual void operator++ () = 0;
virtual QIcon icon (int /*w*/, int /*h*/) const
{
return QIcon ();
}
/**
* @brief Update the display
@ -176,7 +151,7 @@ public:
/**
* @brief Apply any changes to the current object
*
* Apply any changes to the current object. If nothing was
* Apply any changes to the current objects. If nothing was
* changed, the object may be left untouched.
* The dialog will start a transaction on the manager object.
*/

View File

@ -966,7 +966,7 @@ public:
/**
* @brief Gets the QWidget representing this canvas visually in Qt
*/
QWidget *widget ()
QWidget *widget () const
{
return mp_widget;
}

View File

@ -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");

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>791</width>
<height>385</height>
<height>403</height>
</rect>
</property>
<property name="windowTitle">
@ -32,7 +32,7 @@
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Oversampling</string>
<string>Display Quality</string>
</property>
<layout class="QGridLayout">
<property name="leftMargin">
@ -53,7 +53,14 @@
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Use oversampling: </string>
<string>Oversampling mode</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>High resolution mode utilizes the full pixel density on high-DPI displays. Features may look small but rich in details.</string>
</property>
</widget>
</item>
@ -99,6 +106,13 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="highres_mode">
<property name="text">
<string>High resolution mode enabled</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -63,7 +63,7 @@
</property>
<property name="icon">
<iconset>
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="shortcut">
<string>F5</string>

View File

@ -135,7 +135,7 @@
</property>
<property name="icon">
<iconset>
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="shortcut">
<string>F5</string>

View File

@ -6,43 +6,59 @@
<rect>
<x>0</x>
<y>0</y>
<width>601</width>
<height>391</height>
<width>828</width>
<height>567</height>
</rect>
</property>
<property name="windowTitle">
<string>Object Properties</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="content_frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
<widget class="QFrame" name="content_frame">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</widget>
</item>
<item>

View File

@ -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)
{

View File

@ -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<size_t> m_new_sel;
int m_phase;
int m_oversampling;
bool m_hrm;
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
std::set<unsigned int> m_expanded;
bool m_no_stipples;

View File

@ -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 <lay::ViewOp> view_ops;
view_ops.push_back (view_op);
std::vector <lay::Bitmap *> 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 ());
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

View File

@ -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);

View File

@ -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);
@ -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 ());

View File

@ -32,91 +32,222 @@
#include "ui_PropertiesDialog.h"
#include <QStackedLayout>
#include <QAbstractItemModel>
#include <QModelIndex>
namespace lay
{
#if QT_VERSION >= 0x50000
typedef qint64 tree_id_type;
#else
typedef qint32 tree_id_type;
#endif
// ----------------------------------------------------------------------------------------------------------
// PropertiesTreeModel definition and implementation
class PropertiesTreeModel
: public QAbstractItemModel
{
public:
PropertiesTreeModel (PropertiesDialog *dialog, int icon_width, int icon_height)
: QAbstractItemModel (dialog), mp_dialog (dialog), m_icon_width (icon_width), m_icon_height (icon_height)
{ }
int columnCount (const QModelIndex &) const
{
return 1;
}
QVariant data (const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
if (tree_id_type (index.internalId ()) < tree_id_type (mp_dialog->properties_pages ().size ())) {
return tl::to_qstring (mp_dialog->properties_pages () [index.internalId ()]->description (index.row ()));
} else if (index.row () < int (mp_dialog->properties_pages ().size ())) {
return tl::to_qstring (mp_dialog->properties_pages () [index.row ()]->description ());
}
} else if (role == Qt::DecorationRole) {
QIcon icon;
if (tree_id_type (index.internalId ()) < tree_id_type (mp_dialog->properties_pages ().size ())) {
icon = mp_dialog->properties_pages () [index.internalId ()]->icon (index.row (), m_icon_width, m_icon_height);
} else if (index.row () < int (mp_dialog->properties_pages ().size ())) {
icon = mp_dialog->properties_pages () [index.row ()]->icon (m_icon_width, m_icon_height);
}
if (! icon.isNull ()) {
return QVariant (icon);
}
}
return QVariant ();
}
Qt::ItemFlags flags (const QModelIndex &index) const
{
Qt::ItemFlags f = QAbstractItemModel::flags (index);
if (tree_id_type (index.internalId ()) >= tree_id_type (mp_dialog->properties_pages ().size ()) && ! mp_dialog->properties_pages () [index.row ()]->can_apply_to_all ()) {
f &= ~Qt::ItemIsSelectable;
}
return f;
}
bool hasChildren (const QModelIndex &parent) const
{
return (! parent.isValid () || tree_id_type (parent.internalId ()) >= tree_id_type (mp_dialog->properties_pages ().size ()));
}
QModelIndex index (int row, int column, const QModelIndex &parent) const
{
if (! parent.isValid ()) {
return createIndex (row, column, tree_id_type (mp_dialog->properties_pages ().size ()));
} else {
return createIndex (row, column, tree_id_type (parent.row ()));
}
}
QModelIndex parent (const QModelIndex &child) const
{
if (tree_id_type (child.internalId ()) < tree_id_type (mp_dialog->properties_pages ().size ())) {
return createIndex (int (child.internalId ()), child.column (), tree_id_type (mp_dialog->properties_pages ().size ()));
} else {
return QModelIndex ();
}
}
int rowCount (const QModelIndex &parent) const
{
if (! hasChildren (parent)) {
return 0;
} else if (parent.isValid ()) {
return int (mp_dialog->properties_pages () [parent.row ()]->count ());
} else {
return int (mp_dialog->properties_pages ().size ());
}
}
int page_index (const QModelIndex &index)
{
return int (index.internalId ());
}
int object_index (const QModelIndex &index)
{
return int (index.row ());
}
QModelIndex index_for (int page_index, int object_index)
{
if (page_index < 0) {
return QModelIndex ();
} else {
return createIndex (object_index, 0, tree_id_type (page_index));
}
}
QModelIndex index_for (int page_index)
{
if (page_index < 0) {
return QModelIndex ();
} else {
return createIndex (page_index, 0, tree_id_type (mp_dialog->properties_pages ().size ()));
}
}
private:
PropertiesDialog *mp_dialog;
int m_icon_width, m_icon_height;
};
// ----------------------------------------------------------------------------------------------------------
// PropertiesDialog
PropertiesDialog::PropertiesDialog (QWidget * /*parent*/, db::Manager *manager, lay::Editables *editables)
: QDialog (0 /*parent*/),
mp_manager (manager), mp_editables (editables), m_index (-1), m_auto_applied (false), m_transaction_id (0)
mp_manager (manager),
mp_editables (editables),
m_index (0), m_prev_index (-1),
m_auto_applied (false),
m_transaction_id (0),
m_signals_enabled (true)
{
mp_ui = new Ui::PropertiesDialog ();
setObjectName (QString::fromUtf8 ("properties_dialog"));
mp_ui->setupUi (this);
mp_tree_model = 0;
mp_editables->enable_edits (false);
mp_stack = new QStackedLayout;
for (lay::Editables::iterator e = mp_editables->begin (); e != mp_editables->end (); ++e) {
mp_properties_pages.push_back (e->properties_page (mp_manager, mp_ui->content_frame));
if (mp_properties_pages.back ()) {
mp_stack->addWidget (mp_properties_pages.back ());
connect (mp_properties_pages.back (), SIGNAL (edited ()), this, SLOT (apply ()));
auto pp = e->properties_pages (mp_manager, mp_ui->content_frame);
for (auto p = pp.begin (); p != pp.end (); ++p) {
if ((*p)->count () == 0) {
delete *p;
} else {
mp_properties_pages.push_back (*p);
}
}
}
for (size_t i = 0; i < mp_properties_pages.size (); ++i) {
mp_stack->addWidget (mp_properties_pages [i]);
connect (mp_properties_pages [i], SIGNAL (edited ()), this, SLOT (apply ()));
}
// Necessary to maintain the page order for UI regression testing of 0.18 vs. 0.19 (because tl::Collection has changed to order) ..
std::reverse (mp_properties_pages.begin (), mp_properties_pages.end ());
// Add a label as a dummy
QLabel *dummy = new QLabel (QObject::tr ("No object with properties to display"), mp_ui->content_frame);
dummy->setAlignment (Qt::AlignHCenter | Qt::AlignVCenter);
mp_stack->addWidget (dummy);
mp_none = new QLabel (QObject::tr ("No object with properties to display"), mp_ui->content_frame);
mp_none->setAlignment (Qt::AlignHCenter | Qt::AlignVCenter);
mp_stack->addWidget (mp_none);
mp_ui->content_frame->setLayout (mp_stack);
// disable the apply button for first ..
mp_ui->apply_to_all_cbx->setEnabled (false);
mp_ui->relative_cbx->setEnabled (false);
mp_ui->ok_button->setEnabled (false);
// as a proposal, the start button can be enabled in most cases
mp_ui->prev_button->setEnabled (true);
// count the total number of objects
m_objects = mp_editables->selection_size ();
m_current_object = 0;
// look for next usable editable
if (m_index >= int (mp_properties_pages.size ())) {
m_index = -1;
} else {
m_object_indexes.push_back (0);
}
update_title ();
// look for next usable editable
while (m_index < int (mp_properties_pages.size ()) &&
(m_index < 0 || mp_properties_pages [m_index] == 0 || mp_properties_pages [m_index]->at_end ())) {
++m_index;
}
mp_ui->prev_button->setEnabled (false);
// if at end disable the "Next" button and return (this may only happen at the first call)
if (m_index >= int (mp_properties_pages.size ())) {
mp_ui->next_button->setEnabled (false);
mp_stack->setCurrentWidget (dummy);
mp_ui->apply_to_all_cbx->setEnabled (false);
mp_ui->apply_to_all_cbx->setChecked (false);
mp_ui->relative_cbx->setEnabled (false);
mp_ui->relative_cbx->setChecked (false);
mp_ui->ok_button->setEnabled (false);
} else {
mp_ui->next_button->setEnabled (any_next ());
mp_properties_pages [m_index]->update ();
mp_stack->setCurrentWidget (mp_properties_pages [m_index]);
mp_ui->apply_to_all_cbx->setEnabled (! mp_properties_pages [m_index]->readonly () && mp_properties_pages [m_index]->can_apply_to_all ());
mp_ui->apply_to_all_cbx->setChecked (false);
mp_ui->relative_cbx->setEnabled (mp_ui->apply_to_all_cbx->isEnabled () && mp_ui->apply_to_all_cbx->isChecked ());
mp_ui->relative_cbx->setChecked (true);
mp_ui->ok_button->setEnabled (! mp_properties_pages [m_index]->readonly ());
mp_tree_model = new PropertiesTreeModel (this, mp_ui->tree->iconSize ().width (), mp_ui->tree->iconSize ().height ());
mp_ui->tree->setModel (mp_tree_model);
#if QT_VERSION >= 0x50000
mp_ui->tree->header()->setSectionResizeMode (QHeaderView::ResizeToContents);
#else
mp_ui->tree->header()->setResizeMode (QHeaderView::ResizeToContents);
#endif
mp_ui->tree->expandAll ();
if (mp_properties_pages.empty ()) {
mp_ui->tree->hide ();
}
m_signals_enabled = false;
mp_ui->tree->setCurrentIndex (mp_tree_model->index_for (m_index, 0));
m_signals_enabled = true;
update_controls ();
mp_ui->apply_to_all_cbx->setChecked (false);
mp_ui->relative_cbx->setChecked (true);
connect (mp_ui->ok_button, SIGNAL (clicked ()), this, SLOT (ok_pressed ()));
connect (mp_ui->cancel_button, SIGNAL (clicked ()), this, SLOT (cancel_pressed ()));
connect (mp_ui->prev_button, SIGNAL (clicked ()), this, SLOT (prev_pressed ()));
connect (mp_ui->next_button, SIGNAL (clicked ()), this, SLOT (next_pressed ()));
connect (mp_ui->apply_to_all_cbx, SIGNAL (clicked ()), this, SLOT (apply_to_all_pressed ()));
connect (mp_ui->tree->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (current_index_changed (const QModelIndex &, const QModelIndex &)));
connect (mp_ui->tree->selectionModel (), SIGNAL (selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT (selection_changed ()));
}
PropertiesDialog::~PropertiesDialog ()
@ -138,11 +269,147 @@ PropertiesDialog::disconnect ()
mp_properties_pages.clear ();
}
void
PropertiesDialog::apply_to_all_pressed ()
{
m_signals_enabled = false;
if (mp_ui->apply_to_all_cbx->isChecked ()) {
mp_ui->tree->setCurrentIndex (mp_tree_model->index_for (m_index));
} else if (! m_object_indexes.empty ()) {
mp_ui->tree->setCurrentIndex (mp_tree_model->index_for (m_index, int (m_object_indexes.front ())));
}
m_signals_enabled = true;
}
void
PropertiesDialog::selection_changed ()
{
current_index_changed (mp_ui->tree->currentIndex (), QModelIndex ());
}
void
PropertiesDialog::current_index_changed (const QModelIndex &index, const QModelIndex & /*previous*/)
{
if (! m_signals_enabled) {
return;
}
m_object_indexes.clear ();
if (! index.isValid ()) {
m_index = -1;
} else {
if (mp_tree_model->parent (index).isValid ()) {
m_index = mp_tree_model->page_index (index);
if (mp_properties_pages [m_index]->can_apply_to_all ()) {
m_object_indexes.push_back (size_t (mp_tree_model->object_index (index)));
auto selection = mp_ui->tree->selectionModel ()->selectedIndexes ();
for (auto i = selection.begin (); i != selection.end (); ++i) {
if (mp_tree_model->parent (*i).isValid () && mp_tree_model->page_index (*i) == m_index) {
int oi = mp_tree_model->object_index (*i);
if (oi != int (m_object_indexes.front ())) {
m_object_indexes.push_back (size_t (oi));
}
}
}
} else {
m_object_indexes.push_back (size_t (mp_tree_model->object_index (index)));
}
} else {
m_index = index.row ();
mp_ui->apply_to_all_cbx->setChecked (mp_properties_pages [m_index]->can_apply_to_all ());
if (mp_properties_pages [m_index]->can_apply_to_all ()) {
for (size_t oi = 0; oi < mp_properties_pages [m_index]->count (); ++oi) {
m_object_indexes.push_back (oi);
}
} else {
m_object_indexes.push_back (size_t (mp_tree_model->object_index (index)));
}
}
}
if (! m_object_indexes.empty ()) {
m_current_object = 0;
for (int i = 0; i < m_index; ++i) {
m_current_object += mp_properties_pages [i]->count ();
}
m_current_object += int (m_object_indexes.front ());
} else {
m_current_object = -1;
}
update_title ();
update_controls ();
}
void
PropertiesDialog::update_controls ()
{
if (m_prev_index >= 0 && m_index != m_prev_index) {
if (m_prev_index >= 0 && m_prev_index < int (mp_properties_pages.size ())) {
mp_properties_pages [m_prev_index]->leave ();
}
}
m_prev_index = m_index;
mp_ui->apply_to_all_cbx->setChecked (m_object_indexes.size () > 1);
if (m_index < 0) {
mp_stack->setCurrentWidget (mp_none);
mp_ui->prev_button->setEnabled (false);
mp_ui->next_button->setEnabled (false);
mp_ui->apply_to_all_cbx->setEnabled (false);
mp_ui->relative_cbx->setEnabled (false);
mp_ui->ok_button->setEnabled (false);
mp_ui->tree->setEnabled (false);
} else {
mp_stack->setCurrentWidget (mp_properties_pages [m_index]);
mp_ui->prev_button->setEnabled (any_prev ());
mp_ui->next_button->setEnabled (any_next ());
mp_ui->apply_to_all_cbx->setEnabled (! mp_properties_pages [m_index]->readonly () && mp_properties_pages [m_index]->can_apply_to_all ());
mp_ui->relative_cbx->setEnabled (mp_ui->apply_to_all_cbx->isEnabled () && mp_ui->apply_to_all_cbx->isChecked ());
mp_ui->ok_button->setEnabled (! mp_properties_pages [m_index]->readonly ());
mp_ui->tree->setEnabled (true);
mp_properties_pages [m_index]->select_entries (m_object_indexes);
mp_properties_pages [m_index]->update ();
}
}
void
PropertiesDialog::next_pressed ()
{
BEGIN_PROTECTED
if (m_object_indexes.empty ()) {
return;
}
if (! mp_properties_pages [m_index]->readonly ()) {
db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id);
mp_properties_pages [m_index]->apply ();
@ -152,32 +419,32 @@ BEGIN_PROTECTED
}
// advance the current entry
++(*mp_properties_pages [m_index]);
int object_index = int (m_object_indexes.front ());
++object_index;
// look for next usable editable if at end
if (mp_properties_pages [m_index]->at_end ()) {
mp_properties_pages [m_index]->leave ();
if (object_index >= int (mp_properties_pages [m_index]->count ())) {
++m_index;
while (m_index < int (mp_properties_pages.size ()) &&
(mp_properties_pages [m_index] == 0 || ! mp_properties_pages [m_index]->front_checked ())) {
++m_index;
}
object_index = 0;
// because we checked that there are any further elements, this should not happen:
if (m_index >= int (mp_properties_pages.size ())) {
return;
}
mp_stack->setCurrentWidget (mp_properties_pages [m_index]);
}
m_object_indexes.clear ();
m_object_indexes.push_back (object_index);
++m_current_object;
update_title ();
mp_ui->prev_button->setEnabled (true);
mp_ui->next_button->setEnabled (any_next ());
mp_ui->apply_to_all_cbx->setEnabled (! mp_properties_pages [m_index]->readonly () && mp_properties_pages [m_index]->can_apply_to_all ());
mp_ui->relative_cbx->setEnabled (mp_ui->apply_to_all_cbx->isEnabled () && mp_ui->apply_to_all_cbx->isChecked ());
mp_ui->ok_button->setEnabled (! mp_properties_pages [m_index]->readonly ());
mp_properties_pages [m_index]->update ();
update_controls ();
m_signals_enabled = false;
mp_ui->tree->setCurrentIndex (mp_tree_model->index_for (m_index, object_index));
m_signals_enabled = true;
END_PROTECTED
}
@ -187,6 +454,10 @@ PropertiesDialog::prev_pressed ()
{
BEGIN_PROTECTED
if (m_object_indexes.empty ()) {
return;
}
if (! mp_properties_pages [m_index]->readonly ()) {
db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id);
mp_properties_pages [m_index]->apply ();
@ -195,35 +466,35 @@ BEGIN_PROTECTED
}
}
if (mp_properties_pages [m_index]->at_begin ()) {
// advance the current entry
int object_index = int (m_object_indexes.front ());
if (object_index == 0) {
// look for last usable editable if at end
mp_properties_pages [m_index]->leave ();
--m_index;
while (m_index >= 0 &&
(mp_properties_pages [m_index] == 0 || ! mp_properties_pages [m_index]->back_checked ())) {
--m_index;
}
// because we checked that there are any further elements, this should not happen:
if (m_index < 0) {
return;
}
mp_stack->setCurrentWidget (mp_properties_pages [m_index]);
object_index = mp_properties_pages [m_index]->count ();
}
// decrement the current entry
--(*mp_properties_pages [m_index]);
--object_index;
m_object_indexes.clear ();
m_object_indexes.push_back (object_index);
--m_current_object;
update_title ();
mp_ui->next_button->setEnabled (true);
mp_ui->prev_button->setEnabled (any_prev ());
mp_ui->apply_to_all_cbx->setEnabled (! mp_properties_pages [m_index]->readonly () && mp_properties_pages [m_index]->can_apply_to_all ());
mp_ui->relative_cbx->setEnabled (mp_ui->apply_to_all_cbx->isEnabled () && mp_ui->apply_to_all_cbx->isChecked ());
mp_ui->ok_button->setEnabled (! mp_properties_pages [m_index]->readonly ());
mp_properties_pages [m_index]->update ();
update_controls ();
m_signals_enabled = false;
mp_ui->tree->setCurrentIndex (mp_tree_model->index_for (m_index, object_index));
m_signals_enabled = true;
END_PROTECTED
}
@ -231,40 +502,39 @@ END_PROTECTED
void
PropertiesDialog::update_title ()
{
setWindowTitle (tl::to_qstring (tl::to_string (QObject::tr ("Object Properties - ")) + tl::to_string (m_current_object + 1) + tl::to_string (QObject::tr (" of ")) + tl::to_string (m_objects)));
if (m_index < 0) {
setWindowTitle (QObject::tr ("Object Properties"));
} else {
setWindowTitle (tl::to_qstring (tl::to_string (QObject::tr ("Object Properties - ")) + tl::to_string (m_current_object + 1) + tl::to_string (QObject::tr (" of ")) + tl::to_string (m_objects)));
}
}
bool
PropertiesDialog::any_next () const
{
// test-advance
if (m_object_indexes.empty ()) {
return false;
}
int index = m_index;
++(*mp_properties_pages [index]);
if (mp_properties_pages [index]->at_end ()) {
if (m_object_indexes.front () + 1 >= mp_properties_pages [index]->count ()) {
++index;
while (index < int (mp_properties_pages.size ()) &&
(mp_properties_pages [index] == 0 || ! mp_properties_pages [index]->front_checked ())) {
++index;
}
}
// return true, if not at end
bool ret = (index < int (mp_properties_pages.size ()));
--(*mp_properties_pages [m_index]);
return ret;
return (index < int (mp_properties_pages.size ()));
}
bool
PropertiesDialog::any_prev () const
{
// test-decrement
if (m_object_indexes.empty ()) {
return false;
}
int index = m_index;
if (mp_properties_pages [index]->at_begin ()) {
if (m_object_indexes.front () == 0) {
--index;
while (index >= 0 &&
(mp_properties_pages [index] == 0 || ! mp_properties_pages [index]->back_checked ())) {
--index;
}
}
// return true, if not at the beginning

View File

@ -54,6 +54,7 @@ class Editable;
class Editables;
class PropertiesPage;
class MainWindow;
class PropertiesTreeModel;
/**
* @brief The properties dialog
@ -80,20 +81,28 @@ public:
~PropertiesDialog ();
private:
friend class PropertiesTreeModel;
std::vector<lay::PropertiesPage *> mp_properties_pages;
db::Manager *mp_manager;
lay::Editables *mp_editables;
int m_index;
int m_index, m_prev_index;
std::vector<size_t> m_object_indexes;
QStackedLayout *mp_stack;
QLabel *mp_none;
lay::MainWindow *mp_mw;
size_t m_objects, m_current_object;
bool m_auto_applied;
db::Manager::transaction_id_t m_transaction_id;
PropertiesTreeModel *mp_tree_model;
bool m_signals_enabled;
const std::vector<lay::PropertiesPage *> &properties_pages () { return mp_properties_pages; }
void disconnect ();
bool any_prev () const;
bool any_next () const;
void update_title ();
void update_controls ();
public slots:
void apply ();
@ -101,6 +110,9 @@ public slots:
void prev_pressed ();
void cancel_pressed ();
void ok_pressed ();
void apply_to_all_pressed ();
void current_index_changed (const QModelIndex &index, const QModelIndex &previous);
void selection_changed ();
protected:
void reject ();

View File

@ -860,6 +860,40 @@ const char *color_icon =
"xxxxE44ExxD33Dxxxx"
"xxxxxeexxxxddxxxxx";
const char *color_icon_2x =
"xxxxxxxxxxaaaaxxxxxxxxbbbbxxxxxxxxxx"
"xxxxxxxxxA0000AxxxxxxB1111Bxxxxxxxxx"
"xxxxxxxxA000000AxxxxB111111Bxxxxxxxx"
"xxxxxxxA00000000AxxB11111111Bxxxxxxx"
"xxxxxxa0000000000ab1111111111bxxxxxx"
"xxxxxxa0000000000ab1111111111bxxxxxx"
"xxxxxxa0000000000ab1111111111bxxxxxx"
"xxxxxxa0000000000ab1111111111bxxxxxx"
"xxxxxxxA00000000AxxB11111111Bxxxxxxx"
"xxxxxxxxA000000AxxxxB111111Bxxxxxxxx"
"xxxxffffxA0000AxxxxxxB1111Bxccccxxxx"
"xxxF5555FxaaaaxxxxxxxxbbbbxC2222Cxxx"
"xxF555555FxxxxxxxxxxxxxxxxC222222Cxx"
"xF55555555FxxxxxxxxxxxxxxC22222222Cx"
"f5555555555fxxxxxxxxxxxxc2222222222c"
"f5555555555fxxxxxxxxxxxxc2222222222c"
"f5555555555fxxxxxxxxxxxxc2222222222c"
"f5555555555fxxxxxxxxxxxxc2222222222c"
"xF55555555FxxxxxxxxxxxxxxC22222222Cx"
"xxF555555FxxxxxxxxxxxxxxxxC222222Cxx"
"xxxF5555FxeeeexxxxxxxxddddxC2222Cxxx"
"xxxxffffxE4444ExxxxxxD3333Dxccccxxxx"
"xxxxxxxxE444444ExxxxD333333Dxxxxxxxx"
"xxxxxxxE44444444ExxD33333333Dxxxxxxx"
"xxxxxxe4444444444ed3333333333dxxxxxx"
"xxxxxxe4444444444ed3333333333dxxxxxx"
"xxxxxxe4444444444ed3333333333dxxxxxx"
"xxxxxxe4444444444ed3333333333dxxxxxx"
"xxxxxxxE44444444ExxD33333333Dxxxxxxx"
"xxxxxxxxE444444ExxxxD333333Dxxxxxxxx"
"xxxxxxxxxE4444ExxxxxxD3333Dxxxxxxxxx"
"xxxxxxxxxxeeeexxxxxxxxddddxxxxxxxxxx";
void
ColorButton::build_color_menu (QMenu *menu, QObject *receiver, const char *browse_slot, const char *selected_slot)
{
@ -898,10 +932,18 @@ ColorButton::build_color_menu (QMenu *menu, QObject *receiver, const char *brows
codes.insert (std::make_pair ('A' + j, c));
}
QImage icon (18, 16, QImage::Format_ARGB32);
const char *cp = color_icon;
for (int y = 0; y < 16; ++y) {
for (int x = 0; x < 18; ++x) {
int dpr = 1;
#if QT_VERSION >= 0x50000
dpr = (menu->devicePixelRatio () >= 2.0) ? 2 : 1;
#endif
QImage icon (18 * dpr, 16 * dpr, QImage::Format_ARGB32);
#if QT_VERSION >= 0x50000
icon.setDevicePixelRatio (menu->devicePixelRatio ());
#endif
const char *cp = dpr > 1 ? color_icon_2x : color_icon;
for (int y = 0; y < icon.height (); ++y) {
for (int x = 0; x < icon.width (); ++x) {
icon.setPixel (x, y, codes [*cp].rgba ());
++cp;
}
@ -915,6 +957,9 @@ ColorButton::build_color_menu (QMenu *menu, QObject *receiver, const char *brows
std::string name = tl::sprintf ("#%d", i + 1);
QPixmap icon (16, 16);
#if QT_VERSION >= 0x50000
icon.setDevicePixelRatio (menu->devicePixelRatio ());
#endif
icon.fill (color);
submenu->addAction (QIcon (icon), tl::to_qstring (name), receiver, selected_slot)->setData (QVariant (color));
@ -949,7 +994,16 @@ ColorButton::set_color_internal (QColor c)
QPushButton::setIconSize (QSize (rt.width (), rt.height ()));
QPixmap pixmap (rt.width (), rt.height ());
#if QT_VERSION >= 0x050000
double dpr = devicePixelRatio ();
#else
double dpr = 1.0;
#endif
QPixmap pixmap (rt.width () * dpr, rt.height () * dpr);
#if QT_VERSION >= 0x50000
pixmap.setDevicePixelRatio (dpr);
#endif
pixmap.fill (QColor (0, 0, 0, 0));
QColor text_color = palette ().color (QPalette::Active, QPalette::Text);
@ -959,13 +1013,13 @@ ColorButton::set_color_internal (QColor c)
if (! m_color.isValid ()) {
pxpainter.setFont (font ());
QRect r (0, 0, pixmap.width () - 1, pixmap.height () - 1);
QRectF r (0, 0, rt.width () - pxpainter.pen ().widthF (), rt.height () - pxpainter.pen ().widthF ());
pxpainter.drawText (r, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, QObject::tr ("Auto"));
} else {
pxpainter.setBrush (QBrush (c));
QRect r (0, 0, pixmap.width () - 1, pixmap.height () - 1);
QRectF r (0, 0, rt.width () - pxpainter.pen ().widthF (), rt.height () - pxpainter.pen ().widthF ());
pxpainter.drawRect (r);
}

View File

@ -25,6 +25,7 @@
#include "rdbMarkerBrowserDialog.h"
#include "rdb.h"
#include "rdbReader.h"
#include "rdbUtils.h"
#include "tlProgress.h"
#include "layLayoutViewBase.h"
#include "tlExceptions.h"
@ -790,11 +791,7 @@ MarkerBrowserDialog::scan_layer ()
for (db::ShapeIterator shape = cell.shapes ((*l)->layer_index ()).begin (db::ShapeIterator::All); ! shape.at_end (); ++shape) {
std::unique_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*shape, db::CplxTrans (layout.dbu ())));
if (value.get ()) {
rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ());
item->values ().add (value.release ());
}
rdb::create_item_from_shape (rdb.get (), rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), *shape);
++progress;
@ -869,11 +866,7 @@ MarkerBrowserDialog::scan_layer_flat ()
db::RecursiveShapeIterator shape (layout, *cv.cell (), (*l)->layer_index ());
while (! shape.at_end ()) {
std::unique_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*shape, db::CplxTrans (layout.dbu ()) * shape.trans ()));
if (value.get ()) {
rdb::Item *item = rdb->create_item (rdb_top_cell->id (), cat->id ());
item->values ().add (value.release ());
}
rdb::create_item_from_shape (rdb.get (), rdb_top_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()) * shape.trans (), *shape);
++progress;
++shape;

View File

@ -584,10 +584,15 @@ LayoutView::show_properties ()
}
// re-create a new properties dialog
QByteArray geom;
if (mp_properties_dialog) {
geom = mp_properties_dialog->saveGeometry ();
delete mp_properties_dialog.data ();
}
mp_properties_dialog = new lay::PropertiesDialog (widget (), manager (), this);
if (! geom.isEmpty ()) {
mp_properties_dialog->restoreGeometry (geom);
}
// if launched from a dialog, do not use "show" as this blocks user interaction
if (QApplication::activeModalWidget ()) {
@ -731,6 +736,24 @@ 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);
if (mp_control_panel) {
mp_control_panel->set_oversampling (os);
}
} else if (name == cfg_highres_mode) {
bool hrm = false;
tl::from_string (value, hrm);
if (mp_control_panel) {
mp_control_panel->set_highres_mode (hrm);
}
}
if (LayoutViewBase::configure (name, value)) {
return true;
}

View File

@ -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<std::string> &used_symbols) const
NetTracerLayerExpressionInfo::get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerConnectivity &tech, const std::set<std::string> &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<std::string> 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<std::string> us;
return get (layout, tech, us);
}
NetTracerLayerExpression *
NetTracerLayerExpressionInfo::get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set<std::string> &used_symbols) const
NetTracerLayerExpressionInfo::get (const db::Layout &layout, const NetTracerConnectivity &tech, const std::set<std::string> &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<NetTracerLayerExpression> 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));
}

View File

@ -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<std::string> &used_symbols) const;
NetTracerLayerExpression *get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set<std::string> &used_symbols) const;
NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerConnectivity &tech, const std::set<std::string> &used_symbols) const;
NetTracerLayerExpression *get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerConnectivity &tech, const std::set<std::string> &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<NetTracerConnectionInfo>::const_iterator const_iterator;
@ -366,9 +365,29 @@ public:
typedef std::vector<NetTracerSymbolInfo>::const_iterator const_symbol_iterator;
typedef std::vector<NetTracerSymbolInfo>::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
{
@ -416,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);
@ -458,14 +487,73 @@ public:
NetTracerData get_tracer_data (const db::Layout &layout) const;
db::TechnologyComponent *clone () const
private:
std::vector<NetTracerConnectionInfo> m_connections;
std::vector<NetTracerSymbolInfo> m_symbols;
std::string m_name, m_description;
};
class DB_PLUGIN_PUBLIC NetTracerTechnologyComponent
: public db::TechnologyComponent
{
public:
typedef std::vector<NetTracerConnectivity>::const_iterator const_iterator;
typedef std::vector<NetTracerConnectivity>::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.end ();
}
iterator begin ()
{
return m_connectivity.begin ();
}
iterator end ()
{
return m_connectivity.end ();
}
db::NetTracerTechnologyComponent *clone () const
{
return new NetTracerTechnologyComponent (*this);
}
private:
std::vector<NetTracerConnectionInfo> m_connections;
std::vector<NetTracerSymbolInfo> m_symbols;
std::vector<NetTracerConnectivity> m_connectivity;
};
}

View File

@ -65,6 +65,101 @@ namespace tl
};
}
namespace
{
static const db::NetTracerConnectivity *
get_default (const db::NetTracerTechnologyComponent &tc)
{
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 <class Value>
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 (! mp_stack) {
mp_stack = const_cast<db::NetTracerConnectivity *> (get_default (owner));
if (! mp_stack) {
owner.push_back (db::NetTracerConnectivity ());
mp_stack = (owner.end () - 1).operator-> ();
}
(mp_stack->*mp_clear) ();
}
tl::XMLObjTag<Value> 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 <class Value, class Iter>
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;
};
}
namespace db
{
@ -86,8 +181,20 @@ public:
virtual tl::XMLElementBase *xml_element () const
{
return new db::TechnologyComponentXMLElement<NetTracerTechnologyComponent> (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")
// 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, "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<NetTracerConnectionInfo, NetTracerTechnologyComponent, FallbackXMLReadAdaptor <NetTracerConnectionInfo, NetTracerConnectivity::const_iterator>, FallbackXMLWriteAdaptor <NetTracerConnectionInfo>, tl::XMLStdConverter <NetTracerConnectionInfo> > (
FallbackXMLReadAdaptor <NetTracerConnectionInfo, NetTracerConnectivity::const_iterator> (&NetTracerConnectivity::begin, &NetTracerConnectivity::end),
FallbackXMLWriteAdaptor <NetTracerConnectionInfo> (&NetTracerConnectivity::add, &NetTracerConnectivity::clear_connections), "connection") +
tl::XMLMember<NetTracerSymbolInfo, NetTracerTechnologyComponent, FallbackXMLReadAdaptor <NetTracerSymbolInfo, NetTracerConnectivity::const_symbol_iterator>, FallbackXMLWriteAdaptor <NetTracerSymbolInfo>, tl::XMLStdConverter <NetTracerSymbolInfo> > (
FallbackXMLReadAdaptor <NetTracerSymbolInfo, NetTracerConnectivity::const_symbol_iterator> (&NetTracerConnectivity::begin_symbols, &NetTracerConnectivity::end_symbols),
FallbackXMLWriteAdaptor <NetTracerSymbolInfo> (&NetTracerConnectivity::add_symbol, &NetTracerConnectivity::clear_symbols), "symbols")
);
}
};

View File

@ -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<db::TechnologyComponent> &decl_dbTechnologyComponent ();
gsi::Class<db::NetTracerTechnologyComponent> decl_NetTracerTechnology (decl_dbTechnologyComponent (), "db", "NetTracerTechnology",
gsi::Class<db::NetTracerConnectivity> 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<db::NetTracerTechnologyComponent> 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<db::NetTracerTechnologyComponent> 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 <const db::NetTracerTechnologyComponent *> (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 <const db::NetTracerTechnologyComponent *> (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<db::NetTracerShape> 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<db::NetTracer> 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<db::NetTracer> 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<db::NetTracer> 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."
@ -267,7 +334,7 @@ gsi::Class<db::NetTracer> decl_NetTracer ("db", "NetTracer",
"\n"
"tracer = RBA::NetTracer::new\n"
"\n"
"tech = RBA::NetTracerTechnology::new\n"
"tech = RBA::NetTracerConnectivity::new\n"
"tech.connection(\"1/0\", \"2/0\", \"3/0\")\n"
"\n"
"tracer.trace(tech, ly, ly.top_cell, RBA::Point::new(7000, 1500), ly.find_layer(1, 0))\n"
@ -277,7 +344,7 @@ gsi::Class<db::NetTracer> decl_NetTracer ("db", "NetTracer",
"end\n"
"@/code\n"
"\n"
"This class has been introduced in version 0.25."
"This class has been introduced in version 0.25. With version 0.28, the \\NetTracerConnectivity class replaces the 'NetTracerTechnology' class."
);
}

View File

@ -0,0 +1,343 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NetTracerConnectivityEditor</class>
<widget class="QWidget" name="NetTracerConnectivityEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>572</width>
<height>449</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin" stdset="0">
<number>9</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QFrame" name="frame_6">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin" stdset="0">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin" stdset="0">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="help_label">
<property name="text">
<string>&lt;html&gt;Connectivity (&lt;a href=&quot;int:/about/connectivity.xml&quot;&gt;See here for details&lt;/a&gt;)&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_5">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout">
<property name="margin" stdset="0">
<number>0</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="3" column="1">
<widget class="QToolButton" name="move_conductor_down_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/down_16px.png</normaloff>:/down_16px.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="del_conductor_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/del_16px.png</normaloff>:/del_16px.png</iconset>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="5">
<widget class="QTableWidget" name="connectivity_table">
<property name="editTriggers">
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="columnCount">
<number>3</number>
</property>
<column/>
<column/>
<column/>
</widget>
</item>
<item row="0" column="1">
<widget class="QToolButton" name="add_conductor_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/add_16px.png</normaloff>:/add_16px.png</iconset>
</property>
<property name="shortcut">
<string>Return</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>131</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QToolButton" name="move_conductor_up_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/up_16px.png</normaloff>:/up_16px.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin" stdset="0">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin" stdset="0">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="symbol_help_label">
<property name="text">
<string>&lt;html&gt;Computed and symbolic layers (&lt;a href=&quot;int:/about/symbolic_layers.xml&quot;&gt;See here for details&lt;/a&gt;)&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout">
<property name="margin" stdset="0">
<number>0</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="3" column="1">
<widget class="QToolButton" name="move_symbol_down_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/down_16px.png</normaloff>:/down_16px.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="del_symbol_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/del_16px.png</normaloff>:/del_16px.png</iconset>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="5">
<widget class="QTableWidget" name="symbol_table">
<property name="editTriggers">
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="columnCount">
<number>2</number>
</property>
<column/>
<column/>
</widget>
</item>
<item row="0" column="1">
<widget class="QToolButton" name="add_symbol_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/add_16px.png</normaloff>:/add_16px.png</iconset>
</property>
<property name="shortcut">
<string>Return</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>131</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QToolButton" name="move_symbol_up_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/up_16px.png</normaloff>:/up_16px.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../../../icons/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -29,24 +29,14 @@
<property name="spacing">
<number>6</number>
</property>
<item row="3" column="0" rowspan="2" colspan="8">
<item row="3" column="0" rowspan="2" colspan="9">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0" rowspan="2">
<widget class="QPushButton" name="configure_pb">
<property name="text">
<string>Configure</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="8">
<item row="1" column="0" colspan="9">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
@ -67,7 +57,7 @@ Select one or multiple nets and choose &quot;Export&quot; to export the selected
</property>
</widget>
</item>
<item row="2" column="7">
<item row="2" column="8">
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
@ -196,60 +186,7 @@ Select one or multiple nets and choose &quot;Export&quot; to export the selected
</layout>
</widget>
</item>
<item row="5" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="3" rowspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Trace depth:</string>
</property>
</widget>
</item>
<item row="5" column="7" rowspan="2">
<widget class="QPushButton" name="close_pb">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="5" column="6" rowspan="2">
<widget class="QLabel" name="tech_info_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="1" rowspan="2">
<widget class="QPushButton" name="stack_pb">
<property name="text">
<string>Layer Stack</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="7">
<item row="2" column="0" colspan="8">
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
@ -332,7 +269,6 @@ Select one or multiple nets and choose &quot;Export&quot; to export the selected
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -477,7 +413,23 @@ p, li { white-space: pre-wrap; }
</widget>
</widget>
</item>
<item row="0" column="0" colspan="8">
<item row="5" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="9">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
@ -488,7 +440,6 @@ p, li { white-space: pre-wrap; }
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
</font>
@ -498,14 +449,54 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="5" column="5" rowspan="2">
<item row="5" column="2">
<widget class="QComboBox" name="stack_selector">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="stack_pb">
<property name="text">
<string>Layer Stack</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="configure_pb">
<property name="text">
<string>Configure</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="5" column="8">
<widget class="QPushButton" name="close_pb">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="5" column="6">
<widget class="QLabel" name="label_6">
<property name="text">
<string>shapes</string>
</property>
</widget>
</item>
<item row="5" column="4" rowspan="2">
<item row="5" column="5">
<widget class="QLineEdit" name="depth_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -521,6 +512,26 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Trace depth:</string>
</property>
</widget>
</item>
<item row="5" column="7">
<widget class="QLabel" name="tech_info_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NetTracerTechComponentEditor</class>
<widget class="QWidget" name="NetTracerTechComponentEditor" >
<property name="geometry" >
<widget class="QWidget" name="NetTracerTechComponentEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,324 +10,265 @@
<height>449</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QSplitter" name="splitter" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QFrame" name="frame_6" >
<property name="frameShape" >
<widget class="QFrame" name="frame_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_2" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="4" column="5">
<widget class="QToolButton" name="move_down_pb">
<property name="toolTip">
<string>Move selected stacks up</string>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/down_16px.png</normaloff>:/down_16px.png</iconset>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="help_label" >
<property name="text" >
<string>&lt;html>Connectivity (&lt;a href="int:/about/connectivity.xml">See here for details&lt;/a>)&lt;/html></string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_5" >
<property name="frameShape" >
<item row="4" column="0" colspan="2">
<widget class="QToolButton" name="add_pb">
<property name="toolTip">
<string>Add new stack</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/add_16px.png</normaloff>:/add_16px.png</iconset>
</property>
<property name="shortcut">
<string>Return</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="6">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</widget>
</item>
<item row="1" column="0" rowspan="2" colspan="7">
<widget class="QTreeWidget" name="stack_tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Name</string>
</property>
<property name="spacing" >
<number>6</number>
</column>
<column>
<property name="text">
<string>Description</string>
</property>
<item row="3" column="1" >
<widget class="QToolButton" name="move_conductor_down_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/down_16px.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QToolButton" name="del_conductor_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/del_16px.png</iconset>
</property>
<property name="shortcut" >
<string>Del</string>
</property>
</widget>
</item>
<item rowspan="5" row="0" column="0" >
<widget class="QTableWidget" name="connectivity_table" >
<property name="editTriggers" >
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionBehavior" >
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="columnCount" >
<number>3</number>
</property>
<column/>
<column/>
<column/>
</widget>
</item>
<item row="0" column="1" >
<widget class="QToolButton" name="add_conductor_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/add_16px.png</iconset>
</property>
<property name="shortcut" >
<string>Return</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>131</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1" >
<widget class="QToolButton" name="move_conductor_up_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/up_16px.png</iconset>
</property>
</widget>
</item>
</layout>
</column>
</widget>
</item>
<item row="4" column="3">
<widget class="QToolButton" name="del_pb">
<property name="toolTip">
<string>Remove selected stacks</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/del_16px.png</normaloff>:/del_16px.png</iconset>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QToolButton" name="move_up_pb">
<property name="toolTip">
<string>Move selected stacks down</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/up_16px.png</normaloff>:/up_16px.png</iconset>
</property>
</widget>
</item>
<item row="3" column="0" colspan="7">
<widget class="QLabel" name="label">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Double-click to edit text</string>
</property>
</widget>
</item>
<item row="4" column="6">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>157</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="7">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Technology Stacks</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QToolButton" name="clone_pb">
<property name="toolTip">
<string>Clone current stack</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/clone_16px.png</normaloff>:/clone_16px.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_4" >
<property name="frameShape" >
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_3" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Connectivity</string>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="symbol_help_label" >
<property name="text" >
<string>&lt;html>Computed and symbolic layers (&lt;a href="int:/about/symbolic_layers.xml">See here for details&lt;/a>)&lt;/html></string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
<widget class="lay::NetTracerConnectivityEditor" name="connectivity_editor_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="3" column="1" >
<widget class="QToolButton" name="move_symbol_down_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/down_16px.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QToolButton" name="del_symbol_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/del_16px.png</iconset>
</property>
<property name="shortcut" >
<string>Del</string>
</property>
</widget>
</item>
<item rowspan="5" row="0" column="0" >
<widget class="QTableWidget" name="symbol_table" >
<property name="editTriggers" >
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionBehavior" >
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="columnCount" >
<number>2</number>
</property>
<column/>
<column/>
</widget>
</item>
<item row="0" column="1" >
<widget class="QToolButton" name="add_symbol_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/add_16px.png</iconset>
</property>
<property name="shortcut" >
<string>Return</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>131</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1" >
<widget class="QToolButton" name="move_symbol_up_pb" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/up_16px.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<customwidgets>
<customwidget>
<class>lay::NetTracerConnectivityEditor</class>
<extends>QWidget</extends>
<header>layNetTracerConnectivityEditor.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../../icons/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -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,20 @@ NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
symbol_table->verticalHeader ()->hide ();
}
void
NetTracerTechComponentEditor::commit ()
void
NetTracerConnectivityEditor::get_connectivity (db::NetTracerConnectivity &data)
{
db::NetTracerTechnologyComponent *data = dynamic_cast <db::NetTracerTechnologyComponent *> (tech_component ());
if (! data) {
return;
}
*data = m_data;
std::string name = data.name ();
std::string description = data.description ();
data = m_data;
data.set_name (name);
data.set_description (description);
}
void
NetTracerTechComponentEditor::setup ()
NetTracerConnectivityEditor::set_connectivity (const db::NetTracerConnectivity &data)
{
db::NetTracerTechnologyComponent *data = dynamic_cast <db::NetTracerTechnologyComponent *> (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 +326,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 +345,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 +368,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 +385,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 +409,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 +426,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 +452,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 +471,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 +494,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 +511,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 +535,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 +552,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 +578,7 @@ NetTracerTechComponentEditor::symbol_move_down_clicked ()
}
void
NetTracerTechComponentEditor::update ()
NetTracerConnectivityEditor::update ()
{
QStringList labels;
int n;
@ -600,7 +594,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 +646,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) {

View File

@ -0,0 +1,82 @@
/*
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_layNetTracerConnectivityEditor
#define HDR_layNetTracerConnectivityEditor
#include "ui_NetTracerConnectivityEditor.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 NetTracerConnectivity;
}
namespace lay
{
class NetTracerConnectivityEditor
: public QWidget,
public Ui::NetTracerConnectivityEditor
{
Q_OBJECT
public:
NetTracerConnectivityEditor (QWidget *parent);
void set_connectivity (const db::NetTracerConnectivity &data);
void get_connectivity (db::NetTracerConnectivity &);
public slots:
void add_clicked ();
void del_clicked ();
void move_up_clicked ();
void move_down_clicked ();
void symbol_add_clicked ();
void symbol_del_clicked ();
void symbol_move_up_clicked ();
void symbol_move_down_clicked ();
private:
db::NetTracerConnectivity m_data;
void update ();
};
}
#endif

View File

@ -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<QString> 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 <const db::NetTracerTechnologyComponent *> (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::NetTracerTechnologyComponent *tech_component = dynamic_cast <const db::NetTracerTechnologyComponent *> (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

View File

@ -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 ();

View File

@ -22,7 +22,7 @@
#include "dbNetTracerIO.h"
#include "layNetTracerIO.h"
#include "layNetTracerTechComponentEditor.h"
#include "layNetTracerDialog.h"
#include "layNetTracerConfig.h"

View File

@ -0,0 +1,424 @@
/*
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 <QMessageBox>
#include <QInputDialog>
#include <QItemDelegate>
#include <QHeaderView>
#include <QPainter>
#include <fstream>
#include <sstream>
namespace lay
{
// -----------------------------------------------------------------------------------------
// 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<QLineEdit *> (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<QLineEdit *> (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
NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
: TechnologyComponentEditor (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 ()));
stack_tree->header ()->setHighlightSections (false);
stack_tree->header ()->setStretchLastSection (true);
connect (stack_tree, SIGNAL (currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT (current_item_changed(QTreeWidgetItem *, QTreeWidgetItem *)));
}
void
NetTracerTechComponentEditor::commit ()
{
db::NetTracerTechnologyComponent *data = dynamic_cast <db::NetTracerTechnologyComponent *> (tech_component ());
if (! data) {
return;
}
commit_current ();
*data = m_data;
}
void
NetTracerTechComponentEditor::setup ()
{
db::NetTracerTechnologyComponent *data = dynamic_cast <db::NetTracerTechnologyComponent *> (tech_component ());
if (! data) {
return;
}
m_data = *data;
if (m_data.size () == 0) {
m_data.push_back (db::NetTracerConnectivity ());
}
stack_tree->setItemDelegateForColumn (0, new NetTracerTechComponentColumnDelegate (stack_tree, &m_data));
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
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 ())) {
connectivity_editor_widget->get_connectivity (m_data.begin () [row]);
}
}
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
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].set_name (new_name (m_data));
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<int> 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 ());
}
int offset = 0;
for (std::set<int>::const_iterator r = selected_rows.begin (); r != selected_rows.end (); ++r) {
m_data.erase (m_data.begin () + (*r - offset));
++offset;
}
update ();
stack_tree->setCurrentItem (0);
}
void
NetTracerTechComponentEditor::move_up_clicked ()
{
// removes focus from the tree view - commits the data
move_up_pb->setFocus ();
commit_current ();
std::set<int> 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 <int>::const_iterator s = selected_rows.begin (); s != selected_rows.end (); ++s) {
stack_tree->topLevelItem (*s)->setSelected (true);
}
if (n_current >= 0) {
stack_tree->setCurrentItem (stack_tree->topLevelItem (n_current), 0, QItemSelectionModel::Current);
}
}
void
NetTracerTechComponentEditor::move_down_clicked ()
{
// removes focus from the tree view - commits the data
move_down_pb->setFocus ();
commit_current ();
std::set<int> 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 <int>::const_iterator s = selected_rows.begin (); s != selected_rows.end (); ++s) {
stack_tree->topLevelItem (*s)->setSelected (true);
}
if (n_current >= 0) {
stack_tree->setCurrentItem (stack_tree->topLevelItem (n_current), 0, QItemSelectionModel::Current);
}
}
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);
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 (name)));
}
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));
}
}
}

View File

@ -22,8 +22,8 @@
#ifndef HDR_layNetTracerIO
#define HDR_layNetTracerIO
#ifndef HDR_layNetTracerTechComponentEditor
#define HDR_layNetTracerTechComponentEditor
#include "ui_NetTracerTechComponentEditor.h"
@ -48,8 +48,6 @@ namespace db
namespace lay
{
class FileDialog;
class NetTracerTechComponentEditor
: public lay::TechnologyComponentEditor,
public Ui::NetTracerTechComponentEditor
@ -64,18 +62,18 @@ public:
public slots:
void add_clicked ();
void clone_clicked ();
void del_clicked ();
void move_up_clicked ();
void move_down_clicked ();
void symbol_add_clicked ();
void symbol_del_clicked ();
void symbol_move_up_clicked ();
void symbol_move_down_clicked ();
void current_item_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous);
private:
db::NetTracerTechnologyComponent m_data;
void update ();
void commit_current (QTreeWidgetItem *current);
void commit_current ();
};
}

View File

@ -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 \

View File

@ -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"));

View File

@ -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"));

View File

@ -71,8 +71,8 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<normaloff>:/run.png</normaloff>:/run.png</iconset>
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
@ -260,7 +260,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/fit_left_24px.png</normaloff>:/fit_left_24px.png</iconset>
</property>
<property name="iconSize">
@ -280,7 +280,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/fit_front_24px.png</normaloff>:/fit_front_24px.png</iconset>
</property>
<property name="iconSize">
@ -300,7 +300,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/fit_right_24px.png</normaloff>:/fit_right_24px.png</iconset>
</property>
<property name="iconSize">
@ -320,7 +320,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/fit_back_24px.png</normaloff>:/fit_back_24px.png</iconset>
</property>
<property name="iconSize">
@ -340,7 +340,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/fit_top_24px.png</normaloff>:/fit_top_24px.png</iconset>
</property>
<property name="iconSize">
@ -360,7 +360,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../lay/lay/layResources.qrc">
<iconset resource="../../../../icons/icons.qrc">
<normaloff>:/fit_bottom_24px.png</normaloff>:/fit_bottom_24px.png</iconset>
</property>
<property name="iconSize">
@ -628,7 +628,7 @@ See here for more information: &lt;a href=&quot;int:/about/25d_view.xml&quot;&gt
</customwidget>
</customwidgets>
<resources>
<include location="../../../../lay/lay/layResources.qrc"/>
<include location="../../../../icons/icons.qrc"/>
</resources>
<connections>
<connection>

View File

@ -248,42 +248,38 @@ ItemRefUnwrappingIterator category_items_end (const rdb::Category *cat)
return cat->database ()->items_by_category (cat->id ()).second;
}
static void scan_layer1 (rdb::Category *cat, const db::Layout &layout, unsigned int layer)
static void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell, int levels, bool with_properties)
{
rdb::scan_layer (cat, layout, layer);
rdb::scan_layer (cat, layout, layer, from_cell, levels, with_properties);
}
static void scan_layer2 (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell)
static void scan_shapes (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat, bool with_properties)
{
rdb::scan_layer (cat, layout, layer, from_cell);
rdb::scan_layer (cat, iter, flat, with_properties);
}
static void scan_layer3 (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell, int levels)
{
rdb::scan_layer (cat, layout, layer, from_cell, levels);
}
static void scan_shapes (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat)
{
rdb::scan_layer (cat, iter, flat);
}
static void scan_region (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Region &region, bool flat)
static void scan_region (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Region &region, bool flat, bool with_properties)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = region.begin_iter ();
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat);
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties);
}
static void scan_edges (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Edges &edges, bool flat)
static void scan_edges (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Edges &edges, bool flat, bool with_properties)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edges.begin_iter ();
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat);
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties);
}
static void scan_edge_pairs (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::EdgePairs &edge_pairs, bool flat)
static void scan_edge_pairs (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::EdgePairs &edge_pairs, bool flat, bool with_properties)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edge_pairs.begin_iter ();
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat);
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties);
}
static void scan_texts (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Texts &texts, bool flat, bool with_properties)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = texts.begin_iter ();
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties);
}
Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
@ -303,7 +299,7 @@ Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
"\n"
"This method has been introduced in version 0.23."
) +
gsi::method_ext ("scan_shapes", &scan_shapes, gsi::arg ("iter"), gsi::arg ("flat", false),
gsi::method_ext ("scan_shapes", &scan_shapes, gsi::arg ("iter"), gsi::arg ("flat", false), gsi::arg ("with_properties", true),
"@brief Scans the polygon or edge shapes from the shape iterator into the category\n"
"Creates RDB items for each polygon or edge shape read from the iterator and puts them into this category.\n"
"A similar, but lower-level method is \\ReportDatabase#create_items with a \\RecursiveShapeIterator argument.\n"
@ -311,9 +307,11 @@ Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
"if the \\flat argument is false. In this case, the hierarchy the recursive shape iterator traverses is "
"copied into the report database using sample references.\n"
"\n"
"This method has been introduced in version 0.23. The flat mode argument has been added in version 0.26.\n"
"If 'with_properties' is true, user properties will be turned into tagged values as well.\n"
"\n"
"This method has been introduced in version 0.23. The flat mode argument has been added in version 0.26. The 'with_properties' argument has been added in version 0.28.\n"
) +
gsi::method_ext ("scan_collection", &scan_region, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("region"), gsi::arg ("flat", false),
gsi::method_ext ("scan_collection", &scan_region, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("region"), gsi::arg ("flat", false), gsi::arg ("with_properties", true),
"@brief Turns the given region into a hierarchical or flat report database\n"
"The exact behavior depends on the nature of the region. If the region is a hierarchical (original or deep) region "
"and the 'flat' argument is false, this method will produce a hierarchical report database in the given category. "
@ -325,44 +323,38 @@ Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
"\n"
"The transformation argument needs to supply the dbu-to-micron transformation.\n"
"\n"
"This method has been introduced in version 0.26.\n"
"If 'with_properties' is true, user properties will be turned into tagged values as well.\n"
"\n"
"This method has been introduced in version 0.26. The 'with_properties' argument has been added in version 0.28.\n"
) +
gsi::method_ext ("scan_collection", &scan_edges, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edges"), gsi::arg ("flat", false),
gsi::method_ext ("scan_collection", &scan_edges, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edges"), gsi::arg ("flat", false), gsi::arg ("with_properties", true),
"@brief Turns the given edge collection into a hierarchical or flat report database\n"
"This a another flavour of \\scan_collection accepting an edge collection.\n"
"\n"
"This method has been introduced in version 0.26.\n"
"This method has been introduced in version 0.26. The 'with_properties' argument has been added in version 0.28.\n"
) +
gsi::method_ext ("scan_collection", &scan_edge_pairs, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edge_pairs"), gsi::arg ("flat", false),
gsi::method_ext ("scan_collection", &scan_edge_pairs, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edge_pairs"), gsi::arg ("flat", false), gsi::arg ("with_properties", true),
"@brief Turns the given edge pair collection into a hierarchical or flat report database\n"
"This a another flavour of \\scan_collection accepting an edge pair collection.\n"
"\n"
"This method has been introduced in version 0.26.\n"
"This method has been introduced in version 0.26. The 'with_properties' argument has been added in version 0.28.\n"
) +
gsi::method_ext ("scan_layer", &scan_layer1, gsi::arg ("layout"), gsi::arg ("layer"),
"@brief Scans a layer from a layout into this category\n"
"Creates RDB items for each polygon or edge shape read from the each cell in the layout on the given layer and puts them into this category.\n"
"New cells will be generated for every cell encountered in the layout.\n"
"Other settings like database unit, description, top cell etc. are not made in the RDB.\n"
gsi::method_ext ("scan_collection", &scan_texts, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("texts"), gsi::arg ("flat", false), gsi::arg ("with_properties", true),
"@brief Turns the given edge pair collection into a hierarchical or flat report database\n"
"This a another flavour of \\scan_collection accepting a text collection.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"This method has been introduced in version 0.28.\n"
) +
gsi::method_ext ("scan_layer", &scan_layer2, gsi::arg ("layout"), gsi::arg ("layer"), gsi::arg ("cell"),
"@brief Scans a layer from a layout into this category, starting with a given cell\n"
"Creates RDB items for each polygon or edge shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n"
"New cells will be generated when required.\n"
"Other settings like database unit, description, top cell etc. are not made in the RDB.\n"
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method_ext ("scan_layer", &scan_layer3, gsi::arg ("layout"), gsi::arg ("layer"), gsi::arg ("cell"), gsi::arg ("levels"),
gsi::method_ext ("scan_layer", &scan_layer, gsi::arg ("layout"), gsi::arg ("layer"), gsi::arg ("cell", (const db::Cell *) 0, "nil"), gsi::arg ("levels", -1), gsi::arg ("with_properties", true),
"@brief Scans a layer from a layout into this category, starting with a given cell and a depth specification\n"
"Creates RDB items for each polygon or edge shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n"
"New cells will be generated when required.\n"
"\"levels\" is the number of hierarchy levels to take the child cells from. 0 means to use only \"cell\" and don't descend, -1 means \"all levels\".\n"
"Other settings like database unit, description, top cell etc. are not made in the RDB.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"If 'with_properties' is true, user properties will be turned into tagged values as well.\n"
"\n"
"This method has been introduced in version 0.23. The 'with_properties' argument has been added in version 0.28.\n"
) +
gsi::method ("name", &rdb::Category::name,
"@brief Gets the category name\n"
@ -1209,7 +1201,7 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"This convenience method has been added in version 0.25.\n"
) +
gsi::method_ext ("create_items", &rdb::create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"),
gsi::method_ext ("create_items", &rdb::create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"), gsi::arg ("with_properties", true),
"@brief Creates new items from a shape iterator\n"
"This method takes the shapes from the given iterator and produces items from them.\n"
"It accepts various kind of shapes, such as texts, polygons, boxes and paths and "
@ -1217,41 +1209,44 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"A similar method, which is intended for production of polygon or edge error layers and also provides hierarchical database "
"construction is \\RdbCategory#scan_shapes.\n"
"\n"
"This method has been introduced in version 0.25.3.\n"
"This method has been introduced in version 0.25.3. The 'with_properties' argument has been added in version 0.28.\n"
"\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param iter The iterator (a \\RecursiveShapeIterator object) from which to take the items\n"
"@param with_properties If true, user properties will be turned into tagged values as well\n"
) +
gsi::method_ext ("create_item", &rdb::create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shape"),
gsi::method_ext ("create_item", &rdb::create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shape"), gsi::arg ("with_properties", true),
"@brief Creates a new item from a single shape\n"
"This method produces an item from the given shape.\n"
"It accepts various kind of shapes, such as texts, polygons, boxes and paths and "
"converts them to a corresponding item. The transformation argument can be used to "
"supply the transformation that applies the database unit for example.\n"
"\n"
"This method has been introduced in version 0.25.3.\n"
"This method has been introduced in version 0.25.3. The 'with_properties' argument has been added in version 0.28.\n"
"\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param shape The shape to take the geometrical object from\n"
"@param trans The transformation to apply\n"
"@param with_properties If true, user properties will be turned into tagged values as well\n"
) +
gsi::method_ext ("create_items", &rdb::create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shapes"),
gsi::method_ext ("create_items", &rdb::create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shapes"), gsi::arg ("with_properties", true),
"@brief Creates new items from a shape container\n"
"This method takes the shapes from the given container and produces items from them.\n"
"It accepts various kind of shapes, such as texts, polygons, boxes and paths and "
"converts them to corresponding items. The transformation argument can be used to "
"supply the transformation that applies the database unit for example.\n"
"\n"
"This method has been introduced in version 0.25.3.\n"
"This method has been introduced in version 0.25.3. The 'with_properties' argument has been added in version 0.28.\n"
"\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param shapes The shape container from which to take the items\n"
"@param trans The transformation to apply\n"
"@param with_properties If true, user properties will be turned into tagged values as well\n"
) +
gsi::method_ext ("create_items", &rdb::create_items_from_region, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("region"),
gsi::method_ext ("#create_items", &rdb::create_items_from_region, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("region"),
"@brief Creates new polygon items for the given cell/category combination\n"
"For each polygon in the region a single item will be created. The value of the item will be this "
"polygon.\n"
@ -1262,14 +1257,14 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\\RdbCategory#scan_collection is a similar method which also supports construction of "
"hierarchical databases from deep regions.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"This method has been introduced in version 0.23. It has been deprecated in favor of \\RdbCategory#scan_collection in version 0.28.\n"
"\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param region The region (a \\Region object) containing the polygons for which to create items\n"
) +
gsi::method_ext ("create_items", &rdb::create_items_from_edges, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("edges"),
gsi::method_ext ("#create_items", &rdb::create_items_from_edges, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("edges"),
"@brief Creates new edge items for the given cell/category combination\n"
"For each edge a single item will be created. The value of the item will be this "
"edge.\n"
@ -1280,14 +1275,14 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\\RdbCategory#scan_collection is a similar method which also supports construction of "
"hierarchical databases from deep edge collections.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"This method has been introduced in version 0.23. It has been deprecated in favor of \\RdbCategory#scan_collection in version 0.28.\n"
"\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param edges The list of edges (an \\Edges object) for which the items are created\n"
) +
gsi::method_ext ("create_items", &rdb::create_items_from_edge_pairs, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("edge_pairs"),
gsi::method_ext ("#create_items", &rdb::create_items_from_edge_pairs, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("edge_pairs"),
"@brief Creates new edge pair items for the given cell/category combination\n"
"For each edge pair a single item will be created. The value of the item will be this "
"edge pair.\n"
@ -1298,7 +1293,7 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\\RdbCategory#scan_collection is a similar method which also supports construction of "
"hierarchical databases from deep edge pair collections.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"This method has been introduced in version 0.23. It has been deprecated in favor of \\RdbCategory#scan_collection in version 0.28.\n"
"\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"

View File

@ -860,9 +860,11 @@ public:
* @brief Add a value in a generic way
*/
template <class V>
void add_value (const V &v)
ValueBase *add_value (const V &v, id_type tag_id = 0)
{
values ().add (new Value<V> (v));
ValueBase *value = new Value<V> (v);
values ().add (value, tag_id);
return value;
}
/**

View File

@ -34,7 +34,7 @@ namespace rdb
{
void
scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from, int levels)
scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from, int levels, bool with_properties)
{
rdb::Database *rdb = cat->database ();
if (! rdb) {
@ -78,7 +78,7 @@ scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, co
}
create_items_from_shapes (rdb, rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), cell.shapes (layer));
create_items_from_shapes (rdb, rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), cell.shapes (layer), with_properties);
}
@ -92,8 +92,8 @@ class CreateItemsRecursiveReceiver
: public db::RecursiveShapeReceiver
{
public:
CreateItemsRecursiveReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell)
: mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell)
CreateItemsRecursiveReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell, bool with_properties)
: mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell), m_with_properties (with_properties)
{
// just in case the iterator is non-hierarchical
if (cell) {
@ -159,7 +159,7 @@ public:
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
tl_assert (! m_cell_stack.empty ());
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape);
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape, m_with_properties);
}
public:
@ -169,6 +169,7 @@ public:
std::map<db::cell_index_type, const rdb::Cell *> m_id_to_cell;
db::CplxTrans m_trans;
rdb::Cell *mp_rdb_cell;
bool m_with_properties;
const rdb::Cell *cell_for_id (const db::Layout *layout, db::cell_index_type ci)
{
@ -187,8 +188,8 @@ class CreateItemsFlatReceiver
: public db::RecursiveShapeReceiver
{
public:
CreateItemsFlatReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell)
: mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell)
CreateItemsFlatReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell, bool with_properties)
: mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell), m_with_properties (with_properties)
{
// .. nothing yet ..
}
@ -211,7 +212,7 @@ public:
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape);
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape, m_with_properties);
}
public:
@ -219,23 +220,24 @@ public:
rdb::Database *mp_rdb;
db::CplxTrans m_trans;
const rdb::Cell *mp_rdb_cell;
bool m_with_properties;
};
}
void
scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat)
scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat, bool with_properties)
{
if (! iter.top_cell () || ! iter.layout ()) {
return;
}
db::CplxTrans trans (iter.layout ()->dbu ());
scan_layer (cat, 0, trans, iter, flat);
scan_layer (cat, 0, trans, iter, flat, with_properties);
}
void
scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat)
scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat, bool with_properties)
{
if (! cat->database ()) {
return;
@ -243,9 +245,9 @@ scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, con
std::unique_ptr<db::RecursiveShapeReceiver> rec;
if (flat) {
rec.reset (new CreateItemsFlatReceiver (cat, trans, cell));
rec.reset (new CreateItemsFlatReceiver (cat, trans, cell, with_properties));
} else {
rec.reset (new CreateItemsRecursiveReceiver (cat, trans, cell));
rec.reset (new CreateItemsRecursiveReceiver (cat, trans, cell, with_properties));
}
db::RecursiveShapeIterator (iter).push (rec.get ());
@ -253,37 +255,47 @@ scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, con
// ------------------------------------------------------------------------------------------------------------
void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter)
void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter, bool with_properties)
{
tl_assert (iter.layout ());
double dbu = iter.layout ()->dbu ();
for (db::RecursiveShapeIterator i = iter; !i.at_end (); ++i) {
std::unique_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*i, db::CplxTrans (dbu) * i.trans ()));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
create_item_from_shape (db, cell_id, cat_id, db::CplxTrans (dbu) * i.trans (), *i, with_properties);
}
}
void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes)
void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes, bool with_properties)
{
for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); !s.at_end (); ++s) {
std::unique_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*s, trans));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
create_item_from_shape (db, cell_id, cat_id, trans, *s, with_properties);
}
}
void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape)
void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape, bool with_properties)
{
std::unique_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (shape, trans));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
if (! value.get ()) {
return;
}
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
// translate properties
if (with_properties && shape.has_prop_id () && shape.shapes () && shape.shapes ()->cell ()) {
const db::Layout *layout = shape.shapes ()->cell ()->layout ();
if (layout) {
auto ps = layout->properties_repository ().properties (shape.prop_id ());
for (auto i = ps.begin (); i != ps.end (); ++i) {
id_type tag_id = db->tags ().tag (layout->properties_repository ().prop_name (i->first).to_string (), true /*user tag*/).id ();
add_item_value (item, i->second, trans, tag_id);
}
}
}
}
@ -317,50 +329,101 @@ void create_items_from_edge_pairs (rdb::Database *db, rdb::id_type cell_id, rdb:
}
}
void add_item_value (rdb::Item *item, const tl::Variant &v, double dbu)
ValueBase *add_item_value (rdb::Item *item, const tl::Variant &v, const db::CplxTrans &trans, rdb::id_type tag_id)
{
if (dbu > 0 && v.is_user<db::Box> ()) {
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Box> ());
} else if (dbu > 0 && v.is_user<db::Point> ()) {
db::DPoint p = db::CplxTrans (dbu) * v.to_user<db::Point> ();
item->add_value (db::DEdge (p, p));
} else if (dbu > 0 && v.is_user<db::Polygon> ()) {
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Polygon> ());
} else if (dbu > 0 && v.is_user<db::SimplePolygon> ()) {
if (v.is_user<db::Box> ()) {
return item->add_value (trans * v.to_user<db::Box> (), tag_id);
} else if (v.is_user<db::Point> ()) {
db::DPoint p = trans * v.to_user<db::Point> ();
return item->add_value (db::DEdge (p, p), tag_id);
} else if (v.is_user<db::Polygon> ()) {
return item->add_value (trans * v.to_user<db::Polygon> (), tag_id);
} else if (v.is_user<db::SimplePolygon> ()) {
db::DPolygon p;
db::DSimplePolygon sp = db::CplxTrans (dbu) * v.to_user<db::SimplePolygon> ();
db::DSimplePolygon sp = trans * v.to_user<db::SimplePolygon> ();
p.assign_hull (sp.begin_hull (), sp.end_hull ());
item->add_value (p);
} else if (dbu > 0 && v.is_user<db::Edge> ()) {
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Edge> ());
} else if (dbu > 0 && v.is_user<db::EdgePair> ()) {
item->add_value (db::CplxTrans (dbu) * v.to_user<db::EdgePair> ());
} else if (dbu > 0 && v.is_user<db::Path> ()) {
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Path> ());
} else if (dbu > 0 && v.is_user<db::Text> ()) {
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Text> ());
return item->add_value (p, tag_id);
} else if (v.is_user<db::Edge> ()) {
return item->add_value (trans * v.to_user<db::Edge> (), tag_id);
} else if (v.is_user<db::EdgePair> ()) {
return item->add_value (trans * v.to_user<db::EdgePair> (), tag_id);
} else if (v.is_user<db::Path> ()) {
return item->add_value (trans * v.to_user<db::Path> (), tag_id);
} else if (v.is_user<db::Text> ()) {
return item->add_value (trans * v.to_user<db::Text> (), tag_id);
} else if (v.is_user<db::DBox> ()) {
item->add_value (v.to_user<db::DBox> ());
return item->add_value (v.to_user<db::DBox> (), tag_id);
} else if (v.is_user<db::DPoint> ()) {
db::DPoint p = v.to_user<db::DPoint> ();
item->add_value (db::DEdge (p, p));
return item->add_value (db::DEdge (p, p), tag_id);
} else if (v.is_user<db::DPolygon> ()) {
item->add_value (v.to_user<db::DPolygon> ());
return item->add_value (v.to_user<db::DPolygon> (), tag_id);
} else if (v.is_user<db::DSimplePolygon> ()) {
db::DPolygon p;
db::DSimplePolygon sp = v.to_user<db::DSimplePolygon> ();
p.assign_hull (sp.begin_hull (), sp.end_hull ());
item->add_value (p);
return item->add_value (p, tag_id);
} else if (v.is_user<db::DEdge> ()) {
item->add_value (v.to_user<db::DEdge> ());
return item->add_value (v.to_user<db::DEdge> (), tag_id);
} else if (v.is_user<db::DEdgePair> ()) {
item->add_value (v.to_user<db::DEdgePair> ());
return item->add_value (v.to_user<db::DEdgePair> (), tag_id);
} else if (v.is_user<db::DPath> ()) {
item->add_value (v.to_user<db::DPath> ());
return item->add_value (v.to_user<db::DPath> (), tag_id);
} else if (v.is_user<db::DText> ()) {
item->add_value (v.to_user<db::DText> ());
return item->add_value (v.to_user<db::DText> (), tag_id);
} else if (v.is_double () || v.is_long () || v.is_ulong () || v.is_longlong () || v.is_ulonglong ()) {
return item->add_value (v.to_double (), tag_id);
} else {
item->add_value (std::string (v.to_string ()));
return item->add_value (std::string (v.to_string ()), tag_id);
}
}
ValueBase *add_item_value(rdb::Item *item, const tl::Variant &v, double dbu, rdb::id_type tag_id)
{
if (dbu > 0 && v.is_user<db::Box> ()) {
return item->add_value (db::CplxTrans (dbu) * v.to_user<db::Box> (), tag_id);
} else if (dbu > 0 && v.is_user<db::Point> ()) {
db::DPoint p = db::CplxTrans (dbu) * v.to_user<db::Point> ();
return item->add_value (db::DEdge (p, p), tag_id);
} else if (dbu > 0 && v.is_user<db::Polygon> ()) {
return item->add_value (db::CplxTrans (dbu) * v.to_user<db::Polygon> (), tag_id);
} else if (dbu > 0 && v.is_user<db::SimplePolygon> ()) {
db::DPolygon p;
db::DSimplePolygon sp = db::CplxTrans (dbu) * v.to_user<db::SimplePolygon> ();
p.assign_hull (sp.begin_hull (), sp.end_hull ());
return item->add_value (p, tag_id);
} else if (dbu > 0 && v.is_user<db::Edge> ()) {
return item->add_value (db::CplxTrans (dbu) * v.to_user<db::Edge> (), tag_id);
} else if (dbu > 0 && v.is_user<db::EdgePair> ()) {
return item->add_value (db::CplxTrans (dbu) * v.to_user<db::EdgePair> (), tag_id);
} else if (dbu > 0 && v.is_user<db::Path> ()) {
return item->add_value (db::CplxTrans (dbu) * v.to_user<db::Path> (), tag_id);
} else if (dbu > 0 && v.is_user<db::Text> ()) {
return item->add_value (db::CplxTrans (dbu) * v.to_user<db::Text> (), tag_id);
} else if (v.is_user<db::DBox> ()) {
return item->add_value (v.to_user<db::DBox> (), tag_id);
} else if (v.is_user<db::DPoint> ()) {
db::DPoint p = v.to_user<db::DPoint> ();
return item->add_value (db::DEdge (p, p), tag_id);
} else if (v.is_user<db::DPolygon> ()) {
return item->add_value (v.to_user<db::DPolygon> (), tag_id);
} else if (v.is_user<db::DSimplePolygon> ()) {
db::DPolygon p;
db::DSimplePolygon sp = v.to_user<db::DSimplePolygon> ();
p.assign_hull (sp.begin_hull (), sp.end_hull ());
return item->add_value (p, tag_id);
} else if (v.is_user<db::DEdge> ()) {
return item->add_value (v.to_user<db::DEdge> (), tag_id);
} else if (v.is_user<db::DEdgePair> ()) {
return item->add_value (v.to_user<db::DEdgePair> (), tag_id);
} else if (v.is_user<db::DPath> ()) {
return item->add_value (v.to_user<db::DPath> (), tag_id);
} else if (v.is_user<db::DText> ()) {
return item->add_value (v.to_user<db::DText> (), tag_id);
} else if (v.is_double () || v.is_long () || v.is_ulong () || v.is_longlong () || v.is_ulonglong ()) {
return item->add_value (v.to_double (), tag_id);
} else {
return item->add_value (std::string (v.to_string ()), tag_id);
}
}

View File

@ -51,45 +51,63 @@ namespace rdb
*
* If "from" is 0, all cells will be scanned. Levels are the number of hierarchy levels scanned if
* "from" is given. -1 means "all levels".
*
* If "with_properties" is true, user properties are translated into values with tags corresponding
* to the property names.
*/
RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell = 0, int levels = -1);
RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell = 0, int levels = -1, bool with_properties = true);
/**
* @brief Scans a recursive shape iterator into a RDB category
*
* If "with_properties" is true, user properties are translated into values with tags corresponding
* to the property names.
*/
RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat = false);
RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat = false, bool with_properties = true);
/**
* @brief Scans a recursive shape iterator into a RDB category
*
* This version allows supplying a cell and a transformation. With this information, the function can also handle
* pseudo-iterators which don't deliver the information from a layout from from a plain shape collection.
*
* If "with_properties" is true, user properties are translated into values with tags corresponding
* to the property names.
*/
RDB_PUBLIC void scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat = false);
RDB_PUBLIC void scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat = false, bool with_properties = true);
/**
* @brief Creates RDB items from a recursive shape iterator
*
* This function will produce items from the flattened shape iterator. The items will be stored under
* the given cell.
*
* If "with_properties" is true, user properties are translated into values with tags corresponding
* to the property names.
*/
RDB_PUBLIC void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter);
RDB_PUBLIC void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter, bool with_properties = true);
/**
* @brief Creates RDB items from a shape collection
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*
* If "with_properties" is true, user properties are translated into values with tags corresponding
* to the property names.
*/
RDB_PUBLIC void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes);
RDB_PUBLIC void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes, bool with_properties = true);
/**
* @brief Creates RDB items from a single shape
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*
* If "with_properties" is true, user properties are translated into values with tags corresponding
* to the property names.
*/
RDB_PUBLIC void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape);
RDB_PUBLIC void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape, bool with_properties = true);
/**
* @brief Creates RDB items from a region
@ -146,7 +164,14 @@ RDB_PUBLIC_TEMPLATE void create_items_from_sequence (rdb::Database *db, rdb::id_
*
* Unknown types are converted to strings.
*/
RDB_PUBLIC void add_item_value (rdb::Item *item, const tl::Variant &v, double dbu = 0.0);
RDB_PUBLIC ValueBase *add_item_value (rdb::Item *item, const tl::Variant &v, double dbu = 0.0, rdb::id_type tag_id = 0);
/**
* @brief Creates a value from a tl::Variant
*
* This version takes a db::CplxTrans for converting integer-unit geometry objects to micron-unit ones.
*/
RDB_PUBLIC ValueBase *add_item_value(rdb::Item *item, const tl::Variant &v, const db::CplxTrans &trans, rdb::id_type tag_id = 0);
}

View File

@ -29,6 +29,7 @@
#endif
#include <memory>
#include <cmath>
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

View File

@ -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
*

View File

@ -256,7 +256,7 @@ std::string to_lower_case (const std::string &s)
std::string to_local (const std::string &s)
{
std::unique_ptr<char> buffer (new char [MB_CUR_MAX]); // MB_CUR_MAX isn't a constant
std::unique_ptr<char []> buffer (new char [MB_CUR_MAX]); // MB_CUR_MAX isn't a constant
std::string ls;
std::wstring ws = to_wstring (s);

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More