Panels: a panel floated while the floating panels are hidden opens hidden

The floating panels' windows hide while a dialog, a menu, a tool flyout or the
All Tools drawer is open, but the commands went out only when that state
changed. A panel floated meanwhile opened shown at its topmost level, over
the dialog or drawer. A window that floats while the others are hidden now
gets the hide commands in its first frame.
This commit is contained in:
dotCooCoo
2026-11-11 14:40:14 -08:00
parent 7f3a046b18
commit 880b58729b
2 changed files with 47 additions and 7 deletions
+17 -7
View File
@@ -1238,18 +1238,28 @@ fn palette_window_state(modal: bool, popup: bool, active: bool) -> (egui::Window
/// Sends the palette windows of `layout` the level and visibility [`palette_window_state`] gives
/// when they change. craft-ui varies a palette's level through the viewport builder, which egui
/// applies when the window opens and not to one already on screen, so the commands go explicitly to
/// the windows there are.
/// the windows there are. A window that opens while the others are hidden (a panel floated under a
/// dialog, a menu, a flyout or the drawer) opens shown at its palette level, so it gets the commands
/// in its first frame.
#[cfg(not(target_arch = "wasm32"))]
fn palette_window_levels(ctx: &egui::Context, layout: &Layout<String>, modal: bool, popup: bool) {
let active = ctx.input(|i| i.focused || i.raw.viewports.values().any(|v| v.focused == Some(true)));
let key = area_id().with("palette-levels-state");
if ctx.data(|d| d.get_temp::<(bool, bool, bool)>(key)) == Some((modal, popup, active)) {
return;
}
ctx.data_mut(|d| d.insert_temp(key, (modal, popup, active)));
let state = (modal, popup, active);
let windows: Vec<u64> = layout.floating.iter().map(|window| window.id).collect();
let sent = ctx.data(|d| d.get_temp::<((bool, bool, bool), Vec<u64>)>(key));
let (level, visible) = palette_window_state(modal, popup, active);
for window in &layout.floating {
// The windows that already have this state's commands.
let known: &[u64] = match &sent {
Some((was, ids)) if *was == state && !visible => ids,
Some((was, _)) if *was == state => &windows,
_ => &[],
};
let fresh: Vec<u64> = windows.iter().copied().filter(|id| !known.contains(id)).collect();
if sent.as_ref().is_none_or(|(was, ids)| *was != state || *ids != windows) {
ctx.data_mut(|d| d.insert_temp(key, (state, windows)));
}
for window in layout.floating.iter().filter(|window| fresh.contains(&window.id)) {
let viewport = craft_ui::docking::DockArea::<String>::window_viewport(area_id(), window.id);
ctx.send_viewport_cmd_to(viewport, egui::ViewportCommand::WindowLevel(level));
ctx.send_viewport_cmd_to(viewport, egui::ViewportCommand::Visible(visible));
@@ -842,6 +842,36 @@ fn a_torn_off_strip_or_a_new_toolbar_leaves_the_palette_windows_shown() {
assert_eq!(take_palette_commands(&h, viewport).0, [false], "still shown: the drawer hides them again");
}
/// A panel floated while the palette windows are hidden opens hidden too, and shows with the others
/// once the drawer or the dialog over them closes.
#[test]
fn a_panel_floated_while_the_palette_windows_are_hidden_opens_hidden() {
let mut h = Harness::new();
let navigator = h.float("navigator");
h.host.borrow_mut().focus = ViewportId::ROOT;
h.frames(2);
take_palette_commands(&h, navigator);
h.app.run("window.editToolbar", json!({"open": true})).unwrap();
h.frames(2);
assert_eq!(take_palette_commands(&h, navigator).0, [false], "hidden under the drawer");
let layers = h.float("layers");
h.host.borrow_mut().focus = ViewportId::ROOT;
assert!(h.app.ui.tools_drawer, "the drawer stays open");
let (shown, levels) = take_palette_commands(&h, layers);
assert_eq!(shown, [false], "the new palette window is hidden under the drawer");
assert_eq!(levels, [egui::WindowLevel::Normal], "and out of the top level");
h.app.run("window.editToolbar", json!({"open": false})).unwrap();
h.frames(2);
assert_eq!(take_palette_commands(&h, layers).0, [true], "shown when the drawer closes");
h.app.ui.palette_open = true;
h.frames(2);
assert_eq!(take_palette_commands(&h, layers).0, [false], "hidden under the command palette");
let swatches = h.float("swatches");
h.host.borrow_mut().focus = ViewportId::ROOT;
assert_eq!(take_palette_commands(&h, swatches).0, [false], "a panel floated under it is hidden too");
}
/// The frame in which a click elsewhere closes a flyout or the drawer shows the palette windows, as
/// no later frame need come while the app is idle.
#[test]