diff --git a/crates/ui-egui/src/dialogs/modal.rs b/crates/ui-egui/src/dialogs/modal.rs index 6d9f91df3..f72383068 100644 --- a/crates/ui-egui/src/dialogs/modal.rs +++ b/crates/ui-egui/src/dialogs/modal.rs @@ -1,8 +1,9 @@ //! The modal dialog window: a backdrop that keeps the rest of the app from taking clicks, and a //! window with no title bar that opens centred and moves by dragging its heading (the band from its -//! top edge down to the heading), as a title bar would. Where it was moved to stays, per window, for -//! the session, and the window never leaves the screen. Rows too many for the screen's height -//! scroll inside it ([`scrolled_rows`]), so its heading and buttons stay in view. +//! top edge down to the heading), as a title bar would, showing the arrow until it is dragged. Where +//! it was moved to stays, per window, for the session, and the window never leaves the screen. Rows +//! too many for the screen's height scroll inside it ([`scrolled_rows`]), so its heading and buttons +//! stay in view. use egui::{Id, Rect, Vec2}; @@ -60,10 +61,10 @@ pub(crate) fn drag_band(ui: &mut egui::Ui, bottom: f32) { let band = Rect::from_x_y_ranges(outer.x_range(), outer.top()..=bottom.max(outer.top())); // Not focusable (`Sense::drag()` is): Tab goes through the dialog's controls, not the band. let r = ui.interact(band, handle(id), egui::Sense::DRAG); + // Hovered, it keeps the arrow, as a title bar does (the grab cursor is Windows' four-way move + // arrows: #5246); only while it is dragged does it show the window being carried. if r.dragged() { ui.ctx().set_cursor_icon(egui::CursorIcon::Grabbing); - } else if r.hovered() { - ui.ctx().set_cursor_icon(egui::CursorIcon::Grab); } } diff --git a/crates/ui-egui/src/dialogs/tests_modal.rs b/crates/ui-egui/src/dialogs/tests_modal.rs index 5408b78c2..95ff410ca 100644 --- a/crates/ui-egui/src/dialogs/tests_modal.rs +++ b/crates/ui-egui/src/dialogs/tests_modal.rs @@ -118,6 +118,31 @@ fn dialogs_move_by_their_heading_stay_on_screen_and_where_they_were_moved() { } } +/// #5246: the band that moves a dialog keeps the arrow when hovered, as a title bar does (the grab +/// cursor is the four-way move arrows on Windows); it shows the window held only while dragged. +#[test] +fn the_band_that_moves_a_dialog_keeps_the_arrow_until_dragged() { + let opens: [(&str, Open, egui::Id); 2] = [ + ("Offset Path", |app| crate::menus::invoke(app, "object.path.offsetPath", json!({})), egui::Id::unique(("dialog", "offsetPath"))), + ("New Document", open_new_document, egui::Id::unique(("dialog", "newDocument"))), + ]; + for (name, open, id) in opens { + let (ctx, mut app) = (ctx(), app_with_selection()); + open(&mut app); + settle(&ctx, &mut app); + let at = rect_of(&ctx, id).left_top() + vec2(40.0, 6.0); + let cursor = |ctx: &egui::Context, app: &mut VectorcraftApp, events: Vec| { + let input = egui::RawInput { screen_rect: Some(Rect::from_min_size(Pos2::ZERO, SCREEN)), events, ..Default::default() }; + ctx.run_ui(input, |ui| show(app, ui.ctx())).platform_output.cursor_icon + }; + cursor(&ctx, &mut app, vec![Event::PointerMoved(at)]); + assert_eq!(cursor(&ctx, &mut app, vec![]), egui::CursorIcon::Default, "{name}: hovering the band"); + cursor(&ctx, &mut app, vec![button(at, true)]); + assert_eq!(cursor(&ctx, &mut app, vec![Event::PointerMoved(at + vec2(20.0, 10.0))]), egui::CursorIcon::Grabbing, "{name}: dragging it"); + cursor(&ctx, &mut app, vec![button(at + vec2(20.0, 10.0), false)]); + } +} + /// Tab goes through a dialog's controls and does not stop on the band that moves the window. #[test] fn tab_skips_the_band_that_moves_a_dialog() {