Merge pull request #1144 from haranishi/fix/1075-panel-focus-outline
fix: パネルのフォーカス枠の欠けを修正 #1075
This commit is contained in:
commit
20f618d378
|
|
@ -581,7 +581,9 @@ pub fn draw_group_chrome(
|
|||
t: &Tokens,
|
||||
reg: &mut crate::automation::Registry,
|
||||
) -> Vec<DockAction> {
|
||||
draw_group_chrome_details(ui, g, focused, seqs, t, reg).actions
|
||||
let chrome = draw_group_chrome_details(ui, g, seqs, t, reg);
|
||||
paint_group_focus(ui, g, focused, t);
|
||||
chrome.actions
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -590,14 +592,7 @@ pub struct Chrome {
|
|||
pub tabs: Vec<(PanelKind, Rect)>,
|
||||
}
|
||||
|
||||
pub fn draw_group_chrome_details(
|
||||
ui: &mut egui::Ui,
|
||||
g: &Group,
|
||||
focused: PanelKind,
|
||||
seqs: &SeqTabs,
|
||||
t: &Tokens,
|
||||
reg: &mut crate::automation::Registry,
|
||||
) -> Chrome {
|
||||
pub fn draw_group_chrome_details(ui: &mut egui::Ui, g: &Group, seqs: &SeqTabs, t: &Tokens, reg: &mut crate::automation::Registry) -> Chrome {
|
||||
let mut actions = Vec::new();
|
||||
let mut tab_rects: Vec<(PanelKind, Rect)> = Vec::new();
|
||||
let painter = ui.painter().clone();
|
||||
|
|
@ -852,10 +847,6 @@ pub fn draw_group_chrome_details(
|
|||
ui.ctx().data_mut(|d| d.remove::<bool>(list_id));
|
||||
}
|
||||
}
|
||||
// focus outline
|
||||
if active_panel == Some(focused) {
|
||||
painter.rect_stroke(g.rect, 0.0, Stroke::new(1.0, t.focus), StrokeKind::Inside);
|
||||
}
|
||||
// clicking anywhere in the panel focuses it
|
||||
if let Some(p) = active_panel
|
||||
&& ui.rect_contains_pointer(g.rect)
|
||||
|
|
@ -866,6 +857,13 @@ pub fn draw_group_chrome_details(
|
|||
Chrome { actions, tabs: tab_rects }
|
||||
}
|
||||
|
||||
/// Paint once after the group's contents so child backgrounds cannot hide its focus (#1075).
|
||||
pub(crate) fn paint_group_focus(ui: &egui::Ui, group: &Group, focused: PanelKind, tokens: &Tokens) {
|
||||
if group.panels.get(group.active).copied() == Some(focused) {
|
||||
ui.painter().rect_stroke(group.rect, 0.0, Stroke::new(1.0, tokens.focus), StrokeKind::Inside);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_widget_focus(painter: &egui::Painter, response: &egui::Response, tokens: &Tokens) {
|
||||
if response.has_focus() {
|
||||
painter.rect_stroke(response.rect.shrink(2.0), 2.0, Stroke::new(1.5, tokens.focus), StrokeKind::Inside);
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ impl FilmcraftApp {
|
|||
let mut actions = vec![];
|
||||
let mut targets = vec![];
|
||||
for group in &groups {
|
||||
let chrome = dock::draw_group_chrome_details(ui, group, self.ui.focused, &seqs, &t, &mut self.auto);
|
||||
let chrome = dock::draw_group_chrome_details(ui, group, &seqs, &t, &mut self.auto);
|
||||
if let Some(target) = target(group, chrome.tabs, true) {
|
||||
targets.push(target);
|
||||
}
|
||||
|
|
@ -205,6 +205,9 @@ impl FilmcraftApp {
|
|||
self.panel_body(ui, panel, group.content);
|
||||
}
|
||||
}
|
||||
for group in &groups {
|
||||
dock::paint_group_focus(ui, group, self.ui.focused, &t);
|
||||
}
|
||||
let floating_order = self.floating_order(&ctx);
|
||||
for index in floating_order.into_iter().filter(|_| maximized.is_none()) {
|
||||
if let Some(target) = self.floating_group(&ctx, index, &seqs, &mut actions) {
|
||||
|
|
@ -279,7 +282,7 @@ impl FilmcraftApp {
|
|||
panels: floating.panels.clone(),
|
||||
active: floating.active,
|
||||
};
|
||||
let chrome = dock::draw_group_chrome_details(ui, &group, self.ui.focused, seqs, &t, &mut self.auto);
|
||||
let chrome = dock::draw_group_chrome_details(ui, &group, seqs, &t, &mut self.auto);
|
||||
actions.extend(chrome.actions);
|
||||
if let Some(active) = group.panels.get(group.active).copied() {
|
||||
self.panel_body(ui, active, group.content);
|
||||
|
|
@ -307,6 +310,7 @@ impl FilmcraftApp {
|
|||
if next != rect {
|
||||
let _ = self.dock_command(ctx, Action::MoveFloating { panel, rect: [next.min.x, next.min.y, next.width(), next.height()] });
|
||||
}
|
||||
dock::paint_group_focus(ui, &group, self.ui.focused, &t);
|
||||
output = target(&group, chrome.tabs, false);
|
||||
});
|
||||
output
|
||||
|
|
|
|||
|
|
@ -520,3 +520,54 @@ fn scopes_of_colour_bars() {
|
|||
assert!(angles.iter().any(|x| (x - a).abs() < 1.5), "{} at {a:.1}° not in {angles:?}", t.name);
|
||||
}
|
||||
}
|
||||
|
||||
/// #1075: child backgrounds must not cover the focus outline shared with Program. Check the
|
||||
/// rendered primitives, including Media Browser's parent group, in both requested themes.
|
||||
#[test]
|
||||
fn focused_panel_outline_is_not_covered_by_child_backgrounds() {
|
||||
fn rectangles<'a>(shape: &'a egui::Shape, clip: egui::Rect, out: &mut Vec<(&'a egui::epaint::RectShape, egui::Rect)>) {
|
||||
match shape {
|
||||
egui::Shape::Rect(rect) => out.push((rect, clip)),
|
||||
egui::Shape::Vec(shapes) => shapes.iter().for_each(|shape| rectangles(shape, clip, out)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let mut d = Driver::demo();
|
||||
for theme in ["dark", "light"] {
|
||||
d.ok("ui.set", json!({"theme": theme}));
|
||||
for panel in ["Program", "Text", "LumetriScopes", "EssentialSound", "Timeline", "TextToSpeech", "MediaBrowser"] {
|
||||
d.ok("ui.panel.show", json!({"panel": panel}));
|
||||
d.ok("ui.set", json!({"focused": panel}));
|
||||
d.frames(3);
|
||||
d.snapshot(&format!("focus-{theme}-{panel}"), None);
|
||||
let mut rects = Vec::new();
|
||||
for shape in &d.harness.output().shapes {
|
||||
rectangles(&shape.shape, shape.clip_rect, &mut rects);
|
||||
}
|
||||
let focus = d.harness.state().tokens.focus;
|
||||
let outlines: Vec<_> = rects
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, (r, _))| r.stroke.color == focus && r.stroke.width == 1.0 && r.rect.width() > 100.0 && r.rect.height() > 80.0)
|
||||
.collect();
|
||||
assert_eq!(outlines.len(), 1, "{theme} {panel}: one focus outline for the whole parent group");
|
||||
let (at, (outline, _)) = outlines[0];
|
||||
let bounds = outline.rect;
|
||||
let strips = [
|
||||
egui::Rect::from_min_max(bounds.min, egui::pos2(bounds.max.x, bounds.min.y + 1.0)),
|
||||
egui::Rect::from_min_max(egui::pos2(bounds.min.x, bounds.max.y - 1.0), bounds.max),
|
||||
egui::Rect::from_min_max(bounds.min, egui::pos2(bounds.min.x + 1.0, bounds.max.y)),
|
||||
egui::Rect::from_min_max(egui::pos2(bounds.max.x - 1.0, bounds.min.y), bounds.max),
|
||||
];
|
||||
for (child, clip) in &rects[at + 1..] {
|
||||
if child.fill.a() != 0 {
|
||||
let painted = child.rect.intersect(*clip);
|
||||
assert!(
|
||||
strips.iter().all(|edge| !edge.intersect(painted).is_positive()),
|
||||
"{theme} {panel}: a later child background {painted:?} covers the focus outline {bounds:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue