feat(svg-editor): Implement SVG shape loading and editing functionality

- Add SVG shape loading from disk, allowing users to customize shapes by placing SVG files in the designated directory.
- Introduce a new `ShapeCatalog` to manage SVG shapes, prioritizing user-defined shapes over built-in templates.
- Implement an SVG editor with node-based editing capabilities, enabling users to manipulate SVG paths directly.
- Create a new `SvgEditable` structure to represent editable SVG shapes, supporting operations like adding, removing, and moving nodes.
- Enhance the GUI with an SVG editor panel for visual editing of SVG shapes, including controls for node manipulation and saving changes.
- Ensure compatibility with existing shape tools and maintain a seamless user experience across the application.
This commit is contained in:
2026-07-19 13:50:17 +03:00
parent 5632c916ee
commit 6e0d179be9
20 changed files with 1723 additions and 25 deletions
@@ -5010,6 +5010,14 @@ impl HcieIcedApp {
.engine
.set_active_layer(safe_source);
}
// Snapshot shape catalog entries for CustomShape tool
let custom_shapes: Vec<(String, String)> = self.documents
.get(self.active_doc)
.map(|d| {
d.engine.shape_catalog.all().iter().map(|e| (e.kind.clone(), e.svg.clone())).collect()
})
.unwrap_or_default();
let engine = &mut self.documents[self.active_doc].engine;
let color = self.fg_color;
let stroke = self.settings.tool_settings.vector_stroke_width;
@@ -5222,6 +5230,20 @@ impl HcieIcedApp {
_ => unreachable!(),
}
}
Tool::CustomShape(idx) => {
let entry = custom_shapes.get(idx as usize);
match entry {
Some((kind, svg)) => Some(hcie_engine_api::VectorShape::SvgShape {
x1: x0.min(x1), y1: y0.min(y1),
x2: x0.max(x1), y2: y0.max(y1),
kind: kind.clone(),
svg: svg.clone(),
stroke, color, fill_color: color, fill: true,
angle: 0.0, opacity, hardness: 0.5,
}),
None => None,
}
}
_ => None,
};
@@ -773,6 +773,7 @@ fn tool_icon(tool: Tool) -> &'static str {
Tool::SpotRemoval => "icons/spot.svg",
Tool::RedEyeRemoval => "icons/redeye.svg",
Tool::SmartPatch | Tool::AiObjectRemoval => "icons/patch.svg",
Tool::CustomShape(_) => "icons/star.svg",
}
}