feat(xref): row-level context menu actions and unified split-button toolbar

Right-click actions bound to the row under the cursor, split-button toolbar groups with shared borders and hover states, and a notice when an operation needs a selection first.
This commit is contained in:
Karim Jerbi committed 2026-09-15 23:56:31 +01:00
1 parent 494a872e8d
commit 22a9bd602c
28 files changed
+352 -168

No files matched your search

+3 -37
View File
@@ -686,6 +686,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
self.dock_drag_target = None;
self.xref_col_drag = None;
self.xref_col_last = None;
self.xref_split_drag = false;
iced::Task::none()
}
}
@@ -908,6 +909,8 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
.collect()
};
if picked.is_empty() {
self.command_line
.push_info(crate::t!("Select a reference first.").as_ref());
return;
}
let needs_host = matches!(
@@ -1241,43 +1244,6 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
self.post_ref_op(i);
self.refresh_xref_manager();
}
/// Apply the details-pane path draft to the anchor entry (verbatim
/// store, same engine fn as `XREF Path`).
pub(crate) fn xref_manager_path_apply(&mut self) {
if cfg!(target_arch = "wasm32") {
self.command_line.push_error(crate::t!("Reference changes are not available on web — the reference list is read-only.").as_ref());
return;
}
let i = self.active_tab;
let anchor = self.xref_manager.anchor.and_then(|a| {
self.xref_manager
.entries
.get(a)
.filter(|_| !self.xref_manager.nested.contains(&a))
.map(|e| (e.key, e.name.clone()))
});
let Some((key, _)) = anchor else {
return;
};
let new_raw = self.xref_manager.path_input.clone();
if new_raw.is_empty() {
return;
}
self.push_undo_snapshot(i, "XREF-PATH");
match crate::io::xref::set_ref_path(&mut self.tabs[i].scene.document, key, &new_raw)
{
Ok(name) => {
self.command_line.push_output(crate::tf!(
"XREF: Path set for \"{}\" — Reload to apply.",
name
).as_ref());
self.post_ref_op(i);
}
Err(msg) => self.command_line.push_error(msg.as_str()),
}
self.refresh_xref_manager();
}
}
#[cfg(test)]
+23 -6
View File
@@ -2192,6 +2192,25 @@ impl OpenCADStudio {
self.xref_col_last = None;
Task::none()
}
Message::XrefSplitGrab => {
self.xref_split_drag = true;
self.xref_col_last = None;
Task::none()
}
Message::XrefSplitMove(p) => {
if self.xref_split_drag {
if let Some(last) = self.xref_col_last {
self.xref_manager.drag_table_by(p.y - last.y);
}
self.xref_col_last = Some(p);
}
Task::none()
}
Message::XrefSplitRelease => {
self.xref_split_drag = false;
self.xref_col_last = None;
Task::none()
}
Message::XrefManagerTogglePreview => {
self.xref_manager.show_preview ^= true;
Task::none()
@@ -2284,12 +2303,10 @@ impl OpenCADStudio {
self.xref_manager_op(op);
Task::none()
}
Message::XrefManagerPathInput(text) => {
self.xref_manager.path_input = text;
Task::none()
}
Message::XrefManagerPathApply => {
self.xref_manager_path_apply();
Message::XrefRowOp(index, op) => {
// Row-scoped op: select the row first, then run the op.
self.xref_manager.right_click_select(index);
self.xref_manager_op(op);
Task::none()
}
Message::XrefFindReplacePrompt => {