diff --git a/assets/icons/cascade.svg b/assets/icons/cascade.svg
new file mode 100644
index 000000000..ce7f11b19
--- /dev/null
+++ b/assets/icons/cascade.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/data_extract.svg b/assets/icons/data_extract.svg
new file mode 100644
index 000000000..ddcb26568
--- /dev/null
+++ b/assets/icons/data_extract.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/data_link.svg b/assets/icons/data_link.svg
new file mode 100644
index 000000000..ff265870b
--- /dev/null
+++ b/assets/icons/data_link.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/file_tabs.svg b/assets/icons/file_tabs.svg
new file mode 100644
index 000000000..e33a0acd1
--- /dev/null
+++ b/assets/icons/file_tabs.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/layout_tabs.svg b/assets/icons/layout_tabs.svg
new file mode 100644
index 000000000..4758ae242
--- /dev/null
+++ b/assets/icons/layout_tabs.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/navbar.svg b/assets/icons/navbar.svg
new file mode 100644
index 000000000..75c94d7ae
--- /dev/null
+++ b/assets/icons/navbar.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/properties.svg b/assets/icons/properties.svg
new file mode 100644
index 000000000..76cc8b652
--- /dev/null
+++ b/assets/icons/properties.svg
@@ -0,0 +1,15 @@
+
diff --git a/assets/icons/sheetset.svg b/assets/icons/sheetset.svg
new file mode 100644
index 000000000..41ec42d8d
--- /dev/null
+++ b/assets/icons/sheetset.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/tile_horiz.svg b/assets/icons/tile_horiz.svg
new file mode 100644
index 000000000..0b9c0308d
--- /dev/null
+++ b/assets/icons/tile_horiz.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/tile_vert.svg b/assets/icons/tile_vert.svg
new file mode 100644
index 000000000..3c14ed76b
--- /dev/null
+++ b/assets/icons/tile_vert.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/tool_palettes.svg b/assets/icons/tool_palettes.svg
new file mode 100644
index 000000000..474f76b64
--- /dev/null
+++ b/assets/icons/tool_palettes.svg
@@ -0,0 +1,15 @@
+
diff --git a/assets/icons/ucs_icon.svg b/assets/icons/ucs_icon.svg
new file mode 100644
index 000000000..ff12a0b39
--- /dev/null
+++ b/assets/icons/ucs_icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/viewcube.svg b/assets/icons/viewcube.svg
new file mode 100644
index 000000000..071fcf9f7
--- /dev/null
+++ b/assets/icons/viewcube.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/icons/vports_config.svg b/assets/icons/vports_config.svg
new file mode 100644
index 000000000..ae1132b36
--- /dev/null
+++ b/assets/icons/vports_config.svg
@@ -0,0 +1,7 @@
+
diff --git a/assets/icons/vports_join.svg b/assets/icons/vports_join.svg
new file mode 100644
index 000000000..208e25e03
--- /dev/null
+++ b/assets/icons/vports_join.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/vports_named.svg b/assets/icons/vports_named.svg
new file mode 100644
index 000000000..0609c79cc
--- /dev/null
+++ b/assets/icons/vports_named.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/icons/vports_restore.svg b/assets/icons/vports_restore.svg
new file mode 100644
index 000000000..cbf2baabf
--- /dev/null
+++ b/assets/icons/vports_restore.svg
@@ -0,0 +1,7 @@
+
diff --git a/build.rs b/build.rs
index f6bd37116..fbe4cc33a 100644
--- a/build.rs
+++ b/build.rs
@@ -22,7 +22,7 @@ use std::fs;
use std::path::Path;
// Display order for known modules; unknown modules follow alphabetically.
-const PRIORITY: &[&str] = &["home", "annotate", "insert", "view", "manage"];
+const PRIORITY: &[&str] = &["home", "insert", "annotate", "view", "manage"];
fn main() {
let mods_dir = Path::new("src/modules");
diff --git a/src/modules/annotate/data_extract.rs b/src/modules/annotate/data_extract.rs
new file mode 100644
index 000000000..c6fc5d183
--- /dev/null
+++ b/src/modules/annotate/data_extract.rs
@@ -0,0 +1,14 @@
+// DATAEXTRACTION command — launches the Data Extraction wizard.
+
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/data_extract.svg"));
+
+pub fn tool() -> ToolDef {
+ ToolDef {
+ id: "DATAEXTRACTION",
+ label: "Extract\nData",
+ icon: ICON,
+ event: ModuleEvent::Command("DATAEXTRACTION".to_string()),
+ }
+}
diff --git a/src/modules/annotate/data_link.rs b/src/modules/annotate/data_link.rs
new file mode 100644
index 000000000..a2e20e5b6
--- /dev/null
+++ b/src/modules/annotate/data_link.rs
@@ -0,0 +1,14 @@
+// DATALINK command — manages data links to external spreadsheets.
+
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/data_link.svg"));
+
+pub fn tool() -> ToolDef {
+ ToolDef {
+ id: "DATALINK",
+ label: "Link\nData",
+ icon: ICON,
+ event: ModuleEvent::Command("DATALINK".to_string()),
+ }
+}
diff --git a/src/modules/annotate/mod.rs b/src/modules/annotate/mod.rs
index 6f184b00e..82f413032 100644
--- a/src/modules/annotate/mod.rs
+++ b/src/modules/annotate/mod.rs
@@ -1,6 +1,8 @@
// Annotate module — dimension, text, leader, table, and markup tools.
pub mod aligned_dim;
+pub mod data_extract;
+pub mod data_link;
pub mod angular_dim;
pub mod ddedit;
pub mod diameter_dim;
@@ -152,7 +154,12 @@ impl CadModule for AnnotateModule {
style_key: StyleKey::TableStyle,
combo_id: "TABLE_STYLE_COMBO",
manager_cmd: Some("TABLESTYLE"),
- rows: vec![],
+ rows: vec![
+ vec![
+ data_extract::tool(),
+ data_link::tool(),
+ ],
+ ],
},
],
},
diff --git a/src/modules/registry.rs b/src/modules/registry.rs
index f188f19ae..cd74d9a09 100644
--- a/src/modules/registry.rs
+++ b/src/modules/registry.rs
@@ -8,8 +8,8 @@ use crate::modules::CadModule;
pub fn all_modules() -> Vec> {
vec![
Box::new(super::home::HomeModule),
- Box::new(super::annotate::AnnotateModule),
Box::new(super::insert::InsertModule),
+ Box::new(super::annotate::AnnotateModule),
Box::new(super::view::ViewModule),
Box::new(super::manage::ManageModule),
Box::new(super::layout::LayoutModule),
diff --git a/src/modules/view/cascade.rs b/src/modules/view/cascade.rs
new file mode 100644
index 000000000..edf5553c7
--- /dev/null
+++ b/src/modules/view/cascade.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/cascade.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "CASCADE", label: "Cascade", icon: ICON, event: ModuleEvent::Command("CASCADE".to_string()) }
+}
diff --git a/src/modules/view/file_tabs.rs b/src/modules/view/file_tabs.rs
new file mode 100644
index 000000000..b2d55d61f
--- /dev/null
+++ b/src/modules/view/file_tabs.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/file_tabs.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "FILETAB", label: "File\nTabs", icon: ICON, event: ModuleEvent::Command("FILETAB".to_string()) }
+}
diff --git a/src/modules/view/layout_tabs.rs b/src/modules/view/layout_tabs.rs
new file mode 100644
index 000000000..0ce564ef5
--- /dev/null
+++ b/src/modules/view/layout_tabs.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/layout_tabs.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "LAYOUTTAB", label: "Layout\nTabs", icon: ICON, event: ModuleEvent::Command("LAYOUTTAB".to_string()) }
+}
diff --git a/src/modules/view/mod.rs b/src/modules/view/mod.rs
index 2b6b5c637..4bc7c762a 100644
--- a/src/modules/view/mod.rs
+++ b/src/modules/view/mod.rs
@@ -1,15 +1,30 @@
-// View module — navigation, visual styles, and viewport presets.
+// View module — viewport tools, navigation, visual styles, palettes, interface.
+mod cascade;
+mod file_tabs;
mod hidden;
+mod layout_tabs;
+mod navbar;
mod orbit;
mod ortho;
mod pan;
mod persp;
+mod properties_palette;
+mod sheetset;
mod solid;
+mod tile_horiz;
+mod tile_vert;
+mod tool_palettes;
+mod ucs_icon;
+mod viewcube;
mod view_front;
mod view_iso;
mod view_right;
mod view_top;
+mod vports_config;
+mod vports_join;
+mod vports_named;
+mod vports_restore;
mod wireframe;
mod xray;
mod zoom_ext;
@@ -18,7 +33,7 @@ mod zoom_out;
pub mod plot_window;
pub mod zoom_window;
-use crate::modules::{CadModule, RibbonGroup};
+use crate::modules::{CadModule, RibbonGroup, RibbonItem};
pub struct ViewModule;
@@ -32,40 +47,94 @@ impl CadModule for ViewModule {
fn ribbon_groups(&self) -> Vec {
vec![
+ // ── Viewport Tools ───────────────────────────────────────────────
+ RibbonGroup {
+ title: "Viewport Tools",
+ tools: vec![
+ RibbonItem::LargeTool(ucs_icon::tool()),
+ RibbonItem::LargeTool(viewcube::tool()),
+ RibbonItem::LargeTool(navbar::tool()),
+ ],
+ },
+ // ── Navigate ─────────────────────────────────────────────────────
RibbonGroup {
title: "Navigate",
tools: vec![
- zoom_ext::tool().into(),
- zoom_in::tool().into(),
- zoom_out::tool().into(),
- pan::tool().into(),
- orbit::tool().into(),
+ RibbonItem::LargeTool(zoom_ext::tool()),
+ RibbonItem::Tool(zoom_in::tool()),
+ RibbonItem::Tool(zoom_out::tool()),
+ RibbonItem::Tool(pan::tool()),
+ RibbonItem::Tool(orbit::tool()),
],
},
+ // ── Model Viewports ───────────────────────────────────────────────
+ RibbonGroup {
+ title: "Model Viewports",
+ tools: vec![
+ RibbonItem::LargeTool(vports_config::tool()),
+ RibbonItem::Tool(vports_named::tool()),
+ RibbonItem::Tool(vports_join::tool()),
+ RibbonItem::Tool(vports_restore::tool()),
+ ],
+ },
+ // ── Visual Style ──────────────────────────────────────────────────
RibbonGroup {
// WIREFRAME and SOLID ids are special-cased in ribbon.rs
// for toggle-state highlighting based on Ribbon::wireframe.
title: "Visual Style",
tools: vec![
- wireframe::tool().into(),
- solid::tool().into(),
- hidden::tool().into(),
- xray::tool().into(),
+ RibbonItem::LargeDropdown {
+ id: "VISUAL_STYLE",
+ label: "Visual\nStyle",
+ icon: wireframe::tool().icon,
+ items: vec![
+ ("WIREFRAME", "Wireframe", wireframe::tool().icon),
+ ("SOLID", "Shaded", solid::tool().icon),
+ ("HIDDEN", "Hidden", hidden::tool().icon),
+ ("XRAY", "X-Ray", xray::tool().icon),
+ ],
+ default: "WIREFRAME",
+ },
],
},
+ // ── Projection ────────────────────────────────────────────────────
RibbonGroup {
// ORTHO and PERSP ids are special-cased in ribbon.rs
// for toggle-state highlighting based on Camera::projection.
title: "Projection",
- tools: vec![ortho::tool().into(), persp::tool().into()],
+ tools: vec![
+ RibbonItem::LargeTool(ortho::tool()),
+ RibbonItem::LargeTool(persp::tool()),
+ ],
},
+ // ── Preset Views ──────────────────────────────────────────────────
RibbonGroup {
title: "Preset",
tools: vec![
- view_top::tool().into(),
- view_front::tool().into(),
- view_right::tool().into(),
- view_iso::tool().into(),
+ RibbonItem::Tool(view_top::tool()),
+ RibbonItem::Tool(view_front::tool()),
+ RibbonItem::Tool(view_right::tool()),
+ RibbonItem::Tool(view_iso::tool()),
+ ],
+ },
+ // ── Palettes ──────────────────────────────────────────────────────
+ RibbonGroup {
+ title: "Palettes",
+ tools: vec![
+ RibbonItem::LargeTool(tool_palettes::tool()),
+ RibbonItem::LargeTool(properties_palette::tool()),
+ RibbonItem::LargeTool(sheetset::tool()),
+ ],
+ },
+ // ── Interface ─────────────────────────────────────────────────────
+ RibbonGroup {
+ title: "Interface",
+ tools: vec![
+ RibbonItem::LargeTool(file_tabs::tool()),
+ RibbonItem::LargeTool(layout_tabs::tool()),
+ RibbonItem::Tool(tile_horiz::tool()),
+ RibbonItem::Tool(tile_vert::tool()),
+ RibbonItem::Tool(cascade::tool()),
],
},
]
diff --git a/src/modules/view/navbar.rs b/src/modules/view/navbar.rs
new file mode 100644
index 000000000..81f6ab5e5
--- /dev/null
+++ b/src/modules/view/navbar.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/navbar.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "NAVBAR", label: "Navigation\nBar", icon: ICON, event: ModuleEvent::Command("NAVBAR".to_string()) }
+}
diff --git a/src/modules/view/properties_palette.rs b/src/modules/view/properties_palette.rs
new file mode 100644
index 000000000..5184dde0a
--- /dev/null
+++ b/src/modules/view/properties_palette.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/properties.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "PROPERTIES", label: "Properties", icon: ICON, event: ModuleEvent::Command("PROPERTIES".to_string()) }
+}
diff --git a/src/modules/view/sheetset.rs b/src/modules/view/sheetset.rs
new file mode 100644
index 000000000..12ff86930
--- /dev/null
+++ b/src/modules/view/sheetset.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/sheetset.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "SHEETSET", label: "Sheet Set\nManager", icon: ICON, event: ModuleEvent::Command("SHEETSET".to_string()) }
+}
diff --git a/src/modules/view/tile_horiz.rs b/src/modules/view/tile_horiz.rs
new file mode 100644
index 000000000..6b5c0dc4f
--- /dev/null
+++ b/src/modules/view/tile_horiz.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/tile_horiz.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "HORIZONTAL", label: "Tile\nHoriz.", icon: ICON, event: ModuleEvent::Command("HORIZONTAL".to_string()) }
+}
diff --git a/src/modules/view/tile_vert.rs b/src/modules/view/tile_vert.rs
new file mode 100644
index 000000000..b9ff4ee2a
--- /dev/null
+++ b/src/modules/view/tile_vert.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/tile_vert.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "VERTICAL", label: "Tile\nVert.", icon: ICON, event: ModuleEvent::Command("VERTICAL".to_string()) }
+}
diff --git a/src/modules/view/tool_palettes.rs b/src/modules/view/tool_palettes.rs
new file mode 100644
index 000000000..ab55e7fd0
--- /dev/null
+++ b/src/modules/view/tool_palettes.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/tool_palettes.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "TOOLPALETTES", label: "Tool\nPalettes", icon: ICON, event: ModuleEvent::Command("TOOLPALETTES".to_string()) }
+}
diff --git a/src/modules/view/ucs_icon.rs b/src/modules/view/ucs_icon.rs
new file mode 100644
index 000000000..35e3273b4
--- /dev/null
+++ b/src/modules/view/ucs_icon.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/ucs_icon.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "UCSICON", label: "UCS\nIcon", icon: ICON, event: ModuleEvent::Command("UCSICON".to_string()) }
+}
diff --git a/src/modules/view/viewcube.rs b/src/modules/view/viewcube.rs
new file mode 100644
index 000000000..0d717c267
--- /dev/null
+++ b/src/modules/view/viewcube.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/viewcube.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "NAVVCUBE", label: "View\nCube", icon: ICON, event: ModuleEvent::Command("NAVVCUBE".to_string()) }
+}
diff --git a/src/modules/view/vports_config.rs b/src/modules/view/vports_config.rs
new file mode 100644
index 000000000..f97c68320
--- /dev/null
+++ b/src/modules/view/vports_config.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/vports_config.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "VPORTS", label: "Viewport\nConfiguration", icon: ICON, event: ModuleEvent::Command("VPORTS".to_string()) }
+}
diff --git a/src/modules/view/vports_join.rs b/src/modules/view/vports_join.rs
new file mode 100644
index 000000000..10ab31858
--- /dev/null
+++ b/src/modules/view/vports_join.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/vports_join.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "VPJOIN", label: "Join", icon: ICON, event: ModuleEvent::Command("VPJOIN".to_string()) }
+}
diff --git a/src/modules/view/vports_named.rs b/src/modules/view/vports_named.rs
new file mode 100644
index 000000000..96852154d
--- /dev/null
+++ b/src/modules/view/vports_named.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/vports_named.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "VPORTS_NAMED", label: "Named", icon: ICON, event: ModuleEvent::Command("VPORTS".to_string()) }
+}
diff --git a/src/modules/view/vports_restore.rs b/src/modules/view/vports_restore.rs
new file mode 100644
index 000000000..d52d82cc7
--- /dev/null
+++ b/src/modules/view/vports_restore.rs
@@ -0,0 +1,5 @@
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
+pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/vports_restore.svg"));
+pub fn tool() -> ToolDef {
+ ToolDef { id: "VPORTS_RESTORE", label: "Restore", icon: ICON, event: ModuleEvent::Command("VPORTS".to_string()) }
+}