From f2326159917cb8f221607cbdda6722836c84a434 Mon Sep 17 00:00:00 2001 From: Halit Can Date: Wed, 15 Jul 2026 03:11:45 +0300 Subject: [PATCH] feat(iced): implement transform drag messages and handlers --- hcie-iced-app/crates/hcie-iced-gui/src/app.rs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/hcie-iced-app/crates/hcie-iced-gui/src/app.rs b/hcie-iced-app/crates/hcie-iced-gui/src/app.rs index 1cea609..703926e 100644 --- a/hcie-iced-app/crates/hcie-iced-gui/src/app.rs +++ b/hcie-iced-app/crates/hcie-iced-gui/src/app.rs @@ -201,6 +201,10 @@ pub struct IcedDocument { pub selection_transform: Option, /// Transform handle being dragged pub transform_drag_handle: TransformHandle, + /// Transform drag start position in canvas coordinates + pub transform_drag_start: Option<(f32, f32)>, + /// Original transform state before drag (for undo) + pub transform_original: Option, /// Internal clipboard for copy/paste operations pub internal_clipboard: Option, /// Selection mask (alpha channel) for the current selection @@ -375,6 +379,13 @@ pub enum Message { SelectionDragMove(f32, f32), SelectionDragEnd, + // ── Selection transform ───────────────────────────── + TransformDragStart(f32, f32), + TransformDragMove(f32, f32), + TransformDragEnd, + TransformApply, + TransformCancel, + // ── Vector tools ──────────────────────────────────── VectorDrawStart(f32, f32), VectorDrawMove(f32, f32), @@ -527,6 +538,8 @@ impl HcieIcedApp { full_upload: std::cell::RefCell::new(true), selection_transform: None, transform_drag_handle: TransformHandle::None, + transform_drag_start: None, + transform_original: None, internal_clipboard: None, selection_mask: None, selection_bounds: None, @@ -1809,6 +1822,8 @@ impl HcieIcedApp { full_upload: std::cell::RefCell::new(true), selection_transform: None, transform_drag_handle: TransformHandle::None, + transform_drag_start: None, + transform_original: None, internal_clipboard: None, selection_mask: None, selection_bounds: None, @@ -1929,6 +1944,100 @@ impl HcieIcedApp { } } + // ── Selection transform ──────────────────────── + Message::TransformDragStart(x, y) => { + let doc = &mut self.documents[self.active_doc]; + if let Some(ref tr) = doc.selection_transform { + let original = tr.clone(); + doc.transform_drag_start = Some((x, y)); + doc.transform_original = Some(original); + } + } + Message::TransformDragMove(x, y) => { + let doc = &mut self.documents[self.active_doc]; + if let (Some(start), Some(ref mut tr)) = (doc.transform_drag_start, &mut doc.selection_transform) { + let dx = x - start.0; + let dy = y - start.1; + + match doc.transform_drag_handle { + TransformHandle::Move => { + tr.pos = iced::Vector::new(tr.pos.x + dx, tr.pos.y + dy); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::TopLeft => { + tr.pos = iced::Vector::new(tr.pos.x + dx, tr.pos.y + dy); + tr.size = iced::Vector::new(tr.size.x - dx, tr.size.y - dy); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::TopRight => { + tr.size = iced::Vector::new(tr.size.x + dx, tr.size.y - dy); + tr.pos = iced::Vector::new(tr.pos.x, tr.pos.y + dy); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::BottomLeft => { + tr.size = iced::Vector::new(tr.size.x - dx, tr.size.y + dy); + tr.pos = iced::Vector::new(tr.pos.x + dx, tr.pos.y); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::BottomRight => { + tr.size = iced::Vector::new(tr.size.x + dx, tr.size.y + dy); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::Top => { + tr.pos = iced::Vector::new(tr.pos.x, tr.pos.y + dy); + tr.size = iced::Vector::new(tr.size.x, tr.size.y - dy); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::Bottom => { + tr.size = iced::Vector::new(tr.size.x, tr.size.y + dy); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::Left => { + tr.pos = iced::Vector::new(tr.pos.x + dx, tr.pos.y); + tr.size = iced::Vector::new(tr.size.x - dx, tr.size.y); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::Right => { + tr.size = iced::Vector::new(tr.size.x + dx, tr.size.y); + doc.transform_drag_start = Some((x, y)); + } + TransformHandle::Rotate => { + // Calculate rotation from center + let center_x = tr.pos.x + tr.size.x / 2.0; + let center_y = tr.pos.y + tr.size.y / 2.0; + let angle = (y - center_y).atan2(x - center_x); + tr.rotation = angle; + } + TransformHandle::None => {} + } + } + } + Message::TransformDragEnd => { + let doc = &mut self.documents[self.active_doc]; + doc.transform_drag_start = None; + doc.transform_original = None; + } + Message::TransformApply => { + let doc = &mut self.documents[self.active_doc]; + if let Some(_tr) = doc.selection_transform.take() { + // TODO: Apply transform to layer pixels + // For now, just clear the transform + doc.transform_drag_handle = TransformHandle::None; + return Task::perform(async {}, |_| Message::CompositeRefresh); + } + } + Message::TransformCancel => { + let doc = &mut self.documents[self.active_doc]; + // Restore original transform if we have it + if let Some(original) = doc.transform_original.take() { + doc.selection_transform = Some(original); + } else { + doc.selection_transform = None; + } + doc.transform_drag_start = None; + doc.transform_drag_handle = TransformHandle::None; + } + // ── Vector tools ────────────────────────────── Message::VectorDrawStart(x, y) => { self.documents[self.active_doc].vector_draw = Some(((x, y), (x, y))); @@ -2230,6 +2339,8 @@ impl HcieIcedApp { full_upload: std::cell::RefCell::new(true), selection_transform: None, transform_drag_handle: TransformHandle::None, + transform_drag_start: None, + transform_original: None, internal_clipboard: None, selection_mask: None, selection_bounds: None,