From 307c10f1843e179ffb94e5bf2695d5d981e2433a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 7 Sep 2020 22:35:06 +0200 Subject: [PATCH] WIP: better highlighting of snap objects. --- src/edt/edt/edtService.cc | 74 +------ src/edt/edt/edtService.h | 19 +- src/edt/edt/edtServiceImpl.cc | 15 +- src/laybasic/laybasic/layEditorServiceBase.cc | 200 ++++++++++++++++++ src/laybasic/laybasic/layEditorServiceBase.h | 77 +++++++ src/laybasic/laybasic/laybasic.pro | 2 + 6 files changed, 296 insertions(+), 91 deletions(-) create mode 100644 src/laybasic/laybasic/layEditorServiceBase.cc create mode 100644 src/laybasic/laybasic/layEditorServiceBase.h diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index e5d3c48d5..4fad85754 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -61,8 +61,7 @@ ac_from_buttons (unsigned int buttons) // ------------------------------------------------------------- Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator::flags_type flags) - : lay::ViewService (view->view_object_widget ()), - lay::Editable (view), + : lay::EditorServiceBase (view), lay::Plugin (view), db::Object (manager), mp_view (view), @@ -83,8 +82,7 @@ Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator } Service::Service (db::Manager *manager, lay::LayoutView *view) - : lay::ViewService (view->view_object_widget ()), - lay::Editable (view), + : lay::EditorServiceBase (view), lay::Plugin (view), db::Object (manager), mp_view (view), @@ -116,7 +114,6 @@ Service::~Service () } m_edit_markers.clear (); - reset_mouse_cursor (); clear_transient_selection (); } @@ -480,71 +477,6 @@ Service::selection_bbox () return box; } -namespace -{ - -class MouseCursorViewObject - : public lay::ViewObject -{ -public: - MouseCursorViewObject (lay::ViewObjectWidget *widget, const db::DPoint &pt) - : lay::ViewObject (widget, false), m_pt (pt) - { } - - virtual void render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) - { - int dither_pattern = 0; // solid - int lw = int (0.5 + 1.0 / canvas.resolution ()); - - std::vector ops; - ops.resize (1); - ops[0] = lay::ViewOp (canvas.foreground_color ().rgb (), lay::ViewOp::Copy, 0, (unsigned int) dither_pattern, 0, lay::ViewOp::Rect, lw, 0); - lay::CanvasPlane *plane = canvas.plane (ops); - - lay::Renderer &r = canvas.renderer (); - - double rad = 4.0 / canvas.resolution () / vp.trans ().mag (); - - const size_t num_pts = 16; - db::DPoint pts [num_pts]; - for (size_t i = 0; i < num_pts; ++i) { - double x = rad * cos (M_PI * 2.0 * double (i) / double (num_pts)); - double y = rad * sin (M_PI * 2.0 * double (i) / double (num_pts)); - pts [i] = m_pt + db::DVector (x, y); - } - db::DPolygon circle; - circle.assign_hull (pts, pts + num_pts); - - r.draw (circle, vp.trans (), 0, plane, 0, 0); - - r.draw (db::DEdge (m_pt + db::DVector (0, rad * 0.5), m_pt + db::DVector (0, rad * 4)), vp.trans (), 0, plane, 0, 0); - r.draw (db::DEdge (m_pt + db::DVector (rad * 0.5, 0), m_pt + db::DVector (rad * 4, 0)), vp.trans (), 0, plane, 0, 0); - r.draw (db::DEdge (m_pt + db::DVector (0, -rad * 0.5), m_pt + db::DVector (0, -rad * 4)), vp.trans (), 0, plane, 0, 0); - r.draw (db::DEdge (m_pt + db::DVector (-rad * 0.5, 0), m_pt + db::DVector (-rad * 4, 0)), vp.trans (), 0, plane, 0, 0); - } - -private: - db::DPoint m_pt; -}; - -} - -void -Service::set_mouse_cursor (const db::DPoint &pt) -{ - reset_mouse_cursor (); - m_mouse_cursor_markers.push_back (new MouseCursorViewObject (widget (), pt)); -} - -void -Service::reset_mouse_cursor () -{ - for (std::vector::iterator r = m_mouse_cursor_markers.begin (); r != m_mouse_cursor_markers.end (); ++r) { - delete *r; - } - m_mouse_cursor_markers.clear (); -} - void Service::set_edit_marker (lay::ViewObject *edit_marker) { @@ -881,7 +813,7 @@ Service::activated () void Service::deactivated () { - reset_mouse_cursor (); + clear_mouse_cursors (); edit_cancel (); diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index 7f2320f02..22ff094e3 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -27,9 +27,8 @@ #include "edtCommon.h" -#include "layEditable.h" +#include "layEditorServiceBase.h" #include "layPlugin.h" -#include "layViewObject.h" #include "layMarker.h" #include "laySnap.h" #include "layObjectInstPath.h" @@ -72,8 +71,7 @@ std::map pcell_parameters_from_string (const std::stri // ------------------------------------------------------------- class EDT_PUBLIC Service - : public lay::ViewService, - public lay::Editable, + : public lay::EditorServiceBase, public lay::Plugin, public db::Object { @@ -458,16 +456,6 @@ protected: */ virtual void service_configuration_changed (); - /** - * @brief Sets the mouse cursor to the given point - */ - void set_mouse_cursor (const db::DPoint &pt); - - /** - * @brief Resets the mouse cursor - */ - void reset_mouse_cursor (); - /** * @brief Install a marker for representing the edited object * @@ -578,9 +566,6 @@ private: // The marker representing the object to be edited std::vector m_edit_markers; - // The marker representing the mouse cursor - std::vector m_mouse_cursor_markers; - // True, if editing is in progress. bool m_editing; diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index 51b28a90b..b34ce269b 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -417,14 +417,23 @@ void PolygonService::do_mouse_move_inactive (const db::DPoint &p) { lay::PointSnapToObjectResult snap_details = snap2_details (p); - set_mouse_cursor (snap_details.snapped_point); + + clear_mouse_cursors (); + + add_mouse_cursor (snap_details.snapped_point, + snap_details.object_snap == lay::PointSnapToObjectResult::ObjectVertex || + (snap_details.object_snap == lay::PointSnapToObjectResult::ObjectUnspecific && snap_details.object_ref.is_degenerate ())); + + if (snap_details.object_snap == lay::PointSnapToObjectResult::ObjectEdge || + (snap_details.object_snap == lay::PointSnapToObjectResult::ObjectUnspecific && ! snap_details.object_ref.is_degenerate ())) { + add_edge_marker (snap_details.object_ref, false); + } } void PolygonService::do_mouse_move (const db::DPoint &p) { - lay::PointSnapToObjectResult snap_details = snap2_details (p); - set_mouse_cursor (snap_details.snapped_point); + do_mouse_move_inactive (p); set_cursor (lay::Cursor::cross); if (m_points.size () >= 2) { diff --git a/src/laybasic/laybasic/layEditorServiceBase.cc b/src/laybasic/laybasic/layEditorServiceBase.cc new file mode 100644 index 000000000..e05df5bec --- /dev/null +++ b/src/laybasic/laybasic/layEditorServiceBase.cc @@ -0,0 +1,200 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layEditorServiceBase.h" +#include "layViewport.h" +#include "layLayoutView.h" + +namespace lay +{ + +// -------------------------------------------------------------------------------------- + +template +static void +make_circle (double r, const db::DPoint ¢er, db::DPolygon &poly, bool as_hole) +{ + db::DPoint pts [num_pts]; + for (size_t i = 0; i < num_pts; ++i) { + double x = r * cos (M_PI * 2.0 * double (i) / double (num_pts)); + double y = r * sin (M_PI * 2.0 * double (i) / double (num_pts)); + pts [i] = center + db::DVector (x, y); + } + + if (! as_hole) { + poly.assign_hull (pts, pts + num_pts); + } else { + poly.insert_hole (pts, pts + num_pts); + } +} + +class MouseCursorViewObject + : public lay::ViewObject +{ +public: + MouseCursorViewObject (lay::ViewObjectWidget *widget, const db::DPoint &pt, bool solid) + : lay::ViewObject (widget, false), m_pt (pt), m_solid (solid) + { } + + virtual void render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) + { + int dither_pattern = 0; // solid + int cross_dither_pattern = 6; // dotted + + int lw = int (0.5 + 1.0 / canvas.resolution ()); + + std::vector ops; + ops.resize (1); + ops[0] = lay::ViewOp (canvas.foreground_color ().rgb (), lay::ViewOp::Copy, 0, (unsigned int) dither_pattern, 0, lay::ViewOp::Rect, lw, 0); + lay::CanvasPlane *plane = canvas.plane (ops); + + ops[0] = lay::ViewOp (canvas.foreground_color ().rgb (), lay::ViewOp::Copy, 0, (unsigned int) cross_dither_pattern, 0, lay::ViewOp::Rect, lw, 0); + lay::CanvasPlane *cross_plane = canvas.plane (ops); + + lay::Renderer &r = canvas.renderer (); + + double rad = 4.0 / canvas.resolution () / vp.trans ().mag (); + + db::DPolygon c; + if (! m_solid) { + make_circle (rad, m_pt, c, false); + r.draw (c, vp.trans (), 0, plane, 0, 0); + } else { + make_circle (rad * 2, m_pt, c, false); + r.draw (c, vp.trans (), 0, plane, 0, 0); + make_circle (rad, m_pt, c, false); + r.draw (c, vp.trans (), 0, plane, 0, 0); + } + + r.draw (db::DEdge (m_pt + db::DVector (0, -rad * 4), m_pt + db::DVector (0, rad * 4)), vp.trans (), 0, cross_plane, 0, 0); + r.draw (db::DEdge (m_pt + db::DVector (-rad * 4, 0), m_pt + db::DVector (rad * 4, 0)), vp.trans (), 0, cross_plane, 0, 0); + } + +private: + db::DPoint m_pt; + bool m_solid; +}; + +class EdgeMarkerViewObject + : public lay::ViewObject +{ +public: + EdgeMarkerViewObject (lay::ViewObjectWidget *widget, const db::DEdge &edge, bool solid) + : lay::ViewObject (widget, false), m_edge (edge), m_solid (solid) + { } + + virtual void render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) + { + if (m_edge.is_degenerate ()) { + return; + } + + int dashed_style = 2; + int solid_style = 0; + + int lw = int (0.5 + 1.0 / canvas.resolution ()); + + std::vector ops; + ops.resize (1); + ops[0] = lay::ViewOp (canvas.foreground_color ().rgb (), lay::ViewOp::Copy, solid_style, 0, 0, lay::ViewOp::Rect, lw, 0); + lay::CanvasPlane *arrow_plane = canvas.plane (ops); + + ops[0] = lay::ViewOp (canvas.foreground_color ().rgb (), lay::ViewOp::Copy, m_solid ? solid_style : dashed_style, 1, 0, lay::ViewOp::Rect, lw, 0); + lay::CanvasPlane *edge_plane = canvas.plane (ops); + + lay::Renderer &r = canvas.renderer (); + r.draw (m_edge, vp.trans (), 0, edge_plane, 0, 0); + + double arrow_length = 12.0 / canvas.resolution () / vp.trans ().mag (); + + double arrow_width_half = arrow_length * 0.25882; // sin(15 deg) + db::DVector n = db::DVector (m_edge.dy (), -m_edge.dx ()) * (arrow_width_half / m_edge.length ()); + db::DVector d = db::DVector (m_edge.dx (), m_edge.dy ()) * (arrow_length / m_edge.length ()); + + if (m_edge.length () < 2 * arrow_length) { + + r.draw (db::DEdge (m_edge.p1 () - n, m_edge.p1 () + n), vp.trans (), 0, arrow_plane, 0, 0); + r.draw (db::DEdge (m_edge.p2 () - n, m_edge.p2 () + n), vp.trans (), 0, arrow_plane, 0, 0); + + } else { + + db::DPoint pts[3]; + db::DPolygon p; + + pts[0] = m_edge.p1 (); + pts[1] = m_edge.p1 () + d - n; + pts[2] = m_edge.p1 () + d + n; + + p.assign_hull (pts, pts + 3); + r.draw (p, vp.trans (), 0, arrow_plane, 0, 0); + + pts[0] = m_edge.p2 (); + pts[1] = m_edge.p2 () - d + n; + pts[2] = m_edge.p2 () - d - n; + + p.assign_hull (pts, pts + 3); + r.draw (p, vp.trans (), 0, arrow_plane, 0, 0); + + } + } + +private: + db::DEdge m_edge; + bool m_solid; +}; + +// -------------------------------------------------------------------------------------- + +EditorServiceBase::EditorServiceBase (lay::LayoutView *view) + : lay::ViewService (view->view_object_widget ()), + lay::Editable (view) +{ + // .. nothing yet .. +} + +EditorServiceBase::~EditorServiceBase () +{ + clear_mouse_cursors (); +} + +void +EditorServiceBase::add_mouse_cursor (const db::DPoint &pt, bool emphasize) +{ + m_mouse_cursor_markers.push_back (new MouseCursorViewObject (widget (), pt, emphasize)); +} + +void +EditorServiceBase::add_edge_marker (const db::DEdge &e, bool emphasize) +{ + m_mouse_cursor_markers.push_back (new EdgeMarkerViewObject (widget (), e, emphasize)); +} + +void +EditorServiceBase::clear_mouse_cursors () +{ + for (std::vector::iterator r = m_mouse_cursor_markers.begin (); r != m_mouse_cursor_markers.end (); ++r) { + delete *r; + } + m_mouse_cursor_markers.clear (); +} + +} diff --git a/src/laybasic/laybasic/layEditorServiceBase.h b/src/laybasic/laybasic/layEditorServiceBase.h new file mode 100644 index 000000000..1c28ccbee --- /dev/null +++ b/src/laybasic/laybasic/layEditorServiceBase.h @@ -0,0 +1,77 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_layEditorServiceBase +#define HDR_layEditorServiceBase + +#include "laybasicCommon.h" +#include "layEditable.h" +#include "layViewObject.h" + +namespace lay +{ + +/** + * @brief A generic base class for an editor service + * + * This class offers common services such as a mouse cursor. + */ +class LAYBASIC_PUBLIC EditorServiceBase + : public lay::ViewService, + public lay::Editable +{ +public: + /** + * @brief Constructor + */ + EditorServiceBase (lay::LayoutView *view); + + /** + * @brief Destructor + */ + ~EditorServiceBase (); + + /** + * @brief Adds a mouse cursor to the given point + */ + void add_mouse_cursor (const db::DPoint &pt, bool emphasize = false); + + /** + * @brief Adds an edge marker for the given edge + */ + void add_edge_marker (const db::DEdge &e, bool emphasize); + + /** + * @brief Resets the mouse cursor + */ + void clear_mouse_cursors (); + +private: + // The marker representing the mouse cursor + std::vector m_mouse_cursor_markers; +}; + +} + +#endif + diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 2fef55427..38963208b 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -118,6 +118,7 @@ SOURCES = \ layEditorOptionsFrame.cc \ layEditorOptionsPage.cc \ layEditorOptionsPages.cc \ + layEditorServiceBase.cc \ layFileDialog.cc \ layFinder.cc \ layFixedFont.cc \ @@ -222,6 +223,7 @@ HEADERS = \ layEditorOptionsFrame.h \ layEditorOptionsPage.h \ layEditorOptionsPages.h \ + layEditorServiceBase.h \ layFileDialog.h \ layFinder.h \ layFixedFont.h \