mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-02 15:52:14 +00:00
QOL Continue to capture mouse position while dragging ImGui controls and mouse position goes to outside of window (#14999)
* Update GLCanvas3D.cpp * support navigation cube * capture events for transform widgets * camera rotation and pan * selection frame * object drag * fix navigation cube stealing drag events * fix lag on navigation cuve * variable layer height * fix plates toolbar scrollbar * Update GLCanvas3D.cpp * Fix issue that mouse button state is wrong in certain macOS mouse events --------- Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
@@ -1842,6 +1842,10 @@ void GLCanvas3D::enable_separator_toolbar(bool enable)
|
||||
m_separator_toolbar.set_enabled(enable);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::has_mouse_capture() const {
|
||||
return m_canvas != nullptr && m_canvas->HasCapture();
|
||||
}
|
||||
|
||||
void GLCanvas3D::zoom_to_bed()
|
||||
{
|
||||
BoundingBoxf3 box = m_bed.build_volume().bounding_volume();
|
||||
@@ -2182,7 +2186,7 @@ void GLCanvas3D::render(bool only_init)
|
||||
|
||||
// Negative coordinate means out of the window, likely because the window was deactivated.
|
||||
// In that case the tooltip should be hidden.
|
||||
if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.) {
|
||||
if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0. || has_mouse_capture()) { // ORCA continue to capture mouse pos mid drag
|
||||
if (tooltip.empty())
|
||||
tooltip = m_layers_editing.get_tooltip(*this);
|
||||
|
||||
@@ -4170,6 +4174,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
// BBS: single snapshot
|
||||
Plater::SingleSnapshot single(wxGetApp().plater());
|
||||
|
||||
#ifdef __WXMAC__
|
||||
// On macOS, the mouse key state is only present for mouse btn related events such as wxEVT_LEFT_DOWN.
|
||||
// For other events, all buttons are reported as non-pressed, such as window leaving event. This causes
|
||||
// imgui stopped responding if cursor moved out of window, such as
|
||||
// https://github.com/OrcaSlicer/OrcaSlicer/pull/14999#issuecomment-5151344759
|
||||
// We solve this by correcting the state of the event from the actual mouse state querying with `wxGetMouseState()`
|
||||
// so it works like on other platforms.
|
||||
{
|
||||
const auto state = wxGetMouseState();
|
||||
evt.SetLeftDown(state.LeftIsDown());
|
||||
evt.SetMiddleDown(state.MiddleIsDown());
|
||||
evt.SetRightDown(state.RightIsDown());
|
||||
evt.SetAux1Down(state.Aux1IsDown());
|
||||
evt.SetAux2Down(state.Aux2IsDown());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
const float scale = m_retina_helper->get_scale_factor();
|
||||
evt.SetX(evt.GetX() * scale);
|
||||
@@ -4183,11 +4204,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
// ignore left up events coming from imgui windows and not processed by them
|
||||
m_mouse.ignore_left_up = true;
|
||||
m_tooltip.set_in_imgui(false);
|
||||
if (imgui->update_mouse_data(evt)) {
|
||||
|
||||
// while a non-ImGui drag is already in progress (gizmo grabber, object move, rectangle selection, layer editing),
|
||||
// don't let ImGui/ImGuizmo claim the event just because the cursor is hovering something like the navigator cube
|
||||
// that incorrectly suppresses the active drag's tooltip and can interrupt its processing. The active drag always takes priority.
|
||||
const bool other_drag_active = m_gizmos.is_dragging() || m_mouse.dragging || m_rectangle_selection.is_dragging() || m_layers_editing.state == LayersEditing::Editing;
|
||||
|
||||
if (imgui->update_mouse_data(evt) && !other_drag_active) {
|
||||
if ((evt.LeftDown() || (evt.Moving() && (evt.AltDown() || evt.ShiftDown()))) && m_canvas != nullptr)
|
||||
m_canvas->SetFocus();
|
||||
m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast<double>();
|
||||
m_tooltip.set_in_imgui(true);
|
||||
|
||||
// ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
const bool imgui_dragging_active = (GImGui != nullptr && ImGui::GetIO().MouseDown[0] && GImGui->ActiveId != 0) || m_navigator_dragging;
|
||||
if (!has_mouse_capture() && imgui_dragging_active)
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
// release capture as soon as the button goes up
|
||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||
mouse_up_cleanup();
|
||||
|
||||
render();
|
||||
#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
|
||||
printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str());
|
||||
@@ -4284,6 +4321,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
m_main_toolbar.on_mouse(evt2, *this);
|
||||
}
|
||||
|
||||
// ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
if (!has_mouse_capture() && evt.LeftIsDown() && m_gizmos.is_dragging())
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||
mouse_up_cleanup();
|
||||
|
||||
@@ -4389,6 +4430,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
// Start editing the layer height.
|
||||
m_layers_editing.state = LayersEditing::Editing;
|
||||
_perform_layer_editing_action(&evt);
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -4402,6 +4446,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
&& m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation
|
||||
&& m_gizmos.get_current_type() != GLGizmosManager::FuzzySkin) {
|
||||
m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
@@ -4469,6 +4517,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
m_mouse.drag.start_position_3D = m_mouse.scene_position;
|
||||
m_sequential_print_clearance_first_displacement = true;
|
||||
m_moving = true;
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4477,6 +4528,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
}
|
||||
else if (evt.Dragging() && evt.LeftIsDown() && m_mouse.drag.move_volume_idx != -1 && m_layers_editing.state == LayersEditing::Unknown) {
|
||||
if (m_canvas_type != ECanvasType::CanvasAssembleView) {
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
if (!m_mouse.drag.move_requires_threshold) {
|
||||
m_mouse.dragging = true;
|
||||
Vec3d cur_pos = m_mouse.drag.start_position_3D;
|
||||
@@ -4528,6 +4583,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) {
|
||||
//BBS not in assemble view
|
||||
if (m_canvas_type != ECanvasType::CanvasAssembleView) {
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
m_rectangle_selection.dragging(pos.cast<double>());
|
||||
m_dirty = true;
|
||||
}
|
||||
@@ -4537,12 +4596,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
|
||||
if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) {
|
||||
if (m_layers_editing.state == LayersEditing::Editing) {
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
_perform_layer_editing_action(&evt);
|
||||
m_mouse.position = pos.cast<double>();
|
||||
}
|
||||
}
|
||||
// do not process the dragging if the left mouse was set down in another canvas
|
||||
else if (is_camera_rotate(evt, button_mappings)) {
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
// Orca: Sphere rotation for painting view
|
||||
// if dragging over blank area with left button or other button mapped to rotate, then rotate
|
||||
bool middle_or_right_button_used_as_rotate = (evt.MiddleIsDown() && button_mappings[MouseButton::Middle] == MouseAction::Rotation) ||
|
||||
@@ -4622,6 +4688,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0);
|
||||
}
|
||||
else if (is_camera_pan(evt, button_mappings)) {
|
||||
|
||||
if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
m_canvas->CaptureMouse();
|
||||
|
||||
// if dragging with right button or if button functions swapped and dragging with left button over blank area then pan
|
||||
if (m_mouse.is_start_position_2D_defined()) {
|
||||
// get point in model space at Z = 0
|
||||
@@ -6033,9 +6103,18 @@ void GLCanvas3D::_render_3d_navigator()
|
||||
{
|
||||
if (!wxGetApp().show_3d_navigator()) {
|
||||
m_canvas_toolbar_pos[0] = 0;
|
||||
m_navigator_dragging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Fix stealing capture event from other drag events
|
||||
const bool other_drag_active = !m_navigator_dragging && (m_moving || m_rectangle_selection.is_dragging() || m_gizmos.is_dragging() || m_layers_editing.state == LayersEditing::Editing);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
const bool saved_mouse_down0 = io.MouseDown[0];
|
||||
if (other_drag_active)
|
||||
io.MouseDown[0] = false;
|
||||
|
||||
ImGuizmo::BeginFrame();
|
||||
|
||||
auto& style = ImGuizmo::GetStyle();
|
||||
@@ -6060,7 +6139,6 @@ void GLCanvas3D::_render_3d_navigator()
|
||||
sc *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
const float viewManipulateLeft = 0;
|
||||
const float viewManipulateTop = io.DisplaySize.y;
|
||||
const float camDistance = 8.f;
|
||||
@@ -6084,6 +6162,10 @@ void GLCanvas3D::_render_3d_navigator()
|
||||
camDistance, ImVec2(viewManipulateLeft, viewManipulateTop - size), ImVec2(size, size),
|
||||
0x00101010);
|
||||
|
||||
// Restore the real mouse-down state
|
||||
if (other_drag_active)
|
||||
io.MouseDown[0] = saved_mouse_down0;
|
||||
|
||||
if (result.changed) {
|
||||
for (unsigned int c = 0; c < 4; ++c) {
|
||||
for (unsigned int r = 0; r < 4; ++r) {
|
||||
@@ -6115,6 +6197,8 @@ void GLCanvas3D::_render_3d_navigator()
|
||||
|
||||
request_extra_frame();
|
||||
}
|
||||
|
||||
m_navigator_dragging = result.dragging;
|
||||
}
|
||||
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0
|
||||
@@ -9226,8 +9310,12 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
|
||||
|
||||
//ORCA ImGui::IsWindowHovered() returns false when left_down events on buttons that causes scrollbar disappears for a short time
|
||||
auto win_pos = ImGui::GetWindowPos();
|
||||
bool is_win_hovered = ImGui::IsMouseHoveringRect(win_pos, win_pos + ImVec2(window_width + (show_scroll ? scrollbar_size : 0), window_height), !show_scroll); // use non clipped rectangle to reserve clickable area for scrollbar track
|
||||
m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered;
|
||||
bool is_win_hovered = ImGui::IsMouseHoveringRect(win_pos, win_pos + ImVec2(window_width + (show_scroll ? scrollbar_size : 0), window_height), !show_scroll);
|
||||
|
||||
// Also show scrollbar visible and continue to capture mouse position
|
||||
const bool is_scrollbar_active_drag = GImGui != nullptr && ImGui::GetIO().MouseDown[0] && GImGui->ActiveId != 0 && GImGui->ActiveIdWindow == ImGui::GetCurrentWindow();
|
||||
|
||||
m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered || is_scrollbar_active_drag;
|
||||
|
||||
imgui.end();
|
||||
}
|
||||
|
||||
@@ -589,6 +589,7 @@ private:
|
||||
bool m_toolpath_outside{ false };
|
||||
ECursorType m_cursor_type;
|
||||
GLSelectionRectangle m_rectangle_selection;
|
||||
bool m_navigator_dragging{ false };
|
||||
|
||||
//BBS:add plate related logic
|
||||
mutable std::vector<int> m_hover_volume_idxs;
|
||||
@@ -916,6 +917,7 @@ public:
|
||||
void update_volumes_colors_by_extruder();
|
||||
|
||||
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
|
||||
bool has_mouse_capture() const;
|
||||
|
||||
void render(bool only_init = false);
|
||||
bool is_rendering_enabled()
|
||||
|
||||
@@ -442,7 +442,7 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
||||
}
|
||||
} else if (m_dragging) {
|
||||
// when mouse cursor leave window than finish actual dragging operation
|
||||
bool is_leaving = mouse_event.Leaving();
|
||||
bool is_leaving = mouse_event.Leaving() && !m_parent.has_mouse_capture(); // ORCA keep tracking mouse position while drag active and cursor not in window bounds
|
||||
if (mouse_event.Dragging()) {
|
||||
Point mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
auto ray = m_parent.mouse_ray(mouse_coord);
|
||||
|
||||
Reference in New Issue
Block a user