22#include <gdk/gdkkeysyms.h>
23#include <gdkmm/device.h>
24#include <gdkmm/display.h>
25#include <gdkmm/seat.h>
26#include <gtkmm/eventcontrollerkey.h>
27#include <gtkmm/window.h>
28#include <glibmm/i18n.h>
97 static_assert(std::is_final_v<MotionEvent>);
98 _event = std::make_unique<MotionEvent>(event);
99 _event->time = GDK_CURRENT_TIME;
104 , _cursor_filename(
"none")
105 , _cursor_default(
std::move(cursor_filename))
106 , _uses_snap(uses_snap)
108 , _acc_undo{
"doc.undo"}
109 , _acc_redo{
"doc.redo"}
110 , _acc_quick_preview{
"tool.all.quick-preview"}
111 , _acc_quick_zoom{
"tool.all.quick-zoom"}
112 , _acc_quick_pan{
"tool.all.quick-pan"}
141 if (entry_name ==
"changelayer") {
143 }
else if (entry_name ==
"changepage") {
202 if (
auto window =
dynamic_cast<Gtk::Window *
>(
_desktop->
getCanvas()->get_root())) {
203 window->set_cursor(cursor ? cursor :
_cursor);
290 double nudge = prefs->getDoubleLimited(
"/options/nudgedistance/value", 2, 0, 1000,
"px");
294 bool const rotated = prefs->getBool(
"/options/moverotated/value",
true);
302 if (knotholder && knotholder->knot_selected()) {
310 for (
auto &_shape_editor : nt->_shape_editors) {
314 if (knotholder && knotholder->knot_selected()) {
333 static unsigned int panning_cursor = 0;
334 static unsigned int zoom_rb = 0;
340 tolerance = prefs->getIntLimited(
"/options/dragtolerance/value", 0, 0, 100);
341 bool allow_panning = prefs->getBool(
"/options/spacebarpans/value");
354 if (event.num_press == 2) {
356 panning = PANNING_NONE;
357 ungrabCanvasEvents();
360 }
else if (event.num_press == 1) {
362 xyp = event.pos.floor();
363 within_tolerance = true;
365 button_w = event.pos;
367 switch (event.button) {
371 if (is_space_panning()) {
374 discard_delayed_snap_event();
376 panning = PANNING_SPACE_BUTTON1;
378 grabCanvasEvents(EventType::KEY_RELEASE |
379 EventType::BUTTON_RELEASE |
387 if (event.modifiers & GDK_CONTROL_MASK && !_desktop->get_rotation_lock()) {
391 start_angle = current_angle = compute_angle(event.pos);
393 grabCanvasEvents(EventType::KEY_PRESS |
394 EventType::KEY_RELEASE |
395 EventType::BUTTON_RELEASE |
398 } else if (event.modifiers & GDK_SHIFT_MASK) {
403 discard_delayed_snap_event();
405 panning = PANNING_BUTTON2;
407 grabCanvasEvents(EventType::BUTTON_RELEASE | EventType::MOTION);
414 if (event.modifiers & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) {
417 discard_delayed_snap_event();
419 panning = PANNING_BUTTON3;
421 grabCanvasEvents(EventType::BUTTON_RELEASE | EventType::MOTION);
423 } else if (!are_buttons_1_and_3_on(event)) {
437 if (panning == 4 && !xyp.x() && !xyp.y()) {
439 xyp =
event.pos.floor();
440 button_w =
event.pos;
447 if ((panning == 2 && !(event.modifiers & GDK_BUTTON2_MASK)) ||
448 (panning == 1 && !(event.modifiers & GDK_BUTTON1_MASK)) ||
449 (panning == 3 && !(event.modifiers & GDK_BUTTON3_MASK)))
452 panning = PANNING_NONE;
453 ungrabCanvasEvents();
458 if (within_tolerance &&
Geom::LInfty(event.pos.floor() - xyp) < tolerance * 3) {
467 within_tolerance =
false;
477 if (panning_cursor == 0) {
479 auto window =
dynamic_cast<Gtk::Window *
>(_desktop->getCanvas()->get_root());
480 auto cursor = Gdk::Cursor::create(Glib::ustring(
"move"));
481 window->set_cursor(cursor);
484 auto const motion_w =
event.pos;
485 auto const moved_w = motion_w - button_w;
486 _desktop->scroll_relative(moved_w);
489 }
else if (zoom_rb) {
490 if (!checkDragMoved(event.pos)) {
495 auto const motion_w =
event.pos;
496 auto const motion_dt = _desktop->w2d(motion_w);
498 rubberband->move(motion_dt);
502 auto const motion_w = xyp;
503 auto const motion_dt = _desktop->w2d(motion_w);
505 rubberband->start(_desktop, motion_dt);
511 }
else if (rotating) {
512 auto angle = compute_angle(event.pos);
514 double constexpr rotation_snap = 15.0;
515 double delta_angle =
angle - start_angle;
516 if (event.modifiers & GDK_SHIFT_MASK &&
517 event.modifiers & GDK_CONTROL_MASK) {
519 }
else if (event.modifiers & GDK_SHIFT_MASK) {
520 delta_angle = std::round(delta_angle / rotation_snap) * rotation_snap;
521 }
else if (event.modifiers & GDK_CONTROL_MASK) {
523 }
else if (event.modifiers & GDK_ALT_MASK) {
526 delta_angle = std::floor(delta_angle);
528 angle = start_angle + delta_angle;
530 _desktop->rotate_relative_keep_point(_desktop->w2d(
Geom::Rect(_desktop->getCanvas()->get_area_world()).
midpoint()),
531 Geom::rad_from_deg(angle - current_angle));
532 current_angle =
angle;
537 [&] (ButtonReleaseEvent
const &event) {
538 bool middle_mouse_zoom = prefs->getBool(
"/options/middlemousezoom/value");
542 if (panning_cursor == 1) {
544 dynamic_cast<Gtk::Window &
>(*_desktop->getCanvas()->get_root()).set_cursor(_cursor);
547 if (event.button == 2 && rotating) {
549 ungrabCanvasEvents();
552 if (middle_mouse_zoom && within_tolerance && (panning || zoom_rb)) {
556 panning = PANNING_NONE;
557 ungrabCanvasEvents();
560 auto const event_w =
event.pos;
561 auto const event_dt = _desktop->w2d(event_w);
563 double const zoom_inc = prefs->getDoubleLimited(
"/options/zoomincrement/value", M_SQRT2, 1.01, 10);
565 _desktop->zoom_relative(event_dt, (event.modifiers & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc);
567 }
else if (panning == event.button) {
568 panning = PANNING_NONE;
569 ungrabCanvasEvents();
575 auto const motion_w =
event.pos;
576 auto const moved_w = motion_w - button_w;
578 _desktop->scroll_relative(moved_w);
580 }
else if (zoom_rb == event.button) {
586 if (b && !within_tolerance) {
587 _desktop->set_display_area(*b, 10);
594 [&] (KeyPressEvent
const &event) {
595 double const acceleration = prefs->getDoubleLimited(
"/options/scrollingacceleration/value", 0, 0, 6);
596 int const key_scroll = prefs->getIntLimited(
"/options/keyscroll/value", 10, 0, 1000);
598 if (_acc_quick_preview.isTriggeredBy(event)) {
599 _desktop->quick_preview(
true);
602 if (_acc_quick_zoom.isTriggeredBy(event)) {
603 _desktop->zoom_quick(
true);
606 if (_acc_quick_pan.isTriggeredBy(event) && allow_panning) {
608 within_tolerance =
true;
609 panning = PANNING_SPACE;
622 _desktop->getDesktopWidget()->advanceTab(1);
628 case GDK_KEY_ISO_Left_Tab:
630 _desktop->getDesktopWidget()->advanceTab(-1);
645 app->destroyDesktop(_desktop,
true);
651 case GDK_KEY_KP_Left:
658 }
else if (!_keyboardMove(event,
Geom::Point(-1, 0))) {
672 }
else if (!_keyboardMove(event,
Geom::Point(0, -_desktop->yaxisdir()))) {
679 case GDK_KEY_KP_Right:
686 }
else if (!_keyboardMove(event,
Geom::Point(1, 0))) {
693 case GDK_KEY_KP_Down:
700 }
else if (!_keyboardMove(event,
Geom::Point(0, _desktop->yaxisdir()))) {
721 _desktop->rotate_grab_focus();
729 _desktop->zoom_grab_focus();
739 [&] (KeyReleaseEvent
const &event) {
741 if (is_space_panning()) {
742 message_context->clear();
746 panning = PANNING_NONE;
749 ungrabCanvasEvents();
752 if (panning_cursor == 1) {
754 dynamic_cast<Gtk::Window &
>(*_desktop->getCanvas()->get_root()).set_cursor(_cursor);
757 if (_acc_quick_preview.isTriggeredBy(event)) {
758 _desktop->quick_preview(
false);
761 if (_acc_quick_zoom.isTriggeredBy(event) && _desktop->quick_zoomed()) {
762 _desktop->zoom_quick(
false);
768 if (within_tolerance) {
784 [&] (ScrollEvent
const &event) {
786 auto get_scroll_inc = [&] {
return prefs->getIntLimited(
"/options/wheelscroll/value", 40, 0, 1000) * 2; };
792 if (action == Type::CANVAS_ROTATE) {
795 if (_desktop->get_rotation_lock()) {
799 double const delta_y =
event.delta.y();
805 if (event.unit == Gdk::ScrollUnit::WHEEL) {
806 double rotate_inc = prefs->getDoubleLimited(
"/options/rotateincrement/value", 15, 1, 90,
"°");
807 rotate_inc = Geom::rad_from_deg(rotate_inc);
808 angle = delta_y * rotate_inc;
810 angle = delta_y * (Geom::rad_from_deg(15) / 10.0);
811 angle = std::clamp(angle, -1.0, 1.0);
814 _desktop->rotate_relative_keep_point(_desktop->point(), -angle);
817 }
else if (action == Type::CANVAS_PAN_X) {
820 double delta_y =
event.delta.y();
825 if (event.unit == Gdk::ScrollUnit::WHEEL) {
826 delta_y *= get_scroll_inc();
831 _desktop->scroll_relative({-delta_y, 0});
834 }
else if (action == Type::CANVAS_ZOOM) {
837 double const delta_y =
event.delta.y();
843 if (event.unit == Gdk::ScrollUnit::WHEEL) {
844 double const zoom_inc = prefs->getDoubleLimited(
"/options/zoomincrement/value", M_SQRT2, 1.01, 10);
845 scale = std::pow(zoom_inc, delta_y);
847 scale = delta_y / 10;
848 scale = std::clamp(scale, -1.0, 1.0);
849 scale = std::pow(M_SQRT2, scale);
852 _desktop->zoom_relative(_desktop->point(), 1.0 / scale);
855 }
else if (action == Type::CANVAS_PAN_Y) {
858 auto delta =
event.delta;
863 if (event.unit == Gdk::ScrollUnit::WHEEL) {
864 delta *= get_scroll_inc();
869 _desktop->scroll_relative(-
delta);
873 g_warning(
"unhandled scroll event with scroll.state=0x%x", event.modifiers);
877 [&] (CanvasEvent
const &event) {}
890 if (event.num_press != 1) {
893 switch (event.button) {
908 switch (event.button) {
923 _button1on =
event.
modifiers & (unsigned)Gdk::ModifierType::BUTTON1_MASK;
924 _button2on =
event.modifiers & (unsigned)Gdk::ModifierType::BUTTON2_MASK;
925 _button3on =
event.modifiers & (unsigned)Gdk::ModifierType::BUTTON3_MASK;
931bool ToolBase::are_buttons_1_and_3_on()
const
933 return _button1on && _button3on;
938 set_on_buttons(event);
939 return are_buttons_1_and_3_on();
956 if (!are_buttons_1_and_3_on(event) && button.button == 3 &&
957 !(button.modifiers & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
960 }
else if (button.button == 1 && shape_editor && shape_editor->has_knotholder()) {
962 auto &knotholder = shape_editor->knotholder;
963 auto point = button.pos;
964 if (_desktop->getItemAtPoint(point,
true) == knotholder->getItem()) {
965 return knotholder->set_item_clickpos(_desktop->w2d(point) * _desktop->dt2doc());
975bool ToolBase::sp_event_context_knot_mouseover()
const
978 return shape_editor->knot_mouseover();
987void ToolBase::enableSelectionCue(
bool enable)
1002void ToolBase::enableGrDrag(
bool enable)
1006 _grdrag =
new GrDrag(_desktop);
1019bool ToolBase::deleteSelectedDrag(
bool just_one)
1021 if (_grdrag && !_grdrag->selected.empty()) {
1022 _grdrag->deleteSelected(just_one);
1031bool ToolBase::hasGradientDrag()
const
1033 return _grdrag && _grdrag->isNonEmpty();
1041 _desktop->getCanvasCatchall()->grab(mask);
1047void ToolBase::ungrabCanvasEvents()
1049 _desktop->getSnapIndicator()->remove_snaptarget();
1050 _desktop->getCanvasCatchall()->ungrab();
1062void ToolBase::set_high_motion_precision(
bool high_precision)
1070 saveDragOrigin(ev.
pos);
1077 within_tolerance =
true;
1086 if (within_tolerance) {
1092 within_tolerance =
false;
1103 if (!tool || !
key)
return;
1116 snap_delay_handler(
item,
nullptr, event,
origin);
1120 process_delayed_snap_event();
1125 _desktop->getNamedView()->snap_manager.snapprefs.setSnapPostponedGlobally(
false);
1137 dump_event(event,
"ToolBase::start_root_handler");
1141 return tool_root_handler(event);
1144 _filterEventForSnapping(
nullptr, event, DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER);
1146 return tool_root_handler(event);
1155 dump_event(event,
"ToolBase::tool_root_handler");
1159 set_on_buttons(event);
1166 return ToolBase::root_handler(event);
1168 return root_handler(event);
1178 return virtual_item_handler(
item, event);
1181 _filterEventForSnapping(
item, event, DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER);
1183 return virtual_item_handler(
item, event);
1191 set_on_buttons(event);
1195 ret = ToolBase::item_handler(
item, event);
1197 ret = item_handler(
item, event);
1201 ret = tool_root_handler(event);
1218 auto const button_w =
static_cast<MotionEvent const &
>(event).pos;
1219 auto const button_dt =
desktop->
w2d(button_w);
1231 obj = _desktop->getSelection()->items().front();
1240 auto const popup = [&] (std::optional<Geom::Point>
const &pos) {
1242 auto point_win = _desktop->point() * _desktop->d2w();
1243 auto items_under_cursor = _desktop->getItemsAtPoints({point_win},
true,
false, 0,
false);
1244 auto menu = Gtk::make_managed<ContextMenu>(_desktop, obj, items_under_cursor);
1245 _desktop->getDesktopWidget()->get_canvas_grid()->setPopover(menu);
1251 popup(event.orig_pos);
1254 popup(event.orig_pos);
1264 KeyEvent const &event,
char const *ctrl_tip,
char const *shift_tip,
1265 char const *alt_tip)
1269 bool ctrl = ctrl_tip && (
mod_ctrl(event) || keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R);
1270 bool shift = shift_tip && (
mod_shift(event) || keyval == GDK_KEY_Shift_L || keyval == GDK_KEY_Shift_R);
1271 bool alt = alt_tip && (
mod_alt(event) || keyval == GDK_KEY_Alt_L || keyval == GDK_KEY_Alt_R
1272 || keyval == GDK_KEY_Meta_L || keyval == GDK_KEY_Meta_R);
1274 char *tip = g_strdup_printf(
"%s%s%s%s%s", ctrl ? ctrl_tip :
"",
1275 ctrl && (
shift || alt) ?
"; " :
"",
1276 shift ? shift_tip :
"",
1277 (ctrl ||
shift) && alt ?
"; " :
"",
1278 alt ? alt_tip :
"");
1280 if (std::strlen(tip) > 0) {
1299 if (gdk_display_map_keyval(gdk_display_get_default(), GDK_KEY_a, &keys, &n_keys)) {
1300 for (
int i = 0; i < n_keys; i++) {
1317 auto const keyboard = Gdk::Display::get_default()->get_default_seat()->get_keyboard();
1324 GdkModifierType
const event_state,
unsigned const event_group,
1325 unsigned *consumed_modifiers)
1328 GdkModifierType modifiers;
1333 group = event_group;
1335 gdk_display_translate_key(gdk_display_get_default(),
1343 if (consumed_modifiers) {
1344 *consumed_modifiers = modifiers;
1348 if (keyval != event_keyval) {
1349 std::cerr <<
"get_latin_keyval: OH OH OH keyval did change! "
1350 <<
" keyval: " << keyval <<
" (" << (char)keyval <<
")"
1351 <<
" event_keyval: " << event_keyval <<
"(" << (
char)event_keyval <<
")" << std::endl;
1365 unsigned const keyval,
unsigned const keycode, GdkModifierType
const state,
1366 unsigned *consumed_modifiers )
1368 auto const group = gtk_event_controller_key_get_group(
const_cast<GtkEventControllerKey *
>(controller));
1373 unsigned keyval,
unsigned keycode, Gdk::ModifierType state,
1374 unsigned *consumed_modifiers )
1376 auto const group = controller.get_group();
1377 return get_latin_keyval_impl(keyval, keycode,
static_cast<GdkModifierType
>(state), group, consumed_modifiers);
1383 static_cast<GdkModifierType
>(event.
modifiers),
1384 event.
group, consumed_modifiers);
1394 bool select_under,
bool into_groups)
1400 std::vector<SPItem *> vec(tmp.begin(), tmp.end());
1420 std::vector<SPItem*> temp;
1421 temp.push_back(
item);
1423 return item_at_point;
1443 static uint32_t prev_time;
1444 static std::optional<Geom::Point> prev_pos;
1446 if (!_uses_snap || _dse_callback_in_process) {
1451 bool const c1 =
event.modifiers & GDK_BUTTON2_MASK;
1452 bool const c2 =
event.modifiers & GDK_BUTTON3_MASK;
1458 bool const c4 = is_panning();
1460 if (c1 || c2 || c3 || c4) {
1464 discard_delayed_snap_event();
1465 }
else if (getDesktop() && getDesktop()->getNamedView()->snap_manager.snapprefs.getSnapEnabledGlobally()) {
1469 getDesktop()->getNamedView()->snap_manager.snapprefs.setSnapPostponedGlobally(
true);
1471 auto event_pos =
event.pos;
1472 uint32_t event_t =
event.time;
1475 auto dist =
Geom::L2(event_pos - *prev_pos);
1476 uint32_t delta_t = event_t - prev_time;
1477 double speed = delta_t > 0 ? dist / delta_t : 1000;
1485 _dse.emplace(
this,
item, item2, event,
origin);
1486 _schedule_delayed_snap_event();
1497 _dse.emplace(
this,
item, item2, event,
origin);
1498 _schedule_delayed_snap_event();
1504 _dse.emplace(
this,
item, item2, event,
origin);
1505 _schedule_delayed_snap_event();
1508 prev_pos = event_pos;
1509 prev_time = event_t;
1517void ToolBase::process_delayed_snap_event()
1521 _dse_timeout_conn.disconnect();
1529 auto dt = getDesktop();
1535 _dse_callback_in_process =
true;
1536 dt->getNamedView()->snap_manager.snapprefs.setSnapPostponedGlobally(
false);
1540 switch (_dse->getOrigin()) {
1541 case DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER:
1542 tool_root_handler(_dse->getEvent());
1544 case DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER: {
1545 auto item =
reinterpret_cast<SPItem*
>(_dse->getItem());
1547 virtual_item_handler(
item, _dse->getEvent());
1551 case DelayedSnapEvent::KNOT_HANDLER: {
1552 auto knot =
reinterpret_cast<SPKnot*
>(_dse->getItem2());
1555 bool was_grabbed = knot->is_grabbed();
1557 knot->handler_request_position(_dse->getEvent());
1562 case DelayedSnapEvent::CONTROL_POINT_HANDLER: {
1564 auto point =
reinterpret_cast<ControlPoint*
>(_dse->getItem2());
1566 if (point->position().isFinite() && dt == point->_desktop) {
1573 g_warning(
"encountered non-finite point when evaluating snapping callback");
1578 case DelayedSnapEvent::GUIDE_HANDLER: {
1580 auto guide =
reinterpret_cast<SPGuide*
> (_dse->getItem2());
1581 if (guideline && guide) {
1586 case DelayedSnapEvent::GUIDE_HRULER:
1587 case DelayedSnapEvent::GUIDE_VRULER: {
1589 bool horiz = _dse->getOrigin() == DelayedSnapEvent::GUIDE_HRULER;
1590 canvas_grid->
rulerMotion(_dse->getEvent(), horiz);
1594 g_warning(
"Origin of snap-delay event has not been defined!");
1598 _dse_callback_in_process =
false;
1605void ToolBase::discard_delayed_snap_event()
1607 _desktop->getNamedView()->snap_manager.snapprefs.setSnapPostponedGlobally(
false);
1616void ToolBase::_schedule_delayed_snap_event()
1620 double value = prefs->
getDoubleLimited(
"/options/snapdelay/value", 0, 0, 1000);
1628 _dse_timeout_conn = Glib::signal_timeout().connect([
this] {
1629 process_delayed_snap_event();
1634void ToolBase::set_last_active_tool(Glib::ustring last_tool) {
1635 _last_active_tool = std::move(last_tool);
1638const Glib::ustring& ToolBase::get_last_active_tool()
const {
1639 return _last_active_tool;
Rewrite of code originally in desktop-widget.cpp.
Affine inverse() const
Compute the inverse matrix.
CPoint midpoint() const
Get the point in the geometric center of the rectangle.
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
IntPoint floor() const
Round coordinates downwards.
Axis aligned, non-empty rectangle.
This is the root class of the gradient dragging machinery.
static InkscapeApplication * instance()
Singleton instance.
A mask representing a subset of EventTypes.
SPGroup * currentLayer() const
Returns current top layer.
A convenience class for working with MessageStacks.
void flash(MessageType type, char const *message)
pushes a message onto the stack for a brief period of time without disturbing our "current" message
static Type which(Trigger trigger, int button_state)
Given a Trigger, find which modifier is active (category lookup)
SPItemRange items()
Returns a range of selected SPItems.
Data type representing a typeless value of a preference.
Glib::ustring getEntryName() const
Get the last component of the preference's path.
bool getBool(bool def=false) const
Interpret the preference as a Boolean value.
static std::unique_ptr< PreferencesObserver > create(Glib::ustring path, std::function< void(const Preferences::Entry &new_value)> callback)
Preference storage class.
static Preferences * get()
Access the singleton Preferences object.
Entry const getEntry(Glib::ustring const &pref_path)
Retrieve a preference entry without specifying its type.
double getDoubleLimited(Glib::ustring const &pref_path, double def=0.0, double min=DBL_MIN, double max=DBL_MAX, Glib::ustring const &unit="")
Retrieve a limited floating point value.
static Rubberband * get(SPDesktop *desktop)
Geom::OptRect getRectangle() const
void setChangePage(bool option)
void setChangeLayer(bool option)
Decide if the selection changing should change the layer and page selection too.
bool invoke_action(Gtk::AccelKey const &shortcut)
Trigger action from a shortcut.
static Shortcuts & getInstance(bool init=true)
Draggable point, the workhorse of on-canvas editing.
static Glib::ustring virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event)
bool has_knotholder() const
std::unique_ptr< KnotHolder > knotholder
To do: update description of desktop.
Inkscape::UI::Widget::Canvas * getCanvas() const
double current_zoom() const
Inkscape::MessageStack * messageStack() const
SPItem * getItemAtPoint(Geom::Point const &p, bool into_groups, SPItem *upto=nullptr) const
SPItem * getItemFromListAtPointBottom(std::vector< SPItem * > const &list, Geom::Point const &p) const
Inkscape::Selection * getSelection() const
Geom::Rotate const & current_rotation() const
Inkscape::UI::Tools::ToolBase * getTool() const
void set_coordinate_status(Geom::Point const &p)
Sets the coordinate status to a given point.
Inkscape::LayerManager & layerManager()
Geom::Affine const & w2d() const
Transformation from window to desktop coordinates (zoom/rotate).
Base class for visual SVG elements.
Desktop-bound visual control object.
SPObject is an abstract base class of all of the document nodes at the SVG document level.
bool sp_dt_guide_event(Inkscape::CanvasEvent const &event, Inkscape::CanvasItemGuideLine *guide_item, SPGuide *guide)
std::optional< Color > sp_desktop_get_color_tool(SPDesktop *desktop, Glib::ustring const &tool, bool is_fill)
double sp_desktop_get_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool, bool is_fill)
Editable view implementation.
static Glib::ustring const prefs_path
void check_if_knot_deleted(void *knot)
TODO: insert short description here.
Declarations for SPKnot: Desktop-bound visual control object.
void shift(T &a, T &b, T const &c)
Interface for locally managing a current status message.
double angle(std::vector< Point > const &A)
double atan2(Point const &p)
SBasis L2(D2< SBasis > const &a, unsigned k)
Coord LInfty(Point const &p)
Type
This anonymous enum is used to provide a list of the Shifts.
static void popup_at(Gtk::Popover &popover, Gtk::Widget &widget, double const x_offset, double const y_offset, int width, int height)
Helper class to stream background task notifications as a series of messages.
bool mod_alt(unsigned modifiers)
void inspect_event(E &&event, Fs... funcs)
Perform pattern-matching on a CanvasEvent.
Glib::RefPtr< Gdk::Cursor > load_svg_cursor(Gtk::Widget &widget, std::string const &file_name, std::optional< Colors::Color > maybe_fill, std::optional< Colors::Color > maybe_stroke)
Loads an SVG cursor from the specified file name.
bool mod_ctrl_only(unsigned modifiers)
bool mod_ctrl(unsigned modifiers)
bool mod_shift_only(unsigned modifiers)
bool mod_shift(unsigned modifiers)
bool mod_alt_only(unsigned modifiers)
void dump_event(CanvasEvent const &event, char const *prefix, bool merge=true)
Print an event to stdout.
constexpr bool DEBUG_EVENTS
Whether event debug printing is enabled.
static cairo_user_data_key_t key
void sp_selection_item_next(SPDesktop *desktop)
void sp_selection_item_prev(SPDesktop *desktop)
Inkscape::ShapeEditor This is a container class which contains a knotholder for shapes.
Provides a class that shows a temporary indicator on the canvas of where the snap was,...
Abstract base class for events.
unsigned modifiers
The modifiers mask immediately before the event.
virtual EventType type() const =0
Return the dynamic type of the CanvasEvent.
uint32_t keyval
The key that was pressed/released. (Matches gdkkeysyms.h.)
int group
The keyboard group.
uint16_t keycode
The raw code of the key that was pressed/released.
Movement of the mouse pointer.