forked from 1b-agent/opencadstudio-upstream
fix(ribbon): highlight follows each tool's mechanism; start-tab dimming (#355)
Tool highlights used to stick: every click set active_tool, but only interactive commands and a hand-maintained per-modal list ever cleared it, so one-shots (Cleanup/AUDIT, view actions) and unlisted dialogs (Customization/ALIASEDIT, CUI, Plugin Manager…) stayed blue forever. Now the rule is mechanical: state toggles light from state only (the click highlight drops immediately), interactive commands stay lit while running, dialog openers stay lit until the modal closes (generic clear replaces the per-modal list), and one-shots never keep it — the dispatch site turns the highlight off when nothing stayed running. On the Start tab, tools whose command the start gate refuses now render dimmed (grey icon + label) across all button styles, dropdowns and the quick-access strip; start_allowed() is the single shared authority. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
7a93ba82b3
commit
b7457ba09d
7 files changed
+159
-90
No files matched your search
+27
-21
@@ -108,27 +108,7 @@ impl OpenCADStudio {
|
||||
// editors (shortcuts, aliases) — none of them read the scene. This is
|
||||
// the single place that decides; `on_ribbon_tool_click` defers to it
|
||||
// rather than keeping a second, blunter copy (#388, #389).
|
||||
if self.tabs[i].is_start
|
||||
&& !matches!(
|
||||
cmd,
|
||||
"NEW"
|
||||
| "OPEN"
|
||||
| "EXIT"
|
||||
| "QUIT"
|
||||
| "REPORT"
|
||||
| "CHANGELOG"
|
||||
| "ABOUT"
|
||||
| "PLUGINS"
|
||||
| "PLUGINMANAGER"
|
||||
| "DONATE"
|
||||
| "WEBVERSION"
|
||||
| "HELP"
|
||||
| "CUI"
|
||||
| "ALIASEDIT"
|
||||
| "CUILOAD"
|
||||
| "CUIIMPORT"
|
||||
)
|
||||
{
|
||||
if self.tabs[i].is_start && !start_allowed(cmd) {
|
||||
self.command_line
|
||||
.push_info("No drawing open. Use NEW or OPEN to start a drawing.");
|
||||
return Task::none();
|
||||
@@ -235,6 +215,32 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether `cmd` makes sense on the Start (welcome) tab — document lifecycle,
|
||||
/// links, and app-wide configuration; nothing that reads the scene. Single
|
||||
/// source of truth: the dispatch gate refuses everything else, and the ribbon
|
||||
/// dims the tools this rejects.
|
||||
pub fn start_allowed(cmd: &str) -> bool {
|
||||
matches!(
|
||||
cmd,
|
||||
"NEW"
|
||||
| "OPEN"
|
||||
| "EXIT"
|
||||
| "QUIT"
|
||||
| "REPORT"
|
||||
| "CHANGELOG"
|
||||
| "ABOUT"
|
||||
| "PLUGINS"
|
||||
| "PLUGINMANAGER"
|
||||
| "DONATE"
|
||||
| "WEBVERSION"
|
||||
| "HELP"
|
||||
| "CUI"
|
||||
| "ALIASEDIT"
|
||||
| "CUILOAD"
|
||||
| "CUIIMPORT"
|
||||
)
|
||||
}
|
||||
|
||||
// ── Autocomplete registry — one-shot commands ──────────────────────────────
|
||||
// These commands dispatch a single action (file ops, view, layer/style
|
||||
// managers, undo/redo, …) rather than installing an interactive `CadCommand`,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ mod config;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use automation::{export_headless, serve};
|
||||
mod command_driver;
|
||||
mod commands;
|
||||
pub(crate) mod commands;
|
||||
mod document;
|
||||
mod expr_eval;
|
||||
mod helpers;
|
||||
|
||||
@@ -114,7 +114,20 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
|
||||
self.ribbon.note_panel_tool(&tool_id);
|
||||
self.ribbon.activate_tool(&tool_id);
|
||||
match event {
|
||||
ModuleEvent::Command(cmd) => return self.dispatch_command(&cmd),
|
||||
ModuleEvent::Command(cmd) => {
|
||||
let task = self.dispatch_command(&cmd);
|
||||
// One-shot tools (view changes, clipboard, toggles,
|
||||
// audits…) leave nothing running: no interactive
|
||||
// command and no dialog. Their highlight would stick
|
||||
// forever — turn it off now. Interactive commands and
|
||||
// dialog owners keep theirs; the command end / modal
|
||||
// close clears those. (#355)
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].active_cmd.is_none() && self.active_modal.is_none() {
|
||||
self.ribbon.deactivate_tool();
|
||||
}
|
||||
return task;
|
||||
}
|
||||
ModuleEvent::OpenFileDialog => {
|
||||
self.command_line
|
||||
.push_info("Open DWG/DXF: not yet implemented.");
|
||||
@@ -166,6 +179,10 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
|
||||
);
|
||||
}
|
||||
}
|
||||
// Every non-Command event above is a one-shot (state toggle,
|
||||
// clear, dialog spawn) — nothing stays running to clear the
|
||||
// highlight later, so turn it off here. (#355)
|
||||
self.ribbon.deactivate_tool();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
|
||||
+8
-28
@@ -81,33 +81,6 @@ impl OpenCADStudio {
|
||||
self.scale_stage_discard();
|
||||
}
|
||||
match self.active_modal {
|
||||
Some(Layers) => self.ribbon.deactivate_tool_if("LAYERS"),
|
||||
Some(Plot) => {
|
||||
self.ribbon.deactivate_tool_if("PLOT");
|
||||
self.ribbon.deactivate_tool_if("PRINT");
|
||||
self.ribbon.deactivate_tool_if("PAGESETUP");
|
||||
}
|
||||
Some(TextStyle) => {
|
||||
self.ribbon.deactivate_tool_if("STYLE");
|
||||
self.ribbon.deactivate_tool_if("TEXTSTYLE");
|
||||
}
|
||||
Some(TableStyle) => self.ribbon.deactivate_tool_if("TABLESTYLE"),
|
||||
Some(MlStyle) => self.ribbon.deactivate_tool_if("MLSTYLE"),
|
||||
Some(MLeaderStyle) => self.ribbon.deactivate_tool_if("MLEADERSTYLE"),
|
||||
Some(LayoutManager) => {
|
||||
self.ribbon.deactivate_tool_if("LAYOUTMANAGER");
|
||||
self.ribbon.deactivate_tool_if("LAYOUTPANEL");
|
||||
}
|
||||
Some(Plotstyle) => {
|
||||
self.ribbon.deactivate_tool_if("PLOTSTYLE");
|
||||
self.ribbon.deactivate_tool_if("STYLESMANAGER");
|
||||
}
|
||||
Some(DimStyle) => self.ribbon.deactivate_tool_if("DIMSTYLE"),
|
||||
Some(Shortcuts) => {
|
||||
self.ribbon.deactivate_tool_if("SHORTCUTS");
|
||||
self.ribbon.deactivate_tool_if("KEYBOARD");
|
||||
}
|
||||
Some(About) => self.ribbon.deactivate_tool_if("ABOUT"),
|
||||
// Dismissing these via ✕ is the cancel/decline path.
|
||||
Some(Unsaved) => self.pending_close = None,
|
||||
Some(AssocPrompt) => self.mark_assoc_prompted(),
|
||||
@@ -125,10 +98,17 @@ impl OpenCADStudio {
|
||||
// style editors. Committing happens only through the Apply button.
|
||||
Some(Aliases) => {
|
||||
self.alias_editor_rows.clear();
|
||||
self.ribbon.deactivate_tool_if("ALIASEDIT");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// The tool that opened this dialog is done with it now. Keep the
|
||||
// highlight only while an interactive command still runs (it owns
|
||||
// it). Replaces the old per-modal deactivate_tool_if list, which
|
||||
// missed every newly added dialog (CUI, Plugin Manager, Point
|
||||
// Style, Attribute Editor…). (#355)
|
||||
if self.tabs[self.active_tab].active_cmd.is_none() {
|
||||
self.ribbon.deactivate_tool();
|
||||
}
|
||||
self.active_modal = None;
|
||||
// Recentre / reset the size of the next dialog and drop any drag.
|
||||
self.modal_offset = iced::Vector::ZERO;
|
||||
|
||||
@@ -1304,6 +1304,7 @@ impl OpenCADStudio {
|
||||
if !self.clean_screen {
|
||||
col = col.push(self.ribbon.view(
|
||||
is_paper,
|
||||
self.tabs[self.active_tab].is_start,
|
||||
self.tabs[self.active_tab].history.undo_stack.len(),
|
||||
self.tabs[self.active_tab].history.redo_stack.len(),
|
||||
));
|
||||
|
||||
Reference in new issue
Block a user