diff --git a/crates/ui/src/docking/group_tests.rs b/crates/ui/src/docking/group_tests.rs index 059634b84..c87ab8f9f 100644 --- a/crates/ui/src/docking/group_tests.rs +++ b/crates/ui/src/docking/group_tests.rs @@ -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()); diff --git a/crates/ui/src/docking/render/group.rs b/crates/ui/src/docking/render/group.rs index bb313e1f4..83c24ea89 100644 --- a/crates/ui/src/docking/render/group.rs +++ b/crates/ui/src/docking/render/group.rs @@ -75,6 +75,10 @@ impl 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 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 { diff --git a/crates/ui/src/docking/surface.rs b/crates/ui/src/docking/surface.rs index dc1c2a873..ff5789a02 100644 --- a/crates/ui/src/docking/surface.rs +++ b/crates/ui/src/docking/surface.rs @@ -218,7 +218,8 @@ pub struct DockOutput

{ pub actions: Vec>, pub error: Option, /// 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

, /// Whole-floating-group gesture identity; host may display its own group drop preview. diff --git a/docs/ui-docking.md b/docs/ui-docking.md index 5ceb81fd4..a7586f9e7 100644 --- a/docs/ui-docking.md +++ b/docs/ui-docking.md @@ -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