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);