From 070ad1f9c5bb65f22458c7fc69e21f35dc242969 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 22 Apr 2026 22:22:33 +0300 Subject: [PATCH] feat: add Report/About/Changelog buttons to Support ribbon group - REPORT opens GitHub new-issue page - ABOUT opens a dialog window with version, OS and arch info + Copy Info button - CHANGELOG opens GitHub releases page - Fix Windows build: add windows-sys as target-specific dependency for PRINT command Co-Authored-By: Claude Sonnet 4.6 --- Cargo.lock | 1 + Cargo.toml | 3 ++ assets/icons/about.svg | 8 +++ assets/icons/changelog.svg | 9 ++++ assets/icons/report.svg | 17 +++++++ src/app/commands.rs | 14 +++++ src/app/mod.rs | 6 +++ src/app/update.rs | 25 +++++++++ src/app/view.rs | 3 ++ src/modules/home/about.rs | 10 ++++ src/modules/home/changelog.rs | 10 ++++ src/modules/home/mod.rs | 9 ++++ src/modules/home/report.rs | 10 ++++ src/ui/about.rs | 96 +++++++++++++++++++++++++++++++++++ src/ui/mod.rs | 1 + 15 files changed, 222 insertions(+) create mode 100644 assets/icons/about.svg create mode 100644 assets/icons/changelog.svg create mode 100644 assets/icons/report.svg create mode 100644 src/modules/home/about.rs create mode 100644 src/modules/home/changelog.rs create mode 100644 src/modules/home/report.rs create mode 100644 src/ui/about.rs diff --git a/Cargo.lock b/Cargo.lock index cdfab1d4..9c9496da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,7 @@ dependencies = [ "truck-meshalgo", "truck-modeling", "truck-polymesh", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 31433981..abe64f6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ open = "5" printpdf = "0.9.1" flate2 = "1" image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] } + +[target.'cfg(target_os = "windows")'.dependencies] +windows-sys = { version = "0.59", features = ["Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] } diff --git a/assets/icons/about.svg b/assets/icons/about.svg new file mode 100644 index 00000000..7c3b9c03 --- /dev/null +++ b/assets/icons/about.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icons/changelog.svg b/assets/icons/changelog.svg new file mode 100644 index 00000000..0779b636 --- /dev/null +++ b/assets/icons/changelog.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icons/report.svg b/assets/icons/report.svg new file mode 100644 index 00000000..b51e1b25 --- /dev/null +++ b/assets/icons/report.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/app/commands.rs b/src/app/commands.rs index 2e8ce892..1f3c26d6 100644 --- a/src/app/commands.rs +++ b/src/app/commands.rs @@ -2042,6 +2042,20 @@ impl H7CAD { self.command_line.push_info("Opening Patreon page..."); } + "REPORT" => { + let _ = open::that("https://github.com/HakanSeven12/H7CAD/issues/new"); + self.command_line.push_info("Opening GitHub issue page..."); + } + + "ABOUT" => { + return Task::done(Message::AboutOpen); + } + + "CHANGELOG" => { + let _ = open::that("https://github.com/HakanSeven12/H7CAD/releases"); + self.command_line.push_info("Opening release notes..."); + } + // ── Keyboard Shortcuts panel ────────────────────────────────── cmd if cmd == "SHORTCUTS" || cmd.starts_with("SHORTCUTS ") => { let raw_rest = cmd.trim_start_matches("SHORTCUTS").trim(); diff --git a/src/app/mod.rs b/src/app/mod.rs index 0f66ca57..db6f9e9c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -68,6 +68,7 @@ pub(super) struct H7CAD { plotstyle_window: Option, dimstyle_window: Option, shortcuts_window: Option, + about_window: Option, /// In-memory clipboard: cloned entities waiting to be pasted. clipboard: Vec, /// Centroid of the clipboard entities (XZ plane, Y-up). @@ -372,6 +373,9 @@ pub enum Message { ShortcutsPanelOpen, #[allow(dead_code)] ShortcutsPanelClose, + // ── About window ──────────────────────────────────────────────────── + AboutOpen, + AboutCopyInfo, /// Close the viewport right-click context menu without performing any action. ViewportContextMenuClose, /// A window was closed by the OS (e.g. the user clicked the title-bar ✕). @@ -552,6 +556,7 @@ impl H7CAD { plotstyle_window: None, dimstyle_window: None, shortcuts_window: None, + about_window: None, clipboard: Vec::new(), clipboard_centroid: glam::Vec3::ZERO, layout_context_menu: None, @@ -644,6 +649,7 @@ pub fn run() -> iced::Result { 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 { return "About H7CAD".into(); } if let Some(tab) = state.tabs.get(state.active_tab) { let dot = if tab.dirty { "● " } else { "" }; let name = tab.tab_display_name(); diff --git a/src/app/update.rs b/src/app/update.rs index fafd66fb..ba72e71e 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -704,6 +704,7 @@ impl H7CAD { if self.plotstyle_window == Some(id) { self.plotstyle_window = None; } if self.dimstyle_window == Some(id) { self.dimstyle_window = None; } if self.shortcuts_window == Some(id) { self.shortcuts_window = None; } + if self.about_window == Some(id) { self.about_window = None; } Task::none() } @@ -2502,6 +2503,30 @@ impl H7CAD { } } + // ── About window ────────────────────────────────────────────── + Message::AboutOpen => { + if let Some(id) = self.about_window { + return window::gain_focus(id); + } + let (id, task) = window::open(window::Settings { + size: iced::Size::new(340.0, 240.0), + resizable: false, + ..Default::default() + }); + self.about_window = Some(id); + task.map(|_| Message::Noop) + } + + Message::AboutCopyInfo => { + let info = format!( + "H7CAD v{}\nOS: {}\nArch: {}", + env!("CARGO_PKG_VERSION"), + std::env::consts::OS, + std::env::consts::ARCH, + ); + iced::clipboard::write(info) + } + Message::ViewportContextMenuClose => { let i = self.active_tab; self.tabs[i].scene.selection.borrow_mut().context_menu = None; diff --git a/src/app/view.rs b/src/app/view.rs index 3670b5c5..20341551 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -96,6 +96,9 @@ impl H7CAD { if Some(window_id) == self.shortcuts_window { return crate::ui::shortcuts::view_window(&self.shortcut_overrides); } + if Some(window_id) == self.about_window { + return crate::ui::about::view_window(); + } let i = self.active_tab; let tab = &self.tabs[i]; diff --git a/src/modules/home/about.rs b/src/modules/home/about.rs new file mode 100644 index 00000000..854cf2f5 --- /dev/null +++ b/src/modules/home/about.rs @@ -0,0 +1,10 @@ +use crate::modules::{IconKind, ModuleEvent, ToolDef}; + +pub fn tool() -> ToolDef { + ToolDef { + id: "ABOUT", + label: "About", + icon: IconKind::Svg(include_bytes!("../../../assets/icons/about.svg")), + event: ModuleEvent::Command("ABOUT".to_string()), + } +} diff --git a/src/modules/home/changelog.rs b/src/modules/home/changelog.rs new file mode 100644 index 00000000..8987560f --- /dev/null +++ b/src/modules/home/changelog.rs @@ -0,0 +1,10 @@ +use crate::modules::{IconKind, ModuleEvent, ToolDef}; + +pub fn tool() -> ToolDef { + ToolDef { + id: "CHANGELOG", + label: "Changelog", + icon: IconKind::Svg(include_bytes!("../../../assets/icons/changelog.svg")), + event: ModuleEvent::Command("CHANGELOG".to_string()), + } +} diff --git a/src/modules/home/mod.rs b/src/modules/home/mod.rs index 57d23631..9e3bda4b 100644 --- a/src/modules/home/mod.rs +++ b/src/modules/home/mod.rs @@ -2,8 +2,11 @@ pub mod clipboard; pub mod defaults; +mod about; +mod changelog; mod donate; pub mod draw; +mod report; pub mod groups; pub mod inquiry; pub mod layers; @@ -27,7 +30,10 @@ impl CadModule for HomeModule { use crate::modules::annotate::{angular_dim, leader_cmd, linear_dim, mleader_cmd, mtext, radius_dim, text}; use crate::modules::insert::{create_block, insert_block}; use clipboard::{copy_clip, cut, paste}; + use about; + use changelog; use donate; + use report; use draw::{arc, circle, ellipse, hatch, line, polyline, shapes}; use layers::{layfrz, laylck, layoff, layon, laythw, layulk, make_current, match_layer, panel}; use groups::{group, ungroup}; @@ -187,6 +193,9 @@ impl CadModule for HomeModule { title: "Support", tools: vec![ RibbonItem::LargeTool(donate::tool()), + report::tool().into(), + about::tool().into(), + changelog::tool().into(), ], }, ] diff --git a/src/modules/home/report.rs b/src/modules/home/report.rs new file mode 100644 index 00000000..48424c30 --- /dev/null +++ b/src/modules/home/report.rs @@ -0,0 +1,10 @@ +use crate::modules::{IconKind, ModuleEvent, ToolDef}; + +pub fn tool() -> ToolDef { + ToolDef { + id: "REPORT", + label: "Report", + icon: IconKind::Svg(include_bytes!("../../../assets/icons/report.svg")), + event: ModuleEvent::Command("REPORT".to_string()), + } +} diff --git a/src/ui/about.rs b/src/ui/about.rs new file mode 100644 index 00000000..a349d65a --- /dev/null +++ b/src/ui/about.rs @@ -0,0 +1,96 @@ +use crate::app::Message; +use iced::widget::{button, column, container, row, text, Space}; +use iced::{Background, Border, Color, Element, Fill, Theme}; + +const BG: Color = Color { r: 0.15, g: 0.15, b: 0.15, a: 1.0 }; +const PANEL: Color = Color { r: 0.12, g: 0.12, b: 0.12, a: 1.0 }; +const BORDER: Color = Color { r: 0.30, g: 0.30, b: 0.30, a: 1.0 }; +const DIM: Color = Color { r: 0.55, g: 0.55, b: 0.55, a: 1.0 }; +const ACCENT: Color = Color { r: 0.25, g: 0.50, b: 0.85, a: 1.0 }; +const WHITE: Color = Color { r: 0.92, g: 0.92, b: 0.92, a: 1.0 }; + +fn info_row<'a>(label: &'static str, value: String) -> Element<'a, Message> { + row![ + text(label).size(11).color(DIM).width(100), + text(value).size(11).color(WHITE), + ] + .spacing(8) + .align_y(iced::Center) + .padding([3, 0]) + .into() +} + +pub fn view_window<'a>() -> Element<'a, Message> { + let version = env!("CARGO_PKG_VERSION"); + let os = std::env::consts::OS; + let arch = std::env::consts::ARCH; + + let logo = container( + column![ + text("H7CAD").size(32).color(ACCENT), + text("CAD application for Architecture & Engineering") + .size(11).color(DIM), + ] + .spacing(4) + .align_x(iced::Center), + ) + .width(Fill) + .padding(iced::Padding { top: 20.0, right: 0.0, bottom: 16.0, left: 0.0 }) + .align_x(iced::Center); + + let info_block = container( + column![ + info_row("Version", format!("v{}", version)), + info_row("Platform", os.to_string()), + info_row("Arch", arch.to_string()), + ] + .spacing(2) + .padding([12, 16]), + ) + .width(Fill) + .style(|_: &Theme| container::Style { + background: Some(Background::Color(PANEL)), + border: Border { + color: BORDER, + width: 1.0, + radius: 4.0.into(), + }, + ..Default::default() + }); + + let copy_btn = button( + text("Copy Info").size(11), + ) + .on_press(Message::AboutCopyInfo) + .style(|_: &Theme, st| button::Style { + background: Some(Background::Color(match st { + button::Status::Hovered | button::Status::Pressed => + Color { r: 0.20, g: 0.42, b: 0.72, a: 1.0 }, + _ => ACCENT, + })), + text_color: WHITE, + border: Border { radius: 4.0.into(), ..Default::default() }, + ..Default::default() + }) + .padding([6, 16]); + + let footer = row![ + Space::new().width(Fill), + copy_btn, + ] + .align_y(iced::Center) + .padding(iced::Padding { top: 12.0, right: 0.0, bottom: 0.0, left: 0.0 }); + + container( + column![logo, info_block, footer] + .spacing(0) + .padding(iced::Padding { top: 0.0, right: 20.0, bottom: 20.0, left: 20.0 }), + ) + .style(|_: &Theme| container::Style { + background: Some(Background::Color(BG)), + ..Default::default() + }) + .width(Fill) + .height(Fill) + .into() +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 7806c924..8d823f69 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -2,6 +2,7 @@ /// Change this to scale the ribbon, layer manager rows, and property panel rows uniformly. pub const ROW_H: f32 = 26.0; +pub mod about; pub mod app_menu; pub mod command_line; pub mod dimstyle;