From 5675126a894366a22772c030053e60f345a16401 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Wed, 1 Sep 2021 06:10:05 -0700 Subject: [PATCH] Reorganize and clean up the WASM wrapper --- .../widgets/inputs/SwatchPairInput.vue | 8 +- frontend/wasm/src/{document.rs => api.rs} | 254 +++++++++++------- frontend/wasm/src/helpers.rs | 24 ++ frontend/wasm/src/lib.rs | 10 +- frontend/wasm/src/{utils.rs => logging.rs} | 0 frontend/wasm/src/shims.rs | 10 - .../src/{wrappers.rs => type_translators.rs} | 87 ++---- 7 files changed, 217 insertions(+), 176 deletions(-) rename frontend/wasm/src/{document.rs => api.rs} (56%) create mode 100644 frontend/wasm/src/helpers.rs rename frontend/wasm/src/{utils.rs => logging.rs} (100%) delete mode 100644 frontend/wasm/src/shims.rs rename frontend/wasm/src/{wrappers.rs => type_translators.rs} (59%) diff --git a/frontend/src/components/widgets/inputs/SwatchPairInput.vue b/frontend/src/components/widgets/inputs/SwatchPairInput.vue index 15f11e54d..c11438810 100644 --- a/frontend/src/components/widgets/inputs/SwatchPairInput.vue +++ b/frontend/src/components/widgets/inputs/SwatchPairInput.vue @@ -109,25 +109,21 @@ export default defineComponent({ }, async updatePrimaryColor() { - const { Color } = await wasm; - let color = this.primaryColor; const button = this.getRef("primaryButton"); button.style.setProperty("--swatch-color", `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`); color = rgbToDecimalRgb(this.primaryColor); - (await wasm).update_primary_color(new Color(color.r, color.g, color.b, color.a)); + (await wasm).update_primary_color(color.r, color.g, color.b, color.a); }, async updateSecondaryColor() { - const { Color } = await wasm; - let color = this.secondaryColor; const button = this.getRef("secondaryButton"); button.style.setProperty("--swatch-color", `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`); color = rgbToDecimalRgb(this.secondaryColor); - (await wasm).update_secondary_color(new Color(color.r, color.g, color.b, color.a)); + (await wasm).update_secondary_color(color.r, color.g, color.b, color.a); }, }, data() { diff --git a/frontend/wasm/src/document.rs b/frontend/wasm/src/api.rs similarity index 56% rename from frontend/wasm/src/document.rs rename to frontend/wasm/src/api.rs index f56d81871..83df79764 100644 --- a/frontend/wasm/src/document.rs +++ b/frontend/wasm/src/api.rs @@ -1,21 +1,27 @@ +// This file is where functions are defined to be called directly from JS. +// It serves as a thin wrapper over the editor backend API that relies +// on the dispatcher messaging system and more complex Rust data types. + use crate::dispatch; -use crate::shims::Error; -use crate::wrappers::{translate_key, translate_tool, Color}; +use crate::helpers::Error; +use crate::type_translators::{translate_blend_mode, translate_key, translate_tool_type}; +use editor::consts::FILE_SAVE_SUFFIX; use editor::input::input_preprocessor::ModifierKeys; use editor::input::mouse::{EditorMouseState, ScrollDelta, ViewportBounds}; -use editor::message_prelude::*; use editor::misc::EditorError; use editor::tool::{tool_options::ToolOptions, tools, ToolType}; use editor::LayerId; -use graphene::layers::BlendMode; +use editor::{message_prelude::*, Color}; use wasm_bindgen::prelude::*; /// Modify the currently selected tool in the document state store #[wasm_bindgen] pub fn select_tool(tool: String) -> Result<(), JsValue> { - match translate_tool(&tool) { + match translate_tool_type(&tool) { Some(tool) => { - dispatch(ToolMessage::ActivateTool(tool)); + let message = ToolMessage::ActivateTool(tool); + dispatch(message); + Ok(()) } None => Err(Error::new(&format!("Couldn't select {} because it was not recognized as a valid tool", tool)).into()), @@ -26,9 +32,11 @@ pub fn select_tool(tool: String) -> Result<(), JsValue> { #[wasm_bindgen] pub fn set_tool_options(tool: String, options: &JsValue) -> Result<(), JsValue> { match options.into_serde::() { - Ok(options) => match translate_tool(&tool) { + Ok(options) => match translate_tool_type(&tool) { Some(tool) => { - dispatch(ToolMessage::SetToolOptions(tool, options)); + let message = ToolMessage::SetToolOptions(tool, options); + dispatch(message); + Ok(()) } None => Err(Error::new(&format!("Couldn't set options for {} because it was not recognized as a valid tool", tool)).into()), @@ -40,7 +48,7 @@ pub fn set_tool_options(tool: String, options: &JsValue) -> Result<(), JsValue> /// Send a message to a given tool #[wasm_bindgen] pub fn send_tool_message(tool: String, message: &JsValue) -> Result<(), JsValue> { - let tool_message = match translate_tool(&tool) { + let tool_message = match translate_tool_type(&tool) { Some(tool) => match tool { ToolType::Select => match message.into_serde::() { Ok(select_message) => Ok(ToolMessage::Select(select_message)), @@ -50,9 +58,11 @@ pub fn send_tool_message(tool: String, message: &JsValue) -> Result<(), JsValue> }, None => Err(Error::new(&format!("Couldn't send message for {} because it was not recognized as a valid tool", tool)).into()), }; + match tool_message { - Ok(tool_message) => { - dispatch(tool_message); + Ok(message) => { + dispatch(message); + Ok(()) } Err(err) => Err(err), @@ -61,52 +71,62 @@ pub fn send_tool_message(tool: String, message: &JsValue) -> Result<(), JsValue> #[wasm_bindgen] pub fn select_document(document: usize) { - dispatch(DocumentsMessage::SelectDocument(document)) + let message = DocumentsMessage::SelectDocument(document); + dispatch(message); } #[wasm_bindgen] pub fn get_open_documents_list() { - dispatch(DocumentsMessage::GetOpenDocumentsList) + let message = DocumentsMessage::GetOpenDocumentsList; + dispatch(message); } #[wasm_bindgen] pub fn new_document() { - dispatch(DocumentsMessage::NewDocument) + let message = DocumentsMessage::NewDocument; + dispatch(message); } #[wasm_bindgen] pub fn open_document() { - dispatch(DocumentsMessage::OpenDocument) + let message = DocumentsMessage::OpenDocument; + dispatch(message); } #[wasm_bindgen] pub fn open_document_file(name: String, content: String) { - dispatch(DocumentsMessage::OpenDocumentFile(name, content)) + let message = DocumentsMessage::OpenDocumentFile(name, content); + dispatch(message); } #[wasm_bindgen] pub fn save_document() { - dispatch(DocumentMessage::SaveDocument) + let message = DocumentMessage::SaveDocument; + dispatch(message); } #[wasm_bindgen] pub fn close_document(document: usize) { - dispatch(DocumentsMessage::CloseDocument(document)) + let message = DocumentsMessage::CloseDocument(document); + dispatch(message); } #[wasm_bindgen] pub fn close_all_documents() { - dispatch(DocumentsMessage::CloseAllDocuments) + let message = DocumentsMessage::CloseAllDocuments; + dispatch(message); } #[wasm_bindgen] pub fn close_active_document_with_confirmation() { - dispatch(DocumentsMessage::CloseActiveDocumentWithConfirmation) + let message = DocumentsMessage::CloseActiveDocumentWithConfirmation; + dispatch(message); } #[wasm_bindgen] pub fn close_all_documents_with_confirmation() { - dispatch(DocumentsMessage::CloseAllDocumentsWithConfirmation) + let message = DocumentsMessage::CloseAllDocumentsWithConfirmation; + dispatch(message); } /// Send new bounds when document panel viewports get resized or moved within the editor @@ -114,8 +134,9 @@ pub fn close_all_documents_with_confirmation() { #[wasm_bindgen] pub fn bounds_of_viewports(bounds_of_viewports: &[f64]) { let chunked: Vec<_> = bounds_of_viewports.chunks(4).map(ViewportBounds::from_slice).collect(); - let ev = InputPreprocessorMessage::BoundsOfViewports(chunked); - dispatch(ev) + + let message = InputPreprocessorMessage::BoundsOfViewports(chunked); + dispatch(message); } /// Mouse movement within the screenspace bounds of the viewport @@ -123,10 +144,10 @@ pub fn bounds_of_viewports(bounds_of_viewports: &[f64]) { pub fn on_mouse_move(x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); - let modifier_keys = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); + let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); - let ev = InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys); - dispatch(ev) + let message = InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys); + dispatch(message); } /// Mouse scrolling within the screenspace bounds of the viewport @@ -135,10 +156,10 @@ pub fn on_mouse_scroll(x: f64, y: f64, mouse_keys: u8, wheel_delta_x: i32, wheel let mut editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); editor_mouse_state.scroll_delta = ScrollDelta::new(wheel_delta_x, wheel_delta_y, wheel_delta_z); - let modifier_keys = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); + let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); - let ev = InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys); - dispatch(ev) + let message = InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys); + dispatch(message); } /// A mouse button depressed within screenspace the bounds of the viewport @@ -146,10 +167,10 @@ pub fn on_mouse_scroll(x: f64, y: f64, mouse_keys: u8, wheel_delta_x: i32, wheel pub fn on_mouse_down(x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); - let modifier_keys = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); + let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); - let ev = InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys); - dispatch(ev) + let message = InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys); + dispatch(message); } /// A mouse button released @@ -157,200 +178,243 @@ pub fn on_mouse_down(x: f64, y: f64, mouse_keys: u8, modifiers: u8) { pub fn on_mouse_up(x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); - let modifier_keys = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); + let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); - let ev = InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys); - dispatch(ev) + let message = InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys); + dispatch(message); } /// A keyboard button depressed within screenspace the bounds of the viewport #[wasm_bindgen] pub fn on_key_down(name: String, modifiers: u8) { let key = translate_key(&name); - let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); - log::trace!("Key down {:?}, name: {}, modifiers: {:?}", key, name, mods); - let ev = InputPreprocessorMessage::KeyDown(key, mods); - dispatch(ev) + let modifiers = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); + + log::trace!("Key down {:?}, name: {}, modifiers: {:?}", key, name, modifiers); + + let message = InputPreprocessorMessage::KeyDown(key, modifiers); + dispatch(message); } /// A keyboard button released #[wasm_bindgen] pub fn on_key_up(name: String, modifiers: u8) { let key = translate_key(&name); - let mods = ModifierKeys::from_bits(modifiers).expect("invalid modifier keys"); - log::trace!("Key up {:?}, name: {}, modifiers: {:?}", key, name, mods); - let ev = InputPreprocessorMessage::KeyUp(key, mods); - dispatch(ev) + let modifiers = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); + + log::trace!("Key up {:?}, name: {}, modifiers: {:?}", key, name, modifiers); + + let message = InputPreprocessorMessage::KeyUp(key, modifiers); + dispatch(message); } /// Update primary color #[wasm_bindgen] -pub fn update_primary_color(primary_color: Color) { - dispatch(ToolMessage::SelectPrimaryColor(primary_color.inner())) +pub fn update_primary_color(red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> { + let primary_color = match Color::from_rgbaf32(red, green, blue, alpha) { + Some(color) => color, + None => return Err(Error::new("Invalid color").into()), + }; + + let message = ToolMessage::SelectPrimaryColor(primary_color); + dispatch(message); + + Ok(()) } /// Update secondary color #[wasm_bindgen] -pub fn update_secondary_color(secondary_color: Color) { - dispatch(ToolMessage::SelectSecondaryColor(secondary_color.inner())) +pub fn update_secondary_color(red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> { + let secondary_color = match Color::from_rgbaf32(red, green, blue, alpha) { + Some(color) => color, + None => return Err(Error::new("Invalid color").into()), + }; + + let message = ToolMessage::SelectSecondaryColor(secondary_color); + dispatch(message); + + Ok(()) } /// Swap primary and secondary color #[wasm_bindgen] pub fn swap_colors() { - dispatch(ToolMessage::SwapColors) + let message = ToolMessage::SwapColors; + dispatch(message); } /// Reset primary and secondary colors to their defaults #[wasm_bindgen] pub fn reset_colors() { - dispatch(ToolMessage::ResetColors) + let message = ToolMessage::ResetColors; + dispatch(message); } /// Undo history one step #[wasm_bindgen] pub fn undo() { - dispatch(DocumentMessage::Undo) + let message = DocumentMessage::Undo; + dispatch(message); } /// Redo history one step #[wasm_bindgen] pub fn redo() { - dispatch(DocumentMessage::Redo) + let message = DocumentMessage::Redo; + dispatch(message); } /// Select all layers #[wasm_bindgen] pub fn select_all_layers() { - dispatch(DocumentMessage::SelectAllLayers) + let message = DocumentMessage::SelectAllLayers; + dispatch(message); } /// Deselect all layers #[wasm_bindgen] pub fn deselect_all_layers() { - dispatch(DocumentMessage::DeselectAllLayers) + let message = DocumentMessage::DeselectAllLayers; + dispatch(message); } /// Reorder selected layer #[wasm_bindgen] pub fn reorder_selected_layers(delta: i32) { - dispatch(DocumentMessage::ReorderSelectedLayers(delta)) + let message = DocumentMessage::ReorderSelectedLayers(delta); + dispatch(message); } /// Set the blend mode for the selected layers #[wasm_bindgen] pub fn set_blend_mode_for_selected_layers(blend_mode_svg_style_name: String) -> Result<(), JsValue> { - let blend_mode = match blend_mode_svg_style_name.as_str() { - "normal" => BlendMode::Normal, - "multiply" => BlendMode::Multiply, - "darken" => BlendMode::Darken, - "color-burn" => BlendMode::ColorBurn, - "screen" => BlendMode::Screen, - "lighten" => BlendMode::Lighten, - "color-dodge" => BlendMode::ColorDodge, - "overlay" => BlendMode::Overlay, - "soft-light" => BlendMode::SoftLight, - "hard-light" => BlendMode::HardLight, - "difference" => BlendMode::Difference, - "exclusion" => BlendMode::Exclusion, - "hue" => BlendMode::Hue, - "saturation" => BlendMode::Saturation, - "color" => BlendMode::Color, - "luminosity" => BlendMode::Luminosity, - _ => return Err(Error::new(&EditorError::Misc("UnknownBlendMode".to_string()).to_string()).into()), - }; + let blend_mode = translate_blend_mode(blend_mode_svg_style_name.as_str()); - dispatch(DocumentMessage::SetBlendModeForSelectedLayers(blend_mode)); - Ok(()) + match blend_mode { + Some(mode) => { + let message = DocumentMessage::SetBlendModeForSelectedLayers(mode); + dispatch(message); + + Ok(()) + } + None => Err(Error::new(&EditorError::Misc("UnknownBlendMode".to_string()).to_string()).into()), + } } /// Set the opacity for the selected layers #[wasm_bindgen] pub fn set_opacity_for_selected_layers(opacity_percent: f64) { - dispatch(DocumentMessage::SetOpacityForSelectedLayers(opacity_percent / 100.)) + let message = DocumentMessage::SetOpacityForSelectedLayers(opacity_percent / 100.); + dispatch(message); } /// Export the document #[wasm_bindgen] pub fn export_document() { - dispatch(DocumentMessage::ExportDocument) + let message = DocumentMessage::ExportDocument; + dispatch(message); } /// Sets the zoom to the value #[wasm_bindgen] pub fn set_canvas_zoom(new_zoom: f64) { - let ev = MovementMessage::SetCanvasZoom(new_zoom); - dispatch(ev) + let message = MovementMessage::SetCanvasZoom(new_zoom); + dispatch(message); } /// Zoom in to the next step #[wasm_bindgen] pub fn increase_canvas_zoom() { - let ev = MovementMessage::IncreaseCanvasZoom; - dispatch(ev) + let message = MovementMessage::IncreaseCanvasZoom; + dispatch(message); } /// Zoom out to the next step #[wasm_bindgen] pub fn decrease_canvas_zoom() { - let ev = MovementMessage::DecreaseCanvasZoom; - dispatch(ev) + let message = MovementMessage::DecreaseCanvasZoom; + dispatch(message); } /// Sets the rotation to the new value (in radians) #[wasm_bindgen] pub fn set_rotation(new_radians: f64) { - let ev = MovementMessage::SetCanvasRotation(new_radians); - dispatch(ev) + let message = MovementMessage::SetCanvasRotation(new_radians); + dispatch(message); } /// Translates document (in viewport coords) #[wasm_bindgen] pub fn translate_canvas(delta_x: f64, delta_y: f64) { - let ev = MovementMessage::TranslateCanvas((delta_x, delta_y).into()); - dispatch(ev) + let message = MovementMessage::TranslateCanvas((delta_x, delta_y).into()); + dispatch(message); } /// Translates document (in viewport coords) #[wasm_bindgen] pub fn translate_canvas_by_fraction(delta_x: f64, delta_y: f64) { - let ev = MovementMessage::TranslateCanvasByViewportFraction((delta_x, delta_y).into()); - dispatch(ev) + let message = MovementMessage::TranslateCanvasByViewportFraction((delta_x, delta_y).into()); + dispatch(message); } /// Update the list of selected layers. The layer paths have to be stored in one array and are separated by LayerId::MAX #[wasm_bindgen] pub fn select_layers(paths: Vec) { let paths = paths.split(|id| *id == LayerId::MAX).map(|path| path.to_vec()).collect(); - dispatch(DocumentMessage::SetSelectedLayers(paths)) + + let message = DocumentMessage::SetSelectedLayers(paths); + dispatch(message); } /// Toggle visibility of a layer from the layer list #[wasm_bindgen] pub fn toggle_layer_visibility(path: Vec) { - dispatch(DocumentMessage::ToggleLayerVisibility(path)) + let message = DocumentMessage::ToggleLayerVisibility(path); + dispatch(message); } /// Toggle expansions state of a layer from the layer list #[wasm_bindgen] pub fn toggle_layer_expansion(path: Vec) { - dispatch(DocumentMessage::ToggleLayerExpansion(path)) + let message = DocumentMessage::ToggleLayerExpansion(path); + dispatch(message); } /// Renames a layer from the layer list #[wasm_bindgen] pub fn rename_layer(path: Vec, new_name: String) { - dispatch(DocumentMessage::RenameLayer(path, new_name)) + let message = DocumentMessage::RenameLayer(path, new_name); + dispatch(message); } /// Deletes a layer from the layer list #[wasm_bindgen] pub fn delete_layer(path: Vec) { - dispatch(DocumentMessage::DeleteLayer(path)) + let message = DocumentMessage::DeleteLayer(path); + dispatch(message); } /// Requests the backend to add a layer to the layer list #[wasm_bindgen] pub fn add_folder(path: Vec) { - dispatch(DocumentMessage::CreateFolder(path)) + let message = DocumentMessage::CreateFolder(path); + dispatch(message); +} + +/// Get the constant FILE_SAVE_SUFFIX +#[wasm_bindgen] +pub fn file_save_suffix() -> String { + FILE_SAVE_SUFFIX.into() +} + +/// Get the constant i32::MAX +#[wasm_bindgen] +pub fn i32_max() -> i32 { + i32::MAX +} + +/// Get the constant i32::MIN +#[wasm_bindgen] +pub fn i32_min() -> i32 { + i32::MIN } diff --git a/frontend/wasm/src/helpers.rs b/frontend/wasm/src/helpers.rs new file mode 100644 index 000000000..bd56d36d6 --- /dev/null +++ b/frontend/wasm/src/helpers.rs @@ -0,0 +1,24 @@ +use wasm_bindgen::prelude::*; + +// The JavaScript `Error` type +#[wasm_bindgen] +extern "C" { + #[derive(Clone, Debug)] + pub type Error; + + #[wasm_bindgen(constructor)] + pub fn new(msg: &str) -> Error; +} + +/// Takes a string and matches it to its equivalently-named enum variant (useful for simple type translations) +macro_rules! match_string_to_enum { + (match ($e:expr) {$($var:ident),* $(,)?}) => { + match $e { + $( + stringify!($var) => Some($var), + )* + _ => None + } + }; +} +pub(crate) use match_string_to_enum; diff --git a/frontend/wasm/src/lib.rs b/frontend/wasm/src/lib.rs index 01bbbf8a4..870633095 100644 --- a/frontend/wasm/src/lib.rs +++ b/frontend/wasm/src/lib.rs @@ -1,13 +1,13 @@ -pub mod document; -mod shims; -pub mod utils; -pub mod wrappers; +pub mod api; +mod helpers; +pub mod logging; +pub mod type_translators; use editor::{message_prelude::*, Editor}; +use logging::WasmLog; use std::cell::RefCell; use std::panic; use std::sync::atomic::AtomicBool; -use utils::WasmLog; use wasm_bindgen::prelude::*; // Set up the persistent editor backend state (the thread_local macro provides a way to initialize static variables with non-constant functions) diff --git a/frontend/wasm/src/utils.rs b/frontend/wasm/src/logging.rs similarity index 100% rename from frontend/wasm/src/utils.rs rename to frontend/wasm/src/logging.rs diff --git a/frontend/wasm/src/shims.rs b/frontend/wasm/src/shims.rs deleted file mode 100644 index 54cdbf50c..000000000 --- a/frontend/wasm/src/shims.rs +++ /dev/null @@ -1,10 +0,0 @@ -use wasm_bindgen::prelude::*; - -#[wasm_bindgen] -extern "C" { - #[derive(Clone, Debug)] - pub type Error; - - #[wasm_bindgen(constructor)] - pub fn new(msg: &str) -> Error; -} diff --git a/frontend/wasm/src/wrappers.rs b/frontend/wasm/src/type_translators.rs similarity index 59% rename from frontend/wasm/src/wrappers.rs rename to frontend/wasm/src/type_translators.rs index 0ee57f637..d6e1eac7c 100644 --- a/frontend/wasm/src/wrappers.rs +++ b/frontend/wasm/src/type_translators.rs @@ -1,57 +1,9 @@ -use crate::shims::Error; -use editor::consts::FILE_SAVE_SUFFIX; +use crate::helpers::match_string_to_enum; use editor::input::keyboard::Key; -use editor::tool::{SelectAppendMode, ToolType}; -use editor::Color as InnerColor; -use wasm_bindgen::prelude::*; +use editor::tool::ToolType; +use graphene::layers::BlendMode; -#[wasm_bindgen] -pub fn file_save_suffix() -> String { - FILE_SAVE_SUFFIX.into() -} - -#[wasm_bindgen] -pub fn i32_max() -> i32 { - i32::MAX -} - -#[wasm_bindgen] -pub fn i32_min() -> i32 { - i32::MIN -} - -#[wasm_bindgen] -pub struct Color(InnerColor); - -#[wasm_bindgen] -impl Color { - #[wasm_bindgen(constructor)] - pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Result { - match InnerColor::from_rgbaf32(red, green, blue, alpha) { - Some(v) => Ok(Self(v)), - None => Err(Error::new("invalid color").into()), - } - } -} - -impl Color { - pub fn inner(&self) -> InnerColor { - self.0 - } -} - -macro_rules! match_string_to_enum { - (match ($e:expr) {$($var:ident),* $(,)?}) => { - match $e { - $( - stringify!($var) => Some($var), - )* - _ => None - } - }; -} - -pub fn translate_tool(name: &str) -> Option { +pub fn translate_tool_type(name: &str) -> Option { use ToolType::*; match_string_to_enum!(match (name) { @@ -79,15 +31,30 @@ pub fn translate_tool(name: &str) -> Option { }) } -pub fn translate_append_mode(name: &str) -> Option { - use SelectAppendMode::*; +pub fn translate_blend_mode(blend_mode_svg_style_name: &str) -> Option { + use BlendMode::*; - match_string_to_enum!(match (name) { - New, - Add, - Subtract, - Intersect - }) + let blend_mode = match blend_mode_svg_style_name { + "normal" => Normal, + "multiply" => Multiply, + "darken" => Darken, + "color-burn" => ColorBurn, + "screen" => Screen, + "lighten" => Lighten, + "color-dodge" => ColorDodge, + "overlay" => Overlay, + "soft-light" => SoftLight, + "hard-light" => HardLight, + "difference" => Difference, + "exclusion" => Exclusion, + "hue" => Hue, + "saturation" => Saturation, + "color" => Color, + "luminosity" => Luminosity, + _ => return None, + }; + + Some(blend_mode) } pub fn translate_key(name: &str) -> Key {