From 849e3728fe7345ac1fd176475af6d3e7b43e2ce8 Mon Sep 17 00:00:00 2001 From: Halit Can Date: Thu, 16 Jul 2026 12:16:12 +0300 Subject: [PATCH] feat(iced): parametrize shape previews with user tool settings --- .../crates/hcie-iced-gui/src/canvas/mod.rs | 71 ++++++++++++++++--- .../crates/hcie-iced-gui/src/dock/view.rs | 3 +- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/hcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs b/hcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs index 3a7f227..f90c460 100644 --- a/hcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs +++ b/hcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs @@ -68,6 +68,12 @@ struct OverlayProgram { pressure: f32, /// Active tool (drives vector shape preview geometry). active_tool: hcie_engine_api::Tool, + /// Number of points for star shape preview. + star_points: u32, + /// Number of sides for polygon shape preview. + polygon_sides: u32, + /// Corner radius for rectangle shape preview (rounded corners when > 0). + rect_radius: f32, /// Gradient drag preview endpoints in canvas-space. gradient_drag: Option<((f32, f32), (f32, f32))>, /// Extracted edges for marching ants rendering. @@ -706,14 +712,15 @@ impl canvas::Program for OverlayProgram { frame.stroke(&line_path, stroke_style); } hcie_engine_api::Tool::VectorStar => { - // 5-point star preview (ignores settings points for the preview). + // Star preview using user's configured point count. let cx = origin_x + ((x0 + x1) / 2.0) * self.zoom; let cy = origin_y + ((y0 + y1) / 2.0) * self.zoom; let r_out = ((x1 - x0).abs() / 2.0).max(1.0) * self.zoom; let r_in = r_out * 0.5; + let points = self.star_points.max(3); let star_path = Path::new(|b| { - for i in 0..10 { - let t = (i as f32) * std::f32::consts::PI / 5.0 - std::f32::consts::FRAC_PI_2; + for i in 0..(points * 2) { + let t = (i as f32) * std::f32::consts::PI / points as f32 - std::f32::consts::FRAC_PI_2; let r = if i % 2 == 0 { r_out } else { r_in }; let px = cx + r * t.cos(); let py = cy + r * t.sin(); @@ -728,13 +735,14 @@ impl canvas::Program for OverlayProgram { frame.stroke(&star_path, stroke_style); } hcie_engine_api::Tool::VectorPolygon => { - // 6-sided polygon preview. + // Polygon preview using user's configured side count. let cx = origin_x + ((x0 + x1) / 2.0) * self.zoom; let cy = origin_y + ((y0 + y1) / 2.0) * self.zoom; let r = ((x1 - x0).abs() / 2.0).max(1.0) * self.zoom; + let sides = self.polygon_sides.max(3); let poly_path = Path::new(|b| { - for i in 0..6 { - let t = (i as f32) * std::f32::consts::TAU / 6.0 - std::f32::consts::FRAC_PI_2; + for i in 0..sides { + let t = (i as f32) * std::f32::consts::TAU / sides as f32 - std::f32::consts::FRAC_PI_2; let px = cx + r * t.cos(); let py = cy + r * t.sin(); if i == 0 { @@ -1063,14 +1071,48 @@ impl canvas::Program for OverlayProgram { _ => { // Rectangular shapes (Rect, Arrow, Rhombus, etc.) fall // back to a bounding-box outline for the preview. + // For VectorRect, show rounded corners when rect_radius > 0. let v_x = origin_x + x0.min(x1) * self.zoom; let v_y = origin_y + y0.min(y1) * self.zoom; let v_w = (x1 - x0).abs() * self.zoom; let v_h = (y1 - y0).abs() * self.zoom; - let v_path = Path::rectangle( - Point::new(v_x, v_y), - Size::new(v_w, v_h), - ); + let v_path = if self.active_tool == hcie_engine_api::Tool::VectorRect && self.rect_radius > 0.0 { + let max_r = (v_w.min(v_h) / 2.0).min(self.rect_radius * self.zoom); + let k = max_r * 0.5523; // cubic approximation of quarter circle + Path::new(|b| { + b.move_to(Point::new(v_x + max_r, v_y)); + b.line_to(Point::new(v_x + v_w - max_r, v_y)); + b.bezier_curve_to( + Point::new(v_x + v_w - max_r + k, v_y), + Point::new(v_x + v_w, v_y + max_r - k), + Point::new(v_x + v_w, v_y + max_r), + ); + b.line_to(Point::new(v_x + v_w, v_y + v_h - max_r)); + b.bezier_curve_to( + Point::new(v_x + v_w, v_y + v_h - max_r + k), + Point::new(v_x + v_w - max_r + k, v_y + v_h), + Point::new(v_x + v_w - max_r, v_y + v_h), + ); + b.line_to(Point::new(v_x + max_r, v_y + v_h)); + b.bezier_curve_to( + Point::new(v_x + max_r - k, v_y + v_h), + Point::new(v_x, v_y + v_h - max_r + k), + Point::new(v_x, v_y + v_h - max_r), + ); + b.line_to(Point::new(v_x, v_y + max_r)); + b.bezier_curve_to( + Point::new(v_x, v_y + max_r - k), + Point::new(v_x + max_r - k, v_y), + Point::new(v_x + max_r, v_y), + ); + b.close(); + }) + } else { + Path::rectangle( + Point::new(v_x, v_y), + Size::new(v_w, v_h), + ) + }; frame.stroke(&v_path, stroke_style); } } @@ -1221,11 +1263,17 @@ impl canvas::Program for OverlayProgram { /// * `tool_state` — current tool state (for status bar info) /// * `marching_ants_offset` — animation offset for marching ants (0.0..1.0) /// * `pressure` — current pen pressure in [0.0, 1.0] for HUD display +/// * `star_points` — number of points for star shape preview +/// * `polygon_sides` — number of sides for polygon shape preview +/// * `rect_radius` — corner radius for rectangle shape preview pub fn view<'a>( doc: &'a crate::app::IcedDocument, tool_state: &'a crate::app::ToolState, marching_ants_offset: f32, pressure: f32, + star_points: u32, + polygon_sides: u32, + rect_radius: f32, ) -> Element<'a, Message> { let engine_w = doc.engine.canvas_width(); let engine_h = doc.engine.canvas_height(); @@ -1280,6 +1328,9 @@ pub fn view<'a>( marching_ants_offset, pressure, active_tool: tool_state.active_tool, + star_points, + polygon_sides, + rect_radius, gradient_drag: doc.gradient_drag, marching_ants_edges: doc.marching_ants_edges.clone(), selected_vector_bounds: sel_vec_bounds, diff --git a/hcie-iced-app/crates/hcie-iced-gui/src/dock/view.rs b/hcie-iced-app/crates/hcie-iced-gui/src/dock/view.rs index 17dfd71..0cc1d26 100644 --- a/hcie-iced-app/crates/hcie-iced-gui/src/dock/view.rs +++ b/hcie-iced-app/crates/hcie-iced-gui/src/dock/view.rs @@ -41,7 +41,8 @@ pub fn dock_view<'a>( let canvas = { let doc = &app.documents[app.active_doc]; let pressure = app.tablet_state.lock().map(|s| s.current_pressure()).unwrap_or(1.0); - crate::canvas::view(doc, &app.tool_state, app.marching_ants_offset, pressure) + let ts = &app.settings.tool_settings; + crate::canvas::view(doc, &app.tool_state, app.marching_ants_offset, pressure, ts.vector_points, ts.vector_sides, ts.vector_radius) }; column![doc_tab_bar, canvas] .width(Length::Fill)