mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 12:17:14 -06:00
113 lines
3.4 KiB
Rust
113 lines
3.4 KiB
Rust
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),
|
||
}
|