feat(iced): implement transform drag messages and handlers

This commit is contained in:
2026-07-15 03:11:45 +03:00
parent 56bbcdf356
commit f232615991
@@ -201,6 +201,10 @@ pub struct IcedDocument {
pub selection_transform: Option<SelectionTransform>,
/// 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<SelectionTransform>,
/// Internal clipboard for copy/paste operations
pub internal_clipboard: Option<SelectionTransform>,
/// 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,