Dock: flush title bars and a vertical title bar for floating panels

Every docked panel now shows its title bar flush along the top, like the
Properties panel: dock::frame takes the title bar separately and pads
only the content below it.

A floating panel drops its horizontal title bar for a vertical one on
the side facing the nearer workspace edge. Close and the auto-hide pin
sit at the top; the panel's icon sits at the bottom with the title
reading upward above it. The free part of the bar drags the panel. With
auto-hide on, a floating panel shrinks to its title bar until hovered.

Panel views take a dock::Chrome (auto-collapse plus floating) in place
of the bare auto-collapse flag, so the shared title bar knows when to
step aside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
This commit is contained in:
Claude committed 2026-10-09 10:11:02 +00:00
1 parent 089f572373
commit 03763ff197
10 files changed
+271 -81

No files matched your search

+3 -3
View File
@@ -659,8 +659,8 @@ fn options_card<'a>(palette: &'a BlockPalette) -> Element<'a, Message> {
}
/// Build the docked panel element from the palette state.
pub fn view(palette: &BlockPalette, width: f32, auto_collapse: bool) -> Element<'_, Message> {
let title_bar = crate::ui::dock::title_bar(PanelId::BlockPalette, crate::t!("Blocks").into_owned(), auto_collapse);
pub fn view(palette: &BlockPalette, width: f32, chrome: crate::ui::dock::Chrome) -> Element<'_, Message> {
let title_bar = crate::ui::dock::title_bar(PanelId::BlockPalette, crate::t!("Blocks").into_owned(), chrome);
let tabs = {
let buttons = [Tab::Current, Tab::Recent, Tab::Favorites, Tab::Libraries].map(|t| {
@@ -801,7 +801,7 @@ pub fn view(palette: &BlockPalette, width: f32, auto_collapse: bool) -> Element<
.into()
};
crate::ui::dock::frame(column![title_bar, top, body, options_card(palette)].spacing(6), width)
crate::ui::dock::frame(title_bar, column![top, body, options_card(palette)].spacing(6), width)
}
/// Width of the ribbon's block gallery.
+3 -3
View File
@@ -97,10 +97,10 @@ pub fn view<'a>(
document: &'a CadDocument,
open_sketch: Option<&'a str>,
width: f32,
auto_collapse: bool,
chrome: crate::ui::dock::Chrome,
) -> Element<'a, Message> {
let title_bar =
crate::ui::dock::title_bar(PanelId::Browser, crate::t!("Browser").into_owned(), auto_collapse);
crate::ui::dock::title_bar(PanelId::Browser, crate::t!("Browser").into_owned(), chrome);
let mut tree = column![].spacing(1);
@@ -143,5 +143,5 @@ pub fn view<'a>(
.width(Fill)
.height(Fill);
crate::ui::dock::frame(column![title_bar, body].spacing(6), width)
crate::ui::dock::frame(title_bar, column![body].spacing(6), width)
}
+3 -3
View File
@@ -530,9 +530,9 @@ pub fn view<'a>(
doc_id: u64,
epoch: u64,
width: f32,
auto_collapse: bool,
chrome: crate::ui::dock::Chrome,
) -> Element<'a, Message> {
let title_bar = crate::ui::dock::title_bar(PanelId::Count, crate::t!("Count").into_owned(), auto_collapse);
let title_bar = crate::ui::dock::title_bar(PanelId::Count, crate::t!("Count").into_owned(), chrome);
let body = match mode {
Some(mode) if mode.target.is_some() => mode_view(palette, mode, doc),
_ => {
@@ -550,7 +550,7 @@ pub fn view<'a>(
list_view(palette, &instances)
}
};
crate::ui::dock::frame(column![title_bar, body].spacing(6), width)
crate::ui::dock::frame(title_bar, column![body].spacing(6), width)
}
fn bar_button<'a>(icon: Element<'a, Message>, tip: String, m: Option<CountMsg>) -> Element<'a, Message> {
+3 -3
View File
@@ -235,10 +235,10 @@ pub fn view<'a>(
document: &'a CadDocument,
selected: &[Handle],
width: f32,
auto_collapse: bool,
chrome: crate::ui::dock::Chrome,
) -> Element<'a, Message> {
let title_bar =
crate::ui::dock::title_bar(PanelId::PointCloudManager, crate::t!("Point Cloud Manager").into_owned(), auto_collapse);
crate::ui::dock::title_bar(PanelId::PointCloudManager, crate::t!("Point Cloud Manager").into_owned(), chrome);
let query = state.search.trim().to_lowercase();
let matches = |label: &str| query.is_empty() || label.to_lowercase().contains(&query);
// Searching opens every node so the matches show.
@@ -354,5 +354,5 @@ pub fn view<'a>(
.padding([4, 8])
.size(12);
crate::ui::dock::frame(column![title_bar, card, search].spacing(6), width)
crate::ui::dock::frame(title_bar, column![card, search].spacing(6), width)
}
+3 -3
View File
@@ -936,9 +936,9 @@ fn heading(label: &str) -> Element<'static, Message> {
.into()
}
pub fn view<'a>(state: &'a SheetSetManager, width: f32, auto_collapse: bool) -> Element<'a, Message> {
pub fn view<'a>(state: &'a SheetSetManager, width: f32, chrome: crate::ui::dock::Chrome) -> Element<'a, Message> {
let title_bar =
crate::ui::dock::title_bar(PanelId::SheetSetManager, t!("Sheet Set Manager").into_owned(), auto_collapse);
crate::ui::dock::title_bar(PanelId::SheetSetManager, t!("Sheet Set Manager").into_owned(), chrome);
let mut picks: Vec<Pick> =
state.sets.iter().enumerate().map(|(i, db)| Pick(Some(i), db.name().to_string())).collect();
picks.push(Pick(None, t!("Open...").into_owned()));
@@ -1040,7 +1040,7 @@ pub fn view<'a>(state: &'a SheetSetManager, width: f32, auto_collapse: bool) ->
let hint = text(t!("Double-click opens a sheet. Right-click for more commands.").into_owned())
.size(10)
.style(muted_style);
crate::ui::dock::frame(column![title_bar, combo, tabs, card, hint].spacing(6), width)
crate::ui::dock::frame(title_bar, column![combo, tabs, card, hint].spacing(6), width)
}
// ── dialogs ──────────────────────────────────────────────────────────────────
+2 -2
View File
@@ -542,7 +542,7 @@ impl XrefManagerPanel {
pub fn view<'a>(
&'a self,
width: f32,
auto_collapse: bool,
chrome: crate::ui::dock::Chrome,
missing: usize,
doc: &'a CadDocument,
) -> Element<'a, Message> {
@@ -550,7 +550,7 @@ impl XrefManagerPanel {
let title_bar = crate::ui::dock::title_bar(
PanelId::ExternalReferences,
format!("{} ({})", crate::t!("External References").as_ref(), self.entries.len()),
auto_collapse,
chrome,
);
// Table content width: column widths plus gutters, stretched to the
// dock when wider so rows fill the panel; narrower docks sidescroll.