Render Queue: Render Settings templates apply from the menu (#117)
Choosing Draft Settings (or any entry) in a Render Queue item's Render Settings menu did nothing when the menu had been moved up to fit the window. egui hit-tests a fixed-position Area where it was asked to go, not where it was moved, so the popup's "pressed outside" check was true over its own entries and the menu closed on the press, before the click. widgets::pressed_outside tests the press against the rect the popup was drawn at. Every popup with the same check uses it: popup_menu (Render Queue, Effect Controls, dropdowns), the colour popup, the Preview and viewer popups, the panel menu, the Flowchart, OpenType and font menus. Regression test: ui_render_queue.rs picks Draft Settings from a menu moved up to fit a 1000 px window; it failed before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ea25e402b1
commit
8a415e03ca
|
|
@ -287,7 +287,7 @@ pub fn color_popup(ui: &mut egui::Ui, id: egui::Id, pos: egui::Pos2, c: &mut [f3
|
|||
}
|
||||
});
|
||||
});
|
||||
if ui.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer() || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
if widgets::pressed_outside(ui.ctx(), &area.response) || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ui.data_mut(|d| d.insert_temp(open_id, false));
|
||||
}
|
||||
changed
|
||||
|
|
|
|||
|
|
@ -285,8 +285,7 @@ fn dropdown_row(app: &mut EffectcraftApp, ui: &mut egui::Ui, r: Rect, key: &str,
|
|||
}
|
||||
});
|
||||
});
|
||||
let outside =
|
||||
ui.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer() && !r.contains(ui.input(|i| i.pointer.interact_pos()).unwrap_or_default());
|
||||
let outside = widgets::pressed_outside(ui.ctx(), &area.response) && !r.contains(ui.input(|i| i.pointer.interact_pos()).unwrap_or_default());
|
||||
if chosen.is_some() || outside || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ui.data_mut(|d| d.insert_temp(pid.with("open"), false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ pub fn panel_menu_popup(app: &mut EffectcraftApp, ui: &mut egui::Ui) {
|
|||
}
|
||||
});
|
||||
});
|
||||
if close || (ui.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer() && !area.response.hovered()) {
|
||||
if close || crate::widgets::pressed_outside(ui.ctx(), &area.response) {
|
||||
ui.ctx().data_mut(|d| d.remove::<(PanelKind, egui::Pos2)>(id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ pub fn mini_flowchart(app: &mut EffectcraftApp, ctx: &egui::Context) {
|
|||
}
|
||||
});
|
||||
});
|
||||
let outside = ctx.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer();
|
||||
let outside = crate::widgets::pressed_outside(ctx, &area.response);
|
||||
if let Some(id) = open {
|
||||
app.session.open_comp(id);
|
||||
close = true;
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ fn opentype_popup(app: &mut EffectcraftApp, ui: &mut egui::Ui, id: egui::Id, pos
|
|||
for (aid, r, label) in rects {
|
||||
app.auto.add(&aid, r, &label);
|
||||
}
|
||||
let outside = ui.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer() && !area.response.hovered();
|
||||
let outside = widgets::pressed_outside(ui.ctx(), &area.response);
|
||||
if outside || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ui.data_mut(|d| d.insert_temp(open_id, false));
|
||||
}
|
||||
|
|
@ -584,7 +584,7 @@ fn font_popup(app: &EffectcraftApp, ui: &mut egui::Ui, id: egui::Id, pos: egui::
|
|||
});
|
||||
});
|
||||
});
|
||||
let outside = ui.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer() && !area.response.hovered();
|
||||
let outside = widgets::pressed_outside(ui.ctx(), &area.response);
|
||||
if chosen.is_some() || outside || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ui.data_mut(|d| d.insert_temp(id.with("open"), false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,9 +454,7 @@ fn popup(app: &mut EffectcraftApp, ui: &mut egui::Ui, id: &str, anchor: Rect, it
|
|||
}
|
||||
});
|
||||
});
|
||||
let outside = ui.input(|i| i.pointer.any_pressed())
|
||||
&& !area.response.contains_pointer()
|
||||
&& !anchor.contains(ui.input(|i| i.pointer.interact_pos()).unwrap_or_default());
|
||||
let outside = widgets::pressed_outside(ui.ctx(), &area.response) && !anchor.contains(ui.input(|i| i.pointer.interact_pos()).unwrap_or_default());
|
||||
if chosen.is_some() || outside || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ui.data_mut(|d| d.insert_temp(pid.with("open"), false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,6 +229,15 @@ pub fn checkbox(ui: &mut Ui, rect: Rect, on: bool, t: &Tokens, id: egui::Id) ->
|
|||
resp
|
||||
}
|
||||
|
||||
/// A pointer press this frame landed outside a popup `Area` (its `show` response). egui
|
||||
/// hit-tests a fixed-position area where it was asked to go, not where it was moved to fit the
|
||||
/// window, so `contains_pointer` / `hovered` are false over a menu shifted up from the bottom of
|
||||
/// the window and the menu would close on the press before its entry is clicked (#117). The
|
||||
/// area's response rect is where it was drawn.
|
||||
pub fn pressed_outside(ctx: &egui::Context, area: &Response) -> bool {
|
||||
ctx.input(|i| i.pointer.any_pressed() && !i.pointer.interact_pos().is_some_and(|p| area.rect.contains(p)))
|
||||
}
|
||||
|
||||
/// Show a popup menu anchored at `pos` with string options; returns the chosen index.
|
||||
pub fn popup_menu(ui: &mut Ui, id: egui::Id, pos: egui::Pos2, options: &[String], current: Option<usize>) -> Option<usize> {
|
||||
let mut chosen = None;
|
||||
|
|
@ -254,7 +263,7 @@ pub fn popup_menu(ui: &mut Ui, id: egui::Id, pos: egui::Pos2, options: &[String]
|
|||
});
|
||||
});
|
||||
});
|
||||
let clicked_outside = ui.input(|i| i.pointer.any_pressed()) && !area.response.contains_pointer() && !area.response.hovered();
|
||||
let clicked_outside = pressed_outside(ui.ctx(), &area.response);
|
||||
if chosen.is_some() || clicked_outside || ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ui.data_mut(|d| d.insert_temp(open_id, false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
//! Render Queue panel input: choosing a Render Settings template from an item's menu (#117).
|
||||
|
||||
use effectcraft_engine::Session;
|
||||
use effectcraft_engine::project::render_queue::RenderQuality;
|
||||
use effectcraft_ui_egui::EffectcraftApp;
|
||||
use effectcraft_ui_egui::dock::PanelKind;
|
||||
use egui::{Event, Modifiers, Pos2, pos2};
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
use serde_json::json;
|
||||
|
||||
fn click_at(h: &mut Harness<'_, EffectcraftApp>, p: Pos2) {
|
||||
h.input_mut().events.push(Event::PointerMoved(p));
|
||||
h.input_mut().events.push(Event::PointerButton { pos: p, button: egui::PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE });
|
||||
h.step();
|
||||
h.input_mut().events.push(Event::PointerButton { pos: p, button: egui::PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE });
|
||||
h.run_steps(2);
|
||||
}
|
||||
|
||||
/// The Render Settings menu is taller than the room below the item, so it is moved up to fit
|
||||
/// the window; its entries must still take the click instead of the menu closing on the press.
|
||||
#[test]
|
||||
fn render_settings_template_applies_from_a_menu_moved_to_fit_the_window() {
|
||||
let mut s = Session::default();
|
||||
s.execute("file.openDemoProject", json!({})).unwrap();
|
||||
s.execute("renderQueue.add", json!({})).unwrap();
|
||||
let id = s.project.render_queue[0].id;
|
||||
assert_eq!(s.project.render_queue[0].settings.name, "Best Settings");
|
||||
let mut app = Some(EffectcraftApp::new(s));
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| app.take().expect("app"));
|
||||
// Twirl the item open, as clicking its twirl does.
|
||||
h.ctx.data_mut(|d| d.insert_temp(egui::Id::new("rq-ui"), (vec![id], None::<u64>)));
|
||||
h.state_mut().show_panel(PanelKind::RenderQueue);
|
||||
h.run_steps(4);
|
||||
let dd = h.state().auto.find(&format!("renderQueue.item.{id}.renderSettings")).expect("Render Settings menu").clone();
|
||||
let dd_center = pos2(dd.rect[0] + dd.rect[2] / 2.0, dd.rect[1] + dd.rect[3] / 2.0);
|
||||
click_at(&mut h, dd_center);
|
||||
let entry = h.query_by_label_contains("Draft Settings").expect("the Draft Settings entry").rect();
|
||||
assert!(entry.max.y < dd_center.y, "the menu was moved up to fit the window (entry {entry:?}, menu button at {dd_center:?})");
|
||||
click_at(&mut h, entry.center());
|
||||
let it = &h.state().session.project.render_queue[0];
|
||||
assert_eq!(it.settings.name, "Draft Settings");
|
||||
assert_eq!(it.settings.quality, RenderQuality::Draft);
|
||||
assert_eq!(it.settings.resolution, 0.5);
|
||||
assert!(h.query_by_label_contains("Quality: Draft").is_none(), "the menu closed after the choice");
|
||||
}
|
||||
Loading…
Reference in New Issue