From f7590b1aa89139734b716a30baaecc5b41afc611 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 7 Aug 2026 14:29:01 +0300 Subject: [PATCH] feat(plugin-api): let add-ons ask for a visual style by name Removing the binary wireframe event left add-ons with no way to set a visual style except by spelling out a command string. Give them the intent back, in the vocabulary everything else now speaks. The name is carried as text rather than the render-mode type: this crate is dependency-free by default and only pulls acadrust in behind the host feature, which is not a weight to add to the manifest contract for one enum. The host resolves it against the same list its ribbon, its picker and its commands read, so an add-on can offer exactly the styles the application does and no others. An unknown name says so and lists the ones that exist, from that same list. Co-Authored-By: Claude Opus 5 --- crates/ocs_plugin_api/src/ribbon.rs | 9 +++++++++ src/app/update/dialog.rs | 15 +++++++++++++++ src/ui/ribbon/widgets.rs | 8 ++++++++ 3 files changed, 32 insertions(+) diff --git a/crates/ocs_plugin_api/src/ribbon.rs b/crates/ocs_plugin_api/src/ribbon.rs index 282012897..60e5784a5 100644 --- a/crates/ocs_plugin_api/src/ribbon.rs +++ b/crates/ocs_plugin_api/src/ribbon.rs @@ -17,6 +17,15 @@ pub enum ModuleEvent { /// Remove all loaded models from the scene. #[allow(dead_code)] ClearModels, + /// Put the active viewport in a named visual style. + /// + /// The name is one of the render modes the viewport can be drawn in: + /// `WIREFRAME2D`, `WIREFRAME3D`, `HIDDENLINE`, `FLATSHADED`, + /// `GOURAUDSHADED`, `FLATSHADEDWITHEDGES`, `GOURAUDSHADEDWITHEDGES` + /// (case-insensitive). The host resolves it against the same list its own + /// ribbon and commands read, so an add-on offers exactly the styles the + /// application does. An unknown name is reported and nothing changes. + SetVisualStyle(String), /// Toggle the layer manager panel. ToggleLayers, /// Ask the host to open a native file picker. On selection the host diff --git a/src/app/update/dialog.rs b/src/app/update/dialog.rs index d9cb5fd48..4e82f7f58 100644 --- a/src/app/update/dialog.rs +++ b/src/app/update/dialog.rs @@ -158,6 +158,21 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven self.tabs[i].properties = PropertiesPanel::empty(); self.command_line.push_output(crate::t!("Scene cleared.").as_ref()); } + ModuleEvent::SetVisualStyle(name) => { + use crate::modules::view::visual_style; + match visual_style::mode_for_keyword(&name) { + Some(mode) => return Task::done(Message::SetRenderMode(mode)), + None => { + // Name the styles that do exist, from the same + // list every other caller reads. + self.command_line.push_error( + crate::tf!("Unknown visual style \"{name}\".").as_ref(), + ); + self.command_line + .push_info(visual_style::keyword_prompt()); + } + } + } ModuleEvent::ToggleLayers => { return Task::done(Message::ToggleLayers); } diff --git a/src/ui/ribbon/widgets.rs b/src/ui/ribbon/widgets.rs index ae77169cd..a2807cf9b 100644 --- a/src/ui/ribbon/widgets.rs +++ b/src/ui/ribbon/widgets.rs @@ -1122,6 +1122,14 @@ pub fn module_event_to_message(event: ModuleEvent) -> Message { ModuleEvent::Command(cmd) => Message::Command(cmd), ModuleEvent::OpenFileDialog => Message::OpenFile, ModuleEvent::ClearModels => Message::ClearScene, + ModuleEvent::SetVisualStyle(name) => { + match crate::modules::view::visual_style::mode_for_keyword(&name) { + Some(mode) => Message::SetRenderMode(mode), + // Report through the command line rather than silently doing + // nothing, so a plugin author sees the typo. + None => Message::Command(format!("VISUALSTYLES {name}")), + } + } ModuleEvent::ToggleLayers => Message::ToggleLayers, // Needs the tool context + async picker — route through the normal // ribbon-click handler rather than a direct 1:1 message.