mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 08:29:14 +00:00
Control bar: Escape in the frame that releases the gripper cancels only the drag
The release frame's shortcuts run before the bar is drawn, with the button already up, so they missed the drag and the Escape also reached the active tool. The drag now counts as going on in that frame too.
This commit is contained in:
@@ -392,15 +392,17 @@ const FLOAT_WIDTH: f32 = 800.0;
|
||||
const DOCK_ZONE: f32 = 24.0;
|
||||
|
||||
/// The key of a gripper drag in progress: where the pointer holds the bar from its top-left
|
||||
/// corner.
|
||||
/// corner, and the gripper's widget id.
|
||||
fn move_id() -> egui::Id {
|
||||
egui::Id::unique("control_bar_gripper_move")
|
||||
}
|
||||
|
||||
/// Is the Control bar's gripper being dragged? An Escape then cancels the drag, and nothing else.
|
||||
/// A drag left over from a bar hidden while the button was held ends with the button.
|
||||
/// Is the Control bar's gripper being dragged, the frame that releases it included? An Escape then
|
||||
/// cancels the drag, and nothing else. A drag left over from a bar hidden while the button was held
|
||||
/// ends with the button.
|
||||
pub fn control_bar_moving(ctx: &egui::Context) -> bool {
|
||||
ctx.input(|i| i.pointer.primary_down()) && ctx.data(|d| d.get_temp::<egui::Vec2>(move_id()).is_some())
|
||||
let Some((_, gripper)) = ctx.data(|d| d.get_temp::<(egui::Vec2, egui::Id)>(move_id())) else { return false };
|
||||
ctx.input(|i| i.pointer.primary_down()) || ctx.drag_stopped_id() == Some(gripper)
|
||||
}
|
||||
|
||||
/// Where a gripper release puts the Control bar.
|
||||
@@ -545,18 +547,18 @@ fn gripper(app: &mut VectorcraftApp, ui: &mut Ui, t: &Tokens, bar: egui::Rect, d
|
||||
if resp.drag_started()
|
||||
&& let Some(press) = ctx.input(|i| i.pointer.press_origin())
|
||||
{
|
||||
ctx.data_mut(|d| d.insert_temp(move_id(), press - bar.min));
|
||||
ctx.data_mut(|d| d.insert_temp(move_id(), (press - bar.min, resp.id)));
|
||||
}
|
||||
let Some(grab) = ctx.data(|d| d.get_temp::<egui::Vec2>(move_id())) else { return };
|
||||
let Some((grab, _)) = ctx.data(|d| d.get_temp::<(egui::Vec2, egui::Id)>(move_id())) else { return };
|
||||
let canceled = ctx.input(|i| i.key_pressed(egui::Key::Escape) || !i.focused);
|
||||
if canceled || !(resp.dragged() || resp.drag_stopped()) {
|
||||
ctx.data_mut(|d| d.remove::<egui::Vec2>(move_id()));
|
||||
ctx.data_mut(|d| d.remove::<(egui::Vec2, egui::Id)>(move_id()));
|
||||
return;
|
||||
}
|
||||
let window = ctx.content_rect();
|
||||
let target = ctx.input(|i| i.pointer.latest_pos()).and_then(|at| release_at(at, grab, dock_room, window));
|
||||
if resp.drag_stopped() {
|
||||
ctx.data_mut(|d| d.remove::<egui::Vec2>(move_id()));
|
||||
ctx.data_mut(|d| d.remove::<(egui::Vec2, egui::Id)>(move_id()));
|
||||
match target {
|
||||
Some(Release::Edge(bottom)) if app.ui.control_bar_floating || bottom != app.ui.control_bar_bottom => {
|
||||
dock(app, CONTROL_BAR_EDGES[usize::from(bottom)]);
|
||||
|
||||
@@ -2515,11 +2515,40 @@ fn control_bar_drag_escape_restores_placement() {
|
||||
control_bar_frame(&mut app, &ctx, vec![egui::Event::PointerMoved(from.lerp(to, k as f32 / 4.0))]);
|
||||
}
|
||||
assert!(super::control_bar_moving(&ctx), "the drag goes on");
|
||||
let mut out = ctx.run_ui(egui::RawInput { events: vec![press_at(to, false)], screen_rect: Some(DOCK_SCREEN), ..Default::default() }, |_| {});
|
||||
out.textures_delta.clear();
|
||||
for events in [vec![press_at(to, false)], vec![]] {
|
||||
let mut out = ctx.run_ui(egui::RawInput { events, screen_rect: Some(DOCK_SCREEN), ..Default::default() }, |_| {});
|
||||
out.textures_delta.clear();
|
||||
}
|
||||
assert!(!super::control_bar_moving(&ctx), "released with the bar hidden, the drag is over");
|
||||
}
|
||||
|
||||
/// An Escape in the same frame as the gripper's release is the drag's: the frame's shortcuts, which
|
||||
/// run before the bar is drawn, still see the drag, and the bar stays where it was.
|
||||
#[test]
|
||||
fn control_bar_drag_escape_on_release_frame_is_the_drags() {
|
||||
let mut app = crate::VectorcraftApp::new(Session::new(), Default::default());
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let (from, to) = (docked_grip(false), egui::pos2(400.0, 150.0));
|
||||
control_bar_frame(&mut app, &ctx, vec![]);
|
||||
control_bar_frame(&mut app, &ctx, vec![egui::Event::PointerMoved(from), press_at(from, true)]);
|
||||
for k in 1..=4 {
|
||||
control_bar_frame(&mut app, &ctx, vec![egui::Event::PointerMoved(from.lerp(to, k as f32 / 4.0))]);
|
||||
}
|
||||
let escape = egui::Event::Key { key: egui::Key::Escape, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() };
|
||||
let mut moving = None;
|
||||
let input = egui::RawInput { events: vec![escape, press_at(to, false)], screen_rect: Some(DOCK_SCREEN), ..Default::default() };
|
||||
let mut out = ctx.run_ui(input, |ui| {
|
||||
moving = Some(super::control_bar_moving(ui.ctx()));
|
||||
super::control_bar(&mut app, ui);
|
||||
});
|
||||
out.textures_delta.clear();
|
||||
assert_eq!(moving, Some(true), "the release frame's shortcuts see the drag");
|
||||
assert!(!app.ui.control_bar_floating && !app.ui.control_bar_bottom, "the canceled drag leaves the bar at the top");
|
||||
control_bar_frame(&mut app, &ctx, vec![]);
|
||||
assert!(!super::control_bar_moving(&ctx), "the drag is over");
|
||||
}
|
||||
|
||||
/// A gripper drag released outside the window leaves the bar where it was.
|
||||
#[test]
|
||||
fn control_bar_drag_release_outside_window_keeps_previous_placement() {
|
||||
|
||||
Reference in New Issue
Block a user