diff --git a/assets/icons/zoom_window.svg b/assets/icons/zoom_window.svg
new file mode 100644
index 000000000..fc6338006
--- /dev/null
+++ b/assets/icons/zoom_window.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/app/commands/dim.rs b/src/app/commands/dim.rs
index 8b1c6200c..0a0a2b75b 100644
--- a/src/app/commands/dim.rs
+++ b/src/app/commands/dim.rs
@@ -304,7 +304,10 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
- "ZOOM WINDOW" | "ZOOM W" | "ZW" => {
+ // Bare ZOOM enters the interactive window zoom (pick two corners) —
+ // the common "zoom to a rectangle" action. The sub-keyword forms
+ // (ZOOM EXTENTS / IN / OUT / …) are matched above.
+ "ZOOM WINDOW" | "ZOOM W" | "ZW" | "ZOOM" => {
use crate::modules::view::zoom_window::ZoomWindowCommand;
let new_cmd = ZoomWindowCommand::new();
self.command_line.push_info(&new_cmd.prompt());
diff --git a/src/modules/view/mod.rs b/src/modules/view/mod.rs
index 32e9a67f4..a2382c71e 100644
--- a/src/modules/view/mod.rs
+++ b/src/modules/view/mod.rs
@@ -60,6 +60,7 @@ impl CadModule for ViewModule {
title: "Navigate",
tools: vec![
RibbonItem::LargeTool(zoom_ext::tool()),
+ RibbonItem::Tool(zoom_window::tool()),
RibbonItem::Tool(zoom_in::tool()),
RibbonItem::Tool(zoom_out::tool()),
RibbonItem::Tool(pan::tool()),
diff --git a/src/modules/view/zoom_window.rs b/src/modules/view/zoom_window.rs
index 9e893d8f3..41181cd34 100644
--- a/src/modules/view/zoom_window.rs
+++ b/src/modules/view/zoom_window.rs
@@ -3,8 +3,22 @@
use glam::{DVec3, Vec3};
use crate::command::{CadCommand, CmdResult};
+use crate::modules::{IconKind, ModuleEvent, ToolDef};
use crate::scene::model::wire_model::WireModel;
+pub const ICON: IconKind =
+ IconKind::Svg(include_bytes!("../../../assets/icons/zoom_window.svg"));
+
+/// Ribbon button: zoom into a rectangle picked by two corners.
+pub fn tool() -> ToolDef {
+ ToolDef {
+ id: "ZOOM_WINDOW",
+ label: "Zoom Window",
+ icon: ICON,
+ event: ModuleEvent::Command("ZOOM WINDOW".to_string()),
+ }
+}
+
pub struct ZoomWindowCommand {
first: Option,
}