Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
pages-tool.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Page editing tool
4 *
5 * Authors:
6 * Martin Owens <doctormo@geek-2.com>
7 *
8 * Copyright (C) 2021 Authors
9 *
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13#include "pages-tool.h"
14
15#include <gdk/gdkkeysyms.h>
16#include <glibmm/i18n.h>
17
18#include "desktop.h"
19#include "document-undo.h"
20#include "pure-transform.h"
21#include "selection.h"
22#include "snap-preferences.h"
23#include "snap.h"
24
29#include "object/sp-page.h"
30#include "path/path-outline.h"
31#include "ui/icon-names.h"
32#include "ui/knot/knot.h"
33#include "ui/modifiers.h"
34#include "ui/widget/canvas.h"
36
38
39template <typename Tv, typename Tk>
40static auto INDEX_OF(Tv const &v, Tk const &k) { return std::distance(v.begin(), std::find(v.begin(), v.end(), k)); }
41
42namespace Inkscape::UI::Tools {
43
45 : ToolBase(desktop, "/tools/pages", "select.svg")
46{
47 // Save selection state and clear selection before using the tool
48 _selection_state = std::make_unique<Inkscape::SelectionState>(desktop->getSelection()->getState());
50
52 drag_tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
53
54 if (resize_knots.empty()) {
55 for (int i = 0; i < 4; i++) {
56 auto knot = new SPKnot(desktop, _("Resize page"), Inkscape::CANVAS_ITEM_CTRL_TYPE_SIZER, "PageTool:Resize");
57 knot->setAnchor(SP_ANCHOR_CENTER);
58 knot->updateCtrl();
59 knot->hide();
60 knot->moved_signal.connect(sigc::mem_fun(*this, &PagesTool::resizeKnotMoved));
61 knot->ungrabbed_signal.connect(sigc::mem_fun(*this, &PagesTool::resizeKnotFinished));
62 resize_knots.push_back(knot);
63
64 auto m_knot = new SPKnot(desktop, _("Set page margin"), Inkscape::CANVAS_ITEM_CTRL_TYPE_MARGIN, "PageTool:Margin");
65 m_knot->setAnchor(SP_ANCHOR_CENTER);
66 m_knot->updateCtrl();
67 m_knot->hide();
68 m_knot->request_signal.connect(sigc::mem_fun(*this, &PagesTool::marginKnotMoved));
69 m_knot->ungrabbed_signal.connect(sigc::mem_fun(*this, &PagesTool::marginKnotFinished));
70 margin_knots.push_back(m_knot);
71
72 auto &widget = dynamic_cast<Gtk::Widget &>(*desktop->getCanvas());
73 knot->setCursor (SP_KNOT_STATE_DRAGGING , get_cursor(widget, "page-resizing.svg"));
74 knot->setCursor (SP_KNOT_STATE_MOUSEOVER, get_cursor(widget, "page-resize.svg" ));
75 m_knot->setCursor(SP_KNOT_STATE_DRAGGING , get_cursor(widget, "page-resizing.svg"));
76 m_knot->setCursor(SP_KNOT_STATE_MOUSEOVER, get_cursor(widget, "page-resize.svg" ));
77 }
78 }
79
80 if (!visual_box) {
81 visual_box = make_canvasitem<CanvasItemRect>(desktop->getCanvasControls());
82 visual_box->set_stroke(0x0000ff7f);
83 visual_box->set_visible(false);
84 }
85 if (!drag_group) {
86 drag_group = make_canvasitem<CanvasItemGroup>(desktop->getCanvasTemp());
87 drag_group->set_name("CanvasItemGroup:PagesDragShapes");
88 }
89
92 });
94
95 _zoom_connection = desktop->signal_zoom_changed.connect([desktop, this](double) {
96 // This readjusts the knot on zoom because the viewbox position
97 // becomes detached on zoom, likely a precision problem.
99 selectionChanged(desktop->getDocument(), nullptr);
100 }
101 });
102}
103
104
106{
107 connectDocument(nullptr);
108
110
111 visual_box.reset();
112
113 for (auto knot : resize_knots) {
114 delete knot;
115 }
116 resize_knots.clear();
117
118 if (drag_group) {
119 drag_group.reset();
120 drag_shapes.clear(); // Already deleted by group
121 }
122
123 _doc_replaced_connection.disconnect();
124 _zoom_connection.disconnect();
125}
126
128{
129 for (int i = 0; i < resize_knots.size(); i++) {
130 resize_knots[i]->moveto(rect.corner(i));
131 resize_knots[i]->show();
132 }
133}
134
136{
137 for (int i = 0; i < margin_knots.size(); i++) {
138 margin_knots[i]->moveto(middleOfSide(i, margin_rect) * _desktop->doc2dt());
139 margin_knots[i]->show();
140 }
141}
142
143/*
144 * Get the middle of the side of the rectangle.
145 */
147{
148 return Geom::middle_point(rect.corner(side), rect.corner((side + 1) % 4));
149}
150
151void PagesTool::resizeKnotMoved(SPKnot *knot, Geom::Point const &ppointer, guint state)
152{
153 Geom::Rect rect;
154
156 if (page) {
157 // Resizing a specific selected page
158 rect = page->getDesktopRect();
159 } else if (auto document = _desktop->getDocument()) {
160 // Resizing the naked viewBox
161 rect = *(document->preferredBounds()) * document->doc2dt();
162 }
163
164 int index;
165 for (index = 0; index < 4; index++) {
166 if (knot == resize_knots[index]) {
167 break;
168 }
169 }
171 Geom::Point point = getSnappedResizePoint(knot->position(), state, start, page);
172
173 if (point != start) {
174 if (index % 3 == 0)
175 rect[Geom::X].setMin(point[Geom::X]);
176 else
177 rect[Geom::X].setMax(point[Geom::X]);
178
179 if (index < 2)
180 rect[Geom::Y].setMin(point[Geom::Y]);
181 else
182 rect[Geom::Y].setMax(point[Geom::Y]);
183
184 visual_box->set_visible(true);
185 visual_box->set_rect(rect);
186 on_screen_rect = rect;
187 mouse_is_pressed = true;
188 }
189}
190
195{
196 if (!(state & GDK_SHIFT_MASK)) {
197 SnapManager &snap_manager = _desktop->getNamedView()->snap_manager;
198 snap_manager.setup(_desktop, true, target);
200 scp.addOrigin(origin);
201 Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
202 point = sp.getPoint();
203 snap_manager.unSetup();
204 }
205 return point;
206}
207
208void PagesTool::resizeKnotFinished(SPKnot *knot, guint state)
209{
210 auto document = _desktop->getDocument();
211 auto page = document->getPageManager().getSelected();
212 if (on_screen_rect) {
213 document->getPageManager().fitToRect(*on_screen_rect * document->dt2doc(), page);
214 Inkscape::DocumentUndo::done(document, "Resize page", INKSCAPE_ICON("tool-pages"));
215 on_screen_rect = {};
216 }
217 visual_box->set_visible(false);
218 mouse_is_pressed = false;
219}
220
221bool PagesTool::marginKnotMoved(SPKnot *knot, Geom::Point *ppointer, guint state)
222{
223 auto document = _desktop->getDocument();
224 auto &pm = document->getPageManager();
225
226 // Editing margins creates a page for the margin to be stored in.
227 pm.enablePages();
228
229 if (auto page = pm.getSelected()) {
230 Geom::Point point = *ppointer * document->dt2doc();
231
232 // Confine knot to edge
235 point = getSnappedResizePoint(point, state, knot->drag_origin, page);
236 }
237
238 // Calculate what we're acting on, clamp it depending on the side.
239 int side = INDEX_OF(margin_knots, knot);
240 auto axis = (side & 1) ? Geom::X : Geom::Y;
241 auto delta = (point - page->getDocumentRect().corner(side))[axis];
242 auto value = std::max(0.0, (side + 1) & 2 ? -delta : delta);
243 auto scale = document->getDocumentScale()[axis];
244
245 // Set to page and back to to knot to inform confinement.
246 page->setMarginSide(side, value / scale, confine);
247 knot->setPosition(middleOfSide(side, page->getDocumentMargin()) * document->doc2dt(), state);
248
249 Inkscape::DocumentUndo::maybeDone(document, "page-margin", ("Adjust page margin"), INKSCAPE_ICON("tool-pages"));
250 } else {
251 g_warning("Can't add margin, pages not enabled correctly!");
252 }
253 return true;
254}
255
256void PagesTool::marginKnotFinished(SPKnot *knot, guint state)
257{
258 // Margins are updated in real time.
259}
260
262{
263 bool ret = false;
264 auto &page_manager = _desktop->getDocument()->getPageManager();
265
266 inspect_event(event,
267 [&] (ButtonPressEvent const &event) {
268 if (event.num_press == 1 && event.button == 1) {
269 mouse_is_pressed = true;
270 drag_origin_w = event.pos;
271 drag_origin_dt = _desktop->w2d(drag_origin_w);
272 ret = true;
273 if (auto page = pageUnder(drag_origin_dt, false)) {
274 // Select the clicked on page. Manager ignores the same-page.
275 _desktop->getDocument()->getPageManager().selectPage(page);
276 set_cursor("page-dragging.svg");
277 } else if (viewboxUnder(drag_origin_dt)) {
278 dragging_viewbox = true;
279 set_cursor("page-dragging.svg");
280 } else {
282 }
283 } else if (event.button == 3) {
284 menu_popup(event, page_manager.getSelected());
285 ret = true;
286 }
287 },
288 [&] (MotionEvent const &event) {
289 auto point_w = event.pos;
290 auto point_dt = _desktop->w2d(point_w);
291 bool snap = !(event.modifiers & GDK_SHIFT_MASK);
292
293 if (event.modifiers & GDK_BUTTON1_MASK) {
294 if (!mouse_is_pressed) {
295 // this sometimes happens if the mouse was off the edge when the event started
296 drag_origin_w = point_w;
297 drag_origin_dt = point_dt;
298 mouse_is_pressed = true;
299 }
300
301 if (dragging_item || dragging_viewbox) {
302 // Continue to drag item.
303 Geom::Affine tr = moveTo(point_dt, snap);
304 // XXX Moving the existing shapes would be much better, but it has
305 // a weird bug which stops it from working well.
306 // drag_group->update(tr * drag_group->get_parent()->get_affine());
307 addDragShapes(dragging_item, tr);
308 _desktop->getCanvas()->enable_autoscroll();
309 } else if (on_screen_rect) {
310 // Continue to drag new box
311 point_dt = getSnappedResizePoint(point_dt, event.modifiers, drag_origin_dt);
312 on_screen_rect = Geom::Rect(drag_origin_dt, point_dt);
313 } else if (Geom::distance(drag_origin_w, point_w) < drag_tolerance) {
314 // do not start dragging anything new if we're within tolerance from origin.
315 // pass
316 } else if (auto page = pageUnder(drag_origin_dt)) {
317 // Starting to drag page around the screen, the pageUnder must
318 // be the drag_origin as small movements can kill the UX feel.
319 dragging_item = page;
320 page_manager.selectPage(page);
321 addDragShapes(page, Geom::Affine());
322 grabPage(page);
323 } else if (viewboxUnder(drag_origin_dt)) {
324 // Special handling of viewbox dragging
325 dragging_viewbox = true;
326 } else {
327 // Start making a new page.
328 dragging_item = nullptr;
329 on_screen_rect = Geom::Rect(drag_origin_dt, drag_origin_dt);
330 set_cursor("page-draw.svg");
331 }
332 } else {
333 mouse_is_pressed = false;
334 drag_origin_dt = point_dt;
335 }
336 },
337 [&] (ButtonReleaseEvent const &event) {
338 if (event.button != 1) {
339 return;
340 }
341 auto point_w = event.pos;
342 auto point_dt = _desktop->w2d(point_w);
343 bool snap = !(event.modifiers & GDK_SHIFT_MASK);
344 auto document = _desktop->getDocument();
345
346 if (dragging_viewbox || dragging_item) {
347 if (dragging_viewbox || dragging_item->isViewportPage()) {
348 // Move the document's viewport first
349 auto page_items = page_manager.getOverlappingItems(_desktop, dragging_item);
350 auto rect = document->preferredBounds();
351 auto affine = moveTo(point_dt, snap);
352 document->fitToRect(*rect * affine * document->dt2doc(), false);
353 // Now move the page back to where we expect it.
354 if (dragging_item) {
355 dragging_item->movePage(affine, false);
356 dragging_item->setDesktopRect(*rect);
357 }
358 // We have a custom move object because item detection is fubar after fitToRect
359 if (page_manager.move_objects()) {
360 SPPage::moveItems(affine, page_items);
361 }
362 } else {
363 // Move the page object on the canvas.
364 dragging_item->movePage(moveTo(point_dt, snap), page_manager.move_objects());
365 }
366 Inkscape::DocumentUndo::done(_desktop->getDocument(), "Move page position", INKSCAPE_ICON("tool-pages"));
367 } else if (on_screen_rect) {
368 // conclude box here (make new page)
369 page_manager.selectPage(page_manager.newDesktopPage(*on_screen_rect));
370 Inkscape::DocumentUndo::done(_desktop->getDocument(), "Create new drawn page", INKSCAPE_ICON("tool-pages"));
371 }
372 mouse_is_pressed = false;
373 drag_origin_dt = point_dt;
374 ret = true;
375
376 // Clear snap indication on mouse up.
377 _desktop->getSnapIndicator()->remove_snaptarget();
378 },
379 [&] (KeyPressEvent const &event) {
380 if (event.keyval == GDK_KEY_Escape) {
381 mouse_is_pressed = false;
382 ret = true;
383 }
384 if (event.keyval == GDK_KEY_Delete) {
385 page_manager.deletePage(page_manager.move_objects());
386
387 Inkscape::DocumentUndo::done(_desktop->getDocument(), "Delete Page", INKSCAPE_ICON("tool-pages"));
388 ret = true;
389 }
390 },
391 [&] (CanvasEvent const &event) {}
392 );
393
394 // Clean up any finished dragging, doesn't matter how it ends
395 if (!mouse_is_pressed && (dragging_item || on_screen_rect || dragging_viewbox)) {
396 dragging_viewbox = false;
397 dragging_item = nullptr;
398 on_screen_rect = {};
399 clearDragShapes();
400 visual_box->set_visible(false);
401 ret = true;
402 } else if (on_screen_rect) {
403 visual_box->set_visible(true);
404 visual_box->set_rect(*on_screen_rect);
405 ret = true;
406 }
407 if (!mouse_is_pressed) {
408 if (pageUnder(drag_origin_dt) || viewboxUnder(drag_origin_dt)) {
409 // This page under uses the current mouse position (unlike the above)
410 set_cursor("page-mouseover.svg");
411 } else {
412 set_cursor("page-draw.svg");
413 }
414 }
415
416 return ret || ToolBase::root_handler(event);
417}
418
419void PagesTool::menu_popup(CanvasEvent const &event, SPObject *obj)
420{
421 auto &page_manager = _desktop->getDocument()->getPageManager();
422 SPPage *page = page_manager.getSelected();
423 inspect_event(event,
424 [&] (ButtonPressEvent const &event) {
425 drag_origin_dt = _desktop->w2d(event.pos);
426 page = pageUnder(drag_origin_dt);
427 },
428 [&] (CanvasEvent const &event) {}
429 );
430
431 ToolBase::menu_popup(event, page);
432}
433
434void PagesTool::switching_away(std::string const &)
435{
436 if (_selection_state) {
437 _desktop->getSelection()->setState(*_selection_state);
438 _selection_state.reset();
439 }
440}
441
445void PagesTool::grabPage(SPPage *target)
446{
447 _bbox_points.clear();
450}
451
452/*
453 * Generate the movement affine as the page is dragged around (including snapping)
454 */
455Geom::Affine PagesTool::moveTo(Geom::Point xy, bool snap)
456{
457 Geom::Point dxy = xy - drag_origin_dt;
458
459 if (snap) {
460 SnapManager &snap_manager = _desktop->getNamedView()->snap_manager;
461 snap_manager.setup(_desktop, true, dragging_item);
462 snap_manager.snapprefs.clearTargetMask(0); // Disable all snapping targets
469 snap_manager.snapprefs.setTargetMask(SNAPTARGET_GUIDE, -1);
471
473 snap_manager.snapTransformed(_bbox_points, drag_origin_dt, (*bb));
474
475 if (bb->best_snapped_point.getSnapped()) {
476 dxy = bb->getTranslationSnapped();
477 _desktop->getSnapIndicator()->set_new_snaptarget(bb->best_snapped_point);
478 }
479
480 snap_manager.snapprefs.clearTargetMask(-1); // Reset preferences
481 snap_manager.unSetup();
482 }
483
484 return Geom::Translate(dxy);
485}
486
490void PagesTool::addDragShapes(SPPage *page, Geom::Affine tr)
491{
492 clearDragShapes();
493 auto doc = _desktop->getDocument();
494
495 if (page) {
496 addDragShape(Geom::PathVector(Geom::Path(page->getDesktopRect())), tr);
497 } else {
498 auto doc_rect = doc->preferredBounds();
499 addDragShape(Geom::PathVector(Geom::Path(*doc_rect)), tr);
500 }
501 if (Inkscape::Preferences::get()->getBool("/tools/pages/move_objects", true)) {
502 for (auto &item : doc->getPageManager().getOverlappingItems(_desktop, page)) {
503 if (item && !item->isLocked()) {
504 addDragShape(item, tr);
505 }
506 }
507 }
508}
509
513void PagesTool::addDragShape(SPItem *item, Geom::Affine tr)
514{
515 if (auto shape = item_to_outline(item)) {
516 addDragShape(*shape * item->i2dt_affine(), tr);
517 }
518}
519
523void PagesTool::addDragShape(Geom::PathVector &&pth, Geom::Affine tr)
524{
525 auto shape = new CanvasItemBpath(drag_group.get(), pth * tr, false);
526 shape->set_stroke(0x00ff007f);
527 shape->set_fill(0x00000000, SP_WIND_RULE_EVENODD);
528 drag_shapes.push_back(shape);
529}
530
534void PagesTool::clearDragShapes()
535{
536 for (auto &shape : drag_shapes) {
537 shape->unlink();
538 }
539 drag_shapes.clear();
540}
541
545SPPage *PagesTool::pageUnder(Geom::Point pt, bool retain_selected)
546{
547 auto &pm = _desktop->getDocument()->getPageManager();
548
549 // If the point is still on the selected, favour that one.
550 if (auto selected = pm.getSelected()) {
551 if (retain_selected && selected->getSensitiveRect().contains(pt)) {
552 return selected;
553 }
554 }
555
556 return pm.findPageAt(pt);
557}
558
563bool PagesTool::viewboxUnder(Geom::Point pt)
564{
565 if (auto document = _desktop->getDocument()) {
566 auto rect = document->preferredBounds();
567 rect->expandBy(-0.1); // see sp-page getSensitiveRect
568 return !document->getPageManager().hasPages() && rect.contains(pt);
569 }
570 return true;
571}
572
573void PagesTool::connectDocument(SPDocument *doc)
574{
575 _selector_changed_connection.disconnect();
576 if (doc) {
577 auto &page_manager = doc->getPageManager();
578 _selector_changed_connection =
579 page_manager.connectPageSelected([doc, this](SPPage *page) {
580 selectionChanged(doc, page);
581 });
582 selectionChanged(doc, page_manager.getSelected());
583 } else {
584 selectionChanged(doc, nullptr);
585 }
586}
587
588void PagesTool::selectionChanged(SPDocument *doc, SPPage *page)
589{
590 if (_page_modified_connection) {
591 _page_modified_connection.disconnect();
592 for (auto knot : resize_knots) {
593 knot->hide();
594 }
595 for (auto knot : margin_knots) {
596 knot->hide();
597 }
598 }
599
600 // Loop existing pages because highlight_item is unsafe.
601 // Use desktop's document instead of doc, which may be nullptr.
602 for (auto &possible : _desktop->getDocument()->getPageManager().getPages()) {
603 if (highlight_item == possible) {
604 highlight_item->setSelected(false);
605 }
606 }
607 highlight_item = page;
608 if (doc) {
609 if (page) {
610 _page_modified_connection = page->connectModified(sigc::mem_fun(*this, &PagesTool::pageModified));
611 page->setSelected(true);
612 pageModified(page, 0);
613 } else {
614 // This is for viewBox editng directly. A special extra feature
615 _page_modified_connection = doc->connectModified([doc, this](guint){
616 resizeKnotSet(*(doc->preferredBounds()));
617 marginKnotSet(*(doc->preferredBounds()));
618 });
619 resizeKnotSet(*(doc->preferredBounds()));
620 marginKnotSet(*(doc->preferredBounds()));
621 }
622 }
623}
624
625void PagesTool::pageModified(SPObject *object, guint /*flags*/)
626{
627 if (auto page = cast<SPPage>(object)) {
628 resizeKnotSet(page->getDesktopRect());
629 marginKnotSet(page->getDocumentMargin());
630 }
631}
632
633} // namespace Inkscape::UI::Tools
634
635/*
636 Local Variables:
637 mode:c++
638 c-file-style:"stroustrup"
639 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
640 indent-tabs-mode:nil
641 fill-column:99
642 End:
643*/
644// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
double scale
Definition aa.cpp:228
Point origin
Definition aa.cpp:227
uint64_t page
Definition canvas.cpp:171
Inkscape canvas widget.
3x3 matrix representing an affine transformation.
Definition affine.h:70
void setMin(CPoint const &p)
Set the upper left point of the rectangle.
void setMax(CPoint const &p)
Set the lower right point of the rectangle.
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
Sequence of subpaths.
Definition pathvector.h:122
Sequence of contiguous curves, aka spline.
Definition path.h:353
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Translation by a vector.
Definition transforms.h:115
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
static void maybeDone(SPDocument *document, const gchar *keyconst, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
A class to represent ways functionality is driven by shift modifiers.
Definition modifiers.h:101
bool active(int button_state) const
Test if this modifier is currently active.
static Modifier * get(Type index)
A function to turn an enum index into a modifier object.
Definition modifiers.h:213
void clear()
Unselects all selected objects.
sigc::connection connectPageSelected(const sigc::slot< void(SPPage *)> &slot)
void enablePages()
Enables multi page support by turning the document viewBox into the first page.
SPPage * getSelected() const
bool hasPages() const
Preference storage class.
Definition preferences.h:66
static Preferences * get()
Access the singleton Preferences object.
int getIntLimited(Glib::ustring const &pref_path, int def=0, int min=INT_MIN, int max=INT_MAX)
Retrieve a limited integer.
SnappedPoint best_snapped_point
Geom::Point getTranslationSnapped()
SelectionState getState()
Returns the current selection state including selected objects and nodes.
Class to store data for points which are snap candidates, either as a source or as a target.
void addOrigin(Geom::Point pt)
void clearTargetMask(int enabled=-1)
Clear the target mask, this should be done in a four step process.
void setTargetMask(Inkscape::SnapTargetType const target, int enabled=1)
Set a target mask, which will turn off all other targets except the masked ones.
Class describing the result of an attempt to snap.
Geom::Point getPoint() const
bool marginKnotMoved(SPKnot *knot, Geom::Point *point, guint state)
void resizeKnotFinished(SPKnot *knot, guint state)
void resizeKnotSet(Geom::Rect rect)
bool root_handler(CanvasEvent const &event) override
Geom::Point getSnappedResizePoint(Geom::Point point, guint state, Geom::Point origin, SPObject *target=nullptr)
Resize snapping allows knot and tool point snapping consistency.
CanvasItemPtr< CanvasItemRect > visual_box
Definition pages-tool.h:93
bool viewboxUnder(Geom::Point pt)
Returns true if the document contains no pages AND the point is within the document viewbox.
std::optional< Geom::Rect > on_screen_rect
On-screen rectangle, in desktop coordinates.
Definition pages-tool.h:92
PagesTool(SPDesktop *desktop)
void marginKnotSet(Geom::Rect margin_rect)
static Geom::Point middleOfSide(int side, const Geom::Rect &rect)
void resizeKnotMoved(SPKnot *knot, Geom::Point const &ppointer, guint state)
void menu_popup(CanvasEvent const &event, SPObject *obj=nullptr) override
Create popup menu and tell Gtk to show it.
std::unique_ptr< Inkscape::SelectionState > _selection_state
Definition pages-tool.h:97
std::vector< Inkscape::CanvasItemBpath * > drag_shapes
Definition pages-tool.h:95
std::vector< SPKnot * > margin_knots
Definition pages-tool.h:88
sigc::connection _zoom_connection
Definition pages-tool.h:79
void connectDocument(SPDocument *doc)
std::vector< SPKnot * > resize_knots
Definition pages-tool.h:87
sigc::connection _doc_replaced_connection
Definition pages-tool.h:78
CanvasItemPtr< CanvasItemGroup > drag_group
Definition pages-tool.h:94
void marginKnotFinished(SPKnot *knot, guint state)
Base class for Event processors.
Definition tool-base.h:107
Glib::RefPtr< Gdk::Cursor > get_cursor(Gtk::Widget &widget, std::string const &filename) const
Returns the Gdk Cursor for the given filename.
void ungrabCanvasEvents()
Ungrab events from the Canvas Catchall.
void set_cursor(std::string filename)
Sets the current cursor to the given filename.
virtual bool root_handler(CanvasEvent const &event)
To do: update description of desktop.
Definition desktop.h:149
Inkscape::UI::Widget::Canvas * getCanvas() const
Definition desktop.h:190
Inkscape::CanvasItemGroup * getCanvasControls() const
Definition desktop.h:196
sigc::connection connectDocumentReplaced(F &&slot)
Definition desktop.h:257
SPDocument * getDocument() const
Definition desktop.h:189
Inkscape::CanvasItemGroup * getCanvasTemp() const
Definition desktop.h:202
SPNamedView * getNamedView() const
Definition desktop.h:191
Inkscape::Selection * getSelection() const
Definition desktop.h:188
sigc::signal< void(double)> signal_zoom_changed
Emitted when the zoom factor changes (not emitted when scrolling).
Definition desktop.h:251
Geom::Affine const & doc2dt() const
Definition desktop.cpp:1337
Typed SVG document implementation.
Definition document.h:103
Geom::OptRect preferredBounds() const
Definition document.cpp:978
sigc::connection connectModified(ModifiedSignal::slot_type slot)
Inkscape::PageManager & getPageManager()
Definition document.h:164
Base class for visual SVG elements.
Definition sp-item.h:109
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
Definition sp-item.cpp:1828
bool isLocked() const
Definition sp-item.cpp:218
Desktop-bound visual control object.
Definition knot.h:51
Geom::Point drag_origin
Origin of drag.
Definition knot.h:71
void setPosition(Geom::Point const &p, unsigned int state)
Move knot to new position and emits "moved" signal.
Definition knot.cpp:342
Geom::Point position() const
Returns position of knot.
Definition knot.h:160
SnapManager snap_manager
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
Geom::Rect getDesktopRect() const
Get the rectangle of the page, in desktop units.
Definition sp-page.cpp:132
static void moveItems(Geom::Affine translate, std::vector< SPItem * > const &objects)
Move the given items by the given translation in document units.
Definition sp-page.cpp:561
Class to coordinate snapping operations.
Definition snap.h:80
void setup(SPDesktop const *desktop, bool snapindicator=true, SPObject const *item_to_ignore=nullptr, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Convenience shortcut when there is only one item to ignore.
Definition snap.cpp:663
SPNamedView const * getNamedView() const
Definition snap.h:371
void snapTransformed(std::vector< Inkscape::SnapCandidatePoint > const &points, Geom::Point const &pointer, Inkscape::PureTransform &transform)
Method for snapping sets of points while they are being transformed.
Definition snap.cpp:465
void unSetup()
Definition snap.h:147
Inkscape::SnapPreferences & snapprefs
Definition snap.h:342
Inkscape::SnappedPoint freeSnap(Inkscape::SnapCandidatePoint const &p, Geom::OptRect const &bbox_to_snap=Geom::OptRect(), bool to_path_only=false) const
Try to snap a point to grids, guides or objects.
Definition snap.cpp:143
Editable view implementation.
TODO: insert short description here.
@ SP_ANCHOR_CENTER
Definition enums.h:28
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Macro for icon names used in Inkscape.
SPItem * item
@ SP_KNOT_STATE_DRAGGING
Definition knot-enums.h:22
@ SP_KNOT_STATE_MOUSEOVER
Definition knot-enums.h:21
Declarations for SPKnot: Desktop-bound visual control object.
Angle distance(Angle const &a, Angle const &b)
Definition angle.h:163
Point middle_point(LineSegment const &_segment)
void inspect_event(E &&event, Fs... funcs)
Perform pattern-matching on a CanvasEvent.
@ SNAPSOURCE_UNDEFINED
Definition snap-enums.h:19
@ SNAPSOURCE_PAGE_CORNER
Definition snap-enums.h:31
@ SNAPSOURCE_PAGE_CENTER
Definition snap-enums.h:30
@ SNAPTARGET_UNDEFINED
Definition snap-enums.h:71
@ SNAPTARGET_ALIGNMENT_PAGE_EDGE_CENTER
Definition snap-enums.h:129
@ SNAPTARGET_GRID_INTERSECTION
Definition snap-enums.h:98
@ SNAPTARGET_ALIGNMENT_CATEGORY
Definition snap-enums.h:125
@ SNAPTARGET_PAGE_EDGE_CENTER
Definition snap-enums.h:106
@ SNAPTARGET_GUIDE
Definition snap-enums.h:100
@ SNAPTARGET_PAGE_EDGE_CORNER
Definition snap-enums.h:107
@ SNAPTARGET_GUIDE_INTERSECTION
Definition snap-enums.h:101
@ SNAPTARGET_ALIGNMENT_PAGE_EDGE_CORNER
Definition snap-enums.h:130
@ CANVAS_ITEM_CTRL_TYPE_MARGIN
@ CANVAS_ITEM_CTRL_TYPE_SIZER
void getBBoxPoints(Geom::OptRect const bbox, std::vector< SnapCandidatePoint > *points, bool const isTarget, bool const corners, bool const edges, bool const midpoint)
Default version of the getBBoxPoints with default corner source types.
static auto INDEX_OF(Tv const &v, Tk const &k)
Geom::PathVector * item_to_outline(SPItem const *item, bool exclude_markers)
Returns a pathvector that is the outline of the stroked item, with markers.
Two related object to path operations:
Provides a class that shows a temporary indicator on the canvas of where the snap was,...
SPPage – a page object.
A mouse button (left/right/middle) is pressed.
Abstract base class for events.
unsigned modifiers
The modifiers mask immediately before the event.
Movement of the mouse pointer.
@ SP_WIND_RULE_EVENODD
Definition style-enums.h:26
int delta
int index
SPDesktop * desktop