diff --git a/share/keys/inkscape.xml b/share/keys/inkscape.xml
index 1fbd0426b8e8ec12633ab0925e1581d4eb943911..f326a14c3fbb1a0fd15fb9098ce34a011d246c36 100644
--- a/share/keys/inkscape.xml
+++ b/share/keys/inkscape.xml
@@ -31,6 +31,9 @@ override) the bindings in the main default.xml.
+
+
+
diff --git a/src/ui/modifiers.cpp b/src/ui/modifiers.cpp
index 277b0e3402499c9cad921670065e78d15c547cc2..332bfdb0d59bc878c3f449c3d7dfde7a0c0ea45f 100644
--- a/src/ui/modifiers.cpp
+++ b/src/ui/modifiers.cpp
@@ -32,6 +32,9 @@ ModifierIdToTypeMap const &modifier_type_from_id()
{"canvas-pan-x", Type::CANVAS_PAN_X},
{"canvas-zoom", Type::CANVAS_ZOOM},
{"canvas-rotate", Type::CANVAS_ROTATE},
+ {"canvas-box-zoom", Type::CANVAS_BOX_ZOOM},
+ {"canvas-zoom-tablet", Type::CANVAS_ZOOM_TABLET},
+ {"canvas-rotate-tablet", Type::CANVAS_ROTATE_TABLET},
{"select-add-to", Type::SELECT_ADD_TO},
{"select-in-groups", Type::SELECT_IN_GROUPS},
{"select-touch-path", Type::SELECT_TOUCH_PATH},
@@ -88,6 +91,9 @@ Modifier::Container &Modifier::_modifiers()
make_modifier("canvas-pan-x", _("Horizontal pan"), _("Pan/Scroll left and right"), SHIFT, CANVAS, SCROLL),
make_modifier("canvas-zoom", _("Canvas zoom"), _("Zoom in and out with scroll wheel"), CTRL, CANVAS, SCROLL),
make_modifier("canvas-rotate", _("Canvas rotate"), _("Rotate the canvas with scroll wheel"), SHIFT | CTRL, CANVAS, SCROLL),
+ make_modifier("canvas-box-zoom", _("Canvas box zoom"), _("Middle-click + drag to zoom into selection"), SHIFT, CANVAS, DRAG),
+ make_modifier("canvas-zoom-tablet", _("Canvas zoom tablet"), _("Rotate the canvas with middle mouse button"), SHIFT, CANVAS, DRAG),
+ make_modifier("canvas-rotate-tablet", _("Canvas rotate tablet"), _("Rotate the canvas with middle mouse button"), CTRL, CANVAS, DRAG),
// Select tool modifiers (minus transforms)
make_modifier("select-add-to", _("Add to selection"), _("Add items to existing selection"), SHIFT, SELECT, CLICK),
diff --git a/src/ui/modifiers.h b/src/ui/modifiers.h
index 5410ed4c1d4528c05b1ab73a80583ee5ce0a7361..2e09f30bd4d7fabaf63245d4a87aa98764e88a1e 100644
--- a/src/ui/modifiers.h
+++ b/src/ui/modifiers.h
@@ -61,7 +61,10 @@ enum class Type {
CANVAS_PAN_X, // Pan left and right {SHIFT+SCROLL}
CANVAS_ZOOM, // Zoom in and out {CTRL+SCROLL}
CANVAS_ROTATE, // Rotate CW and CCW {CTRL+SHIFT+SCROLL}
-
+ CANVAS_BOX_ZOOM, // Zoom into selected area {MIDDLEMOUSE + DRAG}
+ CANVAS_ZOOM_TABLET, // Zoom in and out with middle mouse {CTRL + MIDDLEMOUSE + DRAG}
+ CANVAS_ROTATE_TABLET, // Rotate CW and CCW with middle mouse {CTRL + MIDDLEMOUSE + DRAG}
+
// Select tool (minus transform)
SELECT_ADD_TO, // Add selection {SHIFT+CLICK}
SELECT_IN_GROUPS, // Select within groups {CTRL+CLICK}
diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp
index 7c927aaba75426c8970e25d3400457f9f935ff36..28ef70a3fffb8504626f411c925730c7be00bb89 100644
--- a/src/ui/tools/tool-base.cpp
+++ b/src/ui/tools/tool-base.cpp
@@ -348,6 +348,24 @@ bool ToolBase::root_handler(CanvasEvent const &event)
return Geom::deg_from_rad(Geom::atan2(cursor - Geom::Point(_desktop->getCanvas()->get_dimensions()) / 2.0));
};
+ auto compute_zoom = [&](Geom::Point const &pt, Geom::Point const &rel) {
+ // Calculate zoom scaling based on vertical drag distance relative to start position.
+ auto start = rel * _desktop->getCanvas()->get_geom_affine().inverse() * _desktop->getCanvas()->get_affine() - _desktop->getCanvas()->get_pos();
+ auto current = pt * _desktop->getCanvas()->get_geom_affine().inverse() * _desktop->getCanvas()->get_affine() - _desktop->getCanvas()->get_pos();
+
+ double vertical_drag = start[Geom::Y] - current[Geom::Y];
+
+ // Make zoom sensitivity relative to window height, better for High Res displays
+ double const window_height = (double) _desktop->getCanvas()->get_height();
+ double scale = 5 * vertical_drag / window_height;
+
+ scale = std::clamp(scale, -3.0, 3.0);
+ scale = std::pow(M_SQRT2, scale);
+
+ return scale;
+ };
+
+
inspect_event(event,
[&] (ButtonPressEvent const &event) {
@@ -364,6 +382,10 @@ bool ToolBase::root_handler(CanvasEvent const &event)
button_w = event.pos;
+ using Modifiers::Type;
+ using Modifiers::Triggers;
+ auto const action = Modifiers::Modifier::which(Triggers::CANVAS | Triggers::DRAG, event.modifiers);
+
switch (event.button) {
case 1:
// TODO Does this make sense? Panning starts on passive mouse motion while space
@@ -384,8 +406,8 @@ bool ToolBase::root_handler(CanvasEvent const &event)
break;
case 2:
- if (event.modifiers & GDK_CONTROL_MASK && !_desktop->get_rotation_lock()) {
- // Canvas ctrl + middle-click to rotate
+ if (action == Type::CANVAS_ROTATE_TABLET && !_desktop->get_rotation_lock()) {
+ // Canvas modifier (default: ctrl) + middle-click to rotate
rotating = true;
start_angle = current_angle = compute_angle(event.pos);
@@ -395,7 +417,17 @@ bool ToolBase::root_handler(CanvasEvent const &event)
EventType::BUTTON_RELEASE |
EventType::MOTION);
- } else if (event.modifiers & GDK_SHIFT_MASK) {
+ } else if (action == Type::CANVAS_ZOOM_TABLET) {
+ // Start zooming
+ zooming = true;
+
+ start_scale = _desktop->current_zoom();
+ center = _desktop->w2d(xyp);
+ grabCanvasEvents(EventType::KEY_PRESS |
+ EventType::KEY_RELEASE |
+ EventType::BUTTON_RELEASE |
+ EventType::MOTION);
+ } else if (action == Type::CANVAS_BOX_ZOOM) {
zoom_rb = 2;
} else {
// When starting panning, make sure there are no snap events pending because these might disable the panning again
@@ -508,25 +540,12 @@ bool ToolBase::root_handler(CanvasEvent const &event)
if (zoom_rb == 2) {
gobble_motion_events(GDK_BUTTON2_MASK);
}
+ } else if (zooming) {
+ auto const current_scale = compute_zoom(event.pos, xyp) * start_scale;
+ _desktop->zoom_absolute(center, current_scale);
} else if (rotating) {
auto angle = compute_angle(event.pos);
- double constexpr rotation_snap = 15.0;
- double delta_angle = angle - start_angle;
- if (event.modifiers & GDK_SHIFT_MASK &&
- event.modifiers & GDK_CONTROL_MASK) {
- delta_angle = 0.0;
- } else if (event.modifiers & GDK_SHIFT_MASK) {
- delta_angle = std::round(delta_angle / rotation_snap) * rotation_snap;
- } else if (event.modifiers & GDK_CONTROL_MASK) {
- // ?
- } else if (event.modifiers & GDK_ALT_MASK) {
- // Decimal raw angle
- } else {
- delta_angle = std::floor(delta_angle);
- }
- angle = start_angle + delta_angle;
-
_desktop->rotate_relative_keep_point(_desktop->w2d(Geom::Rect(_desktop->getCanvas()->get_area_world()).midpoint()),
Geom::rad_from_deg(angle - current_angle));
current_angle = angle;
@@ -544,7 +563,10 @@ bool ToolBase::root_handler(CanvasEvent const &event)
dynamic_cast(*_desktop->getCanvas()->get_root()).set_cursor(_cursor);
}
- if (event.button == 2 && rotating) {
+ if (event.button == 2 && zooming) {
+ zooming = false;
+ ungrabCanvasEvents();
+ } else if (event.button == 2 && rotating) {
rotating = false;
ungrabCanvasEvents();
}
diff --git a/src/ui/tools/tool-base.h b/src/ui/tools/tool-base.h
index b79c414a6d9d1fe25bbad02e368bf4554010cd39..a0f2665682409736989da146c7fa5371685cd142 100644
--- a/src/ui/tools/tool-base.h
+++ b/src/ui/tools/tool-base.h
@@ -178,6 +178,10 @@ private:
bool rotating = false;
double start_angle, current_angle;
+ bool zooming = false;
+ double start_scale;
+ Geom::Point center;
+
public:
bool start_root_handler(CanvasEvent const &event);
bool tool_root_handler(CanvasEvent const &event);