docking: a press in a group header focuses the shown panel

Host widgets in the header, such as a menu button or the host's own tabs,
focus the panel the way a press on its tab or body does.
This commit is contained in:
aiongg committed 2026-10-20 03:47:12 +00:00
1 parent 91e8cf401e
commit 46f2ffd654
4 files changed
+13 -4

No files matched your search

+4 -1
View File
@@ -284,7 +284,10 @@ fn top_border_drags_the_group_and_the_menu_button_only_clicks() {
assert!(held.group_drag.is_none());
let out = d.step(vec![button(menu + vec2(0.0, 200.0), false)]);
assert!(out.actions.iter().all(|a| !matches!(a, Action::MoveGroup { .. } | Action::Move { .. } | Action::Float { .. })), "{:?}", out.actions);
d.click(menu);
// A press in the header focuses the group's shown panel, like a press on its tab.
let pressed = d.step(vec![Event::PointerMoved(menu), button(menu, true)]);
assert_eq!(pressed.focused, Some(3));
d.step(vec![button(menu, false)]);
assert_eq!(d.content.header_clicks, 1);
let out = d.drag(over_tab, d.tab(1).center());
+5 -1
View File
@@ -75,6 +75,10 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
let mut child = ui.new_child(UiBuilder::new().id(self.id.with(("header", selected))).max_rect(header));
child.set_clip_rect(header.intersect(ui.clip_rect()));
self.content.group_header(&mut child, panels, selected, floating);
// A press in the header focuses the shown panel, as a press on its tab does.
if child.rect_contains_pointer(header) && child.input(|i| i.pointer.any_pressed()) {
self.output.focused = Some(selected.clone());
}
}
// The drag bar keeps its reserved width: tabs overflow before it narrows.
let bar_width = self.style.drag_bar_width.clamp(0.0, (strip.width() - header_width).max(0.0));
@@ -176,7 +180,7 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
}
let active = response.has_focus() || response.hovered();
if movable {
// A grip mark at rest, centerd in the bar's reserved width beside the header.
// A grip mark at rest, centered in the bar's reserved width beside the header.
let grip = if self.style.right_to_left {
Rect::from_min_max(hit.min, pos2((hit.left() + self.style.drag_bar_width).min(hit.right()), hit.bottom()))
} else {
+2 -1
View File
@@ -218,7 +218,8 @@ pub struct DockOutput<P> {
pub actions: Vec<Action<P>>,
pub error: Option<DockError>,
/// The panel the user focused this frame: a clicked tab or menu entry, a drop, or a press
/// of any pointer button in a panel body, stripless panels included. Only user input sets
/// of any pointer button in a panel body (stripless panels included) or in a group header,
/// which focuses the group's shown panel. Only user input sets
/// it; [`DockArea::raise_panel`] and host commands do not.
pub focused: Option<P>,
/// Whole-floating-group gesture identity; host may display its own group drop preview.
+2 -1
View File
@@ -112,7 +112,8 @@ survives.
`DockOutput` also has:
- `focused`: the panel the user focused this frame: a clicked tab, a drop, or a press of any
pointer button in a panel body, bare and protected panels included. Commands, `raise_panel` and
pointer button in a panel body (bare and protected panels included) or in the group header,
which focuses the group's shown panel. Commands, `raise_panel` and
workspace resets never set it; a host that tracks the last focused panel clears it when a reset
or command hides, closes or moves that panel.
- `events`: requests outside the layout, such as `DockEvent::ToggleMaximize` (Frame) and