Toolbar: drag commands from drop-downs onto the toolbar; pin icon; Customize Toolbar… (#295)

* Toolbar drop-downs highlight the row under the pointer and the keyboard focus (#288)

A panel drop-down's command rows are full-width rows that take the theme's hover background
(icon, label and shortcut on it) when hovered or focused. Up/Down move the focus through the
enabled rows, Enter starts the command, Escape closes the drop-down. Rows publish
`dropdown:<id>` and the highlighted one `dropdown_hot:<id>`; scenario s46 checks pointer and
keyboard highlight.

Fixes #288

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

* Toolbar: drag commands from drop-downs onto the toolbar; pin icon; Customize Toolbar… (#289)

- A panel drop-down row drags onto the toolbar (a button or a panel's free space, with the
  drop line) and is pinned there; the dragged command's icon follows the pointer.
- A toolbar button dragged off the toolbar, or back into the open drop-down, leaves it (its
  icon shows a cross while releasing would remove it).
- A hovered drop-down row shows a pin at its end: click to pin or unpin.
- Right-click on the toolbar's empty space: Customize Toolbar… (a window listing the tab's
  commands with check boxes, and Reset Toolbar) and Reset Toolbar; command menus have
  Customize Toolbar… too.
- Still per workspace and tab, kept with the preferences. Toolbar buttons also publish
  `button:<id>`; scenario s47 drags a row to the toolbar, unpins by dragging off and into the
  drop-down, uses the pin icon and Customize Toolbar…, and checks it survives a restart.

Fixes #289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

* Toolbar drop-down pin: a push pin drawn in code (upright and filled when pinned); control protocol lists the toolbar handles

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-12 10:27:25 -04:00
1 parent 3d99ab4bb1
commit 2cac9cad6a
7 files changed
+490 -27

No files matched your search

+7 -1
View File
@@ -54,6 +54,8 @@ pub enum Target {
ToolbarCommand {
id: String,
},
/// The toolbar's empty space.
Toolbar,
/// The workspace switcher.
Workspace,
/// The Named Views folder, and one view (saved or standard) in it.
@@ -240,6 +242,7 @@ pub fn target_bodies(app: &SolveApp, target: &Target) -> Vec<String> {
| Target::Units
| Target::Joint { .. }
| Target::ToolbarCommand { .. }
| Target::Toolbar
| Target::Workspace
| Target::NamedViews
| Target::NamedView { .. } => Vec::new(),
@@ -298,6 +301,7 @@ pub fn items(app: &SolveApp, target: &Target) -> Vec<Item> {
Target::NamedViews => vec![act("ui.newView", "New Named View", "perspective")],
Target::Joint { id } => joint_items(app, *id),
Target::ToolbarCommand { id } => crate::toolbar_custom::command_items(app, id),
Target::Toolbar => crate::toolbar_custom::toolbar_items(app),
Target::Workspace => {
let mut v = vec![act("ui.workspace", "Design", "box").key("current")];
for w in ["Generative Design", "Render", "Animation", "Simulation", "Manufacture", "Drawing"] {
@@ -879,7 +883,9 @@ pub fn run_item(app: &mut SolveApp, item: &Item, at: Pos2) {
let _ = app.run("browser.visibility", json!({"visible": true, "paths": [p["path"]], "isolate": true}));
}
"ui.canvasVisible" => drop(app.run("canvas.edit", p)),
"ui.toolbarPin" | "ui.toolbarRemove" | "ui.toolbarReset" | "ui.shortcutPin" => crate::toolbar_custom::run(app, &item.id, &p),
"ui.toolbarPin" | "ui.toolbarRemove" | "ui.toolbarReset" | "ui.toolbarCustomize" | "ui.shortcutPin" => {
crate::toolbar_custom::run(app, &item.id, &p)
}
"ui.workspace" => {}
"ui.findJoint" => {
if let Some(id) = id_of(&p, "joint") {