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 <noreply@anthropic.com>
This commit is contained in:
vangel76
2026-10-17 13:06:52 +07:00
committed by bflatastic
co-authored by Claude Opus 5.5
parent 424a49604c
commit ecbbba4f2e
2 changed files with 32 additions and 4 deletions
+5 -3
View File
@@ -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;
+27 -1
View File
@@ -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<egui::Color32>) {
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");
}