2026-05-12 10:36:15 +03:00
|
|
|
mod cmd_result;
|
|
|
|
|
mod commands;
|
2026-03-22 22:44:32 +03:00
|
|
|
mod document;
|
|
|
|
|
mod helpers;
|
|
|
|
|
mod history;
|
|
|
|
|
mod layers;
|
2026-05-12 10:36:15 +03:00
|
|
|
mod properties;
|
2026-03-22 22:44:32 +03:00
|
|
|
mod update;
|
2026-05-12 10:36:15 +03:00
|
|
|
mod view;
|
2026-03-22 22:44:32 +03:00
|
|
|
|
|
|
|
|
use document::DocumentTab;
|
|
|
|
|
|
|
|
|
|
use crate::modules::ModuleEvent;
|
|
|
|
|
use crate::scene::CubeRegion;
|
|
|
|
|
use crate::snap::Snapper;
|
|
|
|
|
use crate::ui::{AppMenu, CommandLine, Ribbon, StatusBar};
|
2026-05-12 10:36:15 +03:00
|
|
|
use acadrust::types::{Color as AcadColor, LineWeight};
|
|
|
|
|
use acadrust::CadDocument;
|
2026-03-22 22:44:32 +03:00
|
|
|
|
|
|
|
|
use iced::time::Instant;
|
|
|
|
|
use iced::window;
|
|
|
|
|
use iced::{mouse, Point, Task, Theme};
|
2026-05-13 09:59:07 +03:00
|
|
|
use std::sync::atomic::AtomicU8;
|
|
|
|
|
use std::sync::Arc;
|
2026-03-22 22:44:32 +03:00
|
|
|
|
|
|
|
|
pub(super) const POLY_START_DELAY_MS: u128 = 150;
|
|
|
|
|
pub(super) const VARIES_LABEL: &str = "*VARIES*";
|
|
|
|
|
|
2026-05-13 09:59:07 +03:00
|
|
|
// ── File-open progress ─────────────────────────────────────────────────────
|
|
|
|
|
// Phase encoding for OpenProgress.phase atomic. Updated from the background
|
|
|
|
|
// loader thread, read by the UI overlay on every frame.
|
|
|
|
|
pub const OPEN_PHASE_READING: u8 = 0;
|
|
|
|
|
pub const OPEN_PHASE_PARSING: u8 = 1;
|
|
|
|
|
pub const OPEN_PHASE_CACHING: u8 = 2;
|
|
|
|
|
pub const OPEN_PHASE_FINALIZING: u8 = 3;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2026-05-14 11:12:08 +03:00
|
|
|
pub struct OpenProgress {
|
2026-05-13 09:59:07 +03:00
|
|
|
pub name: String,
|
|
|
|
|
pub size_bytes: u64,
|
|
|
|
|
pub phase: Arc<AtomicU8>,
|
|
|
|
|
pub started: Instant,
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 22:44:32 +03:00
|
|
|
// ── Application state ──────────────────────────────────────────────────────
|
|
|
|
|
|
2026-05-23 17:16:15 +03:00
|
|
|
pub(super) struct OpenCADStudio {
|
2026-03-22 22:44:32 +03:00
|
|
|
start: Instant,
|
|
|
|
|
tabs: Vec<DocumentTab>,
|
|
|
|
|
active_tab: usize,
|
|
|
|
|
tab_counter: usize,
|
|
|
|
|
ribbon: Ribbon,
|
|
|
|
|
app_menu: AppMenu,
|
|
|
|
|
command_line: CommandLine,
|
|
|
|
|
status_bar: StatusBar,
|
|
|
|
|
cursor_pos: Point,
|
|
|
|
|
vp_size: (f32, f32),
|
|
|
|
|
snapper: Snapper,
|
|
|
|
|
snap_popup_open: bool,
|
2026-05-06 17:50:46 +03:00
|
|
|
scale_popup_open: bool,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// Whether Tangent snap was enabled before a tangent-pick command started.
|
|
|
|
|
pre_cmd_tangent: Option<bool>,
|
|
|
|
|
/// Orthogonal drawing constraint (F8): constrains picks to 0°/90°/180°/270°.
|
|
|
|
|
ortho_mode: bool,
|
2026-04-07 19:30:25 +03:00
|
|
|
/// Polar tracking (F10): constrains picks to configurable angle increments.
|
2026-03-22 22:44:32 +03:00
|
|
|
polar_mode: bool,
|
2026-04-07 19:30:25 +03:00
|
|
|
/// Polar tracking angle increment in degrees (15 / 30 / 45 / 90).
|
|
|
|
|
polar_increment_deg: f32,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// Show grid lines in the viewport (F7).
|
|
|
|
|
show_grid: bool,
|
2026-04-08 00:12:09 +03:00
|
|
|
/// Dynamic input overlay (F12): show coordinate tooltip near cursor.
|
|
|
|
|
dyn_input: bool,
|
2026-04-03 19:25:55 +03:00
|
|
|
/// Show the UCS icon in the bottom-left corner of model space (UCSICON).
|
|
|
|
|
show_ucs_icon: bool,
|
2026-04-24 01:23:06 +03:00
|
|
|
/// Whether the ViewCube 3D gizmo is visible in model space (NAVVCUBE).
|
|
|
|
|
show_viewcube: bool,
|
|
|
|
|
/// Whether the navigation toolbar is shown in the viewport (NAVBAR).
|
|
|
|
|
show_navbar: bool,
|
|
|
|
|
/// Whether the Properties panel is shown on the left (PROPERTIES).
|
|
|
|
|
show_properties: bool,
|
|
|
|
|
/// Whether the document file tabs are shown at the top (FILETAB).
|
|
|
|
|
show_file_tabs: bool,
|
|
|
|
|
/// Whether the layout/paper-space tabs are shown at the bottom (LAYOUTTAB).
|
|
|
|
|
show_layout_tabs: bool,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// Last point committed by a drawing command — used as ortho/polar base.
|
|
|
|
|
last_point: Option<glam::Vec3>,
|
|
|
|
|
/// OS window Id for the floating Layer Properties Manager (None when closed).
|
|
|
|
|
layer_window: Option<window::Id>,
|
|
|
|
|
/// OS window Id of the primary application window.
|
|
|
|
|
main_window: Option<window::Id>,
|
2026-04-08 22:36:28 +03:00
|
|
|
// ── Floating panel windows ────────────────────────────────────────────
|
2026-05-12 10:36:15 +03:00
|
|
|
page_setup_window: Option<window::Id>,
|
|
|
|
|
textstyle_window: Option<window::Id>,
|
|
|
|
|
tablestyle_window: Option<window::Id>,
|
|
|
|
|
mlstyle_window: Option<window::Id>,
|
|
|
|
|
layout_manager_window: Option<window::Id>,
|
|
|
|
|
plotstyle_window: Option<window::Id>,
|
|
|
|
|
dimstyle_window: Option<window::Id>,
|
|
|
|
|
shortcuts_window: Option<window::Id>,
|
|
|
|
|
about_window: Option<window::Id>,
|
2026-05-16 19:55:57 +03:00
|
|
|
/// New-release notification window — opened on startup when the
|
|
|
|
|
/// GitHub releases API reports a newer version than this build.
|
|
|
|
|
update_notice_window: Option<window::Id>,
|
|
|
|
|
/// Tag of the latest available release (without the leading "v"),
|
|
|
|
|
/// e.g. `"0.3.0"`. `None` when up-to-date or check hasn't returned.
|
|
|
|
|
update_notice_version: Option<String>,
|
2026-05-22 12:55:37 +03:00
|
|
|
/// Release-notes body for the version above (GitHub release "body"
|
|
|
|
|
/// markdown, as returned by the API). May be empty when the release
|
|
|
|
|
/// shipped without notes.
|
|
|
|
|
update_notice_body: Option<String>,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// In-memory clipboard: cloned entities waiting to be pasted.
|
|
|
|
|
clipboard: Vec<acadrust::EntityType>,
|
|
|
|
|
/// Centroid of the clipboard entities (XZ plane, Y-up).
|
|
|
|
|
clipboard_centroid: glam::Vec3,
|
2026-03-31 07:13:36 +03:00
|
|
|
/// Which layout tab has its context menu open (None = closed).
|
|
|
|
|
layout_context_menu: Option<String>,
|
|
|
|
|
/// Inline rename state: (original_name, current_edit_value).
|
|
|
|
|
layout_rename_state: Option<(String, String)>,
|
2026-03-31 07:24:16 +03:00
|
|
|
/// Timestamp of the previous viewport left-click release (for double-click detection).
|
|
|
|
|
last_vp_click_time: Option<Instant>,
|
|
|
|
|
/// Screen position of the previous viewport left-click release.
|
|
|
|
|
last_vp_click_pos: Option<Point>,
|
2026-04-08 22:36:28 +03:00
|
|
|
// page_setup_open: moved to page_setup_window: Option<window::Id>
|
2026-03-31 08:05:17 +03:00
|
|
|
/// Editable paper width buffer for the Page Setup panel (string while typing).
|
|
|
|
|
page_setup_w: String,
|
|
|
|
|
/// Editable paper height buffer for the Page Setup panel (string while typing).
|
|
|
|
|
page_setup_h: String,
|
2026-04-01 00:12:07 +03:00
|
|
|
/// Plot area type: "Layout" | "Extents".
|
|
|
|
|
page_setup_plot_area: String,
|
|
|
|
|
/// Center the drawing on the page when exporting.
|
|
|
|
|
page_setup_center: bool,
|
|
|
|
|
/// Plot offset X in mm (applied after optional centering).
|
|
|
|
|
page_setup_offset_x: String,
|
|
|
|
|
/// Plot offset Y in mm.
|
|
|
|
|
page_setup_offset_y: String,
|
|
|
|
|
/// Plot rotation in degrees: "0" | "90" | "180" | "270".
|
|
|
|
|
page_setup_rotation: String,
|
Feat: ROADMAP Phase 1-5 batch — trim/extend, plot scale, viewport UX, mline caps, table alignment
- TRIM/EXTEND: Ray and XLine entities supported as cutting boundaries and trim targets;
trim results in Ray→Line/Ray, XLine→Ray/Ray or Line; hover preview added
- Plot scale override: Fit/1:1/1:2/1:5/1:10/1:20/1:50/1:100/2:1 buttons added to Page Setup
panel; PageSetupCommit applies scale to PlotSettings
- Viewport UX: locked viewport gets orange border; selected viewport gets white border
- Named view → viewport assignment: Choice dropdown in properties panel copies
view_target/direction/height to the viewport entity
- MLine caps: perpendicular start/end cap lines added for open (non-closed) MLines
- Wipeout polygon grips: boundary vertices become editable grips when clipping_enabled+Polygonal;
world→pixel back-projection on drag
- Table cell alignment: CellStyle.alignment (1-9) drives left/center/right + top/middle/bottom
text positioning; cxf::measure_text() helper added
- New commands/features: DIMCONTINUE (DCO), DIMBASELINE (DBA), TOLERANCE (TOL), TABLE,
ATTDEF, ATTEDIT, ATTDISP, BREAKATPOINT (BAP), PLOTWINDOW (PW), MLINE (ML);
DIMSTYLE/DIMCURRENT/CLAYER/LTSCALE/CELTSCALE/SCALETEXT/XDATA/UCSICON/REGEN/DRAWORDER extended
- PLINE arc mode: A/L/CLOSE text input, bulge computation, arc preview
- Warning cleanup: removed unused imports and unreachable patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 15:31:05 +03:00
|
|
|
/// Plot scale: "Fit" | "1:1" | "1:2" | "1:4" | "1:5" | "1:10" | "1:20" | "1:50" | "1:100" | "2:1".
|
|
|
|
|
page_setup_scale: String,
|
2026-04-06 14:25:13 +03:00
|
|
|
|
2026-04-06 14:37:23 +03:00
|
|
|
// ── Plot Style Table ──────────────────────────────────────────────────
|
|
|
|
|
/// Currently loaded CTB/STB table (None = no override).
|
|
|
|
|
active_plot_style: Option<crate::io::plot_style::PlotStyleTable>,
|
|
|
|
|
|
2026-04-06 14:54:05 +03:00
|
|
|
// ── MLineStyle Dialog ─────────────────────────────────────────────────
|
|
|
|
|
mlstyle_selected: String,
|
|
|
|
|
|
2026-04-06 14:57:11 +03:00
|
|
|
// ── TableStyle Dialog ─────────────────────────────────────────────────
|
|
|
|
|
tablestyle_selected: String,
|
|
|
|
|
|
2026-04-06 15:01:25 +03:00
|
|
|
// ── TextStyle Font Browser ────────────────────────────────────────────
|
|
|
|
|
textstyle_selected: String,
|
|
|
|
|
/// Edit buffer for font file name.
|
|
|
|
|
textstyle_font: String,
|
|
|
|
|
/// Edit buffer for width factor.
|
|
|
|
|
textstyle_width: String,
|
|
|
|
|
/// Edit buffer for oblique angle (degrees).
|
|
|
|
|
textstyle_oblique: String,
|
|
|
|
|
|
2026-04-08 18:31:09 +03:00
|
|
|
// ── Color Scheme ──────────────────────────────────────────────────────
|
|
|
|
|
active_theme: Theme,
|
|
|
|
|
|
2026-04-08 18:34:10 +03:00
|
|
|
// ── Keyboard Shortcut Editor ──────────────────────────────────────────
|
|
|
|
|
/// User-defined function-key overrides: "F3" → command string.
|
|
|
|
|
shortcut_overrides: std::collections::HashMap<String, String>,
|
|
|
|
|
|
2026-04-08 18:28:30 +03:00
|
|
|
// ── Layout Manager Panel ──────────────────────────────────────────────
|
|
|
|
|
layout_manager_selected: String,
|
|
|
|
|
layout_manager_rename_buf: String,
|
|
|
|
|
|
2026-04-08 18:19:48 +03:00
|
|
|
// ── Plot Style Panel ──────────────────────────────────────────────────
|
|
|
|
|
/// Selected ACI index in the panel (1-255).
|
|
|
|
|
plotstyle_panel_aci: u8,
|
|
|
|
|
/// Edit buffers for the selected entry.
|
|
|
|
|
ps_color_buf: String,
|
|
|
|
|
ps_lineweight_buf: String,
|
|
|
|
|
ps_screening_buf: String,
|
|
|
|
|
|
2026-05-13 09:59:07 +03:00
|
|
|
// ── File-open progress ────────────────────────────────────────────────
|
|
|
|
|
/// `Some` while a CAD file is loading — drives the modal overlay.
|
|
|
|
|
/// Cleared when the load finishes, errors, or the user cancels.
|
|
|
|
|
pub(super) opening: Option<OpenProgress>,
|
|
|
|
|
|
2026-05-01 11:31:11 +03:00
|
|
|
// ── Unsaved-changes dialog ────────────────────────────────────────────
|
|
|
|
|
/// Set when the user tries to close a tab or quit while there are unsaved changes.
|
|
|
|
|
pending_close: Option<PendingClose>,
|
|
|
|
|
/// OS window for the unsaved-changes confirmation dialog.
|
|
|
|
|
unsaved_dialog_window: Option<window::Id>,
|
|
|
|
|
|
2026-05-01 16:12:32 +03:00
|
|
|
// ── Custom Save-As dialog ─────────────────────────────────────────────
|
2026-05-01 16:20:38 +03:00
|
|
|
/// OS window for the custom Save As dialog.
|
2026-05-01 16:12:32 +03:00
|
|
|
save_dialog_window: Option<window::Id>,
|
|
|
|
|
/// Currently selected format string, e.g. "DWG 2013".
|
|
|
|
|
save_dialog_format: String,
|
|
|
|
|
/// Editable filename (without path), e.g. "drawing.dwg".
|
|
|
|
|
save_dialog_filename: String,
|
2026-05-01 16:20:38 +03:00
|
|
|
/// Currently browsed folder (PathBuf for reliable fs ops).
|
|
|
|
|
save_dialog_folder: std::path::PathBuf,
|
|
|
|
|
/// Cached directory listing: (display_name, is_dir, full_path).
|
|
|
|
|
save_dialog_entries: Vec<(String, bool, std::path::PathBuf)>,
|
2026-05-01 16:12:32 +03:00
|
|
|
/// True when triggered from the unsaved-changes flow.
|
|
|
|
|
save_dialog_for_unsaved: bool,
|
|
|
|
|
|
2026-04-06 14:25:13 +03:00
|
|
|
// ── DimStyle Dialog ───────────────────────────────────────────────────
|
|
|
|
|
/// Name of the style currently shown in the dialog.
|
|
|
|
|
dimstyle_selected: String,
|
|
|
|
|
/// Active tab: 0=Lines, 1=Arrows, 2=Text, 3=Scale/Units, 4=Tolerances.
|
|
|
|
|
dimstyle_tab: u8,
|
|
|
|
|
// Edit buffers (strings while typing):
|
2026-05-12 10:36:15 +03:00
|
|
|
ds_dimdle: String,
|
|
|
|
|
ds_dimdli: String,
|
|
|
|
|
ds_dimgap: String,
|
|
|
|
|
ds_dimexe: String,
|
|
|
|
|
ds_dimexo: String,
|
|
|
|
|
ds_dimsd1: bool,
|
|
|
|
|
ds_dimsd2: bool,
|
|
|
|
|
ds_dimse1: bool,
|
|
|
|
|
ds_dimse2: bool,
|
|
|
|
|
ds_dimasz: String,
|
|
|
|
|
ds_dimcen: String,
|
|
|
|
|
ds_dimtsz: String,
|
|
|
|
|
ds_dimtxt: String,
|
|
|
|
|
ds_dimtxsty: String,
|
|
|
|
|
ds_dimtad: String,
|
|
|
|
|
ds_dimtih: bool,
|
|
|
|
|
ds_dimtoh: bool,
|
|
|
|
|
ds_dimscale: String,
|
|
|
|
|
ds_dimlfac: String,
|
|
|
|
|
ds_dimlunit: String,
|
|
|
|
|
ds_dimdec: String,
|
|
|
|
|
ds_dimpost: String,
|
|
|
|
|
ds_dimtol: bool,
|
|
|
|
|
ds_dimlim: bool,
|
|
|
|
|
ds_dimtp: String,
|
|
|
|
|
ds_dimtm: String,
|
|
|
|
|
ds_dimtdec: String,
|
|
|
|
|
ds_dimtfac: String,
|
2026-04-06 14:25:13 +03:00
|
|
|
}
|
|
|
|
|
|
2026-05-01 11:31:11 +03:00
|
|
|
/// What triggered the "unsaved changes" dialog.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub(super) enum PendingClose {
|
|
|
|
|
/// User tried to close the tab at this index.
|
|
|
|
|
Tab(usize),
|
|
|
|
|
/// User tried to quit the application.
|
|
|
|
|
Quit,
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 14:25:13 +03:00
|
|
|
/// Identifies a DimStyle field that can be edited in the dialog.
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
|
pub enum DsField {
|
2026-05-12 10:36:15 +03:00
|
|
|
Dimdle,
|
|
|
|
|
Dimdli,
|
|
|
|
|
Dimgap,
|
|
|
|
|
Dimexe,
|
|
|
|
|
Dimexo,
|
|
|
|
|
Dimsd1,
|
|
|
|
|
Dimsd2,
|
|
|
|
|
Dimse1,
|
|
|
|
|
Dimse2,
|
|
|
|
|
Dimasz,
|
|
|
|
|
Dimcen,
|
|
|
|
|
Dimtsz,
|
|
|
|
|
Dimtxt,
|
|
|
|
|
Dimtxsty,
|
|
|
|
|
Dimtad,
|
|
|
|
|
Dimtih,
|
|
|
|
|
Dimtoh,
|
|
|
|
|
Dimscale,
|
|
|
|
|
Dimlfac,
|
|
|
|
|
Dimlunit,
|
|
|
|
|
Dimdec,
|
|
|
|
|
Dimpost,
|
|
|
|
|
Dimtol,
|
|
|
|
|
Dimlim,
|
|
|
|
|
Dimtp,
|
|
|
|
|
Dimtm,
|
|
|
|
|
Dimtdec,
|
|
|
|
|
Dimtfac,
|
2026-03-22 22:44:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum Message {
|
|
|
|
|
Tick(Instant),
|
|
|
|
|
OpenFile,
|
2026-05-13 09:59:07 +03:00
|
|
|
/// File picker returned. `Some((path, size_in_bytes))` → start loading;
|
|
|
|
|
/// `None` → user cancelled the dialog (no overlay shown).
|
|
|
|
|
OpenPathPicked(Option<(PathBuf, u64)>),
|
feat(app): add fixed Start tab with welcome page and recent documents
A pinned "Start" tab now lives at index 0. It cannot be closed, opens
on launch, and replaces the model-space viewport with a welcome page —
similar to Thunderbird's first-run screen.
- Boot opens with only the Start tab; Drawing1 is no longer auto-spawned.
- The Properties left panel becomes a Recent Documents rail on the
Start tab. Recents persist to disk
(%APPDATA%/H7CAD/recent.txt on Windows, $XDG_CONFIG_HOME/H7CAD/recent.txt
on Linux, ~/Library/Application Support/H7CAD/recent.txt on macOS), up
to 20 entries, saved on every open and rehydrated at boot.
Each row opens or removes the file in place.
- The Support ribbon group (Donate / Report / About / Changelog) is
retired; the same actions surface on the welcome page instead. The
Donate button is the primary call-to-action — solid #B03020 brand
fill with a soft brand-tinted ambient glow halo behind the action row
(Thunderbird-style coloured glow against the neutral page).
- Drawing-only overlays (mouse-area, viewcube, navbar, dynamic input,
selection markers) are suppressed on the Start tab so its clicks
don't trigger CAD commands. OpenFile's "current_is_empty" check
refuses to replace the Start tab, and TabClose ignores requests on
it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:19:31 +03:00
|
|
|
/// Open a path from the Start tab's recent-documents list (skips the
|
|
|
|
|
/// file picker; the path is already known).
|
|
|
|
|
OpenRecent(PathBuf),
|
|
|
|
|
/// Drop a path from the recent-documents list.
|
|
|
|
|
RecentRemove(PathBuf),
|
2026-05-13 09:59:07 +03:00
|
|
|
/// User clicked Cancel on the loading overlay. The parser thread keeps
|
|
|
|
|
/// running but its result is discarded.
|
|
|
|
|
OpenCancel,
|
2026-05-06 23:04:53 +03:00
|
|
|
FileOpened(Result<(String, PathBuf, CadDocument, crate::scene::DerivedCaches), String>),
|
2026-03-22 22:44:32 +03:00
|
|
|
SaveFile,
|
|
|
|
|
SaveAs,
|
2026-05-01 16:12:32 +03:00
|
|
|
// ── Custom Save-As dialog ─────────────────────────────────────────────
|
|
|
|
|
SaveDialogFormatChanged(String),
|
|
|
|
|
SaveDialogFilenameChanged(String),
|
2026-05-01 16:20:38 +03:00
|
|
|
/// Navigate the file-chooser to the given directory.
|
|
|
|
|
SaveDialogNavigate(std::path::PathBuf),
|
|
|
|
|
/// User clicked a file entry (fill filename) or directory entry (navigate).
|
|
|
|
|
SaveDialogEntryClicked(std::path::PathBuf, bool),
|
2026-05-01 16:12:32 +03:00
|
|
|
SaveDialogConfirm,
|
|
|
|
|
SaveDialogCancel,
|
2026-03-22 22:44:32 +03:00
|
|
|
ClearScene,
|
|
|
|
|
SetWireframe(bool),
|
|
|
|
|
/// Switch camera projection: true = Orthographic, false = Perspective.
|
|
|
|
|
SetProjection(bool),
|
|
|
|
|
/// Select a ribbon module tab by index.
|
|
|
|
|
RibbonSelectTab(usize),
|
|
|
|
|
/// A ribbon tool button was clicked — highlights the tool and dispatches its event.
|
|
|
|
|
RibbonToolClick {
|
|
|
|
|
tool_id: String,
|
|
|
|
|
event: ModuleEvent,
|
|
|
|
|
},
|
|
|
|
|
// ── Application menu ──────────────────────────────────────────────────
|
|
|
|
|
ToggleAppMenu,
|
|
|
|
|
CloseAppMenu,
|
|
|
|
|
/// Close the menu and immediately dispatch a CAD command.
|
|
|
|
|
CloseAppMenuAndRun(String),
|
|
|
|
|
AppMenuSearch(String),
|
|
|
|
|
// ── Document tabs ──────────────────────────────────────────────────────
|
|
|
|
|
/// Create a new empty document tab.
|
|
|
|
|
TabNew,
|
|
|
|
|
/// Switch to the given tab index.
|
|
|
|
|
TabSwitch(usize),
|
|
|
|
|
/// Close the given tab index.
|
|
|
|
|
TabClose(usize),
|
2026-05-01 11:31:11 +03:00
|
|
|
// ── Unsaved-changes confirmation dialog ───────────────────────────────
|
|
|
|
|
/// User clicked "Save" in the unsaved-changes dialog.
|
|
|
|
|
UnsavedDialogSave,
|
|
|
|
|
/// User clicked "Discard" in the unsaved-changes dialog.
|
|
|
|
|
UnsavedDialogDiscard,
|
|
|
|
|
/// User clicked "Cancel" in the unsaved-changes dialog.
|
|
|
|
|
UnsavedDialogCancel,
|
|
|
|
|
/// Save-as path picked for the unsaved-changes → save → close flow.
|
|
|
|
|
UnsavedPickedSavePath(Option<std::path::PathBuf>),
|
2026-03-22 22:44:32 +03:00
|
|
|
// ─────────────────────────────────────────────────────────────────────
|
|
|
|
|
CommandInput(String),
|
|
|
|
|
CommandSubmit,
|
|
|
|
|
Command(String),
|
2026-05-26 18:59:51 +03:00
|
|
|
/// Append one typed character to the command-line input from the
|
|
|
|
|
/// global key-press subscription. Used when the text-input widget
|
|
|
|
|
/// itself isn't focused (focus parked on viewport / button / etc.)
|
|
|
|
|
/// so typing still routes to the command line.
|
|
|
|
|
CommandAppendChar(String),
|
|
|
|
|
/// Pop the trailing character off the command-line input — backspace
|
|
|
|
|
/// counterpart to `CommandAppendChar`.
|
|
|
|
|
CommandBackspace,
|
2026-04-07 00:04:12 +03:00
|
|
|
/// Recall previous command in history (↑ arrow key).
|
|
|
|
|
CommandHistoryPrev,
|
|
|
|
|
/// Recall next command in history (↓ arrow key).
|
|
|
|
|
CommandHistoryNext,
|
2026-05-26 22:13:15 +03:00
|
|
|
/// Toggle the dropdown listing the full command-line history.
|
|
|
|
|
CommandHistoryToggle,
|
2026-03-22 22:44:32 +03:00
|
|
|
ToggleLayers,
|
|
|
|
|
LayerToggleVisible(usize),
|
|
|
|
|
LayerToggleLock(usize),
|
|
|
|
|
LayerToggleFreeze(usize),
|
2026-04-06 23:41:39 +03:00
|
|
|
/// Toggle per-viewport freeze: (layer_index, vp_col_index)
|
|
|
|
|
LayerToggleVpFreeze(usize, usize),
|
2026-03-22 22:44:32 +03:00
|
|
|
LayerNew,
|
|
|
|
|
LayerDelete,
|
|
|
|
|
LayerSetCurrent,
|
|
|
|
|
LayerSelect(usize),
|
|
|
|
|
LayerRenameStart(usize),
|
|
|
|
|
LayerRenameEdit(String),
|
|
|
|
|
LayerColorPickerToggle(usize),
|
|
|
|
|
LayerColorMorePalette,
|
|
|
|
|
LayerColorSet(u8),
|
|
|
|
|
LayerLinetypeSet(String),
|
|
|
|
|
LayerLineweightSet(LineWeight),
|
|
|
|
|
LayerTransparencyEdit(usize, String),
|
|
|
|
|
LayerRenameCommit,
|
|
|
|
|
CursorMoved(Point),
|
|
|
|
|
ViewportClick,
|
|
|
|
|
ViewportMove(Point),
|
|
|
|
|
ViewportLeftPress,
|
|
|
|
|
ViewportLeftRelease,
|
|
|
|
|
ViewportRightPress,
|
|
|
|
|
ViewportRightRelease,
|
|
|
|
|
ViewportMiddlePress,
|
|
|
|
|
ViewportMiddleRelease,
|
|
|
|
|
ViewportScroll(mouse::ScrollDelta),
|
|
|
|
|
ViewportExit,
|
|
|
|
|
ViewCubeSnap(CubeRegion),
|
|
|
|
|
WindowResized(f32, f32),
|
|
|
|
|
/// Enter pressed globally — finalises the active command (no text-input involvement).
|
|
|
|
|
CommandFinalize,
|
|
|
|
|
/// Escape pressed globally — cancels the active command.
|
|
|
|
|
CommandEscape,
|
|
|
|
|
/// Toggle the global snap on/off (OSNAP button body click).
|
|
|
|
|
ToggleSnapEnabled,
|
|
|
|
|
/// Toggle grid-snap on/off — F9 / SNAP status-bar button.
|
|
|
|
|
ToggleGridSnap,
|
2026-04-24 01:23:06 +03:00
|
|
|
/// Toggle the ViewCube 3D gizmo visibility (NAVVCUBE).
|
|
|
|
|
ToggleViewCube,
|
|
|
|
|
/// Toggle the navigation toolbar visibility (NAVBAR).
|
|
|
|
|
ToggleNavbar,
|
|
|
|
|
/// Toggle the Properties panel visibility (PROPERTIES).
|
|
|
|
|
ToggleProperties,
|
|
|
|
|
/// Toggle the document file tabs at the top (FILETAB).
|
|
|
|
|
ToggleFileTabs,
|
|
|
|
|
/// Toggle the layout tabs at the bottom (LAYOUTTAB).
|
|
|
|
|
ToggleLayoutTabs,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// Toggle grid display in the viewport — F7 / GRID status-bar button.
|
|
|
|
|
ToggleGrid,
|
|
|
|
|
/// Toggle orthogonal drawing constraint — F8 / ORTHO status-bar button.
|
|
|
|
|
ToggleOrtho,
|
2026-05-23 07:15:26 +03:00
|
|
|
/// Toggle LWDISPLAY header flag — LWT status-bar button.
|
|
|
|
|
ToggleLineweightDisplay,
|
2026-04-07 19:30:25 +03:00
|
|
|
/// Toggle polar-angle constraint — F10 / POLAR status-bar button.
|
2026-03-22 22:44:32 +03:00
|
|
|
TogglePolar,
|
2026-04-07 19:30:25 +03:00
|
|
|
/// Set polar tracking angle increment (right-click POLAR button).
|
|
|
|
|
SetPolarAngle(f32),
|
2026-05-06 17:50:46 +03:00
|
|
|
/// Set the model-space annotation scale (CANNOSCALE equivalent).
|
|
|
|
|
SetAnnotationScale(f32),
|
|
|
|
|
/// Set the active viewport's custom_scale (paper space).
|
|
|
|
|
SetViewportScale(f64),
|
|
|
|
|
/// Toggle the scale picker popup open/closed.
|
|
|
|
|
ToggleScalePopup,
|
|
|
|
|
/// Close the scale picker popup.
|
|
|
|
|
CloseScalePopup,
|
2026-04-08 00:12:09 +03:00
|
|
|
/// Toggle dynamic input overlay (F12).
|
|
|
|
|
ToggleDynInput,
|
2026-04-08 00:26:54 +03:00
|
|
|
/// Toggle object snap tracking (F11).
|
|
|
|
|
ToggleOTrack,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// Toggle an individual snap mode (from popup row click).
|
|
|
|
|
ToggleSnap(crate::snap::SnapType),
|
|
|
|
|
/// Open / close the OSNAP popup (▾ arrow click).
|
|
|
|
|
ToggleSnapPopup,
|
|
|
|
|
/// Close the OSNAP popup (click-catcher outside the panel).
|
|
|
|
|
CloseSnapPopup,
|
|
|
|
|
/// Enable all snap modes.
|
|
|
|
|
SnapSelectAll,
|
|
|
|
|
/// Disable all snap modes.
|
|
|
|
|
SnapClearAll,
|
|
|
|
|
/// Toggle a ribbon dropdown open/closed.
|
|
|
|
|
ToggleRibbonDropdown(String),
|
|
|
|
|
/// Close any open ribbon dropdown (click-catcher outside the panel).
|
|
|
|
|
CloseRibbonDropdown,
|
|
|
|
|
/// User selected a specific item from a ribbon dropdown.
|
|
|
|
|
DropdownSelectItem {
|
|
|
|
|
dropdown_id: &'static str,
|
|
|
|
|
cmd: &'static str,
|
|
|
|
|
},
|
|
|
|
|
/// Delete key — erase all currently selected entities.
|
|
|
|
|
DeleteSelected,
|
|
|
|
|
Undo,
|
|
|
|
|
Redo,
|
|
|
|
|
UndoMany(usize),
|
|
|
|
|
RedoMany(usize),
|
|
|
|
|
// ── Ribbon ────────────────────────────────────────────────────────────
|
|
|
|
|
/// User selected a layer from the layer combobox in the ribbon.
|
|
|
|
|
RibbonLayerChanged(String),
|
|
|
|
|
/// User changed the active color in the Properties toolbar.
|
|
|
|
|
RibbonColorChanged(AcadColor),
|
|
|
|
|
/// Toggle the full ACI palette inside the ribbon color picker.
|
|
|
|
|
RibbonColorPaletteToggle,
|
|
|
|
|
/// User changed the active linetype in the Properties toolbar.
|
|
|
|
|
RibbonLinetypeChanged(String),
|
|
|
|
|
/// User changed the active lineweight in the Properties toolbar.
|
|
|
|
|
RibbonLineweightChanged(LineWeight),
|
2026-04-09 03:38:23 +03:00
|
|
|
/// User selected a style from a style combobox in the ribbon.
|
2026-05-12 10:36:15 +03:00
|
|
|
RibbonStyleChanged {
|
|
|
|
|
key: crate::modules::StyleKey,
|
|
|
|
|
name: String,
|
|
|
|
|
},
|
2026-03-22 22:44:32 +03:00
|
|
|
|
|
|
|
|
// ── Properties panel ──────────────────────────────────────────────────
|
|
|
|
|
/// User selected a layer from the layer pick_list in the Properties panel.
|
|
|
|
|
PropLayerChanged(String),
|
|
|
|
|
PropSelectionGroupChanged(crate::ui::properties::SelectionGroup),
|
|
|
|
|
/// User picked a color from the Properties color picker.
|
|
|
|
|
PropColorChanged(AcadColor),
|
|
|
|
|
/// User selected a lineweight from the Properties pick_list.
|
|
|
|
|
PropLwChanged(LineWeight),
|
|
|
|
|
/// User selected a linetype from the linetype pick_list.
|
|
|
|
|
PropLinetypeChanged(String),
|
|
|
|
|
/// User toggled a boolean property (e.g. Invisible).
|
|
|
|
|
PropBoolToggle(&'static str),
|
|
|
|
|
/// User selected a hatch pattern from the pattern pick_list in Properties.
|
|
|
|
|
PropHatchPatternChanged(String),
|
|
|
|
|
/// User selected a generic choice field in the Properties panel.
|
|
|
|
|
PropGeomChoiceChanged {
|
|
|
|
|
field: &'static str,
|
|
|
|
|
value: String,
|
|
|
|
|
},
|
|
|
|
|
/// User is typing in an editable geometry field (live buffer update).
|
|
|
|
|
PropGeomInput {
|
|
|
|
|
field: &'static str,
|
|
|
|
|
value: String,
|
|
|
|
|
},
|
|
|
|
|
/// User committed a geometry/common field edit (Enter pressed).
|
|
|
|
|
PropGeomCommit(&'static str),
|
|
|
|
|
/// Toggle the inline color picker dropdown open/closed.
|
|
|
|
|
PropColorPickerToggle,
|
|
|
|
|
/// Toggle the full ACI colour palette expansion.
|
|
|
|
|
PropColorPaletteToggle,
|
2026-03-31 07:24:16 +03:00
|
|
|
/// Enter the model-space editing mode inside the given viewport (MSPACE).
|
|
|
|
|
EnterViewport(acadrust::Handle),
|
|
|
|
|
/// Exit MSPACE and return to paper-space editing (PSPACE).
|
|
|
|
|
ExitViewport,
|
2026-03-31 12:52:07 +03:00
|
|
|
/// MS command: enter MSPACE for the first available viewport.
|
|
|
|
|
MspaceCommand,
|
|
|
|
|
/// PS command: exit MSPACE (PSPACE).
|
|
|
|
|
PspaceCommand,
|
2026-03-22 22:44:32 +03:00
|
|
|
/// Switch to a named layout ("Model" or paper space layout name).
|
|
|
|
|
LayoutSwitch(String),
|
|
|
|
|
/// Create a new paper space layout.
|
|
|
|
|
LayoutCreate,
|
2026-03-31 07:13:36 +03:00
|
|
|
/// Delete the named paper space layout (Model cannot be deleted).
|
|
|
|
|
LayoutDelete(String),
|
|
|
|
|
/// Begin inline rename for the given layout tab.
|
|
|
|
|
LayoutRenameStart(String),
|
|
|
|
|
/// Live-update the rename text input buffer.
|
|
|
|
|
LayoutRenameEdit(String),
|
|
|
|
|
/// Commit the rename (Enter pressed in the text input).
|
|
|
|
|
LayoutRenameCommit,
|
|
|
|
|
/// Cancel an in-progress rename (Escape).
|
|
|
|
|
LayoutRenameCancel,
|
|
|
|
|
/// Open the right-click context menu for the given layout tab.
|
|
|
|
|
LayoutContextMenu(String),
|
|
|
|
|
/// Close the layout context menu.
|
|
|
|
|
LayoutContextMenuClose,
|
2026-04-08 18:28:30 +03:00
|
|
|
// ── Layout Manager Panel ────────────────────────────────────────────
|
|
|
|
|
LayoutManagerOpen,
|
2026-04-09 12:44:31 +03:00
|
|
|
#[allow(dead_code)]
|
2026-04-08 18:28:30 +03:00
|
|
|
LayoutManagerClose,
|
|
|
|
|
LayoutManagerSelect(String),
|
|
|
|
|
LayoutManagerRenameBuf(String),
|
|
|
|
|
LayoutManagerRenameCommit,
|
|
|
|
|
LayoutManagerNew,
|
|
|
|
|
LayoutManagerDelete,
|
|
|
|
|
LayoutManagerMoveLeft,
|
|
|
|
|
LayoutManagerMoveRight,
|
|
|
|
|
LayoutManagerSetCurrent,
|
2026-04-08 18:31:09 +03:00
|
|
|
/// Switch the UI color scheme.
|
|
|
|
|
SetTheme(Theme),
|
2026-04-08 18:34:10 +03:00
|
|
|
// ── Keyboard Shortcut Editor ────────────────────────────────────────
|
|
|
|
|
ShortcutsPanelOpen,
|
2026-04-09 12:44:31 +03:00
|
|
|
#[allow(dead_code)]
|
2026-04-08 18:34:10 +03:00
|
|
|
ShortcutsPanelClose,
|
2026-04-22 22:22:33 +03:00
|
|
|
// ── About window ────────────────────────────────────────────────────
|
|
|
|
|
AboutOpen,
|
|
|
|
|
AboutCopyInfo,
|
2026-04-08 00:41:01 +03:00
|
|
|
/// Close the viewport right-click context menu without performing any action.
|
|
|
|
|
ViewportContextMenuClose,
|
2026-05-01 11:31:11 +03:00
|
|
|
/// The user clicked the title-bar ✕ (fires before the window closes).
|
|
|
|
|
WindowCloseRequested(window::Id),
|
|
|
|
|
/// A window was fully closed (fires after `window::close()` is called).
|
2026-03-22 22:44:32 +03:00
|
|
|
OsWindowClosed(window::Id),
|
|
|
|
|
/// No-op — used as a fallback when a TabEvent has no host mapping.
|
|
|
|
|
Noop,
|
2026-05-16 19:55:57 +03:00
|
|
|
/// GitHub releases API returned a result. `Some(version)` means a
|
|
|
|
|
/// newer release exists; we open the update-notice window.
|
2026-05-22 12:55:37 +03:00
|
|
|
UpdateCheckResult(Option<crate::update_check::UpdateInfo>),
|
2026-05-16 19:55:57 +03:00
|
|
|
/// User dismissed the update-notice window.
|
|
|
|
|
UpdateNoticeClose,
|
|
|
|
|
/// User clicked the "Open release page" button — opens the GitHub
|
|
|
|
|
/// release URL in the OS default browser and closes the notice.
|
|
|
|
|
UpdateNoticeOpenRelease,
|
2026-03-31 08:05:17 +03:00
|
|
|
// ── Page Setup ────────────────────────────────────────────────────────
|
|
|
|
|
/// Open the Page Setup panel for the current layout.
|
|
|
|
|
PageSetupOpen,
|
|
|
|
|
/// Close (cancel) the Page Setup panel without applying changes.
|
|
|
|
|
PageSetupClose,
|
|
|
|
|
/// Live-edit of the paper width field.
|
|
|
|
|
PageSetupWidthEdit(String),
|
|
|
|
|
/// Live-edit of the paper height field.
|
|
|
|
|
PageSetupHeightEdit(String),
|
2026-04-01 00:12:07 +03:00
|
|
|
/// User selected a paper size preset (e.g. "A4 Portrait").
|
|
|
|
|
PageSetupPreset(String),
|
|
|
|
|
/// User changed the plot area type ("Layout" or "Extents").
|
|
|
|
|
PageSetupPlotArea(String),
|
|
|
|
|
/// Toggle center-on-page.
|
|
|
|
|
PageSetupCenterToggle,
|
|
|
|
|
/// Live-edit of plot offset X.
|
|
|
|
|
PageSetupOffsetXEdit(String),
|
|
|
|
|
/// Live-edit of plot offset Y.
|
|
|
|
|
PageSetupOffsetYEdit(String),
|
|
|
|
|
/// User changed plot rotation.
|
|
|
|
|
PageSetupRotation(String),
|
Feat: ROADMAP Phase 1-5 batch — trim/extend, plot scale, viewport UX, mline caps, table alignment
- TRIM/EXTEND: Ray and XLine entities supported as cutting boundaries and trim targets;
trim results in Ray→Line/Ray, XLine→Ray/Ray or Line; hover preview added
- Plot scale override: Fit/1:1/1:2/1:5/1:10/1:20/1:50/1:100/2:1 buttons added to Page Setup
panel; PageSetupCommit applies scale to PlotSettings
- Viewport UX: locked viewport gets orange border; selected viewport gets white border
- Named view → viewport assignment: Choice dropdown in properties panel copies
view_target/direction/height to the viewport entity
- MLine caps: perpendicular start/end cap lines added for open (non-closed) MLines
- Wipeout polygon grips: boundary vertices become editable grips when clipping_enabled+Polygonal;
world→pixel back-projection on drag
- Table cell alignment: CellStyle.alignment (1-9) drives left/center/right + top/middle/bottom
text positioning; cxf::measure_text() helper added
- New commands/features: DIMCONTINUE (DCO), DIMBASELINE (DBA), TOLERANCE (TOL), TABLE,
ATTDEF, ATTEDIT, ATTDISP, BREAKATPOINT (BAP), PLOTWINDOW (PW), MLINE (ML);
DIMSTYLE/DIMCURRENT/CLAYER/LTSCALE/CELTSCALE/SCALETEXT/XDATA/UCSICON/REGEN/DRAWORDER extended
- PLINE arc mode: A/L/CLOSE text input, bulge computation, arc preview
- Warning cleanup: removed unused imports and unreachable patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 15:31:05 +03:00
|
|
|
PageSetupScale(String),
|
2026-03-31 08:05:17 +03:00
|
|
|
/// Apply the changes entered in Page Setup.
|
|
|
|
|
PageSetupCommit,
|
|
|
|
|
// ── Plot / Export ─────────────────────────────────────────────────────
|
|
|
|
|
/// Show the SVG save-file dialog and trigger export.
|
|
|
|
|
PlotExport,
|
|
|
|
|
/// Callback after the user picks (or cancels) the export path.
|
|
|
|
|
PlotExportPath(Option<std::path::PathBuf>),
|
2026-04-08 22:21:50 +03:00
|
|
|
/// Send current layout to the system printer (via lp / lpr).
|
|
|
|
|
PrintToPrinter,
|
|
|
|
|
/// Callback from the async printer job.
|
|
|
|
|
PrintResult(Result<String, String>),
|
2026-04-06 14:37:23 +03:00
|
|
|
// ── Plot Style Table ─────────────────────────────────────────────────
|
|
|
|
|
/// Open file dialog to load a CTB/STB plot style table.
|
|
|
|
|
PlotStyleLoad,
|
|
|
|
|
/// Callback when the user picks (or cancels) a CTB/STB file.
|
|
|
|
|
PlotStyleLoaded(Option<crate::io::plot_style::PlotStyleTable>),
|
|
|
|
|
/// Clear the active plot style table.
|
|
|
|
|
PlotStyleClear,
|
2026-04-08 18:19:48 +03:00
|
|
|
/// Open/close the Plot Style panel.
|
|
|
|
|
PlotStylePanelOpen,
|
2026-04-09 12:44:31 +03:00
|
|
|
#[allow(dead_code)]
|
2026-04-08 18:19:48 +03:00
|
|
|
PlotStylePanelClose,
|
|
|
|
|
/// Select an ACI entry in the panel.
|
|
|
|
|
PlotStylePanelSelectAci(u8),
|
|
|
|
|
/// Edit buffers changed.
|
|
|
|
|
PlotStylePanelColorBuf(String),
|
|
|
|
|
PlotStylePanelLwBuf(String),
|
|
|
|
|
PlotStylePanelScreenBuf(String),
|
|
|
|
|
/// Apply current edit buffers to the selected ACI entry.
|
|
|
|
|
PlotStylePanelApply,
|
|
|
|
|
/// Save the modified table back to disk.
|
|
|
|
|
PlotStylePanelSave,
|
|
|
|
|
/// Save callback.
|
|
|
|
|
PlotStylePanelSavePath(Option<std::path::PathBuf>),
|
2026-04-06 15:01:25 +03:00
|
|
|
// ── TextStyle Font Browser ────────────────────────────────────────────
|
|
|
|
|
TextStyleDialogOpen,
|
2026-04-09 12:44:31 +03:00
|
|
|
#[allow(dead_code)]
|
2026-04-06 15:01:25 +03:00
|
|
|
TextStyleDialogClose,
|
|
|
|
|
TextStyleDialogSelect(String),
|
|
|
|
|
TextStyleDialogSetCurrent,
|
|
|
|
|
TextStyleDialogNew,
|
|
|
|
|
TextStyleDialogDelete,
|
|
|
|
|
/// Edit a string field (FontFile / Width / Oblique).
|
2026-05-12 10:36:15 +03:00
|
|
|
TextStyleEdit {
|
|
|
|
|
field: &'static str,
|
|
|
|
|
value: String,
|
|
|
|
|
},
|
2026-04-06 15:01:25 +03:00
|
|
|
/// Commit edits to the selected text style.
|
|
|
|
|
TextStyleApply,
|
|
|
|
|
/// Select a font from the built-in font list.
|
|
|
|
|
TextStyleFontPick(String),
|
2026-04-06 14:57:11 +03:00
|
|
|
// ── TableStyle Dialog ─────────────────────────────────────────────────
|
|
|
|
|
TableStyleDialogOpen,
|
2026-04-09 12:44:31 +03:00
|
|
|
#[allow(dead_code)]
|
2026-04-06 14:57:11 +03:00
|
|
|
TableStyleDialogClose,
|
|
|
|
|
TableStyleDialogSelect(String),
|
|
|
|
|
TableStyleDialogNew,
|
|
|
|
|
TableStyleDialogDelete,
|
2026-04-06 14:54:05 +03:00
|
|
|
// ── MLineStyle Dialog ─────────────────────────────────────────────────
|
|
|
|
|
MlStyleDialogOpen,
|
2026-04-09 12:44:31 +03:00
|
|
|
#[allow(dead_code)]
|
2026-04-06 14:54:05 +03:00
|
|
|
MlStyleDialogClose,
|
|
|
|
|
MlStyleDialogSelect(String),
|
|
|
|
|
MlStyleDialogSetCurrent,
|
|
|
|
|
MlStyleDialogNew,
|
|
|
|
|
MlStyleDialogDelete,
|
2026-04-06 14:25:13 +03:00
|
|
|
// ── DimStyle Dialog ───────────────────────────────────────────────────
|
|
|
|
|
DimStyleDialogOpen,
|
|
|
|
|
DimStyleDialogClose,
|
|
|
|
|
/// Apply edits to the selected style.
|
|
|
|
|
DimStyleDialogApply,
|
|
|
|
|
/// Select a different style in the dialog list.
|
|
|
|
|
DimStyleDialogSelect(String),
|
|
|
|
|
/// Switch the active tab.
|
|
|
|
|
DimStyleDialogTab(u8),
|
|
|
|
|
/// Create a new empty style (prompts via command line).
|
|
|
|
|
DimStyleDialogNew,
|
|
|
|
|
/// Set the selected style as the document's current dim style.
|
|
|
|
|
DimStyleDialogSetCurrent,
|
|
|
|
|
/// Delete the selected style.
|
|
|
|
|
DimStyleDialogDelete,
|
|
|
|
|
// Field edit messages:
|
|
|
|
|
DsEdit(DsField, String),
|
|
|
|
|
DsToggle(DsField),
|
2026-04-06 23:19:08 +03:00
|
|
|
// ── Raster Image ──────────────────────────────────────────────────────
|
|
|
|
|
/// Open file-picker dialog for IMAGE command (async).
|
|
|
|
|
ImagePick,
|
|
|
|
|
/// Result of the image file picker + pixel dimension decode.
|
|
|
|
|
ImagePickResult(Result<(std::path::PathBuf, u32, u32), String>),
|
2026-04-08 00:02:38 +03:00
|
|
|
// ── XREF ──────────────────────────────────────────────────────────────
|
|
|
|
|
/// Open file-picker dialog for XATTACH command (async).
|
|
|
|
|
XAttachPick,
|
|
|
|
|
/// Result of the XATTACH file picker.
|
|
|
|
|
XAttachPickResult(Result<std::path::PathBuf, String>),
|
2026-04-08 00:05:04 +03:00
|
|
|
// ── WBLOCK ────────────────────────────────────────────────────────────
|
|
|
|
|
/// Trigger the WBLOCK save dialog for `block_name` (or `*` = selection).
|
|
|
|
|
WblockSave(String),
|
|
|
|
|
/// Result of the WBLOCK save path dialog.
|
|
|
|
|
WblockSaveResult(String, Option<std::path::PathBuf>),
|
2026-04-08 00:07:58 +03:00
|
|
|
// ── DATAEXTRACTION ────────────────────────────────────────────────────
|
|
|
|
|
/// Save the pre-built CSV string to a file chosen by the user.
|
|
|
|
|
DataExtractionSave(String),
|
|
|
|
|
/// Path chosen (or None = cancelled).
|
|
|
|
|
DataExtractionSaveResult(String, Option<std::path::PathBuf>),
|
2026-04-08 00:46:05 +03:00
|
|
|
// ── STL export ────────────────────────────────────────────────────────
|
|
|
|
|
/// Trigger STL export: collect meshes and show save dialog.
|
|
|
|
|
StlExport,
|
|
|
|
|
/// Callback after the user picks (or cancels) the STL save path.
|
|
|
|
|
StlExportPath(Option<std::path::PathBuf>),
|
2026-04-08 22:23:58 +03:00
|
|
|
// ── STEP export ───────────────────────────────────────────────────────
|
|
|
|
|
/// Trigger STEP AP203 export: show save dialog.
|
|
|
|
|
StepExport,
|
|
|
|
|
/// Callback after the user picks (or cancels) the STEP save path.
|
|
|
|
|
StepExportPath(Option<std::path::PathBuf>),
|
2026-04-08 12:59:27 +03:00
|
|
|
// ── OBJ import ────────────────────────────────────────────────────────
|
|
|
|
|
/// Trigger OBJ import: show open-file dialog.
|
|
|
|
|
ObjImport,
|
|
|
|
|
/// Callback after the user picks (or cancels) the OBJ file path.
|
|
|
|
|
ObjImportPath(Option<std::path::PathBuf>),
|
2026-03-22 22:44:32 +03:00
|
|
|
}
|
|
|
|
|
|
2026-05-23 17:16:15 +03:00
|
|
|
impl OpenCADStudio {
|
2026-03-22 22:44:32 +03:00
|
|
|
fn new() -> Self {
|
feat(app): add fixed Start tab with welcome page and recent documents
A pinned "Start" tab now lives at index 0. It cannot be closed, opens
on launch, and replaces the model-space viewport with a welcome page —
similar to Thunderbird's first-run screen.
- Boot opens with only the Start tab; Drawing1 is no longer auto-spawned.
- The Properties left panel becomes a Recent Documents rail on the
Start tab. Recents persist to disk
(%APPDATA%/H7CAD/recent.txt on Windows, $XDG_CONFIG_HOME/H7CAD/recent.txt
on Linux, ~/Library/Application Support/H7CAD/recent.txt on macOS), up
to 20 entries, saved on every open and rehydrated at boot.
Each row opens or removes the file in place.
- The Support ribbon group (Donate / Report / About / Changelog) is
retired; the same actions surface on the welcome page instead. The
Donate button is the primary call-to-action — solid #B03020 brand
fill with a soft brand-tinted ambient glow halo behind the action row
(Thunderbird-style coloured glow against the neutral page).
- Drawing-only overlays (mouse-area, viewcube, navbar, dynamic input,
selection markers) are suppressed on the Start tab so its clicks
don't trigger CAD commands. OpenFile's "current_is_empty" check
refuses to replace the Start tab, and TabClose ignores requests on
it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:19:31 +03:00
|
|
|
// Boot with only the Welcome/Start tab. The user creates drawings
|
|
|
|
|
// explicitly (File → New); we never auto-spawn Drawing1.
|
|
|
|
|
let start_tab = DocumentTab::new_start();
|
|
|
|
|
let mut app_menu = AppMenu::new();
|
|
|
|
|
// Restore recents from disk so the Start page lists them across runs.
|
|
|
|
|
app_menu.load_persistent_recents();
|
2026-03-22 22:44:32 +03:00
|
|
|
let mut app = Self {
|
|
|
|
|
start: Instant::now(),
|
feat(app): add fixed Start tab with welcome page and recent documents
A pinned "Start" tab now lives at index 0. It cannot be closed, opens
on launch, and replaces the model-space viewport with a welcome page —
similar to Thunderbird's first-run screen.
- Boot opens with only the Start tab; Drawing1 is no longer auto-spawned.
- The Properties left panel becomes a Recent Documents rail on the
Start tab. Recents persist to disk
(%APPDATA%/H7CAD/recent.txt on Windows, $XDG_CONFIG_HOME/H7CAD/recent.txt
on Linux, ~/Library/Application Support/H7CAD/recent.txt on macOS), up
to 20 entries, saved on every open and rehydrated at boot.
Each row opens or removes the file in place.
- The Support ribbon group (Donate / Report / About / Changelog) is
retired; the same actions surface on the welcome page instead. The
Donate button is the primary call-to-action — solid #B03020 brand
fill with a soft brand-tinted ambient glow halo behind the action row
(Thunderbird-style coloured glow against the neutral page).
- Drawing-only overlays (mouse-area, viewcube, navbar, dynamic input,
selection markers) are suppressed on the Start tab so its clicks
don't trigger CAD commands. OpenFile's "current_is_empty" check
refuses to replace the Start tab, and TabClose ignores requests on
it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:19:31 +03:00
|
|
|
tabs: vec![start_tab],
|
2026-03-22 22:44:32 +03:00
|
|
|
active_tab: 0,
|
feat(app): add fixed Start tab with welcome page and recent documents
A pinned "Start" tab now lives at index 0. It cannot be closed, opens
on launch, and replaces the model-space viewport with a welcome page —
similar to Thunderbird's first-run screen.
- Boot opens with only the Start tab; Drawing1 is no longer auto-spawned.
- The Properties left panel becomes a Recent Documents rail on the
Start tab. Recents persist to disk
(%APPDATA%/H7CAD/recent.txt on Windows, $XDG_CONFIG_HOME/H7CAD/recent.txt
on Linux, ~/Library/Application Support/H7CAD/recent.txt on macOS), up
to 20 entries, saved on every open and rehydrated at boot.
Each row opens or removes the file in place.
- The Support ribbon group (Donate / Report / About / Changelog) is
retired; the same actions surface on the welcome page instead. The
Donate button is the primary call-to-action — solid #B03020 brand
fill with a soft brand-tinted ambient glow halo behind the action row
(Thunderbird-style coloured glow against the neutral page).
- Drawing-only overlays (mouse-area, viewcube, navbar, dynamic input,
selection markers) are suppressed on the Start tab so its clicks
don't trigger CAD commands. OpenFile's "current_is_empty" check
refuses to replace the Start tab, and TabClose ignores requests on
it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:19:31 +03:00
|
|
|
tab_counter: 0,
|
2026-03-22 22:44:32 +03:00
|
|
|
ribbon: Ribbon::new(),
|
feat(app): add fixed Start tab with welcome page and recent documents
A pinned "Start" tab now lives at index 0. It cannot be closed, opens
on launch, and replaces the model-space viewport with a welcome page —
similar to Thunderbird's first-run screen.
- Boot opens with only the Start tab; Drawing1 is no longer auto-spawned.
- The Properties left panel becomes a Recent Documents rail on the
Start tab. Recents persist to disk
(%APPDATA%/H7CAD/recent.txt on Windows, $XDG_CONFIG_HOME/H7CAD/recent.txt
on Linux, ~/Library/Application Support/H7CAD/recent.txt on macOS), up
to 20 entries, saved on every open and rehydrated at boot.
Each row opens or removes the file in place.
- The Support ribbon group (Donate / Report / About / Changelog) is
retired; the same actions surface on the welcome page instead. The
Donate button is the primary call-to-action — solid #B03020 brand
fill with a soft brand-tinted ambient glow halo behind the action row
(Thunderbird-style coloured glow against the neutral page).
- Drawing-only overlays (mouse-area, viewcube, navbar, dynamic input,
selection markers) are suppressed on the Start tab so its clicks
don't trigger CAD commands. OpenFile's "current_is_empty" check
refuses to replace the Start tab, and TabClose ignores requests on
it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:19:31 +03:00
|
|
|
app_menu,
|
2026-03-22 22:44:32 +03:00
|
|
|
command_line: CommandLine::new(),
|
|
|
|
|
status_bar: StatusBar::new(),
|
|
|
|
|
cursor_pos: Point::ORIGIN,
|
|
|
|
|
vp_size: (1280.0, 720.0),
|
|
|
|
|
snapper: Snapper::default(),
|
|
|
|
|
snap_popup_open: false,
|
2026-05-06 17:50:46 +03:00
|
|
|
scale_popup_open: false,
|
2026-03-22 22:44:32 +03:00
|
|
|
pre_cmd_tangent: None,
|
|
|
|
|
ortho_mode: false,
|
|
|
|
|
polar_mode: false,
|
2026-04-07 19:30:25 +03:00
|
|
|
polar_increment_deg: 45.0,
|
2026-03-22 22:44:32 +03:00
|
|
|
show_grid: false,
|
2026-04-08 00:12:09 +03:00
|
|
|
dyn_input: true,
|
2026-04-03 19:25:55 +03:00
|
|
|
show_ucs_icon: true,
|
2026-04-24 01:23:06 +03:00
|
|
|
show_viewcube: true,
|
|
|
|
|
show_navbar: true,
|
|
|
|
|
show_properties: true,
|
|
|
|
|
show_file_tabs: true,
|
|
|
|
|
show_layout_tabs: true,
|
2026-03-22 22:44:32 +03:00
|
|
|
last_point: None,
|
|
|
|
|
layer_window: None,
|
|
|
|
|
main_window: None,
|
2026-05-12 10:36:15 +03:00
|
|
|
page_setup_window: None,
|
|
|
|
|
textstyle_window: None,
|
|
|
|
|
tablestyle_window: None,
|
|
|
|
|
mlstyle_window: None,
|
2026-04-08 22:36:28 +03:00
|
|
|
layout_manager_window: None,
|
2026-05-12 10:36:15 +03:00
|
|
|
plotstyle_window: None,
|
|
|
|
|
dimstyle_window: None,
|
|
|
|
|
shortcuts_window: None,
|
|
|
|
|
about_window: None,
|
2026-05-16 19:55:57 +03:00
|
|
|
update_notice_window: None,
|
|
|
|
|
update_notice_version: None,
|
2026-05-22 12:55:37 +03:00
|
|
|
update_notice_body: None,
|
2026-03-22 22:44:32 +03:00
|
|
|
clipboard: Vec::new(),
|
|
|
|
|
clipboard_centroid: glam::Vec3::ZERO,
|
2026-03-31 07:13:36 +03:00
|
|
|
layout_context_menu: None,
|
|
|
|
|
layout_rename_state: None,
|
2026-03-31 07:24:16 +03:00
|
|
|
last_vp_click_time: None,
|
|
|
|
|
last_vp_click_pos: None,
|
2026-03-31 08:05:17 +03:00
|
|
|
page_setup_w: String::new(),
|
|
|
|
|
page_setup_h: String::new(),
|
2026-04-01 00:12:07 +03:00
|
|
|
page_setup_plot_area: "Layout".to_string(),
|
|
|
|
|
page_setup_center: true,
|
|
|
|
|
page_setup_offset_x: "0.0".to_string(),
|
|
|
|
|
page_setup_offset_y: "0.0".to_string(),
|
|
|
|
|
page_setup_rotation: "0".to_string(),
|
Feat: ROADMAP Phase 1-5 batch — trim/extend, plot scale, viewport UX, mline caps, table alignment
- TRIM/EXTEND: Ray and XLine entities supported as cutting boundaries and trim targets;
trim results in Ray→Line/Ray, XLine→Ray/Ray or Line; hover preview added
- Plot scale override: Fit/1:1/1:2/1:5/1:10/1:20/1:50/1:100/2:1 buttons added to Page Setup
panel; PageSetupCommit applies scale to PlotSettings
- Viewport UX: locked viewport gets orange border; selected viewport gets white border
- Named view → viewport assignment: Choice dropdown in properties panel copies
view_target/direction/height to the viewport entity
- MLine caps: perpendicular start/end cap lines added for open (non-closed) MLines
- Wipeout polygon grips: boundary vertices become editable grips when clipping_enabled+Polygonal;
world→pixel back-projection on drag
- Table cell alignment: CellStyle.alignment (1-9) drives left/center/right + top/middle/bottom
text positioning; cxf::measure_text() helper added
- New commands/features: DIMCONTINUE (DCO), DIMBASELINE (DBA), TOLERANCE (TOL), TABLE,
ATTDEF, ATTEDIT, ATTDISP, BREAKATPOINT (BAP), PLOTWINDOW (PW), MLINE (ML);
DIMSTYLE/DIMCURRENT/CLAYER/LTSCALE/CELTSCALE/SCALETEXT/XDATA/UCSICON/REGEN/DRAWORDER extended
- PLINE arc mode: A/L/CLOSE text input, bulge computation, arc preview
- Warning cleanup: removed unused imports and unreachable patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 15:31:05 +03:00
|
|
|
page_setup_scale: "Fit".to_string(),
|
2026-05-13 09:59:07 +03:00
|
|
|
opening: None,
|
2026-05-01 11:31:11 +03:00
|
|
|
pending_close: None,
|
|
|
|
|
unsaved_dialog_window: None,
|
2026-05-01 16:12:32 +03:00
|
|
|
save_dialog_window: None,
|
|
|
|
|
save_dialog_format: "DWG 2018".to_string(),
|
|
|
|
|
save_dialog_filename: "drawing.dwg".to_string(),
|
|
|
|
|
save_dialog_folder: std::env::var("HOME")
|
|
|
|
|
.or_else(|_| std::env::var("USERPROFILE"))
|
2026-05-01 16:20:38 +03:00
|
|
|
.unwrap_or_else(|_| ".".to_string())
|
|
|
|
|
.into(),
|
|
|
|
|
save_dialog_entries: Vec::new(),
|
2026-05-01 16:12:32 +03:00
|
|
|
save_dialog_for_unsaved: false,
|
2026-04-06 14:37:23 +03:00
|
|
|
// Plot style
|
|
|
|
|
active_plot_style: None,
|
2026-04-08 18:31:09 +03:00
|
|
|
// Color scheme (default: dark CAD-style)
|
|
|
|
|
active_theme: Theme::Dark,
|
2026-04-08 18:34:10 +03:00
|
|
|
// Keyboard shortcuts
|
|
|
|
|
shortcut_overrides: std::collections::HashMap::new(),
|
2026-04-08 18:28:30 +03:00
|
|
|
// Layout Manager
|
|
|
|
|
layout_manager_selected: "Model".to_string(),
|
|
|
|
|
layout_manager_rename_buf: String::new(),
|
2026-04-08 18:19:48 +03:00
|
|
|
plotstyle_panel_aci: 1,
|
|
|
|
|
ps_color_buf: String::new(),
|
|
|
|
|
ps_lineweight_buf: "255".to_string(),
|
|
|
|
|
ps_screening_buf: "100".to_string(),
|
2026-04-06 15:01:25 +03:00
|
|
|
// TextStyle font browser
|
|
|
|
|
textstyle_selected: "Standard".to_string(),
|
|
|
|
|
textstyle_font: String::new(),
|
|
|
|
|
textstyle_width: "1.0".to_string(),
|
|
|
|
|
textstyle_oblique: "0.0".to_string(),
|
2026-04-06 14:57:11 +03:00
|
|
|
// TableStyle dialog
|
|
|
|
|
tablestyle_selected: "Standard".to_string(),
|
2026-04-06 14:54:05 +03:00
|
|
|
// MLineStyle dialog
|
|
|
|
|
mlstyle_selected: "Standard".to_string(),
|
2026-04-06 14:25:13 +03:00
|
|
|
// DimStyle dialog
|
|
|
|
|
dimstyle_selected: "Standard".to_string(),
|
|
|
|
|
dimstyle_tab: 0,
|
2026-05-12 10:36:15 +03:00
|
|
|
ds_dimdle: "0".to_string(),
|
|
|
|
|
ds_dimdli: "3.75".to_string(),
|
|
|
|
|
ds_dimgap: "0.625".to_string(),
|
|
|
|
|
ds_dimexe: "1.25".to_string(),
|
2026-04-06 14:25:13 +03:00
|
|
|
ds_dimexo: "0.625".to_string(),
|
2026-05-12 10:36:15 +03:00
|
|
|
ds_dimsd1: false,
|
|
|
|
|
ds_dimsd2: false,
|
|
|
|
|
ds_dimse1: false,
|
|
|
|
|
ds_dimse2: false,
|
|
|
|
|
ds_dimasz: "0.18".to_string(),
|
|
|
|
|
ds_dimcen: "0.09".to_string(),
|
2026-04-06 14:25:13 +03:00
|
|
|
ds_dimtsz: "0".to_string(),
|
2026-05-12 10:36:15 +03:00
|
|
|
ds_dimtxt: "0.18".to_string(),
|
|
|
|
|
ds_dimtxsty: "Standard".to_string(),
|
2026-04-06 14:25:13 +03:00
|
|
|
ds_dimtad: "1".to_string(),
|
2026-05-12 10:36:15 +03:00
|
|
|
ds_dimtih: false,
|
|
|
|
|
ds_dimtoh: false,
|
|
|
|
|
ds_dimscale: "1".to_string(),
|
|
|
|
|
ds_dimlfac: "1".to_string(),
|
|
|
|
|
ds_dimlunit: "2".to_string(),
|
|
|
|
|
ds_dimdec: "2".to_string(),
|
2026-04-06 14:25:13 +03:00
|
|
|
ds_dimpost: "<>".to_string(),
|
2026-05-12 10:36:15 +03:00
|
|
|
ds_dimtol: false,
|
|
|
|
|
ds_dimlim: false,
|
|
|
|
|
ds_dimtp: "0".to_string(),
|
|
|
|
|
ds_dimtm: "0".to_string(),
|
|
|
|
|
ds_dimtdec: "2".to_string(),
|
|
|
|
|
ds_dimtfac: "1".to_string(),
|
2026-03-22 22:44:32 +03:00
|
|
|
};
|
|
|
|
|
app.sync_ribbon_layers();
|
|
|
|
|
app
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Boot function for `iced::daemon`: returns initial state plus a task that
|
|
|
|
|
/// opens the primary application window.
|
|
|
|
|
fn boot() -> (Self, Task<Message>) {
|
|
|
|
|
use helpers::build_window_icon;
|
|
|
|
|
let state = Self::new();
|
|
|
|
|
let (id, open_task) = window::open(window::Settings {
|
|
|
|
|
maximized: true,
|
|
|
|
|
icon: window::icon::from_rgba(build_window_icon(), 32, 32).ok(),
|
2026-05-01 11:31:11 +03:00
|
|
|
exit_on_close_request: false,
|
2026-03-22 22:44:32 +03:00
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
let mut s = state;
|
|
|
|
|
s.main_window = Some(id);
|
2026-05-16 19:55:57 +03:00
|
|
|
let open_main = open_task.map(|_| Message::Noop);
|
|
|
|
|
let check_update = Task::perform(
|
|
|
|
|
crate::update_check::check_for_update(),
|
|
|
|
|
Message::UpdateCheckResult,
|
|
|
|
|
);
|
2026-05-26 18:59:51 +03:00
|
|
|
let focus_cmd = s.focus_cmd_input();
|
|
|
|
|
(s, Task::batch([open_main, check_update, focus_cmd]))
|
2026-03-22 22:44:32 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
|
|
pub fn run() -> iced::Result {
|
2026-05-23 17:16:15 +03:00
|
|
|
iced::daemon(OpenCADStudio::boot, OpenCADStudio::update, OpenCADStudio::view)
|
|
|
|
|
.subscription(OpenCADStudio::subscription)
|
|
|
|
|
.title(|state: &OpenCADStudio, window_id: window::Id| {
|
2026-05-12 10:36:15 +03:00
|
|
|
if Some(window_id) == state.layer_window {
|
|
|
|
|
return "Layer Properties Manager".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.page_setup_window {
|
|
|
|
|
return "Page Setup".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.textstyle_window {
|
|
|
|
|
return "Text Style".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.tablestyle_window {
|
|
|
|
|
return "Table Style".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.mlstyle_window {
|
|
|
|
|
return "Multiline Style".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.layout_manager_window {
|
|
|
|
|
return "Layout Manager".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.plotstyle_window {
|
|
|
|
|
return "Plot Style Table Editor".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.dimstyle_window {
|
|
|
|
|
return "Dimension Style Manager".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.shortcuts_window {
|
|
|
|
|
return "Keyboard Shortcuts".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.about_window {
|
2026-05-23 17:16:15 +03:00
|
|
|
return "About Open CAD Studio".into();
|
2026-05-12 10:36:15 +03:00
|
|
|
}
|
2026-05-16 19:55:57 +03:00
|
|
|
if Some(window_id) == state.update_notice_window {
|
|
|
|
|
return "Update Available".into();
|
|
|
|
|
}
|
2026-05-12 10:36:15 +03:00
|
|
|
if Some(window_id) == state.unsaved_dialog_window {
|
|
|
|
|
return "Unsaved Changes".into();
|
|
|
|
|
}
|
|
|
|
|
if Some(window_id) == state.save_dialog_window {
|
|
|
|
|
return "Save As".into();
|
|
|
|
|
}
|
2026-04-08 22:36:28 +03:00
|
|
|
if let Some(tab) = state.tabs.get(state.active_tab) {
|
2026-03-22 22:44:32 +03:00
|
|
|
let dot = if tab.dirty { "● " } else { "" };
|
|
|
|
|
let name = tab.tab_display_name();
|
2026-05-23 17:16:15 +03:00
|
|
|
format!("{}Open CAD Studio — {}", dot, name)
|
2026-03-22 22:44:32 +03:00
|
|
|
} else {
|
2026-05-23 17:16:15 +03:00
|
|
|
"Open CAD Studio".to_string()
|
2026-03-22 22:44:32 +03:00
|
|
|
}
|
|
|
|
|
})
|
2026-05-23 17:16:15 +03:00
|
|
|
.theme(|state: &OpenCADStudio, _| state.active_theme.clone())
|
2026-03-22 22:44:32 +03:00
|
|
|
.run()
|
|
|
|
|
}
|