From ecbbba4f2e78ee0e5b0abac3cc978fa4e85a3521 Mon Sep 17 00:00:00 2001 From: vangel76 Date: Fri, 16 Oct 2026 20:31:51 +0200 Subject: [PATCH] Panels: floating panel groups paint an opaque background (#2421) The shared dock left its pane and tab strip backgrounds transparent because the docked card behind them is filled. Floating groups lie on the canvas, so the canvas showed through. They now paint the panel colour, which is what the card shows when docked. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/panel_docking.rs | 8 ++++--- crates/ui-egui/src/panel_docking_tests.rs | 28 ++++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/panel_docking.rs b/crates/ui-egui/src/panel_docking.rs index d01858d3c..9cb1cdbf6 100644 --- a/crates/ui-egui/src/panel_docking.rs +++ b/crates/ui-egui/src/panel_docking.rs @@ -644,9 +644,11 @@ pub(crate) fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) -> bool { } let mut style = craft_ui::docking::DockStyle::from_ui(ui); style.tab_height = 33.0; - // The dock is a card (`theme::card`): its panes and tab strip lie on the card's colour. - style.background = egui::Color32::TRANSPARENT; - style.tab_background = egui::Color32::TRANSPARENT; + // The dock is a card (`theme::card`) filled with the panel colour. Floating groups lie on + // the canvas, not on that card, so panes and tab strip paint the same colour themselves; + // transparent they showed the canvas through (#2421). + style.background = t.panel; + style.tab_background = t.panel; style.active_background = t.button; style.text = t.text_strong; style.inactive_text = t.text_dim; diff --git a/crates/ui-egui/src/panel_docking_tests.rs b/crates/ui-egui/src/panel_docking_tests.rs index c66623e75..9eccbf0e8 100644 --- a/crates/ui-egui/src/panel_docking_tests.rs +++ b/crates/ui-egui/src/panel_docking_tests.rs @@ -1,5 +1,5 @@ use super::*; -use egui::{Event, Modifiers, PointerButton, Pos2, vec2}; +use egui::{Event, Modifiers, PointerButton, Pos2, pos2, vec2}; use egui_kittest::{Harness, kittest::Queryable}; fn app() -> VectorcraftApp { @@ -614,3 +614,29 @@ fn the_window_menu_item_hides_a_shown_panel_and_shows_it_again() { app.run("window.panel", json!({"panel":"properties"})).unwrap(); assert!(shown(&app), "without the menu's toggle the command only shows the panel"); } + +/// A floating group lies on the canvas, not on the dock's card, so its tab strip and body paint +/// their own opaque background (#2421). +#[test] +fn floating_group_paints_an_opaque_background() { + let mut app = app(); + app.run("window.panel.float", json!({"panel":"properties","x":400,"y":200,"width":300,"height":420})).unwrap(); + let h = harness(app, vec2(1280.0, 800.0)); + // Paint order: the last big filled rectangle over a point decides what the user sees there + // (outlines and small widgets don't count). + fn topmost(shape: &egui::Shape, p: Pos2, found: &mut Option) { + match shape { + egui::Shape::Rect(r) if r.rect.contains(p) && r.rect.width() >= 200.0 && r.stroke.is_empty() => *found = Some(r.fill), + egui::Shape::Vec(v) => v.iter().for_each(|s| topmost(s, p, found)), + _ => {} + } + } + let opaque_at = |p: Pos2| { + let mut found = None; + h.output().shapes.iter().for_each(|s| topmost(&s.shape, p, &mut found)); + found.is_some_and(|c| c.a() == 255) + }; + // Tab strip to the right of the tabs, and the body's empty bottom-right corner. + assert!(opaque_at(pos2(690.0, 210.0)), "tab strip is transparent"); + assert!(opaque_at(pos2(690.0, 610.0)), "body is transparent"); +}