Dialogs can be moved by dragging the title bar (#29)
All dialogs (Layer Style, New Document, filters, ...) were pinned to the centre. Dragging the title row now moves them, clamped so the dialog stays on screen. The title text is no longer selectable, so dragging it moves the dialog instead of selecting text. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
11e5af23ad
commit
8d21ca349d
|
|
@ -12,8 +12,13 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
let mut fields = d.fields.clone();
|
||||
let mut outcome: Option<bool> = None; // Some(true)=OK, Some(false)=Cancel
|
||||
let title = title(&d);
|
||||
let id = egui::Id::new(("dialog", d.id));
|
||||
// Offset from centre, moved by dragging the title bar (view state only, so egui memory).
|
||||
let offset: egui::Vec2 = ctx.data(|m| m.get_temp(id)).unwrap_or_default();
|
||||
let mut drag = egui::Vec2::ZERO;
|
||||
let area = egui::Modal::default_area(id).anchor(egui::Align2::CENTER_CENTER, offset);
|
||||
// Photoshop doesn't dim the window behind dialogs: previews must be judged at true contrast.
|
||||
let modal = egui::Modal::new(egui::Id::new(("dialog", d.id))).backdrop_color(egui::Color32::TRANSPARENT).show(ctx, |ui| {
|
||||
let modal = egui::Modal::new(id).area(area).backdrop_color(egui::Color32::TRANSPARENT).show(ctx, |ui| {
|
||||
ui.set_min_width(380.0);
|
||||
let wide = crate::prefs_ui::width(&d.fields);
|
||||
if let Some(w) = wide {
|
||||
|
|
@ -33,7 +38,9 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
ui.set_min_width(w);
|
||||
ui.set_max_width(w);
|
||||
}
|
||||
ui.label(egui::RichText::new(&title).font(crate::theme::semibold(15.0)));
|
||||
let t = ui.add(egui::Label::new(egui::RichText::new(&title).font(crate::theme::semibold(15.0))).selectable(false)).rect;
|
||||
let bar = egui::Rect::from_min_max(t.min, egui::pos2(ui.max_rect().right(), t.bottom()));
|
||||
drag = ui.interact(bar, id.with("title"), egui::Sense::drag()).drag_delta();
|
||||
ui.add_space(4.0);
|
||||
crate::widgets::hairline(ui);
|
||||
ui.add_space(8.0);
|
||||
|
|
@ -89,6 +96,11 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
}
|
||||
});
|
||||
});
|
||||
if drag != egui::Vec2::ZERO {
|
||||
// Keep the whole dialog (and so its title bar) on screen.
|
||||
let room = ((ctx.content_rect().size() - modal.response.rect.size()) / 2.0).max(egui::Vec2::ZERO);
|
||||
ctx.data_mut(|m| m.insert_temp(id, (offset + drag).clamp(-room, room)));
|
||||
}
|
||||
if modal.should_close() && outcome.is_none() {
|
||||
outcome = Some(false);
|
||||
}
|
||||
|
|
@ -173,3 +185,36 @@ pub fn open_command_dialog(app: &mut PhotocraftApp, command: &str, label: &str)
|
|||
}
|
||||
app.ui.open_dialog(DialogKind::Command, fields)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn dragging_the_title_bar_moves_the_dialog() {
|
||||
use egui_kittest::{Harness, kittest::Queryable};
|
||||
|
||||
let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());
|
||||
let mut harness = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_ui_state(|ui, app| show(app, ui.ctx()), app);
|
||||
PhotocraftApp::setup_context(&harness.ctx, crate::theme::ThemeKind::ALL[0]);
|
||||
harness.state_mut().ui.open_dialog(DialogKind::LayerStyle, serde_json::Map::new());
|
||||
harness.run_steps(3);
|
||||
let before = harness.get_by_label("Layer Style").rect();
|
||||
|
||||
// Grab the title text itself: it must move the dialog, not select the text.
|
||||
let from = before.center();
|
||||
harness.hover_at(from);
|
||||
harness.drag_at(from);
|
||||
harness.run_steps(2);
|
||||
for i in 1..=10 {
|
||||
harness.hover_at(from + egui::vec2(-12.0, 8.0) * i as f32);
|
||||
harness.run_steps(1);
|
||||
}
|
||||
harness.drop_at(from + egui::vec2(-120.0, 80.0));
|
||||
harness.run_steps(3);
|
||||
|
||||
let moved = harness.get_by_label("Layer Style").rect().min - before.min;
|
||||
assert!((moved - egui::vec2(-120.0, 80.0)).length() < 1.0, "dialog moved by {moved:?}");
|
||||
assert_eq!(harness.state().ui.dialogs.len(), 1, "dragging must not close the dialog");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue