feat(zoom): default to window mode

Keep all existing zoom modes available as interactive options.\n\nRefs #804
This commit is contained in:
Hakan Seven committed 2026-08-18 20:29:55 +03:00
1 parent f4889d4c70
commit 08f4cc97f8
2 files changed
+68 -28

No files matched your search

+1 -24
View File
@@ -920,30 +920,7 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
// Bare ZOOM prompts with the mode options as clickable keywords;
// the sub-keyword forms (ZOOM EXTENTS / WINDOW / …) run directly.
"ZOOM" => {
use crate::command::KeywordCommand;
let c = KeywordCommand::new(
"ZOOM",
"ZOOM [Window / Extents / Previous / Object / All / Dynamic / Extents All / In / Out / Scale]:",
vec![
("Window", "W", None),
("Extents", "E", None),
("Previous", "P", None),
("Object", "O", None),
("All", "A", None),
("Dynamic", "D", None),
("Extents All", "EA", None),
("In", "I", None),
("Out", "OUT", None),
("Scale", "S", Some("ZOOM scale factor (e.g. 2 or 0.5):")),
],
);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
"ZOOM WINDOW" | "ZOOM W" | "ZW" => {
"ZOOM" | "ZOOM WINDOW" | "ZOOM W" | "ZW" => {
use crate::modules::view::zoom_window::ZoomWindowCommand;
let new_cmd = ZoomWindowCommand::new();
self.command_line.push_info(&new_cmd.prompt());
+67 -4
View File
@@ -3,7 +3,7 @@
use glam::{DVec3, Vec3};
use crate::t;
use crate::command::{CadCommand, CmdResult};
use crate::command::{CadCommand, CmdOption, CmdResult};
use crate::modules::{IconKind, ModuleEvent, ToolDef};
use crate::scene::model::wire_model::WireModel;
@@ -22,11 +22,15 @@ pub fn tool() -> ToolDef {
pub struct ZoomWindowCommand {
first: Option<Vec3>,
scale_prompt: bool,
}
impl ZoomWindowCommand {
pub fn new() -> Self {
Self { first: None }
Self {
first: None,
scale_prompt: false,
}
}
}
@@ -36,14 +40,73 @@ impl CadCommand for ZoomWindowCommand {
}
fn prompt(&self) -> String {
if self.first.is_none() {
if self.scale_prompt {
t!("ZOOM scale factor (e.g. 2 or 0.5):").into_owned()
} else if self.first.is_none() {
t!("ZOOM WINDOW Specify first corner:").into_owned()
} else {
t!("ZOOM WINDOW Specify opposite corner:").into_owned()
}
}
fn on_point(&mut self, pt: DVec3) -> CmdResult { let pt = pt.as_vec3();
fn options(&self) -> Vec<CmdOption> {
if self.first.is_some() || self.scale_prompt {
return Vec::new();
}
vec![
CmdOption::new("Window", "W"),
CmdOption::new("Extents", "E"),
CmdOption::new("Previous", "P"),
CmdOption::new("Object", "O"),
CmdOption::new("All", "A"),
CmdOption::new("Dynamic", "D"),
CmdOption::new("Extents All", "EA"),
CmdOption::new("In", "I"),
CmdOption::new("Out", "OUT"),
CmdOption::new("Scale", "S"),
]
}
fn wants_text_input(&self) -> bool {
true
}
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
let text = text.trim();
if text.is_empty() {
return None;
}
if self.scale_prompt {
return Some(CmdResult::Dispatch(format!("ZOOM SCALE {text}")));
}
let command = match text.to_uppercase().as_str() {
"W" | "WINDOW" => {
self.first = None;
return Some(CmdResult::NeedPoint);
}
"E" | "EXTENTS" => "ZOOM EXTENTS",
"P" | "PREVIOUS" => "ZOOM PREVIOUS",
"O" | "OBJECT" => "ZOOM OBJECT",
"A" | "ALL" => "ZOOM ALL",
"D" | "DYNAMIC" => "ZOOM DYNAMIC",
"EA" | "EXTENTS ALL" => "ZOOM EXTENTS ALL",
"I" | "IN" => "ZOOM IN",
"OUT" => "ZOOM OUT",
"S" | "SCALE" => {
self.first = None;
self.scale_prompt = true;
return Some(CmdResult::NeedPoint);
}
_ => return None,
};
Some(CmdResult::Dispatch(command.to_string()))
}
fn on_point(&mut self, pt: DVec3) -> CmdResult {
if self.scale_prompt {
return CmdResult::NeedPoint;
}
let pt = pt.as_vec3();
if let Some(p1) = self.first {
CmdResult::ZoomToWindow { p1: p1.as_dvec3(), p2: pt.as_dvec3() }
} else {