mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' of github.com:KLayout/klayout
This commit is contained in:
commit
fdbf26f184
|
|
@ -1060,7 +1060,15 @@ EdgeProcessor::insert (const db::Edge &e, EdgeProcessor::property_type p)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
EdgeProcessor::insert (const db::SimplePolygon &q, EdgeProcessor::property_type p)
|
||||
{
|
||||
for (db::SimplePolygon::polygon_edge_iterator e = q.begin_edge (); ! e.at_end (); ++e) {
|
||||
insert (*e, p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EdgeProcessor::insert (const db::Polygon &q, EdgeProcessor::property_type p)
|
||||
{
|
||||
for (db::Polygon::polygon_edge_iterator e = q.begin_edge (); ! e.at_end (); ++e) {
|
||||
|
|
|
|||
|
|
@ -633,6 +633,11 @@ public:
|
|||
*/
|
||||
void insert (const db::Polygon &q, property_type p = 0);
|
||||
|
||||
/**
|
||||
* @brief Insert a simple polygon
|
||||
*/
|
||||
void insert (const db::SimplePolygon &q, property_type p = 0);
|
||||
|
||||
/**
|
||||
* @brief Insert a polygon reference
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4145,6 +4145,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
|
|||
++nscm;
|
||||
if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) {
|
||||
found = true;
|
||||
} else {
|
||||
++scm;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ public:
|
|||
void push_front (const db::Point &p) { m_contour.push_front (p); }
|
||||
void pop_back () { m_contour.pop_back (); }
|
||||
void pop_front () { m_contour.pop_front (); }
|
||||
iterator erase (iterator i) { return m_contour.erase (i); }
|
||||
iterator insert (iterator i, const db::Point &p) { return m_contour.insert (i, p); }
|
||||
bool empty () const { return m_contour.empty (); }
|
||||
size_t size () const { return m_contour.size (); }
|
||||
|
||||
|
|
@ -136,9 +138,12 @@ public:
|
|||
}
|
||||
|
||||
template <class I>
|
||||
void insert (iterator at, I from, I to)
|
||||
iterator insert (iterator at, I from, I to)
|
||||
{
|
||||
// NOTE: in some STL m_contour.insert already returns the new iterator
|
||||
size_t index_at = at - m_contour.begin ();
|
||||
m_contour.insert (at, from, to);
|
||||
return m_contour.begin () + index_at;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -725,27 +730,56 @@ PolygonGenerator::join_contours (db::Coord x)
|
|||
PGPolyContour &cprev = (*mp_contours) [iprev];
|
||||
|
||||
tl_assert (cprev.size () >= 2);
|
||||
tl_assert (c1.size () >= 2);
|
||||
|
||||
PGPolyContour::iterator ins = cprev.end ();
|
||||
db::Coord xprev = 0;
|
||||
db::Edge eprev;
|
||||
|
||||
#if 1
|
||||
// shallow analysis: insert the cutline at the end of the sequence - this may
|
||||
// cut lines collinear with contour edges
|
||||
|
||||
eprev = db::Edge (ins[-2], ins[-1]);
|
||||
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (ins[-2], ins[-1]), m_y));
|
||||
#else
|
||||
// deep analysis: determine insertion point: pick the one where the cutline is shortest
|
||||
|
||||
for (PGPolyContour::iterator i = ins; i > cprev.begin () + 1; --i) {
|
||||
|
||||
db::Edge ecut (i[-2], i[-1]);
|
||||
db::Coord xcut = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (i[-2], i[-1]), m_y));
|
||||
|
||||
if (ins == i || (i[-1].y () >= m_y && i[-2].y () < m_y && xcut < c1.back ().x () && xcut > xprev)) {
|
||||
xprev = xcut;
|
||||
eprev = ecut;
|
||||
ins = i;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// compute intersection point with next edge
|
||||
db::Edge eprev (cprev.end ()[-2], cprev.back ());
|
||||
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
|
||||
db::Point pprev (xprev, m_y);
|
||||
|
||||
// remove collinear edges along the cut line
|
||||
cprev.back () = pprev;
|
||||
while (cprev.size () > 1 && cprev.end ()[-2].y () == m_y && cprev.end ()[-1].y () == m_y) {
|
||||
cprev.pop_back ();
|
||||
ins[-1] = pprev;
|
||||
while (ins - cprev.begin () > 1 && ins[-2].y () == m_y && ins[-1].y () == m_y) {
|
||||
ins = cprev.erase (ins - 1);
|
||||
}
|
||||
|
||||
tl_assert (c1.size () >= 2);
|
||||
if ((c1.begin () + 1)->y () == m_y) {
|
||||
cprev.insert (cprev.end (), c1.begin () + 1, c1.end ());
|
||||
ins = cprev.insert (ins, c1.begin () + 1, c1.end ());
|
||||
ins += c1.size () - 1;
|
||||
} else {
|
||||
cprev.insert (cprev.end (), c1.begin (), c1.end ());
|
||||
ins = cprev.insert (ins, c1.begin (), c1.end ());
|
||||
ins += c1.size ();
|
||||
}
|
||||
cprev.push_back (pprev);
|
||||
|
||||
ins = cprev.insert (ins, pprev);
|
||||
++ins;
|
||||
if (eprev.p2 () != pprev) {
|
||||
cprev.push_back (eprev.p2 ());
|
||||
cprev.insert (ins, eprev.p2 ());
|
||||
}
|
||||
|
||||
mp_contours->free (i1);
|
||||
|
|
|
|||
|
|
@ -185,10 +185,19 @@ public:
|
|||
return db::vprod_sign (edge (), other.edge ()) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator== (const loose_end_struct<CuttingEdgeType> &other) const
|
||||
{
|
||||
if (! db::coord_traits<double>::equal (proj (), other.proj ())) {
|
||||
return false;
|
||||
} else {
|
||||
return db::vprod_sign (edge (), other.edge ()) == 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class PolygonType, class Edge>
|
||||
static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, CutPolygonReceiverBase *right_of_line)
|
||||
static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, cut_polygon_receiver_base<PolygonType> *right_of_line)
|
||||
{
|
||||
typedef typename PolygonType::point_type point_type;
|
||||
typedef typename PolygonType::coord_type coord_type;
|
||||
|
|
@ -259,6 +268,7 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
// tie together last and first partial segments.
|
||||
if (cutting_segments[nfirst].segment < 0) {
|
||||
cutting_segments[nfirst].enter = cutting_segments.back ().enter;
|
||||
cutting_segments[nfirst].segment = cutting_segments.back ().segment;
|
||||
cutting_segments.pop_back ();
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +278,7 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
|
||||
if (nc == 0) {
|
||||
// the hull is fully on the right side -> just output the input polygon and that's it.
|
||||
right_of_line->put (&input);
|
||||
right_of_line->put (input);
|
||||
return true;
|
||||
} else {
|
||||
// remember hole contours for later assignment
|
||||
|
|
@ -279,7 +289,7 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
} else {
|
||||
PolygonType poly;
|
||||
poly.assign_hull (contour.begin (), contour.end ());
|
||||
right_of_line->put (&poly);
|
||||
right_of_line->put (poly);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,23 +307,28 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
|
||||
std::stable_sort (loose_ends.begin (), loose_ends.end ());
|
||||
|
||||
// bring the points in a strict enter/leave order if possible
|
||||
// we allow single pairs of collinear entry/leave edges (cut lines) and bring them in the right order
|
||||
|
||||
bool enter = false;
|
||||
for (typename std::vector<loose_end_struct<cut_polygon_edge_type> >::iterator i = loose_ends.begin (); i != loose_ends.end (); ++i) {
|
||||
if (i + 1 != loose_ends.end () && i[1] == i[0]) {
|
||||
if (i + 2 != loose_ends.end () && i[2] == i[0]) {
|
||||
// triple collinear
|
||||
return false;
|
||||
}
|
||||
if (i[0].enter != enter && i[1].enter == enter) {
|
||||
std::swap (i[0], i[1]);
|
||||
}
|
||||
}
|
||||
enter = !enter;
|
||||
}
|
||||
|
||||
// the points now have to be in strict enter/leave order - otherwise fallback to merge
|
||||
|
||||
enter = false;
|
||||
for (typename std::vector<loose_end_struct<cut_polygon_edge_type> >::iterator i = loose_ends.begin (); i != loose_ends.end (); ++i) {
|
||||
if (i->enter != enter) {
|
||||
typename std::vector<loose_end_struct<cut_polygon_edge_type> >::iterator j = i + 1;
|
||||
typename std::vector<loose_end_struct<cut_polygon_edge_type> >::iterator jj = loose_ends.end ();
|
||||
for ( ; j != loose_ends.end () && !(*j < *i) && !(*i < *j); ++j) {
|
||||
if (j->enter == enter) {
|
||||
jj = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jj == loose_ends.end ()) {
|
||||
return false; // cannot cut (self-overlapping, self-intersecting)
|
||||
}
|
||||
std::swap (*jj, *i);
|
||||
return false;
|
||||
}
|
||||
enter = !enter;
|
||||
}
|
||||
|
|
@ -410,7 +425,7 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
// it might happen in some cases, that cut pieces may vanish (i.e. all points on a line). Thus we check, if that
|
||||
// is the case and do not produce a polygon then.
|
||||
if (poly.vertices () > 0) {
|
||||
right_of_line->put (&poly);
|
||||
right_of_line->put (poly);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -441,7 +456,7 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
}
|
||||
}
|
||||
|
||||
right_of_line->put (&*hull);
|
||||
right_of_line->put (*hull);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -452,7 +467,7 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, C
|
|||
// we assign to a PolygonType, this check is not possible.
|
||||
for (typename std::vector<PolygonType>::iterator hole = hole_polygons.begin (); hole != hole_polygons.end (); ++hole) {
|
||||
if (hole->vertices () > 0) {
|
||||
right_of_line->put (&*hole);
|
||||
right_of_line->put (*hole);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -474,23 +489,22 @@ namespace
|
|||
/**
|
||||
* @brief A polygon sink for the edge processor that feeds the polygon into the cut algorithm
|
||||
*/
|
||||
template <class Sink, class PolygonType, class Edge>
|
||||
struct cut_polygon_sink
|
||||
template <class Sink, class PolygonType>
|
||||
struct cut_polygon_bool_sink
|
||||
: public Sink
|
||||
{
|
||||
cut_polygon_sink (const Edge &_line, CutPolygonReceiverBase *_right_of_line)
|
||||
: line (_line), right_of_line (_right_of_line)
|
||||
cut_polygon_bool_sink (cut_polygon_receiver_base<PolygonType> *_right_of_line)
|
||||
: right_of_line (_right_of_line)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual void put (const PolygonType &poly)
|
||||
{
|
||||
tl_assert (_cut_polygon_internal (poly, line, right_of_line));
|
||||
right_of_line->put (poly);
|
||||
}
|
||||
|
||||
Edge line;
|
||||
CutPolygonReceiverBase *right_of_line;
|
||||
cut_polygon_receiver_base<PolygonType> *right_of_line;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -500,20 +514,31 @@ namespace
|
|||
* fallback.
|
||||
*/
|
||||
template <class PolygonType, class Edge>
|
||||
void cut_polygon_internal_int (const PolygonType &input, const Edge &line, CutPolygonReceiverBase *right_of_line)
|
||||
void cut_polygon_internal_int (const PolygonType &input, const Edge &line, cut_polygon_receiver_base<PolygonType> *right_of_line)
|
||||
{
|
||||
bool ok = _cut_polygon_internal (input, line, right_of_line);
|
||||
if (! ok) {
|
||||
|
||||
// If the cut operation fails on the plain input, merge the input polygon and try again
|
||||
// If the fast cut operation fails, use boolean AND to perform the cut operation
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.insert_sequence (input.begin_edge ());
|
||||
db::SimpleMerge op;
|
||||
PolygonType clip (input.box ());
|
||||
std::vector<PolygonType> mask;
|
||||
cut_polygon (clip, line, std::back_inserter (mask));
|
||||
|
||||
cut_polygon_sink<typename get_sink_type<PolygonType>::result, PolygonType, Edge> sink (line, right_of_line);
|
||||
db::PolygonGenerator pg (sink);
|
||||
ep.process (pg, op);
|
||||
if (! mask.empty ()) {
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.insert_sequence (input.begin_edge (), 0);
|
||||
ep.insert_sequence (mask.begin (), mask.end (), 1);
|
||||
|
||||
db::BooleanOp op (BooleanOp::And);
|
||||
|
||||
cut_polygon_bool_sink<typename get_sink_type<PolygonType>::result, PolygonType> sink (right_of_line);
|
||||
db::PolygonGenerator pg (sink);
|
||||
ep.process (pg, op);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -524,14 +549,14 @@ namespace
|
|||
*/
|
||||
template <class PolygonType, class IPolygonType>
|
||||
class cut_polygon_receiver_double_impl
|
||||
: public CutPolygonReceiverBase
|
||||
: public cut_polygon_receiver_base<IPolygonType>
|
||||
{
|
||||
public:
|
||||
cut_polygon_receiver_double_impl ()
|
||||
: mp_next (0)
|
||||
{ }
|
||||
|
||||
void set_next (CutPolygonReceiverBase *next)
|
||||
void set_next (cut_polygon_receiver_base<PolygonType> *next)
|
||||
{
|
||||
mp_next = next;
|
||||
}
|
||||
|
|
@ -541,14 +566,14 @@ namespace
|
|||
m_tr = tr;
|
||||
}
|
||||
|
||||
virtual void put (const void *p)
|
||||
virtual void put (const IPolygonType &p)
|
||||
{
|
||||
PolygonType pp = ((const IPolygonType *) p)->transformed (m_tr, false);
|
||||
mp_next->put ((void *) &pp);
|
||||
PolygonType pp = p.transformed (m_tr, false);
|
||||
mp_next->put (pp);
|
||||
}
|
||||
|
||||
private:
|
||||
CutPolygonReceiverBase *mp_next;
|
||||
cut_polygon_receiver_base<PolygonType> *mp_next;
|
||||
db::CplxTrans m_tr;
|
||||
};
|
||||
|
||||
|
|
@ -565,7 +590,7 @@ namespace
|
|||
* transform the polygon to int. On output, the polygon is transformed back to double.
|
||||
*/
|
||||
template <class PolygonType, class Edge>
|
||||
void cut_polygon_internal_double (const PolygonType &input, const Edge &line, CutPolygonReceiverBase *right_of_line)
|
||||
void cut_polygon_internal_double (const PolygonType &input, const Edge &line, cut_polygon_receiver_base<PolygonType> *right_of_line)
|
||||
{
|
||||
db::DBox bbox = input.box ();
|
||||
bbox += db::DBox (0, 0, 0, 0);
|
||||
|
|
@ -585,22 +610,22 @@ namespace
|
|||
|
||||
}
|
||||
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::Polygon &polygon, const db::Polygon::edge_type &line, CutPolygonReceiverBase *right_of_line)
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::Polygon &polygon, const db::Polygon::edge_type &line, cut_polygon_receiver_base<db::Polygon> *right_of_line)
|
||||
{
|
||||
cut_polygon_internal_int (polygon, line, right_of_line);
|
||||
}
|
||||
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::SimplePolygon &polygon, const db::SimplePolygon::edge_type &line, CutPolygonReceiverBase *right_of_line)
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::SimplePolygon &polygon, const db::SimplePolygon::edge_type &line, cut_polygon_receiver_base<db::SimplePolygon> *right_of_line)
|
||||
{
|
||||
cut_polygon_internal_int (polygon, line, right_of_line);
|
||||
}
|
||||
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::DPolygon &polygon, const db::DPolygon::edge_type &line, CutPolygonReceiverBase *right_of_line)
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::DPolygon &polygon, const db::DPolygon::edge_type &line, cut_polygon_receiver_base<db::DPolygon> *right_of_line)
|
||||
{
|
||||
cut_polygon_internal_double (polygon, line, right_of_line);
|
||||
}
|
||||
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::DSimplePolygon &polygon, const db::DSimplePolygon::edge_type &line, CutPolygonReceiverBase *right_of_line)
|
||||
template<> DB_PUBLIC void cut_polygon_internal (const db::DSimplePolygon &polygon, const db::DSimplePolygon::edge_type &line, cut_polygon_receiver_base<db::DSimplePolygon> *right_of_line)
|
||||
{
|
||||
cut_polygon_internal_double (polygon, line, right_of_line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,25 +74,26 @@ private:
|
|||
|
||||
// Some helper classes and functions for implementing cut_polygon
|
||||
|
||||
class DB_PUBLIC CutPolygonReceiverBase
|
||||
template <class Polygon>
|
||||
class DB_PUBLIC cut_polygon_receiver_base
|
||||
{
|
||||
public:
|
||||
virtual ~CutPolygonReceiverBase () { }
|
||||
virtual void put (const void *) = 0;
|
||||
virtual ~cut_polygon_receiver_base () { }
|
||||
virtual void put (const Polygon &) = 0;
|
||||
};
|
||||
|
||||
template <class OutputIter, class Polygon>
|
||||
class cut_polygon_receiver
|
||||
: public CutPolygonReceiverBase
|
||||
: public cut_polygon_receiver_base<Polygon>
|
||||
{
|
||||
public:
|
||||
cut_polygon_receiver (const OutputIter &iter)
|
||||
: m_iter (iter)
|
||||
{ }
|
||||
|
||||
virtual void put (const void *polygon)
|
||||
virtual void put (const Polygon &polygon)
|
||||
{
|
||||
*m_iter++ = *((const Polygon *) polygon);
|
||||
*m_iter++ = polygon;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -100,7 +101,7 @@ private:
|
|||
};
|
||||
|
||||
template <class PolygonType, class Edge>
|
||||
void DB_PUBLIC cut_polygon_internal (const PolygonType &input, const Edge &line, CutPolygonReceiverBase *right_of_line);
|
||||
void DB_PUBLIC cut_polygon_internal (const PolygonType &input, const Edge &line, cut_polygon_receiver_base<PolygonType> *right_of_line);
|
||||
|
||||
/**
|
||||
* @brief Polygon cut function
|
||||
|
|
|
|||
|
|
@ -2570,6 +2570,67 @@ TEST(102)
|
|||
EXPECT_EQ (out[0].to_string (), "(0,0;0,200;100,200;100,100;200,100;200,200;500,200;500,100;600,100;600,200;0,200;0,1000;1000,1000;1000,0)");
|
||||
}
|
||||
|
||||
TEST(103)
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
{
|
||||
db::Point pts[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (0, 500),
|
||||
db::Point (1500, 500),
|
||||
db::Point (1500, 0),
|
||||
db::Point (1000, 0),
|
||||
db::Point (1000, 400),
|
||||
db::Point (500, 400),
|
||||
db::Point (500, 0)
|
||||
};
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
ep.insert (p, 0);
|
||||
}
|
||||
|
||||
{
|
||||
db::Point pts[] = {
|
||||
db::Point (100, 100),
|
||||
db::Point (100, 400),
|
||||
db::Point (400, 400),
|
||||
db::Point (400, 100)
|
||||
};
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
ep.insert (p, 1);
|
||||
}
|
||||
|
||||
{
|
||||
db::Point pts[] = {
|
||||
db::Point (1100, 100),
|
||||
db::Point (1100, 400),
|
||||
db::Point (1400, 400),
|
||||
db::Point (1400, 100)
|
||||
};
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
ep.insert (p, 1);
|
||||
}
|
||||
|
||||
std::vector<db::Polygon> out;
|
||||
db::PolygonContainer pc (out);
|
||||
db::PolygonGenerator pg (pc, true, true);
|
||||
db::BooleanOp op (db::BooleanOp::ANotB);
|
||||
|
||||
ep.process (pg, op);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (1));
|
||||
#if 1
|
||||
// fast hole treatment
|
||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;1100,400;1100,100;1400,100;1400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;500,400;500,0)");
|
||||
#else
|
||||
// elaborate hole treatment
|
||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;1100,400;1100,100;1400,100;1400,400;500,400;500,0)");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Bug 134
|
||||
TEST(134)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -559,15 +559,18 @@ TEST(9c)
|
|||
std::vector<db::Polygon> right_of;
|
||||
|
||||
db::cut_polygon (in, db::Edge (db::Point (15835, 0), db::Point (15835, 1)), std::back_inserter (right_of));
|
||||
EXPECT_EQ (right_of.size (), size_t (3));
|
||||
EXPECT_EQ (right_of[0].to_string (), "(17335,8265;16335,9265;15835,9265;15835,9765;17335,9765)");
|
||||
EXPECT_EQ (right_of[1].to_string (), "(15835,9765;16002,9932;15835,10015;17335,10015;17335,9765)");
|
||||
EXPECT_EQ (right_of[2].to_string (), "(15835,10015;15835,10265;17335,10265;17335,10015)");
|
||||
EXPECT_EQ (right_of.size (), size_t (1));
|
||||
EXPECT_EQ (right_of[0].to_string (), "(17335,8265;16335,9265;15835,9265;15835,9765;16002,9932;15835,10015;15835,10265;17335,10265)");
|
||||
|
||||
right_of.clear ();
|
||||
db::cut_polygon (in, db::Edge (db::Point (15835, 1), db::Point (15835, 0)), std::back_inserter (right_of));
|
||||
EXPECT_EQ (right_of.size (), size_t (1));
|
||||
EXPECT_EQ (right_of[0].to_string (), "(14335,8265;14335,10265;15335,10265;15335,9765;15668,9932;15335,10265;15835,10265;15835,10015;15668,9932;15835,9765;15335,9765;14335,9265;15335,9265;15335,9765;15835,9765;15835,9265;15335,9265)");
|
||||
EXPECT_EQ (right_of.size (), size_t (4));
|
||||
if (right_of.size () >= 4) {
|
||||
EXPECT_EQ (right_of[0].to_string (), "(14335,8265;14335,9265;15335,9265)");
|
||||
EXPECT_EQ (right_of[1].to_string (), "(15335,9265;15335,9765;15668,9932;15835,9765;15835,9265)");
|
||||
EXPECT_EQ (right_of[2].to_string (), "(14335,9265;14335,10265;15335,10265;15335,9765)");
|
||||
EXPECT_EQ (right_of[3].to_string (), "(15668,9932;15335,10265;15835,10265;15835,10015)");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(9d)
|
||||
|
|
@ -2373,6 +2376,23 @@ TEST(404)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(405)
|
||||
{
|
||||
db::Polygon poly;
|
||||
std::string s ("(0,0;0,1126;30,1126;30,30;3044,30;3044,1126;5782,1126;5782,30;8796,30;8796,1126;0,1126;0,1141;3009,1141;3009,1156;3194,1156;3194,1141;8826,1141;8826,0;5742,0;5742,1126;3084,1126;3084,0)");
|
||||
tl::Extractor ex (s.c_str ());
|
||||
ex.read (poly);
|
||||
|
||||
std::vector<db::Polygon> sp;
|
||||
db::split_polygon (poly, sp);
|
||||
|
||||
EXPECT_EQ (sp.size (), size_t (2));
|
||||
if (sp.size () >= 2) {
|
||||
EXPECT_EQ (sp[0].to_string (), "(5742,0;5742,1126;5782,1126;5782,30;8796,30;8796,1126;3194,1126;3194,1141;8826,1141;8826,0)");
|
||||
EXPECT_EQ (sp[1].to_string (), "(0,0;0,1126;30,1126;30,30;3044,30;3044,1126;0,1126;0,1141;3009,1141;3009,1156;3194,1156;3194,1126;3084,1126;3084,0)");
|
||||
}
|
||||
}
|
||||
|
||||
static db::Polygon str2poly (const std::string &s)
|
||||
{
|
||||
db::Polygon poly;
|
||||
|
|
@ -2382,7 +2402,7 @@ static db::Polygon str2poly (const std::string &s)
|
|||
}
|
||||
|
||||
// self-overlapping, non-orientable check
|
||||
TEST(405)
|
||||
TEST(500)
|
||||
{
|
||||
std::string ps;
|
||||
std::vector<db::Polygon> parts;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ struct Callback
|
|||
|
||||
#define _TMPLARGPART
|
||||
#define _FUNCARGLIST
|
||||
#define _COMMA
|
||||
#define _CALLARGLIST
|
||||
#define _CALLARGS
|
||||
#define _SETVALUE
|
||||
|
|
@ -87,6 +88,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGLIST
|
||||
#undef _CALLARGS
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -94,15 +96,17 @@ struct Callback
|
|||
|
||||
// 1 argument
|
||||
|
||||
#define _TMPLARGPART , class A1
|
||||
#define _TMPLARGPART class A1
|
||||
#define _FUNCARGLIST A1
|
||||
#define _CALLARGLIST , A1 a1
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1
|
||||
#define _CALLARGS a1
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
|
||||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -110,9 +114,10 @@ struct Callback
|
|||
|
||||
// 2 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2
|
||||
#define _TMPLARGPART class A1, class A2
|
||||
#define _FUNCARGLIST A1, A2
|
||||
#define _CALLARGLIST , A1 a1, A2 a2
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2
|
||||
#define _CALLARGS a1, a2
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -120,6 +125,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -127,9 +133,10 @@ struct Callback
|
|||
|
||||
// 3 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2, class A3
|
||||
#define _TMPLARGPART class A1, class A2, class A3
|
||||
#define _FUNCARGLIST A1, A2, A3
|
||||
#define _CALLARGLIST , A1 a1, A2 a2, A3 a3
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2, A3 a3
|
||||
#define _CALLARGS a1, a2, a3
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -138,6 +145,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -145,9 +153,10 @@ struct Callback
|
|||
|
||||
// 4 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2, class A3, class A4
|
||||
#define _TMPLARGPART class A1, class A2, class A3, class A4
|
||||
#define _FUNCARGLIST A1, A2, A3, A4
|
||||
#define _CALLARGLIST , A1 a1, A2 a2, A3 a3, A4 a4
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2, A3 a3, A4 a4
|
||||
#define _CALLARGS a1, a2, a3, a4
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -157,6 +166,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -164,9 +174,10 @@ struct Callback
|
|||
|
||||
// 5 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2, class A3, class A4, class A5
|
||||
#define _TMPLARGPART class A1, class A2, class A3, class A4, class A5
|
||||
#define _FUNCARGLIST A1, A2, A3, A4, A5
|
||||
#define _CALLARGLIST , A1 a1, A2 a2, A3 a3, A4 a4, A5 a5
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2, A3 a3, A4 a4, A5 a5
|
||||
#define _CALLARGS a1, a2, a3, a4, a5
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -177,6 +188,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -184,9 +196,10 @@ struct Callback
|
|||
|
||||
// 6 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2, class A3, class A4, class A5, class A6
|
||||
#define _TMPLARGPART class A1, class A2, class A3, class A4, class A5, class A6
|
||||
#define _FUNCARGLIST A1, A2, A3, A4, A5, A6
|
||||
#define _CALLARGLIST , A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6
|
||||
#define _CALLARGS a1, a2, a3, a4, a5, a6
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -198,6 +211,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -205,9 +219,10 @@ struct Callback
|
|||
|
||||
// 7 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2, class A3, class A4, class A5, class A6, class A7
|
||||
#define _TMPLARGPART class A1, class A2, class A3, class A4, class A5, class A6, class A7
|
||||
#define _FUNCARGLIST A1, A2, A3, A4, A5, A6, A7
|
||||
#define _CALLARGLIST , A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7
|
||||
#define _CALLARGS a1, a2, a3, a4, a5, a6, a7
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -220,6 +235,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
@ -227,9 +243,10 @@ struct Callback
|
|||
|
||||
// 8 arguments
|
||||
|
||||
#define _TMPLARGPART , class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8
|
||||
#define _TMPLARGPART class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8
|
||||
#define _FUNCARGLIST A1, A2, A3, A4, A5, A6, A7, A8
|
||||
#define _CALLARGLIST , A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8
|
||||
#define _COMMA ,
|
||||
#define _CALLARGLIST A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8
|
||||
#define _CALLARGS a1, a2, a3, a4, a5, a6, a7, a8
|
||||
#define _SETVALUE args.write<A1> (a1); \
|
||||
args.write<A2> (a2); \
|
||||
|
|
@ -243,6 +260,7 @@ struct Callback
|
|||
#include "gsiCallbackVar.h"
|
||||
|
||||
#undef _SETVALUE
|
||||
#undef _COMMA
|
||||
#undef _CALLARGS
|
||||
#undef _CALLARGLIST
|
||||
#undef _FUNCARGLIST
|
||||
|
|
|
|||
|
|
@ -30,24 +30,24 @@
|
|||
// _CALLARGLIST ", A1 a1"
|
||||
// _SETVALUE "args.template write<A1> (a1);"
|
||||
|
||||
template <class X _TMPLARGPART>
|
||||
void issue (void (X::*) (_FUNCARGLIST) _CALLARGLIST) const
|
||||
template <class X _COMMA _TMPLARGPART>
|
||||
void issue (void (X::*) (_FUNCARGLIST) _COMMA _CALLARGLIST) const
|
||||
{
|
||||
SerialArgs args (argsize), ret (retsize);
|
||||
_SETVALUE
|
||||
call_int (args, ret);
|
||||
}
|
||||
|
||||
template <class X _TMPLARGPART>
|
||||
void issue (void (X::*) (_FUNCARGLIST) const _CALLARGLIST) const
|
||||
template <class X _COMMA _TMPLARGPART>
|
||||
void issue (void (X::*) (_FUNCARGLIST) const _COMMA _CALLARGLIST) const
|
||||
{
|
||||
SerialArgs args (argsize), ret (retsize);
|
||||
_SETVALUE
|
||||
call_int (args, ret);
|
||||
}
|
||||
|
||||
template <class X, class R _TMPLARGPART>
|
||||
R issue (R (X::*) (_FUNCARGLIST) _CALLARGLIST) const
|
||||
template <class X, class R _COMMA _TMPLARGPART>
|
||||
R issue (R (X::*) (_FUNCARGLIST) _COMMA _CALLARGLIST) const
|
||||
{
|
||||
tl::Heap heap;
|
||||
SerialArgs args (argsize), ret (retsize);
|
||||
|
|
@ -56,8 +56,8 @@ R issue (R (X::*) (_FUNCARGLIST) _CALLARGLIST) const
|
|||
return ret.template read<R> (heap);
|
||||
}
|
||||
|
||||
template <class X, class R _TMPLARGPART>
|
||||
R issue (R (X::*) (_FUNCARGLIST) const _CALLARGLIST) const
|
||||
template <class X, class R _COMMA _TMPLARGPART>
|
||||
R issue (R (X::*) (_FUNCARGLIST) const _COMMA _CALLARGLIST) const
|
||||
{
|
||||
tl::Heap heap;
|
||||
SerialArgs args (argsize), ret (retsize);
|
||||
|
|
@ -66,4 +66,3 @@ R issue (R (X::*) (_FUNCARGLIST) const _CALLARGLIST) const
|
|||
return ret.template read<R> (heap);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
// basics
|
||||
TEST(1)
|
||||
{
|
||||
return; // @@@
|
||||
tl::Eval e;
|
||||
tl::Variant v;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "gsiDecl.h"
|
||||
#include "gsiSignals.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layConfig.h"
|
||||
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
# include "gsiQtGuiExternals.h"
|
||||
|
|
@ -189,11 +190,266 @@ gsi::Methods cm_method_decl ()
|
|||
// is not the first base class.
|
||||
static lay::AbstractMenu *menu (lay::MainWindow *mw)
|
||||
{
|
||||
return mw->menu ();
|
||||
return mw->dispatcher ()->menu ();
|
||||
}
|
||||
|
||||
static void clear_config (lay::MainWindow *mw)
|
||||
{
|
||||
mw->dispatcher ()->clear_config ();
|
||||
}
|
||||
|
||||
static bool write_config (lay::MainWindow *mw, const std::string &config_file)
|
||||
{
|
||||
return mw->dispatcher ()->write_config (config_file);
|
||||
}
|
||||
|
||||
static bool read_config (lay::MainWindow *mw, const std::string &config_file)
|
||||
{
|
||||
return mw->dispatcher ()->read_config (config_file);
|
||||
}
|
||||
|
||||
static tl::Variant get_config (lay::MainWindow *mw, const std::string &name)
|
||||
{
|
||||
std::string value;
|
||||
if (mw->dispatcher ()->config_get (name, value)) {
|
||||
return tl::Variant (value);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
static void set_config (lay::MainWindow *mw, const std::string &name, const std::string &value)
|
||||
{
|
||||
mw->dispatcher ()->config_set (name, value);
|
||||
}
|
||||
|
||||
static std::vector<std::string>
|
||||
get_config_names (lay::MainWindow *mw)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
mw->dispatcher ()->get_config_names (names);
|
||||
return names;
|
||||
}
|
||||
|
||||
static void
|
||||
config_end (lay::MainWindow *mw)
|
||||
{
|
||||
mw->dispatcher ()->config_end ();
|
||||
}
|
||||
|
||||
static void
|
||||
set_key_bindings (lay::MainWindow *mw, const std::map<std::string, std::string> &bindings)
|
||||
{
|
||||
std::map<std::string, std::string> b = mw->menu ()->get_shortcuts (false);
|
||||
std::map<std::string, std::string> b_def = mw->menu ()->get_shortcuts (true);
|
||||
|
||||
for (std::map<std::string, std::string>::const_iterator i = bindings.begin (); i != bindings.end (); ++i) {
|
||||
b[i->first] = i->second;
|
||||
}
|
||||
|
||||
// cfg_key_bindings needs a special notation: lay::Action::no_shortcut () to force "none" instead of default
|
||||
// and and empty string to restore default.
|
||||
for (std::map<std::string, std::string>::iterator i = b.begin (); i != b.end (); ++i) {
|
||||
std::map<std::string, std::string>::const_iterator j = b_def.find (i->first);
|
||||
if (j != b_def.end ()) {
|
||||
if (i->second != j->second) {
|
||||
if (i->second.empty ()) {
|
||||
i->second = lay::Action::no_shortcut ();
|
||||
}
|
||||
} else {
|
||||
i->second.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string> > bv (b.begin (), b.end ());
|
||||
mw->dispatcher ()->config_set (lay::cfg_key_bindings, lay::pack_key_binding (bv));
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string>
|
||||
get_key_bindings (lay::MainWindow *mw)
|
||||
{
|
||||
return mw->menu ()->get_shortcuts (false);
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string>
|
||||
get_default_key_bindings (lay::MainWindow *mw)
|
||||
{
|
||||
return mw->menu ()->get_shortcuts (true);
|
||||
}
|
||||
|
||||
|
||||
static std::map<std::string, bool>
|
||||
get_menu_items_hidden (lay::MainWindow *mw)
|
||||
{
|
||||
std::map<std::string, std::string> kb = get_key_bindings (mw);
|
||||
std::map<std::string, bool> h;
|
||||
|
||||
if (mw->dispatcher ()->menu ()) {
|
||||
for (std::map<std::string, std::string>::const_iterator i = kb.begin (); i != kb.end (); ++i) {
|
||||
lay::Action *a = mw->dispatcher ()->menu ()->action (i->first);
|
||||
if (a) {
|
||||
h.insert (std::make_pair (i->first, a->is_hidden ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static std::map<std::string, bool>
|
||||
get_default_menu_items_hidden (lay::MainWindow *mw)
|
||||
{
|
||||
std::map<std::string, std::string> kb = get_key_bindings (mw);
|
||||
|
||||
// currently, all menu items are visible by default
|
||||
std::map<std::string, bool> h;
|
||||
for (std::map<std::string, std::string>::const_iterator i = kb.begin (); i != kb.end (); ++i) {
|
||||
h.insert (std::make_pair (i->first, false));
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static void
|
||||
set_menu_items_hidden (lay::MainWindow *mw, const std::map<std::string, bool> &hidden)
|
||||
{
|
||||
std::map<std::string, bool> h = get_menu_items_hidden (mw);
|
||||
for (std::map<std::string, bool>::const_iterator i = hidden.begin (); i != hidden.end (); ++i) {
|
||||
h[i->first] = i->second;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, bool> > hv;
|
||||
hv.insert (hv.end (), h.begin (), h.end ());
|
||||
mw->dispatcher ()->config_set (lay::cfg_menu_items_hidden, lay::pack_menu_items_hidden (hv));
|
||||
}
|
||||
|
||||
Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "MainWindow",
|
||||
|
||||
// Dispatcher interface and convenience functions
|
||||
method ("dispatcher", &lay::MainWindow::dispatcher,
|
||||
"@brief Gets the dispatcher interface (the plugin root configuration space)\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method_ext ("clear_config", &clear_config,
|
||||
"@brief Clears the configuration parameters\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().clear_config()'. See \\Dispatcher#clear_config for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("write_config", &write_config, gsi::arg ("file_name"),
|
||||
"@brief Writes configuration to a file\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().write_config(...)'. See \\Dispatcher#write_config for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("read_config", &read_config, gsi::arg ("file_name"),
|
||||
"@brief Reads the configuration from a file\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().read_config(...)'. See \\Dispatcher#read_config for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("get_config", &get_config, gsi::arg ("name"),
|
||||
"@brief Gets the value of a local configuration parameter\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().get_config(...)'. See \\Dispatcher#get_config for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("set_config", &set_config, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Set a local configuration parameter with the given name to the given value\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().set_config(...)'. See \\Dispatcher#set_config for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("get_config_names", &get_config_names,
|
||||
"@brief Gets the configuration parameter names\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().get_config_names(...)'. See \\Dispatcher#get_config_names for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("commit_config", &config_end,
|
||||
"@brief Commits the configuration settings\n"
|
||||
"This method is provided for using MainWindow without an Application object. "
|
||||
"It's a convience method which is equivalent to 'dispatcher().config_end(...)'. See \\Dispatcher#config_end for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
||||
// key binding configuration
|
||||
gsi::method_ext ("get_key_bindings", &get_key_bindings,
|
||||
"@brief Gets the current key bindings\n"
|
||||
"This method returns a hash with the key binding vs. menu item path.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("get_default_key_bindings", &get_default_key_bindings,
|
||||
"@brief Gets the default key bindings\n"
|
||||
"This method returns a hash with the default key binding vs. menu item path.\n"
|
||||
"You can use this hash with \\set_key_bindings to reset all key bindings to the default ones.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("set_key_bindings", &set_key_bindings, gsi::arg ("bindings"),
|
||||
"@brief Sets key bindings.\n"
|
||||
"Sets the given key bindings. "
|
||||
"Pass a hash listing the key bindings per menu item paths. Key strings follow the usual notation, e.g. 'Ctrl+A', 'Shift+X' or just 'F2'.\n"
|
||||
"Use an empty value to remove a key binding from a menu entry.\n"
|
||||
"\n"
|
||||
"\\get_key_bindings will give you the current key bindings, \\get_default_key_bindings will give you the default ones.\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# reset all key bindings to default:\n"
|
||||
"mw = RBA::MainWindow.instance()\n"
|
||||
"mw.set_key_bindings(mw.get_default_key_bindings())\n"
|
||||
"\n"
|
||||
"# disable key binding for 'copy':\n"
|
||||
"RBA::MainWindow.instance.set_key_bindings({ \"edit_menu.copy\" => \"\" })\n"
|
||||
"\n"
|
||||
"# configure 'copy' to use Shift+K and 'cut' to use Ctrl+K:\n"
|
||||
"RBA::MainWindow.instance.set_key_bindings({ \"edit_menu.copy\" => \"Shift+K\", \"edit_menu.cut\" => \"Ctrl+K\" })\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("get_menu_items_hidden", &get_menu_items_hidden,
|
||||
"@brief Gets the flags indicating whether menu items are hidden\n"
|
||||
"This method returns a hash with the hidden flag vs. menu item path.\n"
|
||||
"You can use this hash with \\set_menu_items_hidden.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("get_default_menu_items_hidden", &get_default_menu_items_hidden,
|
||||
"@brief Gets the flags indicating whether menu items are hidden by default\n"
|
||||
"You can use this hash with \\set_menu_items_hidden to restore the visibility of all menu items.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("set_menu_items_hidden", &set_menu_items_hidden,
|
||||
"@brief sets the flags indicating whether menu items are hidden\n"
|
||||
"This method allows hiding certain menu items. It takes a hash with hidden flags vs. menu item paths. "
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# show all menu items:\n"
|
||||
"mw = RBA::MainWindow.instance()\n"
|
||||
"mw.set_menu_items_hidden(mw.get_default_menu_items_hidden())\n"
|
||||
"\n"
|
||||
"# hide the 'copy' entry from the 'Edit' menu:\n"
|
||||
"RBA::MainWindow.instance().set_menu_items_hidden({ \"edit_menu.copy\" => true })\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
||||
// QMainWindow interface
|
||||
gsi::method_ext ("menu", &menu,
|
||||
"@brief Returns a reference to the abstract menu\n"
|
||||
|
|
@ -510,7 +766,7 @@ Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M
|
|||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
) +
|
||||
gsi::method ("call_menu", &lay::MainWindow::menu_activated,
|
||||
gsi::method ("call_menu", &lay::MainWindow::menu_activated, gsi::arg ("symbol"),
|
||||
"@brief Calls the menu item with the provided symbol.\n"
|
||||
"To obtain all symbols, use menu_symbols.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ ApplicationBase::init_app ()
|
|||
bool editable_from_config = false;
|
||||
|
||||
{
|
||||
lay::Dispatcher cfg (0);
|
||||
lay::Dispatcher cfg;
|
||||
|
||||
for (std::vector <std::string>::const_iterator c = m_config_files.begin (); c != m_config_files.end (); ++c) {
|
||||
try {
|
||||
|
|
@ -1474,7 +1474,7 @@ GuiApplication::start_recording ()
|
|||
lay::Dispatcher *
|
||||
GuiApplication::dispatcher () const
|
||||
{
|
||||
return mp_mw;
|
||||
return mp_mw->dispatcher ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1482,7 +1482,7 @@ GuiApplication::setup ()
|
|||
{
|
||||
tl_assert (mp_mw == 0);
|
||||
|
||||
mp_mw = new lay::MainWindow (this, 0, "main_window", is_undo_enabled ());
|
||||
mp_mw = new lay::MainWindow (this, "main_window", is_undo_enabled ());
|
||||
|
||||
QObject::connect (mp_mw, SIGNAL (closed ()), this, SLOT (quit ()));
|
||||
|
||||
|
|
@ -1579,7 +1579,7 @@ NonGuiApplication::setup ()
|
|||
mp_pr = new lay::ProgressReporter ();
|
||||
mp_pb = new TextProgress (10 /*verbosity level*/);
|
||||
mp_pr->set_progress_bar (mp_pb);
|
||||
mp_dispatcher = new lay::Dispatcher (0);
|
||||
mp_dispatcher = new lay::Dispatcher ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,27 +356,6 @@ CustomizeMenuConfigPage::~CustomizeMenuConfigPage ()
|
|||
mp_ui = 0;
|
||||
}
|
||||
|
||||
static void get_shortcuts (const lay::AbstractMenu &menu, const std::string &root, std::map<std::string, std::string> &bindings, bool with_defaults)
|
||||
{
|
||||
std::vector<std::string> items = menu.items (root);
|
||||
for (std::vector<std::string>::const_iterator i = items.begin (); i != items.end (); ++i) {
|
||||
if (i->size () > 0) {
|
||||
if (menu.is_valid (*i) && menu.action (*i)->is_visible ()) {
|
||||
if (menu.is_menu (*i)) {
|
||||
// a menu must be listed (so it can be hidden), but does not have a shortcut
|
||||
// but we don't include special menus
|
||||
if (i->at (0) != '@') {
|
||||
bindings.insert (std::make_pair (*i, std::string ()));
|
||||
}
|
||||
get_shortcuts (menu, *i, bindings, with_defaults);
|
||||
} else if (! menu.is_separator (*i)) {
|
||||
bindings.insert (std::make_pair (*i, with_defaults ? menu.action (*i)->get_default_shortcut () : menu.action (*i)->get_effective_shortcut ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CustomizeMenuConfigPage::reset_clicked ()
|
||||
{
|
||||
|
|
@ -405,12 +384,10 @@ CustomizeMenuConfigPage::apply (const std::vector<std::pair<std::string, std::st
|
|||
m_paths_for_action.clear ();
|
||||
|
||||
// get the current bindings
|
||||
m_current_bindings.clear ();
|
||||
get_shortcuts (*mp_dispatcher->menu (), std::string (), m_current_bindings, false);
|
||||
m_current_bindings = mp_dispatcher->menu ()->get_shortcuts (false);
|
||||
|
||||
// get the default bindings
|
||||
std::map<std::string, std::string> default_bindings;
|
||||
get_shortcuts (*mp_dispatcher->menu (), std::string (), default_bindings, true);
|
||||
std::map<std::string, std::string> default_bindings = mp_dispatcher->menu ()->get_shortcuts (true);
|
||||
|
||||
m_enable_event = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -154,9 +154,11 @@ show_dock_widget (QDockWidget *dock_widget, bool visible)
|
|||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const char *name, bool undo_enabled)
|
||||
MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
|
||||
: QMainWindow (0),
|
||||
lay::Dispatcher (plugin_parent, false),
|
||||
tl::Object (),
|
||||
lay::DispatcherDelegate (),
|
||||
m_dispatcher (this),
|
||||
m_text_progress (this, 10 /*verbosity threshold*/),
|
||||
m_mode (std::numeric_limits<unsigned int>::max ()),
|
||||
mp_setup_form (0),
|
||||
|
|
@ -175,6 +177,9 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha
|
|||
mp_app (app),
|
||||
m_manager (undo_enabled)
|
||||
{
|
||||
// install us as menu widget parent
|
||||
m_dispatcher.set_menu_parent_widget (this);
|
||||
|
||||
// ensures the deferred method scheduler is present
|
||||
tl::DeferredMethodScheduler::instance ();
|
||||
|
||||
|
|
@ -699,7 +704,7 @@ MainWindow::about_to_exec ()
|
|||
bool f;
|
||||
|
||||
f = false;
|
||||
config_get (cfg_full_hier_new_cell, f);
|
||||
dispatcher ()->config_get (cfg_full_hier_new_cell, f);
|
||||
if (!f) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("<html><body>"
|
||||
|
|
@ -737,7 +742,7 @@ MainWindow::about_to_exec ()
|
|||
}
|
||||
|
||||
f = false;
|
||||
config_get (cfg_no_stipple, f);
|
||||
dispatcher ()->config_get (cfg_no_stipple, f);
|
||||
if (f) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("Layers are shown without fill because fill has been intentionally turned off. This can be confusing since selecting a stipple does not have an effect in this case.\n\nTo turn this feature off, uncheck \"Show Layers Without Fill\" in the \"View\" menu.")),
|
||||
|
|
@ -749,7 +754,7 @@ MainWindow::about_to_exec ()
|
|||
}
|
||||
|
||||
f = false;
|
||||
config_get (cfg_markers_visible, f);
|
||||
dispatcher ()->config_get (cfg_markers_visible, f);
|
||||
if (! f) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("Markers are not visible because they have been turned off.\nYou may not see markers when using the marker browser feature.\n\nTo turn markers on, check \"Show Markers\" in the \"View\" menu.")),
|
||||
|
|
@ -761,7 +766,7 @@ MainWindow::about_to_exec ()
|
|||
}
|
||||
|
||||
f = false;
|
||||
config_get (cfg_hide_empty_layers, f);
|
||||
dispatcher ()->config_get (cfg_hide_empty_layers, f);
|
||||
if (f) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("The \"Hide Empty Layers\" feature is enabled. This can be confusing, in particular in edit mode, because layers are not shown although they are actually present.\n\nTo disable this feature, uncheck \"Hide Empty Layers\" in the layer panel's context menu.")),
|
||||
|
|
@ -916,8 +921,6 @@ MainWindow::config_finalize ()
|
|||
bool
|
||||
MainWindow::configure (const std::string &name, const std::string &value)
|
||||
{
|
||||
lay::Dispatcher::configure (name, value);
|
||||
|
||||
if (name == cfg_grid) {
|
||||
|
||||
double g = 0.0;
|
||||
|
|
@ -3337,7 +3340,7 @@ MainWindow::do_create_view ()
|
|||
view->set_synchronous (synchronous ());
|
||||
|
||||
int tl = 0;
|
||||
config_get (cfg_initial_hier_depth, tl);
|
||||
dispatcher ()->config_get (cfg_initial_hier_depth, tl);
|
||||
view->set_hier_levels (std::make_pair (0, tl));
|
||||
|
||||
// select the current mode and select the enabled editables
|
||||
|
|
@ -3399,7 +3402,7 @@ MainWindow::create_or_load_layout (const std::string *filename, const db::LoadLa
|
|||
if (mode == 0) {
|
||||
// reset the hierarchy depth in the "replace" case
|
||||
int tl = 0;
|
||||
config_get (cfg_initial_hier_depth, tl);
|
||||
dispatcher ()->config_get (cfg_initial_hier_depth, tl);
|
||||
vw->set_hier_levels (std::make_pair (0, tl));
|
||||
vw->clear_states ();
|
||||
vw->store_state ();
|
||||
|
|
@ -3552,7 +3555,7 @@ MainWindow::get_hier_levels () const
|
|||
return current_view ()->get_hier_levels ();
|
||||
} else {
|
||||
int tl = 0;
|
||||
config_get (cfg_initial_hier_depth, tl);
|
||||
dispatcher ()->config_get (cfg_initial_hier_depth, tl);
|
||||
return std::make_pair (0, tl);
|
||||
}
|
||||
}
|
||||
|
|
@ -4136,7 +4139,7 @@ MainWindow::plugin_registered (lay::PluginDeclaration *cls)
|
|||
void
|
||||
MainWindow::plugin_removed (lay::PluginDeclaration *cls)
|
||||
{
|
||||
cls->remove_menu_items (this);
|
||||
cls->remove_menu_items (dispatcher ());
|
||||
|
||||
// recreate all plugins except the one that got removed
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ class ProgressWidget;
|
|||
*/
|
||||
class LAY_PUBLIC MainWindow
|
||||
: public QMainWindow,
|
||||
public lay::Dispatcher
|
||||
public tl::Object,
|
||||
public lay::DispatcherDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
@ -107,7 +108,7 @@ public:
|
|||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
MainWindow (QApplication *app = 0, lay::Plugin *parent_plugin = 0, const char *name = "main_window", bool undo_enabled = true);
|
||||
MainWindow (QApplication *app = 0, const char *name = "main_window", bool undo_enabled = true);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -115,11 +116,11 @@ public:
|
|||
~MainWindow ();
|
||||
|
||||
/**
|
||||
* @brief Implementation of the Dispatcher interface
|
||||
* @brief Gets the dispatcher interface
|
||||
*/
|
||||
QWidget *menu_parent_widget ()
|
||||
lay::Dispatcher *dispatcher () const
|
||||
{
|
||||
return this;
|
||||
return const_cast<lay::Dispatcher *> (&m_dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -498,6 +499,14 @@ public:
|
|||
*/
|
||||
void show_macro_editor (const std::string &cat = std::string (), bool add = false);
|
||||
|
||||
/**
|
||||
* @brief Gets the main window's menu
|
||||
*/
|
||||
AbstractMenu *menu ()
|
||||
{
|
||||
return m_dispatcher.menu ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles a generic menu request
|
||||
*/
|
||||
|
|
@ -658,6 +667,8 @@ protected:
|
|||
void do_update_mru_menus ();
|
||||
|
||||
private:
|
||||
lay::Dispatcher m_dispatcher;
|
||||
|
||||
TextProgressDelegate m_text_progress;
|
||||
|
||||
// Main menu
|
||||
|
|
|
|||
|
|
@ -572,8 +572,8 @@ Navigator::showEvent (QShowEvent *)
|
|||
void
|
||||
Navigator::closeEvent (QCloseEvent *)
|
||||
{
|
||||
mp_main_window->config_set (cfg_show_navigator, "false");
|
||||
mp_main_window->config_end ();
|
||||
mp_main_window->dispatcher ()->config_set (cfg_show_navigator, "false");
|
||||
mp_main_window->dispatcher ()->config_end ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -127,30 +127,48 @@ public:
|
|||
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (f_mouse_press_event.can_issue ()) {
|
||||
return f_mouse_press_event.issue<lay::ViewService, bool, const db::DPoint &, unsigned int, bool> (&lay::ViewService::mouse_press_event, p, buttons, prio);
|
||||
return f_mouse_press_event.issue (&PluginBase::mouse_press_event_noref, p, buttons, prio);
|
||||
} else {
|
||||
return lay::ViewService::mouse_press_event (p, buttons, prio);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this version doesn't take a point reference which allows up to store the point
|
||||
bool mouse_press_event_noref (db::DPoint p, unsigned int buttons, bool prio)
|
||||
{
|
||||
return mouse_press_event (p, buttons, prio);
|
||||
}
|
||||
|
||||
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (f_mouse_click_event.can_issue ()) {
|
||||
return f_mouse_click_event.issue<lay::ViewService, bool, const db::DPoint &, unsigned int, bool> (&lay::ViewService::mouse_click_event, p, buttons, prio);
|
||||
return f_mouse_click_event.issue (&PluginBase::mouse_click_event_noref, p, buttons, prio);
|
||||
} else {
|
||||
return lay::ViewService::mouse_click_event (p, buttons, prio);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this version doesn't take a point reference which allows up to store the point
|
||||
bool mouse_click_event_noref (db::DPoint p, unsigned int buttons, bool prio)
|
||||
{
|
||||
return mouse_click_event (p, buttons, prio);
|
||||
}
|
||||
|
||||
virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (f_mouse_double_click_event.can_issue ()) {
|
||||
return f_mouse_double_click_event.issue<lay::ViewService, bool, const db::DPoint &, unsigned int, bool> (&lay::ViewService::mouse_double_click_event, p, buttons, prio);
|
||||
return f_mouse_double_click_event.issue (&PluginBase::mouse_double_click_event_noref, p, buttons, prio);
|
||||
} else {
|
||||
return lay::ViewService::mouse_double_click_event (p, buttons, prio);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this version doesn't take a point reference which allows up to store the point
|
||||
bool mouse_double_click_event_noref (db::DPoint p, unsigned int buttons, bool prio)
|
||||
{
|
||||
return mouse_double_click_event (p, buttons, prio);
|
||||
}
|
||||
|
||||
virtual bool leave_event (bool prio)
|
||||
{
|
||||
if (f_leave_event.can_issue ()) {
|
||||
|
|
@ -172,30 +190,48 @@ public:
|
|||
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (f_mouse_move_event.can_issue ()) {
|
||||
return f_mouse_move_event.issue<lay::ViewService, bool, const db::DPoint &, unsigned int, bool> (&lay::ViewService::mouse_move_event, p, buttons, prio);
|
||||
return f_mouse_move_event.issue (&PluginBase::mouse_move_event_noref, p, buttons, prio);
|
||||
} else {
|
||||
return lay::ViewService::mouse_move_event (p, buttons, prio);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this version doesn't take a point reference which allows up to store the point
|
||||
bool mouse_move_event_noref (db::DPoint p, unsigned int buttons, bool prio)
|
||||
{
|
||||
return mouse_move_event (p, buttons, prio);
|
||||
}
|
||||
|
||||
virtual bool mouse_release_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (f_mouse_release_event.can_issue ()) {
|
||||
return f_mouse_release_event.issue<lay::ViewService, bool, const db::DPoint &, unsigned int, bool> (&lay::ViewService::mouse_release_event, p, buttons, prio);
|
||||
return f_mouse_release_event.issue (&PluginBase::mouse_release_event_noref, p, buttons, prio);
|
||||
} else {
|
||||
return lay::ViewService::mouse_release_event (p, buttons, prio);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this version doesn't take a point reference which allows up to store the point
|
||||
bool mouse_release_event_noref (db::DPoint p, unsigned int buttons, bool prio)
|
||||
{
|
||||
return mouse_release_event (p, buttons, prio);
|
||||
}
|
||||
|
||||
virtual bool wheel_event (int delta, bool horizontal, const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (f_wheel_event.can_issue ()) {
|
||||
return f_wheel_event.issue<lay::ViewService, bool, int, bool, const db::DPoint &, unsigned int, bool> (&lay::ViewService::wheel_event, delta, horizontal, p, buttons, prio);
|
||||
return f_wheel_event.issue (&PluginBase::wheel_event_noref, delta, horizontal, p, buttons, prio);
|
||||
} else {
|
||||
return lay::ViewService::wheel_event (delta, horizontal, p, buttons, prio);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this version doesn't take a point reference which allows up to store the point
|
||||
bool wheel_event_noref (int delta, bool horizontal, db::DPoint p, unsigned int buttons, bool prio)
|
||||
{
|
||||
return wheel_event (delta, horizontal, p, buttons, prio);
|
||||
}
|
||||
|
||||
virtual void activated ()
|
||||
{
|
||||
if (f_activated.can_issue ()) {
|
||||
|
|
@ -693,7 +729,7 @@ Class<gsi::PluginBase> decl_Plugin ("lay", "Plugin",
|
|||
"@param buttons A combination of the constants in the \\ButtonState class which codes both the mouse buttons and the key modifiers (.e. ShiftButton etc).\n"
|
||||
"@return True to terminate dispatcher\n"
|
||||
) +
|
||||
callback ("mouse_button_pressed_event", &gsi::PluginBase::mouse_press_event, &gsi::PluginBase::f_mouse_press_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
callback ("mouse_button_pressed_event", &gsi::PluginBase::mouse_press_event_noref, &gsi::PluginBase::f_mouse_press_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button pressed event\n"
|
||||
"This method will called by the view when a button is pressed on the mouse.\n"
|
||||
"\n"
|
||||
|
|
@ -715,11 +751,11 @@ Class<gsi::PluginBase> decl_Plugin ("lay", "Plugin",
|
|||
"@param buttons A combination of the constants in the \\ButtonState class which codes both the mouse buttons and the key modifiers (.e. LeftButton, ShiftButton etc).\n"
|
||||
"@return True to terminate dispatcher\n"
|
||||
) +
|
||||
callback ("mouse_click_event", &gsi::PluginBase::mouse_click_event, &gsi::PluginBase::f_mouse_click_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
callback ("mouse_click_event", &gsi::PluginBase::mouse_click_event_noref, &gsi::PluginBase::f_mouse_click_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button click event (after the button has been released)\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse button has been released without moving it.\n"
|
||||
) +
|
||||
callback ("mouse_double_click_event", &gsi::PluginBase::mouse_double_click_event, &gsi::PluginBase::f_mouse_double_click_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
callback ("mouse_double_click_event", &gsi::PluginBase::mouse_double_click_event_noref, &gsi::PluginBase::f_mouse_double_click_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button double-click event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse button has been double-clicked.\n"
|
||||
) +
|
||||
|
|
@ -733,15 +769,15 @@ Class<gsi::PluginBase> decl_Plugin ("lay", "Plugin",
|
|||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse enters the canvas area.\n"
|
||||
"This method does not have a position nor button flags.\n"
|
||||
) +
|
||||
callback ("mouse_moved_event", &gsi::PluginBase::mouse_move_event, &gsi::PluginBase::f_mouse_move_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
callback ("mouse_moved_event", &gsi::PluginBase::mouse_move_event_noref, &gsi::PluginBase::f_mouse_move_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse move event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse is moved in the canvas area.\n"
|
||||
) +
|
||||
callback ("mouse_button_released_event", &gsi::PluginBase::mouse_release_event, &gsi::PluginBase::f_mouse_release_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
callback ("mouse_button_released_event", &gsi::PluginBase::mouse_release_event_noref, &gsi::PluginBase::f_mouse_release_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button release event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse button is released.\n"
|
||||
) +
|
||||
callback ("wheel_event", &gsi::PluginBase::wheel_event, &gsi::PluginBase::f_wheel_event, gsi::arg ("delta"), gsi::arg ("horizontal"), gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
callback ("wheel_event", &gsi::PluginBase::wheel_event_noref, &gsi::PluginBase::f_wheel_event, gsi::arg ("delta"), gsi::arg ("horizontal"), gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse wheel is rotated.\n"
|
||||
"Additional parameters for this event are 'delta' (the rotation angle in units of 1/8th degree) and 'horizontal' which is true when the horizontal wheel was rotated and "
|
||||
"false if the vertical wheel was rotated.\n"
|
||||
|
|
|
|||
|
|
@ -1677,4 +1677,26 @@ AbstractMenu::collect_configure_actions (std::vector<lay::ConfigureAction *> &ca
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AbstractMenu::get_shortcuts (const std::string &root, std::map<std::string, std::string> &bindings, bool with_defaults)
|
||||
{
|
||||
std::vector<std::string> items = this->items (root);
|
||||
for (std::vector<std::string>::const_iterator i = items.begin (); i != items.end (); ++i) {
|
||||
if (i->size () > 0) {
|
||||
if (is_valid (*i) && action (*i)->is_visible ()) {
|
||||
if (is_menu (*i)) {
|
||||
// a menu must be listed (so it can be hidden), but does not have a shortcut
|
||||
// but we don't include special menus
|
||||
if (i->at (0) != '@') {
|
||||
bindings.insert (std::make_pair (*i, std::string ()));
|
||||
}
|
||||
get_shortcuts (*i, bindings, with_defaults);
|
||||
} else if (! is_separator (*i)) {
|
||||
bindings.insert (std::make_pair (*i, with_defaults ? action (*i)->get_default_shortcut () : action (*i)->get_effective_shortcut ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -773,6 +773,18 @@ public:
|
|||
*/
|
||||
QActionGroup *make_exclusive_group (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Gets the keyboard shortcuts
|
||||
* @param with_defaults Returns the default shortcuts if true. Otherwise returns the effective shortcut.
|
||||
* @return a hash with menu paths for keys and key binding for values
|
||||
*/
|
||||
std::map<std::string, std::string> get_shortcuts (bool with_defaults)
|
||||
{
|
||||
std::map<std::string, std::string> b;
|
||||
get_shortcuts (std::string (), b, with_defaults);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the root node of the menu
|
||||
*/
|
||||
|
|
@ -798,6 +810,7 @@ private:
|
|||
void collect_group (std::vector<std::string> &grp, const std::string &name, const AbstractMenuItem &item) const;
|
||||
void collect_configure_actions (std::vector<ConfigureAction *> &ca, AbstractMenuItem &item);
|
||||
void emit_changed ();
|
||||
void get_shortcuts (const std::string &root, std::map<std::string, std::string> &bindings, bool with_defaults);
|
||||
|
||||
Dispatcher *mp_dispatcher;
|
||||
AbstractMenuItem m_root;
|
||||
|
|
|
|||
|
|
@ -36,13 +36,26 @@ static Dispatcher *ms_dispatcher_instance = 0;
|
|||
|
||||
Dispatcher::Dispatcher (Plugin *parent, bool standalone)
|
||||
: Plugin (parent, standalone),
|
||||
m_menu (this)
|
||||
m_menu (this),
|
||||
mp_menu_parent_widget (0),
|
||||
mp_delegate (0)
|
||||
{
|
||||
if (! parent && ! ms_dispatcher_instance) {
|
||||
ms_dispatcher_instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher::Dispatcher (DispatcherDelegate *delegate, Plugin *parent, bool standalone)
|
||||
: Plugin (parent, standalone),
|
||||
m_menu (this),
|
||||
mp_menu_parent_widget (0),
|
||||
mp_delegate (delegate)
|
||||
{
|
||||
if (! ms_dispatcher_instance) {
|
||||
ms_dispatcher_instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher::~Dispatcher ()
|
||||
{
|
||||
if (ms_dispatcher_instance == this) {
|
||||
|
|
@ -57,9 +70,23 @@ Dispatcher::configure (const std::string &name, const std::string &value)
|
|||
for (std::vector<lay::ConfigureAction *>::const_iterator a = ca.begin (); a != ca.end (); ++a) {
|
||||
(*a)->configure (value);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (mp_delegate) {
|
||||
return mp_delegate->configure (name, value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Dispatcher::config_finalize ()
|
||||
{
|
||||
if (mp_delegate) {
|
||||
return mp_delegate->config_finalize ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Writing and Reading of configuration
|
||||
|
||||
struct ConfigGetAdaptor
|
||||
|
|
|
|||
|
|
@ -41,11 +41,69 @@ class AbstractMenu;
|
|||
class Action;
|
||||
class ConfigureAction;
|
||||
|
||||
/**
|
||||
* @brief A delegate by which the dispatcher can submit notification events
|
||||
*/
|
||||
class LAYBASIC_PUBLIC DispatcherDelegate
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Notifies the plugin root that a new plugin class has been registered
|
||||
*
|
||||
* This method is called when a plugin is loaded dynamically during runtime.
|
||||
*/
|
||||
virtual void plugin_registered (lay::PluginDeclaration * /*cls*/)
|
||||
{
|
||||
// .. this implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Notifies the plugin root that a plugin class is about to be removed
|
||||
*/
|
||||
virtual void plugin_removed (lay::PluginDeclaration * /*cls*/)
|
||||
{
|
||||
// .. this implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects the given mode
|
||||
*
|
||||
* The implementation is supposed to select the given mode on all related plugins.
|
||||
*/
|
||||
virtual void select_mode (int /*mode*/)
|
||||
{
|
||||
// .. this implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Menu command handler
|
||||
*/
|
||||
virtual void menu_activated (const std::string & /*symbol*/)
|
||||
{
|
||||
// .. this implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receives configuration events
|
||||
*/
|
||||
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configuration finalization
|
||||
*/
|
||||
virtual void config_finalize ()
|
||||
{
|
||||
// .. the default implementation does nothing ..
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The central menu event and configuration dispatcher class
|
||||
*
|
||||
* This class acts as the top level dispatcher for plugin events and the menu configuration.
|
||||
*
|
||||
*/
|
||||
class LAYBASIC_PUBLIC Dispatcher
|
||||
: public Plugin
|
||||
|
|
@ -57,7 +115,14 @@ public:
|
|||
* @param parent Usually 0, but a dispatcher may have parents. In this case, the dispatcher is not the actual dispatcher, but the real plugin chain's root is.
|
||||
* @param standalone The standalone flag passed to the plugin constructor.
|
||||
*/
|
||||
Dispatcher (Plugin *parent, bool standalone = false);
|
||||
Dispatcher (Plugin *parent = 0, bool standalone = false);
|
||||
|
||||
/**
|
||||
* @brief The root constructor
|
||||
*
|
||||
* @param delegate The notification receiver for dispatcher events
|
||||
*/
|
||||
Dispatcher (DispatcherDelegate *delegate, Plugin *parent = 0, bool standalone = false);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -95,29 +160,65 @@ public:
|
|||
*
|
||||
* This method is called when a plugin is loaded dynamically during runtime.
|
||||
*/
|
||||
virtual void plugin_registered (lay::PluginDeclaration * /*cls*/) { }
|
||||
virtual void plugin_registered (lay::PluginDeclaration *cls)
|
||||
{
|
||||
if (mp_delegate) {
|
||||
mp_delegate->plugin_registered (cls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Notifies the plugin root that a plugin class is about to be removed
|
||||
*/
|
||||
virtual void plugin_removed (lay::PluginDeclaration * /*cls*/) { }
|
||||
virtual void plugin_removed (lay::PluginDeclaration *cls)
|
||||
{
|
||||
if (mp_delegate) {
|
||||
mp_delegate->plugin_registered (cls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects the given mode
|
||||
*
|
||||
* The implementation is supposed to select the given mode on all related plugins.
|
||||
*/
|
||||
virtual void select_mode (int /*mode*/) { }
|
||||
virtual void select_mode (int mode)
|
||||
{
|
||||
if (mp_delegate) {
|
||||
mp_delegate->select_mode (mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called, when a menu item is selected
|
||||
*/
|
||||
virtual void menu_activated (const std::string &symbol)
|
||||
{
|
||||
if (mp_delegate) {
|
||||
mp_delegate->menu_activated (symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parent widget
|
||||
*/
|
||||
virtual QWidget *menu_parent_widget () { return 0; }
|
||||
QWidget *menu_parent_widget ()
|
||||
{
|
||||
return mp_menu_parent_widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parent widget
|
||||
*/
|
||||
void set_menu_parent_widget (QWidget *w)
|
||||
{
|
||||
mp_menu_parent_widget = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the dispatcher supplies a user interface
|
||||
*/
|
||||
virtual bool has_ui () { return menu_parent_widget () != 0; }
|
||||
bool has_ui () { return menu_parent_widget () != 0; }
|
||||
|
||||
/**
|
||||
* @brief Gets the AbstractMenu object
|
||||
|
|
@ -132,12 +233,15 @@ public:
|
|||
protected:
|
||||
// capture the configuration events so we can change the value of the configuration actions
|
||||
virtual bool configure (const std::string &name, const std::string &value);
|
||||
virtual void config_finalize ();
|
||||
|
||||
private:
|
||||
Dispatcher (const Dispatcher &);
|
||||
Dispatcher &operator= (const Dispatcher &);
|
||||
|
||||
lay::AbstractMenu m_menu;
|
||||
QWidget *mp_menu_parent_widget;
|
||||
DispatcherDelegate *mp_delegate;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin
|
|||
{
|
||||
// either it's us or the parent has a dispatcher
|
||||
tl_assert (dispatcher () != 0);
|
||||
set_menu_parent_widget (this);
|
||||
|
||||
// ensures the deferred method scheduler is present
|
||||
tl::DeferredMethodScheduler::instance ();
|
||||
|
|
@ -712,11 +713,6 @@ LayoutView::~LayoutView ()
|
|||
mp_bookmarks_view = 0;
|
||||
}
|
||||
|
||||
QWidget *LayoutView::menu_parent_widget ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
lay::EditorOptionsPages *LayoutView::editor_options_pages ()
|
||||
{
|
||||
if (! mp_editor_options_frame) {
|
||||
|
|
|
|||
|
|
@ -2917,9 +2917,6 @@ private:
|
|||
|
||||
std::list<lay::CellView>::iterator cellview_iter (int cv_index);
|
||||
std::list<lay::CellView>::const_iterator cellview_iter (int cv_index) const;
|
||||
|
||||
// implementation of Dispatcher
|
||||
virtual QWidget *menu_parent_widget ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,3 +193,9 @@ TEST(22_split_gate)
|
|||
run_test (_this, "nand2_split_gate", "nand2_split_gate.oas");
|
||||
}
|
||||
|
||||
// empty gds
|
||||
TEST(23_issue709)
|
||||
{
|
||||
run_test (_this, "empty_subcells", "empty_subcells.gds");
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,25 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
* cell empty_subcells
|
||||
.SUBCKT empty_subcells
|
||||
* cell instance $1 r0 *1 0,0
|
||||
X$1 1 2 blockB
|
||||
* cell instance $2 r0 *1 310,0
|
||||
X$2 1 2 blockA
|
||||
.ENDS empty_subcells
|
||||
|
||||
* cell blockB
|
||||
* pin V
|
||||
* pin W
|
||||
.SUBCKT blockB 1 2
|
||||
* net 1 V
|
||||
* net 2 W
|
||||
.ENDS blockB
|
||||
|
||||
* cell blockA
|
||||
* pin A
|
||||
* pin B
|
||||
.SUBCKT blockA 1 2
|
||||
* net 1 A
|
||||
* net 2 B
|
||||
.ENDS blockA
|
||||
Binary file not shown.
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
source($lvs_test_source)
|
||||
report_lvs($lvs_test_target_lvsdb, true)
|
||||
target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
|
||||
|
||||
schematic("empty_subcells_sch.cir")
|
||||
|
||||
deep
|
||||
|
||||
m1 = input(1, 0)
|
||||
via = input(2, 0)
|
||||
m2 = input(3, 0)
|
||||
lab = labels(254,0)
|
||||
|
||||
connect(m1, via)
|
||||
connect(via, m2)
|
||||
connect(m2, lab)
|
||||
|
||||
netlist.make_top_level_pins
|
||||
compare
|
||||
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#%lvsdb-klayout
|
||||
|
||||
# Layout
|
||||
layout(
|
||||
top(empty_subcells)
|
||||
unit(1)
|
||||
|
||||
# Layer section
|
||||
# This section lists the mask layers (drawing or derived) and their connections.
|
||||
|
||||
# Mask layers
|
||||
layer(l1 '1/0')
|
||||
layer(l2 '2/0')
|
||||
layer(l3 '3/0')
|
||||
layer(l4 '254/0')
|
||||
|
||||
# Mask layer connectivity
|
||||
connect(l1 l1 l2)
|
||||
connect(l2 l1 l2 l3)
|
||||
connect(l3 l2 l3 l4)
|
||||
connect(l4 l3)
|
||||
|
||||
# Circuit section
|
||||
# Circuits are the hierarchical building blocks of the netlist.
|
||||
circuit(blockA
|
||||
|
||||
# Circuit boundary
|
||||
rect((100 10) (30 80))
|
||||
|
||||
# Nets with their geometries
|
||||
net(1 name(A)
|
||||
rect(l3 (100 60) (30 30))
|
||||
text(l4 A (-10 -10))
|
||||
)
|
||||
net(2 name(B)
|
||||
rect(l3 (100 10) (30 30))
|
||||
text(l4 B (-10 -10))
|
||||
)
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(1 name(A))
|
||||
pin(2 name(B))
|
||||
|
||||
)
|
||||
circuit(blockB
|
||||
|
||||
# Circuit boundary
|
||||
rect((100 10) (30 80))
|
||||
|
||||
# Nets with their geometries
|
||||
net(1 name(V)
|
||||
rect(l3 (100 60) (30 30))
|
||||
text(l4 V (-10 -10))
|
||||
)
|
||||
net(2 name(W)
|
||||
rect(l3 (100 10) (30 30))
|
||||
text(l4 W (-10 -10))
|
||||
)
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(1 name(V))
|
||||
pin(2 name(W))
|
||||
|
||||
)
|
||||
circuit(empty_subcells
|
||||
|
||||
# Circuit boundary
|
||||
rect((100 10) (340 80))
|
||||
|
||||
# Nets with their geometries
|
||||
net(1
|
||||
rect(l1 (180 60) (90 30))
|
||||
rect(l2 (-160 -20) (90 10))
|
||||
rect(l2 (40 -10) (180 10))
|
||||
)
|
||||
net(2
|
||||
rect(l1 (180 10) (90 30))
|
||||
rect(l2 (-160 -20) (90 10))
|
||||
rect(l2 (40 -10) (180 10))
|
||||
)
|
||||
|
||||
# Subcircuits and their connections
|
||||
circuit(1 blockB location(0 0)
|
||||
pin(0 1)
|
||||
pin(1 2)
|
||||
)
|
||||
circuit(2 blockA location(310 0)
|
||||
pin(0 1)
|
||||
pin(1 2)
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
# Reference netlist
|
||||
reference(
|
||||
|
||||
# Circuit section
|
||||
# Circuits are the hierarchical building blocks of the netlist.
|
||||
circuit(BLOCKA
|
||||
|
||||
# Nets
|
||||
net(1 name(A))
|
||||
net(2 name(B))
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(1 name(A))
|
||||
pin(2 name(B))
|
||||
|
||||
)
|
||||
circuit(BLOCKB
|
||||
|
||||
# Nets
|
||||
net(1 name(V))
|
||||
net(2 name(W))
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(1 name(V))
|
||||
pin(2 name(W))
|
||||
|
||||
)
|
||||
circuit(EMPTY_SUBCELLS
|
||||
|
||||
# Nets
|
||||
net(1 name(E))
|
||||
net(2 name(F))
|
||||
|
||||
# Subcircuits and their connections
|
||||
circuit(1 BLOCKA name('1')
|
||||
pin(0 1)
|
||||
pin(1 2)
|
||||
)
|
||||
circuit(2 BLOCKB name('2')
|
||||
pin(0 1)
|
||||
pin(1 2)
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
# Cross reference
|
||||
xref(
|
||||
circuit(blockA BLOCKA match
|
||||
xref(
|
||||
net(1 1 match)
|
||||
net(2 2 match)
|
||||
pin(0 0 match)
|
||||
pin(1 1 match)
|
||||
)
|
||||
)
|
||||
circuit(blockB BLOCKB match
|
||||
xref(
|
||||
net(1 1 match)
|
||||
net(2 2 match)
|
||||
pin(0 0 match)
|
||||
pin(1 1 match)
|
||||
)
|
||||
)
|
||||
circuit(empty_subcells EMPTY_SUBCELLS match
|
||||
xref(
|
||||
net(1 1 warning)
|
||||
net(2 2 warning)
|
||||
circuit(2 1 match)
|
||||
circuit(1 2 match)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
.subckt blockA a b
|
||||
.ends
|
||||
|
||||
.subckt blockB v w
|
||||
.ends
|
||||
|
||||
.subckt empty_subcells
|
||||
X1 e f blockA
|
||||
X2 e f blockB
|
||||
.ends
|
||||
|
|
@ -2841,21 +2841,32 @@ class BasicTest(unittest.TestCase):
|
|||
|
||||
# binary strings
|
||||
|
||||
qba = pya.A.ia_cref_to_qba([ 17, 42, 0, 8 ])
|
||||
self.assertEqual(repr(qba), "b'\\x11*\\x00\\x08'")
|
||||
self.assertEqual(pya.A.qba_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_cref_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_cptr_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_ref_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_ptr_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
if "ia_cref_to_qba" in pya.A.__dict__:
|
||||
|
||||
qba = pya.A.ia_cref_to_qba_cref([ 17, 42, 0, 8 ])
|
||||
self.assertEqual(repr(qba), "b'\\x11*\\x00\\x08'")
|
||||
qba = pya.A.ia_cref_to_qba([ 17, 42, 0, 8 ])
|
||||
if sys.version_info < (3, 0):
|
||||
self.assertEqual(repr(qba), "bytearray(b'\\x11*\\x00\\x08')")
|
||||
else:
|
||||
self.assertEqual(repr(qba), "b'\\x11*\\x00\\x08'")
|
||||
self.assertEqual(pya.A.qba_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_cref_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_cptr_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_ref_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.qba_ptr_to_ia(qba), [ 17, 42, 0, 8 ])
|
||||
|
||||
qba = pya.A.ia_cref_to_qba_cref([ 17, 42, 0, 8 ])
|
||||
if sys.version_info < (3, 0):
|
||||
self.assertEqual(repr(qba), "bytearray(b'\\x11*\\x00\\x08')")
|
||||
else:
|
||||
self.assertEqual(repr(qba), "b'\\x11*\\x00\\x08'")
|
||||
|
||||
self.assertEqual(pya.A.qba_to_ia(b'\x00\x01\x02'), [ 0, 1, 2 ])
|
||||
self.assertEqual(pya.A.qba_to_ia(b'\x00\x01\x02'), [ 0, 1, 2 ])
|
||||
|
||||
ba = pya.A.ia_cref_to_ba([ 17, 42, 0, 8 ])
|
||||
self.assertEqual(repr(ba), "b'\\x11*\\x00\\x08'")
|
||||
if sys.version_info < (3, 0):
|
||||
self.assertEqual(repr(ba), "bytearray(b'\\x11*\\x00\\x08')")
|
||||
else:
|
||||
self.assertEqual(repr(ba), "b'\\x11*\\x00\\x08'")
|
||||
self.assertEqual(pya.A.ba_to_ia(ba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.ba_cref_to_ia(ba), [ 17, 42, 0, 8 ])
|
||||
self.assertEqual(pya.A.ba_cptr_to_ia(ba), [ 17, 42, 0, 8 ])
|
||||
|
|
@ -2863,7 +2874,10 @@ class BasicTest(unittest.TestCase):
|
|||
self.assertEqual(pya.A.ba_ptr_to_ia(ba), [ 17, 42, 0, 8 ])
|
||||
|
||||
ba = pya.A.ia_cref_to_ba_cref([ 17, 42, 0, 8 ])
|
||||
self.assertEqual(repr(ba), "b'\\x11*\\x00\\x08'")
|
||||
if sys.version_info < (3, 0):
|
||||
self.assertEqual(repr(ba), "bytearray(b'\\x11*\\x00\\x08')")
|
||||
else:
|
||||
self.assertEqual(repr(ba), "b'\\x11*\\x00\\x08'")
|
||||
|
||||
self.assertEqual(pya.A.ba_to_ia(b'\x00\x01\x02'), [ 0, 1, 2 ])
|
||||
|
||||
|
|
|
|||
|
|
@ -487,12 +487,18 @@ class QtBindingTest(unittest.TestCase):
|
|||
|
||||
slm = MyStandardItemModel()
|
||||
rn = slm.roleNames()
|
||||
self.assertEqual(map2str(rn), "{0: b'display', 1: b'decoration', 2: b'edit', 3: b'toolTip', 4: b'statusTip', 5: b'whatsThis'}")
|
||||
if sys.version_info < (3, 0):
|
||||
self.assertEqual(map2str(rn), "{0: display, 1: decoration, 2: edit, 3: toolTip, 4: statusTip, 5: whatsThis}")
|
||||
else:
|
||||
self.assertEqual(map2str(rn), "{0: b'display', 1: b'decoration', 2: b'edit', 3: b'toolTip', 4: b'statusTip', 5: b'whatsThis'}")
|
||||
rnNew = slm.roleNames()
|
||||
rnNew[7] = "blabla"
|
||||
slm.srn(rnNew)
|
||||
rn = slm.roleNames()
|
||||
self.assertEqual(map2str(rn), "{0: b'display', 1: b'decoration', 2: b'edit', 3: b'toolTip', 4: b'statusTip', 5: b'whatsThis', 7: b'blabla'}")
|
||||
if sys.version_info < (3, 0):
|
||||
self.assertEqual(map2str(rn), "{0: display, 1: decoration, 2: edit, 3: toolTip, 4: statusTip, 5: whatsThis, 7: blabla}")
|
||||
else:
|
||||
self.assertEqual(map2str(rn), "{0: b'display', 1: b'decoration', 2: b'edit', 3: b'toolTip', 4: b'statusTip', 5: b'whatsThis', 7: b'blabla'}")
|
||||
|
||||
def test_44(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -770,7 +770,10 @@ class Basic_TestClass < TestBase
|
|||
b.each_b_copy { |bb| arr.push(bb.str) }
|
||||
assert_equal(arr, ["a", "y", "uu"])
|
||||
# through enumerator
|
||||
assert_equal(b.each_b_copy.collect(&:str), ["a", "y", "uu"])
|
||||
if RUBY_VERSION > "2.0.0"
|
||||
# this creates GC leaks in 2.0.0
|
||||
assert_equal(b.each_b_copy.collect(&:str), ["a", "y", "uu"])
|
||||
end
|
||||
|
||||
arr = []
|
||||
b.each_b_copy { |bb| bb.set_str(bb.str + "x"); arr.push(bb.str) }
|
||||
|
|
@ -784,7 +787,10 @@ class Basic_TestClass < TestBase
|
|||
b.each_b_cref { |bb| arr.push(bb.str) }
|
||||
assert_equal(arr, ["a", "y", "uu"])
|
||||
# through enumerator
|
||||
assert_equal(b.each_b_cref.collect(&:str), ["a", "y", "uu"])
|
||||
if RUBY_VERSION > "2.0.0"
|
||||
# this creates GC leaks in 2.0.0
|
||||
assert_equal(b.each_b_cref.collect(&:str), ["a", "y", "uu"])
|
||||
end
|
||||
|
||||
arr = []
|
||||
# this works, since the "const B &" will be converted to a copy
|
||||
|
|
@ -800,7 +806,10 @@ class Basic_TestClass < TestBase
|
|||
b.each_b_cptr { |bb| arr.push(bb.str) }
|
||||
assert_equal(arr, ["a", "y", "uu"])
|
||||
# through enumerator
|
||||
assert_equal(b.each_b_cptr.collect(&:str), ["a", "y", "uu"])
|
||||
if RUBY_VERSION > "2.0.0"
|
||||
# this creates GC leaks in 2.0.0
|
||||
assert_equal(b.each_b_cptr.collect(&:str), ["a", "y", "uu"])
|
||||
end
|
||||
|
||||
arr = []
|
||||
# const references cannot be modified
|
||||
|
|
@ -821,7 +830,10 @@ class Basic_TestClass < TestBase
|
|||
b.each_b_ref { |bb| arr.push(bb.str) }
|
||||
assert_equal(arr, ["a", "y", "uu"])
|
||||
# through enumerator
|
||||
assert_equal(b.each_b_ref.collect(&:str), ["a", "y", "uu"])
|
||||
if RUBY_VERSION > "2.0.0"
|
||||
# this creates GC leaks in 2.0.0
|
||||
assert_equal(b.each_b_ref.collect(&:str), ["a", "y", "uu"])
|
||||
end
|
||||
|
||||
arr = []
|
||||
b.each_b_ref { |bb| bb.set_str(bb.str + "x"); arr.push(bb.str) }
|
||||
|
|
@ -835,7 +847,10 @@ class Basic_TestClass < TestBase
|
|||
b.each_b_ptr { |bb| arr.push(bb.str) }
|
||||
assert_equal(arr, ["ax", "yx", "uux"])
|
||||
# through enumerator
|
||||
assert_equal(b.each_b_ptr.collect(&:str), ["ax", "yx", "uux"])
|
||||
if RUBY_VERSION > "2.0.0"
|
||||
# this creates GC leaks in 2.0.0
|
||||
assert_equal(b.each_b_ptr.collect(&:str), ["ax", "yx", "uux"])
|
||||
end
|
||||
|
||||
arr = []
|
||||
b.each_b_ptr { |bb| bb.set_str(bb.str + "x"); arr.push(bb.str) }
|
||||
|
|
@ -1422,6 +1437,7 @@ class Basic_TestClass < TestBase
|
|||
|
||||
# makes sure the objects inside the block before are deleted
|
||||
GC.start
|
||||
GC.start # 2.0.0 needs a second one
|
||||
|
||||
assert_equal(RBA::A.instance_count, ic0)
|
||||
assert_equal(RBA::A.a20_get == nil, true)
|
||||
|
|
|
|||
|
|
@ -383,6 +383,42 @@ RESULT
|
|||
|
||||
end
|
||||
|
||||
def test_6
|
||||
|
||||
app = RBA::Application.instance
|
||||
mw = app.main_window
|
||||
|
||||
assert_equal(mw.get_key_bindings["file_menu.exit"], "Ctrl+Q")
|
||||
|
||||
# key bindings
|
||||
|
||||
mw.set_key_bindings({"file_menu.exit" => "F2"})
|
||||
assert_equal(mw.get_key_bindings["file_menu.exit"], "F2")
|
||||
|
||||
mw.set_key_bindings({"file_menu.exit" => ""})
|
||||
assert_equal(mw.get_key_bindings["file_menu.exit"], "")
|
||||
|
||||
mw.set_key_bindings(mw.get_default_key_bindings)
|
||||
assert_equal(mw.get_key_bindings["file_menu.exit"], "Ctrl+Q")
|
||||
|
||||
mw.set_key_bindings({"file_menu.exit" => ""})
|
||||
assert_equal(mw.get_key_bindings["file_menu.exit"], "")
|
||||
|
||||
# menu items hidden
|
||||
|
||||
assert_equal(mw.get_menu_items_hidden["file_menu.exit"], false)
|
||||
|
||||
mw.set_menu_items_hidden({"file_menu.exit" => true})
|
||||
assert_equal(mw.get_menu_items_hidden["file_menu.exit"], true)
|
||||
|
||||
mw.set_menu_items_hidden(mw.get_default_menu_items_hidden)
|
||||
assert_equal(mw.get_menu_items_hidden["file_menu.exit"], false)
|
||||
|
||||
mw.set_menu_items_hidden({"file_menu.exit" => true})
|
||||
assert_equal(mw.get_menu_items_hidden["file_menu.exit"], true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue