Improvements to DockArea for nested Docks and styling - #2840
Conversation
gpui's TestWindow panics (unimplemented!) in its HasWindowHandle impl instead of returning Err, so the graceful `.ok()?` bail in the input and accessibility ns_view helpers never fires -- a downstream crate's tests that build a Root or render an Input over a test window panic. Probe the handle under catch_unwind and no-op when there is no backing AppKit window.
Lets a consumer close a panel it only holds a PanelId for (e.g. an unresolved/InvalidPanel leaf from a restored layout), where remove_panel would need a live Entity<P>.
A cross-DockArea drag -- dragging a tab between an outer dock and a nested dock hosted inside one of its own panels -- would insert a PanelId with no backing entity into the target tree while the panel stayed registered in its real owner: a ghost tab in one, a duplicate in the other. Guard move_panel to no-op when the panel is not owned here, so the panel stays in its source. Covered by a_move_of_an_unowned_panel_is_ignored.
Record each tab-group leaf's on-screen rect during render (via on_prepaint) into a node_bounds map, exposed as DockArea::node_bounds. Lets a host paint spatial overlays over panes -- e.g. a vimium-style pane picker badging each pane -- which the pure-data tree cannot express. The wrapper that captures the rect carries no sizing (that stays on the parent resizable_panel), so split layout is unchanged.
…utton Panels can override Panel::render_tab to have the final say over their own tab -- restyle it, swap the label, add a prefix icon, or add/drop a suffix -- while the tab bar keeps its layout, drag/drop, and activation. The tab group builds the fully wired Tab and routes it through the panel; the default returns it unchanged. Closable panels get a built-in close (X) button suffix. It stops click propagation so closing never also selects the tab, and closes by panel id so it targets its own tab regardless of which is active.
2223042 to
c74ada0
Compare
|
Thanks for this PR! The tests are careful, and the I have one concern about the new close button. In if !self.constraints.is_closable() { return; }
if !self.draggable(cx) { return; } // = !is_locked() && !is_last_panel()So the X button can be drawn but do nothing when:
This is the same trap the
The smallest fix is to ask .when(group.is_draggable() && panel.closable(cx), |this| { ... })The current tests do not catch this. One note if you also want to cover the |
huacnlee
left a comment
There was a problem hiding this comment.
Thanks for putting this together. I found two issues that should be addressed before merging:
-
DockArea::node_boundscan return stale bounds for removed nodes. Its public documentation says it returnsNonewhen a node is not a rendered tab group, but entries are never removed fromnode_bounds. After a leaf is removed, a caller retaining itsNodeIdcan still receive an obsolete on-screen rectangle. Please clear stale entries or otherwise make the implementation match the documented contract, and add a regression test covering node removal. -
The accessibility workaround catches panics around the entire
ns_view(window)call. This can silently hide unrelated failures in handle matching or pointer conversion. Please narrow thecatch_unwindscope toHasWindowHandle::window_handle, as the native input implementation does. A regression test for the expected test-window panic path would also be valuable.
There is also a testing gap in the new close button behavior: the current tests verify only that the button is rendered. Please add an interaction test that clicks the close button on a non-active tab and verifies that the correct PanelId is removed without selecting or otherwise triggering the tab click handler.
The targeted tests currently included in this PR pass locally.
I'm stretching the "1 PR to solve 1 problem" request a bit, but unfortunately GitHub does not yet support stacked PRs across forks which would make trying to upstream these independently somewhat annoying.
Summary of changes: Adds some improvements to the
DockAreato make managing docks, creating nested docks, and styling docks a bit easier.Description
unreachable!) when attempting to get aTestWindowhandle. This catches the panic and gracefully recovers. I don't like the solution here, but it works for now. gpui-component does not hit this panic today becausemacos_accessibilityis disabled in tests, but it may be required for some tests to do hit detection.DockArea::remove_panel_idpublic to support scenarios where you may have a panel ID but not a reference to the entity.pre_paint, records leaf nodes render areas to allow for possibilities like e.g. vimimum style tab pickers (shown below).PanelView::render_tabcallback which allows for full customization of theTab. Changes default behavior so that closeable tabs have a "Close Tab"-icon suffix button for closing.Media
Screenshot of the tabs
The
DockArea::move_panelchanges help allow this:move_panels_compressed.mp4
And the overlay mentioned (in my application, but unblocked by these changes):
overlay_compressed.mp4
How to Test
Added new tests.
Checklist
cargo runfor story tests related to the changes.