feat(iced): parametrize shape previews with user tool settings
This commit is contained in:
@@ -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<Message> 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<Message> 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<Message> 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(
|
||||
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<Message> 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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user