feat: Dynamic Input overlay (DYNMODE / F12)

- overlay.rs: dynamic_input_overlay() canvas widget draws a semi-transparent
  coordinate tooltip near the cursor; shows X/Y in absolute mode or
  dist/angle relative to last_point when a command base point exists
- statusbar: DYN toggle pill with F12 tooltip (calls ToggleDynInput)
- app/mod.rs: dyn_input: bool field (default true), ToggleDynInput message
- view.rs: builds DYN label and pushes overlay into viewport_stack when
  dyn_input=true and a command is active
- document.rs: last_cursor_screen: iced::Point — updated on every ViewportMove
- ROADMAP.md: Dynamic Input overlay marked ✅

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Sonnet 4.6 committed 2026-04-08 00:12:09 +03:00
1 parent f80d694818
commit 51e6c4b359
7 files changed
+127 -2

No files matched your search

+3
View File
@@ -8,6 +8,7 @@ use acadrust::{CadDocument, Handle};
use acadrust::tables::Ucs;
use crate::linetypes;
use std::path::PathBuf;
use iced;
// ── Per-document tab state ─────────────────────────────────────────────────
@@ -27,6 +28,7 @@ pub(super) struct DocumentTab {
pub(super) wireframe: bool,
pub(super) visual_style: String,
pub(super) last_cursor_world: glam::Vec3,
pub(super) last_cursor_screen: iced::Point,
pub(super) history: HistoryState,
pub(super) active_layer: String,
/// Currently active UCS. `None` means WCS (identity transform).
@@ -57,6 +59,7 @@ impl DocumentTab {
wireframe: false,
visual_style: "Shaded".into(),
last_cursor_world: glam::Vec3::ZERO,
last_cursor_screen: iced::Point::ORIGIN,
history: HistoryState::default(),
active_layer: "0".to_string(),
active_ucs: None,
+5
View File
@@ -49,6 +49,8 @@ pub(super) struct H7CAD {
polar_increment_deg: f32,
/// Show grid lines in the viewport (F7).
show_grid: bool,
/// Dynamic input overlay (F12): show coordinate tooltip near cursor.
dyn_input: bool,
/// Show the UCS icon in the bottom-left corner of model space (UCSICON).
show_ucs_icon: bool,
/// Last point committed by a drawing command — used as ortho/polar base.
@@ -230,6 +232,8 @@ pub enum Message {
TogglePolar,
/// Set polar tracking angle increment (right-click POLAR button).
SetPolarAngle(f32),
/// Toggle dynamic input overlay (F12).
ToggleDynInput,
/// Toggle an individual snap mode (from popup row click).
ToggleSnap(crate::snap::SnapType),
/// Open / close the OSNAP popup (▾ arrow click).
@@ -450,6 +454,7 @@ impl H7CAD {
polar_mode: false,
polar_increment_deg: 45.0,
show_grid: false,
dyn_input: true,
show_ucs_icon: true,
last_point: None,
layer_window: None,
+2
View File
@@ -1031,6 +1031,7 @@ impl H7CAD {
pt
};
self.tabs[i].last_cursor_world = effective;
self.tabs[i].last_cursor_screen = p;
let mut previews = if needs_entity {
let hover_handle =
@@ -1658,6 +1659,7 @@ impl H7CAD {
if self.polar_mode { self.ortho_mode = false; }
Task::none()
}
Message::ToggleDynInput => { self.dyn_input ^= true; Task::none() }
Message::SetPolarAngle(deg) => {
self.polar_increment_deg = deg;
self.polar_mode = true;
+27 -1
View File
@@ -135,7 +135,26 @@ impl H7CAD {
.unwrap_or(Color { r: 0.11, g: 0.11, b: 0.11, a: 1.0 })
};
let viewport_stack = stack![
// Dynamic input overlay — shown when a command is active and DYN is on.
let dyn_input_overlay: Option<Element<'_, Message>> =
if self.dyn_input && tab.active_cmd.is_some() {
let w = tab.last_cursor_world;
let label = if let Some(base) = self.last_point {
// Show relative distance + angle when we have a base point.
let dx = (w.x - base.x) as f64;
let dy = (w.z - base.z) as f64;
let dist = (dx * dx + dy * dy).sqrt();
let ang = dy.atan2(dx).to_degrees();
format!("d={:.3} <{:.1}°", dist, ang)
} else {
format!("X:{:.3} Y:{:.3}", w.x, w.z)
};
Some(overlay::dynamic_input_overlay(tab.last_cursor_screen, label))
} else {
None
};
let mut viewport_stack = stack![
container(viewport_3d)
.style(move |_: &Theme| container::Style {
background: Some(Background::Color(bg_color)),
@@ -151,6 +170,9 @@ impl H7CAD {
]
.width(Fill)
.height(Fill);
if let Some(dyn_ol) = dyn_input_overlay {
viewport_stack = viewport_stack.push(dyn_ol);
}
let center_stack = iced::widget::stack![
row![tab.properties.view(), viewport_stack]
@@ -179,6 +201,7 @@ impl H7CAD {
self.polar_mode,
self.polar_increment_deg,
self.show_grid,
self.dyn_input,
tab.scene.layout_names(),
tab.scene.current_layout.clone(),
self.layout_rename_state.as_ref(),
@@ -342,6 +365,9 @@ impl H7CAD {
keyboard::Key::Named(keyboard::key::Named::F10) => {
Some(Message::TogglePolar)
}
keyboard::Key::Named(keyboard::key::Named::F12) => {
Some(Message::ToggleDynInput)
}
keyboard::Key::Character(c) if ctrl => match c.as_str() {
"n" => Some(Message::ClearScene),
"o" => Some(Message::OpenFile),