mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-06 15:21:09 +00:00
Let the camera pan and orbit freely while sketching in the Design tab
Panning or orbiting with a right-drag no longer ends the polyline chain or drops the point already placed. Only a right-click that doesn't move does. In the Touchpad camera style, Alt+move and Shift+move now orbit and pan even while a draw tool is armed.
This commit is contained in:
@@ -262,9 +262,9 @@ and a band is not a "gesture" in the `CadLevel::Gesture` sense because nothing h
|
||||
|---|---|---|---|---|---|
|
||||
| `Move` | — | `update_hover` / `update_solid_hover` (**non-consuming**, returns false) | — | passthrough | hover only asks for a repaint, `:10022-10025` |
|
||||
| `LeftDown` | orbit may begin | latch press, **return false** | — | consume-or-orbit is the canvas's call | `:10058-10063`; consuming here killed orbit once already |
|
||||
| `LeftDrag` > 8 px | — | start + drive band, **consume** | — | no longer orbits in this canvas | middle-drag orbits, right-drag pans (`:10013-10016`) |
|
||||
| `LeftDrag` > 8 px | — | start + drive band, **consume**, when Shift is held or the left button has no camera action | — | otherwise the left button's drag action (Preferences > Control) | the band is Prepare's Shift+left-drag rectangle selection |
|
||||
| `LeftUp` | — | commit pick **or** resolve band | — | — | `:10035-10041` |
|
||||
| `MiddleDrag` / `RightDrag` | — | must not see it | — | orbit / pan | camera gestures never reach the FSM |
|
||||
| `MiddleDrag` / `RightDrag` | — | must not see it | — | the button's drag action (Preferences > Control) | camera gestures never reach the FSM; a right press reaches the tool only once its release shows it was a click |
|
||||
| `RightClick` | — | — | offer menu | — | `snaporca-xmh6` open: a right-click that only clears the sketch selection eats the offer |
|
||||
| `Esc` | — | — | `escape()` ladder | — | one route whatever holds focus (`:4228-4231`) |
|
||||
| `Del` / `Backspace` | — | `delete_selected_or_last_sketch_entity()` | char hook | — | `:4260` |
|
||||
|
||||
+10
-7
@@ -154,15 +154,18 @@ rather than to its end points: a press that wandered past the budget at any mome
|
||||
navigation, even if it comes back to where it started, which is what stops a slow, careful
|
||||
orbit from ending in a menu. There is no time budget — a gesture that means something different
|
||||
when it is slow is exactly what the interaction charter rules out. The raycast uses the press
|
||||
position, not the release. An armed sketch tool that already consumed the right
|
||||
button (to terminate a chain, say) declines to also open a menu, through a read-and-clear flag.
|
||||
Past either budget the event is navigation, and navigation does not transition the state
|
||||
machine.
|
||||
position, not the release. The sketch tool sees a right press only once the release has shown it
|
||||
was a click: the press itself goes to the camera, which may pan or orbit with that button, and the
|
||||
canvas replays it to the tool on a stationary release. A tool that uses the click (to terminate a
|
||||
chain, say) keeps the menu closed. Past either budget the event is navigation, and navigation
|
||||
does not transition the state machine.
|
||||
|
||||
Navigation itself is Prepare's: the camera reads the drag actions set in Preferences > Control
|
||||
for each button. The left button is shared with picking, so a whole body is swept with a
|
||||
rectangle on plain left-drag only while no camera action is assigned to it, and with
|
||||
Shift+left-drag otherwise — Prepare's own rectangle selection.
|
||||
for each button, and in the Touchpad camera style a move with Alt held orbits and one with Shift
|
||||
held pans, whatever tool is armed. The left button is shared with picking and drawing, so a tool
|
||||
handle or a press that draws takes it first, as a gizmo does in Prepare; a whole body is swept
|
||||
with a rectangle on plain left-drag only while no camera action is assigned to the left button,
|
||||
and with Shift+left-drag otherwise — Prepare's own rectangle selection.
|
||||
|
||||
Entering a sketch changes three things at once so the mode is legible: a banner above the
|
||||
canvas (a sibling of the canvas, not a child over it — on GTK a child window over a
|
||||
|
||||
@@ -1051,15 +1051,18 @@ void DesignCanvas::set_on_context_menu(std::function<void(const wxPoint&)> cb)
|
||||
return;
|
||||
m_ctx_bound = true;
|
||||
// Bound AFTER GLCanvas3D's own handlers, so this runs first and can consume the event.
|
||||
// It only consumes when it actually opens the offer; every other right-click still falls
|
||||
// through to the polyline-chain end and the move gizmo, which were there first.
|
||||
// Right-drag pans. Without remembering where the press landed, every pan ended by popping
|
||||
// the offer over wherever the camera stopped — the menu appearing as the reward for moving
|
||||
// the view. The offer is the release of a STATIONARY right-click (kCadRightClickDriftPx).
|
||||
// It only consumes when it actually opens the offer.
|
||||
// Right-drag may pan or orbit (Preferences > Control). Without remembering where the press
|
||||
// landed, every such drag ended by popping the offer over wherever the camera stopped — the
|
||||
// menu appearing as the reward for moving the view. A right-click is the release of a
|
||||
// STATIONARY press (kCadRightClickDriftPx); only that reaches the sketch tool or the offer.
|
||||
m_canvas_widget->Bind(wxEVT_RIGHT_DOWN, [this](wxMouseEvent& e) {
|
||||
m_ctx_press = e.GetPosition();
|
||||
m_ctx_travelled = false;
|
||||
e.Skip(); // the canvas still needs the press to seed the orbit
|
||||
// Drop any press the tool still keeps (only a click's release takes it, so a pan's stays)
|
||||
// before the canvas offers it this one, which ImGui may take instead.
|
||||
m_sketch_tool.drop_right_click();
|
||||
e.Skip(); // the canvas still needs the press to seed a pan or an orbit
|
||||
});
|
||||
m_canvas_widget->Bind(wxEVT_MOTION, [this](wxMouseEvent& e) {
|
||||
if (e.RightIsDown()) {
|
||||
@@ -1070,12 +1073,13 @@ void DesignCanvas::set_on_context_menu(std::function<void(const wxPoint&)> cb)
|
||||
});
|
||||
m_canvas_widget->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent& e) {
|
||||
const wxPoint d = e.GetPosition() - m_ctx_press;
|
||||
// Always read-and-clear, even when another guard already rules the offer out, or a
|
||||
// terminator recorded under one condition would still be pending under the next.
|
||||
const bool terminated = m_sketch_tool.take_right_consumed();
|
||||
// Click, or navigation? A press that travelled orbited; one that did not, did not.
|
||||
// Click, or navigation? A press that travelled panned or orbited; one that did not, did not.
|
||||
const bool is_click = !m_ctx_travelled && std::max(std::abs(d.x), std::abs(d.y)) <= kCadRightClickDriftPx;
|
||||
if (m_on_context_menu && !terminated && !inline_busy() && is_click) {
|
||||
// Ending a chain or abandoning an anchor uses the click up.
|
||||
const bool terminated = is_click && m_canvas && m_sketch_tool.take_right_click(*m_canvas);
|
||||
if (terminated)
|
||||
m_canvas->set_as_dirty(); // drawn by the canvas's own RightUp (e.Skip below) or at idle
|
||||
else if (m_on_context_menu && !inline_busy() && is_click) {
|
||||
// The menu belongs to what you POINTED AT — and pointing happened at the PRESS, not
|
||||
// at the release, so the raycast uses the press position. Within a 3 px budget the
|
||||
// two are the same pixel in practice; using the press is what makes that a
|
||||
|
||||
@@ -10315,14 +10315,14 @@ std::vector<int> DesignSketchTool::connected_loop(int seed) const
|
||||
// the offer was excluded in sketch mode wholesale so a right-click could end a polyline chain,
|
||||
// abandon an anchor or exit a tool. That made every sketch row in the atlas unreachable.
|
||||
// The honest test is not "which mode are we in" but "did the tool actually USE this right-click",
|
||||
// and only the tool knows. Wrapping on_mouse records that once, for every terminator, instead of
|
||||
// threading a flag through the twenty-odd sites that consume a RightDown.
|
||||
// and only the tool knows: take_right_click returns it for every terminator, from the
|
||||
// twenty-odd sites that consume a RightDown.
|
||||
// Right-click abandons the anchor a draw tool has down. With NOTHING down there is nothing to
|
||||
// abandon — and consuming the click anyway made the offer unreachable from every armed draw tool:
|
||||
// on_mouse records the consumption in m_right_consumed and DesignCanvas's RIGHT_UP handler
|
||||
// suppresses the menu whenever it is set, so right-click became a no-op that also hid the one door
|
||||
// to half the vocabulary (47 of 86 verbs have no shortcut). Measured on the rig: with Line armed,
|
||||
// two right-clicks in a row produced no menu and no tool change; only Escape freed it.
|
||||
// DesignCanvas's RIGHT_UP handler suppresses the menu whenever the tool used the click, so
|
||||
// right-click became a no-op that also hid the one door to half the vocabulary (47 of 86 verbs
|
||||
// have no shortcut). Measured on the rig: with Line armed, two right-clicks in a row produced no
|
||||
// menu and no tool change; only Escape freed it.
|
||||
// Same rule as xmh6, which said it for the selection: clearing nothing is not a gesture
|
||||
// terminator. ghcz.
|
||||
bool DesignSketchTool::right_abandon()
|
||||
@@ -10334,12 +10334,24 @@ bool DesignSketchTool::right_abandon()
|
||||
return true;
|
||||
}
|
||||
|
||||
// The camera follows Preferences > Control here as in Prepare, so no tool may take a gesture the
|
||||
// camera owns. A right press may start whatever drag action the right button is given, and
|
||||
// whether it did is known only at the release: ending a chain on the press made every pan or
|
||||
// orbit started there end the chain too. The press goes to the camera and is kept;
|
||||
// DesignCanvas's RIGHT_UP handler replays it through take_right_click when it was a click.
|
||||
bool DesignSketchTool::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
{
|
||||
const bool consumed = on_mouse_impl(evt, canvas);
|
||||
if (evt.RightDown())
|
||||
m_right_consumed = consumed;
|
||||
return consumed;
|
||||
if (evt.RightDown()) {
|
||||
m_right_press = evt;
|
||||
return false;
|
||||
}
|
||||
return on_mouse_impl(evt, canvas);
|
||||
}
|
||||
|
||||
bool DesignSketchTool::take_right_click(GLCanvas3D& canvas)
|
||||
{
|
||||
auto press = std::exchange(m_right_press, {});
|
||||
return press && on_mouse_impl(*press, canvas);
|
||||
}
|
||||
|
||||
bool DesignSketchTool::on_mouse_impl(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
@@ -11288,9 +11300,9 @@ bool DesignSketchTool::on_mouse_impl(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
return true;
|
||||
}
|
||||
if (evt.RightDown()) {
|
||||
// Hand the click back (return false) so the offer opens: the m_right_consumed flag
|
||||
// this return value feeds means "the tool USED this right-click", and a plain
|
||||
// right-click in Select mode is not a gesture terminator.
|
||||
// Hand the click back (return false) so the offer opens: take_right_click returns
|
||||
// this value as "the tool USED this right-click", and a plain right-click in Select
|
||||
// mode is not a gesture terminator.
|
||||
//
|
||||
// But do NOT drop the selection on the way out. The offer menu describes WHAT IS
|
||||
// SELECTED, so clearing first guaranteed it could only ever describe nothing: select
|
||||
|
||||
@@ -9,14 +9,15 @@
|
||||
#include "slic3r/GUI/GLSelectionRectangle.hpp" // left-drag rubber band over the committed bodies
|
||||
#include <Eigen/Core>
|
||||
#include <cstddef>
|
||||
#include <wx/event.h>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class wxMouseEvent;
|
||||
class wxPoint;
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -149,10 +150,10 @@ public:
|
||||
// Right-click on a draw tool: true when an in-progress anchor was abandoned, false when
|
||||
// there was nothing to abandon — and false is what lets the offer menu open. ghcz.
|
||||
bool right_abandon();
|
||||
// True if the LAST right-press was consumed as a gesture terminator (end a polyline chain,
|
||||
// abandon an anchor, exit a tool). Read-and-clear: the canvas asks on the matching release to
|
||||
// decide whether that right-click was the user's, in which case it opens the offer.
|
||||
bool take_right_consumed() { const bool b = m_right_consumed; m_right_consumed = false; return b; }
|
||||
// Replays and clears the right press on_mouse kept for the camera: true if the tool used it as
|
||||
// a gesture terminator (end a polyline chain, abandon an anchor), so no offer opens.
|
||||
bool take_right_click(GLCanvas3D& canvas);
|
||||
void drop_right_click() { m_right_press.reset(); }
|
||||
void render(GLCanvas3D& canvas);
|
||||
// The in-canvas value field, drawn by render() before any early return. Owned by
|
||||
// DesignCanvas; null until it sets it. Not a window — see SketchInlineEditor.hpp.
|
||||
@@ -1274,7 +1275,7 @@ private:
|
||||
void hit_display_sketch(const DisplaySketch& d, const Vec2d& p, double tol,
|
||||
int& edge_feat, int& edge_reg, int& edge_ent,
|
||||
double& edge_d, int& face_feat, int& face_reg) const;
|
||||
bool m_right_consumed{false}; // last RightDown was a gesture terminator, not a menu
|
||||
std::optional<wxMouseEvent> m_right_press; // right press not yet known to be a click
|
||||
bool m_escalate_repick{true}; // re-picking the same sub-element takes the whole body
|
||||
void render_solid_highlight();
|
||||
// The above's edge and vertex highlight, from explicit arguments, so the committed selection
|
||||
|
||||
@@ -4311,7 +4311,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
}
|
||||
if (evt.LeftDown() && m_canvas != nullptr)
|
||||
m_canvas->SetFocus(); // grab keyboard focus so Delete/keys reach this canvas
|
||||
if (m_design_sketch_tool->on_mouse(evt, *this)) {
|
||||
// A Touchpad-style orbit or pan (a plain move with Alt or Shift held) is the camera's,
|
||||
// whatever the tool would make of the move. Only a drag consults the button mappings.
|
||||
const bool camera_move = evt.Moving() && (is_camera_rotate(evt, {}) || is_camera_pan(evt, {}));
|
||||
if (!camera_move && m_design_sketch_tool->on_mouse(evt, *this)) {
|
||||
m_dirty = true;
|
||||
render(); // force an immediate redraw so the sketch overlay updates live
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user