mirror of https://github.com/KLayout/klayout.git
Rulers: confine box/ellipse to square/circle with Ctrl, center box/ellipse with Ctrl - same as for drawing boxes
This commit is contained in:
parent
18c2f5dfa4
commit
ddee74ab78
|
|
@ -50,6 +50,10 @@ ToolkitWidget::ToolkitWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispat
|
||||||
mp_y_le->set_label ("dy:");
|
mp_y_le->set_label ("dy:");
|
||||||
mp_layout->addWidget (mp_y_le);
|
mp_layout->addWidget (mp_y_le);
|
||||||
|
|
||||||
|
mp_d_le = new lay::DecoratedLineEdit (this);
|
||||||
|
mp_d_le->set_label ("d:");
|
||||||
|
mp_layout->addWidget (mp_d_le);
|
||||||
|
|
||||||
mp_layout->addStretch (1);
|
mp_layout->addStretch (1);
|
||||||
|
|
||||||
hide ();
|
hide ();
|
||||||
|
|
@ -86,12 +90,24 @@ ToolkitWidget::commit (lay::Dispatcher *dispatcher)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
if (mp_d_le->hasFocus ()) {
|
||||||
|
|
||||||
|
double d = 0.0;
|
||||||
|
|
||||||
|
tl::from_string (tl::to_string (mp_d_le->text ()), d);
|
||||||
|
|
||||||
|
dispatcher->call_function (ant::Service::d_function_name (), tl::to_string (d));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
double dx = 0.0, dy = 0.0;
|
double dx = 0.0, dy = 0.0;
|
||||||
|
|
||||||
tl::from_string (tl::to_string (mp_x_le->text ()), dx);
|
tl::from_string (tl::to_string (mp_x_le->text ()), dx);
|
||||||
tl::from_string (tl::to_string (mp_y_le->text ()), dy);
|
tl::from_string (tl::to_string (mp_y_le->text ()), dy);
|
||||||
|
|
||||||
dispatcher->call_function (ant::Service::function_name (), db::DVector (dx, dy).to_string ());
|
dispatcher->call_function (ant::Service::xy_function_name (), db::DVector (dx, dy).to_string ());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +116,7 @@ ToolkitWidget::commit (lay::Dispatcher *dispatcher)
|
||||||
void
|
void
|
||||||
ToolkitWidget::configure (const std::string &name, const std::string &value)
|
ToolkitWidget::configure (const std::string &name, const std::string &value)
|
||||||
{
|
{
|
||||||
if (name == ant::Service::configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
|
if (name == ant::Service::xy_configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
@ -113,6 +129,18 @@ ToolkitWidget::configure (const std::string &name, const std::string &value)
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (name == ant::Service::d_configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
double d;
|
||||||
|
tl::from_string (value, d);
|
||||||
|
|
||||||
|
mp_d_le->setText (tl::to_qstring (tl::micron_to_string (d)));
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHBoxLayout *mp_layout;
|
QHBoxLayout *mp_layout;
|
||||||
lay::DecoratedLineEdit *mp_x_le, *mp_y_le;
|
lay::DecoratedLineEdit *mp_x_le, *mp_y_le, *mp_d_le;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1043,8 +1043,10 @@ View::render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
|
||||||
// ant::Service implementation
|
// ant::Service implementation
|
||||||
|
|
||||||
const char *Service::editor_options_name () { return "ant-toolkit-widget-name"; }
|
const char *Service::editor_options_name () { return "ant-toolkit-widget-name"; }
|
||||||
const char *Service::configure_name () { return "ant-toolkit-widget-value"; }
|
const char *Service::xy_configure_name () { return "ant-toolkit-widget-xy-value"; }
|
||||||
const char *Service::function_name () { return "ant-toolkit-widget-commit"; }
|
const char *Service::d_configure_name () { return "ant-toolkit-widget-d-value"; }
|
||||||
|
const char *Service::xy_function_name () { return "ant-toolkit-widget-xy-commit"; }
|
||||||
|
const char *Service::d_function_name () { return "ant-toolkit-widget-d-commit"; }
|
||||||
|
|
||||||
Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
|
Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
|
||||||
: lay::EditorServiceBase (view),
|
: lay::EditorServiceBase (view),
|
||||||
|
|
@ -1061,6 +1063,9 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
|
||||||
m_drawing (false), m_current (),
|
m_drawing (false), m_current (),
|
||||||
m_move_mode (MoveNone),
|
m_move_mode (MoveNone),
|
||||||
m_seg_index (0),
|
m_seg_index (0),
|
||||||
|
m_length_confined (false),
|
||||||
|
m_length (0.0),
|
||||||
|
m_centered (false),
|
||||||
m_current_template (0),
|
m_current_template (0),
|
||||||
m_hover (false),
|
m_hover (false),
|
||||||
m_hover_wait (false),
|
m_hover_wait (false),
|
||||||
|
|
@ -1906,6 +1911,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
|
||||||
|
|
||||||
// cancel any edit operations so far
|
// cancel any edit operations so far
|
||||||
m_move_mode = MoveNone;
|
m_move_mode = MoveNone;
|
||||||
|
m_length_confined = false;
|
||||||
|
|
||||||
// reset selection
|
// reset selection
|
||||||
clear_selection ();
|
clear_selection ();
|
||||||
|
|
@ -2023,6 +2029,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
|
||||||
|
|
||||||
pts.push_back (m_p1);
|
pts.push_back (m_p1);
|
||||||
m_current.set_points_exact (pts);
|
m_current.set_points_exact (pts);
|
||||||
|
m_length_confined = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2058,7 +2065,7 @@ Service::create_measure_ruler (const db::DPoint &pt, lay::angle_constraint_type
|
||||||
void
|
void
|
||||||
Service::function (const std::string &name, const std::string &value)
|
Service::function (const std::string &name, const std::string &value)
|
||||||
{
|
{
|
||||||
if (name == function_name ()) {
|
if (name == xy_function_name ()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
@ -2109,6 +2116,59 @@ Service::function (const std::string &name, const std::string &value)
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (name == d_function_name ()) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
double s = 0.0;
|
||||||
|
tl::from_string (value, s);
|
||||||
|
|
||||||
|
if (m_drawing) {
|
||||||
|
|
||||||
|
m_length_confined = true;
|
||||||
|
m_length = s;
|
||||||
|
|
||||||
|
ant::Object::point_list pts = m_current.points ();
|
||||||
|
confine_length (pts);
|
||||||
|
m_current.set_points_exact (pts);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Service::confine_length (ant::Object::point_list &pts)
|
||||||
|
{
|
||||||
|
if (m_length_confined && pts.size () >= 2) {
|
||||||
|
|
||||||
|
const ant::Template &tpl = current_template ();
|
||||||
|
bool is_box_style = (tpl.outline () == ant::Object::OL_box || tpl.outline () == ant::Object::OL_ellipse);
|
||||||
|
|
||||||
|
db::DPoint p1 = m_centered ? m_p1 : pts [pts.size () - 2];
|
||||||
|
db::DVector s = pts.back () - p1;
|
||||||
|
if (is_box_style) {
|
||||||
|
db::DVector snew = s;
|
||||||
|
double l = m_centered ? m_length * 0.5 : m_length;
|
||||||
|
if (fabs (s.x ()) < fabs (s.y ()) + db::epsilon) {
|
||||||
|
snew.set_y (l * (s.y () < 0 ? -1.0 : 1.0));
|
||||||
|
}
|
||||||
|
if (fabs (s.y ()) < fabs (s.x ()) + db::epsilon) {
|
||||||
|
snew.set_x (l * (s.x () < 0 ? -1.0 : 1.0));
|
||||||
|
}
|
||||||
|
s = snew;
|
||||||
|
} else {
|
||||||
|
double l = s.double_length ();
|
||||||
|
if (l > db::epsilon) {
|
||||||
|
s *= m_length / l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pts.back () = p1 + s;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2131,11 +2191,31 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ant::Template &tpl = current_template ();
|
||||||
|
|
||||||
|
// for normal rulers with box or ellipse rendering we use a different button scheme:
|
||||||
|
// Shift will keep the center, Ctrl will confine the box to a square/ellipse to a circle
|
||||||
|
bool snap_square = false;
|
||||||
|
bool is_box_style = (tpl.outline () == ant::Object::OL_box || tpl.outline () == ant::Object::OL_ellipse);
|
||||||
|
if (tpl.mode () == ant::Template::RulerNormal && is_box_style) {
|
||||||
|
snap_square = (buttons & lay::ControlButton) != 0;
|
||||||
|
m_centered = (buttons & lay::ShiftButton) != 0;
|
||||||
|
} else {
|
||||||
|
m_centered = false;
|
||||||
|
}
|
||||||
|
|
||||||
lay::PointSnapToObjectResult snap_details;
|
lay::PointSnapToObjectResult snap_details;
|
||||||
if (m_drawing) {
|
if (m_drawing) {
|
||||||
snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons));
|
lay::angle_constraint_type ac;
|
||||||
|
if (snap_square) {
|
||||||
|
ac = lay::AC_DiagonalOnly;
|
||||||
|
} else if (is_box_style) {
|
||||||
|
ac = lay::AC_Any;
|
||||||
|
} else {
|
||||||
|
ac = ac_from_buttons (buttons);
|
||||||
|
}
|
||||||
|
snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac);
|
||||||
} else {
|
} else {
|
||||||
const ant::Template &tpl = current_template ();
|
|
||||||
snap_details = snap1_details (p, m_obj_snap && tpl.snap () && (tpl.mode () != ant::Template::RulerAutoMetricEdge || ! view ()->transient_selection_mode ()));
|
snap_details = snap1_details (p, m_obj_snap && tpl.snap () && (tpl.mode () != ant::Template::RulerAutoMetricEdge || ! view ()->transient_selection_mode ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2149,8 +2229,19 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||||
// otherwise we risk manipulating p1 too.
|
// otherwise we risk manipulating p1 too.
|
||||||
ant::Object::point_list pts = m_current.points ();
|
ant::Object::point_list pts = m_current.points ();
|
||||||
if (! pts.empty ()) {
|
if (! pts.empty ()) {
|
||||||
|
|
||||||
pts.back () = snap_details.snapped_point;
|
pts.back () = snap_details.snapped_point;
|
||||||
|
|
||||||
|
confine_length (pts);
|
||||||
|
|
||||||
|
if (m_centered) {
|
||||||
|
pts.front () = m_p1 - (pts.back () - m_p1);
|
||||||
|
} else {
|
||||||
|
pts.front () = m_p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
m_current.set_points_exact (pts);
|
m_current.set_points_exact (pts);
|
||||||
|
|
||||||
db::DVector delta;
|
db::DVector delta;
|
||||||
|
|
@ -2161,7 +2252,9 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
|
||||||
|
|
||||||
lay::EditorOptionsPage *tb = toolbox_widget ();
|
lay::EditorOptionsPage *tb = toolbox_widget ();
|
||||||
if (tb) {
|
if (tb) {
|
||||||
tb->configure (configure_name (), delta.to_string ());
|
double d = is_box_style ? std::min (fabs (delta.x ()), fabs (delta.y ())) : delta.length ();
|
||||||
|
tb->configure (xy_configure_name (), delta.to_string ());
|
||||||
|
tb->configure (d_configure_name (), tl::to_string (d));
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_active_ruler->redraw ();
|
mp_active_ruler->redraw ();
|
||||||
|
|
|
||||||
|
|
@ -199,8 +199,10 @@ public:
|
||||||
|
|
||||||
// for communicating with the toolbox widget
|
// for communicating with the toolbox widget
|
||||||
static const char *editor_options_name ();
|
static const char *editor_options_name ();
|
||||||
static const char *configure_name ();
|
static const char *xy_configure_name ();
|
||||||
static const char *function_name ();
|
static const char *d_configure_name ();
|
||||||
|
static const char *xy_function_name ();
|
||||||
|
static const char *d_function_name ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current move mode:
|
* The current move mode:
|
||||||
|
|
@ -598,6 +600,11 @@ private:
|
||||||
MoveMode m_move_mode;
|
MoveMode m_move_mode;
|
||||||
// The currently moving segment
|
// The currently moving segment
|
||||||
size_t m_seg_index;
|
size_t m_seg_index;
|
||||||
|
// When set to true, the length is confined to the value given by m_length
|
||||||
|
bool m_length_confined;
|
||||||
|
double m_length;
|
||||||
|
// When set to true, the last point was established in centered fashion
|
||||||
|
bool m_centered;
|
||||||
// The ruler template
|
// The ruler template
|
||||||
std::vector<ant::Template> m_ruler_templates;
|
std::vector<ant::Template> m_ruler_templates;
|
||||||
unsigned int m_current_template;
|
unsigned int m_current_template;
|
||||||
|
|
@ -618,6 +625,7 @@ private:
|
||||||
db::DPoint snap2_visual (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::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);
|
lay::TwoPointSnapToObjectResult auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl);
|
||||||
|
void confine_length (ant::Object::point_list &pts);
|
||||||
|
|
||||||
const ant::Template ¤t_template () const;
|
const ant::Template ¤t_template () const;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue