feat(iced): add Apply/Cancel overlay and shape deletion

This commit is contained in:
2026-07-16 05:17:52 +03:00
parent 76da953a17
commit 4f05745255
2 changed files with 153 additions and 13 deletions
+85 -13
View File
@@ -628,6 +628,10 @@ pub enum Message {
VectorSelectDragEnd,
VectorShapeDelete,
VectorShapeSelect(Option<usize>),
VectorShapeApply,
VectorShapeCancel,
VectorShapeFlipH,
VectorShapeFlipV,
// ── Lasso / polygon selection ───────────────────────
LassoDragMove(f32, f32),
@@ -3520,17 +3524,14 @@ impl HcieIcedApp {
Message::VectorShapeDelete => {
if let Some(idx) = self.documents[self.active_doc].selected_vector_shape {
let layer_id = self.documents[self.active_doc].engine.active_layer_id();
// Remove the shape from the layer's shape list.
if let Some(shapes) = self.documents[self.active_doc].engine.get_layer_shapes_direct(layer_id) {
if idx < shapes.len() {
shapes.remove(idx);
}
}
self.documents[self.active_doc].engine.delete_vector_shape(layer_id, idx);
self.documents[self.active_doc].selected_vector_shape = None;
self.vector_shapes_snapshot = None;
self.documents[self.active_doc].engine.mark_composite_dirty();
self.refresh_composite_if_needed();
return Task::perform(async {}, |_| Message::CompositeRefresh);
} else {
return self.update(Message::Deselect);
}
}
Message::VectorShapeSelect(idx) => {
@@ -3542,6 +3543,78 @@ impl HcieIcedApp {
self.vector_shapes_snapshot = None;
}
}
// ── Vector shape apply / cancel / flip ──────
Message::VectorShapeApply => {
// Commit edits: clear snapshot and deselect.
let doc = &mut self.documents[self.active_doc];
doc.selected_vector_shape = None;
doc.vector_edit_handle = hcie_engine_api::VectorEditHandle::None;
self.vector_shapes_snapshot = None;
self.vector_drag_last = None;
}
Message::VectorShapeCancel => {
// Restore snapshot: put original shapes back, then deselect.
if let Some(snapshot) = self.vector_shapes_snapshot.take() {
let doc = &mut self.documents[self.active_doc];
let layer_id = doc.engine.active_layer_id();
if let Some(shapes) = doc.engine.get_layer_shapes_direct(layer_id) {
*shapes = snapshot;
}
doc.selected_vector_shape = None;
doc.vector_edit_handle = hcie_engine_api::VectorEditHandle::None;
self.vector_drag_last = None;
doc.engine.mark_composite_dirty();
self.refresh_composite_if_needed();
}
}
Message::VectorShapeFlipH => {
if let Some(idx) = self.documents[self.active_doc].selected_vector_shape {
let layer_id = self.documents[self.active_doc].engine.active_layer_id();
if let Some(shapes) = self.documents[self.active_doc].engine.get_layer_shapes_direct(layer_id) {
if let Some(shape) = shapes.get_mut(idx) {
match shape {
hcie_engine_api::VectorShape::FreePath { pts, .. } => {
let cx = pts.iter().map(|p| p[0]).sum::<f32>() / pts.len() as f32;
for p in pts.iter_mut() {
p[0] = 2.0 * cx - p[0];
}
}
_ => {
let (x1, y1, x2, y2) = shape.bounds();
// Swap x1/x2 to flip horizontally.
shape.set_bounds(x2, y1, x1, y2);
}
}
self.documents[self.active_doc].engine.mark_composite_dirty();
self.refresh_composite_if_needed();
}
}
}
}
Message::VectorShapeFlipV => {
if let Some(idx) = self.documents[self.active_doc].selected_vector_shape {
let layer_id = self.documents[self.active_doc].engine.active_layer_id();
if let Some(shapes) = self.documents[self.active_doc].engine.get_layer_shapes_direct(layer_id) {
if let Some(shape) = shapes.get_mut(idx) {
match shape {
hcie_engine_api::VectorShape::FreePath { pts, .. } => {
let cy = pts.iter().map(|p| p[1]).sum::<f32>() / pts.len() as f32;
for p in pts.iter_mut() {
p[1] = 2.0 * cy - p[1];
}
}
_ => {
let (x1, y1, x2, y2) = shape.bounds();
// Swap y1/y2 to flip vertically.
shape.set_bounds(x1, y2, x2, y1);
}
}
self.documents[self.active_doc].engine.mark_composite_dirty();
self.refresh_composite_if_needed();
}
}
}
}
// ── Lasso / polygon selection ─────────────────
Message::LassoDragMove(x, y) => {
@@ -4877,10 +4950,7 @@ impl HcieIcedApp {
} else if self.documents[self.active_doc].selection_transform.is_some() {
return self.update(Message::TransformCancel);
} else if self.documents[self.active_doc].selected_vector_shape.is_some() {
self.documents[self.active_doc].selected_vector_shape = None;
self.vector_shapes_snapshot = None;
self.documents[self.active_doc].vector_edit_handle = hcie_engine_api::VectorEditHandle::None;
self.vector_drag_last = None;
return self.update(Message::VectorShapeCancel);
} else if self.documents[self.active_doc].selection_bounds.is_some()
|| self.documents[self.active_doc].selection_rect.is_some()
{
@@ -4892,13 +4962,15 @@ impl HcieIcedApp {
}
}
Message::EnterPressed => {
// Mirrors egui's Enter: crop > transform > text-commit > viewer.
// Mirrors egui's Enter: crop > transform > text-commit > vector-apply > viewer.
if self.documents[self.active_doc].crop_state.active {
return self.update(Message::CropConfirm);
} else if self.documents[self.active_doc].selection_transform.is_some() {
return self.update(Message::TransformApply);
} else if self.active_document_mut().text_draft.is_some() {
return self.update(Message::TextCommit);
} else if self.documents[self.active_doc].selected_vector_shape.is_some() {
return self.update(Message::VectorShapeApply);
} else {
return self.update(Message::ViewerEnter);
}
@@ -5290,9 +5362,9 @@ impl HcieIcedApp {
// reserved — egui maps Enter to crop confirm).
// ── Named keys ───────────────────────────────
// Delete = Clear selection / deselect
// Delete = Delete selected vector shape, or clear selection
iced::keyboard::Key::Named(iced::keyboard::key::Named::Delete) => {
Some(Message::Deselect)
Some(Message::VectorShapeDelete)
}
// F11 = Fullscreen toggle
iced::keyboard::Key::Named(iced::keyboard::key::Named::F11) => {