Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
object-picker-tool.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2
5#include "desktop.h"
6#include "object/sp-page.h"
8
9namespace Inkscape::UI::Tools {
10
11// label text size
12static const auto fontsize = 12;
13
14ObjectPickerTool::ObjectPickerTool(SPDesktop* desktop): ToolBase(desktop, "/tools/picker", "object-pick.svg", false) {
15 _zoom = desktop->signal_zoom_changed.connect([this](double){
16 // erase text; it doesn't scale well
17 show_text(Geom::Point(), nullptr);
18 });
19
20 // create text label and its frame
21 auto group = desktop->getCanvasTemp();
22 _frame = make_canvasitem<CanvasItemRect>(group);
23 _label = make_canvasitem<CanvasItemText>(group);
24
25 _label->set_fontsize(fontsize);
26 _label->set_fill(0x000000'ff); // black text
27 _label->set_background(0xffffff'bf); // white with some transparency
28 _label->set_border(4);
29 _label->set_fixed_line(true);
30 _label->set_visible(false);
31
32 _frame->set_shadow(0x00000020, 1);
33 _frame->set_stroke(0); // transparent
34 _frame->set_visible(false);
35}
36
41
43 SPObject* item = desktop->getItemAtPoint(point, false);
44 if (item) return item;
45
46 if (auto document = desktop->getDocument()) {
47 auto pt = desktop->w2d(point);
48 item = document->getPageManager().findPageAt(pt);
49 }
50
51 return item;
52}
53
55 auto handled = false;
56 auto switch_back = false;
57 auto desktop = _desktop;
58
59 inspect_event(event,
60
61 [&] (MotionEvent const &event) {
62 auto cursor = event.pos;
63 auto item = get_item_at(desktop, cursor);
64 show_text(cursor, item ? item->getId() : nullptr);
65 auto msg = item ? Glib::ustring("Pick object <b>") + item->getId() + Glib::ustring("</b>") : "Pick objects.";
67 },
68
69 [&] (ButtonPressEvent const &event) {
70 if (event.button != 1) return;
71
72 auto cursor = event.pos;
73 auto item = get_item_at(desktop, cursor);
74 show_text(cursor, item ? item->getId() : nullptr);
75 if (item) {
76 // object picked
77 if (!signal_object_picked.emit(item)) {
78 switch_back = true;
79 }
80 }
81 },
82
83 [&] (CanvasEvent const &event) {}
84 );
85
86 if (switch_back) {
87 auto last = get_last_active_tool();
88 if (!last.empty()) {
90 }
91 handled = true;
92 }
93
94 return handled || ToolBase::root_handler(event);
95}
96
97// Set label to show "text", move it above "cursor" on canvas
98void ObjectPickerTool::show_text(const Geom::Point& cursor, const char* text) {
99 _label->set_visible(false);
100 _frame->set_visible(false);
101
102 auto desktop = _desktop;
103 if (!desktop || !text) return;
104
105 auto position = desktop->w2d(Geom::Point(cursor.x(), cursor.y() - 2.5 * fontsize));
106
107 _label->set_text(text);
108 _label->set_coord(position);
109 _label->set_visible(true);
110 _label->update(false);
111
112 // TODO: improve text positioning and/or drop shadow drawing
113 // Review comments from PBS:
114 /*
115 The text rectangle returned by get_text_size() is not computed immediately, but only set on update(). That means the shadow is out of date and lags the text (only in certain situations).
116 I'm not sure of a nice way to fix this outside of moving the text bounds computation out of CanvasItemText into some common code and using that here. Or you could duplicate the shadow functionality from CanvasItemRect into CanvasItemText, since it already duplicates the rectangle fill.
117 It would also be nice to not have to add get_text_size() at all.
118 */
119 auto box = Geom::Rect::from_xywh(position, _label->get_text_size().dimensions() / desktop->current_zoom());
120 _frame->set_rect(box);
121 _frame->set_visible(true);
122}
123
124} // namespace
void set_active_tool(InkscapeWindow *win, Glib::ustring const &tool)
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
Two-dimensional point that doubles as a vector.
Definition point.h:66
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
MessageId flash(MessageType type, char const *message)
Temporarily pushes a message onto the stack.
CanvasItemPtr< CanvasItemText > _label
CanvasItemPtr< CanvasItemRect > _frame
bool root_handler(const CanvasEvent &event) override
sigc::signal< bool(SPObject *)> signal_object_picked
void show_text(const Geom::Point &cursor, const char *text)
Base class for Event processors.
Definition tool-base.h:95
void ungrabCanvasEvents()
Ungrab events from the Canvas Catchall.
virtual bool root_handler(CanvasEvent const &event)
const Glib::ustring & get_last_active_tool() const
To do: update description of desktop.
Definition desktop.h:149
double current_zoom() const
Definition desktop.h:335
SPDocument * getDocument() const
Definition desktop.h:189
Inkscape::MessageStack * messageStack() const
Definition desktop.h:160
Inkscape::CanvasItemGroup * getCanvasTemp() const
Definition desktop.h:202
SPItem * getItemAtPoint(Geom::Point const &p, bool into_groups, SPItem *upto=nullptr) const
Definition desktop.cpp:352
sigc::signal< void(double)> signal_zoom_changed
Emitted when the zoom factor changes (not emitted when scrolling).
Definition desktop.h:251
Geom::Affine const & w2d() const
Transformation from window to desktop coordinates (zoom/rotate).
Definition desktop.h:416
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
char const * getId() const
Returns the objects current ID string.
Glib::ustring msg
Editable view implementation.
SPItem * item
static const auto fontsize
SPObject * get_item_at(SPDesktop *desktop, const Geom::Point &point)
void inspect_event(E &&event, Fs... funcs)
Perform pattern-matching on a CanvasEvent.
@ INFORMATION_MESSAGE
Definition message.h:30
SPPage – a page object.
A mouse button (left/right/middle) is pressed.
Abstract base class for events.
Movement of the mouse pointer.
SPDesktop * desktop