Refactor ViewportPosition from u32 (UVec2) to f64 (DVec2) (#345)

* Refactor ViewportPosition from u32 (UVec2) to f64 (DVec2)

* Fix pseudo_hash call

* Replace hash function with proper function for uuid generation

* Cargo fmt

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Keavon Chambers 2021-08-14 02:45:24 -07:00
parent 42c3b1f6e9
commit 3f230c02b4
20 changed files with 128 additions and 75 deletions

48
Cargo.lock generated
View File

@ -98,7 +98,9 @@ dependencies = [
"graphite-graphene", "graphite-graphene",
"graphite-proc-macros", "graphite-proc-macros",
"log", "log",
"rand_chacha",
"serde", "serde",
"spin",
"thiserror", "thiserror",
] ]
@ -187,6 +189,15 @@ version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
[[package]]
name = "lock_api"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
dependencies = [
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.14" version = "0.4.14"
@ -202,6 +213,12 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.27" version = "1.0.27"
@ -220,6 +237,22 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.4"
@ -249,6 +282,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.126" version = "1.0.126"
@ -280,6 +319,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "spin"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.73" version = "1.0.73"

View File

@ -15,6 +15,8 @@ thiserror = "1.0.24"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
graphite-proc-macros = { path = "../proc-macros" } graphite-proc-macros = { path = "../proc-macros" }
glam = { version="0.17", features = ["serde"] } glam = { version="0.17", features = ["serde"] }
rand_chacha = "0.3.1"
spin = "0.9.2"
[dependencies.graphene] [dependencies.graphene]
path = "../graphene" path = "../graphene"

View File

@ -100,11 +100,11 @@ mod test {
})); }));
editor.select_primary_color(Color::RED); editor.select_primary_color(Color::RED);
editor.draw_rect(100, 200, 300, 400); editor.draw_rect(100., 200., 300., 400.);
editor.select_primary_color(Color::BLUE); editor.select_primary_color(Color::BLUE);
editor.draw_shape(10, 1200, 1300, 400); editor.draw_shape(10., 1200., 1300., 400.);
editor.select_primary_color(Color::GREEN); editor.select_primary_color(Color::GREEN);
editor.draw_ellipse(104, 1200, 1300, 400); editor.draw_ellipse(104., 1200., 1300., 400.);
editor editor
} }
@ -278,7 +278,7 @@ mod test {
editor.handle_message(DocumentMessage::SelectLayers(vec![vec![rect_id], vec![ellipse_id]])).unwrap(); editor.handle_message(DocumentMessage::SelectLayers(vec![vec![rect_id], vec![ellipse_id]])).unwrap();
editor.handle_message(DocumentsMessage::CopySelectedLayers).unwrap(); editor.handle_message(DocumentsMessage::CopySelectedLayers).unwrap();
editor.handle_message(DocumentMessage::DeleteSelectedLayers).unwrap(); editor.handle_message(DocumentMessage::DeleteSelectedLayers).unwrap();
editor.draw_rect(0, 800, 12, 200); editor.draw_rect(0., 800., 12., 200.);
editor.handle_message(DocumentsMessage::PasteLayers { path: vec![], insert_index: -1 }).unwrap(); editor.handle_message(DocumentsMessage::PasteLayers { path: vec![], insert_index: -1 }).unwrap();
editor.handle_message(DocumentsMessage::PasteLayers { path: vec![], insert_index: -1 }).unwrap(); editor.handle_message(DocumentsMessage::PasteLayers { path: vec![], insert_index: -1 }).unwrap();
@ -303,7 +303,7 @@ mod test {
/// - create rect, shape and ellipse /// - create rect, shape and ellipse
/// - select ellipse and rect /// - select ellipse and rect
/// - move them down and back up again /// - move them down and back up again
fn move_seletion() { fn move_selection() {
init_logger(); init_logger();
let mut editor = create_editor_with_three_layers(); let mut editor = create_editor_with_three_layers();

View File

@ -1,16 +1,20 @@
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
pub mod dispatcher; pub mod dispatcher;
pub mod message; pub mod message;
use crate::message_prelude::*; use crate::message_prelude::*;
pub use dispatcher::*; pub use dispatcher::*;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha20Rng,
};
use spin::Mutex;
pub use crate::input::InputPreprocessor; pub use crate::input::InputPreprocessor;
use std::collections::VecDeque; use std::collections::VecDeque;
pub type ActionList = Vec<Vec<MessageDiscriminant>>; pub type ActionList = Vec<Vec<MessageDiscriminant>>;
static RNG: Mutex<Option<ChaCha20Rng>> = Mutex::new(None);
// TODO: Add Send + Sync requirement // TODO: Add Send + Sync requirement
// Use something like rw locks for synchronization // Use something like rw locks for synchronization
pub trait MessageHandlerData {} pub trait MessageHandlerData {}
@ -25,12 +29,10 @@ where
fn actions(&self) -> ActionList; fn actions(&self) -> ActionList;
} }
pub fn generate_hash<'a>(messages: impl IntoIterator<Item = &'a Message>, ipp: &InputPreprocessor, document_hash: u64) -> u64 { pub fn generate_uuid() -> u64 {
let mut s = DefaultHasher::new(); let mut lock = RNG.lock();
document_hash.hash(&mut s); if lock.is_none() {
ipp.hash(&mut s); *lock = Some(ChaCha20Rng::seed_from_u64(0));
for message in messages {
message.pseudo_hash().hash(&mut s);
} }
s.finish() lock.as_mut().map(ChaCha20Rng::next_u64).unwrap()
} }

View File

@ -242,7 +242,7 @@ impl DocumentMessageHandler {
} }
/// Returns a list of `LayerPanelEntry`s intended for display purposes. These don't contain /// Returns a list of `LayerPanelEntry`s intended for display purposes. These don't contain
/// any actual data, but ratfolderch as visibility and names of the layers. /// any actual data, but rather attributes such as visibility and names of the layers.
pub fn layer_panel(&mut self, path: &[LayerId]) -> Result<Vec<LayerPanelEntry>, EditorError> { pub fn layer_panel(&mut self, path: &[LayerId]) -> Result<Vec<LayerPanelEntry>, EditorError> {
let folder = self.document.folder(path)?; let folder = self.document.folder(path)?;
let paths: Vec<Vec<LayerId>> = folder.layer_ids.iter().map(|id| [path, &[*id]].concat()).collect(); let paths: Vec<Vec<LayerId>> = folder.layer_ids.iter().map(|id| [path, &[*id]].concat()).collect();
@ -284,7 +284,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
} }
CommitTransaction => self.document_backup = None, CommitTransaction => self.document_backup = None,
ExportDocument => { ExportDocument => {
let bbox = self.document.visible_layers_bounding_box().unwrap_or([DVec2::ZERO, ipp.viewport_size.as_f64()]); let bbox = self.document.visible_layers_bounding_box().unwrap_or([DVec2::ZERO, ipp.viewport_size]);
let size = bbox[1] - bbox[0]; let size = bbox[1] - bbox[0];
let name = match self.name.ends_with(FILE_SAVE_SUFFIX) { let name = match self.name.ends_with(FILE_SAVE_SUFFIX) {
true => self.name.clone().replace(FILE_SAVE_SUFFIX, FILE_EXPORT_SUFFIX), true => self.name.clone().replace(FILE_SAVE_SUFFIX, FILE_EXPORT_SUFFIX),

View File

@ -32,7 +32,7 @@ pub enum MovementMessage {
ZoomCanvasToFitAll, ZoomCanvasToFitAll,
} }
#[derive(Debug, Clone, Hash, Default, PartialEq)] #[derive(Debug, Clone, Default, PartialEq)]
pub struct MovementMessageHandler { pub struct MovementMessageHandler {
translating: bool, translating: bool,
rotating: bool, rotating: bool,
@ -43,7 +43,7 @@ pub struct MovementMessageHandler {
impl MovementMessageHandler { impl MovementMessageHandler {
fn create_document_transform_from_layerdata(&self, layerdata: &LayerData, viewport_size: &ViewportPosition, responses: &mut VecDeque<Message>) { fn create_document_transform_from_layerdata(&self, layerdata: &LayerData, viewport_size: &ViewportPosition, responses: &mut VecDeque<Message>) {
let half_viewport = viewport_size.as_f64() / 2.; let half_viewport = *viewport_size / 2.;
let scaled_half_viewport = half_viewport / layerdata.scale; let scaled_half_viewport = half_viewport / layerdata.scale;
responses.push_back( responses.push_back(
DocumentOperation::SetLayerTransform { DocumentOperation::SetLayerTransform {
@ -64,7 +64,6 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
self.translating = true; self.translating = true;
self.mouse_pos = ipp.mouse.position; self.mouse_pos = ipp.mouse.position;
} }
RotateCanvasBegin { snap } => { RotateCanvasBegin { snap } => {
self.rotating = true; self.rotating = true;
self.snapping = snap; self.snapping = snap;
@ -86,17 +85,17 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
} }
MouseMove => { MouseMove => {
if self.translating { if self.translating {
let delta = ipp.mouse.position.as_f64() - self.mouse_pos.as_f64(); let delta = ipp.mouse.position - self.mouse_pos;
let transformed_delta = document.root.transform.inverse().transform_vector2(delta); let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
layerdata.translation += transformed_delta; layerdata.translation += transformed_delta;
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses); self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
} }
if self.rotating { if self.rotating {
let half_viewport = ipp.viewport_size.as_f64() / 2.; let half_viewport = ipp.viewport_size / 2.;
let rotation = { let rotation = {
let start_vec = self.mouse_pos.as_f64() - half_viewport; let start_vec = self.mouse_pos - half_viewport;
let end_vec = ipp.mouse.position.as_f64() - half_viewport; let end_vec = ipp.mouse.position - half_viewport;
start_vec.angle_between(end_vec) start_vec.angle_between(end_vec)
}; };
@ -140,8 +139,8 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
} }
WheelCanvasZoom => { WheelCanvasZoom => {
let scroll = ipp.mouse.scroll_delta.scroll_delta(); let scroll = ipp.mouse.scroll_delta.scroll_delta();
let mouse = ipp.mouse.position.as_f64(); let mouse = ipp.mouse.position;
let viewport_size = ipp.viewport_size.as_f64(); let viewport_size = ipp.viewport_size;
let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE; let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE;
if ipp.mouse.scroll_delta.y > 0 { if ipp.mouse.scroll_delta.y > 0 {
zoom_factor = 1. / zoom_factor zoom_factor = 1. / zoom_factor
@ -177,7 +176,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
let pos1 = document.root.transform.inverse().transform_point2(pos1); let pos1 = document.root.transform.inverse().transform_point2(pos1);
let pos2 = document.root.transform.inverse().transform_point2(pos2); let pos2 = document.root.transform.inverse().transform_point2(pos2);
let v1 = document.root.transform.inverse().transform_point2(DVec2::ZERO); let v1 = document.root.transform.inverse().transform_point2(DVec2::ZERO);
let v2 = document.root.transform.inverse().transform_point2(ipp.viewport_size.as_f64()); let v2 = document.root.transform.inverse().transform_point2(ipp.viewport_size);
let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5); let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5);
let size = (pos2 - pos1) / (v2 - v1); let size = (pos2 - pos1) / (v2 - v1);

View File

@ -30,7 +30,7 @@ bitflags! {
} }
} }
#[derive(Debug, Default, Hash)] #[derive(Debug, Default)]
pub struct InputPreprocessor { pub struct InputPreprocessor {
pub keyboard: KeyStates, pub keyboard: KeyStates,
pub mouse: MouseState, pub mouse: MouseState,
@ -81,7 +81,7 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessor {
responses.push_back( responses.push_back(
graphene::Operation::TransformLayer { graphene::Operation::TransformLayer {
path: vec![], path: vec![],
transform: glam::DAffine2::from_translation((size.as_f64() - self.viewport_size.as_f64()) / 2.).to_cols_array(), transform: glam::DAffine2::from_translation((size - self.viewport_size) / 2.).to_cols_array(),
} }
.into(), .into(),
); );
@ -141,7 +141,7 @@ mod test {
#[test] #[test]
fn process_action_mouse_move_handle_modifier_keys() { fn process_action_mouse_move_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default(); let mut input_preprocessor = InputPreprocessor::default();
let message = InputPreprocessorMessage::MouseMove((4, 809).into(), ModifierKeys::ALT); let message = InputPreprocessorMessage::MouseMove((4., 809.).into(), ModifierKeys::ALT);
let mut responses = VecDeque::new(); let mut responses = VecDeque::new();
input_preprocessor.process_action(message, (), &mut responses); input_preprocessor.process_action(message, (), &mut responses);

View File

@ -1,8 +1,8 @@
use bitflags::bitflags; use bitflags::bitflags;
use glam::DVec2; use glam::DVec2;
// origin is top left // Origin is top left
pub type ViewportPosition = glam::UVec2; pub type ViewportPosition = DVec2;
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
pub struct ScrollDelta { pub struct ScrollDelta {
@ -23,7 +23,7 @@ impl ScrollDelta {
} }
} }
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Default, PartialEq)]
pub struct MouseState { pub struct MouseState {
pub position: ViewportPosition, pub position: ViewportPosition,
pub mouse_keys: MouseKeys, pub mouse_keys: MouseKeys,
@ -31,17 +31,18 @@ pub struct MouseState {
} }
impl MouseState { impl MouseState {
pub fn new() -> MouseState { pub fn new() -> Self {
Self::default() Self::default()
} }
pub fn from_pos(x: u32, y: u32) -> MouseState { pub fn from_pos(x: f64, y: f64) -> Self {
MouseState { Self {
position: (x, y).into(), position: (x, y).into(),
mouse_keys: MouseKeys::default(), mouse_keys: MouseKeys::default(),
scroll_delta: ScrollDelta::default(), scroll_delta: ScrollDelta::default(),
} }
} }
pub fn from_u8_pos(keys: u8, position: ViewportPosition) -> Self { pub fn from_u8_pos(keys: u8, position: ViewportPosition) -> Self {
let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys"); let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys");
Self { Self {

View File

@ -50,7 +50,7 @@ impl Editor {
} }
pub mod message_prelude { pub mod message_prelude {
pub use crate::communication::generate_hash; pub use crate::communication::generate_uuid;
pub use crate::communication::message::{AsMessage, Message, MessageDiscriminant}; pub use crate::communication::message::{AsMessage, Message, MessageDiscriminant};
pub use crate::communication::{ActionList, MessageHandler}; pub use crate::communication::{ActionList, MessageHandler};
pub use crate::document::{DocumentMessage, DocumentMessageDiscriminant}; pub use crate::document::{DocumentMessage, DocumentMessageDiscriminant};

View File

@ -11,35 +11,35 @@ use graphene::color::Color;
/// A set of utility functions to make the writing of editor test more declarative /// A set of utility functions to make the writing of editor test more declarative
pub trait EditorTestUtils { pub trait EditorTestUtils {
fn draw_rect(&mut self, x1: u32, y1: u32, x2: u32, y2: u32); fn draw_rect(&mut self, x1: f64, y1: f64, x2: f64, y2: f64);
fn draw_shape(&mut self, x1: u32, y1: u32, x2: u32, y2: u32); fn draw_shape(&mut self, x1: f64, y1: f64, x2: f64, y2: f64);
fn draw_ellipse(&mut self, x1: u32, y1: u32, x2: u32, y2: u32); fn draw_ellipse(&mut self, x1: f64, y1: f64, x2: f64, y2: f64);
/// Select given tool and drag it from (x1, y1) to (x2, y2) /// Select given tool and drag it from (x1, y1) to (x2, y2)
fn drag_tool(&mut self, typ: ToolType, x1: u32, y1: u32, x2: u32, y2: u32); fn drag_tool(&mut self, typ: ToolType, x1: f64, y1: f64, x2: f64, y2: f64);
fn move_mouse(&mut self, x: u32, y: u32); fn move_mouse(&mut self, x: f64, y: f64);
fn mousedown(&mut self, state: MouseState); fn mousedown(&mut self, state: MouseState);
fn mouseup(&mut self, state: MouseState); fn mouseup(&mut self, state: MouseState);
fn lmb_mousedown(&mut self, x: u32, y: u32); fn lmb_mousedown(&mut self, x: f64, y: f64);
fn input(&mut self, message: InputPreprocessorMessage); fn input(&mut self, message: InputPreprocessorMessage);
fn select_tool(&mut self, typ: ToolType); fn select_tool(&mut self, typ: ToolType);
fn select_primary_color(&mut self, color: Color); fn select_primary_color(&mut self, color: Color);
} }
impl EditorTestUtils for Editor { impl EditorTestUtils for Editor {
fn draw_rect(&mut self, x1: u32, y1: u32, x2: u32, y2: u32) { fn draw_rect(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
self.drag_tool(ToolType::Rectangle, x1, y1, x2, y2); self.drag_tool(ToolType::Rectangle, x1, y1, x2, y2);
} }
fn draw_shape(&mut self, x1: u32, y1: u32, x2: u32, y2: u32) { fn draw_shape(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
self.drag_tool(ToolType::Shape, x1, y1, x2, y2); self.drag_tool(ToolType::Shape, x1, y1, x2, y2);
} }
fn draw_ellipse(&mut self, x1: u32, y1: u32, x2: u32, y2: u32) { fn draw_ellipse(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
self.drag_tool(ToolType::Ellipse, x1, y1, x2, y2); self.drag_tool(ToolType::Ellipse, x1, y1, x2, y2);
} }
fn drag_tool(&mut self, typ: ToolType, x1: u32, y1: u32, x2: u32, y2: u32) { fn drag_tool(&mut self, typ: ToolType, x1: f64, y1: f64, x2: f64, y2: f64) {
self.select_tool(typ); self.select_tool(typ);
self.move_mouse(x1, y1); self.move_mouse(x1, y1);
self.lmb_mousedown(x1, y1); self.lmb_mousedown(x1, y1);
@ -51,7 +51,7 @@ impl EditorTestUtils for Editor {
}); });
} }
fn move_mouse(&mut self, x: u32, y: u32) { fn move_mouse(&mut self, x: f64, y: f64) {
self.input(InputPreprocessorMessage::MouseMove((x, y).into(), ModifierKeys::default())); self.input(InputPreprocessorMessage::MouseMove((x, y).into(), ModifierKeys::default()));
} }
@ -63,7 +63,7 @@ impl EditorTestUtils for Editor {
self.handle_message(InputPreprocessorMessage::MouseUp(state, ModifierKeys::default())).unwrap() self.handle_message(InputPreprocessorMessage::MouseUp(state, ModifierKeys::default())).unwrap()
} }
fn lmb_mousedown(&mut self, x: u32, y: u32) { fn lmb_mousedown(&mut self, x: f64, y: f64) {
self.mousedown(MouseState { self.mousedown(MouseState {
position: (x, y).into(), position: (x, y).into(),
mouse_keys: MouseKeys::LEFT, mouse_keys: MouseKeys::LEFT,

View File

@ -58,7 +58,7 @@ impl Fsm for EllipseToolFsmState {
fn transition( fn transition(
self, self,
event: ToolMessage, event: ToolMessage,
document: &DocumentMessageHandler, _document: &DocumentMessageHandler,
tool_data: &DocumentToolData, tool_data: &DocumentToolData,
data: &mut Self::ToolData, data: &mut Self::ToolData,
input: &InputPreprocessor, input: &InputPreprocessor,
@ -72,7 +72,7 @@ impl Fsm for EllipseToolFsmState {
(Ready, DragStart) => { (Ready, DragStart) => {
shape_data.drag_start = input.mouse.position; shape_data.drag_start = input.mouse.position;
responses.push_back(DocumentMessage::StartTransaction.into()); responses.push_back(DocumentMessage::StartTransaction.into());
shape_data.path = Some(vec![generate_hash(&*responses, input, document.document.hash())]); shape_data.path = Some(vec![generate_uuid()]);
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
responses.push_back( responses.push_back(

View File

@ -19,7 +19,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Eyedropper {
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) { fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
let mouse_pos = data.2.mouse.position; let mouse_pos = data.2.mouse.position;
let tolerance = DVec2::splat(SELECTION_TOLERANCE); let tolerance = DVec2::splat(SELECTION_TOLERANCE);
let quad = Quad::from_box([mouse_pos.as_f64() - tolerance, mouse_pos.as_f64() + tolerance]); let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
if let Some(path) = data.0.document.intersects_quad_root(quad).last() { if let Some(path) = data.0.document.intersects_quad_root(quad).last() {
if let Ok(layer) = data.0.document.layer(path) { if let Ok(layer) = data.0.document.layer(path) {

View File

@ -17,7 +17,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Fill {
fn process_action(&mut self, _action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) { fn process_action(&mut self, _action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
let mouse_pos = data.2.mouse.position; let mouse_pos = data.2.mouse.position;
let tolerance = DVec2::splat(SELECTION_TOLERANCE); let tolerance = DVec2::splat(SELECTION_TOLERANCE);
let quad = Quad::from_box([mouse_pos.as_f64() - tolerance, mouse_pos.as_f64() + tolerance]); let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
if let Some(path) = data.0.document.intersects_quad_root(quad).last() { if let Some(path) = data.0.document.intersects_quad_root(quad).last() {
responses.push_back( responses.push_back(

View File

@ -59,7 +59,7 @@ impl Fsm for LineToolFsmState {
fn transition( fn transition(
self, self,
event: ToolMessage, event: ToolMessage,
document: &DocumentMessageHandler, _document: &DocumentMessageHandler,
tool_data: &DocumentToolData, tool_data: &DocumentToolData,
data: &mut Self::ToolData, data: &mut Self::ToolData,
input: &InputPreprocessor, input: &InputPreprocessor,
@ -72,7 +72,7 @@ impl Fsm for LineToolFsmState {
(Ready, DragStart) => { (Ready, DragStart) => {
data.drag_start = input.mouse.position; data.drag_start = input.mouse.position;
responses.push_back(DocumentMessage::StartTransaction.into()); responses.push_back(DocumentMessage::StartTransaction.into());
data.path = Some(vec![generate_hash(&*responses, input, document.document.hash())]); data.path = Some(vec![generate_uuid()]);
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
responses.push_back( responses.push_back(
@ -122,8 +122,8 @@ impl Fsm for LineToolFsmState {
} }
fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: bool) -> Message { fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: bool) -> Message {
let mut start = data.drag_start.as_f64(); let mut start = data.drag_start;
let stop = data.drag_current.as_f64(); let stop = data.drag_current;
let dir = stop - start; let dir = stop - start;

View File

@ -65,7 +65,7 @@ impl Fsm for PenToolFsmState {
responses: &mut VecDeque<Message>, responses: &mut VecDeque<Message>,
) -> Self { ) -> Self {
let transform = document.document.root.transform; let transform = document.document.root.transform;
let pos = transform.inverse() * DAffine2::from_translation(input.mouse.position.as_f64()); let pos = transform.inverse() * DAffine2::from_translation(input.mouse.position);
use PenMessage::*; use PenMessage::*;
use PenToolFsmState::*; use PenToolFsmState::*;
@ -74,7 +74,7 @@ impl Fsm for PenToolFsmState {
(Ready, DragStart) => { (Ready, DragStart) => {
responses.push_back(DocumentMessage::StartTransaction.into()); responses.push_back(DocumentMessage::StartTransaction.into());
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
data.path = Some(vec![generate_hash(&*responses, input, document.document.hash())]); data.path = Some(vec![generate_uuid()]);
data.points.push(pos); data.points.push(pos);
data.next_point = pos; data.next_point = pos;

View File

@ -58,7 +58,7 @@ impl Fsm for RectangleToolFsmState {
fn transition( fn transition(
self, self,
event: ToolMessage, event: ToolMessage,
document: &DocumentMessageHandler, _document: &DocumentMessageHandler,
tool_data: &DocumentToolData, tool_data: &DocumentToolData,
data: &mut Self::ToolData, data: &mut Self::ToolData,
input: &InputPreprocessor, input: &InputPreprocessor,
@ -72,7 +72,7 @@ impl Fsm for RectangleToolFsmState {
(Ready, DragStart) => { (Ready, DragStart) => {
shape_data.drag_start = input.mouse.position; shape_data.drag_start = input.mouse.position;
responses.push_back(DocumentMessage::StartTransaction.into()); responses.push_back(DocumentMessage::StartTransaction.into());
shape_data.path = Some(vec![generate_hash(&*responses, input, document.document.hash())]); shape_data.path = Some(vec![generate_uuid()]);
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
responses.push_back( responses.push_back(

View File

@ -11,8 +11,8 @@ pub struct Resize {
} }
impl Resize { impl Resize {
pub fn calculate_transform(&self, center: Key, lock_ratio: Key, ipp: &InputPreprocessor) -> Option<Message> { pub fn calculate_transform(&self, center: Key, lock_ratio: Key, ipp: &InputPreprocessor) -> Option<Message> {
let mut start = self.drag_start.as_f64(); let mut start = self.drag_start;
let stop = ipp.mouse.position.as_f64(); let stop = ipp.mouse.position;
let mut size = stop - start; let mut size = stop - start;
if ipp.keyboard.get(lock_ratio as usize) { if ipp.keyboard.get(lock_ratio as usize) {

View File

@ -79,9 +79,9 @@ impl SelectToolData {
fn selection_box(&self) -> [DVec2; 2] { fn selection_box(&self) -> [DVec2; 2] {
if self.drag_current == self.drag_start { if self.drag_current == self.drag_start {
let tolerance = DVec2::splat(SELECTION_TOLERANCE); let tolerance = DVec2::splat(SELECTION_TOLERANCE);
[self.drag_start.as_f64() - tolerance, self.drag_start.as_f64() + tolerance] [self.drag_start - tolerance, self.drag_start + tolerance]
} else { } else {
[self.drag_start.as_f64(), self.drag_current.as_f64()] [self.drag_start, self.drag_current]
} }
} }
} }
@ -122,7 +122,7 @@ impl Fsm for SelectToolFsmState {
Dragging Dragging
} else { } else {
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
data.box_id = Some(vec![generate_hash(&*responses, input, document.document.hash())]); data.box_id = Some(vec![generate_uuid()]);
responses.push_back( responses.push_back(
Operation::AddBoundingBox { Operation::AddBoundingBox {
path: data.box_id.clone().unwrap(), path: data.box_id.clone().unwrap(),
@ -139,7 +139,7 @@ impl Fsm for SelectToolFsmState {
responses.push_back( responses.push_back(
Operation::TransformLayerInViewport { Operation::TransformLayerInViewport {
path: path.clone(), path: path.clone(),
transform: DAffine2::from_translation(input.mouse.position.as_f64() - data.drag_current.as_f64()).to_cols_array(), transform: DAffine2::from_translation(input.mouse.position - data.drag_current).to_cols_array(),
} }
.into(), .into(),
); );
@ -149,8 +149,8 @@ impl Fsm for SelectToolFsmState {
} }
(DrawingBox, MouseMove) => { (DrawingBox, MouseMove) => {
data.drag_current = input.mouse.position; data.drag_current = input.mouse.position;
let start = data.drag_start.as_f64(); let start = data.drag_start;
let size = data.drag_current.as_f64() - start; let size = data.drag_current - start;
responses.push_back( responses.push_back(
Operation::SetLayerTransformInViewport { Operation::SetLayerTransformInViewport {

View File

@ -58,7 +58,7 @@ impl Fsm for ShapeToolFsmState {
fn transition( fn transition(
self, self,
event: ToolMessage, event: ToolMessage,
document: &DocumentMessageHandler, _document: &DocumentMessageHandler,
tool_data: &DocumentToolData, tool_data: &DocumentToolData,
data: &mut Self::ToolData, data: &mut Self::ToolData,
input: &InputPreprocessor, input: &InputPreprocessor,
@ -72,7 +72,7 @@ impl Fsm for ShapeToolFsmState {
(Ready, DragStart) => { (Ready, DragStart) => {
shape_data.drag_start = input.mouse.position; shape_data.drag_start = input.mouse.position;
responses.push_back(DocumentMessage::StartTransaction.into()); responses.push_back(DocumentMessage::StartTransaction.into());
shape_data.path = Some(vec![generate_hash(&*responses, input, document.document.hash())]); shape_data.path = Some(vec![generate_uuid()]);
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
data.sides = match tool_data.tool_options.get(&ToolType::Shape) { data.sides = match tool_data.tool_options.get(&ToolType::Shape) {
Some(&ToolOptions::Shape { Some(&ToolOptions::Shape {

View File

@ -107,7 +107,7 @@ pub fn close_all_documents_with_confirmation() -> Result<(), JsValue> {
// TODO: Call event when the panels are resized // TODO: Call event when the panels are resized
/// Viewport resized /// Viewport resized
#[wasm_bindgen] #[wasm_bindgen]
pub fn viewport_resize(new_width: u32, new_height: u32) -> Result<(), JsValue> { pub fn viewport_resize(new_width: f64, new_height: f64) -> Result<(), JsValue> {
let ev = InputPreprocessorMessage::ViewportResize((new_width, new_height).into()); let ev = InputPreprocessorMessage::ViewportResize((new_width, new_height).into());
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error) EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error)
} }
@ -115,8 +115,9 @@ pub fn viewport_resize(new_width: u32, new_height: u32) -> Result<(), JsValue> {
// TODO: When a mouse button is down that started in the viewport, this should trigger even when the mouse is outside the viewport (or even the browser window if the browser supports it) // TODO: When a mouse button is down that started in the viewport, this should trigger even when the mouse is outside the viewport (or even the browser window if the browser supports it)
/// Mouse movement within the screenspace bounds of the viewport /// Mouse movement within the screenspace bounds of the viewport
#[wasm_bindgen] #[wasm_bindgen]
pub fn on_mouse_move(x: u32, y: u32, modifiers: u8) -> Result<(), JsValue> { pub fn on_mouse_move(x: f64, y: f64, modifiers: u8) -> Result<(), JsValue> {
let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys");
// TODO: Convert these screenspace viewport coordinates to canvas coordinates based on the current zoom and pan // TODO: Convert these screenspace viewport coordinates to canvas coordinates based on the current zoom and pan
let ev = InputPreprocessorMessage::MouseMove((x, y).into(), mods); let ev = InputPreprocessorMessage::MouseMove((x, y).into(), mods);
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error) EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error)
@ -133,7 +134,7 @@ pub fn on_mouse_scroll(delta_x: i32, delta_y: i32, delta_z: i32, modifiers: u8)
/// A mouse button depressed within screenspace the bounds of the viewport /// A mouse button depressed within screenspace the bounds of the viewport
#[wasm_bindgen] #[wasm_bindgen]
pub fn on_mouse_down(x: u32, y: u32, mouse_keys: u8, modifiers: u8) -> Result<(), JsValue> { pub fn on_mouse_down(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Result<(), JsValue> {
let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys");
let ev = InputPreprocessorMessage::MouseDown(MouseState::from_u8_pos(mouse_keys, (x, y).into()), mods); let ev = InputPreprocessorMessage::MouseDown(MouseState::from_u8_pos(mouse_keys, (x, y).into()), mods);
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error) EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error)
@ -141,7 +142,7 @@ pub fn on_mouse_down(x: u32, y: u32, mouse_keys: u8, modifiers: u8) -> Result<()
/// A mouse button released /// A mouse button released
#[wasm_bindgen] #[wasm_bindgen]
pub fn on_mouse_up(x: u32, y: u32, mouse_keys: u8, modifiers: u8) -> Result<(), JsValue> { pub fn on_mouse_up(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Result<(), JsValue> {
let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys");
let ev = InputPreprocessorMessage::MouseUp(MouseState::from_u8_pos(mouse_keys, (x, y).into()), mods); let ev = InputPreprocessorMessage::MouseUp(MouseState::from_u8_pos(mouse_keys, (x, y).into()), mods);
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error) EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error)