mirror of https://github.com/KLayout/klayout.git
commit
0f739bcbef
|
|
@ -1431,7 +1431,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
|
|||
const ant::Object *robj = dynamic_cast <const ant::Object *> ((*ri).ptr ());
|
||||
if (robj && (! robj_min || robj == robj_min)) {
|
||||
|
||||
if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index) && m_move_mode != MoveRuler) {
|
||||
if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index)) {
|
||||
|
||||
// found anything: make the moved ruler the selection
|
||||
clear_selection ();
|
||||
|
|
@ -1516,28 +1516,70 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
|
|||
}
|
||||
|
||||
void
|
||||
Service::move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constraint_type /*ac*/)
|
||||
Service::snap_rulers (lay::angle_constraint_type ac)
|
||||
{
|
||||
if (m_rulers.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
lay::PointSnapToObjectResult min_snp;
|
||||
double min_dist = -1.0;
|
||||
db::DVector min_delta;
|
||||
|
||||
for (auto r = m_rulers.begin (); r != m_rulers.end (); ++r) {
|
||||
|
||||
const ant::Object *ruler = (*r)->ruler ();
|
||||
|
||||
db::DPoint p1 = m_trans * ruler->p1 ();
|
||||
db::DPoint p2 = m_trans * ruler->p2 ();
|
||||
|
||||
auto tr = db::DTrans ((m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
|
||||
db::DPoint org1 = tr * ruler->p1 ();
|
||||
db::DPoint org2 = tr * ruler->p2 ();
|
||||
|
||||
auto snp = snap2_details (org1, p1, ruler, ac);
|
||||
double dist = p1.distance (snp.snapped_point);
|
||||
|
||||
if (min_dist < 0 || dist < min_dist) {
|
||||
min_snp = snp;
|
||||
min_dist = dist;
|
||||
min_delta = snp.snapped_point - p1;
|
||||
}
|
||||
|
||||
snp = snap2_details (org2, p2, ruler, ac);
|
||||
dist = p2.distance (snp.snapped_point);
|
||||
|
||||
if (min_dist < 0 || dist < min_dist) {
|
||||
min_snp = snp;
|
||||
min_dist = dist;
|
||||
min_delta = snp.snapped_point - p2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (min_snp.object_snap != lay::PointSnapToObjectResult::NoObject) {
|
||||
mouse_cursor_from_snap_details (min_snp);
|
||||
}
|
||||
|
||||
m_trans = db::DTrans (min_delta) * m_trans;
|
||||
}
|
||||
|
||||
void
|
||||
Service::move_transform (const db::DPoint & /*p*/, db::DFTrans tr, lay::angle_constraint_type ac)
|
||||
{
|
||||
if (m_rulers.empty () || m_selected.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_move_mode == MoveRuler) {
|
||||
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
|
||||
clear_mouse_cursors ();
|
||||
|
||||
db::DVector dp = p - db::DPoint ();
|
||||
|
||||
m_original.transform (db::DTrans (m_p1 - db::DPoint ()) * db::DTrans (tr) * db::DTrans (db::DPoint () - m_p1));
|
||||
m_current.transform (db::DTrans (dp) * db::DTrans (tr) * db::DTrans (-dp));
|
||||
|
||||
// display current rulers' parameters
|
||||
show_message ();
|
||||
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveSelected) {
|
||||
if (m_move_mode == MoveSelected) {
|
||||
|
||||
m_trans *= db::DTrans (m_p1 - db::DPoint ()) * db::DTrans (tr) * db::DTrans (db::DPoint () - m_p1);
|
||||
|
||||
snap_rulers (ac_eff);
|
||||
|
||||
for (std::vector<ant::View *>::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
|
||||
(*r)->transform_by (db::DCplxTrans (m_trans));
|
||||
}
|
||||
|
|
@ -1553,90 +1595,66 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
|
|||
return;
|
||||
}
|
||||
|
||||
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
|
||||
clear_mouse_cursors ();
|
||||
|
||||
if (m_move_mode == MoveP1) {
|
||||
|
||||
m_current.seg_p1 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second);
|
||||
m_current.seg_p1 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP2) {
|
||||
|
||||
m_current.seg_p2 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second);
|
||||
m_current.seg_p2 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP12) {
|
||||
|
||||
db::DPoint p12 = snap2 (m_p1, p, &m_current, ac).second;
|
||||
db::DPoint p12 = snap2_visual (m_p1, p, &m_current, ac);
|
||||
m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), p12.y ()));
|
||||
m_current.seg_p2 (m_seg_index, db::DPoint (p12.x (), m_current.seg_p2 (m_seg_index).y ()));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP21) {
|
||||
|
||||
db::DPoint p21 = snap2 (m_p1, p, &m_current, ac).second;
|
||||
db::DPoint p21 = snap2_visual (m_p1, p, &m_current, ac);
|
||||
m_current.seg_p1 (m_seg_index, db::DPoint (p21.x (), m_current.seg_p1 (m_seg_index).y ()));
|
||||
m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), p21.y ()));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP1X) {
|
||||
|
||||
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
|
||||
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
|
||||
m_current.seg_p1 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p1 (m_seg_index).y ()));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP2X) {
|
||||
|
||||
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
|
||||
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
|
||||
m_current.seg_p2 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p2 (m_seg_index).y ()));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP1Y) {
|
||||
|
||||
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
|
||||
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
|
||||
m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), pc.y ()));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveP2Y) {
|
||||
|
||||
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
|
||||
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
|
||||
m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), pc.y ()));
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveRuler) {
|
||||
|
||||
// try two ways of snapping
|
||||
db::DVector dp = lay::snap_angle (p - m_p1, ac == lay::AC_Global ? m_snap_mode : ac);
|
||||
|
||||
db::DPoint p1 = m_original.p1 () + dp;
|
||||
db::DPoint p2 = m_original.p2 () + dp;
|
||||
|
||||
std::pair<bool, db::DPoint> r1 = snap1 (p1, m_obj_snap && m_original.snap ());
|
||||
db::DPoint q1 = r1.second;
|
||||
std::pair<bool, db::DPoint> r2 = snap1 (p2, m_obj_snap && m_original.snap ());
|
||||
db::DPoint q2 = r2.second;
|
||||
|
||||
if ((!r2.first && r1.first) || ((r1.first || (!r1.first && !r2.first)) && q1.distance (p1) < q2.distance (p2))) {
|
||||
q2 = q1 + (m_original.p2 () - m_original.p1 ());
|
||||
} else {
|
||||
q1 = q2 + (m_original.p1 () - m_original.p2 ());
|
||||
}
|
||||
|
||||
m_current.p1 (q1);
|
||||
m_current.p2 (q2);
|
||||
|
||||
m_rulers [0]->redraw ();
|
||||
|
||||
} else if (m_move_mode == MoveSelected) {
|
||||
|
||||
db::DVector dp = p - m_p1;
|
||||
// round the drag distance to grid if required: this is the least we can do in this case
|
||||
if (m_grid_snap) {
|
||||
dp = db::DVector (lay::snap (dp.x (), m_grid), lay::snap (dp.y (), m_grid));
|
||||
}
|
||||
|
||||
dp = lay::snap_angle (dp, ac == lay::AC_Global ? m_snap_mode : ac);
|
||||
dp = lay::snap_angle (dp, ac_eff);
|
||||
|
||||
m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
|
||||
|
||||
snap_rulers (ac_eff);
|
||||
|
||||
for (std::vector<ant::View *>::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
|
||||
(*r)->transform_by (db::DCplxTrans (m_trans));
|
||||
}
|
||||
|
|
@ -1646,7 +1664,6 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
|
|||
if (m_move_mode != MoveSelected) {
|
||||
show_message ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1703,6 +1720,7 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
|
|||
// termine the operation
|
||||
m_move_mode = MoveNone;
|
||||
|
||||
clear_mouse_cursors ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1766,6 +1784,7 @@ Service::edit_cancel ()
|
|||
if (m_move_mode != MoveNone) {
|
||||
|
||||
m_move_mode = MoveNone;
|
||||
m_selected.clear ();
|
||||
selection_to_view ();
|
||||
|
||||
}
|
||||
|
|
@ -2039,7 +2058,7 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
|||
// otherwise we risk manipulating p1 too.
|
||||
ant::Object::point_list pts = m_current.points ();
|
||||
if (! pts.empty ()) {
|
||||
pts.back () = snap2 (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)).second;
|
||||
pts.back () = snap_details.snapped_point;
|
||||
}
|
||||
m_current.set_points_exact (pts);
|
||||
|
||||
|
|
@ -2094,11 +2113,16 @@ Service::snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::O
|
|||
return lay::obj_snap (m_obj_snap && obj->snap () ? mp_view : 0, p1, p2, g, snap_mode, snap_range);
|
||||
}
|
||||
|
||||
std::pair <bool, db::DPoint>
|
||||
Service::snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac)
|
||||
db::DPoint
|
||||
Service::snap2_visual (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac)
|
||||
{
|
||||
lay::PointSnapToObjectResult res = snap2_details (p1, p2, obj, ac);
|
||||
return std::make_pair (res.object_snap != lay::PointSnapToObjectResult::NoObject, res.snapped_point);
|
||||
|
||||
if (res.object_snap != lay::PointSnapToObjectResult::NoObject) {
|
||||
mouse_cursor_from_snap_details (res);
|
||||
}
|
||||
|
||||
return res.snapped_point;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -208,10 +208,9 @@ public:
|
|||
* MoveP2X - dragging P2.x (if box-like)
|
||||
* MoveP1Y - dragging P1.y (if box-like)
|
||||
* MoveP2Y - dragging P2.y (if box-like)
|
||||
* MoveRuler - dragging a whole ruler (one)
|
||||
* MoveSelection - dragging a whole ruler (many)
|
||||
*/
|
||||
enum MoveMode { MoveNone, MoveP1, MoveP2, MoveP12, MoveP21, MoveP1X, MoveP2X, MoveP1Y, MoveP2Y, MoveRuler, MoveSelected };
|
||||
enum MoveMode { MoveNone, MoveP1, MoveP2, MoveP12, MoveP21, MoveP1X, MoveP2X, MoveP1Y, MoveP2Y, MoveSelected };
|
||||
|
||||
Service (db::Manager *manager, lay::LayoutViewBase *view);
|
||||
|
||||
|
|
@ -601,7 +600,7 @@ private:
|
|||
|
||||
std::pair<bool, db::DPoint> snap1 (const db::DPoint &p, bool obj_snap);
|
||||
lay::PointSnapToObjectResult snap1_details (const db::DPoint &p, bool obj_snap);
|
||||
std::pair<bool, db::DPoint> snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
|
||||
db::DPoint snap2_visual (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
|
||||
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
|
||||
lay::TwoPointSnapToObjectResult auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl);
|
||||
|
||||
|
|
@ -620,6 +619,8 @@ private:
|
|||
virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
virtual void deactivated ();
|
||||
|
||||
void snap_rulers (lay::angle_constraint_type ac);
|
||||
|
||||
/**
|
||||
* @brief Select a certain ruler
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,10 +42,18 @@ public:
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
GenericRasterizer (const db::Polygon &fp, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, const db::Vector &dim)
|
||||
GenericRasterizer (const std::vector<db::Polygon> &fr, const db::Box &rasterized_area, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, const db::Vector &dim)
|
||||
: m_row_step (row_step), m_column_step (column_step), m_row_steps (0), m_column_steps (0), m_origin (origin), m_dim (dim)
|
||||
{
|
||||
rasterize (fp);
|
||||
rasterize (rasterized_area, fr);
|
||||
}
|
||||
|
||||
GenericRasterizer (const db::Polygon &fp, const db::Box &rasterized_area, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, const db::Vector &dim)
|
||||
: m_row_step (row_step), m_column_step (column_step), m_row_steps (0), m_column_steps (0), m_origin (origin), m_dim (dim)
|
||||
{
|
||||
std::vector<db::Polygon> fr;
|
||||
fr.push_back (fp);
|
||||
rasterize (rasterized_area, fr);
|
||||
}
|
||||
|
||||
void move (const db::Vector &d)
|
||||
|
|
@ -59,7 +67,44 @@ public:
|
|||
m_area_maps.clear ();
|
||||
}
|
||||
|
||||
void rasterize (const db::Polygon &fp)
|
||||
const db::Point &p0 () const { return m_origin; }
|
||||
|
||||
unsigned int row_steps () const { return m_row_steps; }
|
||||
unsigned int column_steps () const { return m_column_steps; }
|
||||
|
||||
unsigned int area_maps () const
|
||||
{
|
||||
return (unsigned int) m_area_maps.size ();
|
||||
}
|
||||
|
||||
int index_for_p0 (const db::Point &p0) const
|
||||
{
|
||||
for (auto i = m_area_maps.begin (); i != m_area_maps.end (); ++i) {
|
||||
if (i->p0 () == p0) {
|
||||
return int (i - m_area_maps.begin ());
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const db::AreaMap &area_map (unsigned int i) const
|
||||
{
|
||||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
db::AreaMap &area_map (unsigned int i)
|
||||
{
|
||||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<db::AreaMap> m_area_maps;
|
||||
db::Vector m_row_step, m_column_step;
|
||||
unsigned int m_row_steps, m_column_steps;
|
||||
db::Point m_origin;
|
||||
db::Vector m_dim;
|
||||
|
||||
void rasterize (const db::Box &rasterized_area, const std::vector<db::Polygon> &fr)
|
||||
{
|
||||
db::Coord dx = m_row_step.x ();
|
||||
db::Coord dy = m_column_step.y ();
|
||||
|
|
@ -81,12 +126,12 @@ public:
|
|||
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
|
||||
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
|
||||
|
||||
db::Box fp_bbox = fp.box ();
|
||||
db::Box ra_org = rasterized_area;
|
||||
|
||||
// compensate for distortion by sheared kernel
|
||||
db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
|
||||
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
|
||||
fp_bbox.enlarge (db::Vector (ex, ey));
|
||||
ra_org.enlarge (db::Vector (ex, ey));
|
||||
|
||||
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
|
||||
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
|
||||
|
|
@ -95,16 +140,16 @@ public:
|
|||
db::Coord ddy = dy * db::Coord (m_column_steps) - m_row_step.y () * rows_per_columns;
|
||||
|
||||
// round polygon bbox
|
||||
db::Coord fp_left = db::Coord (tl::round_down (fp_bbox.left () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord fp_bottom = db::Coord (tl::round_down (fp_bbox.bottom () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
db::Coord fp_right = db::Coord (tl::round_up (fp_bbox.right () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord fp_top = db::Coord (tl::round_up (fp_bbox.top () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
fp_bbox = db::Box (fp_left, fp_bottom, fp_right, fp_top);
|
||||
db::Coord ra_left = db::Coord (tl::round_down (ra_org.left () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord ra_bottom = db::Coord (tl::round_down (ra_org.bottom () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
db::Coord ra_right = db::Coord (tl::round_up (ra_org.right () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord ra_top = db::Coord (tl::round_up (ra_org.top () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
db::Box ra = db::Box (ra_left, ra_bottom, ra_right, ra_top);
|
||||
|
||||
size_t nx = fp_bbox.width () / ddx;
|
||||
size_t ny = fp_bbox.height () / ddy;
|
||||
size_t nx = ra.width () / ddx;
|
||||
size_t ny = ra.height () / ddy;
|
||||
|
||||
tl_assert (fp.box ().inside (fp_bbox));
|
||||
tl_assert (ra_org.inside (ra));
|
||||
|
||||
if (nx == 0 || ny == 0) {
|
||||
// nothing to rasterize:
|
||||
|
|
@ -122,9 +167,15 @@ public:
|
|||
db::Vector dr = m_row_step * long (ir);
|
||||
db::Vector dc = m_column_step * long (ic);
|
||||
|
||||
am.reinitialize (db::Point (fp_left, fp_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
am.reinitialize (db::Point (ra_left, ra_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
|
||||
if (db::rasterize (fp, am)) {
|
||||
bool any = false;
|
||||
for (auto i = fr.begin (); i != fr.end (); ++i) {
|
||||
if (db::rasterize (*i, am)) {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
if (any) {
|
||||
m_area_maps.push_back (db::AreaMap ());
|
||||
m_area_maps.back ().swap (am);
|
||||
}
|
||||
|
|
@ -142,9 +193,15 @@ public:
|
|||
db::Vector dr = m_row_step * long ((rows_per_columns > 0 ? -int (ir + 1) : ir) + m_row_steps);
|
||||
db::Vector dc = m_column_step * long ((columns_per_rows > 0 ? -int (ic + 1) : ic) + m_column_steps);
|
||||
|
||||
am.reinitialize (db::Point (fp_left, fp_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
am.reinitialize (db::Point (ra_left, ra_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
|
||||
if (db::rasterize (fp, am)) {
|
||||
bool any = false;
|
||||
for (auto i = fr.begin (); i != fr.end (); ++i) {
|
||||
if (db::rasterize (*i, am)) {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
if (any) {
|
||||
m_area_maps.push_back (db::AreaMap ());
|
||||
m_area_maps.back ().swap (am);
|
||||
}
|
||||
|
|
@ -153,39 +210,107 @@ public:
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
const db::Point &p0 () const { return m_origin; }
|
||||
|
||||
unsigned int row_steps () const { return m_row_steps; }
|
||||
unsigned int column_steps () const { return m_column_steps; }
|
||||
|
||||
unsigned int area_maps () const
|
||||
{
|
||||
return (unsigned int) m_area_maps.size ();
|
||||
}
|
||||
|
||||
const db::AreaMap &area_map (unsigned int i) const
|
||||
{
|
||||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
db::AreaMap &area_map (unsigned int i)
|
||||
{
|
||||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<db::AreaMap> m_area_maps;
|
||||
db::Vector m_row_step, m_column_step;
|
||||
unsigned int m_row_steps, m_column_steps;
|
||||
db::Point m_origin;
|
||||
db::Vector m_dim;
|
||||
};
|
||||
|
||||
static size_t
|
||||
create_instances (GenericRasterizer &am, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &fill_margin, const GenericRasterizer *exclude_rasterized, std::vector<db::Polygon> *filled_regions)
|
||||
{
|
||||
size_t ninsts = 0;
|
||||
|
||||
for (unsigned int i = 0; i < am.area_maps (); ++i) {
|
||||
|
||||
db::AreaMap &am1 = am.area_map (i);
|
||||
const db::AreaMap *am1_excl = 0;
|
||||
if (exclude_rasterized) {
|
||||
int ie = exclude_rasterized->index_for_p0 (am1.p0 ());
|
||||
if (ie >= 0) {
|
||||
am1_excl = &exclude_rasterized->area_map (ie);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nx = am1.nx ();
|
||||
size_t ny = am1.ny ();
|
||||
|
||||
// Create the fill cell instances
|
||||
for (size_t i = 0; i < nx; ++i) {
|
||||
|
||||
for (size_t j = 0; j < ny; ) {
|
||||
|
||||
size_t jj = j + 1;
|
||||
if (am1.get (i, j) == am1.pixel_area () && (!am1_excl || am1_excl->get (i, j) == 0)) {
|
||||
|
||||
while (jj != ny && am1.get (i, jj) == am1.pixel_area () && (!am1_excl || am1_excl->get (i, jj) == 0)) {
|
||||
++jj;
|
||||
}
|
||||
|
||||
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
|
||||
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
|
||||
|
||||
db::CellInstArray array;
|
||||
|
||||
// try to expand the array in x direction
|
||||
size_t ii = i + 1;
|
||||
for ( ; ii < nx; ++ii) {
|
||||
bool all = true;
|
||||
for (size_t k = j; k < jj && all; ++k) {
|
||||
all = (am1.get (ii, k) == am1.pixel_area () && (!am1_excl || am1_excl->get (ii, k) == 0));
|
||||
}
|
||||
if (all) {
|
||||
for (size_t k = j; k < jj; ++k) {
|
||||
// disable pixel, so we do not see it again in the following columns
|
||||
am1.get (ii, k) = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ninsts += (jj - j) * (ii - i);
|
||||
|
||||
if (jj > j + 1 || ii > i + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
|
||||
} else {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
|
||||
}
|
||||
|
||||
{
|
||||
// In case we run this from a tiling processor we need to lock against multithread races
|
||||
tl_assert (cell->layout () != 0);
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->insert (array);
|
||||
}
|
||||
|
||||
if (filled_regions) {
|
||||
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
|
||||
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
|
||||
filled_regions->push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
|
||||
} else {
|
||||
db::Box fill_box (db::Point (), db::Point () + am1.p ());
|
||||
fill_box.enlarge (fill_margin);
|
||||
for (size_t k = 0; k < jj - j; ++k) {
|
||||
for (size_t l = 0; l < ii - i; ++l) {
|
||||
filled_regions->push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
j = jj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ninsts;
|
||||
}
|
||||
|
||||
static bool
|
||||
fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box)
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
if (row_step.x () <= 0 || column_step.y () <= 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row step must have a positive x component while column step must have a positive y component")));
|
||||
|
|
@ -197,156 +322,155 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
|
||||
db::Vector kernel_origin (fc_bbox.left (), fc_bbox.bottom ());
|
||||
|
||||
std::vector <db::Polygon> filled_regions;
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
// under- and oversize the polygon to remove slivers that cannot be filled.
|
||||
db::Coord dx = fc_bbox.width () / 2 - 1, dy = fc_bbox.height () / 2 - 1;
|
||||
|
||||
std::vector <db::Polygon> fpa;
|
||||
std::vector <db::Polygon> fpb;
|
||||
fpa.push_back (fp0);
|
||||
db::Region fr (fp0);
|
||||
db::Box rasterized_area = fp0.box ();
|
||||
|
||||
ep.size (fpa, -dx, 0, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
std::unique_ptr<GenericRasterizer> exclude_rasterized;
|
||||
bool has_exclude_area = false;
|
||||
|
||||
ep.size (fpa, dx, 0, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
if (! exclude_area.empty ()) {
|
||||
|
||||
ep.size (fpa, 0, -dy, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
auto it = exclude_area.begin_iter ();
|
||||
it.first.confine_region (fp0.box ());
|
||||
|
||||
ep.size (fpa, 0, dy, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
// over- and undersize the polygons to fill gaps that cannot be filled.
|
||||
db::Region excluded (it.first, it.second);
|
||||
excluded.set_merged_semantics (false);
|
||||
excluded.size (dx, 0);
|
||||
excluded.set_merged_semantics (true);
|
||||
excluded.size (-dx, 0);
|
||||
excluded.set_merged_semantics (false);
|
||||
excluded.size (dy, 0);
|
||||
excluded.set_merged_semantics (true);
|
||||
excluded.size (-dy, 0);
|
||||
excluded.merge ();
|
||||
|
||||
ep.simple_merge (fpa, fpb, false /*=don't resolve holes*/);
|
||||
if (! excluded.empty ()) {
|
||||
|
||||
filled_regions.clear ();
|
||||
bool any_fill = false;
|
||||
has_exclude_area = true;
|
||||
|
||||
for (std::vector <db::Polygon>::const_iterator fp = fpb.begin (); fp != fpb.end (); ++fp) {
|
||||
if (enhanced_fill || remaining_parts != 0) {
|
||||
|
||||
if (fp->hull ().size () == 0) {
|
||||
continue;
|
||||
}
|
||||
// In enhanced fill or if the remaining parts are requested, it is better to implement the
|
||||
// exclude area by a boolean NOT
|
||||
fr -= excluded;
|
||||
|
||||
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
|
||||
bool ef = enhanced_fill;
|
||||
if (ef && ! glue_box.empty () && ! fp->box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
|
||||
ef = false;
|
||||
}
|
||||
} else {
|
||||
|
||||
// pick a heuristic "good" starting point in enhanced mode
|
||||
// TODO: this is a pretty weak optimization.
|
||||
db::Point o = origin;
|
||||
if (ef) {
|
||||
o = fp->hull () [0];
|
||||
}
|
||||
|
||||
size_t ninsts = 0;
|
||||
|
||||
GenericRasterizer am (*fp, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ());
|
||||
|
||||
for (unsigned int i = 0; i < am.area_maps (); ++i) {
|
||||
|
||||
db::AreaMap &am1 = am.area_map (i);
|
||||
|
||||
size_t nx = am1.nx ();
|
||||
size_t ny = am1.ny ();
|
||||
|
||||
// Create the fill cell instances
|
||||
for (size_t i = 0; i < nx; ++i) {
|
||||
|
||||
for (size_t j = 0; j < ny; ) {
|
||||
|
||||
size_t jj = j + 1;
|
||||
if (am1.get (i, j) == am1.pixel_area ()) {
|
||||
|
||||
while (jj != ny && am1.get (i, jj) == am1.pixel_area ()) {
|
||||
++jj;
|
||||
}
|
||||
|
||||
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
|
||||
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
|
||||
|
||||
db::CellInstArray array;
|
||||
|
||||
// try to expand the array in x direction
|
||||
size_t ii = i + 1;
|
||||
for ( ; ii < nx; ++ii) {
|
||||
bool all = true;
|
||||
for (size_t k = j; k < jj && all; ++k) {
|
||||
all = am1.get (ii, k) == am1.pixel_area ();
|
||||
}
|
||||
if (all) {
|
||||
for (size_t k = j; k < jj; ++k) {
|
||||
// disable pixel, so we do not see it again in the following columns
|
||||
am1.get (ii, k) = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ninsts += (jj - j) * (ii - i);
|
||||
|
||||
if (jj > j + 1 || ii > i + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
|
||||
} else {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
|
||||
}
|
||||
|
||||
{
|
||||
// In case we run this from a tiling processor we need to lock against multithread races
|
||||
tl_assert (cell->layout () != 0);
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->insert (array);
|
||||
}
|
||||
|
||||
if (remaining_parts) {
|
||||
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
|
||||
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
|
||||
filled_regions.push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
|
||||
} else {
|
||||
db::Box fill_box (db::Point (), db::Point () + am1.p ());
|
||||
fill_box.enlarge (fill_margin);
|
||||
for (size_t k = 0; k < jj - j; ++k) {
|
||||
for (size_t l = 0; l < ii - i; ++l) {
|
||||
filled_regions.push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
any_fill = true;
|
||||
|
||||
}
|
||||
|
||||
j = jj;
|
||||
// Otherwise use a second rasterizer for the exclude polygons that must have a zero pixel coverage for the
|
||||
// pixel to be filled.
|
||||
|
||||
std::vector<db::Polygon> excluded_poly;
|
||||
excluded_poly.reserve (excluded.count ());
|
||||
for (auto i = excluded.begin (); ! i.at_end (); ++i) {
|
||||
excluded_poly.push_back (*i);
|
||||
}
|
||||
excluded.clear ();
|
||||
|
||||
exclude_rasterized.reset (new GenericRasterizer (excluded_poly, rasterized_area, row_step, column_step, origin, fc_bbox.p2 () - fc_bbox.p1 ()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector <db::Polygon> filled_poly, filled_poly_uncleaned;
|
||||
|
||||
// save the uncleaned polygons, so we subtract the filled parts to
|
||||
// form the remaining parts
|
||||
if (remaining_parts) {
|
||||
filled_poly_uncleaned.reserve (fr.count ());
|
||||
for (auto i = fr.begin (); ! i.at_end (); ++i) {
|
||||
filled_poly_uncleaned.push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
// under- and oversize the polygon to remove slivers that cannot be filled.
|
||||
fr.set_merged_semantics (true);
|
||||
fr.size (-dx, 0);
|
||||
fr.set_merged_semantics (false);
|
||||
fr.size (dx, 0);
|
||||
fr.set_merged_semantics (true);
|
||||
fr.size (0, -dy);
|
||||
fr.set_merged_semantics (false);
|
||||
fr.size (0, dy);
|
||||
fr.set_merged_semantics (true);
|
||||
fr.merge ();
|
||||
|
||||
filled_poly.reserve (fr.count ());
|
||||
for (auto i = fr.begin (); ! i.at_end (); ++i) {
|
||||
filled_poly.push_back (*i);
|
||||
}
|
||||
|
||||
fr.clear ();
|
||||
|
||||
std::vector <db::Polygon> filled_regions;
|
||||
bool any_fill = false;
|
||||
|
||||
if (filled_poly.empty ()) {
|
||||
|
||||
// not need to do anything
|
||||
|
||||
} else if (exclude_rasterized.get ()) {
|
||||
|
||||
tl_assert (remaining_parts == 0);
|
||||
GenericRasterizer am (filled_poly, rasterized_area, row_step, column_step, origin, fc_bbox.p2 () - fc_bbox.p1 ());
|
||||
|
||||
size_t ninsts = create_instances (am, cell, fill_cell_index, kernel_origin, fill_margin, exclude_rasterized.get (), 0);
|
||||
if (ninsts > 0) {
|
||||
any_fill = true;
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 30 && ninsts > 0) {
|
||||
tl::info << "Part " << fp->to_string ();
|
||||
tl::info << "Part " << fp0.to_string ();
|
||||
tl::info << "Created " << ninsts << " instances";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (auto fp = filled_poly.begin (); fp != filled_poly.end (); ++fp) {
|
||||
|
||||
if (fp->is_empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
|
||||
bool ef = enhanced_fill;
|
||||
if (ef && ! glue_box.empty () && ! fp->box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
|
||||
ef = false;
|
||||
}
|
||||
|
||||
// pick a heuristic "good" starting point in enhanced mode
|
||||
// TODO: this is a pretty weak optimization.
|
||||
db::Point o = origin;
|
||||
if (ef) {
|
||||
o = fp->hull () [0];
|
||||
}
|
||||
|
||||
GenericRasterizer am (*fp, rasterized_area, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ());
|
||||
|
||||
size_t ninsts = create_instances (am, cell, fill_cell_index, kernel_origin, fill_margin, 0, remaining_parts ? &filled_regions : 0);
|
||||
if (ninsts > 0) {
|
||||
any_fill = true;
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 30 && ninsts > 0) {
|
||||
tl::info << "Part " << fp->to_string ();
|
||||
tl::info << "Created " << ninsts << " instances";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (any_fill) {
|
||||
if (any_fill || has_exclude_area) {
|
||||
|
||||
if (remaining_parts) {
|
||||
std::vector <db::Polygon> fp1;
|
||||
fp1.push_back (fp0);
|
||||
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
|
||||
db::EdgeProcessor ep;
|
||||
ep.boolean (filled_poly_uncleaned, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -358,25 +482,25 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box)
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_box, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, glue_box);
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_box, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box)
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
if (fc_bbox.empty () || fc_bbox.width () == 0 || fc_bbox.height () == 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)")));
|
||||
}
|
||||
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_bbox, db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), origin, enhanced_fill, remaining_parts, fill_margin, glue_box);
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_bbox, db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), origin, enhanced_fill, remaining_parts, fill_margin, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, int iteration, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, int iteration, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
if (row_step.x () <= 0 || column_step.y () <= 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row step must have a positive x component while column step must have a positive y component")));
|
||||
|
|
@ -403,7 +527,7 @@ fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill
|
|||
tl::RelativeProgress progress (progress_title, n);
|
||||
|
||||
for (db::Region::const_iterator p = fr.begin_merged (); !p.at_end (); ++p) {
|
||||
if (! fill_polygon_impl (cell, *p, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin, glue_box)) {
|
||||
if (! fill_polygon_impl (cell, *p, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin, glue_box, exclude_area)) {
|
||||
if (remaining_polygons) {
|
||||
rem_poly.push_back (*p);
|
||||
}
|
||||
|
|
@ -433,27 +557,27 @@ fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill
|
|||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
fill_region_impl (cell, fr, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box);
|
||||
fill_region_impl (cell, fr, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
if (fc_bbox.empty () || fc_bbox.width () == 0 || fc_bbox.height () == 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)")));
|
||||
}
|
||||
|
||||
fill_region_impl (cell, fr, fill_cell_index, fc_bbox, db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()),
|
||||
origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box);
|
||||
origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index,
|
||||
const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
const db::Region *fill_region = &fr;
|
||||
|
||||
|
|
@ -467,7 +591,7 @@ fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fi
|
|||
++iteration;
|
||||
|
||||
remaining.clear ();
|
||||
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration, glue_box);
|
||||
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration, glue_box, exclude_area);
|
||||
|
||||
new_fill_region.swap (remaining);
|
||||
fill_region = &new_fill_region;
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@
|
|||
|
||||
#include "dbTypes.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Cell;
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* @brief Creates a tiling pattern for a single polygon using a fill cell which is repeated periodically
|
||||
|
|
@ -41,6 +41,7 @@ class Region;
|
|||
* @param column_step (some_versions) The column advance vector of the fill cell. By default this is (0, fc_bbox.height())
|
||||
* @param origin Specifies the origin of the fill raster if enhanced_fill is false
|
||||
* @param enhanced_fill If set, the tiling offset will be optimized such that as much tiling cells fit into each polygon
|
||||
* @param exclude_area The region which fill cells must not overlap
|
||||
*
|
||||
* Optional parameters:
|
||||
*
|
||||
|
|
@ -79,12 +80,16 @@ class Region;
|
|||
*/
|
||||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (),
|
||||
const db::Box &glue_box = db::Box ());
|
||||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (),
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -98,12 +103,16 @@ fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cel
|
|||
*/
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0,
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0,
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
/**
|
||||
* @brief An iterative version for enhanced fill
|
||||
|
|
@ -118,6 +127,7 @@ fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell
|
|||
DB_PUBLIC void
|
||||
fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index,
|
||||
const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons = 0,
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1780,7 +1780,7 @@ Layout::force_update ()
|
|||
// NOTE: the assumption is that either one thread is writing or
|
||||
// multiple threads are reading. Hence, we do not need to lock hier_dirty() or bboxes_dirty().
|
||||
// We still do double checking as another thread might do the update as well.
|
||||
if (! hier_dirty () && ! bboxes_dirty ()) {
|
||||
if (! update_needed ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1829,10 +1829,16 @@ Layout::update () const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::update_needed () const
|
||||
{
|
||||
return hier_dirty () || bboxes_dirty ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::do_update ()
|
||||
{
|
||||
if (! hier_dirty () && ! bboxes_dirty ()) {
|
||||
if (! update_needed ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1619,6 +1619,14 @@ public:
|
|||
*/
|
||||
top_down_const_iterator end_top_cells () const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether an update is needed
|
||||
*
|
||||
* If this value is false, update or force_update will not
|
||||
* do anything.
|
||||
*/
|
||||
bool update_needed () const;
|
||||
|
||||
/**
|
||||
* @brief Provide a const version of the update method
|
||||
*
|
||||
|
|
|
|||
|
|
@ -511,7 +511,7 @@ MeasureNetEval::put_func (const tl::Variant &name, const tl::Variant &value) con
|
|||
MeasureNetEval::AreaAndPerimeter
|
||||
MeasureNetEval::compute_area_and_perimeter (int layer_index) const
|
||||
{
|
||||
if (layer_index < 0 || layer_index >= (unsigned int) m_layers.size ()) {
|
||||
if (layer_index < 0 || layer_index >= (int) m_layers.size ()) {
|
||||
return AreaAndPerimeter ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1512,16 +1512,17 @@ public:
|
|||
* @param tr The transformation to apply on assignment
|
||||
* @param compress True, if the contours shall be compressed
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class D, class T>
|
||||
polygon (const db::polygon<D> &p, const T &tr, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
polygon (const db::polygon<D> &p, const T &tr, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
// create an entry for the hull contour
|
||||
m_bbox = box_type (tr (p.box ().p1 ()), tr (p.box ().p2 ()));
|
||||
m_ctrs.resize (p.holes () + 1);
|
||||
m_ctrs [0].assign (p.begin_hull (), p.end_hull (), tr, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [0].assign (p.begin_hull (), p.end_hull (), tr, false, compress, normalize, remove_reflected);
|
||||
for (unsigned int i = 0; i < m_ctrs.size () - 1; ++i) {
|
||||
m_ctrs [i + 1].assign (p.begin_hole (i), p.end_hole (i), tr, true, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [i + 1].assign (p.begin_hole (i), p.end_hole (i), tr, true, compress, normalize, remove_reflected);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1533,16 +1534,16 @@ public:
|
|||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
*/
|
||||
template <class D>
|
||||
explicit polygon (const db::polygon<D> &p, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
explicit polygon (const db::polygon<D> &p, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
db::point_coord_converter<C, D> tr;
|
||||
|
||||
// create an entry for the hull contour
|
||||
m_bbox = box_type (tr (p.box ().p1 ()), tr (p.box ().p2 ()));
|
||||
m_ctrs.resize (p.holes () + 1);
|
||||
m_ctrs [0].assign (p.begin_hull (), p.end_hull (), tr, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [0].assign (p.begin_hull (), p.end_hull (), tr, false, compress, normalize, remove_reflected);
|
||||
for (unsigned int i = 0; i < m_ctrs.size () - 1; ++i) {
|
||||
m_ctrs [i + 1].assign (p.begin_hole (i), p.end_hole (i), tr, true, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [i + 1].assign (p.begin_hole (i), p.end_hole (i), tr, true, compress, normalize, remove_reflected);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2072,11 +2073,12 @@ public:
|
|||
* @param end The end of the sequence of points for the contour
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class I>
|
||||
void assign_hull (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void assign_hull (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
m_ctrs [0].assign (start, end, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [0].assign (start, end, false, compress, normalize, remove_reflected);
|
||||
m_bbox = m_ctrs [0].bbox ();
|
||||
}
|
||||
|
||||
|
|
@ -2089,14 +2091,15 @@ public:
|
|||
* so it is oriented properly.
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*
|
||||
* @param start The start of the sequence of points for the contour
|
||||
* @param end The end of the sequence of points for the contour
|
||||
*/
|
||||
template <class I, class T>
|
||||
void assign_hull (I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void assign_hull (I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
m_ctrs [0].assign (start, end, op, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [0].assign (start, end, op, false, compress, normalize, remove_reflected);
|
||||
m_bbox = m_ctrs [0].bbox ();
|
||||
}
|
||||
|
||||
|
|
@ -2128,11 +2131,12 @@ public:
|
|||
* @param end The end of the sequence of points for the contour
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class I>
|
||||
void assign_hole (unsigned int h, I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void assign_hole (unsigned int h, I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
m_ctrs [h + 1].assign (start, end, true, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [h + 1].assign (start, end, true, compress, normalize, remove_reflected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2144,14 +2148,15 @@ public:
|
|||
* so it is oriented properly.
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*
|
||||
* @param start The start of the sequence of points for the contour
|
||||
* @param end The end of the sequence of points for the contour
|
||||
*/
|
||||
template <class I, class T>
|
||||
void assign_hole (unsigned int h, I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void assign_hole (unsigned int h, I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
m_ctrs [h + 1].assign (start, end, op, true, compress, true /*normalize*/, remove_reflected);
|
||||
m_ctrs [h + 1].assign (start, end, op, true, compress, normalize, remove_reflected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2183,11 +2188,12 @@ public:
|
|||
* @param end The end of the sequence of points for the contour
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class I>
|
||||
void insert_hole (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void insert_hole (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
insert_hole (start, end, db::unit_trans<C> (), compress, remove_reflected);
|
||||
insert_hole (start, end, db::unit_trans<C> (), compress, remove_reflected, normalize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2204,13 +2210,14 @@ public:
|
|||
* @param end The end of the sequence of points for the contour
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class I, class T>
|
||||
void insert_hole (I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void insert_hole (I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
// add the hole
|
||||
contour_type &h = add_hole ();
|
||||
h.assign (start, end, op, true, compress, true /*normalize*/, remove_reflected);
|
||||
h.assign (start, end, op, true, compress, normalize, remove_reflected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2637,13 +2644,14 @@ public:
|
|||
* @param tr The transformation to apply
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class D, class T>
|
||||
simple_polygon (const db::simple_polygon<D> &p, const T &tr, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
simple_polygon (const db::simple_polygon<D> &p, const T &tr, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
// create an entry for the hull contour
|
||||
m_bbox = box_type (tr (p.box ().p1 ()), tr (p.box ().p2 ()));
|
||||
m_hull.assign (p.begin_hull (), p.end_hull (), tr, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_hull.assign (p.begin_hull (), p.end_hull (), tr, false, compress, normalize, remove_reflected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2652,15 +2660,16 @@ public:
|
|||
* @param p The source polygon
|
||||
* @param compress true, if the sequence shall be compressed (colinear points removed)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class D>
|
||||
explicit simple_polygon (const db::simple_polygon<D> &p, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
explicit simple_polygon (const db::simple_polygon<D> &p, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
db::point_coord_converter<C, D> tr;
|
||||
|
||||
// create an entry for the hull contour
|
||||
m_bbox = box_type (tr (p.box ().p1 ()), tr (p.box ().p2 ()));
|
||||
m_hull.assign (p.begin_hull (), p.end_hull (), tr, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_hull.assign (p.begin_hull (), p.end_hull (), tr, false, compress, normalize, remove_reflected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2992,11 +3001,12 @@ public:
|
|||
* @param end The end of the sequence of points for the contour
|
||||
* @param compress true, if the sequence shall be compressed (colinear segments joined)
|
||||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
* @param normalize If true, the orientation is normalized
|
||||
*/
|
||||
template <class I, class T>
|
||||
void assign_hull (I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void assign_hull (I start, I end, T op, bool compress = default_compression<C> (), bool remove_reflected = false, bool normalize = true)
|
||||
{
|
||||
m_hull.assign (start, end, op, false, compress, true /*normalize*/, remove_reflected);
|
||||
m_hull.assign (start, end, op, false, compress, normalize, remove_reflected);
|
||||
m_bbox = m_hull.bbox ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1441,8 +1441,10 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
if (! layout ()) {
|
||||
|
||||
if (needs_translate (tag)) {
|
||||
|
||||
return reinsert_member_with_props (tag, ref, sh);
|
||||
} else {
|
||||
|
||||
} else if (! ref.has_prop_id ()) {
|
||||
|
||||
// simple replace case
|
||||
|
||||
|
|
@ -1459,7 +1461,21 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, sh);
|
||||
}
|
||||
|
||||
return ref;
|
||||
} else {
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<db::object_with_properties<Sh>, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (typename db::object_with_properties<Sh>::tag ()));
|
||||
}
|
||||
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
||||
db::object_with_properties<Sh> swp (sh, ref.prop_id ());
|
||||
get_layer<db::object_with_properties<Sh>, db::stable_layer_tag> ().replace (ref.basic_iter (typename db::object_with_properties<Sh>::tag ()), swp);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
db::layer_op<db::object_with_properties<Sh>, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, swp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1514,9 +1530,9 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
|
||||
}
|
||||
|
||||
return ref;
|
||||
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ Writer::write (db::Layout &layout, tl::OutputStream &stream)
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Writing file: ")) + stream.path ());
|
||||
|
||||
if (layout.under_construction ()) {
|
||||
if (layout.under_construction () && layout.update_needed ()) {
|
||||
tl::warn << tl::to_string (tr ("Cannot properly write a layout that is under construction - forcing update."));
|
||||
layout.force_update ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1510,23 +1510,23 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::
|
|||
|
||||
static void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_skew (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_multi (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t)
|
||||
|
|
@ -2215,6 +2215,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief Fills the given region with cells of the given type (extended version)\n"
|
||||
"@param region The region to fill\n"
|
||||
"@param fill_cell_index The fill cell to place\n"
|
||||
|
|
@ -2224,6 +2225,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"@param fill_margin See explanation below\n"
|
||||
"@param remaining_polygons See explanation below\n"
|
||||
"@param glue_box Guarantees fill cell compatibility to neighbor regions in enhanced mode\n"
|
||||
"@param exclude_area A region that defines the areas which are not be filled\n"
|
||||
"\n"
|
||||
"This method creates a regular pattern of fill cells to cover the interior of the given region as far as possible. "
|
||||
"This process is also known as tiling. This implementation supports rectangular (not necessarily square) tile cells. "
|
||||
|
|
@ -2236,6 +2238,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"The implementation will basically try to find a repetition pattern of the tile cell's footprint "
|
||||
"and produce instances which fit entirely into the fill region.\n"
|
||||
"If an exclude area is given, the fill cells also must not overlap that region.\n"
|
||||
"\n"
|
||||
"There is also a version available which offers skew step vectors as a generalization of the orthogonal ones.\n"
|
||||
"\n"
|
||||
|
|
@ -2246,8 +2249,11 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"If the 'remaining_polygons' argument is non-nil, the corresponding region will receive all polygons from the input region "
|
||||
"which could not be filled and where there is no chance of filling because not a single tile will fit into them.\n"
|
||||
"\n"
|
||||
"'remaining_parts' and 'remaining_polygons' can be identical with the input. In that case the input will be overwritten with "
|
||||
"'remaining_parts' and 'remaining_polygons' can point to the same Region object.\n"
|
||||
"They can also be identical with the input. In that case the input will be overwritten with "
|
||||
"the respective output. Otherwise, the respective polygons are added to these regions.\n"
|
||||
"'remaining_polygons' is not used if 'exclude_area' is present and non-empty. In that case, the\n"
|
||||
"original polygons, which cannot be filled at all, are copied to 'remaining_parts'.\n"
|
||||
"\n"
|
||||
"This allows setting up a more elaborate fill scheme using multiple iterations and local origin-optimization ('origin' is nil):\n"
|
||||
"\n"
|
||||
|
|
@ -2260,7 +2266,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"fill_margin = RBA::Point::new(0, 0) # x/y distance between tile cells with different origin\n"
|
||||
"\n"
|
||||
"# Iteration: fill a region and fill the remaining parts as long as there is anything left.\n"
|
||||
"# Polygons not worth being considered further are dropped (last argument is nil).\n"
|
||||
"# Polygons not worth being considered further are dropped ('remaining_polygons' argument is nil).\n"
|
||||
"while !r.is_empty?\n"
|
||||
" c.fill_region(r, fc_index, fc_box, nil, r, fill_margin, nil)\n"
|
||||
"end\n"
|
||||
|
|
@ -2275,7 +2281,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"at the raster implied by origin at the glue box border and beyond. To ensure fill cell compatibility inside the tiling processor, it is sufficient to use the tile "
|
||||
"box as the glue box.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23 and enhanced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.23 and enhanced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("fill_region", &fill_region_skew, gsi::arg ("region"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
|
|
@ -2287,16 +2293,18 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief Fills the given region with cells of the given type (skew step version)\n"
|
||||
"@param region The region to fill\n"
|
||||
"@param fill_cell_index The fill cell to place\n"
|
||||
"@param fc_bbox The fill cell's box to place\n"
|
||||
"@param fc_bbox The fill cell's box, defining the box that needs to be inside the fill region\n"
|
||||
"@param row_step The 'rows' step vector\n"
|
||||
"@param column_step The 'columns' step vector\n"
|
||||
"@param origin The global origin of the fill pattern or nil to allow local (per-polygon) optimization\n"
|
||||
"@param remaining_parts See explanation in other version\n"
|
||||
"@param fill_margin See explanation in other version\n"
|
||||
"@param remaining_polygons See explanation in other version\n"
|
||||
"@param exclude_area A region that defines the areas which are not be filled\n"
|
||||
"\n"
|
||||
"This version is similar to the version providing an orthogonal fill, but it offers more generic stepping of the fill cell.\n"
|
||||
"The step pattern is defined by an origin and two vectors (row_step and column_step) which span the axes of the fill cell pattern.\n"
|
||||
|
|
@ -2305,7 +2313,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"be overlapping and there can be space between the fill box instances. Fill boxes are placed where they fit entirely into a polygon of the region. "
|
||||
"The fill boxes lower left corner is the reference for the fill pattern and aligns with the origin if given.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
"This variant has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("fill_region_multi", &fill_region_multi, gsi::arg ("region"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
|
|
@ -2315,6 +2323,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief Fills the given region with cells of the given type in enhanced mode with iterations\n"
|
||||
"This version operates like \\fill_region, but repeats the fill generation until no further fill cells can be placed. "
|
||||
"As the fill pattern origin changes between the iterations, narrow regions can be filled which cannot with a fixed fill pattern origin. "
|
||||
|
|
@ -2323,7 +2332,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"The origin is ignored unless a glue box is given. See \\fill_region for a description of this concept.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("begin_shapes_rec", &begin_shapes_rec, gsi::arg ("layer"),
|
||||
"@brief Delivers a recursive shape iterator for the shapes below the cell on the given layer\n"
|
||||
|
|
|
|||
|
|
@ -1758,6 +1758,13 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"is ongoing or the layout is brought into invalid state by\n"
|
||||
"\"start_changes\".\n"
|
||||
) +
|
||||
gsi::method ("update_needed", &db::Layout::update_needed,
|
||||
"@brief Gets a value indicating whether the Layout object needs an update\n"
|
||||
"If this method returns false, \\update will not do anything. This is useful to force an update at "
|
||||
"specific times during 'under_construction' conditions.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30.4."
|
||||
) +
|
||||
gsi::method ("update", (void (db::Layout::*) ()) &db::Layout::force_update,
|
||||
"@brief Updates the internals of the layout\n"
|
||||
"This method updates the internal state of the layout. Usually this is done automatically\n"
|
||||
|
|
|
|||
|
|
@ -868,12 +868,12 @@ static db::SimplePolygon transformed_icplx_sp (const db::SimplePolygon *p, const
|
|||
|
||||
static db::SimplePolygon *spolygon_from_dspolygon (const db::DSimplePolygon &p)
|
||||
{
|
||||
return new db::SimplePolygon (p, false);
|
||||
return new db::SimplePolygon (p, false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static db::DSimplePolygon spolygon_to_dspolygon (const db::SimplePolygon *p, double dbu)
|
||||
{
|
||||
return db::DSimplePolygon (*p * dbu, false);
|
||||
return db::DSimplePolygon (*p, db::CplxTrans (dbu), false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
Class<db::SimplePolygon> decl_SimplePolygon ("db", "SimplePolygon",
|
||||
|
|
@ -1031,12 +1031,12 @@ Class<db::SimplePolygonWithProperties> decl_SimplePolygonWithProperties (decl_Si
|
|||
|
||||
static db::DSimplePolygon *dspolygon_from_ispolygon (const db::SimplePolygon &p)
|
||||
{
|
||||
return new db::DSimplePolygon (p, false);
|
||||
return new db::DSimplePolygon (p, false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static db::SimplePolygon dspolygon_to_spolygon (const db::DSimplePolygon *p, double dbu)
|
||||
{
|
||||
return db::SimplePolygon (*p * (1.0 / dbu), false);
|
||||
return db::SimplePolygon (*p, db::VCplxTrans (1.0 / dbu), false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static db::SimplePolygon transformed_vplx_sp (const db::DSimplePolygon *p, const db::VCplxTrans &t)
|
||||
|
|
@ -2036,12 +2036,12 @@ static db::Polygon minkowski_sum_pc (const db::Polygon *p, const std::vector<db:
|
|||
|
||||
static db::Polygon *polygon_from_dpolygon (const db::DPolygon &p)
|
||||
{
|
||||
return new db::Polygon (p, false);
|
||||
return new db::Polygon (p, false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static db::DPolygon polygon_to_dpolygon (const db::Polygon *p, double dbu)
|
||||
{
|
||||
return db::DPolygon (*p * dbu, false);
|
||||
return db::DPolygon (*p, db::CplxTrans (dbu), false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static bool is_convex (const db::Polygon *p)
|
||||
|
|
@ -2380,12 +2380,12 @@ Class<db::PolygonWithProperties> decl_PolygonWithProperties (decl_Polygon, "db",
|
|||
|
||||
static db::DPolygon *dpolygon_from_ipolygon (const db::Polygon &p)
|
||||
{
|
||||
return new db::DPolygon (p, false);
|
||||
return new db::DPolygon (p, false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static db::Polygon dpolygon_to_polygon (const db::DPolygon *p, double dbu)
|
||||
{
|
||||
return db::Polygon (*p * (1.0 / dbu), false);
|
||||
return db::Polygon (*p, db::VCplxTrans (1.0 / dbu), false, false /*don't remove reflected*/, false /*no normalize*/);
|
||||
}
|
||||
|
||||
static db::Polygon transformed_vcplx_dp (const db::DPolygon *p, const db::VCplxTrans &t)
|
||||
|
|
|
|||
|
|
@ -1309,23 +1309,23 @@ tl::Variant complex_op (db::Region *region, db::CompoundRegionOperationNode *nod
|
|||
|
||||
static void
|
||||
fill_region (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_skew (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static db::Region
|
||||
|
|
@ -4340,41 +4340,44 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief A mapping of \\Cell#fill_region to the Region class\n"
|
||||
"\n"
|
||||
"This method is equivalent to \\Cell#fill_region, but is based on Region (with the cell being the first parameter).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("fill", &fill_region_skew, gsi::arg ("in_cell"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
gsi::arg ("fc_origin"),
|
||||
gsi::arg ("fc_bbox"),
|
||||
gsi::arg ("row_step"),
|
||||
gsi::arg ("column_step"),
|
||||
gsi::arg ("origin", &default_origin, "(0, 0)"),
|
||||
gsi::arg ("remaining_parts", (db::Region *)0, "nil"),
|
||||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief A mapping of \\Cell#fill_region to the Region class\n"
|
||||
"\n"
|
||||
"This method is equivalent to \\Cell#fill_region, but is based on Region (with the cell being the first parameter).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("fill_multi", &fill_region_multi, gsi::arg ("in_cell"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
gsi::arg ("fc_origin"),
|
||||
gsi::arg ("fc_bbox"),
|
||||
gsi::arg ("row_step"),
|
||||
gsi::arg ("column_step"),
|
||||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief A mapping of \\Cell#fill_region to the Region class\n"
|
||||
"\n"
|
||||
"This method is equivalent to \\Cell#fill_region, but is based on Region (with the cell being the first parameter).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("nets", &nets, gsi::arg ("extracted"), gsi::arg ("net_prop_name", tl::Variant (), "nil"), gsi::arg ("net_filter", (const std::vector<const db::Net *> *) (0), "nil"),
|
||||
"@brief Pulls the net shapes from a LayoutToNetlist database\n"
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ Class<db::ViaType> decl_dbViaType ("db", "ViaType",
|
|||
"@brief If non-zero, the top layer's dimensions will be rounded to this grid.\n"
|
||||
),
|
||||
"@brief Describes a via type\n"
|
||||
"These objects are used by PCellDeclaration#via_types to specify the via types a "
|
||||
"These objects are used by \\PCellDeclaration#via_types to specify the via types a "
|
||||
"via PCell is able to provide.\n"
|
||||
"\n"
|
||||
"The basic parameters of a via type are bottom and top layers (the layers that are "
|
||||
|
|
|
|||
|
|
@ -377,3 +377,98 @@ TEST(6)
|
|||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au6.oas", db::WriteOAS);
|
||||
}
|
||||
|
||||
// exclude_area
|
||||
TEST(7)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/fill_tool7.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
|
||||
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
|
||||
|
||||
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
|
||||
|
||||
unsigned int excl_layer = ly.get_layer (db::LayerProperties (2, 0));
|
||||
db::Region excl_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), excl_layer));
|
||||
|
||||
db::Region remaining_polygons;
|
||||
|
||||
db::Vector rs (2500, 0);
|
||||
db::Vector cs (650, 2500);
|
||||
db::Box fc_box = ly.cell (fill_cell).bbox ();
|
||||
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), false, &remaining_polygons, db::Vector (), 0, db::Box (), excl_region);
|
||||
|
||||
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
|
||||
remaining_polygons.insert_into (&ly, top_cell, l100);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au7.oas", db::WriteOAS);
|
||||
}
|
||||
|
||||
// exclude_area
|
||||
TEST(8)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/fill_tool8.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
|
||||
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
|
||||
|
||||
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
|
||||
|
||||
unsigned int excl_layer = ly.get_layer (db::LayerProperties (2, 0));
|
||||
db::Region excl_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), excl_layer));
|
||||
|
||||
db::Vector rs (2500, 0);
|
||||
db::Vector cs (650, 2500);
|
||||
db::Box fc_box = ly.cell (fill_cell).bbox ();
|
||||
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), false, 0, db::Vector (), 0, db::Box (), excl_region);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au8.oas", db::WriteOAS);
|
||||
}
|
||||
|
||||
// exclude_area
|
||||
TEST(9)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/fill_tool9.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
|
||||
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
|
||||
|
||||
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
|
||||
|
||||
unsigned int excl_layer = ly.get_layer (db::LayerProperties (2, 0));
|
||||
db::Region excl_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), excl_layer));
|
||||
|
||||
db::Vector rs (2500, 0);
|
||||
db::Vector cs (650, 2500);
|
||||
db::Box fc_box = ly.cell (fill_cell).bbox ();
|
||||
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), true, 0, db::Vector (), 0, db::Box (), excl_region);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au9.oas", db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,7 +294,9 @@ TEST(2)
|
|||
EXPECT_EQ (g.hier_generation_id (), size_t (3));
|
||||
|
||||
g.clear ();
|
||||
EXPECT_EQ (g.update_needed (), true);
|
||||
g.update ();
|
||||
EXPECT_EQ (g.update_needed (), false);
|
||||
el.reset ();
|
||||
EXPECT_EQ (g.hier_generation_id (), size_t (4));
|
||||
|
||||
|
|
@ -387,7 +389,9 @@ TEST(3)
|
|||
EXPECT_EQ (el.hier_dirty, true);
|
||||
|
||||
el.reset ();
|
||||
EXPECT_EQ (g.update_needed (), true);
|
||||
g.update ();
|
||||
EXPECT_EQ (g.update_needed (), false);
|
||||
|
||||
top->shapes (0).insert (db::Box (0, 0, 10, 20));
|
||||
top->shapes (1).insert (db::Box (0, 0, 10, 20));
|
||||
|
|
|
|||
|
|
@ -2404,6 +2404,10 @@ TEST(12A)
|
|||
|
||||
db::Cell &topcell = layout.cell (*layout.begin_top_down ());
|
||||
|
||||
// standalone copy
|
||||
db::Shapes copy (true);
|
||||
copy = topcell.shapes (lindex);
|
||||
|
||||
db::Shapes::shape_iterator shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All);
|
||||
while (! shape.at_end ()) {
|
||||
topcell.shapes (lindex).replace (*shape, db::Box (shape->box ().transformed (db::Trans (1))));
|
||||
|
|
@ -2436,6 +2440,70 @@ TEST(12A)
|
|||
"box (-1050,150;-150,2150) #112\n"
|
||||
);
|
||||
|
||||
shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All);
|
||||
while (! shape.at_end ()) {
|
||||
topcell.shapes (lindex).replace (*shape, db::Box (shape->box ().transformed (db::Trans (1))));
|
||||
++shape;
|
||||
}
|
||||
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex)),
|
||||
"box (-2000,-1000;0,-100) #0\n"
|
||||
"box (-2100,-1100;-100,-200) #0\n"
|
||||
"box (-2150,-1050;-150,-150) #0\n"
|
||||
"box (-2000,-1000;0,-100) #110\n"
|
||||
"box (-2100,-1100;-100,-200) #111\n"
|
||||
"box (-2150,-1050;-150,-150) #112\n"
|
||||
);
|
||||
|
||||
// on standalone shapes
|
||||
|
||||
shape = copy.begin (db::Shapes::shape_iterator::All);
|
||||
while (! shape.at_end ()) {
|
||||
copy.replace (*shape, db::Box (shape->box ().transformed (db::Trans (1))));
|
||||
++shape;
|
||||
}
|
||||
|
||||
EXPECT_EQ (shapes_to_string (_this, copy),
|
||||
"box (-1000,0;-100,2000) #0\n"
|
||||
"box (-1100,100;-200,2100) #0\n"
|
||||
"box (-1050,150;-150,2150) #0\n"
|
||||
"box (-1000,0;-100,2000) #10\n"
|
||||
"box (-1100,100;-200,2100) #11\n"
|
||||
"box (-1050,150;-150,2150) #12\n"
|
||||
);
|
||||
|
||||
shape = copy.begin (db::Shapes::shape_iterator::All);
|
||||
while (! shape.at_end ()) {
|
||||
if (shape->has_prop_id ()) {
|
||||
copy.replace_prop_id (*shape, shape->prop_id () + 100);
|
||||
}
|
||||
++shape;
|
||||
}
|
||||
|
||||
EXPECT_EQ (shapes_to_string (_this, copy),
|
||||
"box (-1000,0;-100,2000) #0\n"
|
||||
"box (-1100,100;-200,2100) #0\n"
|
||||
"box (-1050,150;-150,2150) #0\n"
|
||||
"box (-1000,0;-100,2000) #110\n"
|
||||
"box (-1100,100;-200,2100) #111\n"
|
||||
"box (-1050,150;-150,2150) #112\n"
|
||||
);
|
||||
|
||||
shape = copy.begin (db::Shapes::shape_iterator::All);
|
||||
while (! shape.at_end ()) {
|
||||
copy.replace (*shape, db::Box (shape->box ().transformed (db::Trans (1))));
|
||||
++shape;
|
||||
}
|
||||
|
||||
EXPECT_EQ (shapes_to_string (_this, copy),
|
||||
"box (-2000,-1000;0,-100) #0\n"
|
||||
"box (-2100,-1100;-100,-200) #0\n"
|
||||
"box (-2150,-1050;-150,-150) #0\n"
|
||||
"box (-2000,-1000;0,-100) #110\n"
|
||||
"box (-2100,-1100;-100,-200) #111\n"
|
||||
"box (-2150,-1050;-150,-150) #112\n"
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,16 +10,16 @@
|
|||
<p>
|
||||
Select "Path" mode from the toolbar. The editor options dialog will open that additionally prompts for
|
||||
basic path parameters, such as width and extension scheme. When a path is being drawn, it will receive
|
||||
the settings entered into this dialog. The path properties can even be changed, while the path is
|
||||
being drawn. Don't forget to click "Apply" to take over the current entries. If the dialog has been
|
||||
closed unintentionally, it can be reopened with the F3 shortcut.
|
||||
the settings entered into this dialog. The path properties can be changed, while the path is
|
||||
being drawn. If the option page has been closed unintentionally, it can be reopened with the F3 shortcut.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To actually draw a path,
|
||||
choose a layer from the layer panel in which to create a new box.
|
||||
choose a layer from the layer panel in which to create a new path.
|
||||
Left click at the first vertex, move the mouse to the second vertex, click to place this one and continue
|
||||
to the last vertex. Double-click at the last vertex to finish the path. Press the ESC key to cancel the operation.
|
||||
Use the backspace key to remove the current segment and go back to the previous segment.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
@ -30,5 +30,21 @@
|
|||
also during editing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<keyword name="Via"/>
|
||||
<keyword name="Vias"/>
|
||||
Paths are often used for wires. KLayout can be configured to provide
|
||||
vias that allow switching from one layer to another and place a via
|
||||
between the layers where the paths overlap. Before you can use the via feature,
|
||||
KLayout has to be equipped with via definitions. Vias are basically PCells which
|
||||
need to support a specific set of parameters. Via PCells need to expose a number
|
||||
of descriptors to define the options supported by a particular PCell (e.g. the
|
||||
layers which are connected or the type of via if multiple flavors are available).
|
||||
This scheme allows for a lot of flexibility, but needs some coding skills.
|
||||
In the macro IDE, a code sample is provided which implements two simple vias
|
||||
for a three-layer metal stack. For more details see <class_doc href="PCellDeclaration"/>,
|
||||
method "via_types" and <class_doc href="ViaType"/>.
|
||||
</p>
|
||||
|
||||
</doc>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
<topic href="/manual/create_cells.xml"/>
|
||||
<topic href="/manual/create_polygon.xml"/>
|
||||
<topic href="/manual/create_box.xml"/>
|
||||
<topic href="/manual/create_path.xml"/>
|
||||
<topic href="/manual/create_text.xml"/>
|
||||
<topic href="/manual/create_instance.xml"/>
|
||||
<topic href="/manual/move_sel.xml"/>
|
||||
|
|
|
|||
|
|
@ -976,7 +976,7 @@ marker.destroy</pre>
|
|||
<p>
|
||||
The PluginFactory itself acts as a singleton per plugin class and provides not only the ability to create
|
||||
Plugin objects but also a couple of configuration options and a global handler for configuration and menu
|
||||
events. The configuration includes:
|
||||
events. The PluginFactory provides:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
|
@ -991,6 +991,10 @@ marker.destroy</pre>
|
|||
After an option is configured, the individual Plugin objects and the PluginFactory receives "configure" calls
|
||||
when a configuration option changes or for the initial configuration.
|
||||
</li>
|
||||
<li>Widgets: The plugin factory can provide widgets for the configuration dialog ('File/Setup') and the
|
||||
editor options dock. Respective callbacks are <class_doc href="PluginFactory#create_config_pages"/>
|
||||
and <class_doc href="PluginFactory#create_editor_options_pages"/>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
|
@ -1048,5 +1052,29 @@ marker.destroy</pre>
|
|||
over the mouse in certain circumstances and is supposed to put the plugin into a "watching" instead of "dragging" state.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A plugin may also create markers for visual feedback and highlights. This can be done explicitly
|
||||
using marker objects (<class_doc href="Marker"/>) or in a application-defined fashion by generating
|
||||
mouse cursors. The API functions for this purpose are <class_doc href="Plugin#clear_mouse_cursors"/>,
|
||||
<class_doc href="Plugin#add_mouse_cursor"/> and <class_doc href="Plugin#add_edge_marker"/>. These
|
||||
functions provide cursors and highlights that match the visual effects of other plugins and
|
||||
interface with the mouse tracking feature of the application.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another service the Plugin class provides is snapping:
|
||||
there exist a number of global configuration options which control snapping (grids, snapping to
|
||||
objects, angle constraints). The plugin offers a number of snap functions that follow the
|
||||
application's current configuration and implement snapping accordingly. These methods are
|
||||
<class_doc href="Plugin#snap"/> and <class_doc href="Plugin#snap2"/>. While the first
|
||||
method provides grid and angle snapping, the second also implements snapping to layout objects.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The "drag box" sample macro demonstrates many of these features.
|
||||
The sample is available from the macro templates when you create a new
|
||||
macro in the macro IDE.
|
||||
</p>
|
||||
|
||||
</doc>
|
||||
|
||||
|
|
|
|||
|
|
@ -644,6 +644,10 @@ module DRC
|
|||
DRCFillStep::new(false, x, y)
|
||||
end
|
||||
|
||||
def fill_exclude(excl)
|
||||
DRCFillExclude::new(excl)
|
||||
end
|
||||
|
||||
def auto_origin
|
||||
DRCFillOrigin::new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5755,6 +5755,8 @@ CODE
|
|||
# @li @b multi_origin @/b: lets the algorithm choose the origin and repeats the fill with different origins
|
||||
# until no further fill cell can be fitted. @/li
|
||||
# @li @b fill_pattern(..) @/b: specifies the fill pattern. @/li
|
||||
# @li @b fill_exclude(excl) @/b: specifies a fill exclude region ('excl' is a polygon layer). This is conceptually
|
||||
# equivalent to subtracting that layer from the fill region, but usually more efficient. @/li
|
||||
# @/ul
|
||||
#
|
||||
# "fill_pattern" generates a fill pattern object. This object is used for configuring the fill pattern
|
||||
|
|
@ -5895,6 +5897,7 @@ CODE
|
|||
pattern = nil
|
||||
origin = RBA::DPoint::new
|
||||
repeat = false
|
||||
excl = nil
|
||||
|
||||
args.each_with_index do |a,ai|
|
||||
if a.is_a?(DRCSource)
|
||||
|
|
@ -5907,6 +5910,11 @@ CODE
|
|||
raise("Duplicate fill pattern specification for '#{m}' at argument ##{ai+1}")
|
||||
end
|
||||
pattern = a
|
||||
elsif a.is_a?(DRCFillExclude)
|
||||
if excl
|
||||
raise("Duplicate exclude region specification for '#{m}' at argument ##{ai+1}")
|
||||
end
|
||||
excl = a.excl
|
||||
elsif a.is_a?(DRCFillStep)
|
||||
if a.for_row
|
||||
if row_step
|
||||
|
|
@ -5938,6 +5946,10 @@ CODE
|
|||
column_step = RBA::DVector::new(0, pattern.default_ypitch)
|
||||
end
|
||||
|
||||
if !excl
|
||||
excl = RBA::Region::new
|
||||
end
|
||||
|
||||
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
|
||||
|
||||
result = nil
|
||||
|
|
@ -5988,6 +6000,7 @@ CODE
|
|||
tp.var("fc_index", fc_index)
|
||||
tp.var("repeat", repeat)
|
||||
tp.var("with_left", with_left)
|
||||
tp.var("excl", excl)
|
||||
|
||||
tp.queue(<<"END")
|
||||
var tc_box = _frame.bbox;
|
||||
|
|
@ -5997,8 +6010,8 @@ CODE
|
|||
tile_box = tile_box & tc_box;
|
||||
var left = with_left ? Region.new : nil;
|
||||
repeat ?
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox);
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox, excl) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox, excl);
|
||||
with_left && _output(#{result_arg}, left)
|
||||
)
|
||||
END
|
||||
|
|
@ -6020,9 +6033,9 @@ END
|
|||
|
||||
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
|
||||
if repeat
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result)
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result, RBA::Box::new, excl)
|
||||
else
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result)
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result, RBA::Box::new, excl)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -475,6 +475,18 @@ module DRC
|
|||
|
||||
end
|
||||
|
||||
# A wrapper for the fill step definition
|
||||
class DRCFillExclude
|
||||
def initialize(excl)
|
||||
excl.is_a?(DRCLayer) || raise("Exclude layer argument needs to be a DRC layer")
|
||||
excl.requires_region("Exclude layer")
|
||||
@excl = excl.data
|
||||
end
|
||||
def excl
|
||||
@excl
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the fill step definition
|
||||
class DRCFillStep
|
||||
def initialize(for_row, x, y = nil)
|
||||
|
|
|
|||
|
|
@ -1453,6 +1453,16 @@ TEST(47bd_fillWithUsingOutputDeep)
|
|||
run_test (_this, "47b", true);
|
||||
}
|
||||
|
||||
TEST(47c_fillWithExcludeArea)
|
||||
{
|
||||
run_test (_this, "47c", false);
|
||||
}
|
||||
|
||||
TEST(47cd_fillWithExcludeAreaDeep)
|
||||
{
|
||||
run_test (_this, "47c", true);
|
||||
}
|
||||
|
||||
TEST(48_drcWithFragments)
|
||||
{
|
||||
run_test (_this, "48", false);
|
||||
|
|
|
|||
|
|
@ -419,8 +419,6 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>all_layers_rb</tabstop>
|
||||
<tabstop>visible_layers_rb</tabstop>
|
||||
<tabstop>h_none_rb</tabstop>
|
||||
<tabstop>h_left_rb</tabstop>
|
||||
<tabstop>h_center_rb</tabstop>
|
||||
|
|
@ -429,7 +427,8 @@
|
|||
<tabstop>v_top_rb</tabstop>
|
||||
<tabstop>v_center_rb</tabstop>
|
||||
<tabstop>v_bottom_rb</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
<tabstop>all_layers_rb</tabstop>
|
||||
<tabstop>visible_layers_rb</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ The perimeter calculation only takes true outside edges into account. Internal e
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>area_le</tabstop>
|
||||
<tabstop>perimeter_le</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BoxPropertiesPage</class>
|
||||
<widget class="QWidget" name="BoxPropertiesPage" >
|
||||
<property name="geometry" >
|
||||
<widget class="QWidget" name="BoxPropertiesPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
|
|
@ -9,63 +10,60 @@
|
|||
<height>370</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" >
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame1" >
|
||||
<property name="frameShape" >
|
||||
<widget class="QFrame" name="frame1">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12" >
|
||||
<property name="font" >
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<pointsize>12</pointsize>
|
||||
<weight>75</weight>
|
||||
<italic>false</italic>
|
||||
<bold>true</bold>
|
||||
<underline>false</underline>
|
||||
<strikeout>false</strikeout>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Box Properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="layer_lbl" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<widget class="QLabel" name="layer_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -75,13 +73,13 @@
|
|||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
|
|
@ -90,420 +88,396 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="mode_tab" >
|
||||
<property name="currentIndex" >
|
||||
<widget class="QTabWidget" name="mode_tab">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_4" >
|
||||
<attribute name="title" >
|
||||
<widget class="QWidget" name="tab_4">
|
||||
<attribute name="title">
|
||||
<string>Corners</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="label_16" >
|
||||
<property name="text" >
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="5" >
|
||||
<widget class="Line" name="line_2" >
|
||||
<property name="orientation" >
|
||||
<item row="2" column="0" colspan="5">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4" >
|
||||
<widget class="QLineEdit" name="y2_le_1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLineEdit" name="y2_le_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLineEdit" name="x1_le_1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="x1_le_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3" >
|
||||
<widget class="QLabel" name="label_13" >
|
||||
<property name="text" >
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>h = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="x2_le_1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="x2_le_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_17" >
|
||||
<property name="text" >
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Width/height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QLineEdit" name="y1_le_1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLineEdit" name="y1_le_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QLabel" name="label_18" >
|
||||
<property name="text" >
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>w = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_15" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Upper right (x/y) </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" >
|
||||
<widget class="QLineEdit" name="w_le_1" >
|
||||
<property name="enabled" >
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="w_le_1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Lower left (x/y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label_11" >
|
||||
<property name="text" >
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_14" >
|
||||
<property name="text" >
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4" >
|
||||
<widget class="QLineEdit" name="h_le_1" >
|
||||
<property name="enabled" >
|
||||
<item row="4" column="4">
|
||||
<widget class="QLineEdit" name="h_le_1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLabel" name="label_19" >
|
||||
<property name="text" >
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_20" >
|
||||
<property name="text" >
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Center (x/y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QLabel" name="label_21" >
|
||||
<property name="text" >
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3" >
|
||||
<widget class="QLabel" name="label_22" >
|
||||
<property name="text" >
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<widget class="QLineEdit" name="cx_le_1" >
|
||||
<property name="enabled" >
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="cx_le_1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4" >
|
||||
<widget class="QLineEdit" name="cy_le_1" >
|
||||
<property name="enabled" >
|
||||
<item row="3" column="4">
|
||||
<widget class="QLineEdit" name="cy_le_1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3" >
|
||||
<attribute name="title" >
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>Center/Size</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="3" column="4" >
|
||||
<widget class="QLineEdit" name="y1_le_2" >
|
||||
<property name="enabled" >
|
||||
<item row="3" column="4">
|
||||
<widget class="QLineEdit" name="y1_le_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QLineEdit" name="cy_le_2" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLineEdit" name="cy_le_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Size (w/h)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="5" >
|
||||
<widget class="Line" name="line" >
|
||||
<property name="orientation" >
|
||||
<item row="2" column="0" colspan="5">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLineEdit" name="cx_le_2" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="cx_le_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="label_6" >
|
||||
<property name="text" >
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>w = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Center (x/y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4" >
|
||||
<widget class="QLineEdit" name="h_le_2" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLineEdit" name="h_le_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Lower left (x/y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3" >
|
||||
<widget class="QLabel" name="label_10" >
|
||||
<property name="text" >
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="w_le_2" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="w_le_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label_8" >
|
||||
<property name="text" >
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>h = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<widget class="QLineEdit" name="x1_le_2" >
|
||||
<property name="enabled" >
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="x1_le_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QLabel" name="label_9" >
|
||||
<property name="text" >
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" >
|
||||
<widget class="QLineEdit" name="x2_le_2" >
|
||||
<property name="enabled" >
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="x2_le_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4" >
|
||||
<widget class="QLineEdit" name="y2_le_2" >
|
||||
<property name="enabled" >
|
||||
<item row="4" column="4">
|
||||
<widget class="QLineEdit" name="y2_le_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_23" >
|
||||
<property name="text" >
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>Upper right (x/y) </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QLabel" name="label_24" >
|
||||
<property name="text" >
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3" >
|
||||
<widget class="QLabel" name="label_25" >
|
||||
<property name="text" >
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -514,13 +488,13 @@
|
|||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>478</width>
|
||||
<height>10</height>
|
||||
|
|
@ -529,25 +503,25 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dbu_cb" >
|
||||
<property name="text" >
|
||||
<widget class="QCheckBox" name="dbu_cb">
|
||||
<property name="text">
|
||||
<string>Coordinates in database units</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="abs_cb" >
|
||||
<property name="text" >
|
||||
<widget class="QCheckBox" name="abs_cb">
|
||||
<property name="text">
|
||||
<string>Absolute (accumulated) transformations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>478</width>
|
||||
<height>16</height>
|
||||
|
|
@ -556,26 +530,26 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame2" >
|
||||
<property name="frameShape" >
|
||||
<widget class="QFrame" name="frame2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>211</width>
|
||||
<height>20</height>
|
||||
|
|
@ -584,15 +558,15 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="prop_pb" >
|
||||
<property name="text" >
|
||||
<widget class="QPushButton" name="prop_pb">
|
||||
<property name="text">
|
||||
<string>User Properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="inst_pb" >
|
||||
<property name="text" >
|
||||
<widget class="QPushButton" name="inst_pb">
|
||||
<property name="text">
|
||||
<string>Instantiation</string>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>164</height>
|
||||
<width>464</width>
|
||||
<height>180</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -99,6 +99,11 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>shallow_rb</tabstop>
|
||||
<tabstop>deep_rb</tabstop>
|
||||
<tabstop>dont_ask_cbx</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
|
|
|||
|
|
@ -671,9 +671,22 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>h_distribute</tabstop>
|
||||
<tabstop>h_pitch</tabstop>
|
||||
<tabstop>h_space</tabstop>
|
||||
<tabstop>v_distribute</tabstop>
|
||||
<tabstop>v_pitch</tabstop>
|
||||
<tabstop>v_space</tabstop>
|
||||
<tabstop>h_none_rb</tabstop>
|
||||
<tabstop>h_left_rb</tabstop>
|
||||
<tabstop>h_center_rb</tabstop>
|
||||
<tabstop>h_right_rb</tabstop>
|
||||
<tabstop>v_none_rb</tabstop>
|
||||
<tabstop>v_top_rb</tabstop>
|
||||
<tabstop>v_center_rb</tabstop>
|
||||
<tabstop>v_bottom_rb</tabstop>
|
||||
<tabstop>all_layers_rb</tabstop>
|
||||
<tabstop>visible_layers_rb</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
|
|
|
|||
|
|
@ -470,6 +470,7 @@
|
|||
<tabstop>grid_cb</tabstop>
|
||||
<tabstop>edit_grid_le</tabstop>
|
||||
<tabstop>snap_objects_cbx</tabstop>
|
||||
<tabstop>snap_objects_to_grid_cbx</tabstop>
|
||||
<tabstop>conn_angle_cb</tabstop>
|
||||
<tabstop>move_angle_cb</tabstop>
|
||||
<tabstop>hier_sel_cbx</tabstop>
|
||||
|
|
|
|||
|
|
@ -268,6 +268,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>scrollArea</tabstop>
|
||||
<tabstop>width_le</tabstop>
|
||||
<tabstop>type_cb</tabstop>
|
||||
<tabstop>start_ext_le</tabstop>
|
||||
<tabstop>end_ext_le</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>542</width>
|
||||
<height>243</height>
|
||||
<width>528</width>
|
||||
<height>248</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
|
|
@ -292,6 +292,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>scrollArea</tabstop>
|
||||
<tabstop>text_le</tabstop>
|
||||
<tabstop>halign_cbx</tabstop>
|
||||
<tabstop>valign_cbx</tabstop>
|
||||
<tabstop>size_le</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>666</width>
|
||||
<height>649</height>
|
||||
<height>668</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -182,7 +182,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
|||
|
|
@ -365,6 +365,19 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>cell_name_le</tabstop>
|
||||
<tabstop>origin_groupbox</tabstop>
|
||||
<tabstop>lt</tabstop>
|
||||
<tabstop>ct</tabstop>
|
||||
<tabstop>rt</tabstop>
|
||||
<tabstop>lc</tabstop>
|
||||
<tabstop>cc</tabstop>
|
||||
<tabstop>rc</tabstop>
|
||||
<tabstop>lb</tabstop>
|
||||
<tabstop>cb</tabstop>
|
||||
<tabstop>rb</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -272,6 +272,8 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>x_le</tabstop>
|
||||
<tabstop>y_le</tabstop>
|
||||
<tabstop>dbu_cb</tabstop>
|
||||
<tabstop>abs_cb</tabstop>
|
||||
<tabstop>prop_pb</tabstop>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>469</width>
|
||||
<width>472</width>
|
||||
<height>271</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -138,6 +138,12 @@ Leave empty to get the same radius than for outer corners)</string>
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>amend_cb</tabstop>
|
||||
<tabstop>router_le</tabstop>
|
||||
<tabstop>rinner_le</tabstop>
|
||||
<tabstop>points_le</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
|
|
|||
|
|
@ -1,52 +1,51 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TextPropertiesPage</class>
|
||||
<widget class="QWidget" name="TextPropertiesPage" >
|
||||
<property name="geometry" >
|
||||
<widget class="QWidget" name="TextPropertiesPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>555</width>
|
||||
<height>366</height>
|
||||
<width>568</width>
|
||||
<height>375</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="2" column="3" >
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>y = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" >
|
||||
<widget class="QLineEdit" name="x_le" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="x_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="5" >
|
||||
<item row="3" column="0" colspan="5">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>8</height>
|
||||
|
|
@ -54,19 +53,19 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="0" >
|
||||
<widget class="QLabel" name="Text size" >
|
||||
<property name="text" >
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="Text size">
|
||||
<property name="text">
|
||||
<string>Text size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="5" >
|
||||
<item row="11" column="0" colspan="5">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>457</width>
|
||||
<height>51</height>
|
||||
|
|
@ -74,22 +73,22 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="5" >
|
||||
<item row="8" column="0" colspan="5">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>431</width>
|
||||
<height>8</height>
|
||||
|
|
@ -97,34 +96,34 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>x = </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="5" >
|
||||
<widget class="QFrame" name="button_frame" >
|
||||
<property name="frameShape" >
|
||||
<item row="12" column="0" colspan="5">
|
||||
<widget class="QFrame" name="button_frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>211</width>
|
||||
<height>20</height>
|
||||
|
|
@ -133,15 +132,15 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="prop_pb" >
|
||||
<property name="text" >
|
||||
<widget class="QPushButton" name="prop_pb">
|
||||
<property name="text">
|
||||
<string>User Properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="inst_pb" >
|
||||
<property name="text" >
|
||||
<widget class="QPushButton" name="inst_pb">
|
||||
<property name="text">
|
||||
<string>Instantiation</string>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -149,121 +148,114 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="4" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<item row="7" column="1" colspan="4">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Hint: orientation, alignments and size cannot be saved to OASIS files
|
||||
Enable a vector font and text scaling in the setup dialog
|
||||
to show text objects scaled and rotated</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="Orientation" >
|
||||
<property name="text" >
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="Orientation">
|
||||
<property name="text">
|
||||
<string>Orientation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Position (x/y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="3" colspan="2" >
|
||||
<widget class="QLabel" name="label_6" >
|
||||
<property name="text" >
|
||||
<item row="6" column="3" colspan="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>(Leave empty for default)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="4" >
|
||||
<widget class="QLineEdit" name="text_le" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="1" column="1" colspan="4">
|
||||
<widget class="QLineEdit" name="text_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="2" colspan="3" >
|
||||
<widget class="QCheckBox" name="abs_cb" >
|
||||
<property name="text" >
|
||||
<item row="10" column="2" colspan="3">
|
||||
<widget class="QCheckBox" name="abs_cb">
|
||||
<property name="text">
|
||||
<string>Absolute (accumulated) transformations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4" >
|
||||
<widget class="QLineEdit" name="y_le" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLineEdit" name="y_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2" colspan="3" >
|
||||
<widget class="QCheckBox" name="dbu_cb" >
|
||||
<property name="text" >
|
||||
<item row="9" column="2" colspan="3">
|
||||
<widget class="QCheckBox" name="dbu_cb">
|
||||
<property name="text">
|
||||
<string>Coordinates in database units</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="5" >
|
||||
<widget class="QFrame" name="frame" >
|
||||
<property name="frameShape" >
|
||||
<item row="0" column="0" colspan="5">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12" >
|
||||
<property name="font" >
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<pointsize>12</pointsize>
|
||||
<weight>75</weight>
|
||||
<italic>false</italic>
|
||||
<bold>true</bold>
|
||||
<underline>false</underline>
|
||||
<strikeout>false</strikeout>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Text Properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="layer_lbl" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<widget class="QLabel" name="layer_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -271,141 +263,149 @@ to show text objects scaled and rotated</string>
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2" >
|
||||
<widget class="QComboBox" name="orient_cbx" >
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="orient_cbx">
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(r0)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/r0_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/r0_24px.png</normaloff>:/r0_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(r90)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/r90_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/r90_24px.png</normaloff>:/r90_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(r180)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/r180_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/r180_24px.png</normaloff>:/r180_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(r270)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/r270_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/r270_24px.png</normaloff>:/r270_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(m0)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/m0_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/m0_24px.png</normaloff>:/m0_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(m45)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/m45_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/m45_24px.png</normaloff>:/m45_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(m90)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/m90_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/m90_24px.png</normaloff>:/m90_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(m135)</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="layResources.qrc" >:/m135_24px.png</iconset>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/m135_24px.png</normaloff>:/m135_24px.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2" >
|
||||
<widget class="QLineEdit" name="size_le" />
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="size_le"/>
|
||||
</item>
|
||||
<item row="5" column="2" >
|
||||
<widget class="QComboBox" name="halign_cbx" >
|
||||
<item row="5" column="2">
|
||||
<widget class="QComboBox" name="halign_cbx">
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Center</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" >
|
||||
<widget class="QLabel" name="label_8" >
|
||||
<property name="text" >
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>h =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3" >
|
||||
<widget class="QLabel" name="label_9" >
|
||||
<property name="text" >
|
||||
<item row="5" column="3">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>v =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="4" >
|
||||
<widget class="QComboBox" name="valign_cbx" >
|
||||
<item row="5" column="4">
|
||||
<widget class="QComboBox" name="valign_cbx">
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>(Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Top</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Center</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>Bottom</string>
|
||||
</property>
|
||||
</item>
|
||||
|
|
@ -427,7 +427,7 @@ to show text objects scaled and rotated</string>
|
|||
<tabstop>inst_pb</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="layResources.qrc" />
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ HEADERS += \
|
|||
edtPartialService.h \
|
||||
edtPlugin.h \
|
||||
edtService.h \
|
||||
edtUtils.h \
|
||||
edtCommon.h \
|
||||
edtDistribute.h \
|
||||
|
||||
|
|
@ -91,7 +90,6 @@ SOURCES += \
|
|||
edtPartialService.cc \
|
||||
edtPlugin.cc \
|
||||
edtService.cc \
|
||||
edtUtils.cc \
|
||||
gsiDeclEdt.cc \
|
||||
edtDistribute.cc \
|
||||
|
||||
|
|
|
|||
|
|
@ -108,10 +108,37 @@ BoxService::do_mouse_move_inactive (const db::DPoint &p)
|
|||
void
|
||||
BoxService::do_mouse_move (const db::DPoint &p)
|
||||
{
|
||||
do_mouse_move_inactive (p);
|
||||
lay::PointSnapToObjectResult snap_details = snap2_details (p);
|
||||
db::DPoint ps = snap_details.snapped_point;
|
||||
|
||||
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
|
||||
|
||||
clear_mouse_cursors ();
|
||||
|
||||
db::DPoint px (p.x (), m_p1.y ());
|
||||
lay::PointSnapToObjectResult snap_details_x = snap2_details (px);
|
||||
|
||||
db::DPoint py (m_p1.x (), p.y ());
|
||||
lay::PointSnapToObjectResult snap_details_y = snap2_details (py);
|
||||
|
||||
if (snap_details_x.object_snap != lay::PointSnapToObjectResult::NoObject) {
|
||||
ps = db::DPoint (snap_details_x.snapped_point.x (), ps.y ());
|
||||
mouse_cursor_from_snap_details (snap_details_x, true /*add*/);
|
||||
}
|
||||
|
||||
if (snap_details_y.object_snap != lay::PointSnapToObjectResult::NoObject) {
|
||||
ps = db::DPoint (ps.x (), snap_details_y.snapped_point.y ());
|
||||
mouse_cursor_from_snap_details (snap_details_y, true /*add*/);
|
||||
}
|
||||
|
||||
add_mouse_cursor (ps);
|
||||
|
||||
} else {
|
||||
mouse_cursor_from_snap_details (snap_details);
|
||||
}
|
||||
|
||||
set_cursor (lay::Cursor::cross);
|
||||
m_p2 = snap2 (p);
|
||||
m_p2 = ps;
|
||||
update_marker ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include "dbLayout.h"
|
||||
|
||||
#include "edtDialogs.h"
|
||||
#include "edtUtils.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "layObjectInstPath.h"
|
||||
#include "layCellView.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
|
|||
if (pc.first) {
|
||||
const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pc.second);
|
||||
if (pc_decl) {
|
||||
param = pcell_parameters_to_string (pc_decl->named_parameters (mp_pcell_parameters->get_parameters (&ok)));
|
||||
param = lay::pcell_parameters_to_string (pc_decl->named_parameters (mp_pcell_parameters->get_parameters (&ok)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ InstService::sync_to_config ()
|
|||
dispatcher ()->config_set (cfg_edit_inst_lib_name, m_lib_name);
|
||||
dispatcher ()->config_set (cfg_edit_inst_cell_name, m_cell_or_pcell_name);
|
||||
if (m_is_pcell) {
|
||||
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, pcell_parameters_to_string (m_pcell_parameters));
|
||||
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, lay::pcell_parameters_to_string (m_pcell_parameters));
|
||||
} else {
|
||||
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, std::string ());
|
||||
}
|
||||
|
|
@ -531,7 +531,7 @@ InstService::configure (const std::string &name, const std::string &value)
|
|||
|
||||
if (name == cfg_edit_inst_pcell_parameters) {
|
||||
|
||||
std::map<std::string, tl::Variant> pcp = pcell_parameters_from_string (value);
|
||||
std::map<std::string, tl::Variant> pcp = lay::pcell_parameters_from_string (value);
|
||||
if (pcp != m_pcell_parameters) {
|
||||
|
||||
m_pcell_parameters = pcp;
|
||||
|
|
@ -772,7 +772,7 @@ InstService::config_finalize ()
|
|||
// TODO: it's somewhat questionable to do this inside "config_finalize" as this method is supposed
|
||||
// to reflect changes rather than induce some.
|
||||
if (m_is_pcell) {
|
||||
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, pcell_parameters_to_string (m_pcell_parameters));
|
||||
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, lay::pcell_parameters_to_string (m_pcell_parameters));
|
||||
} else {
|
||||
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, std::string ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@
|
|||
#include "layPlugin.h"
|
||||
#include "layViewObject.h"
|
||||
#include "layMarker.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbClipboard.h"
|
||||
#include "edtUtils.h"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ MoveTrackerService::issue_edit_events ()
|
|||
call_editor_hooks (m_editor_hooks, &edt::EditorHooks::begin_edits);
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
std::vector<edt::Service *> services = view ()->get_plugins<edt::Service> ();
|
||||
std::vector<lay::ObjectInstPath> sel;
|
||||
|
|
|
|||
|
|
@ -1213,7 +1213,7 @@ PartialService::timeout ()
|
|||
partial_objects::const_iterator r = transient_selection.begin ();
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (r->first.cv_index ());
|
||||
|
||||
|
|
@ -1468,7 +1468,7 @@ PartialService::issue_editor_hook_calls (const tl::weak_collection<edt::EditorHo
|
|||
db::DTrans move_trans = db::DTrans (m_current - m_start);
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
// Issue editor hook calls for the shape modification events
|
||||
|
||||
|
|
@ -1559,7 +1559,7 @@ PartialService::issue_editor_hook_calls (const tl::weak_collection<edt::EditorHo
|
|||
}
|
||||
|
||||
db::Shape
|
||||
PartialService::modify_shape (TransformationVariants &tv, const db::Shape &shape_in, const lay::ObjectInstPath &path, const std::set <EdgeWithIndex> &sel, const db::DTrans &move_trans, std::map <EdgeWithIndex, db::Edge> &new_edges, std::map <PointWithIndex, db::Point> &new_points)
|
||||
PartialService::modify_shape (lay::TransformationVariants &tv, const db::Shape &shape_in, const lay::ObjectInstPath &path, const std::set <EdgeWithIndex> &sel, const db::DTrans &move_trans, std::map <EdgeWithIndex, db::Edge> &new_edges, std::map <PointWithIndex, db::Point> &new_points)
|
||||
{
|
||||
tl_assert (shape_in.shapes () != 0);
|
||||
db::Shape shape = shape_in;
|
||||
|
|
@ -1642,7 +1642,7 @@ void
|
|||
PartialService::transform_selection (const db::DTrans &move_trans)
|
||||
{
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
// since a shape reference may become invalid while moving it and
|
||||
// because it creates ambiguities, we treat each shape separately:
|
||||
|
|
@ -1798,7 +1798,7 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
|
|||
|
||||
set_cursor (lay::Cursor::size_all);
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
// drag the vertex or edge/segment
|
||||
if (is_single_point_selection () || is_single_edge_selection ()) {
|
||||
|
|
@ -1862,7 +1862,7 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
|
|||
|
||||
if (mp_box) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
m_p2 = p;
|
||||
mp_box->set_points (m_p1, m_p2);
|
||||
|
|
@ -1922,7 +1922,7 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
|
||||
} else if (! mp_box) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
if (m_selection.empty ()) {
|
||||
|
||||
|
|
@ -2015,7 +2015,7 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
|
||||
if (m_dragging) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
if (m_current != m_start) {
|
||||
|
||||
|
|
@ -2059,7 +2059,7 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
view ()->clear_selection ();
|
||||
m_selection = selection;
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
lay::Editable::SelectionMode mode = lay::Editable::Replace;
|
||||
bool shift = ((buttons & lay::ShiftButton) != 0);
|
||||
|
|
@ -2192,7 +2192,7 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt
|
|||
|
||||
if ((buttons & lay::LeftButton) != 0 && prio) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
close_editor_hooks (false);
|
||||
|
||||
|
|
@ -2215,7 +2215,7 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt
|
|||
db::DPoint new_point_d = snap (p);
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view (), true /*per cv and layer*/, false /*per cv*/);
|
||||
lay::TransformationVariants tv (view (), true /*per cv and layer*/, false /*per cv*/);
|
||||
|
||||
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (r->first.cv_index (), r->first.layer ());
|
||||
if (tv_list && ! tv_list->empty ()) {
|
||||
|
|
@ -2304,7 +2304,7 @@ PartialService::mouse_release_event (const db::DPoint &p, unsigned int buttons,
|
|||
|
||||
if (prio && mp_box) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
ui ()->ungrab_mouse (this);
|
||||
|
||||
|
|
@ -2402,7 +2402,7 @@ PartialService::snap_marker_to_grid (const db::DVector &v, bool &snapped) const
|
|||
db::DVector snapped_to (1.0, 1.0);
|
||||
db::DVector vv = lay::snap_angle (v, move_ac (), &snapped_to);
|
||||
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
for (auto r = m_selection.begin (); r != m_selection.end (); ++r) {
|
||||
|
||||
|
|
@ -2548,7 +2548,7 @@ PartialService::selection_bbox ()
|
|||
{
|
||||
// build the transformation variants cache
|
||||
// TODO: this is done multiple times - once for each service!
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
const db::DCplxTrans &vp = view ()->viewport ().trans ();
|
||||
|
||||
lay::TextInfo text_info (view ());
|
||||
|
|
@ -2938,7 +2938,7 @@ PartialService::single_selected_point () const
|
|||
// build the transformation variants cache and
|
||||
// use only the first one of the explicit transformations
|
||||
// TODO: clarify how this can be implemented in a more generic form or leave it thus.
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (m_selection.begin ()->first.cv_index (), m_selection.begin ()->first.layer ());
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (m_selection.begin ()->first.cv_index ());
|
||||
|
|
@ -2960,7 +2960,7 @@ PartialService::single_selected_edge () const
|
|||
// build the transformation variants cache and
|
||||
// use only the first one of the explicit transformations
|
||||
// TODO: clarify how this can be implemented in a more generic form or leave it thus.
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (m_selection.begin ()->first.cv_index (), m_selection.begin ()->first.layer ());
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (m_selection.begin ()->first.cv_index ());
|
||||
|
|
@ -3042,7 +3042,7 @@ PartialService::do_selection_to_view ()
|
|||
if (! m_selection.empty ()) {
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
for (partial_objects::const_iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
|
||||
|
||||
|
|
@ -3418,7 +3418,7 @@ PartialService::handle_guiding_shape_changes ()
|
|||
|
||||
// Hint: get_parameters_from_pcell_and_guiding_shapes invalidates the shapes because it resets the changed
|
||||
// guiding shapes. We must not access s->shape after that.
|
||||
if (! get_parameters_from_pcell_and_guiding_shapes (layout, s->first.cell_index (), parameters_for_pcell)) {
|
||||
if (! lay::get_parameters_from_pcell_and_guiding_shapes (layout, s->first.cell_index (), parameters_for_pcell)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@
|
|||
#include "layViewObject.h"
|
||||
#include "layRubberBox.h"
|
||||
#include "laySnap.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
#include "edtUtils.h"
|
||||
#include "edtConfig.h"
|
||||
#include "edtEditorHooks.h"
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ private:
|
|||
db::DEdge single_selected_edge () const;
|
||||
bool handle_guiding_shape_changes ();
|
||||
void transform_selection (const db::DTrans &move_trans);
|
||||
db::Shape modify_shape (TransformationVariants &tv, const db::Shape &shape_in, const lay::ObjectInstPath &path, const std::set<EdgeWithIndex> &sel, const db::DTrans &move_trans, std::map <EdgeWithIndex, db::Edge> &new_edges, std::map <PointWithIndex, db::Point> &new_points);
|
||||
db::Shape modify_shape (lay::TransformationVariants &tv, const db::Shape &shape_in, const lay::ObjectInstPath &path, const std::set<EdgeWithIndex> &sel, const db::DTrans &move_trans, std::map <EdgeWithIndex, db::Edge> &new_edges, std::map <PointWithIndex, db::Point> &new_points);
|
||||
|
||||
void open_editor_hooks ();
|
||||
void close_editor_hooks (bool commit);
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ db::Instance
|
|||
PathService::make_via (const db::SelectedViaDefinition &via_def, double w_bottom, double h_bottom, double w_top, double h_top, const db::DPoint &via_pos)
|
||||
{
|
||||
if (! via_def.via_type.cut.is_null ()) {
|
||||
edt::set_or_request_current_layer (view (), via_def.via_type.cut, cv_index (), false /*don't make current*/);
|
||||
lay::set_or_request_current_layer (view (), via_def.via_type.cut, cv_index (), false /*don't make current*/);
|
||||
}
|
||||
|
||||
std::map<std::string, tl::Variant> params;
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ public:
|
|||
menu_entries.push_back (lay::menu_item ("edt::combine_mode", "combine_mode:edit_mode", "@toolbar.end_modes", tl::to_string (tr ("Combine{Select background combination mode}"))));
|
||||
|
||||
// Key binding only
|
||||
menu_entries.push_back (lay::menu_item ("edt::via", "via:edit_mode", "@secrets.end", tl::to_string (tr ("Via")) + "(V)"));
|
||||
menu_entries.push_back (lay::menu_item ("edt::via", "via:edit_mode", "@secrets.end", tl::to_string (tr ("Via")) + "(O)"));
|
||||
menu_entries.push_back (lay::menu_item ("edt::via_up", "via_up:edit_mode", "@secrets.end", tl::to_string (tr ("Via up"))));
|
||||
menu_entries.push_back (lay::menu_item ("edt::via_down", "via_down:edit_mode", "@secrets.end", tl::to_string (tr ("Via down"))));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@
|
|||
#if defined(HAVE_QT)
|
||||
|
||||
#include "edtRecentConfigurationPage.h"
|
||||
#include "edtUtils.h"
|
||||
#include "layDispatcher.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "layLayerTreeModel.h"
|
||||
#include "layBusy.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "tlLog.h"
|
||||
|
|
@ -267,7 +267,7 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
|||
std::map<std::string, tl::Variant> pcp;
|
||||
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++pcp_column) {
|
||||
if (c->rendering == RecentConfigurationPage::PCellParameters) {
|
||||
pcp = pcell_parameters_from_string (values [pcp_column]);
|
||||
pcp = lay::pcell_parameters_from_string (values [pcp_column]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
|||
{
|
||||
std::map<std::string, tl::Variant> pcp;
|
||||
try {
|
||||
pcp = pcell_parameters_from_string (values [column]);
|
||||
pcp = lay::pcell_parameters_from_string (values [column]);
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << tl::to_string (tr ("Configuration error (PCellParameters): ")) << ex.msg ();
|
||||
}
|
||||
|
|
@ -384,7 +384,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item)
|
|||
ex.read (cv_index);
|
||||
}
|
||||
|
||||
edt::set_or_request_current_layer (view (), lp, cv_index);
|
||||
lay::set_or_request_current_layer (view (), lp, cv_index);
|
||||
|
||||
} else {
|
||||
dispatcher ()->config_set (c->cfg_name, v);
|
||||
|
|
|
|||
|
|
@ -42,27 +42,6 @@
|
|||
namespace edt
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Convert buttons to an angle constraint
|
||||
|
||||
lay::angle_constraint_type
|
||||
ac_from_buttons (unsigned int buttons)
|
||||
{
|
||||
if ((buttons & lay::ShiftButton) != 0) {
|
||||
if ((buttons & lay::ControlButton) != 0) {
|
||||
return lay::AC_Any;
|
||||
} else {
|
||||
return lay::AC_Ortho;
|
||||
}
|
||||
} else {
|
||||
if ((buttons & lay::ControlButton) != 0) {
|
||||
return lay::AC_Diagonal;
|
||||
} else {
|
||||
return lay::AC_Global;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIterator::flags_type flags)
|
||||
|
|
@ -301,12 +280,10 @@ Service::snap (const db::DPoint &p, const db::DPoint &plast, bool connect) const
|
|||
return snap (ps);
|
||||
}
|
||||
|
||||
const int sr_pixels = 8; // TODO: make variable
|
||||
|
||||
lay::PointSnapToObjectResult
|
||||
Service::snap2_details (const db::DPoint &p) const
|
||||
{
|
||||
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
|
||||
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (lay::snap_range_pixels ());
|
||||
return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range);
|
||||
}
|
||||
|
||||
|
|
@ -319,7 +296,7 @@ Service::snap2 (const db::DPoint &p) const
|
|||
db::DPoint
|
||||
Service::snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect) const
|
||||
{
|
||||
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
|
||||
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (lay::snap_range_pixels ());
|
||||
return lay::obj_snap (m_snap_to_objects ? view () : 0, plast, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, connect ? connect_ac () : move_ac (), snap_range).snapped_point;
|
||||
}
|
||||
|
||||
|
|
@ -616,7 +593,7 @@ Service::selection_bbox ()
|
|||
{
|
||||
// build the transformation variants cache
|
||||
// TODO: this is done multiple times - once for each service!
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
const db::DCplxTrans &vp = view ()->viewport ().trans ();
|
||||
|
||||
lay::TextInfo text_info (view ());
|
||||
|
|
@ -710,7 +687,7 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
}
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
// 1.) first transform all shapes
|
||||
|
||||
|
|
@ -891,7 +868,7 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
|||
|
||||
if (m_editing || m_immediate) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
if (! m_editing) {
|
||||
// in this mode, ignore exceptions here since it is rather annoying to have messages popping
|
||||
|
|
@ -926,7 +903,7 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio
|
|||
|
||||
if ((buttons & lay::LeftButton) != 0) {
|
||||
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
|
||||
if (! m_editing) {
|
||||
|
||||
|
|
@ -971,7 +948,7 @@ bool
|
|||
Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (m_editing && prio && (buttons & lay::LeftButton) != 0) {
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
do_finish_edit ();
|
||||
m_editing = false;
|
||||
set_edit_marker (0);
|
||||
|
|
@ -986,7 +963,7 @@ bool
|
|||
Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
if (view ()->is_editable () && prio && (buttons & lay::RightButton) != 0 && m_editing) {
|
||||
m_alt_ac = ac_from_buttons (buttons);
|
||||
m_alt_ac = lay::ac_from_buttons (buttons);
|
||||
do_mouse_transform (p, db::DFTrans (db::DFTrans::r90));
|
||||
m_alt_ac = lay::AC_Global;
|
||||
return true;
|
||||
|
|
@ -1777,7 +1754,7 @@ Service::do_selection_to_view ()
|
|||
m_markers.reserve (selection_size ());
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
lay::TransformationVariants tv (view ());
|
||||
|
||||
// prepare a default transformation for empty variants
|
||||
std::vector<db::DCplxTrans> empty_tv;
|
||||
|
|
@ -1955,7 +1932,7 @@ Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj, bool comm
|
|||
|
||||
// Hint: get_parameters_from_pcell_and_guiding_shapes invalidates the shapes because it resets the changed
|
||||
// guiding shapes. We must not access s->shape after that.
|
||||
if (! get_parameters_from_pcell_and_guiding_shapes (layout, obj.cell_index (), parameters_for_pcell)) {
|
||||
if (! lay::get_parameters_from_pcell_and_guiding_shapes (layout, obj.cell_index (), parameters_for_pcell)) {
|
||||
return std::make_pair (false, lay::ObjectInstPath ());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@
|
|||
#include "laySnap.h"
|
||||
#include "layObjectInstPath.h"
|
||||
#include "layTextInfo.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "tlColor.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbShape.h"
|
||||
#include "edtUtils.h"
|
||||
#include "edtConfig.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlException.h"
|
||||
|
|
@ -55,19 +55,15 @@ class PluginDeclarationBase;
|
|||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
extern lay::angle_constraint_type ac_from_buttons (unsigned int buttons);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Utility function: serialize PCell parameters into a string
|
||||
* @brief A helper class that identifies clipboard data for edt::
|
||||
*/
|
||||
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters);
|
||||
|
||||
/**
|
||||
* @brief Utility: deserialize PCell parameters from a string
|
||||
*/
|
||||
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
|
||||
class EDT_PUBLIC ClipboardData
|
||||
: public db::ClipboardData
|
||||
{
|
||||
public:
|
||||
ClipboardData () { }
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ ShapeEditService::change_edit_layer (const db::LayerProperties &lp)
|
|||
}
|
||||
m_layer = (unsigned int) layer;
|
||||
|
||||
edt::set_or_request_current_layer (view (), lp, m_cv_index);
|
||||
lay::set_or_request_current_layer (view (), lp, m_cv_index);
|
||||
|
||||
if (editing ()) {
|
||||
close_editor_hooks (false);
|
||||
|
|
|
|||
|
|
@ -1358,6 +1358,9 @@ Object::from_string (const char *str, const char *base_dir)
|
|||
color = true;
|
||||
} else if (ex.test ("mono:")) {
|
||||
color = false;
|
||||
} else {
|
||||
// unrecognized token
|
||||
return;
|
||||
}
|
||||
|
||||
size_t w = 0;
|
||||
|
|
@ -2499,13 +2502,19 @@ Object::mem_stat (db::MemStatistics *stat, db::MemStatistics::purpose_t purpose,
|
|||
const char *
|
||||
Object::class_name () const
|
||||
{
|
||||
return "img::Object";
|
||||
if (m_layer_binding != db::LayerProperties ()) {
|
||||
// This makes old KLayout versions ignore these images and not crash
|
||||
return "img::ObjectV2";
|
||||
} else {
|
||||
return "img::Object";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registration of the img::Object class in the DUserObject space
|
||||
*/
|
||||
static db::DUserObjectDeclaration class_registrar (new db::user_object_factory_impl<img::Object, db::DCoord> ("img::Object"));
|
||||
static db::DUserObjectDeclaration class_registrar_v2 (new db::user_object_factory_impl<img::Object, db::DCoord> ("img::ObjectV2"));
|
||||
|
||||
} // namespace img
|
||||
|
||||
|
|
|
|||
|
|
@ -1080,6 +1080,7 @@ Service::edit_cancel ()
|
|||
{
|
||||
if (m_move_mode != move_none) {
|
||||
m_move_mode = move_none;
|
||||
m_selected.clear ();
|
||||
selection_to_view ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1118,14 +1119,27 @@ Service::paste ()
|
|||
{
|
||||
if (db::Clipboard::instance ().begin () != db::Clipboard::instance ().end ()) {
|
||||
|
||||
std::vector<const db::DUserObject *> new_objects;
|
||||
|
||||
for (db::Clipboard::iterator c = db::Clipboard::instance ().begin (); c != db::Clipboard::instance ().end (); ++c) {
|
||||
const db::ClipboardValue<img::Object> *value = dynamic_cast<const db::ClipboardValue<img::Object> *> (*c);
|
||||
if (value) {
|
||||
img::Object *image = new img::Object (value->get ());
|
||||
mp_view->annotation_shapes ().insert (db::DUserObject (image));
|
||||
new_objects.push_back (&mp_view->annotation_shapes ().insert (db::DUserObject (image)));
|
||||
}
|
||||
}
|
||||
|
||||
// make new objects selected
|
||||
|
||||
if (! new_objects.empty ()) {
|
||||
|
||||
for (auto r = new_objects.begin (); r != new_objects.end (); ++r) {
|
||||
m_selected.insert (mp_view->annotation_shapes ().iterator_from_pointer (*r));
|
||||
}
|
||||
|
||||
selection_to_view ();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
|
||||
#include "gsiDeclLayConfigPage.h"
|
||||
|
||||
#include "gsiQtGuiExternals.h"
|
||||
#include "gsiQtWidgetsExternals.h" // for Qt5
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
ConfigPageImpl::ConfigPageImpl (const std::string &title)
|
||||
: lay::ConfigPage (0), m_title (title)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
ConfigPageImpl::commit_impl (lay::Dispatcher *root)
|
||||
{
|
||||
lay::ConfigPage::commit (root);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigPageImpl::commit (lay::Dispatcher *root)
|
||||
{
|
||||
if (f_commit.can_issue ()) {
|
||||
f_commit.issue<ConfigPageImpl, lay::Dispatcher *> (&ConfigPageImpl::commit_impl, root);
|
||||
} else {
|
||||
ConfigPageImpl::commit_impl (root);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ConfigPageImpl::setup_impl (lay::Dispatcher *root)
|
||||
{
|
||||
lay::ConfigPage::setup (root);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigPageImpl::setup (lay::Dispatcher *root)
|
||||
{
|
||||
if (f_setup.can_issue ()) {
|
||||
f_setup.issue<ConfigPageImpl, lay::Dispatcher *> (&ConfigPageImpl::setup_impl, root);
|
||||
} else {
|
||||
ConfigPageImpl::setup_impl (root);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigPageImpl *new_config_page (const std::string &title)
|
||||
{
|
||||
return new ConfigPageImpl (title);
|
||||
}
|
||||
|
||||
Class<ConfigPageImpl> decl_ConfigPage (QT_EXTERNAL_BASE (QFrame) "lay", "ConfigPage",
|
||||
constructor ("new", &new_config_page, gsi::arg ("title"),
|
||||
"@brief Creates a new ConfigPage object\n"
|
||||
"@param title The title of the page and also the position in the configuration page tree\n"
|
||||
"\n"
|
||||
"The title has the form 'Group|Page' - e.g. 'Application|Macro Development IDE' will place "
|
||||
"the configuration page in the 'Application' group and into the 'Macro Development IDE' page."
|
||||
) +
|
||||
callback ("apply", &ConfigPageImpl::commit, &ConfigPageImpl::f_commit, gsi::arg ("dispatcher"),
|
||||
"@brief Reimplement this method to transfer data from the page to the configuration\n"
|
||||
"In this method, you should transfer all widget data into corresponding configuration updates.\n"
|
||||
"Use \\Dispatcher#set_config on the dispatcher object ('dispatcher' argument) to set a configuration parameter.\n"
|
||||
) +
|
||||
callback ("setup", &ConfigPageImpl::setup, &ConfigPageImpl::f_setup, gsi::arg ("dispatcher"),
|
||||
"@brief Reimplement this method to transfer data from the configuration to the page\n"
|
||||
"In this method, you should transfer all configuration data to the widgets.\n"
|
||||
"Use \\Dispatcher#get_config on the dispatcher object ('dispatcher' argument) to get a configuration parameter "
|
||||
"and set the editing widget's state accordingly.\n"
|
||||
),
|
||||
"@brief The plugin framework's configuration page\n"
|
||||
"\n"
|
||||
"This object provides a way to establish plugin-specific configuration pages.\n"
|
||||
"\n"
|
||||
"The only way of communication between the page and the plugin is through "
|
||||
"configuration parameters. One advantage of this approach is that the current state is "
|
||||
"automatically persisted. Configuration parameters can be obtained by the plugin "
|
||||
"directly from the \\Dispatcher object) or by listening to 'configure' calls.\n"
|
||||
"\n"
|
||||
"For the purpose of data transfer, the configuration page has two methods: 'apply' which is supposed to transfer "
|
||||
"the editor widget's state into configuration parameters. 'setup' does the inverse and transfer "
|
||||
"configuration parameters into editor widget states. Both methods are called by the system when "
|
||||
"some transfer is needed.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.30.4.\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if !defined(_HDR_gsiDeclLayConfigPage)
|
||||
#define _HDR_gsiDeclLayConfigPage
|
||||
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
|
||||
#include "layPluginConfigPage.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
class ConfigPageImpl
|
||||
: public lay::ConfigPage, public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
ConfigPageImpl (const std::string &title);
|
||||
|
||||
virtual std::string title () const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void commit_impl (lay::Dispatcher *root);
|
||||
virtual void commit (lay::Dispatcher *root);
|
||||
void setup_impl (lay::Dispatcher *root);
|
||||
virtual void setup (lay::Dispatcher *root);
|
||||
|
||||
gsi::Callback f_commit;
|
||||
gsi::Callback f_setup;
|
||||
|
||||
private:
|
||||
tl::weak_ptr<lay::LayoutViewBase> mp_view;
|
||||
tl::weak_ptr<lay::Dispatcher> mp_dispatcher;
|
||||
std::string m_title;
|
||||
std::string m_index;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
|
||||
#include "gsiDeclLayEditorOptionsPage.h"
|
||||
|
||||
#include "gsiQtGuiExternals.h"
|
||||
#include "gsiQtWidgetsExternals.h" // for Qt5
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
Class<lay::EditorOptionsPage> decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWidget) "lay", "EditorOptionsPageBase",
|
||||
method ("view", &lay::EditorOptionsPage::view,
|
||||
"@brief Gets the view object this page is associated with\n"
|
||||
) +
|
||||
method ("title", &lay::EditorOptionsPage::title,
|
||||
"@brief Gets the title string of the page\n"
|
||||
) +
|
||||
method ("order", &lay::EditorOptionsPage::order,
|
||||
"@brief Gets the order index of the page\n"
|
||||
) +
|
||||
method ("is_focus_page?", &lay::EditorOptionsPage::is_focus_page,
|
||||
"@brief Gets a flag indicating whether the page is a focus page\n"
|
||||
"See \\focus_page= for a description is this attribute.\n"
|
||||
) +
|
||||
method ("focus_page=", &lay::EditorOptionsPage::set_focus_page, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether the page is a focus page\n"
|
||||
"The focus page is the page that is selected when the tab key is pressed during some plugin action.\n"
|
||||
) +
|
||||
method ("is_modal_page?", &lay::EditorOptionsPage::is_modal_page,
|
||||
"@brief Gets a flag indicating whether the page is a modal page\n"
|
||||
"See \\modal_page= for a description is this attribute.\n"
|
||||
) +
|
||||
method ("modal_page=", &lay::EditorOptionsPage::set_modal_page, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether the page is a modal page\n"
|
||||
"A modal page is shown in a modal dialog upon \\show. Non-modal pages are shown in the "
|
||||
"editor options dock.\n"
|
||||
) +
|
||||
method ("show", &lay::EditorOptionsPage::show,
|
||||
"@brief Shows the page\n"
|
||||
"@return A value indicating whether the page was opened non-modal (-1), accepted (1) or rejected (0)\n"
|
||||
"Provided the page is selected because the plugin is active, this method will "
|
||||
"open a dialog to show the page if it is modal, or locate the page in the editor options "
|
||||
"dock and bring it to the front if it is non-modal.\n"
|
||||
"\n"
|
||||
"Before the page is shown, \\setup is called. When the page is dismissed (accepted), \\apply is called. "
|
||||
"You can overload these methods to transfer data to and from the configuration space or to perform other "
|
||||
"actions, not related to configuration parameters."
|
||||
) +
|
||||
method ("apply", &lay::EditorOptionsPage::apply, gsi::arg ("dispatcher"),
|
||||
"@brief Transfers data from the page to the configuration\n"
|
||||
) +
|
||||
method ("setup", &lay::EditorOptionsPage::setup, gsi::arg ("dispatcher"),
|
||||
"@brief Transfers data from the configuration to the page\n"
|
||||
),
|
||||
"@brief The plugin framework's editor options page base class\n"
|
||||
"\n"
|
||||
"This class is provided as an interface to the base class implementation for various functions.\n"
|
||||
"You can use these methods in order to pass down events to the original implementation or access\n"
|
||||
"objects not created in script space.\n"
|
||||
"\n"
|
||||
"It features some useful methods such as 'view' and provides a slot to call for triggering a data "
|
||||
"transfer ('edited').\n"
|
||||
"\n"
|
||||
"Note that even though the page class is derived from QWidget, you can call QWidget methods "
|
||||
"but not overload virtual methods from QWidget.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.30.4.\n"
|
||||
);
|
||||
|
||||
EditorOptionsPageImpl::EditorOptionsPageImpl (const std::string &title, int index)
|
||||
: lay::EditorOptionsPage (), m_title (title), m_index (index)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPageImpl::call_edited ()
|
||||
{
|
||||
lay::EditorOptionsPage::edited ();
|
||||
}
|
||||
|
||||
static void apply_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
|
||||
{
|
||||
ep->lay::EditorOptionsPage::apply (root);
|
||||
}
|
||||
|
||||
static void setup_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
|
||||
{
|
||||
ep->lay::EditorOptionsPage::setup (root);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPageImpl::apply_impl (lay::Dispatcher *root)
|
||||
{
|
||||
lay::EditorOptionsPage::apply (root);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPageImpl::apply (lay::Dispatcher *root)
|
||||
{
|
||||
if (f_apply.can_issue ()) {
|
||||
f_apply.issue<EditorOptionsPageImpl, lay::Dispatcher *> (&EditorOptionsPageImpl::apply_impl, root);
|
||||
} else {
|
||||
EditorOptionsPageImpl::apply_impl (root);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPageImpl::setup_impl (lay::Dispatcher *root)
|
||||
{
|
||||
lay::EditorOptionsPage::setup (root);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPageImpl::setup (lay::Dispatcher *root)
|
||||
{
|
||||
if (f_setup.can_issue ()) {
|
||||
f_setup.issue<EditorOptionsPageImpl, lay::Dispatcher *> (&EditorOptionsPageImpl::setup_impl, root);
|
||||
} else {
|
||||
EditorOptionsPageImpl::setup_impl (root);
|
||||
}
|
||||
}
|
||||
|
||||
EditorOptionsPageImpl *new_editor_options_page (const std::string &title, int index)
|
||||
{
|
||||
return new EditorOptionsPageImpl (title, index);
|
||||
}
|
||||
|
||||
Class<EditorOptionsPageImpl> decl_EditorOptionsPage (decl_EditorOptionsPageBase, "lay", "EditorOptionsPage",
|
||||
constructor ("new", &new_editor_options_page, gsi::arg ("title"), gsi::arg ("index"),
|
||||
"@brief Creates a new EditorOptionsPage object\n"
|
||||
"@param title The title of the page\n"
|
||||
"@param index The position of the page in the tab bar\n"
|
||||
) +
|
||||
method ("edited", &EditorOptionsPageImpl::call_edited,
|
||||
"@brief Call this method when some entry widget has changed\n"
|
||||
"When some entry widget (for example 'editingFinished' slot of a QLineEdit), "
|
||||
"call this method to initiate a transfer of information from the page to the plugin.\n"
|
||||
) +
|
||||
// prevents infinite recursion
|
||||
method_ext ("apply", &apply_fb, gsi::arg ("dispatcher"), "@hide") +
|
||||
callback ("apply", &EditorOptionsPageImpl::apply, &EditorOptionsPageImpl::f_apply, gsi::arg ("dispatcher"),
|
||||
"@brief Reimplement this method to transfer data from the page to the configuration\n"
|
||||
"In this method, you should transfer all widget data into corresponding configuration updates.\n"
|
||||
"Use \\Dispatcher#set_config on the dispatcher object ('dispatcher' argument) to set a configuration parameter.\n"
|
||||
) +
|
||||
// prevents infinite recursion
|
||||
method_ext ("setup", &setup_fb, gsi::arg ("dispatcher"), "@hide") +
|
||||
callback ("setup", &EditorOptionsPageImpl::setup, &EditorOptionsPageImpl::f_setup, gsi::arg ("dispatcher"),
|
||||
"@brief Reimplement this method to transfer data from the configuration to the page\n"
|
||||
"In this method, you should transfer all configuration data to the widgets.\n"
|
||||
"Use \\Dispatcher#get_config on the dispatcher object ('dispatcher' argument) to get a configuration parameter "
|
||||
"and set the editing widget's state accordingly.\n"
|
||||
),
|
||||
"@brief The plugin framework's editor options page\n"
|
||||
"\n"
|
||||
"This object provides a way to establish plugin-specific editor options pages.\n"
|
||||
"\n"
|
||||
"The preferred way of communication between the page and the plugin is through "
|
||||
"configuration parameters. One advantage of this approach is that the current state is "
|
||||
"automatically persisted.\n"
|
||||
"\n"
|
||||
"For this purpose, the editor options page has two methods: 'apply' which is supposed to transfer "
|
||||
"the editor widget's state into configuration parameters. 'setup' does the inverse and transfer "
|
||||
"configuration parameters into editor widget states. Both methods are called by the system when "
|
||||
"some transfer is needed.\n"
|
||||
"\n"
|
||||
"When you want to respond to widget signals and transfer information, call \\edited "
|
||||
"in the signal slot. This will trigger a transfer (aka 'apply').\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.30.4.\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if !defined(_HDR_gsiDeclLayEditorOptionsPage)
|
||||
#define _HDR_gsiDeclLayEditorOptionsPage
|
||||
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
|
||||
#include "layEditorOptionsPage.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
class EditorOptionsPageImpl
|
||||
: public lay::EditorOptionsPage, public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
EditorOptionsPageImpl (const std::string &title, int index);
|
||||
|
||||
virtual std::string title () const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
virtual int order () const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
void call_edited ();
|
||||
virtual void apply (lay::Dispatcher *root);
|
||||
virtual void setup (lay::Dispatcher *root);
|
||||
|
||||
gsi::Callback f_apply;
|
||||
gsi::Callback f_setup;
|
||||
|
||||
private:
|
||||
tl::weak_ptr<lay::LayoutViewBase> mp_view;
|
||||
tl::weak_ptr<lay::Dispatcher> mp_dispatcher;
|
||||
std::string m_title;
|
||||
int m_index;
|
||||
|
||||
void apply_impl (lay::Dispatcher *root);
|
||||
void setup_impl (lay::Dispatcher *root);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,153 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HDR_gsiDeclLayPlugin
|
||||
#define _HDR_gsiDeclLayPlugin
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
|
||||
#include "layEditorServiceBase.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
class PluginImpl
|
||||
: public lay::EditorServiceBase
|
||||
{
|
||||
public:
|
||||
PluginImpl ();
|
||||
|
||||
void init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
|
||||
void grab_mouse ();
|
||||
void ungrab_mouse ();
|
||||
void set_cursor (int c);
|
||||
|
||||
virtual void menu_activated (const std::string &symbol);
|
||||
db::DPoint snap (db::DPoint p) const;
|
||||
db::DVector snap_vector (db::DVector v) const;
|
||||
db::DPoint snap_from_to (const db::DPoint &p, const db::DPoint &plast, bool connect, lay::angle_constraint_type ac) const;
|
||||
db::DVector snap_delta (const db::DVector &v, bool connect, lay::angle_constraint_type ac) const;
|
||||
db::DPoint snap2 (const db::DPoint &p, bool visualize);
|
||||
db::DPoint snap2_from_to (const db::DPoint &p, const db::DPoint &plast, bool connect, lay::angle_constraint_type ac, bool visualize);
|
||||
|
||||
// Captures some edt space configuration events for convencience
|
||||
void configure_edt (const std::string &name, const std::string &value);
|
||||
// NOTE: The implementation does not allow to bypass the base class configuration call
|
||||
bool configure_impl (const std::string &name, const std::string &value);
|
||||
// for testing
|
||||
void configure_test (const std::string &name, const std::string &value);
|
||||
virtual bool configure (const std::string &name, const std::string &value);
|
||||
// NOTE: The implementation does not allow to bypass the base class configuration call
|
||||
virtual void config_finalize_impl ();
|
||||
virtual void config_finalize ();
|
||||
virtual bool key_event (unsigned int key, unsigned int buttons);
|
||||
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio) ;
|
||||
bool mouse_press_event_noref (db::DPoint p, unsigned int buttons, bool prio);
|
||||
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
bool mouse_click_event_noref (db::DPoint p, unsigned int buttons, bool prio);
|
||||
virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
bool mouse_double_click_event_noref (db::DPoint p, unsigned int buttons, bool prio);
|
||||
virtual bool leave_event (bool prio);
|
||||
virtual bool enter_event (bool prio);
|
||||
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
bool mouse_move_event_noref (db::DPoint p, unsigned int buttons, bool prio);
|
||||
virtual bool mouse_release_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
bool mouse_release_event_noref (db::DPoint p, unsigned int buttons, bool prio);
|
||||
virtual bool wheel_event (int delta, bool horizontal, const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
bool wheel_event_noref (int delta, bool horizontal, db::DPoint p, unsigned int buttons, bool prio);
|
||||
void activated_impl ();
|
||||
virtual void activated ();
|
||||
void deactivated_impl ();
|
||||
virtual void deactivated ();
|
||||
virtual void drag_cancel ();
|
||||
virtual void update ();
|
||||
void add_mouse_cursor_dpoint (const db::DPoint &p, bool emphasize);
|
||||
void add_mouse_cursor_point (const db::Point &p, int cv_index, const db::LayerProperties &lp, bool emphasize);
|
||||
void add_edge_marker_dedge (const db::DEdge &p, bool emphasize);
|
||||
void add_edge_marker_edge (const db::Edge &p, int cv_index, const db::LayerProperties &lp, bool emphasize);
|
||||
|
||||
// for testing
|
||||
bool has_tracking_position_test () const;
|
||||
virtual bool has_tracking_position () const;
|
||||
|
||||
// for testing
|
||||
db::DPoint tracking_position_test () const;
|
||||
virtual db::DPoint tracking_position () const;
|
||||
|
||||
virtual int focus_page_open ();
|
||||
|
||||
virtual lay::ViewService *view_service_interface ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
lay::LayoutViewBase *view () const
|
||||
{
|
||||
return const_cast<lay::LayoutViewBase *> (mp_view.get ());
|
||||
}
|
||||
|
||||
lay::Dispatcher *dispatcher () const
|
||||
{
|
||||
return const_cast<lay::Dispatcher *> (mp_dispatcher.get ());
|
||||
}
|
||||
|
||||
gsi::Callback f_menu_activated;
|
||||
gsi::Callback f_configure;
|
||||
gsi::Callback f_config_finalize;
|
||||
gsi::Callback f_key_event;
|
||||
gsi::Callback f_mouse_press_event;
|
||||
gsi::Callback f_mouse_click_event;
|
||||
gsi::Callback f_mouse_double_click_event;
|
||||
gsi::Callback f_leave_event;
|
||||
gsi::Callback f_enter_event;
|
||||
gsi::Callback f_mouse_move_event;
|
||||
gsi::Callback f_mouse_release_event;
|
||||
gsi::Callback f_wheel_event;
|
||||
gsi::Callback f_activated;
|
||||
gsi::Callback f_deactivated;
|
||||
gsi::Callback f_drag_cancel;
|
||||
gsi::Callback f_update;
|
||||
gsi::Callback f_has_tracking_position;
|
||||
gsi::Callback f_tracking_position;
|
||||
gsi::Callback f_focus_page_open;
|
||||
|
||||
private:
|
||||
tl::weak_ptr<lay::LayoutViewBase> mp_view;
|
||||
tl::weak_ptr<lay::Dispatcher> mp_dispatcher;
|
||||
|
||||
// Angle constraints and grids
|
||||
lay::angle_constraint_type m_connect_ac, m_move_ac;
|
||||
db::DVector m_edit_grid;
|
||||
bool m_snap_to_objects;
|
||||
bool m_snap_objects_to_grid;
|
||||
db::DVector m_global_grid;
|
||||
|
||||
lay::angle_constraint_type connect_ac (lay::angle_constraint_type ac) const;
|
||||
lay::angle_constraint_type move_ac (lay::angle_constraint_type ac) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,602 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
#include "gsiEnums.h"
|
||||
|
||||
#include "gsiDeclLayEditorOptionsPage.h"
|
||||
#include "gsiDeclLayConfigPage.h"
|
||||
#include "gsiDeclLayPlugin.h"
|
||||
|
||||
#include "layEditorOptionsPages.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
class PluginFactoryBase;
|
||||
|
||||
static std::map <std::string, PluginFactoryBase *> s_factories;
|
||||
extern bool s_in_create_plugin;
|
||||
|
||||
class PluginFactoryBase
|
||||
: public lay::PluginDeclaration
|
||||
{
|
||||
public:
|
||||
PluginFactoryBase ()
|
||||
: PluginDeclaration (),
|
||||
m_implements_mouse_mode (true), mp_registration (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~PluginFactoryBase ()
|
||||
{
|
||||
for (auto f = s_factories.begin (); f != s_factories.end (); ++f) {
|
||||
if (f->second == this) {
|
||||
s_factories.erase (f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete mp_registration;
|
||||
mp_registration = 0;
|
||||
}
|
||||
|
||||
void register_gsi (int position, const char *name, const char *title)
|
||||
{
|
||||
register_gsi2 (position, name, title, 0);
|
||||
}
|
||||
|
||||
void register_gsi2 (int position, const char *name, const char *title, const char *icon)
|
||||
{
|
||||
// makes the object owned by the C++ side
|
||||
keep ();
|
||||
|
||||
// remove an existing factory with the same name
|
||||
std::map <std::string, PluginFactoryBase *>::iterator f = s_factories.find (name);
|
||||
if (f != s_factories.end () && f->second != this) {
|
||||
// NOTE: this also removes the plugin from the s_factories list
|
||||
delete f->second;
|
||||
}
|
||||
s_factories[name] = this;
|
||||
|
||||
// cancel any previous registration and register (again)
|
||||
delete mp_registration;
|
||||
mp_registration = new tl::RegisteredClass<lay::PluginDeclaration> (this, position, name, false /*does not own object*/);
|
||||
|
||||
m_mouse_mode_title = name;
|
||||
if (title) {
|
||||
m_mouse_mode_title += "\t";
|
||||
m_mouse_mode_title += title;
|
||||
}
|
||||
if (icon) {
|
||||
m_mouse_mode_title += "\t<";
|
||||
m_mouse_mode_title += icon;
|
||||
m_mouse_mode_title += ">";
|
||||
}
|
||||
|
||||
// (dynamically) register the plugin class. This will also call initialize if the main window is
|
||||
// present already.
|
||||
register_plugin ();
|
||||
}
|
||||
|
||||
virtual bool configure (const std::string &name, const std::string &value)
|
||||
{
|
||||
if (f_configure.can_issue ()) {
|
||||
return f_configure.issue<lay::PluginDeclaration, bool, const std::string &, const std::string &> (&lay::PluginDeclaration::configure, name, value);
|
||||
} else {
|
||||
return lay::PluginDeclaration::configure (name, value);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void config_finalize ()
|
||||
{
|
||||
if (f_config_finalize.can_issue ()) {
|
||||
f_config_finalize.issue<lay::PluginDeclaration> (&lay::PluginDeclaration::config_finalize);
|
||||
} else {
|
||||
lay::PluginDeclaration::config_finalize ();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool menu_activated (const std::string &symbol) const
|
||||
{
|
||||
if (f_menu_activated.can_issue ()) {
|
||||
return f_menu_activated.issue<lay::PluginDeclaration, bool, const std::string &> (&lay::PluginDeclaration::menu_activated, symbol);
|
||||
} else {
|
||||
return lay::PluginDeclaration::menu_activated (symbol);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void initialize (lay::Dispatcher *root)
|
||||
{
|
||||
if (f_initialize.can_issue ()) {
|
||||
f_initialize.issue<lay::PluginDeclaration> (&lay::PluginDeclaration::initialize, root);
|
||||
} else {
|
||||
lay::PluginDeclaration::initialize (root);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void uninitialize (lay::Dispatcher *root)
|
||||
{
|
||||
if (f_uninitialize.can_issue ()) {
|
||||
f_uninitialize.issue<lay::PluginDeclaration> (&lay::PluginDeclaration::uninitialize, root);
|
||||
} else {
|
||||
lay::PluginDeclaration::uninitialize (root);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
void add_editor_options_page (EditorOptionsPageImpl *page) const
|
||||
{
|
||||
page->keep ();
|
||||
m_editor_options_pages.push_back (page);
|
||||
}
|
||||
|
||||
void get_editor_options_pages_impl () const
|
||||
{
|
||||
// .. nothing here ..
|
||||
}
|
||||
|
||||
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages_out, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
|
||||
{
|
||||
try {
|
||||
|
||||
m_editor_options_pages.clear ();
|
||||
|
||||
if (f_get_editor_options_pages.can_issue ()) {
|
||||
f_get_editor_options_pages.issue<PluginFactoryBase> (&PluginFactoryBase::get_editor_options_pages_impl);
|
||||
} else {
|
||||
get_editor_options_pages_impl ();
|
||||
}
|
||||
|
||||
for (auto i = m_editor_options_pages.begin (); i != m_editor_options_pages.end (); ++i) {
|
||||
if (*i) {
|
||||
(*i)->init (view, dispatcher);
|
||||
(*i)->set_plugin_declaration (this);
|
||||
pages_out.push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
m_editor_options_pages.clear ();
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
} catch (std::exception &ex) {
|
||||
tl::error << ex.what ();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
void add_config_page (ConfigPageImpl *page) const
|
||||
{
|
||||
page->keep ();
|
||||
m_config_pages.push_back (page);
|
||||
}
|
||||
|
||||
void get_config_pages_impl () const
|
||||
{
|
||||
// .. nothing here ..
|
||||
}
|
||||
|
||||
virtual std::vector<std::pair <std::string, lay::ConfigPage *> > config_pages (QWidget *parent) const
|
||||
{
|
||||
std::vector<std::pair <std::string, lay::ConfigPage *> > pages_out;
|
||||
|
||||
try {
|
||||
|
||||
m_config_pages.clear ();
|
||||
|
||||
if (f_config_pages.can_issue ()) {
|
||||
f_config_pages.issue<PluginFactoryBase> (&PluginFactoryBase::get_config_pages_impl);
|
||||
} else {
|
||||
get_config_pages_impl ();
|
||||
}
|
||||
|
||||
pages_out.clear ();
|
||||
for (auto i = m_config_pages.begin (); i != m_config_pages.end (); ++i) {
|
||||
if (*i) {
|
||||
(*i)->setParent (parent);
|
||||
pages_out.push_back (std::make_pair ((*i)->title (), *i));
|
||||
}
|
||||
}
|
||||
|
||||
m_config_pages.clear ();
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
} catch (std::exception &ex) {
|
||||
tl::error << ex.what ();
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
return pages_out;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *root, lay::LayoutViewBase *view) const
|
||||
{
|
||||
if (f_create_plugin.can_issue ()) {
|
||||
return create_plugin_gsi (manager, root, view);
|
||||
} else {
|
||||
return lay::PluginDeclaration::create_plugin (manager, root, view);
|
||||
}
|
||||
}
|
||||
|
||||
virtual gsi::PluginImpl *create_plugin_gsi (db::Manager *manager, lay::Dispatcher *root, lay::LayoutViewBase *view) const
|
||||
{
|
||||
s_in_create_plugin = true;
|
||||
|
||||
gsi::PluginImpl *ret = 0;
|
||||
try {
|
||||
|
||||
ret = f_create_plugin.issue<PluginFactoryBase, gsi::PluginImpl *, db::Manager *, lay::Dispatcher *, lay::LayoutViewBase *> (&PluginFactoryBase::create_plugin_gsi, manager, root, view);
|
||||
if (ret) {
|
||||
ret->init (view, root);
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
} catch (std::exception &ex) {
|
||||
tl::error << ex.what ();
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
s_in_create_plugin = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
|
||||
{
|
||||
menu_entries = m_menu_entries;
|
||||
}
|
||||
|
||||
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
|
||||
{
|
||||
options = m_options;
|
||||
}
|
||||
|
||||
void add_menu_entry1 (const std::string &menu_name, const std::string &insert_pos)
|
||||
{
|
||||
m_menu_entries.push_back (lay::separator (menu_name, insert_pos));
|
||||
}
|
||||
|
||||
void add_menu_entry2 (const std::string &symbol, const std::string &menu_name, const std::string &insert_pos, const std::string &title)
|
||||
{
|
||||
m_menu_entries.push_back (lay::menu_item (symbol, menu_name, insert_pos, title));
|
||||
}
|
||||
|
||||
void add_menu_entry_copy (const std::string &symbol, const std::string &menu_name, const std::string &insert_pos, const std::string ©_from)
|
||||
{
|
||||
m_menu_entries.push_back (lay::menu_item_copy (symbol, menu_name, insert_pos, copy_from));
|
||||
}
|
||||
|
||||
void add_submenu (const std::string &menu_name, const std::string &insert_pos, const std::string &title)
|
||||
{
|
||||
m_menu_entries.push_back (lay::submenu (menu_name, insert_pos, title));
|
||||
}
|
||||
|
||||
void add_config_menu_item (const std::string &menu_name, const std::string &insert_pos, const std::string &title, const std::string &cname, const std::string &cvalue)
|
||||
{
|
||||
m_menu_entries.push_back (lay::config_menu_item (menu_name, insert_pos, title, cname, cvalue));
|
||||
}
|
||||
|
||||
void add_menu_entry3 (const std::string &symbol, const std::string &menu_name, const std::string &insert_pos, const std::string &title, bool sub_menu)
|
||||
{
|
||||
if (sub_menu) {
|
||||
m_menu_entries.push_back (lay::submenu (symbol, menu_name, insert_pos, title));
|
||||
} else {
|
||||
m_menu_entries.push_back (lay::menu_item (symbol, menu_name, insert_pos, title));
|
||||
}
|
||||
}
|
||||
|
||||
void add_option (const std::string &name, const std::string &default_value)
|
||||
{
|
||||
m_options.push_back (std::make_pair (name, default_value));
|
||||
}
|
||||
|
||||
void has_tool_entry (bool f)
|
||||
{
|
||||
m_implements_mouse_mode = f;
|
||||
}
|
||||
|
||||
virtual bool implements_mouse_mode (std::string &title) const
|
||||
{
|
||||
title = m_mouse_mode_title;
|
||||
return m_implements_mouse_mode;
|
||||
}
|
||||
|
||||
gsi::Callback f_create_plugin;
|
||||
gsi::Callback f_initialize;
|
||||
gsi::Callback f_uninitialize;
|
||||
gsi::Callback f_configure;
|
||||
gsi::Callback f_config_finalize;
|
||||
gsi::Callback f_menu_activated;
|
||||
gsi::Callback f_get_editor_options_pages;
|
||||
gsi::Callback f_config_pages;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, std::string> > m_options;
|
||||
std::vector<lay::MenuEntry> m_menu_entries;
|
||||
bool m_implements_mouse_mode;
|
||||
std::string m_mouse_mode_title;
|
||||
tl::RegisteredClass <lay::PluginDeclaration> *mp_registration;
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
mutable std::vector<ConfigPageImpl *> m_config_pages;
|
||||
mutable std::vector<EditorOptionsPageImpl *> m_editor_options_pages;
|
||||
#endif
|
||||
};
|
||||
|
||||
Class<gsi::PluginFactoryBase> decl_PluginFactory ("lay", "PluginFactory",
|
||||
method ("register", &PluginFactoryBase::register_gsi, gsi::arg ("position"), gsi::arg ("name"), gsi::arg ("title"),
|
||||
"@brief Registers the plugin factory\n"
|
||||
"@param position An integer that determines the order in which the plugins are created. The internal plugins use the values from 1000 to 50000.\n"
|
||||
"@param name The plugin name. This is an arbitrary string which should be unique. Hence it is recommended to use a unique prefix, i.e. \"myplugin::ThePluginClass\".\n"
|
||||
"@param title The title string which is supposed to appear in the tool bar and menu related to this plugin.\n"
|
||||
"\n"
|
||||
"Registration of the plugin factory makes the object known to the system. Registration requires that the menu items have been set "
|
||||
"already. Hence it is recommended to put the registration at the end of the initialization method of the factory class.\n"
|
||||
) +
|
||||
method ("register", &PluginFactoryBase::register_gsi2, gsi::arg ("position"), gsi::arg ("name"), gsi::arg ("title"), gsi::arg ("icon"),
|
||||
"@brief Registers the plugin factory\n"
|
||||
"@param position An integer that determines the order in which the plugins are created. The internal plugins use the values from 1000 to 50000.\n"
|
||||
"@param name The plugin name. This is an arbitrary string which should be unique. Hence it is recommended to use a unique prefix, i.e. \"myplugin::ThePluginClass\".\n"
|
||||
"@param title The title string which is supposed to appear in the tool bar and menu related to this plugin.\n"
|
||||
"@param icon The path to the icon that appears in the tool bar and menu related to this plugin.\n"
|
||||
"\n"
|
||||
"This version also allows registering an icon for the tool bar.\n"
|
||||
"\n"
|
||||
"Registration of the plugin factory makes the object known to the system. Registration requires that the menu items have been set "
|
||||
"already. Hence it is recommended to put the registration at the end of the initialization method of the factory class.\n"
|
||||
) +
|
||||
callback ("configure", &gsi::PluginFactoryBase::configure, &gsi::PluginFactoryBase::f_configure, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Gets called for configuration events for the plugin singleton\n"
|
||||
"This method can be reimplemented to receive configuration events "
|
||||
"for the plugin singleton. Before a configuration can be received it must be "
|
||||
"registered by calling \\add_option in the plugin factories' constructor.\n"
|
||||
"\n"
|
||||
"The implementation of this method may return true indicating that the configuration request "
|
||||
"will not be handled by further modules. It's more cooperative to return false which will "
|
||||
"make the system distribute the configuration request to other receivers as well.\n"
|
||||
"\n"
|
||||
"@param name The configuration key\n"
|
||||
"@param value The value of the configuration variable\n"
|
||||
"@return True to stop further processing\n"
|
||||
) +
|
||||
callback ("config_finalize", &gsi::PluginFactoryBase::config_finalize, &gsi::PluginFactoryBase::f_config_finalize,
|
||||
"@brief Gets called after a set of configuration events has been sent\n"
|
||||
"This method can be reimplemented and is called after a set of configuration events "
|
||||
"has been sent to the plugin factory singleton with \\configure. It can be used to "
|
||||
"set up user interfaces properly for example.\n"
|
||||
) +
|
||||
callback ("menu_activated", &gsi::PluginFactoryBase::menu_activated, &gsi::PluginFactoryBase::f_menu_activated, gsi::arg ("symbol"),
|
||||
"@brief Gets called when a menu item is selected\n"
|
||||
"\n"
|
||||
"Usually, menu-triggered functionality is implemented in the per-view instance of the plugin. "
|
||||
"However, using this method it is possible to implement functionality globally for all plugin "
|
||||
"instances. The symbol is the string registered with the specific menu item in the \\add_menu_item "
|
||||
"call.\n"
|
||||
"\n"
|
||||
"If this method was handling the menu event, it should return true. This indicates that the event "
|
||||
"will not be propagated to other plugins hence avoiding duplicate calls.\n"
|
||||
) +
|
||||
callback ("initialized", &gsi::PluginFactoryBase::initialize, &gsi::PluginFactoryBase::f_initialize, gsi::arg ("dispatcher"),
|
||||
"@brief Gets called when the plugin singleton is initialized, i.e. when the application has been started.\n"
|
||||
"@param dispatcher The reference to the \\MainWindow object\n"
|
||||
) +
|
||||
callback ("uninitialized", &gsi::PluginFactoryBase::uninitialize, &gsi::PluginFactoryBase::f_uninitialize, gsi::arg ("dispatcher"),
|
||||
"@brief Gets called when the application shuts down and the plugin is unregistered\n"
|
||||
"This event can be used to free resources allocated with this factory singleton.\n"
|
||||
"@param dispatcher The reference to the \\MainWindow object\n"
|
||||
) +
|
||||
factory_callback ("create_plugin", &gsi::PluginFactoryBase::create_plugin_gsi, &gsi::PluginFactoryBase::f_create_plugin, gsi::arg ("manager"), gsi::arg ("dispatcher"), gsi::arg ("view"),
|
||||
"@brief Creates the plugin\n"
|
||||
"This is the basic functionality that the factory must provide. This method must create a plugin of the "
|
||||
"specific type.\n"
|
||||
"@param manager The database manager object responsible for handling database transactions\n"
|
||||
"@param dispatcher The reference to the \\MainWindow object\n"
|
||||
"@param view The \\LayoutView that is plugin is created for\n"
|
||||
"@return The new \\Plugin implementation object\n"
|
||||
) +
|
||||
method ("add_menu_entry", &gsi::PluginFactoryBase::add_menu_entry1, gsi::arg ("menu_name"), gsi::arg ("insert_pos"),
|
||||
"@brief Specifies a separator\n"
|
||||
"Call this method in the factory constructor to build the menu items that this plugin shall create.\n"
|
||||
"This specific call inserts a separator at the given position (insert_pos). The position uses abstract menu item paths "
|
||||
"and \"menu_name\" names the component that will be created. See \\AbstractMenu for a description of the path.\n"
|
||||
) +
|
||||
method ("add_menu_entry", &gsi::PluginFactoryBase::add_menu_entry2, gsi::arg ("symbol"), gsi::arg ("menu_name"), gsi::arg ("insert_pos"), gsi::arg ("title"),
|
||||
"@brief Specifies a menu item\n"
|
||||
"Call this method in the factory constructor to build the menu items that this plugin shall create.\n"
|
||||
"This specific call inserts a menu item at the specified position (insert_pos). The position uses abstract menu item paths "
|
||||
"and \"menu_name\" names the component that will be created. See \\AbstractMenu for a description of the path.\n"
|
||||
"When the menu item is selected \"symbol\" is the string that is sent to the \\menu_activated callback (either the global one for the factory ot the one of the per-view plugin instance).\n"
|
||||
"\n"
|
||||
"@param symbol The string to send to the plugin if the menu is triggered\n"
|
||||
"@param menu_name The name of entry to create at the given position\n"
|
||||
"@param insert_pos The position where to create the entry\n"
|
||||
"@param title The title string for the item. The title can contain a keyboard shortcut in round braces after the title text, i.e. \"My Menu Item(F12)\"\n"
|
||||
) +
|
||||
method ("#add_menu_entry", &gsi::PluginFactoryBase::add_menu_entry3, gsi::arg ("symbol"), gsi::arg ("menu_name"), gsi::arg ("insert_pos"), gsi::arg ("title"), gsi::arg ("sub_menu"),
|
||||
"@brief Specifies a menu item or sub-menu\n"
|
||||
"Similar to the previous form of \"add_menu_entry\", but this version allows also to create sub-menus by setting the "
|
||||
"last parameter to \"true\".\n"
|
||||
"\n"
|
||||
"With version 0.27 it's more convenient to use \\add_submenu."
|
||||
) +
|
||||
method ("add_menu_item_clone", &gsi::PluginFactoryBase::add_menu_entry_copy, gsi::arg ("symbol"), gsi::arg ("menu_name"), gsi::arg ("insert_pos"), gsi::arg ("copy_from"),
|
||||
"@brief Specifies a menu item as a clone of another one\n"
|
||||
"Using this method, a menu item can be made a clone of another entry (given as path by 'copy_from').\n"
|
||||
"The new item will share the \\Action object with the original one, so manipulating the action will change both the original entry "
|
||||
"and the new entry.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("add_submenu", &gsi::PluginFactoryBase::add_submenu, gsi::arg ("menu_name"), gsi::arg ("insert_pos"), gsi::arg ("title"),
|
||||
"@brief Specifies a menu item or sub-menu\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("add_config_menu_item", &gsi::PluginFactoryBase::add_config_menu_item, gsi::arg ("menu_name"), gsi::arg ("insert_pos"), gsi::arg ("title"), gsi::arg ("cname"), gsi::arg ("cvalue"),
|
||||
"@brief Adds a configuration menu item\n"
|
||||
"\n"
|
||||
"Menu items created this way will send a configuration request with 'cname' as the configuration parameter name "
|
||||
"and 'cvalue' as the configuration parameter value.\n"
|
||||
"If 'cvalue' is a string with a single question mark (\"?\"), the item is a check box that reflects the boolean "
|
||||
"value of the configuration item.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("add_option", &gsi::PluginFactoryBase::add_option, gsi::arg ("name"), gsi::arg ("default_value"),
|
||||
"@brief Specifies configuration variables.\n"
|
||||
"Call this method in the factory constructor to add configuration key/value pairs to the configuration repository. "
|
||||
"Without specifying configuration variables, the status of a plugin cannot be persisted. "
|
||||
"\n\n"
|
||||
"Once the configuration variables are known, they can be retrieved on demand using \"get_config\" from "
|
||||
"\\MainWindow or listening to \\configure callbacks (either in the factory or the plugin instance). Configuration variables can "
|
||||
"be set using \"set_config\" from \\MainWindow. This scheme also works without registering the configuration options, but "
|
||||
"doing so has the advantage that it is guaranteed that a variable with this keys exists and has the given default value initially."
|
||||
) +
|
||||
#if defined(HAVE_QTBINDINGS)
|
||||
method ("add_editor_options_page", &PluginFactoryBase::add_editor_options_page, gsi::arg ("page"),
|
||||
"@brief Adds the given editor options page\n"
|
||||
"See \\create_editor_options_pages how to use this function. The method is effective only in "
|
||||
"the reimplementation context of this function.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30.4."
|
||||
) +
|
||||
callback ("create_editor_options_pages", &PluginFactoryBase::get_editor_options_pages_impl, &PluginFactoryBase::f_get_editor_options_pages,
|
||||
"@brief Creates the editor option pages\n"
|
||||
"The editor option pages are widgets of type \\EditorOptionsPage. These Qt widgets "
|
||||
"are displayed in a seperate dock (the 'editor options') and become visible when the plugin is active - i.e. "
|
||||
"its mode is selected. Use this method to provide customized pages that will be displayed in the "
|
||||
"editor options dock.\n"
|
||||
"\n"
|
||||
"In order to create config pages, instantiate a \\EditorOptionsPage object and "
|
||||
"call \\add_editor_options_page to register it.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30.4."
|
||||
) +
|
||||
method ("add_config_page", &PluginFactoryBase::add_config_page, gsi::arg ("page"),
|
||||
"@brief Adds the given configuration page\n"
|
||||
"See \\create_config_pages how to use this function. The method is effective only in "
|
||||
"the reimplementation context of this function.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30.4."
|
||||
) +
|
||||
callback ("create_config_pages", &PluginFactoryBase::get_config_pages_impl, &PluginFactoryBase::f_config_pages,
|
||||
"@brief Creates the configuration widgets\n"
|
||||
"The configuration pages are widgets that are displayed in the "
|
||||
"configuration dialog ('File/Setup'). Every plugin can create multiple such "
|
||||
"widgets and specify, where these widgets are displayed. The widgets are of type \\ConfigPage.\n"
|
||||
"\n"
|
||||
"The title string also specifies the location of the widget in the "
|
||||
"configuration page hierarchy. See \\ConfigPage for more details.\n"
|
||||
"\n"
|
||||
"In order to create config pages, instantiate a \\ConfigPage object and "
|
||||
"call \\add_config_page to register it.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30.4."
|
||||
) +
|
||||
#endif
|
||||
method ("has_tool_entry=", &gsi::PluginFactoryBase::has_tool_entry, gsi::arg ("f"),
|
||||
"@brief Enables or disables the tool bar entry\n"
|
||||
"Initially this property is set to true. This means that the plugin will have a visible entry in the toolbar. "
|
||||
"This property can be set to false to disable this feature. In that case, the title and icon given on registration will be ignored. "
|
||||
),
|
||||
"@brief The plugin framework's plugin factory object\n"
|
||||
"\n"
|
||||
"Plugins are components that extend KLayout's functionality in various aspects. Scripting support exists "
|
||||
"currently for providing mouse mode handlers and general on-demand functionality connected with a menu "
|
||||
"entry.\n"
|
||||
"\n"
|
||||
"Plugins are objects that implement the \\Plugin interface. Each layout view is associated with one instance "
|
||||
"of such an object. The PluginFactory is a singleton which is responsible for creating \\Plugin objects and "
|
||||
"providing certain configuration information such as where to put the menu items connected to this plugin and "
|
||||
"what configuration keys are used.\n"
|
||||
"\n"
|
||||
"An implementation of PluginFactory must at least provide an implementation of \\create_plugin. This method "
|
||||
"must instantiate a new object of the specific plugin.\n"
|
||||
"\n"
|
||||
"After the factory has been created, it must be registered in the system using one of the \\register methods. "
|
||||
"It is therefore recommended to put the call to \\register at the end of the \"initialize\" method. For the registration "
|
||||
"to work properly, the menu items must be defined before \\register is called.\n"
|
||||
"\n"
|
||||
"The following features can also be implemented:\n"
|
||||
"\n"
|
||||
"@<ul>\n"
|
||||
" @<li>Reserve keys in the configuration file using \\add_option in the constructor@</li>\n"
|
||||
" @<li>Create menu items by using \\add_menu_entry in the constructor@</li>\n"
|
||||
" @<li>Set the title for the mode entry that appears in the tool bar using the \\register argument@</li>\n"
|
||||
" @<li>Provide global functionality (independent from the layout view) using \\configure or \\menu_activated@</li>\n"
|
||||
"@</ul>\n"
|
||||
"\n"
|
||||
"This is a simple example for a plugin in Ruby. It switches the mouse cursor to a 'cross' cursor when it is active:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"class PluginTestFactory < RBA::PluginFactory\n"
|
||||
"\n"
|
||||
" # Constructor\n"
|
||||
" def initialize\n"
|
||||
" # registers the new plugin class at position 100000 (at the end), with name\n"
|
||||
" # \"my_plugin_test\" and title \"My plugin test\"\n"
|
||||
" register(100000, \"my_plugin_test\", \"My plugin test\")\n"
|
||||
" end\n"
|
||||
" \n"
|
||||
" # Create a new plugin instance of the custom type\n"
|
||||
" def create_plugin(manager, dispatcher, view)\n"
|
||||
" return PluginTest.new\n"
|
||||
" end\n"
|
||||
"\n"
|
||||
"end\n"
|
||||
"\n"
|
||||
"# The plugin class\n"
|
||||
"class PluginTest < RBA::Plugin\n"
|
||||
" def mouse_moved_event(p, buttons, prio)\n"
|
||||
" if prio\n"
|
||||
" # Set the cursor to cross if our plugin is active.\n"
|
||||
" set_cursor(RBA::Cursor::Cross)\n"
|
||||
" end\n"
|
||||
" # Returning false indicates that we don't want to consume the event.\n"
|
||||
" # This way for example the cursor position tracker still works.\n"
|
||||
" false\n"
|
||||
" end\n"
|
||||
" def mouse_click_event(p, buttons, prio)\n"
|
||||
" if prio\n"
|
||||
" puts \"mouse button clicked.\"\n"
|
||||
" # This indicates we want to consume the event and others don't receive the mouse click\n"
|
||||
" # with prio = false.\n"
|
||||
" return true\n"
|
||||
" end\n"
|
||||
" # don't consume the event if we are not active.\n"
|
||||
" false\n"
|
||||
" end\n"
|
||||
"end\n"
|
||||
"\n"
|
||||
"# Instantiate the new plugin factory.\n"
|
||||
"PluginTestFactory.new\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.22.\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -7,6 +7,9 @@ include($$PWD/../../lib.pri)
|
|||
DEFINES += MAKE_LAY_LIBRARY
|
||||
|
||||
HEADERS = \
|
||||
gsiDeclLayConfigPage.h \
|
||||
gsiDeclLayEditorOptionsPage.h \
|
||||
gsiDeclLayPlugin.h \
|
||||
layApplication.h \
|
||||
layClipDialog.h \
|
||||
layControlWidgetStack.h \
|
||||
|
|
@ -117,8 +120,12 @@ FORMS = \
|
|||
|
||||
SOURCES = \
|
||||
gsiDeclLayApplication.cc \
|
||||
gsiDeclLayConfigPage.cc \
|
||||
gsiDeclLayEditorOptionsPage.cc \
|
||||
gsiDeclLayHelpDialog.cc \
|
||||
gsiDeclLayMainWindow.cc \
|
||||
gsiDeclLayPlugin.cc \
|
||||
gsiDeclLayPluginFactory.cc \
|
||||
layApplication.cc \
|
||||
layClipDialog.cc \
|
||||
layControlWidgetStack.cc \
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
<file alias="new_macro.lym">macro_templates/new_macro.lym</file>
|
||||
<file alias="new_text_file.txt">macro_templates/new_text_file.txt</file>
|
||||
<file alias="new_ruby_file.rb">macro_templates/new_ruby_file.rb</file>
|
||||
<file alias="drag_box_sample.lym">macro_templates/drag_box_sample.lym</file>
|
||||
<file alias="drag_box_sample_python.lym">macro_templates/drag_box_sample_python.lym</file>
|
||||
<file alias="pcell.lym">macro_templates/pcell.lym</file>
|
||||
<file alias="pcell_sample.lym">macro_templates/pcell_sample.lym</file>
|
||||
<file alias="qt_designer.lym">macro_templates/qt_designer.lym</file>
|
||||
|
|
|
|||
|
|
@ -1664,32 +1664,38 @@ MainWindow::select_mode (int m)
|
|||
}
|
||||
}
|
||||
|
||||
// if the current mode supports editing, show the editor options panel
|
||||
update_editor_options_dock ();
|
||||
|
||||
const lay::PluginDeclaration *pd_sel = 0;
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
const lay::PluginDeclaration *pd = cls.operator-> ();
|
||||
if (pd->id () == m_mode) {
|
||||
pd_sel = pd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool eo_visible = false;
|
||||
if (mp_eo_stack && pd_sel) {
|
||||
eo_visible = pd_sel->editable_enabled ();
|
||||
}
|
||||
if (current_view () && eo_visible) {
|
||||
lay::EditorOptionsPages *eo_pages = current_view ()->editor_options_pages ();
|
||||
if (! eo_pages || ! eo_pages->has_content ()) {
|
||||
eo_visible = false;
|
||||
}
|
||||
}
|
||||
void
|
||||
MainWindow::update_editor_options_dock ()
|
||||
{
|
||||
// if the current mode supports editing, show the editor options panel
|
||||
|
||||
if (eo_visible != m_eo_visible) {
|
||||
m_eo_visible = eo_visible;
|
||||
show_dock_widget (mp_eo_dock_widget, m_eo_visible);
|
||||
const lay::PluginDeclaration *pd_sel = 0;
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
const lay::PluginDeclaration *pd = cls.operator-> ();
|
||||
if (pd->id () == m_mode) {
|
||||
pd_sel = pd;
|
||||
}
|
||||
}
|
||||
|
||||
bool eo_visible = false;
|
||||
if (mp_eo_stack && pd_sel) {
|
||||
eo_visible = pd_sel->editable_enabled ();
|
||||
}
|
||||
if (current_view () && eo_visible) {
|
||||
lay::EditorOptionsPages *eo_pages = current_view ()->editor_options_pages ();
|
||||
if (! eo_pages || ! eo_pages->has_content ()) {
|
||||
eo_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (eo_visible != m_eo_visible) {
|
||||
m_eo_visible = eo_visible;
|
||||
show_dock_widget (mp_eo_dock_widget, m_eo_visible);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2439,6 +2445,7 @@ MainWindow::select_view (int index)
|
|||
|
||||
current_view_changed ();
|
||||
|
||||
update_editor_options_dock ();
|
||||
clear_current_pos ();
|
||||
edits_enabled_changed ();
|
||||
clear_message ();
|
||||
|
|
@ -4381,6 +4388,11 @@ MainWindow::plugin_registered (lay::PluginDeclaration *cls)
|
|||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->create_plugins ();
|
||||
}
|
||||
|
||||
// regenerate the setup form
|
||||
delete mp_setup_form;
|
||||
mp_setup_form = new SettingsForm (0, dispatcher (), "setup_form"),
|
||||
mp_setup_form->setup ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ class ProgressWidget;
|
|||
class LAY_PUBLIC MainWindow
|
||||
: public QMainWindow,
|
||||
public tl::Object,
|
||||
public gsi::ObjectBase,
|
||||
public lay::DispatcherDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -857,6 +858,7 @@ private:
|
|||
void interactive_close_view (int from, int to, bool invert_range, bool all_cellviews);
|
||||
void call_on_current_view (void (lay::LayoutView::*func) (), const std::string &op_desc);
|
||||
void current_view_changed ();
|
||||
void update_editor_options_dock ();
|
||||
void update_window_title ();
|
||||
void update_tab_title (int i);
|
||||
void add_view (LayoutViewWidget *view);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,431 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>A plugin sample\nThis sample provides a box drawing feature and demonstrates UI components and snapping</description>
|
||||
<format>general</format>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<shortcut></shortcut>
|
||||
<interpreter>ruby</interpreter>
|
||||
<text># Sample plugin
|
||||
|
||||
# This plugin implements a box that can be drawn by
|
||||
# clicking at the first and then at the second point.
|
||||
# There is one box which is replacing the previous one.
|
||||
# Line color and line width of the box can be configured
|
||||
# by editor options (line width) or configuration pages
|
||||
# (color). These settings are managed through configuration
|
||||
# options and their current state is persisted.
|
||||
#
|
||||
# The dimension of the box can be entered numerically
|
||||
# while dragging the box. This feature is implemented
|
||||
# through a modal "focus page", which opens when you
|
||||
# press the Tab key during editing and when the keyboard
|
||||
# focus is on the canvas.
|
||||
#
|
||||
# Register this macro as "autorun" to enable the plugin
|
||||
# on startup.
|
||||
|
||||
module DragBox
|
||||
|
||||
CFG_COLOR = "drag-box-color"
|
||||
CFG_WIDTH = "drag-box-width"
|
||||
|
||||
# An option page providing a single entry box for configuring the line width
|
||||
# This page communicates via configuration options. One advantage of this
|
||||
# approach is that the values are persisted
|
||||
|
||||
class DragBoxEditorOptionsPage < RBA::EditorOptionsPage
|
||||
|
||||
# Creates a new page with title "Options" and at position 1 (second from left)
|
||||
|
||||
def initialize
|
||||
|
||||
super("Options", 1)
|
||||
|
||||
layout2 = RBA::QVBoxLayout::new(self)
|
||||
layout = RBA::QHBoxLayout::new(self)
|
||||
layout2.addLayout(layout)
|
||||
label = RBA::QLabel::new("Line width", self)
|
||||
layout.addWidget(label)
|
||||
@spin_box = RBA::QSpinBox::new(self)
|
||||
@spin_box.setMinimum(1)
|
||||
@spin_box.setMaximum(16)
|
||||
layout.addWidget(@spin_box)
|
||||
layout.addStretch(1)
|
||||
layout2.addStretch(1)
|
||||
|
||||
# connect the spin box value change with the "edited" slot
|
||||
# which will result in a call of "apply".
|
||||
@spin_box.valueChanged = lambda { |x| self.edited }
|
||||
|
||||
end
|
||||
|
||||
# "setup" is called when the page needs to be populated with information -
|
||||
# i.e. on first show.
|
||||
def setup(dispatcher)
|
||||
begin
|
||||
@spin_box.setValue(dispatcher.get_config(CFG_WIDTH).to_i)
|
||||
rescue
|
||||
@spin_box.setValue(1)
|
||||
end
|
||||
end
|
||||
|
||||
# "apply" is called when the page is requested to submit the entered
|
||||
# values to the plugin. Usually this should be done via configuration
|
||||
# events.
|
||||
def apply(dispatcher)
|
||||
dispatcher.set_config(CFG_WIDTH, @spin_box.value.to_s)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A (modal) option page, also called a "focus page". This page is
|
||||
# registered like an editor options page. It is brought to front
|
||||
# when the user hits the "Tab" key during editing.
|
||||
# In this case, this page uses "setup" and "apply" callbacks to
|
||||
# set and fetch information. It also employs a handler named
|
||||
# "update_box" to communicate changes between the client (the
|
||||
# plugin) and the page.
|
||||
#
|
||||
# Attributes that the client needs to take care of are
|
||||
# "self.box" (the current box), "self.pfix" (the start point)
|
||||
# and "self.update_box".
|
||||
|
||||
class DragBoxFocusPage < RBA::EditorOptionsPage
|
||||
|
||||
# Creates a new page with title "Options" and at
|
||||
# position 1 (second from left)
|
||||
|
||||
attr_accessor :box
|
||||
attr_accessor :pfix
|
||||
attr_accessor :update_box
|
||||
|
||||
def initialize
|
||||
|
||||
super("Geometry", 2)
|
||||
|
||||
self.focus_page = true
|
||||
self.modal_page = true
|
||||
|
||||
@box = RBA::DBox::new
|
||||
@pfix = RBA::DPoint::new
|
||||
|
||||
layout = RBA::QGridLayout::new(self)
|
||||
layout.setColumnStretch(1, 1)
|
||||
|
||||
label = RBA::QLabel::new("Width", self)
|
||||
layout.addWidget(label, 0, 0, 1, 1)
|
||||
@le_width = RBA::QLineEdit::new(self)
|
||||
layout.addWidget(@le_width, 0, 1, 1, 1)
|
||||
|
||||
label = RBA::QLabel::new("Height", self)
|
||||
layout.addWidget(label, 1, 0, 1, 1)
|
||||
@le_height = RBA::QLineEdit::new(self)
|
||||
layout.addWidget(@le_height, 1, 1, 1, 1)
|
||||
|
||||
layout.setRowStretch(2, 1)
|
||||
|
||||
end
|
||||
|
||||
# Is called when the page needs to be set up.
|
||||
# We assume that the client has properly set up self.box
|
||||
def setup(dispatcher)
|
||||
@le_width.text = "%.12g" % @box.width
|
||||
@le_height.text = "%.12g" % @box.height
|
||||
end
|
||||
|
||||
# Apply is called when the dialog is accepted or the "Apply" button is pressed
|
||||
# Usually this method is intended to submit configuration parameter changes,
|
||||
# but we can use it for any other purpose as well.
|
||||
|
||||
def apply(dispatcher)
|
||||
|
||||
# fetches the coordinates from the entry boxes
|
||||
# throws an exception in case of an error
|
||||
x = @le_width.text.to_f
|
||||
y = @le_height.text.to_f
|
||||
|
||||
# prepares a new box with the given dimensions
|
||||
# using the initial point ("pfix") and considering
|
||||
# the drag direction
|
||||
t = b = @pfix.y
|
||||
l = r = @pfix.x
|
||||
|
||||
if @box.bottom < t - 1e-10
|
||||
b = t - y
|
||||
else
|
||||
t = b + y
|
||||
end
|
||||
|
||||
if @box.left < l - 1e-10
|
||||
l = r - x
|
||||
else
|
||||
r = l + x
|
||||
end
|
||||
|
||||
# issue the event (call the handler) to inform the plugin of this change
|
||||
if @update_box
|
||||
@update_box.call(RBA::DBox::new(l, b, r, t))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# The widget placed into the configuration page
|
||||
|
||||
# A configuration page with a single entry box to change
|
||||
# the box color in RGB hex style.
|
||||
# Configuration pages appear in the Setup dialog and can
|
||||
# communicate only through configuration parameter updates.
|
||||
|
||||
class DragBoxConfigPage < RBA::ConfigPage
|
||||
|
||||
# Initializes the page. Places it on a new section ("Drag Box") and "Configure" page
|
||||
# and creates a single entry field.
|
||||
def initialize
|
||||
|
||||
super("Drag Box|Configure")
|
||||
|
||||
layout = RBA::QHBoxLayout::new(self)
|
||||
label = RBA::QLabel::new("Color (hex, rrggbb)", self)
|
||||
layout.addWidget(label)
|
||||
@line_edit = RBA::QLineEdit::new(self)
|
||||
layout.addWidget(@line_edit)
|
||||
layout.addStretch(1)
|
||||
|
||||
end
|
||||
|
||||
# This method is called to request an update of the entry fields
|
||||
def setup(dispatcher)
|
||||
@line_edit.setText(dispatcher.get_config(CFG_COLOR))
|
||||
end
|
||||
|
||||
# This method is called to request a transfer of the edited values
|
||||
# to the configuration space.
|
||||
def apply(dispatcher)
|
||||
dispatcher.set_config(CFG_COLOR, @line_edit.text)
|
||||
end
|
||||
end
|
||||
|
||||
# The custom plugin implementation.
|
||||
|
||||
class DragBoxPlugin < RBA::Plugin
|
||||
|
||||
def initialize(view)
|
||||
super()
|
||||
@marker = nil
|
||||
@last_marker = nil
|
||||
@box = nil
|
||||
@start_point = nil
|
||||
@view = view
|
||||
@color = nil
|
||||
@width = 1
|
||||
end
|
||||
|
||||
# This method receives configuration callbacks
|
||||
def configure(name, value)
|
||||
if name == CFG_COLOR
|
||||
# configure marker color
|
||||
begin
|
||||
@color = value != "" ? value.to_i(16) : nil
|
||||
rescue
|
||||
@color = nil
|
||||
end
|
||||
self._configure_marker
|
||||
elsif name == CFG_WIDTH
|
||||
# configure marker line width
|
||||
begin
|
||||
@width = value.to_i
|
||||
rescue
|
||||
@width = nil
|
||||
end
|
||||
self._configure_marker
|
||||
end
|
||||
end
|
||||
|
||||
# clears all markers
|
||||
def _clear_marker
|
||||
[ @marker, @last_marker ].each { |marker| marker && marker._destroy }
|
||||
@marker = nil
|
||||
@last_marker = nil
|
||||
end
|
||||
|
||||
# stops dragging the marker and copy to a static one
|
||||
def _finish
|
||||
if @last_marker
|
||||
@last_marker._destroy
|
||||
end
|
||||
@last_marker = @marker
|
||||
@marker = nil
|
||||
# reset to idle
|
||||
self.ungrab_mouse
|
||||
RBA::MainWindow.instance.message("Box finished: " + @box.to_s, 10000)
|
||||
end
|
||||
|
||||
# updates the marker with the current box
|
||||
def _update_marker
|
||||
if ! @marker
|
||||
@marker = RBA::Marker::new(@view)
|
||||
self._configure_marker
|
||||
end
|
||||
@marker.set(@box)
|
||||
end
|
||||
|
||||
# changes the marker's appearance
|
||||
def _configure_marker
|
||||
if @marker
|
||||
@marker.line_style = 2 # short-dashed
|
||||
@marker.vertex_size = 0 # no vertexes
|
||||
@marker.line_width = @width
|
||||
@marker.color = @color ? (@color | 0xff000000) : 0 # auto
|
||||
end
|
||||
end
|
||||
|
||||
# Updates the box with the given value and updates the marker.
|
||||
# This method is bound to the focus page handler when needed.
|
||||
def _update_box(box)
|
||||
@box = box
|
||||
self._update_marker
|
||||
end
|
||||
|
||||
# overloaded callback: the focus page is requested
|
||||
def focus_page_open
|
||||
|
||||
# stop unless dragging
|
||||
if !@marker
|
||||
return
|
||||
end
|
||||
|
||||
# configure the focus page and show it:
|
||||
# the page will call the handler of "update_box" to commit
|
||||
# changes to the box
|
||||
fp = self.focus_page
|
||||
fp.box = @box
|
||||
fp.pfix = @start_point
|
||||
fp.update_box = lambda { |box| self._update_box(box) }
|
||||
ret = fp.show
|
||||
fp.update_box = nil
|
||||
if ret == 1
|
||||
# accepted: stop dragging now, we are done.
|
||||
self._finish
|
||||
end
|
||||
|
||||
return ret
|
||||
|
||||
end
|
||||
|
||||
# overloaded callback:
|
||||
# plugin is activated - i.e. the mode is selected
|
||||
def activated
|
||||
RBA::MainWindow.instance.message("Click on point to start dragging a box", 10000)
|
||||
end
|
||||
|
||||
# overloaded callback:
|
||||
# plugin is deactivated - i.e. the mode is unselected
|
||||
def deactivated
|
||||
self._clear_marker
|
||||
RBA::MainWindow.instance.message("", 0)
|
||||
end
|
||||
|
||||
# overloaded callback:
|
||||
# a mouse button was clicked
|
||||
|
||||
def mouse_click_event(p, buttons, prio)
|
||||
|
||||
if prio
|
||||
|
||||
# first-level event: start a new box or
|
||||
# stop dragging it and freeze the box
|
||||
if ! @marker
|
||||
p = self.snap2(p)
|
||||
@box = RBA::DBox::new(p, p)
|
||||
@start_point = p
|
||||
self._clear_marker
|
||||
self._update_marker
|
||||
self.grab_mouse
|
||||
RBA::MainWindow.instance.message("Drag the box and click again", 10000)
|
||||
else
|
||||
p = self.snap2(p, @start_point, true, self.ac_from_buttons(buttons))
|
||||
self._update_box(RBA::DBox::new(@start_point, p))
|
||||
self._finish
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
# overloaded callback:
|
||||
# the mouse was moved
|
||||
def mouse_moved_event(p, buttons, prio)
|
||||
|
||||
if prio
|
||||
# first-level event: if not dragging, provide a
|
||||
# mouse cursor for tracking. If dragging, update
|
||||
# the box and provide a mouse cursor.
|
||||
if !@marker
|
||||
self.clear_mouse_cursors
|
||||
p = self.snap2(p, :visualize => true)
|
||||
self.add_mouse_cursor(p)
|
||||
else
|
||||
self.clear_mouse_cursors
|
||||
p = self.snap2(p, @start_point, true, self.ac_from_buttons(buttons), :visualize => true)
|
||||
self.add_mouse_cursor(p)
|
||||
@box = RBA::DBox::new(@start_point, p)
|
||||
self._update_marker
|
||||
end
|
||||
end
|
||||
|
||||
# NOTE: we must not digest this event (i.e. return true)
|
||||
# to allow the mouse tracker to receive the events as well
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Implements a "plugin factory".
|
||||
# The purpose of this object is to create a plugin object
|
||||
# and corresponding UI objects.
|
||||
|
||||
class DragBoxPluginFactory < RBA::PluginFactory
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.has_tool_entry = true
|
||||
# NOTE: it's a good practice to register configuration options
|
||||
self.add_option(CFG_WIDTH, "1")
|
||||
self.add_option(CFG_COLOR, "")
|
||||
self.register(-1000, "drag_box", "Drag Box")
|
||||
end
|
||||
|
||||
# Called to create the configuration pages
|
||||
def create_config_pages
|
||||
self.add_config_page(DragBoxConfigPage::new)
|
||||
end
|
||||
|
||||
# Called to create the editor options pages
|
||||
def create_editor_options_pages
|
||||
self.add_editor_options_page(DragBoxEditorOptionsPage::new)
|
||||
self.add_editor_options_page(DragBoxFocusPage::new)
|
||||
end
|
||||
|
||||
# Creates the plugin
|
||||
def create_plugin(manager, root, view)
|
||||
return DragBoxPlugin::new(view)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Creates the singleton instance - as we register it,
|
||||
# it is not garbage collected
|
||||
DragBoxPluginFactory::new
|
||||
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>A plugin sample\nThis sample provides a box drawing feature and demonstrates UI components and snapping</description>
|
||||
<format>general</format>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<shortcut></shortcut>
|
||||
<interpreter>python</interpreter>
|
||||
<text># Sample plugin
|
||||
|
||||
# This plugin implements a box that can be drawn by
|
||||
# clicking at the first and then at the second point.
|
||||
# There is one box which is replacing the previous one.
|
||||
# Line color and line width of the box can be configured
|
||||
# by editor options (line width) or configuration pages
|
||||
# (color). These settings are managed through configuration
|
||||
# options and their current state is persisted.
|
||||
#
|
||||
# The dimension of the box can be entered numerically
|
||||
# while dragging the box. This feature is implemented
|
||||
# through a modal "focus page", which opens when you
|
||||
# press the Tab key during editing and when the keyboard
|
||||
# focus is on the canvas.
|
||||
#
|
||||
# Register this macro as "autorun" to enable the plugin
|
||||
# on startup.
|
||||
|
||||
cfg_color = "drag-box-color"
|
||||
cfg_width = "drag-box-width"
|
||||
|
||||
# The widget placed into the editor options dock
|
||||
|
||||
class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
|
||||
|
||||
"""
|
||||
An option page providing a single entry box for configuring the line width
|
||||
This page communicates via configuration options. One advantage of this
|
||||
approach is that the values are persisted
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
"""
|
||||
Creates a new page with title "Options" and at position 1 (second from left)
|
||||
"""
|
||||
|
||||
super(DragBoxEditorOptionsPage, self).__init__("Options", 1)
|
||||
|
||||
layout2 = pya.QVBoxLayout(self)
|
||||
layout = pya.QHBoxLayout(self)
|
||||
layout2.addLayout(layout)
|
||||
label = pya.QLabel("Line width", self)
|
||||
layout.addWidget(label)
|
||||
self.spin_box = pya.QSpinBox(self)
|
||||
self.spin_box.setMinimum(1)
|
||||
self.spin_box.setMaximum(16)
|
||||
layout.addWidget(self.spin_box)
|
||||
layout.addStretch(1)
|
||||
layout2.addStretch(1)
|
||||
|
||||
# connect the spin box value change with the "edited" slot
|
||||
# which will result in a call of "apply".
|
||||
self.spin_box.valueChanged = lambda x: self.edited()
|
||||
|
||||
def setup(self, dispatcher):
|
||||
|
||||
"""
|
||||
"setup" is called when the page needs to be populated with information -
|
||||
i.e. on first show.
|
||||
"""
|
||||
|
||||
try:
|
||||
self.spin_box.setValue(int(dispatcher.get_config(cfg_width)))
|
||||
except:
|
||||
self.spin_box.setValue(1)
|
||||
|
||||
def apply(self, dispatcher):
|
||||
|
||||
"""
|
||||
"apply" is called when the page is requested to submit the entered
|
||||
values to the plugin. Usually this should be done via configuration
|
||||
events.
|
||||
"""
|
||||
|
||||
dispatcher.set_config(cfg_width, str(self.spin_box.value))
|
||||
|
||||
# The modal dialog page that appears when "Tab" is pressed
|
||||
|
||||
class DragBoxFocusPage(pya.EditorOptionsPage):
|
||||
|
||||
"""
|
||||
A (modal) option page, also called a "focus page". This page is
|
||||
registered like an editor options page. It is brought to front
|
||||
when the user hits the "Tab" key during editing.
|
||||
In this case, this page uses "setup" and "apply" callbacks to
|
||||
set and fetch information. It also employs a handler named
|
||||
"update_box" to communicate changes between the client (the
|
||||
plugin) and the page.
|
||||
|
||||
Attributes that the client needs to take care of are
|
||||
"self.box" (the current box), "self.pfix" (the start point)
|
||||
and "self.update_box".
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
"""
|
||||
Creates a new page with title "Options" and at
|
||||
position 1 (second from left)
|
||||
"""
|
||||
|
||||
super(DragBoxFocusPage, self).__init__("Geometry", 2)
|
||||
|
||||
self.focus_page = True
|
||||
self.modal_page = True
|
||||
|
||||
self.box = pya.DBox()
|
||||
self.pfix = pya.DPoint()
|
||||
self.update_box = None
|
||||
|
||||
layout = pya.QGridLayout(self)
|
||||
layout.setColumnStretch(1, 1)
|
||||
|
||||
label = pya.QLabel("Width", self)
|
||||
layout.addWidget(label, 0, 0, 1, 1)
|
||||
self.le_width = pya.QLineEdit(self)
|
||||
layout.addWidget(self.le_width, 0, 1, 1, 1)
|
||||
|
||||
label = pya.QLabel("Height", self)
|
||||
layout.addWidget(label, 1, 0, 1, 1)
|
||||
self.le_height = pya.QLineEdit(self)
|
||||
layout.addWidget(self.le_height, 1, 1, 1, 1)
|
||||
|
||||
layout.setRowStretch(2, 1)
|
||||
|
||||
def setup(self, dispatcher):
|
||||
|
||||
"""
|
||||
Is called when the page needs to be set up.
|
||||
We assume that the client has properly set up self.box
|
||||
"""
|
||||
|
||||
self.le_width.text = "%.12g" % self.box.width()
|
||||
self.le_height.text = "%.12g" % self.box.height()
|
||||
|
||||
def apply(self, dispatcher):
|
||||
|
||||
"""
|
||||
Apply is called when the dialog is accepted or the "Apply" button is pressed
|
||||
Usually this method is intended to submit configuration parameter changes,
|
||||
but we can use it for any other purpose as well.
|
||||
"""
|
||||
|
||||
# fetches the coordinates from the entry boxes
|
||||
# throws an exception in case of an error
|
||||
x = float(self.le_width.text)
|
||||
y = float(self.le_height.text)
|
||||
|
||||
# prepares a new box with the given dimensions
|
||||
# using the initial point ("pfix") and considering
|
||||
# the drag direction
|
||||
t = b = self.pfix.y
|
||||
l = r = self.pfix.x
|
||||
|
||||
if self.box.bottom < t - 1e-10:
|
||||
b = t - y
|
||||
else:
|
||||
t = b + y
|
||||
|
||||
if self.box.left < l - 1e-10:
|
||||
l = r - x
|
||||
else:
|
||||
r = l + x
|
||||
|
||||
# issue the event (call the handler) to inform the plugin of this change
|
||||
if self.update_box is not None:
|
||||
self.update_box(pya.DBox(l, b, r, t))
|
||||
|
||||
# The widget placed into the configuration page
|
||||
|
||||
class DragBoxConfigPage(pya.ConfigPage):
|
||||
|
||||
"""
|
||||
A configuration page with a single entry box to change
|
||||
the box color in RGB hex style.
|
||||
Configuration pages appear in the Setup dialog and can
|
||||
communicate only through configuration parameter updates.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
"""
|
||||
Initializes the page. Places it on a new section ("Drag Box") and "Configure" page
|
||||
and creates a single entry field.
|
||||
"""
|
||||
|
||||
super(DragBoxConfigPage, self).__init__("Drag Box|Configure")
|
||||
|
||||
layout = pya.QHBoxLayout(self)
|
||||
label = pya.QLabel("Color (hex, rrggbb)", self)
|
||||
layout.addWidget(label)
|
||||
self.line_edit = pya.QLineEdit(self)
|
||||
layout.addWidget(self.line_edit)
|
||||
layout.addStretch(1)
|
||||
|
||||
def setup(self, dispatcher):
|
||||
"""
|
||||
This method is called to request an update of the entry fields
|
||||
"""
|
||||
self.line_edit.setText(dispatcher.get_config(cfg_color))
|
||||
|
||||
def apply(self, dispatcher):
|
||||
"""
|
||||
This method is called to request a transfer of the edited values
|
||||
to the configuration space.
|
||||
"""
|
||||
dispatcher.set_config(cfg_color, self.line_edit.text)
|
||||
|
||||
class DragBoxPlugin(pya.Plugin):
|
||||
|
||||
"""
|
||||
The custom plugin implementation.
|
||||
"""
|
||||
|
||||
def __init__(self, view):
|
||||
super(DragBoxPlugin, self).__init__()
|
||||
self.marker = None
|
||||
self.last_marker = None
|
||||
self.box = None
|
||||
self.start_point = None
|
||||
self.view = view
|
||||
self.color = None
|
||||
self.width = 1
|
||||
|
||||
def configure(self, name, value):
|
||||
"""
|
||||
This method receives configuration callbacks
|
||||
"""
|
||||
if name == cfg_color:
|
||||
# configure marker color
|
||||
try:
|
||||
if value != "":
|
||||
self.color = int(value, 16)
|
||||
else:
|
||||
self.color = None
|
||||
except:
|
||||
self.color = None
|
||||
self._configure_marker()
|
||||
elif name == cfg_width:
|
||||
# configure marker line width
|
||||
try:
|
||||
self.width = int(value)
|
||||
except:
|
||||
self.width = None
|
||||
self._configure_marker()
|
||||
|
||||
def _clear_marker(self):
|
||||
"""
|
||||
clears all markers
|
||||
"""
|
||||
for marker in [ self.marker, self.last_marker ]:
|
||||
if marker is not None:
|
||||
marker._destroy()
|
||||
self.marker = None
|
||||
self.last_marker = None
|
||||
|
||||
def _finish(self):
|
||||
"""
|
||||
stops dragging the marker and copy to a static one
|
||||
"""
|
||||
if self.last_marker is not None:
|
||||
self.last_marker._destroy()
|
||||
self.last_marker = self.marker
|
||||
self.marker = None
|
||||
# reset to idle
|
||||
self.ungrab_mouse()
|
||||
pya.MainWindow.instance().message("Box finished: " + str(self.box), 10000)
|
||||
|
||||
def _update_marker(self):
|
||||
"""
|
||||
updates the marker with the current box
|
||||
"""
|
||||
if self.marker is None:
|
||||
self.marker = pya.Marker(self.view)
|
||||
self._configure_marker()
|
||||
self.marker.set(self.box)
|
||||
|
||||
def _configure_marker(self):
|
||||
"""
|
||||
changes the marker's appearance
|
||||
"""
|
||||
if self.marker is not None:
|
||||
self.marker.line_style = 2 # short-dashed
|
||||
self.marker.vertex_size = 0 # no vertexes
|
||||
self.marker.line_width = self.width
|
||||
if self.color is not None:
|
||||
self.marker.color = self.color | 0xff000000
|
||||
else:
|
||||
self.marker.color = 0 # auto
|
||||
|
||||
def _update_box(self, box):
|
||||
"""
|
||||
Updates the box with the given value and updates the marker.
|
||||
This method is bound to the focus page handler when needed.
|
||||
"""
|
||||
self.box = box
|
||||
self._update_marker()
|
||||
|
||||
def focus_page_open(self):
|
||||
|
||||
"""
|
||||
overloaded callback: the focus page is requested
|
||||
"""
|
||||
|
||||
# stop unless dragging
|
||||
if self.marker is None:
|
||||
return
|
||||
|
||||
# configure the focus page and show it:
|
||||
# the page will call the handler of "update_box" to commit
|
||||
# changes to the box
|
||||
fp = self.focus_page()
|
||||
fp.box = self.box
|
||||
fp.pfix = self.start_point
|
||||
fp.update_box = self._update_box
|
||||
ret = fp.show()
|
||||
fp.update_box = None
|
||||
if ret == 1:
|
||||
# accepted: stop dragging now, we are done.
|
||||
self._finish()
|
||||
|
||||
return ret
|
||||
|
||||
def activated(self):
|
||||
|
||||
"""
|
||||
overloaded callback:
|
||||
plugin is activated - i.e. the mode is selected
|
||||
"""
|
||||
|
||||
pya.MainWindow.instance().message("Click on point to start dragging a box", 10000)
|
||||
|
||||
def deactivated(self):
|
||||
|
||||
"""
|
||||
overloaded callback:
|
||||
plugin is deactivated - i.e. the mode is unselected
|
||||
"""
|
||||
|
||||
self._clear_marker()
|
||||
pya.MainWindow.instance().message("", 0)
|
||||
|
||||
def mouse_click_event(self, p, buttons, prio):
|
||||
|
||||
"""
|
||||
overloaded callback:
|
||||
a mouse button was clicked
|
||||
"""
|
||||
|
||||
if prio:
|
||||
# first-level event: start a new box or
|
||||
# stop dragging it and freeze the box
|
||||
if self.marker is None:
|
||||
p = self.snap2(p)
|
||||
self.box = pya.DBox(p, p)
|
||||
self.start_point = p
|
||||
self._clear_marker()
|
||||
self._update_marker()
|
||||
self.grab_mouse()
|
||||
pya.MainWindow.instance().message("Drag the box and click again", 10000)
|
||||
else:
|
||||
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons))
|
||||
self._update_box(pya.DBox(self.start_point, p))
|
||||
self._finish()
|
||||
return True
|
||||
return False
|
||||
|
||||
def mouse_moved_event(self, p, buttons, prio):
|
||||
|
||||
"""
|
||||
overloaded callback:
|
||||
the mouse was moved
|
||||
"""
|
||||
|
||||
if prio:
|
||||
# first-level event: if not dragging, provide a
|
||||
# mouse cursor for tracking. If dragging, update
|
||||
# the box and provide a mouse cursor.
|
||||
if self.marker is None:
|
||||
self.clear_mouse_cursors()
|
||||
p = self.snap2(p, visualize=True)
|
||||
self.add_mouse_cursor(p)
|
||||
else:
|
||||
self.clear_mouse_cursors()
|
||||
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons), visualize=True)
|
||||
self.add_mouse_cursor(p)
|
||||
self.box = pya.DBox(self.start_point, p)
|
||||
self._update_marker()
|
||||
# NOTE: we must not digest this event (i.e. return True)
|
||||
# to allow the mouse tracker to receive the events as well
|
||||
return False
|
||||
|
||||
class DragBoxPluginFactory(pya.PluginFactory):
|
||||
|
||||
"""
|
||||
Implements a "plugin factory".
|
||||
The purpose of this object is to create a plugin object
|
||||
and corresponding UI objects.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(DragBoxPluginFactory, self).__init__()
|
||||
self.has_tool_entry = True
|
||||
# NOTE: it's a good practice to register configuration options
|
||||
self.add_option(cfg_width, "1")
|
||||
self.add_option(cfg_color, "")
|
||||
self.register(-1000, "drag_box", "Drag Box")
|
||||
|
||||
def create_config_pages(self):
|
||||
"""
|
||||
Called to create the configuration pages
|
||||
"""
|
||||
self.add_config_page(DragBoxConfigPage())
|
||||
|
||||
def create_editor_options_pages(self):
|
||||
"""
|
||||
Called to create the editor options pages
|
||||
"""
|
||||
self.add_editor_options_page(DragBoxEditorOptionsPage())
|
||||
self.add_editor_options_page(DragBoxFocusPage())
|
||||
|
||||
def create_plugin(self, manager, root, view):
|
||||
"""
|
||||
Creates the plugin
|
||||
"""
|
||||
return DragBoxPlugin(view)
|
||||
|
||||
# Creates the singleton instance - as we register it,
|
||||
# it is not garbage collected
|
||||
DragBoxPluginFactory()
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
@ -25,6 +25,7 @@ editor_hooks_sample.lym
|
|||
qt_designer.lym
|
||||
qt_dialog.lym
|
||||
qt_server.lym
|
||||
drag_box_sample.lym
|
||||
|
||||
[pymacros]
|
||||
# General group
|
||||
|
|
@ -45,4 +46,5 @@ editor_hooks_sample_python.lym
|
|||
qt_designer_python.lym
|
||||
qt_dialog_python.lym
|
||||
qt_server_python.lym
|
||||
drag_box_sample_python.lym
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
#include "layDispatcher.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static std::vector<std::string>
|
||||
get_config_names (lay::Dispatcher *dispatcher)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
dispatcher->get_config_names (names);
|
||||
return names;
|
||||
}
|
||||
|
||||
static lay::Dispatcher *dispatcher_instance ()
|
||||
{
|
||||
return lay::Dispatcher::instance ();
|
||||
}
|
||||
|
||||
static tl::Variant get_config (lay::Dispatcher *dispatcher, const std::string &name)
|
||||
{
|
||||
std::string value;
|
||||
if (dispatcher->config_get (name, value)) {
|
||||
return tl::Variant (value);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exposes the Dispatcher interface
|
||||
*
|
||||
* This interface is intentionally not derived from Plugin. It is used currently to
|
||||
* identify the dispatcher node for configuration. The Plugin nature of this interface
|
||||
* is somewhat artificial and may be removed later.
|
||||
*
|
||||
* TODO: this is a duplicate of the respective methods in LayoutView and Application.
|
||||
* This is intentional since we don't want to spend the only derivation path on this.
|
||||
* Once there is a mixin concept, provide a path through that concept.
|
||||
*/
|
||||
Class<lay::Dispatcher> decl_Dispatcher ("lay", "Dispatcher",
|
||||
method ("clear_config", &lay::Dispatcher::clear_config,
|
||||
"@brief Clears the configuration parameters\n"
|
||||
) +
|
||||
method ("instance", &dispatcher_instance,
|
||||
"@brief Gets the singleton instance of the Dispatcher object\n"
|
||||
"\n"
|
||||
"@return The instance\n"
|
||||
) +
|
||||
method ("write_config", &lay::Dispatcher::write_config, gsi::arg ("file_name"),
|
||||
"@brief Writes configuration to a file\n"
|
||||
"@return A value indicating whether the operation was successful\n"
|
||||
"\n"
|
||||
"If the configuration file cannot be written, false \n"
|
||||
"is returned but no exception is thrown.\n"
|
||||
) +
|
||||
method ("read_config", &lay::Dispatcher::read_config, gsi::arg ("file_name"),
|
||||
"@brief Reads the configuration from a file\n"
|
||||
"@return A value indicating whether the operation was successful\n"
|
||||
"\n"
|
||||
"This method silently does nothing, if the config file does not\n"
|
||||
"exist. If it does and an error occurred, the error message is printed\n"
|
||||
"on stderr. In both cases, false is returned.\n"
|
||||
) +
|
||||
method_ext ("get_config", &get_config, gsi::arg ("name"),
|
||||
"@brief Gets the value of a local configuration parameter\n"
|
||||
"\n"
|
||||
"@param name The name of the configuration parameter whose value shall be obtained (a string)\n"
|
||||
"\n"
|
||||
"@return The value of the parameter or nil if there is no such parameter\n"
|
||||
) +
|
||||
method ("set_config", (void (lay::Dispatcher::*) (const std::string &, const std::string &)) &lay::Dispatcher::config_set, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Set a local configuration parameter with the given name to the given value\n"
|
||||
"\n"
|
||||
"@param name The name of the configuration parameter to set\n"
|
||||
"@param value The value to which to set the configuration parameter\n"
|
||||
"\n"
|
||||
"This method sets a configuration parameter with the given name to the given value. "
|
||||
"Values can only be strings. Numerical values have to be converted into strings first. "
|
||||
"Local configuration parameters override global configurations for this specific view. "
|
||||
"This allows for example to override global settings of background colors. "
|
||||
"Any local settings are not written to the configuration file. "
|
||||
) +
|
||||
method_ext ("get_config_names", &get_config_names,
|
||||
"@brief Gets the configuration parameter names\n"
|
||||
"\n"
|
||||
"@return A list of configuration parameter names\n"
|
||||
"\n"
|
||||
"This method returns the names of all known configuration parameters. These names can be used to "
|
||||
"get and set configuration parameter values.\n"
|
||||
) +
|
||||
method ("commit_config", &lay::Dispatcher::config_end,
|
||||
"@brief Commits the configuration settings\n"
|
||||
"\n"
|
||||
"Some configuration options are queued for performance reasons and become active only after 'commit_config' has been called. "
|
||||
"After a sequence of \\set_config calls, this method should be called to activate the "
|
||||
"settings made by these calls.\n"
|
||||
),
|
||||
"@brief Root of the configuration space in the plugin context and menu dispatcher\n"
|
||||
"\n"
|
||||
"This class provides access to the root configuration space in the context "
|
||||
"of plugin programming. You can use this class to obtain configuration parameters "
|
||||
"from the configuration tree during plugin initialization. However, the "
|
||||
"preferred way of plugin configuration is through \\Plugin#configure.\n"
|
||||
"\n"
|
||||
"Currently, the application object provides an identical entry point for configuration modification. "
|
||||
"For example, \"Application::instance.set_config\" is identical to \"Dispatcher::instance.set_config\". "
|
||||
"Hence there is little motivation for the Dispatcher class currently and "
|
||||
"this interface may be modified or removed in the future."
|
||||
"\n"
|
||||
"This class has been introduced in version 0.25 as 'PluginRoot'.\n"
|
||||
"It is renamed and enhanced as 'Dispatcher' in 0.27."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -144,6 +144,11 @@ static std::string get_line_style (lay::LayoutViewBase *view, unsigned int index
|
|||
return view->line_styles ().style (index).to_string ();
|
||||
}
|
||||
|
||||
static std::string layer_list_name (lay::LayoutViewBase *view, unsigned int index)
|
||||
{
|
||||
return view->get_properties (index).name ();
|
||||
}
|
||||
|
||||
static void transaction (lay::LayoutViewBase *view, const std::string &desc)
|
||||
{
|
||||
view->manager ()->transaction (desc);
|
||||
|
|
@ -358,14 +363,6 @@ static QWidget *widget (lay::LayoutViewBase *view)
|
|||
|
||||
#endif
|
||||
|
||||
static std::vector<std::string>
|
||||
get_config_names (lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
view->get_config_names (names);
|
||||
return names;
|
||||
}
|
||||
|
||||
static void
|
||||
send_key_press_event (lay::LayoutViewBase *view, unsigned int key, unsigned int buttons)
|
||||
{
|
||||
|
|
@ -497,7 +494,9 @@ static bool view_is_dirty (lay::LayoutViewBase *view)
|
|||
return view->is_dirty ();
|
||||
}
|
||||
|
||||
LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutViewBase",
|
||||
extern Class<lay::Dispatcher> decl_Dispatcher;
|
||||
|
||||
LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase (decl_Dispatcher, "lay", "LayoutViewBase",
|
||||
gsi::constant ("LV_NoLayers", (unsigned int) lay::LayoutViewBase::LV_NoLayers,
|
||||
"@brief With this option, no layers view will be provided (see \\layer_control_frame)\n"
|
||||
"Use this value with the constructor's 'options' argument.\n"
|
||||
|
|
@ -1572,6 +1571,10 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
|
|||
"@brief Sets the title of the given layer properties tab\n"
|
||||
"This method has been introduced in version 0.21.\n"
|
||||
) +
|
||||
gsi::method_ext ("layer_list_name", &layer_list_name, gsi::arg ("index"),
|
||||
"@brief Gets the title of the given layer properties tab\n"
|
||||
"This method has been introduced in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("remove_stipple", &remove_stipple, gsi::arg ("index"),
|
||||
"@brief Removes the stipple pattern with the given index\n"
|
||||
"The pattern with an index less than the first custom pattern cannot be removed. "
|
||||
|
|
@ -1940,68 +1943,6 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
|
|||
"\n"
|
||||
"This method has been added in version 0.26."
|
||||
) +
|
||||
// HINT: the cast is important to direct GSI to the LayoutView method rather than the
|
||||
// Plugin method (in which case we get a segmentation violation ..)
|
||||
// TODO: this method belongs to the Plugin interface and should be located there.
|
||||
// Change this once there is a mixin concept available and the Plugin interface can
|
||||
// be mixed into LayoutView.
|
||||
gsi::method ("clear_config", (void (lay::LayoutViewBase::*)()) &lay::LayoutViewBase::clear_config,
|
||||
"@brief Clears the local configuration parameters\n"
|
||||
"\n"
|
||||
"See \\set_config for a description of the local configuration parameters."
|
||||
) +
|
||||
// TODO: this method belongs to the Plugin interface and should be located there.
|
||||
// Change this once there is a mixin concept available and the Plugin interface can
|
||||
// be mixed into LayoutView.
|
||||
gsi::method_ext ("get_config_names", &get_config_names,
|
||||
"@brief Gets the configuration parameter names\n"
|
||||
"\n"
|
||||
"@return A list of configuration parameter names\n"
|
||||
"\n"
|
||||
"This method returns the names of all known configuration parameters. These names can be used to "
|
||||
"get and set configuration parameter values.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.25.\n"
|
||||
) +
|
||||
// TODO: this method belongs to the Plugin interface and should be located there.
|
||||
// Change this once there is a mixin concept available and the Plugin interface can
|
||||
// be mixed into LayoutView.
|
||||
gsi::method ("get_config", (std::string (lay::LayoutViewBase::*)(const std::string &name) const) &lay::LayoutViewBase::config_get, gsi::arg ("name"),
|
||||
"@brief Gets the value of a local configuration parameter\n"
|
||||
"\n"
|
||||
"@param name The name of the configuration parameter whose value shall be obtained (a string)\n"
|
||||
"\n"
|
||||
"@return The value of the parameter\n"
|
||||
"\n"
|
||||
"See \\set_config for a description of the local configuration parameters."
|
||||
) +
|
||||
// TODO: this method belongs to the Plugin interface and should be located there.
|
||||
// Change this once there is a mixin concept available and the Plugin interface can
|
||||
// be mixed into LayoutView.
|
||||
gsi::method ("set_config", (void (lay::LayoutViewBase::*)(const std::string &name, const std::string &value)) &lay::LayoutViewBase::config_set, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Sets a local configuration parameter with the given name to the given value\n"
|
||||
"\n"
|
||||
"@param name The name of the configuration parameter to set\n"
|
||||
"@param value The value to which to set the configuration parameter\n"
|
||||
"\n"
|
||||
"This method sets a local configuration parameter with the given name to the given value. "
|
||||
"Values can only be strings. Numerical values have to be converted into strings first. "
|
||||
"Local configuration parameters override global configurations for this specific view. "
|
||||
"This allows for example to override global settings of background colors. "
|
||||
"Any local settings are not written to the configuration file. "
|
||||
) +
|
||||
// TODO: this method belongs to the Plugin interface and should be located there.
|
||||
// Change this once there is a mixin concept available and the Plugin interface can
|
||||
// be mixed into LayoutView.
|
||||
gsi::method ("commit_config", (void (lay::LayoutViewBase::*)()) &lay::LayoutViewBase::config_end,
|
||||
"@brief Commits the configuration settings\n"
|
||||
"\n"
|
||||
"Some configuration options are queued for performance reasons and become active only after 'commit_config' has been called. "
|
||||
"After a sequence of \\set_config calls, this method should be called to activate the "
|
||||
"settings made by these calls.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25.\n"
|
||||
) +
|
||||
gsi::method_ext ("transaction", &gsi::transaction, gsi::arg ("description"),
|
||||
"@brief Begins a transaction\n"
|
||||
"\n"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -54,6 +54,15 @@ Editable::Editable (lay::Editables *editables)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editable::init (lay::Editables *editables)
|
||||
{
|
||||
mp_editables = editables;
|
||||
if (editables) {
|
||||
editables->m_editables.push_back (this);
|
||||
}
|
||||
}
|
||||
|
||||
Editable::~Editable ()
|
||||
{
|
||||
// Reasoning for reset (): on MSVC, virtual functions must not be called inside
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ public:
|
|||
*/
|
||||
Editable (Editables *editables = 0);
|
||||
|
||||
/**
|
||||
* @brief Initializes after constructor with a null pointer was called
|
||||
*/
|
||||
void init (Editables *editables);
|
||||
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
#include "layEditorOptionsPage.h"
|
||||
#include "layEditorOptionsPages.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "tlExceptions.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QKeyEvent>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -34,16 +38,96 @@ namespace lay
|
|||
// EditorOptionsPage implementation
|
||||
|
||||
EditorOptionsPage::EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
|
||||
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
|
||||
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
|
||||
{
|
||||
attach_events ();
|
||||
}
|
||||
|
||||
EditorOptionsPage::EditorOptionsPage ()
|
||||
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EditorOptionsPage::~EditorOptionsPage ()
|
||||
{
|
||||
set_owner (0);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
|
||||
{
|
||||
mp_view = view;
|
||||
mp_dispatcher = dispatcher;
|
||||
attach_events ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::edited ()
|
||||
{
|
||||
apply (dispatcher ());
|
||||
}
|
||||
|
||||
static bool is_parent_widget (QWidget *w, QWidget *parent)
|
||||
{
|
||||
while (w && w != parent) {
|
||||
w = dynamic_cast<QWidget *> (w->parent ());
|
||||
}
|
||||
return w == parent;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorOptionsPage::focusNextPrevChild (bool next)
|
||||
{
|
||||
bool res = QWidget::focusNextPrevChild (next);
|
||||
|
||||
// Stop making the focus leave the page - this way we can jump back to the
|
||||
// view on "enter"
|
||||
if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
|
||||
focusWidget ()->setFocus ();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::keyPressEvent (QKeyEvent *event)
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
if (! is_modal_page () && event->modifiers () == Qt::NoModifier && event->key () == Qt::Key_Return) {
|
||||
// The Return key on a non-modal page commits the values and gives back the focus
|
||||
// to the view
|
||||
apply (dispatcher ());
|
||||
view ()->set_focus ();
|
||||
event->accept ();
|
||||
} else {
|
||||
QWidget::keyPressEvent (event);
|
||||
}
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::set_focus ()
|
||||
{
|
||||
setFocus (Qt::TabFocusReason);
|
||||
QWidget::focusNextPrevChild (true);
|
||||
}
|
||||
|
||||
int
|
||||
EditorOptionsPage::show ()
|
||||
{
|
||||
if (mp_owner && m_active) {
|
||||
if (! is_modal_page ()) {
|
||||
mp_owner->make_page_current (this);
|
||||
return -1;
|
||||
} else {
|
||||
return mp_owner->exec_modal (this) ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::attach_events ()
|
||||
{
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef HDR_layEditorOptionsPage
|
||||
#define HDR_layEditorOptionsPage
|
||||
|
||||
#include "layuiCommon.h"
|
||||
#include "laybasicCommon.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
|
|
@ -49,13 +49,14 @@ class EditorOptionsPages;
|
|||
/**
|
||||
* @brief The base class for a object properties page
|
||||
*/
|
||||
class LAYUI_PUBLIC EditorOptionsPage
|
||||
class LAYBASIC_PUBLIC EditorOptionsPage
|
||||
: public QWidget, public tl::Object
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
|
||||
EditorOptionsPage ();
|
||||
virtual ~EditorOptionsPage ();
|
||||
|
||||
virtual std::string title () const = 0;
|
||||
|
|
@ -65,20 +66,28 @@ public:
|
|||
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
|
||||
virtual void config_recent_for_layer (lay::Dispatcher * /*root*/, const db::LayerProperties & /*lp*/, int /*cv_index*/) { }
|
||||
|
||||
bool is_focus_page () const { return m_focus_page; }
|
||||
void set_focus_page (bool f) { m_focus_page = f; }
|
||||
void set_focus ();
|
||||
|
||||
bool is_modal_page () const { return m_modal_page; }
|
||||
void set_modal_page (bool f) { m_modal_page = f; }
|
||||
|
||||
bool active () const { return m_active; }
|
||||
void activate (bool active);
|
||||
void set_owner (EditorOptionsPages *owner);
|
||||
|
||||
/**
|
||||
* @brief Shows the editor page
|
||||
* @return -1, if the page is shown non-modal, otherwise 1 or 0 if the dialog was accepted (1) or rejected (0)
|
||||
*/
|
||||
int show ();
|
||||
|
||||
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
|
||||
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
|
||||
|
||||
protected slots:
|
||||
void edited ()
|
||||
{
|
||||
apply (dispatcher ());
|
||||
}
|
||||
void init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
|
||||
|
||||
protected:
|
||||
lay::Dispatcher *dispatcher () const
|
||||
{
|
||||
return mp_dispatcher;
|
||||
|
|
@ -89,12 +98,21 @@ protected:
|
|||
return mp_view;
|
||||
}
|
||||
|
||||
protected slots:
|
||||
void edited ();
|
||||
|
||||
protected:
|
||||
virtual void active_cellview_changed () { }
|
||||
virtual void technology_changed (const std::string & /*tech*/) { }
|
||||
|
||||
virtual bool focusNextPrevChild (bool next);
|
||||
virtual void keyPressEvent (QKeyEvent *event);
|
||||
|
||||
private:
|
||||
EditorOptionsPages *mp_owner;
|
||||
bool m_active;
|
||||
bool m_focus_page;
|
||||
bool m_modal_page;
|
||||
const lay::PluginDeclaration *mp_plugin_declaration;
|
||||
lay::Dispatcher *mp_dispatcher;
|
||||
lay::LayoutViewBase *mp_view;
|
||||
|
|
@ -0,0 +1,449 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
#include "tlInternational.h"
|
||||
#include "layEditorOptionsPages.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "layPlugin.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTabWidget>
|
||||
#include <QToolButton>
|
||||
#include <QCompleter>
|
||||
#include <QLineEdit>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// EditorOptionsPages implementation
|
||||
|
||||
struct EOPCompareOp
|
||||
{
|
||||
bool operator() (lay::EditorOptionsPage *a, lay::EditorOptionsPage *b) const
|
||||
{
|
||||
return a->order () < b->order ();
|
||||
}
|
||||
};
|
||||
|
||||
EditorOptionsPages::EditorOptionsPages (QWidget *parent, const std::vector<lay::EditorOptionsPage *> &pages, lay::Dispatcher *dispatcher)
|
||||
: QFrame (parent), mp_dispatcher (dispatcher)
|
||||
{
|
||||
mp_modal_pages = new EditorOptionsModalPages (this);
|
||||
|
||||
QVBoxLayout *ly1 = new QVBoxLayout (this);
|
||||
ly1->setContentsMargins (0, 0, 0, 0);
|
||||
|
||||
mp_pages = new QTabWidget (this);
|
||||
mp_pages->setSizePolicy (QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored));
|
||||
ly1->addWidget (mp_pages);
|
||||
|
||||
m_pages = pages;
|
||||
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
(*p)->set_owner (this);
|
||||
}
|
||||
|
||||
update (0);
|
||||
setup ();
|
||||
}
|
||||
|
||||
EditorOptionsPages::~EditorOptionsPages ()
|
||||
{
|
||||
while (m_pages.size () > 0) {
|
||||
delete m_pages.front ();
|
||||
}
|
||||
|
||||
delete mp_modal_pages;
|
||||
mp_modal_pages = 0;
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::focusInEvent (QFocusEvent * /*event*/)
|
||||
{
|
||||
// Sends the focus to the current page's last focus owner
|
||||
if (mp_pages->currentWidget () && mp_pages->currentWidget ()->focusWidget ()) {
|
||||
mp_pages->currentWidget ()->focusWidget ()->setFocus ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
EditorOptionsPages::has_content () const
|
||||
{
|
||||
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active () && ! (*p)->is_modal_page ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorOptionsPages::has_modal_content () const
|
||||
{
|
||||
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active () && (*p)->is_modal_page ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorOptionsPages::exec_modal (EditorOptionsPage *page)
|
||||
{
|
||||
for (int i = 0; i < mp_modal_pages->count (); ++i) {
|
||||
|
||||
if (mp_modal_pages->widget (i) == page) {
|
||||
|
||||
// found the page - make it current and show the dialog
|
||||
mp_modal_pages->set_current_index (i);
|
||||
page->setup (mp_dispatcher);
|
||||
page->set_focus ();
|
||||
return mp_modal_pages->exec () != 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::activate (const lay::Plugin *plugin)
|
||||
{
|
||||
for (auto op = m_pages.begin (); op != m_pages.end (); ++op) {
|
||||
bool is_active = false;
|
||||
if ((*op)->plugin_declaration () == 0) {
|
||||
is_active = (plugin && plugin->plugin_declaration ()->enable_catchall_editor_options_pages ());
|
||||
} else if (plugin && plugin->plugin_declaration () == (*op)->plugin_declaration ()) {
|
||||
is_active = true;
|
||||
}
|
||||
(*op)->activate (is_active);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::unregister_page (lay::EditorOptionsPage *page)
|
||||
{
|
||||
std::vector <lay::EditorOptionsPage *> pages;
|
||||
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if (*p != page) {
|
||||
pages.push_back (*p);
|
||||
}
|
||||
}
|
||||
m_pages = pages;
|
||||
update (0);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::make_page_current (lay::EditorOptionsPage *page)
|
||||
{
|
||||
for (int i = 0; i < mp_pages->count (); ++i) {
|
||||
if (mp_pages->widget (i) == page) {
|
||||
mp_pages->setCurrentIndex (i);
|
||||
page->setup (mp_dispatcher);
|
||||
page->set_focus ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::activate_page (lay::EditorOptionsPage *page)
|
||||
{
|
||||
try {
|
||||
if (page->active ()) {
|
||||
page->setup (mp_dispatcher);
|
||||
}
|
||||
} catch (...) {
|
||||
// catch any errors related to configuration file errors etc.
|
||||
}
|
||||
|
||||
update (page);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::update (lay::EditorOptionsPage *page)
|
||||
{
|
||||
std::vector <lay::EditorOptionsPage *> sorted_pages = m_pages;
|
||||
std::sort (sorted_pages.begin (), sorted_pages.end (), EOPCompareOp ());
|
||||
|
||||
if (! page && m_pages.size () > 0) {
|
||||
page = m_pages.back ();
|
||||
}
|
||||
|
||||
while (mp_pages->count () > 0) {
|
||||
mp_pages->removeTab (0);
|
||||
}
|
||||
|
||||
while (mp_modal_pages->count () > 0) {
|
||||
mp_modal_pages->remove_page (0);
|
||||
}
|
||||
|
||||
int index = -1;
|
||||
int modal_index = -1;
|
||||
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = sorted_pages.begin (); p != sorted_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
if (! (*p)->is_modal_page ()) {
|
||||
if ((*p) == page) {
|
||||
index = mp_pages->count ();
|
||||
}
|
||||
mp_pages->addTab (*p, tl::to_qstring ((*p)->title ()));
|
||||
} else {
|
||||
if ((*p) == page) {
|
||||
modal_index = mp_modal_pages->count ();
|
||||
}
|
||||
mp_modal_pages->add_page (*p);
|
||||
}
|
||||
} else {
|
||||
(*p)->setParent (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = mp_pages->currentIndex ();
|
||||
}
|
||||
if (index >= int (mp_pages->count ())) {
|
||||
index = mp_pages->count () - 1;
|
||||
}
|
||||
mp_pages->setCurrentIndex (index);
|
||||
|
||||
if (modal_index < 0) {
|
||||
modal_index = mp_modal_pages->current_index ();
|
||||
}
|
||||
if (modal_index >= int (mp_modal_pages->count ())) {
|
||||
modal_index = mp_modal_pages->count () - 1;
|
||||
}
|
||||
mp_modal_pages->set_current_index (modal_index);
|
||||
|
||||
setVisible (mp_pages->count () > 0);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::setup ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
(*p)->setup (mp_dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
// make the display consistent with the status (this is important for
|
||||
// PCell parameters where the PCell may be asked to modify the parameters)
|
||||
do_apply (false);
|
||||
do_apply (true);
|
||||
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::do_apply (bool modal)
|
||||
{
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active () && modal == (*p)->is_modal_page ()) {
|
||||
// NOTE: we apply to the root dispatcher, so other dispatchers (views) get informed too.
|
||||
(*p)->apply (mp_dispatcher->dispatcher ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::apply ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
do_apply (false);
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// EditorOptionsModalPages implementation
|
||||
|
||||
EditorOptionsModalPages::EditorOptionsModalPages (EditorOptionsPages *parent)
|
||||
: QDialog (parent), mp_parent (parent), mp_single_page (0)
|
||||
{
|
||||
QVBoxLayout *ly = new QVBoxLayout (this);
|
||||
ly->setContentsMargins (0, 0, 0, 0);
|
||||
|
||||
QVBoxLayout *ly4 = new QVBoxLayout (0);
|
||||
ly4->setContentsMargins (6, 6, 6, 0);
|
||||
ly->addLayout (ly4);
|
||||
mp_pages = new QTabWidget (this);
|
||||
ly4->addWidget (mp_pages, 1);
|
||||
#if QT_VERSION >= 0x50400
|
||||
mp_pages->setTabBarAutoHide (true);
|
||||
#endif
|
||||
mp_pages->hide ();
|
||||
|
||||
mp_single_page_frame = new QFrame (this);
|
||||
QVBoxLayout *ly2 = new QVBoxLayout (mp_single_page_frame);
|
||||
ly2->setContentsMargins (0, 0, 0, 0);
|
||||
ly->addWidget (mp_single_page_frame, 1);
|
||||
mp_single_page_frame->hide ();
|
||||
|
||||
QVBoxLayout *ly3 = new QVBoxLayout (0);
|
||||
ly3->setContentsMargins (6, 6, 6, 6);
|
||||
ly->addLayout (ly3);
|
||||
mp_button_box = new QDialogButtonBox (this);
|
||||
ly3->addWidget (mp_button_box);
|
||||
mp_button_box->setOrientation (Qt::Horizontal);
|
||||
mp_button_box->setStandardButtons (QDialogButtonBox::Cancel | QDialogButtonBox::Apply | QDialogButtonBox::Ok);
|
||||
|
||||
connect (mp_button_box, SIGNAL (clicked(QAbstractButton *)), this, SLOT (clicked(QAbstractButton *)));
|
||||
connect (mp_button_box, SIGNAL (accepted()), this, SLOT (accept()));
|
||||
connect (mp_button_box, SIGNAL (rejected()), this, SLOT (reject()));
|
||||
|
||||
update_title ();
|
||||
}
|
||||
|
||||
EditorOptionsModalPages::~EditorOptionsModalPages ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
int
|
||||
EditorOptionsModalPages::count ()
|
||||
{
|
||||
return mp_single_page ? 1 : mp_pages->count ();
|
||||
}
|
||||
|
||||
int
|
||||
EditorOptionsModalPages::current_index ()
|
||||
{
|
||||
return mp_single_page ? 0 : mp_pages->currentIndex ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::set_current_index (int index)
|
||||
{
|
||||
if (! mp_single_page) {
|
||||
mp_pages->setCurrentIndex (index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::add_page (EditorOptionsPage *page)
|
||||
{
|
||||
if (! mp_single_page) {
|
||||
if (mp_pages->count () == 0) {
|
||||
mp_single_page = page;
|
||||
mp_single_page->setParent (mp_single_page_frame);
|
||||
mp_single_page_frame->layout ()->addWidget (mp_single_page);
|
||||
mp_single_page_frame->show ();
|
||||
mp_pages->hide ();
|
||||
} else {
|
||||
mp_pages->addTab (page, tl::to_qstring (page->title ()));
|
||||
}
|
||||
} else {
|
||||
mp_pages->clear ();
|
||||
mp_single_page_frame->layout ()->removeWidget (mp_single_page);
|
||||
mp_single_page_frame->hide ();
|
||||
mp_pages->addTab (mp_single_page, tl::to_qstring (mp_single_page->title ()));
|
||||
mp_single_page = 0;
|
||||
mp_pages->addTab (page, tl::to_qstring (page->title ()));
|
||||
mp_pages->show ();
|
||||
}
|
||||
|
||||
update_title ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::remove_page (int index)
|
||||
{
|
||||
if (mp_single_page) {
|
||||
if (index == 0) {
|
||||
mp_single_page->setParent (0);
|
||||
mp_single_page = 0;
|
||||
mp_single_page_frame->hide ();
|
||||
mp_single_page_frame->layout ()->removeWidget (mp_single_page);
|
||||
}
|
||||
} else {
|
||||
mp_pages->removeTab (index);
|
||||
if (mp_pages->count () == 1) {
|
||||
mp_pages->hide ();
|
||||
mp_single_page = dynamic_cast<EditorOptionsPage *> (mp_pages->widget (0));
|
||||
mp_pages->removeTab (0);
|
||||
mp_single_page->setParent (mp_single_page_frame);
|
||||
mp_single_page_frame->layout ()->addWidget (mp_single_page);
|
||||
mp_single_page_frame->show ();
|
||||
}
|
||||
}
|
||||
|
||||
update_title ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::update_title ()
|
||||
{
|
||||
if (mp_single_page) {
|
||||
setWindowTitle (tl::to_qstring (mp_single_page->title ()));
|
||||
} else {
|
||||
setWindowTitle (tr ("Editor Options"));
|
||||
}
|
||||
}
|
||||
|
||||
EditorOptionsPage *
|
||||
EditorOptionsModalPages::widget (int index)
|
||||
{
|
||||
if (mp_single_page) {
|
||||
return index == 0 ? mp_single_page : 0;
|
||||
} else {
|
||||
return dynamic_cast<EditorOptionsPage *> (mp_pages->widget (index));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::accept ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
mp_parent->do_apply (true);
|
||||
QDialog::accept ();
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::reject ()
|
||||
{
|
||||
QDialog::reject ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::clicked (QAbstractButton *button)
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
if (button == mp_button_box->button (QDialogButtonBox::Apply)) {
|
||||
mp_parent->do_apply (true);
|
||||
}
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -25,17 +25,19 @@
|
|||
#ifndef HDR_layEditorOptionsPages
|
||||
#define HDR_layEditorOptionsPages
|
||||
|
||||
#include "layuiCommon.h"
|
||||
#include "laybasicCommon.h"
|
||||
#include "layEditorOptionsPage.h"
|
||||
|
||||
#include <tlVariant.h>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QDialog>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class QTabWidget;
|
||||
class QLabel;
|
||||
class QDialogButtonBox;
|
||||
class QAbstractButton;
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -43,11 +45,12 @@ namespace lay
|
|||
class PluginDeclaration;
|
||||
class Dispatcher;
|
||||
class Plugin;
|
||||
class EditorOptionsModalPages;
|
||||
|
||||
/**
|
||||
* @brief The object properties dialog
|
||||
* @brief The object properties tab widget
|
||||
*/
|
||||
class LAYUI_PUBLIC EditorOptionsPages
|
||||
class LAYBASIC_PUBLIC EditorOptionsPages
|
||||
: public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -58,7 +61,10 @@ public:
|
|||
|
||||
void unregister_page (lay::EditorOptionsPage *page);
|
||||
void activate_page (lay::EditorOptionsPage *page);
|
||||
void activate (const lay::Plugin *plugin);
|
||||
void focusInEvent (QFocusEvent *event);
|
||||
void make_page_current (lay::EditorOptionsPage *page);
|
||||
bool exec_modal (lay::EditorOptionsPage *page);
|
||||
|
||||
const std::vector <lay::EditorOptionsPage *> &pages () const
|
||||
{
|
||||
|
|
@ -66,6 +72,8 @@ public:
|
|||
}
|
||||
|
||||
bool has_content () const;
|
||||
bool has_modal_content () const;
|
||||
void do_apply (bool modal);
|
||||
|
||||
public slots:
|
||||
void apply ();
|
||||
|
|
@ -75,9 +83,43 @@ private:
|
|||
std::vector <lay::EditorOptionsPage *> m_pages;
|
||||
lay::Dispatcher *mp_dispatcher;
|
||||
QTabWidget *mp_pages;
|
||||
EditorOptionsModalPages *mp_modal_pages;
|
||||
|
||||
void update (lay::EditorOptionsPage *page);
|
||||
void do_apply ();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The object properties modal page dialog
|
||||
*/
|
||||
class LAYBASIC_PUBLIC EditorOptionsModalPages
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsModalPages (EditorOptionsPages *parent);
|
||||
~EditorOptionsModalPages ();
|
||||
|
||||
int count ();
|
||||
int current_index ();
|
||||
void set_current_index (int index);
|
||||
void add_page (EditorOptionsPage *page);
|
||||
void remove_page (int index);
|
||||
EditorOptionsPage *widget (int index);
|
||||
|
||||
private slots:
|
||||
void accept ();
|
||||
void reject ();
|
||||
void clicked (QAbstractButton *button);
|
||||
|
||||
private:
|
||||
EditorOptionsPages *mp_parent;
|
||||
QTabWidget *mp_pages;
|
||||
QFrame *mp_single_page_frame;
|
||||
EditorOptionsPage *mp_single_page;
|
||||
QDialogButtonBox *mp_button_box;
|
||||
|
||||
void update_title ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -21,6 +21,8 @@
|
|||
*/
|
||||
|
||||
#include "layEditorServiceBase.h"
|
||||
#include "layEditorOptionsPage.h"
|
||||
#include "layEditorOptionsPages.h"
|
||||
#include "layViewport.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "laybasicConfig.h"
|
||||
|
|
@ -207,16 +209,26 @@ private:
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
EditorServiceBase::EditorServiceBase (LayoutViewBase *view)
|
||||
: lay::ViewService (view->canvas ()),
|
||||
: lay::ViewService (view ? view->canvas () : 0),
|
||||
lay::Editable (view),
|
||||
lay::Plugin (view),
|
||||
mp_view (view),
|
||||
m_cursor_enabled (true),
|
||||
m_has_tracking_position (false)
|
||||
m_has_tracking_position (false),
|
||||
m_active (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::init (LayoutViewBase *view)
|
||||
{
|
||||
mp_view = view;
|
||||
lay::Plugin::init (view);
|
||||
lay::ViewService::init (view ? view->canvas () : 0);
|
||||
lay::Editable::init (view);
|
||||
}
|
||||
|
||||
EditorServiceBase::~EditorServiceBase ()
|
||||
{
|
||||
clear_mouse_cursors ();
|
||||
|
|
@ -265,9 +277,11 @@ EditorServiceBase::clear_mouse_cursors ()
|
|||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::mouse_cursor_from_snap_details (const lay::PointSnapToObjectResult &snap_details)
|
||||
EditorServiceBase::mouse_cursor_from_snap_details (const lay::PointSnapToObjectResult &snap_details, bool noclear)
|
||||
{
|
||||
clear_mouse_cursors ();
|
||||
if (! noclear) {
|
||||
clear_mouse_cursors ();
|
||||
}
|
||||
|
||||
add_mouse_cursor (snap_details.snapped_point,
|
||||
snap_details.object_snap == lay::PointSnapToObjectResult::ObjectVertex ||
|
||||
|
|
@ -319,15 +333,95 @@ void
|
|||
EditorServiceBase::deactivated ()
|
||||
{
|
||||
clear_mouse_cursors ();
|
||||
if (ui ()) {
|
||||
ui ()->ungrab_mouse (this);
|
||||
}
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::activated ()
|
||||
{
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
std::vector<lay::EditorOptionsPage *>
|
||||
EditorServiceBase::editor_options_pages ()
|
||||
{
|
||||
lay::EditorOptionsPages *eo_pages = mp_view->editor_options_pages ();
|
||||
if (!eo_pages) {
|
||||
return std::vector<lay::EditorOptionsPage *> ();
|
||||
} else {
|
||||
std::vector<lay::EditorOptionsPage *> pages;
|
||||
for (auto p = eo_pages->pages ().begin (); p != eo_pages->pages ().end (); ++p) {
|
||||
if ((*p)->plugin_declaration () == plugin_declaration ()) {
|
||||
pages.push_back (*p);
|
||||
}
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
}
|
||||
|
||||
lay::EditorOptionsPage *
|
||||
EditorServiceBase::focus_page ()
|
||||
{
|
||||
auto pages = editor_options_pages ();
|
||||
for (auto p = pages.begin (); p != pages.end (); ++p) {
|
||||
if ((*p)->is_focus_page ()) {
|
||||
return *p;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
|
||||
{
|
||||
if (is_active () && key == Qt::Key_Tab && buttons == 0) {
|
||||
focus_page_open ();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EditorServiceBase::focus_page_open ()
|
||||
{
|
||||
auto fp = focus_page ();
|
||||
return fp ? fp->show () : 0;
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::show_error (tl::Exception &ex)
|
||||
{
|
||||
tl::error << ex.msg ();
|
||||
#if defined(HAVE_QT)
|
||||
QMessageBox::critical (ui ()->widget (), tr ("Error"), tl::to_qstring (ex.msg ()));
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool
|
||||
EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::show_error (tl::Exception &ex)
|
||||
{
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
|
||||
int
|
||||
EditorServiceBase::focus_page_open ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,12 @@ public:
|
|||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
EditorServiceBase (lay::LayoutViewBase *view);
|
||||
EditorServiceBase (lay::LayoutViewBase *view = 0);
|
||||
|
||||
/**
|
||||
* @brief Initialize after constructor was called with null view pointer
|
||||
*/
|
||||
void init (lay::LayoutViewBase *view);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -69,6 +74,14 @@ public:
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the plugin is active
|
||||
*/
|
||||
bool is_active () const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a mouse cursor to the given point
|
||||
*/
|
||||
|
|
@ -97,7 +110,7 @@ public:
|
|||
/**
|
||||
* @brief Provides a nice mouse tracking cursor from the given snap details
|
||||
*/
|
||||
void mouse_cursor_from_snap_details (const lay::PointSnapToObjectResult &snap_details);
|
||||
void mouse_cursor_from_snap_details (const lay::PointSnapToObjectResult &snap_details, bool noclear = false);
|
||||
|
||||
/**
|
||||
* @brief Gets the tracking cursor color
|
||||
|
|
@ -136,10 +149,141 @@ public:
|
|||
*/
|
||||
void show_error (tl::Exception &ex);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Menu command handler
|
||||
*/
|
||||
virtual void menu_activated (const std::string & /*symbol*/)
|
||||
{
|
||||
// .. this implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration option
|
||||
*/
|
||||
virtual bool configure (const std::string &name, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Configuration finalization
|
||||
*/
|
||||
virtual void config_finalize ()
|
||||
{
|
||||
lay::Plugin::config_finalize ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when the plugin is deactivated
|
||||
*/
|
||||
virtual void deactivated ();
|
||||
|
||||
/**
|
||||
* @brief Called when the plugin is activated
|
||||
*/
|
||||
virtual void activated ();
|
||||
|
||||
/**
|
||||
* @brief Key event handler
|
||||
*/
|
||||
virtual bool key_event (unsigned int /*key*/, unsigned int /*buttons*/);
|
||||
|
||||
/**
|
||||
* @brief Mouse press event handler
|
||||
*/
|
||||
virtual bool mouse_press_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mouse single-click event handler
|
||||
*/
|
||||
virtual bool mouse_click_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mouse double-click event handler
|
||||
*/
|
||||
virtual bool mouse_double_click_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mouse leave event handler
|
||||
*/
|
||||
virtual bool leave_event (bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mouse enter event handler
|
||||
*/
|
||||
virtual bool enter_event (bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mouse move event handler
|
||||
*/
|
||||
virtual bool mouse_move_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mouse release event handler
|
||||
*/
|
||||
virtual bool mouse_release_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wheel event handler
|
||||
*/
|
||||
virtual bool wheel_event (int /*delta*/, bool /*horizontal*/, const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the internal data after a coordinate system change for example
|
||||
*/
|
||||
virtual void update ()
|
||||
{
|
||||
// The default implementation does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This method is called when some mouse dragging operation should be cancelled
|
||||
*/
|
||||
virtual void drag_cancel ()
|
||||
{
|
||||
// The default implementation does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets called when the focus page opens
|
||||
*
|
||||
* The default implementation will call fp->show() and return its return value.
|
||||
*/
|
||||
virtual int focus_page_open ();
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Gets the editor options pages associated with this plugin
|
||||
*/
|
||||
std::vector<lay::EditorOptionsPage *> editor_options_pages ();
|
||||
|
||||
/**
|
||||
* @brief Gets the focus page or 0 if there is none
|
||||
*/
|
||||
lay::EditorOptionsPage *focus_page ();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The marker representing the mouse cursor
|
||||
lay::LayoutViewBase *mp_view;
|
||||
|
|
@ -148,6 +292,7 @@ private:
|
|||
bool m_cursor_enabled;
|
||||
bool m_has_tracking_position;
|
||||
db::DPoint m_tracking_position;
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@
|
|||
#include "dbLayout.h"
|
||||
#include "dbLibrary.h"
|
||||
|
||||
#include "edtUtils.h"
|
||||
#include "edtService.h"
|
||||
#include "layEditorUtils.h"
|
||||
|
||||
#include "layCellView.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
|
@ -38,10 +37,35 @@
|
|||
# include <QMessageBox>
|
||||
#endif
|
||||
|
||||
namespace edt {
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
int snap_range_pixels ()
|
||||
{
|
||||
return 8; // TODO: make variable
|
||||
}
|
||||
|
||||
// Convert buttons to an angle constraint
|
||||
lay::angle_constraint_type
|
||||
ac_from_buttons (unsigned int buttons)
|
||||
{
|
||||
if ((buttons & lay::ShiftButton) != 0) {
|
||||
if ((buttons & lay::ControlButton) != 0) {
|
||||
return lay::AC_Any;
|
||||
} else {
|
||||
return lay::AC_Ortho;
|
||||
}
|
||||
} else {
|
||||
if ((buttons & lay::ControlButton) != 0) {
|
||||
return lay::AC_Diagonal;
|
||||
} else {
|
||||
return lay::AC_Global;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters)
|
||||
{
|
||||
std::string param;
|
||||
|
|
@ -21,15 +21,18 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef HDR_edtUtils
|
||||
#define HDR_edtUtils
|
||||
#ifndef HDR_layEditorUtils
|
||||
#define HDR_layEditorUtils
|
||||
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "laybasicCommon.h"
|
||||
|
||||
#include "layObjectInstPath.h"
|
||||
#include "laySnap.h"
|
||||
|
||||
#include "dbInstElement.h"
|
||||
#include "dbClipboardData.h"
|
||||
|
|
@ -38,23 +41,34 @@
|
|||
|
||||
namespace lay
|
||||
{
|
||||
class LayoutViewBase;
|
||||
class Dispatcher;
|
||||
}
|
||||
|
||||
namespace edt {
|
||||
class LayoutViewBase;
|
||||
class Dispatcher;
|
||||
|
||||
class Service;
|
||||
// -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Gets the snap range in pixels
|
||||
*/
|
||||
LAYBASIC_PUBLIC int snap_range_pixels ();
|
||||
|
||||
/**
|
||||
* @brief Convert a button flag set to an angle constraint
|
||||
*
|
||||
* This implements the standard modifiers for angle constraints - i.e.
|
||||
* ortho for "Shift".
|
||||
*/
|
||||
LAYBASIC_PUBLIC lay::angle_constraint_type ac_from_buttons (unsigned int buttons);
|
||||
|
||||
/**
|
||||
* @brief Serializes PCell parameters to a string
|
||||
*/
|
||||
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters);
|
||||
LAYBASIC_PUBLIC std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters);
|
||||
|
||||
/**
|
||||
* @brief Deserializes PCell parameters from a string
|
||||
*/
|
||||
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
|
||||
LAYBASIC_PUBLIC std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
|
||||
|
||||
/**
|
||||
* @brief Fetch PCell parameters from a cell and merge the guiding shapes into them
|
||||
|
|
@ -64,6 +78,7 @@ std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::stri
|
|||
* @param parameters_for_pcell Will receive the parameters
|
||||
* @return true, if the cell is a PCell and parameters have been fetched
|
||||
*/
|
||||
LAYBASIC_PUBLIC
|
||||
bool
|
||||
get_parameters_from_pcell_and_guiding_shapes (db::Layout *layout, db::cell_index_type cell_index, db::pcell_parameters_type ¶meters_for_pcell);
|
||||
|
||||
|
|
@ -71,23 +86,14 @@ get_parameters_from_pcell_and_guiding_shapes (db::Layout *layout, db::cell_index
|
|||
/**
|
||||
* @brief Request to make the given layer the current one (asks whether to create the layer if needed)
|
||||
*/
|
||||
LAYBASIC_PUBLIC
|
||||
bool
|
||||
set_or_request_current_layer (lay::LayoutViewBase *view, const db::LayerProperties &lp, unsigned int cv_index, bool make_current = true);
|
||||
|
||||
/**
|
||||
* @brief A helper class that identifies clipboard data for edt::
|
||||
*/
|
||||
class ClipboardData
|
||||
: public db::ClipboardData
|
||||
{
|
||||
public:
|
||||
ClipboardData () { }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A cache for the transformation variants for a certain layer and cell view index for a lay::LayoutView
|
||||
*/
|
||||
class TransformationVariants
|
||||
class LAYBASIC_PUBLIC TransformationVariants
|
||||
{
|
||||
public:
|
||||
TransformationVariants (const lay::LayoutViewBase *view, bool per_cv_and_layer = true, bool per_cv = true);
|
||||
|
|
@ -398,21 +398,6 @@ LayoutViewBase::init (db::Manager *mgr)
|
|||
|
||||
mp_canvas = new lay::LayoutCanvas (this);
|
||||
|
||||
// occupy services and editables:
|
||||
// these services get deleted by the canvas destructor automatically:
|
||||
if ((m_options & LV_NoTracker) == 0) {
|
||||
mp_tracker = new lay::MouseTracker (this);
|
||||
}
|
||||
if ((m_options & LV_NoZoom) == 0) {
|
||||
mp_zoom_service = new lay::ZoomService (this);
|
||||
}
|
||||
if ((m_options & LV_NoSelection) == 0) {
|
||||
mp_selection_service = new lay::SelectionService (this);
|
||||
}
|
||||
if ((m_options & LV_NoMove) == 0) {
|
||||
mp_move_service = new lay::MoveService (this);
|
||||
}
|
||||
|
||||
create_plugins ();
|
||||
}
|
||||
|
||||
|
|
@ -602,20 +587,41 @@ void LayoutViewBase::create_plugins (const lay::PluginDeclaration *except_this)
|
|||
clear_plugins ();
|
||||
|
||||
// create the plugins
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ) {
|
||||
|
||||
if (&*cls != except_this) {
|
||||
// NOTE: during "create_plugin" a plugin may be unregistered, so don't increment the iterator after
|
||||
auto current = cls.operator-> ();
|
||||
std::string current_name = cls.current_name ();
|
||||
++cls;
|
||||
|
||||
if (current != except_this) {
|
||||
|
||||
// TODO: clean solution. The following is a HACK:
|
||||
if (cls.current_name () == "ant::Plugin" || cls.current_name () == "img::Plugin") {
|
||||
if (current_name == "ant::Plugin" || current_name == "img::Plugin") {
|
||||
// ant and img are created always
|
||||
create_plugin (&*cls);
|
||||
create_plugin (current);
|
||||
} else if (current_name == "laybasic::MouseTrackerPlugin") {
|
||||
if ((m_options & LV_NoTracker) == 0) {
|
||||
mp_tracker = dynamic_cast<lay::MouseTracker *> (create_plugin (current));
|
||||
}
|
||||
} else if (current_name == "laybasic::MoveServicePlugin") {
|
||||
if ((m_options & LV_NoMove) == 0) {
|
||||
mp_move_service = dynamic_cast<lay::MoveService *> (create_plugin (current));
|
||||
}
|
||||
} else if (current_name == "laybasic::SelectionServicePlugin") {
|
||||
if ((m_options & LV_NoSelection) == 0) {
|
||||
mp_selection_service = dynamic_cast<lay::SelectionService *> (create_plugin (current));
|
||||
}
|
||||
} else if (current_name == "laybasic::ZoomServicePlugin") {
|
||||
if ((m_options & LV_NoZoom) == 0) {
|
||||
mp_zoom_service = dynamic_cast<lay::ZoomService *> (create_plugin (current));
|
||||
}
|
||||
} else if ((options () & LV_NoPlugins) == 0) {
|
||||
// others: only create unless LV_NoPlugins is set
|
||||
create_plugin (&*cls);
|
||||
} else if ((options () & LV_NoGrid) == 0 && cls.current_name () == "GridNetPlugin") {
|
||||
create_plugin (current);
|
||||
} else if ((options () & LV_NoGrid) == 0 && current_name == "lay::GridNetPlugin") {
|
||||
// except grid net plugin which is created on request
|
||||
create_plugin (&*cls);
|
||||
create_plugin (current);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -685,6 +691,12 @@ LayoutViewBase::message (const std::string & /*s*/, int /*timeout*/)
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::set_focus ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutViewBase::is_dirty () const
|
||||
{
|
||||
|
|
@ -763,14 +775,6 @@ LayoutViewBase::configure (const std::string &name, const std::string &value)
|
|||
{
|
||||
lay::Dispatcher::configure (name, value);
|
||||
|
||||
if (mp_move_service && mp_move_service->configure (name, value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mp_tracker && mp_tracker->configure (name, value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == cfg_default_lyp_file) {
|
||||
|
||||
m_def_lyp_file = value;
|
||||
|
|
@ -1419,14 +1423,6 @@ LayoutViewBase::config_finalize ()
|
|||
void
|
||||
LayoutViewBase::enable_edits (bool enable)
|
||||
{
|
||||
// enable or disable these services:
|
||||
if (mp_selection_service) {
|
||||
mp_selection_service->enable (enable);
|
||||
}
|
||||
if (mp_move_service) {
|
||||
mp_move_service->enable (enable);
|
||||
}
|
||||
|
||||
// enable or disable the services that implement "lay::ViewService"
|
||||
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
lay::ViewService *svc = (*p)->view_service_interface ();
|
||||
|
|
@ -1965,6 +1961,22 @@ LayoutViewBase::set_properties (unsigned int index, const LayerPropertiesList &p
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::clear_layers (unsigned int index)
|
||||
{
|
||||
LayerPropertiesList ll;
|
||||
ll.set_name (get_properties (index).name ());
|
||||
set_properties (index, ll);
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::clear_layers ()
|
||||
{
|
||||
LayerPropertiesList ll;
|
||||
ll.set_name (get_properties ().name ());
|
||||
set_properties (ll);
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::expand_properties ()
|
||||
{
|
||||
|
|
@ -4848,13 +4860,6 @@ LayoutViewBase::background_color (tl::Color c)
|
|||
|
||||
do_set_background_color (c, contrast);
|
||||
|
||||
if (mp_selection_service) {
|
||||
mp_selection_service->set_colors (c, contrast);
|
||||
}
|
||||
if (mp_zoom_service) {
|
||||
mp_zoom_service->set_colors (c, contrast);
|
||||
}
|
||||
|
||||
// Set the color for all ViewService interfaces
|
||||
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
lay::ViewService *svc = (*p)->view_service_interface ();
|
||||
|
|
@ -5517,7 +5522,7 @@ LayoutViewBase::paste_interactive (bool transient_mode)
|
|||
// operations.
|
||||
trans->close ();
|
||||
|
||||
if (mp_move_service && mp_move_service->begin_move (trans.release (), transient_mode)) {
|
||||
if (mp_move_service && mp_move_service->start_move (trans.release (), transient_mode)) {
|
||||
switch_mode (-1); // move mode
|
||||
}
|
||||
}
|
||||
|
|
@ -5796,20 +5801,12 @@ LayoutViewBase::mode (int m)
|
|||
m_mode = m;
|
||||
mp_active_plugin = 0;
|
||||
|
||||
if (m > 0) {
|
||||
|
||||
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
if ((*p)->plugin_declaration ()->id () == m) {
|
||||
mp_active_plugin = *p;
|
||||
mp_canvas->activate ((*p)->view_service_interface ());
|
||||
break;
|
||||
}
|
||||
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
if ((*p)->plugin_declaration ()->id () == m) {
|
||||
mp_active_plugin = *p;
|
||||
mp_canvas->activate ((*p)->view_service_interface ());
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (m == 0 && mp_selection_service) {
|
||||
mp_canvas->activate (mp_selection_service);
|
||||
} else if (m == -1 && mp_move_service) {
|
||||
mp_canvas->activate (mp_move_service);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,8 +157,8 @@ struct LAYBASIC_PUBLIC LayerDisplayProperties
|
|||
* It manages the layer display list, bookmark list etc.
|
||||
*/
|
||||
class LAYBASIC_PUBLIC LayoutViewBase :
|
||||
public lay::Editables,
|
||||
public lay::Dispatcher
|
||||
public lay::Dispatcher, // needs to be first as it is the GSI base class
|
||||
public lay::Editables
|
||||
{
|
||||
public:
|
||||
typedef lay::CellView::unspecific_cell_path_type cell_path_type;
|
||||
|
|
@ -295,6 +295,11 @@ public:
|
|||
*/
|
||||
virtual void message (const std::string &s = "", int timeout = 10);
|
||||
|
||||
/**
|
||||
* @brief Sets the keyboard focus to the view
|
||||
*/
|
||||
virtual void set_focus ();
|
||||
|
||||
/**
|
||||
* @brief The "dirty" flag indicates that one of the layout has been modified
|
||||
*
|
||||
|
|
@ -510,18 +515,12 @@ public:
|
|||
/**
|
||||
* @brief Clear the given layer view list
|
||||
*/
|
||||
void clear_layers (unsigned int index)
|
||||
{
|
||||
set_properties (index, LayerPropertiesList ());
|
||||
}
|
||||
void clear_layers (unsigned int index);
|
||||
|
||||
/**
|
||||
* @brief Clear the current layer view list
|
||||
*/
|
||||
void clear_layers ()
|
||||
{
|
||||
set_properties (LayerPropertiesList ());
|
||||
}
|
||||
void clear_layers ();
|
||||
|
||||
/**
|
||||
* @brief Access the current layer properties list
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace lay
|
|||
{
|
||||
|
||||
MouseTracker::MouseTracker (lay::LayoutViewBase *view)
|
||||
: lay::ViewService (view->canvas ()), mp_view (view),
|
||||
: lay::ViewService (view->canvas ()), lay::Plugin (view), mp_view (view),
|
||||
m_cursor_color (tl::Color ()), m_cursor_line_style (0), m_cursor_enabled (false)
|
||||
{
|
||||
ui ()->grab_mouse (this, false);
|
||||
|
|
@ -129,5 +129,31 @@ MouseTracker::mouse_move_event (const db::DPoint &p, unsigned int /*buttons*/, b
|
|||
return false;
|
||||
}
|
||||
|
||||
} // namespace lay
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// NOTE: configuration currently is not declared here.
|
||||
// Same for the configuration pages.
|
||||
|
||||
class MouseTrackerDeclaration
|
||||
: public lay::PluginDeclaration
|
||||
{
|
||||
public:
|
||||
MouseTrackerDeclaration ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
|
||||
{
|
||||
return new MouseTracker (view);
|
||||
}
|
||||
|
||||
virtual bool enable_catchall_editor_options_pages () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> tracker_decl (new MouseTrackerDeclaration (), -1000, "laybasic::MouseTrackerPlugin");
|
||||
|
||||
} // namespace lay
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "layViewObject.h"
|
||||
#include "layMarker.h"
|
||||
#include "layPlugin.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
class QMouseEvent;
|
||||
|
|
@ -36,7 +37,7 @@ class LayoutCanvas;
|
|||
class LayoutViewBase;
|
||||
|
||||
class MouseTracker
|
||||
: public lay::ViewService
|
||||
: public lay::ViewService, public lay::Plugin
|
||||
{
|
||||
public:
|
||||
MouseTracker (lay::LayoutViewBase *view);
|
||||
|
|
@ -45,6 +46,11 @@ public:
|
|||
bool leave_event (bool prio);
|
||||
bool configure (const std::string &name, const std::string &value);
|
||||
|
||||
lay::ViewService *view_service_interface ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
lay::LayoutViewBase *mp_view;
|
||||
tl::shared_collection<lay::DMarker> mp_markers;
|
||||
|
|
|
|||
|
|
@ -20,11 +20,10 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "layMove.h"
|
||||
#include "layEditable.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "laySelector.h"
|
||||
#include "laybasicConfig.h"
|
||||
|
||||
|
|
@ -35,7 +34,7 @@ namespace lay
|
|||
// MoveService implementation
|
||||
|
||||
MoveService::MoveService (lay::LayoutViewBase *view)
|
||||
: lay::ViewService (view->canvas ()),
|
||||
: lay::EditorServiceBase (view),
|
||||
m_dragging (false),
|
||||
m_dragging_transient (false),
|
||||
mp_editables (view),
|
||||
|
|
@ -50,44 +49,36 @@ MoveService::~MoveService ()
|
|||
drag_cancel ();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MoveService::deactivated ()
|
||||
{
|
||||
EditorServiceBase::deactivated ();
|
||||
m_shift = db::DPoint ();
|
||||
mp_view->clear_transient_selection ();
|
||||
mp_editables->clear_transient_selection ();
|
||||
drag_cancel ();
|
||||
}
|
||||
|
||||
lay::angle_constraint_type
|
||||
ac_from_buttons (unsigned int buttons)
|
||||
{
|
||||
if ((buttons & lay::ShiftButton) != 0) {
|
||||
if ((buttons & lay::ControlButton) != 0) {
|
||||
return lay::AC_Any;
|
||||
} else {
|
||||
return lay::AC_Ortho;
|
||||
}
|
||||
} else {
|
||||
if ((buttons & lay::ControlButton) != 0) {
|
||||
return lay::AC_Diagonal;
|
||||
} else {
|
||||
return lay::AC_Global;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MoveService::configure (const std::string &name, const std::string &value)
|
||||
{
|
||||
if (lay::EditorServiceBase::configure (name, value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == cfg_grid) {
|
||||
tl::from_string (value, m_global_grid);
|
||||
}
|
||||
|
||||
return false; // not taken
|
||||
}
|
||||
|
||||
bool
|
||||
MoveService::key_event (unsigned int key, unsigned int /*buttons*/)
|
||||
MoveService::key_event (unsigned int key, unsigned int buttons)
|
||||
{
|
||||
if (lay::EditorServiceBase::key_event (key, buttons)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double dx = 0.0, dy = 0.0;
|
||||
if (int (key) == lay::KeyDown) {
|
||||
dy = -1.0;
|
||||
|
|
@ -129,6 +120,16 @@ MoveService::key_event (unsigned int key, unsigned int /*buttons*/)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
MoveService::focus_page_open ()
|
||||
{
|
||||
// This method is called on "Tab" by "key_event". "fp" is null as we don't have a focus page registered.
|
||||
if (is_active () && dispatcher ()) {
|
||||
dispatcher ()->menu_activated ("cm_sel_move");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
MoveService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||
{
|
||||
|
|
@ -240,7 +241,7 @@ MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool
|
|||
}
|
||||
|
||||
bool
|
||||
MoveService::begin_move (db::Transaction *transaction, bool transient_selection)
|
||||
MoveService::start_move (db::Transaction *transaction, bool transient_selection)
|
||||
{
|
||||
if (m_dragging) {
|
||||
return false;
|
||||
|
|
@ -308,7 +309,7 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_
|
|||
|
||||
ui ()->hover_reset ();
|
||||
|
||||
mp_view->clear_transient_selection ();
|
||||
mp_editables->clear_transient_selection ();
|
||||
|
||||
m_dragging = true;
|
||||
m_dragging_transient = drag_transient;
|
||||
|
|
@ -366,5 +367,24 @@ MoveService::finish ()
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class MoveServiceDeclaration
|
||||
: public lay::PluginDeclaration
|
||||
{
|
||||
public:
|
||||
MoveServiceDeclaration ()
|
||||
: lay::PluginDeclaration (-1)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
|
||||
{
|
||||
return new MoveService (view);
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> move_service_decl (new MoveServiceDeclaration (), -970, "laybasic::MoveServicePlugin");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,25 +24,25 @@
|
|||
#define HDR_layMove
|
||||
|
||||
#include "laybasicCommon.h"
|
||||
#include "layEditorServiceBase.h"
|
||||
#include "dbManager.h"
|
||||
#include "layViewObject.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace lay {
|
||||
|
||||
class Editables;
|
||||
class LayoutViewBase;
|
||||
|
||||
class LAYBASIC_PUBLIC MoveService :
|
||||
public lay::ViewService
|
||||
public lay::EditorServiceBase
|
||||
{
|
||||
public:
|
||||
MoveService (lay::LayoutViewBase *view);
|
||||
~MoveService ();
|
||||
|
||||
bool start_move (db::Transaction *transaction = 0, bool transient_selection = false);
|
||||
|
||||
bool configure (const std::string &name, const std::string &value);
|
||||
bool begin_move (db::Transaction *transaction = 0, bool transient_selection = false);
|
||||
void finish ();
|
||||
void cancel ();
|
||||
|
||||
|
|
@ -56,6 +56,7 @@ private:
|
|||
virtual bool key_event (unsigned int key, unsigned int buttons);
|
||||
virtual void drag_cancel ();
|
||||
virtual void deactivated ();
|
||||
int focus_page_open ();
|
||||
|
||||
bool handle_click (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ PluginDeclaration::PluginDeclaration ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PluginDeclaration::PluginDeclaration (int id)
|
||||
: m_id (id), m_editable_enabled (true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PluginDeclaration::~PluginDeclaration ()
|
||||
{
|
||||
if (Dispatcher::instance ()) {
|
||||
|
|
@ -309,8 +315,23 @@ PluginDeclaration::register_plugin ()
|
|||
// Plugin implementation
|
||||
|
||||
Plugin::Plugin (Plugin *parent, bool standalone)
|
||||
: mp_parent (parent), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (standalone)
|
||||
: mp_parent (0), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (false)
|
||||
{
|
||||
init (parent, standalone);
|
||||
}
|
||||
|
||||
Plugin::Plugin ()
|
||||
: mp_parent (0), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (false)
|
||||
{
|
||||
// .. nothing yet (waiting for init) ..
|
||||
}
|
||||
|
||||
void
|
||||
Plugin::init (Plugin *parent, bool standalone)
|
||||
{
|
||||
mp_parent = parent;
|
||||
m_standalone = standalone;
|
||||
|
||||
if (! parent) {
|
||||
if (! standalone) {
|
||||
// load the root with the default configuration
|
||||
|
|
@ -325,6 +346,7 @@ Plugin::Plugin (Plugin *parent, bool standalone)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Plugin::~Plugin ()
|
||||
{
|
||||
if (mp_parent) {
|
||||
|
|
|
|||
|
|
@ -160,6 +160,11 @@ public:
|
|||
*/
|
||||
PluginDeclaration ();
|
||||
|
||||
/**
|
||||
* @brief Constructor with a fixed ID
|
||||
*/
|
||||
PluginDeclaration (int id);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
|
|
@ -331,6 +336,18 @@ public:
|
|||
{
|
||||
// .. no pages in the default implementation ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether "catchall" editor options pages shall be included
|
||||
*
|
||||
* "catchall" editor options pages are ones that are unspecific and render a null "plugin_declaration".
|
||||
* A plugin can choose to include these pages if it listens to global configuration events.
|
||||
* Otherwise it should return false here to suppress these pages.
|
||||
*/
|
||||
virtual bool enable_catchall_editor_options_pages () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -504,6 +521,18 @@ public:
|
|||
*/
|
||||
Plugin (Plugin *parent, bool standalone = false);
|
||||
|
||||
/**
|
||||
* @brief The default constructor
|
||||
*
|
||||
* This constructor needs to be followed by init()
|
||||
*/
|
||||
Plugin ();
|
||||
|
||||
/**
|
||||
* @brief Initialization, following the default constructor
|
||||
*/
|
||||
void init (Plugin *parent, bool standalone = false);
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ SelectionService::SelectionService (lay::LayoutViewBase *view) :
|
|||
QObject (),
|
||||
#endif
|
||||
lay::ViewService (view->canvas ()),
|
||||
lay::Plugin (view),
|
||||
mp_view (view),
|
||||
mp_box (0),
|
||||
m_color (0),
|
||||
|
|
@ -317,4 +318,29 @@ SelectionService::begin (const db::DPoint &pos)
|
|||
ui ()->grab_mouse (this, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class SelectionServiceDeclaration
|
||||
: public lay::PluginDeclaration
|
||||
{
|
||||
public:
|
||||
SelectionServiceDeclaration ()
|
||||
: lay::PluginDeclaration (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
|
||||
{
|
||||
return new SelectionService (view);
|
||||
}
|
||||
|
||||
virtual bool enable_catchall_editor_options_pages () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> selection_service_decl (new SelectionServiceDeclaration (), -980, "laybasic::SelectionServicePlugin");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "layViewObject.h"
|
||||
#include "layEditable.h"
|
||||
#include "layPlugin.h"
|
||||
|
||||
#if defined (HAVE_QT)
|
||||
# include <QTimer>
|
||||
|
|
@ -45,7 +46,8 @@ class LAYBASIC_PUBLIC SelectionService :
|
|||
#if defined (HAVE_QT)
|
||||
public QObject,
|
||||
#endif
|
||||
public lay::ViewService
|
||||
public lay::ViewService,
|
||||
public lay::Plugin
|
||||
{
|
||||
#if defined (HAVE_QT)
|
||||
Q_OBJECT
|
||||
|
|
@ -55,6 +57,11 @@ public:
|
|||
SelectionService (lay::LayoutViewBase *view);
|
||||
~SelectionService ();
|
||||
|
||||
lay::ViewService *view_service_interface ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void set_colors (tl::Color background, tl::Color color);
|
||||
void begin (const db::DPoint &pos);
|
||||
|
||||
|
|
|
|||
|
|
@ -191,8 +191,15 @@ ViewObject::freeze ()
|
|||
// ViewService implementation
|
||||
|
||||
ViewService::ViewService (ViewObjectUI *widget)
|
||||
: mp_widget (widget), m_abs_grab (false), m_enabled (true)
|
||||
: mp_widget (0), m_abs_grab (false), m_enabled (true)
|
||||
{
|
||||
init (widget);
|
||||
}
|
||||
|
||||
void
|
||||
ViewService::init (ViewObjectUI *widget)
|
||||
{
|
||||
mp_widget = widget;
|
||||
if (widget) {
|
||||
widget->register_service (this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@ public:
|
|||
*/
|
||||
ViewService (ViewObjectUI *widget = 0);
|
||||
|
||||
/**
|
||||
* @brief Initialization, can follow default constructor
|
||||
*/
|
||||
void init (ViewObjectUI *widget);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace lay
|
|||
// ZoomService implementation
|
||||
|
||||
ZoomService::ZoomService (lay::LayoutViewBase *view)
|
||||
: lay::ViewService (view->canvas ()),
|
||||
: lay::ViewService (view->canvas ()), lay::Plugin (view),
|
||||
mp_view (view),
|
||||
mp_box (0),
|
||||
m_color (0)
|
||||
|
|
@ -282,5 +282,28 @@ ZoomService::begin (const db::DPoint &pos)
|
|||
ui ()->grab_mouse (this, true);
|
||||
}
|
||||
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class ZoomServiceDeclaration
|
||||
: public lay::PluginDeclaration
|
||||
{
|
||||
public:
|
||||
ZoomServiceDeclaration ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
|
||||
{
|
||||
return new ZoomService (view);
|
||||
}
|
||||
|
||||
virtual bool enable_catchall_editor_options_pages () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> zoom_service_decl (new ZoomServiceDeclaration (), -990, "laybasic::ZoomServicePlugin");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#define HDR_layZoomBox
|
||||
|
||||
#include "layViewObject.h"
|
||||
#include "layPlugin.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -35,7 +36,7 @@ class LayoutCanvas;
|
|||
class RubberBox;
|
||||
|
||||
class LAYBASIC_PUBLIC ZoomService
|
||||
: public lay::ViewService
|
||||
: public lay::ViewService, public lay::Plugin
|
||||
{
|
||||
public:
|
||||
ZoomService (lay::LayoutViewBase *view);
|
||||
|
|
@ -45,6 +46,11 @@ public:
|
|||
void begin (const db::DPoint &pos);
|
||||
void begin_pan (const db::DPoint &pos);
|
||||
|
||||
lay::ViewService *view_service_interface ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
virtual bool mouse_release_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
|
|
|
|||
|
|
@ -28,13 +28,16 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
|
|||
|
||||
SOURCES += \
|
||||
gsiDeclLayLayers.cc \
|
||||
gsiDeclLayDispatcher.cc \
|
||||
gsiDeclLayLayoutViewBase.cc \
|
||||
gsiDeclLayMarker.cc \
|
||||
gsiDeclLayMenu.cc \
|
||||
gsiDeclLayPlugin.cc \
|
||||
gsiDeclLayTlAdded.cc \
|
||||
gsiDeclLayRdbAdded.cc \
|
||||
layAbstractMenu.cc \
|
||||
layEditorOptionsPage.cc \
|
||||
layEditorOptionsPages.cc \
|
||||
layEditorUtils.cc \
|
||||
layLayoutViewConfig.cc \
|
||||
layMargin.cc \
|
||||
laybasicForceLink.cc \
|
||||
|
|
@ -87,6 +90,9 @@ SOURCES += \
|
|||
layUtils.cc \
|
||||
|
||||
HEADERS += \
|
||||
layEditorOptionsPage.h \
|
||||
layEditorOptionsPages.h \
|
||||
layEditorUtils.h \
|
||||
layMargin.h \
|
||||
laybasicConfig.h \
|
||||
laybasicForceLink.h \
|
||||
|
|
|
|||
|
|
@ -390,6 +390,14 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<tabstops>
|
||||
<tabstop>oversampling</tabstop>
|
||||
<tabstop>subres_mode</tabstop>
|
||||
<tabstop>highres_mode</tabstop>
|
||||
<tabstop>default_font_size</tabstop>
|
||||
<tabstop>global_trans</tabstop>
|
||||
<tabstop>def_depth</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -240,6 +240,15 @@ p, li { white-space: pre-wrap; }
|
|||
<header>layWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>lib_cb</tabstop>
|
||||
<tabstop>le_cell_name</tabstop>
|
||||
<tabstop>find_next</tabstop>
|
||||
<tabstop>lv_cells</tabstop>
|
||||
<tabstop>cb_show_all_cells</tabstop>
|
||||
<tabstop>ok_button</tabstop>
|
||||
<tabstop>cancel_button</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -144,6 +144,11 @@
|
|||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>cbx_context</tabstop>
|
||||
<tabstop>cbx_window</tabstop>
|
||||
<tabstop>le_max_markers</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue