use super::{Deserialize, Point, Serialize, Value}; /// Modifier keys. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct Mods { #[serde(default)] pub shift: bool, /// Option on macOS. #[serde(default)] pub alt: bool, /// Command on macOS, Ctrl elsewhere. #[serde(default)] pub cmd: bool, #[serde(default)] pub ctrl: bool, #[serde(default)] pub space: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum PointerKind { /// Button pressed. Down, /// Moved with the button held. Drag, /// Button released. Up, /// Moved with no button (hover). Move, DoubleClick, } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct PointerEvent { pub kind: PointerKind, /// Document coordinates. pub pos: Point, #[serde(default)] pub mods: Mods, #[serde(default = "one")] pub pressure: f32, } fn one() -> f32 { 1.0 } impl PointerEvent { pub fn new(kind: PointerKind, x: f64, y: f64) -> Self { Self { kind, pos: Point::new(x, y), mods: Mods::default(), pressure: 1.0 } } pub fn with_mods(mut self, m: Mods) -> Self { self.mods = m; self } /// The pen `pressure` of a pointer event given as JSON (control channel, MCP): 0..1, default 1. pub fn json_pressure(e: &Value) -> f32 { e.get("pressure").and_then(Value::as_f64).filter(|f| f.is_finite()).map_or(1.0, |f| f.clamp(0.0, 1.0) as f32) } /// How long the pointer then holds still, in seconds, from a JSON pointer event's `holdMs` /// (0..60000; default 0): the time [`Tool::tick`] gets. pub fn json_hold(e: &Value) -> f64 { e.get("holdMs").and_then(Value::as_f64).filter(|f| f.is_finite()).map_or(0.0, |ms| ms.clamp(0.0, 60_000.0) / 1000.0) } } /// Keys tools care about. #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum ToolKey { Enter, Escape, Backspace, Delete, Up, Down, Left, Right, /// Illustrator: ↑/↓ while drawing a polygon/star change sides/points; `[`/`]` change sizes. BracketLeft, BracketRight, Tab, Home, End, /// A digit key 0–9 (5 while dragging with the Perspective Selection tool moves perpendicular /// to the plane). Digit(u8), /// A letter key a–z, lowercase (E while dragging a Selection or Group Selection marquee makes it /// select only the objects entirely inside it, and E again switches it back). Letter(char), } /// What a tool asks the engine to do. #[derive(Clone, Debug, PartialEq)] pub enum Action { /// Start an interaction (snapshot the document). The label becomes the undo name. Begin(String), /// Replace the current preview with this command, applied to the snapshot. Preview(String, Value), /// Finish the interaction: keep the last preview as one undo step. Commit, /// Abort the interaction: restore the snapshot. Cancel, /// Execute a command immediately (its own undo step, if it edits). Exec(String, Value), /// Ask the UI to open a dialog (e.g. click with the Rectangle tool → size dialog). Dialog(String, Value), /// Switch to another tool (e.g. after placing a text frame). SwitchTool(String), /// Call the tool's `notify` after the preceding actions ran (e.g. to pick up a created object). Notify(String), }