mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 16:48:12 +08:00
Simplify platform-specific keyboard layouts with Accel key and global platform variable (#748)
* Simplify platform-specific keyboard layouts with Accel key and global platform variable Co-authored-by: Dennis <dennis@kobert.dev>
This commit is contained in:
co-authored by
Dennis
parent
d8ae727ea9
commit
776992a297
Generated
+1
@@ -215,6 +215,7 @@ dependencies = [
|
|||||||
"graphite-proc-macros",
|
"graphite-proc-macros",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
"log",
|
"log",
|
||||||
|
"once_cell",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"remain",
|
"remain",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
|||||||
] }
|
] }
|
||||||
remain = "0.2.2"
|
remain = "0.2.2"
|
||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
|
once_cell = "1.13.0" # Remove when `core::cell::OnceCell` is stabilized (<https://doc.rust-lang.org/core/cell/struct.OnceCell.html>)
|
||||||
|
|
||||||
[dependencies.graphene]
|
[dependencies.graphene]
|
||||||
path = "../graphene"
|
path = "../graphene"
|
||||||
|
|||||||
+15
-18
@@ -17,6 +17,7 @@ struct DispatcherMessageHandlers {
|
|||||||
broadcast_message_handler: BroadcastMessageHandler,
|
broadcast_message_handler: BroadcastMessageHandler,
|
||||||
debug_message_handler: DebugMessageHandler,
|
debug_message_handler: DebugMessageHandler,
|
||||||
dialog_message_handler: DialogMessageHandler,
|
dialog_message_handler: DialogMessageHandler,
|
||||||
|
globals_message_handler: GlobalsMessageHandler,
|
||||||
input_mapper_message_handler: InputMapperMessageHandler,
|
input_mapper_message_handler: InputMapperMessageHandler,
|
||||||
input_preprocessor_message_handler: InputPreprocessorMessageHandler,
|
input_preprocessor_message_handler: InputPreprocessorMessageHandler,
|
||||||
layout_message_handler: LayoutMessageHandler,
|
layout_message_handler: LayoutMessageHandler,
|
||||||
@@ -127,26 +128,25 @@ impl Dispatcher {
|
|||||||
self.responses.push(message);
|
self.responses.push(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Globals(message) => {
|
||||||
|
self.message_handlers.globals_message_handler.process_message(message, (), &mut queue);
|
||||||
|
}
|
||||||
InputMapper(message) => {
|
InputMapper(message) => {
|
||||||
let actions = self.collect_actions();
|
let actions = self.collect_actions();
|
||||||
let keyboard_platform = self.message_handlers.portfolio_message_handler.platform.as_keyboard_platform_layout();
|
|
||||||
|
|
||||||
self.message_handlers
|
self.message_handlers
|
||||||
.input_mapper_message_handler
|
.input_mapper_message_handler
|
||||||
.process_message(message, (&self.message_handlers.input_preprocessor_message_handler, keyboard_platform, actions), &mut queue);
|
.process_message(message, (&self.message_handlers.input_preprocessor_message_handler, actions), &mut queue);
|
||||||
}
|
}
|
||||||
InputPreprocessor(message) => {
|
InputPreprocessor(message) => {
|
||||||
let keyboard_platform = self.message_handlers.portfolio_message_handler.platform.as_keyboard_platform_layout();
|
let keyboard_platform = GLOBAL_PLATFORM.get().expect("Failed to get GLOBAL_PLATFORM").as_keyboard_platform_layout();
|
||||||
|
|
||||||
self.message_handlers.input_preprocessor_message_handler.process_message(message, keyboard_platform, &mut queue);
|
self.message_handlers.input_preprocessor_message_handler.process_message(message, keyboard_platform, &mut queue);
|
||||||
}
|
}
|
||||||
Layout(message) => {
|
Layout(message) => {
|
||||||
let keyboard_platform = self.message_handlers.portfolio_message_handler.platform.as_keyboard_platform_layout();
|
let action_input_mapping = &|action_to_find: &MessageDiscriminant| self.message_handlers.input_mapper_message_handler.action_input_mapping(action_to_find);
|
||||||
let action_input_mapping = &|action_to_find: &MessageDiscriminant| self.message_handlers.input_mapper_message_handler.action_input_mapping(action_to_find, keyboard_platform);
|
|
||||||
|
|
||||||
self.message_handlers
|
self.message_handlers.layout_message_handler.process_message(message, action_input_mapping, &mut queue);
|
||||||
.layout_message_handler
|
|
||||||
.process_message(message, (action_input_mapping, keyboard_platform), &mut queue);
|
|
||||||
}
|
}
|
||||||
Portfolio(message) => {
|
Portfolio(message) => {
|
||||||
self.message_handlers
|
self.message_handlers
|
||||||
@@ -243,7 +243,6 @@ impl Dispatcher {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::application::set_uuid_seed;
|
|
||||||
use crate::application::Editor;
|
use crate::application::Editor;
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
@@ -262,14 +261,17 @@ mod test {
|
|||||||
/// 2. A blue shape
|
/// 2. A blue shape
|
||||||
/// 3. A green ellipse
|
/// 3. A green ellipse
|
||||||
fn create_editor_with_three_layers() -> Editor {
|
fn create_editor_with_three_layers() -> Editor {
|
||||||
set_uuid_seed(0);
|
init_logger();
|
||||||
let mut editor = Editor::new();
|
let mut editor = Editor::create();
|
||||||
|
|
||||||
editor.new_document();
|
editor.new_document();
|
||||||
|
|
||||||
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.);
|
||||||
|
|
||||||
@@ -282,7 +284,6 @@ mod test {
|
|||||||
/// - paste
|
/// - paste
|
||||||
/// - assert that ellipse was copied
|
/// - assert that ellipse was copied
|
||||||
fn copy_paste_single_layer() {
|
fn copy_paste_single_layer() {
|
||||||
init_logger();
|
|
||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
|
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
|
||||||
@@ -316,7 +317,6 @@ mod test {
|
|||||||
/// - paste
|
/// - paste
|
||||||
/// - assert that shape was copied
|
/// - assert that shape was copied
|
||||||
fn copy_paste_single_layer_from_middle() {
|
fn copy_paste_single_layer_from_middle() {
|
||||||
init_logger();
|
|
||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
|
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
|
||||||
@@ -351,7 +351,6 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copy_paste_folder() {
|
fn copy_paste_folder() {
|
||||||
init_logger();
|
|
||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
const FOLDER_INDEX: usize = 3;
|
const FOLDER_INDEX: usize = 3;
|
||||||
@@ -447,7 +446,6 @@ mod test {
|
|||||||
/// - paste
|
/// - paste
|
||||||
/// - paste
|
/// - paste
|
||||||
fn copy_paste_deleted_layers() {
|
fn copy_paste_deleted_layers() {
|
||||||
init_logger();
|
|
||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
const ELLIPSE_INDEX: usize = 2;
|
const ELLIPSE_INDEX: usize = 2;
|
||||||
@@ -499,7 +497,6 @@ mod test {
|
|||||||
/// - select ellipse and rect
|
/// - select ellipse and rect
|
||||||
/// - move them down and back up again
|
/// - move them down and back up again
|
||||||
fn move_selection() {
|
fn move_selection() {
|
||||||
init_logger();
|
|
||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
fn map_to_vec(paths: Vec<&[LayerId]>) -> Vec<Vec<LayerId>> {
|
fn map_to_vec(paths: Vec<&[LayerId]>) -> Vec<Vec<LayerId>> {
|
||||||
@@ -555,8 +552,8 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
init_logger();
|
init_logger();
|
||||||
set_uuid_seed(0);
|
let mut editor = Editor::create();
|
||||||
let mut editor = Editor::new();
|
|
||||||
let test_file = include_str!("../graphite-test-document.graphite");
|
let test_file = include_str!("../graphite-test-document.graphite");
|
||||||
let responses = editor.handle_message(PortfolioMessage::OpenDocumentFile {
|
let responses = editor.handle_message(PortfolioMessage::OpenDocumentFile {
|
||||||
document_name: "Graphite Version Test".into(),
|
document_name: "Graphite Version Test".into(),
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
use crate::messages::portfolio::document::utility_types::misc::Platform;
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
pub static GLOBAL_PLATFORM: OnceCell<Platform> = OnceCell::new();
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use crate::messages::portfolio::document::utility_types::misc::Platform;
|
||||||
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[impl_message(Message, Globals)]
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum GlobalsMessage {
|
||||||
|
SetPlatform { platform: Platform },
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct GlobalsMessageHandler {}
|
||||||
|
|
||||||
|
impl MessageHandler<GlobalsMessage, ()> for GlobalsMessageHandler {
|
||||||
|
#[remain::check]
|
||||||
|
fn process_message(&mut self, message: GlobalsMessage, _data: (), _responses: &mut VecDeque<Message>) {
|
||||||
|
match message {
|
||||||
|
GlobalsMessage::SetPlatform { platform } => {
|
||||||
|
GLOBAL_PLATFORM.set(platform).expect("Failed to set GLOBAL_PLATFORM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
advertise_actions!(GlobalsMessageDiscriminant;
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
mod globals_message;
|
||||||
|
mod globals_message_handler;
|
||||||
|
|
||||||
|
pub mod global_variables;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use globals_message::{GlobalsMessage, GlobalsMessageDiscriminant};
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use globals_message_handler::GlobalsMessageHandler;
|
||||||
@@ -4,7 +4,6 @@ use crate::messages::input_mapper::utility_types::macros::*;
|
|||||||
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
|
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
|
||||||
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
|
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
@@ -75,10 +74,7 @@ pub fn default_mapping() -> Mapping {
|
|||||||
// TextToolMessage
|
// TextToolMessage
|
||||||
entry!(KeyUp(Lmb); action_dispatch=TextToolMessage::Interact),
|
entry!(KeyUp(Lmb); action_dispatch=TextToolMessage::Interact),
|
||||||
entry!(KeyDown(Escape); action_dispatch=TextToolMessage::Abort),
|
entry!(KeyDown(Escape); action_dispatch=TextToolMessage::Abort),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(Enter); modifiers=[Accel], action_dispatch=TextToolMessage::CommitText),
|
||||||
standard!(KeyDown(Enter); modifiers=[Control], action_dispatch=TextToolMessage::CommitText),
|
|
||||||
mac_only!(KeyDown(Enter); modifiers=[Command], action_dispatch=TextToolMessage::CommitText),
|
|
||||||
),
|
|
||||||
//
|
//
|
||||||
// GradientToolMessage
|
// GradientToolMessage
|
||||||
entry!(KeyDown(Lmb); action_dispatch=GradientToolMessage::PointerDown),
|
entry!(KeyDown(Lmb); action_dispatch=GradientToolMessage::PointerDown),
|
||||||
@@ -159,10 +155,7 @@ pub fn default_mapping() -> Mapping {
|
|||||||
entry!(KeyDown(KeyM); action_dispatch=ToolMessage::ActivateToolRectangle),
|
entry!(KeyDown(KeyM); action_dispatch=ToolMessage::ActivateToolRectangle),
|
||||||
entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolEllipse),
|
entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolEllipse),
|
||||||
entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolShape),
|
entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolShape),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyX); modifiers=[Shift, Accel], action_dispatch=ToolMessage::ResetColors),
|
||||||
standard!(KeyDown(KeyX); modifiers=[Shift, Control], action_dispatch=ToolMessage::ResetColors),
|
|
||||||
mac_only!(KeyDown(KeyX); modifiers=[Shift, Command], action_dispatch=ToolMessage::ResetColors),
|
|
||||||
),
|
|
||||||
entry!(KeyDown(KeyX); modifiers=[Shift], action_dispatch=ToolMessage::SwapColors),
|
entry!(KeyDown(KeyX); modifiers=[Shift], action_dispatch=ToolMessage::SwapColors),
|
||||||
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=ToolMessage::SelectRandomPrimaryColor),
|
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=ToolMessage::SelectRandomPrimaryColor),
|
||||||
//
|
//
|
||||||
@@ -170,70 +163,22 @@ pub fn default_mapping() -> Mapping {
|
|||||||
entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
||||||
entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
||||||
entry!(KeyDown(KeyP); modifiers=[Alt], action_dispatch=DocumentMessage::DebugPrintDocument),
|
entry!(KeyDown(KeyP); modifiers=[Alt], action_dispatch=DocumentMessage::DebugPrintDocument),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyZ); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::Redo),
|
||||||
standard!(KeyDown(KeyZ); modifiers=[Control, Shift], action_dispatch=DocumentMessage::Redo),
|
entry!(KeyDown(KeyZ); modifiers=[Accel], action_dispatch=DocumentMessage::Undo),
|
||||||
mac_only!(KeyDown(KeyZ); modifiers=[Command, Shift], action_dispatch=DocumentMessage::Redo),
|
entry!(KeyDown(KeyA); modifiers=[Accel, Alt], action_dispatch=DocumentMessage::DeselectAllLayers),
|
||||||
),
|
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=DocumentMessage::SelectAllLayers),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyS); modifiers=[Accel], action_dispatch=DocumentMessage::SaveDocument),
|
||||||
standard!(KeyDown(KeyZ); modifiers=[Control], action_dispatch=DocumentMessage::Undo),
|
entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
||||||
mac_only!(KeyDown(KeyZ); modifiers=[Command], action_dispatch=DocumentMessage::Undo),
|
entry!(KeyDown(KeyG); modifiers=[Accel], action_dispatch=DocumentMessage::GroupSelectedLayers),
|
||||||
),
|
entry!(KeyDown(KeyG); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::UngroupSelectedLayers),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyN); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::CreateEmptyFolder { container_path: vec![] }),
|
||||||
standard!(KeyDown(KeyA); modifiers=[Control, Alt], action_dispatch=DocumentMessage::DeselectAllLayers),
|
entry!(KeyDown(Digit0); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasToFitAll),
|
||||||
mac_only!(KeyDown(KeyA); modifiers=[Command, Alt], action_dispatch=DocumentMessage::DeselectAllLayers),
|
entry!(KeyDown(Digit1); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasTo100Percent),
|
||||||
),
|
entry!(KeyDown(Digit2); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasTo200Percent),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(BracketLeft); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::SelectedLayersLowerToBack),
|
||||||
standard!(KeyDown(KeyA); modifiers=[Control], action_dispatch=DocumentMessage::SelectAllLayers),
|
entry!(KeyDown(BracketRight); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::SelectedLayersRaiseToFront),
|
||||||
mac_only!(KeyDown(KeyA); modifiers=[Command], action_dispatch=DocumentMessage::SelectAllLayers),
|
entry!(KeyDown(BracketLeft); modifiers=[Accel], action_dispatch=DocumentMessage::SelectedLayersLower),
|
||||||
),
|
entry!(KeyDown(BracketRight); modifiers=[Accel], action_dispatch=DocumentMessage::SelectedLayersRaise),
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyS); modifiers=[Control], action_dispatch=DocumentMessage::SaveDocument),
|
|
||||||
mac_only!(KeyDown(KeyS); modifiers=[Command], action_dispatch=DocumentMessage::SaveDocument),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyD); modifiers=[Control], action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
|
||||||
mac_only!(KeyDown(KeyD); modifiers=[Command], action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyG); modifiers=[Control], action_dispatch=DocumentMessage::GroupSelectedLayers),
|
|
||||||
mac_only!(KeyDown(KeyG); modifiers=[Command], action_dispatch=DocumentMessage::GroupSelectedLayers),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyG); modifiers=[Control, Shift], action_dispatch=DocumentMessage::UngroupSelectedLayers),
|
|
||||||
mac_only!(KeyDown(KeyG); modifiers=[Command, Shift], action_dispatch=DocumentMessage::UngroupSelectedLayers),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyN); modifiers=[Control, Shift], action_dispatch=DocumentMessage::CreateEmptyFolder { container_path: vec![] }),
|
|
||||||
mac_only!(KeyDown(KeyN); modifiers=[Command, Shift], action_dispatch=DocumentMessage::CreateEmptyFolder { container_path: vec![] }),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(Digit0); modifiers=[Control], action_dispatch=DocumentMessage::ZoomCanvasToFitAll),
|
|
||||||
mac_only!(KeyDown(Digit0); modifiers=[Command], action_dispatch=DocumentMessage::ZoomCanvasToFitAll),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(Digit1); modifiers=[Control], action_dispatch=DocumentMessage::ZoomCanvasTo100Percent),
|
|
||||||
mac_only!(KeyDown(Digit1); modifiers=[Command], action_dispatch=DocumentMessage::ZoomCanvasTo100Percent),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(Digit2); modifiers=[Control], action_dispatch=DocumentMessage::ZoomCanvasTo200Percent),
|
|
||||||
mac_only!(KeyDown(Digit2); modifiers=[Command], action_dispatch=DocumentMessage::ZoomCanvasTo200Percent),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(BracketLeft); modifiers=[Control, Shift], action_dispatch=DocumentMessage::SelectedLayersLowerToBack),
|
|
||||||
mac_only!(KeyDown(BracketLeft); modifiers=[Command, Shift], action_dispatch=DocumentMessage::SelectedLayersLowerToBack),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(BracketRight); modifiers=[Control, Shift], action_dispatch=DocumentMessage::SelectedLayersRaiseToFront),
|
|
||||||
mac_only!(KeyDown(BracketRight); modifiers=[Command, Shift], action_dispatch=DocumentMessage::SelectedLayersRaiseToFront),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(BracketLeft); modifiers=[Control], action_dispatch=DocumentMessage::SelectedLayersLower),
|
|
||||||
mac_only!(KeyDown(BracketLeft); modifiers=[Command], action_dispatch=DocumentMessage::SelectedLayersLower),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(BracketRight); modifiers=[Control], action_dispatch=DocumentMessage::SelectedLayersRaise),
|
|
||||||
mac_only!(KeyDown(BracketRight); modifiers=[Command], action_dispatch=DocumentMessage::SelectedLayersRaise),
|
|
||||||
),
|
|
||||||
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }),
|
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }),
|
||||||
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }),
|
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }),
|
||||||
entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT }),
|
entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT }),
|
||||||
@@ -271,18 +216,9 @@ pub fn default_mapping() -> Mapping {
|
|||||||
entry!(KeyUp(Mmb); action_dispatch=NavigationMessage::TransformCanvasEnd),
|
entry!(KeyUp(Mmb); action_dispatch=NavigationMessage::TransformCanvasEnd),
|
||||||
entry!(KeyDown(Lmb); modifiers=[Space], action_dispatch=NavigationMessage::TranslateCanvasBegin),
|
entry!(KeyDown(Lmb); modifiers=[Space], action_dispatch=NavigationMessage::TranslateCanvasBegin),
|
||||||
entry!(KeyUp(Lmb); modifiers=[Space], action_dispatch=NavigationMessage::TransformCanvasEnd),
|
entry!(KeyUp(Lmb); modifiers=[Space], action_dispatch=NavigationMessage::TransformCanvasEnd),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(NumpadAdd); modifiers=[Accel], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
||||||
standard!(KeyDown(NumpadAdd); modifiers=[Control], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
entry!(KeyDown(Equal); modifiers=[Accel], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
||||||
mac_only!(KeyDown(NumpadAdd); modifiers=[Command], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
entry!(KeyDown(Minus); modifiers=[Accel], action_dispatch=NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }),
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(Equal); modifiers=[Control], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
|
||||||
mac_only!(KeyDown(Equal); modifiers=[Command], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(Minus); modifiers=[Control], action_dispatch=NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }),
|
|
||||||
mac_only!(KeyDown(Minus); modifiers=[Command], action_dispatch=NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }),
|
|
||||||
),
|
|
||||||
entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::WheelCanvasZoom),
|
entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::WheelCanvasZoom),
|
||||||
entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::WheelCanvasTranslate { use_y_as_x: true }),
|
entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::WheelCanvasTranslate { use_y_as_x: true }),
|
||||||
entry!(WheelScroll; action_dispatch=NavigationMessage::WheelCanvasTranslate { use_y_as_x: false }),
|
entry!(WheelScroll; action_dispatch=NavigationMessage::WheelCanvasTranslate { use_y_as_x: false }),
|
||||||
@@ -292,47 +228,19 @@ pub fn default_mapping() -> Mapping {
|
|||||||
entry!(KeyDown(PageDown); action_dispatch=NavigationMessage::TranslateCanvasByViewportFraction { delta: DVec2::new(0., -1.) }),
|
entry!(KeyDown(PageDown); action_dispatch=NavigationMessage::TranslateCanvasByViewportFraction { delta: DVec2::new(0., -1.) }),
|
||||||
//
|
//
|
||||||
// PortfolioMessage
|
// PortfolioMessage
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyO); modifiers=[Accel], action_dispatch=PortfolioMessage::OpenDocument),
|
||||||
standard!(KeyDown(KeyO); modifiers=[Control], action_dispatch=PortfolioMessage::OpenDocument),
|
entry!(KeyDown(KeyI); modifiers=[Accel], action_dispatch=PortfolioMessage::Import),
|
||||||
mac_only!(KeyDown(KeyO); modifiers=[Command], action_dispatch=PortfolioMessage::OpenDocument),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyI); modifiers=[Control], action_dispatch=PortfolioMessage::Import),
|
|
||||||
mac_only!(KeyDown(KeyI); modifiers=[Command], action_dispatch=PortfolioMessage::Import),
|
|
||||||
),
|
|
||||||
entry!(KeyDown(Tab); modifiers=[Control], action_dispatch=PortfolioMessage::NextDocument),
|
entry!(KeyDown(Tab); modifiers=[Control], action_dispatch=PortfolioMessage::NextDocument),
|
||||||
entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument),
|
entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument),
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyW); modifiers=[Accel], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
|
||||||
standard!(KeyDown(KeyW); modifiers=[Control], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
|
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=PortfolioMessage::Cut { clipboard: Clipboard::Device }),
|
||||||
mac_only!(KeyDown(KeyW); modifiers=[Command], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
|
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }),
|
||||||
),
|
entry!(KeyDown(KeyV); modifiers=[Accel], action_dispatch=FrontendMessage::TriggerPaste),
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyX); modifiers=[Control], action_dispatch=PortfolioMessage::Cut { clipboard: Clipboard::Device }),
|
|
||||||
mac_only!(KeyDown(KeyX); modifiers=[Command], action_dispatch=PortfolioMessage::Cut { clipboard: Clipboard::Device }),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyC); modifiers=[Control], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }),
|
|
||||||
mac_only!(KeyDown(KeyC); modifiers=[Command], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
// This shortcut is intercepted in the frontend; it exists here only as a shortcut mapping source
|
|
||||||
standard!(KeyDown(KeyV); modifiers=[Control], action_dispatch=FrontendMessage::TriggerPaste),
|
|
||||||
mac_only!(KeyDown(KeyV); modifiers=[Command], action_dispatch=FrontendMessage::TriggerPaste),
|
|
||||||
),
|
|
||||||
//
|
//
|
||||||
// DialogMessage
|
// DialogMessage
|
||||||
entry_multiplatform!(
|
entry!(KeyDown(KeyN); modifiers=[Accel], action_dispatch=DialogMessage::RequestNewDocumentDialog),
|
||||||
standard!(KeyDown(KeyN); modifiers=[Control], action_dispatch=DialogMessage::RequestNewDocumentDialog),
|
entry!(KeyDown(KeyW); modifiers=[Accel, Alt], action_dispatch=DialogMessage::CloseAllDocumentsWithConfirmation),
|
||||||
mac_only!(KeyDown(KeyN); modifiers=[Command], action_dispatch=DialogMessage::RequestNewDocumentDialog),
|
entry!(KeyDown(KeyE); modifiers=[Accel], action_dispatch=DialogMessage::RequestExportDialog),
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyW); modifiers=[Control, Alt], action_dispatch=DialogMessage::CloseAllDocumentsWithConfirmation),
|
|
||||||
mac_only!(KeyDown(KeyW); modifiers=[Command, Alt], action_dispatch=DialogMessage::CloseAllDocumentsWithConfirmation),
|
|
||||||
),
|
|
||||||
entry_multiplatform!(
|
|
||||||
standard!(KeyDown(KeyE); modifiers=[Control], action_dispatch=DialogMessage::RequestExportDialog),
|
|
||||||
mac_only!(KeyDown(KeyE); modifiers=[Command], action_dispatch=DialogMessage::RequestExportDialog),
|
|
||||||
),
|
|
||||||
//
|
//
|
||||||
// DebugMessage
|
// DebugMessage
|
||||||
entry!(KeyDown(KeyT); modifiers=[Alt], action_dispatch=DebugMessage::ToggleTraceLogs),
|
entry!(KeyDown(KeyT); modifiers=[Alt], action_dispatch=DebugMessage::ToggleTraceLogs),
|
||||||
@@ -350,7 +258,6 @@ pub fn default_mapping() -> Mapping {
|
|||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: TransformLayerMessage::TypeDigit { digit: i as u8 }.into(),
|
action: TransformLayerMessage::TypeDigit { digit: i as u8 }.into(),
|
||||||
input: InputMapperMessage::KeyDown(*key),
|
input: InputMapperMessage::KeyDown(*key),
|
||||||
platform_layout: None,
|
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use super::utility_types::input_keyboard::KeysGroup;
|
use super::utility_types::input_keyboard::KeysGroup;
|
||||||
use super::utility_types::misc::Mapping;
|
use super::utility_types::misc::Mapping;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{self, Key};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{self, Key};
|
||||||
use crate::messages::portfolio::document::utility_types::misc::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
@@ -11,11 +10,11 @@ pub struct InputMapperMessageHandler {
|
|||||||
mapping: Mapping,
|
mapping: Mapping,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageHandler<InputMapperMessage, (&InputPreprocessorMessageHandler, KeyboardPlatformLayout, ActionList)> for InputMapperMessageHandler {
|
impl MessageHandler<InputMapperMessage, (&InputPreprocessorMessageHandler, ActionList)> for InputMapperMessageHandler {
|
||||||
fn process_message(&mut self, message: InputMapperMessage, data: (&InputPreprocessorMessageHandler, KeyboardPlatformLayout, ActionList), responses: &mut VecDeque<Message>) {
|
fn process_message(&mut self, message: InputMapperMessage, data: (&InputPreprocessorMessageHandler, ActionList), responses: &mut VecDeque<Message>) {
|
||||||
let (input, keyboard_platform, actions) = data;
|
let (input, actions) = data;
|
||||||
|
|
||||||
if let Some(message) = self.mapping.match_input_message(message, &input.keyboard, actions, keyboard_platform) {
|
if let Some(message) = self.mapping.match_input_message(message, &input.keyboard, actions) {
|
||||||
responses.push_back(message);
|
responses.push_back(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +43,7 @@ impl InputMapperMessageHandler {
|
|||||||
output.replace("Key", "")
|
output.replace("Key", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant, keyboard_platform: KeyboardPlatformLayout) -> Vec<KeysGroup> {
|
pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Vec<KeysGroup> {
|
||||||
let key_up = self.mapping.key_up.iter();
|
let key_up = self.mapping.key_up.iter();
|
||||||
let key_down = self.mapping.key_down.iter();
|
let key_down = self.mapping.key_down.iter();
|
||||||
let double_click = std::iter::once(&self.mapping.double_click);
|
let double_click = std::iter::once(&self.mapping.double_click);
|
||||||
@@ -56,8 +55,6 @@ impl InputMapperMessageHandler {
|
|||||||
|
|
||||||
// Filter for the desired message
|
// Filter for the desired message
|
||||||
let found_actions = all_mapping_entries.filter(|entry| entry.action.to_discriminant() == *action_to_find);
|
let found_actions = all_mapping_entries.filter(|entry| entry.action.to_discriminant() == *action_to_find);
|
||||||
// Filter for a compatible keyboard platform layout
|
|
||||||
let found_actions = found_actions.filter(|entry| if let Some(layout) = entry.platform_layout { layout == keyboard_platform } else { true });
|
|
||||||
|
|
||||||
// Find the key combinations for all keymaps matching the desired action
|
// Find the key combinations for all keymaps matching the desired action
|
||||||
assert!(std::mem::size_of::<usize>() >= std::mem::size_of::<Key>());
|
assert!(std::mem::size_of::<usize>() >= std::mem::size_of::<Key>());
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ const KEY_MASK_STORAGE_LENGTH: usize = (NUMBER_OF_KEYS + STORAGE_SIZE_BITS - 1)
|
|||||||
|
|
||||||
pub type KeyStates = BitVector<KEY_MASK_STORAGE_LENGTH>;
|
pub type KeyStates = BitVector<KEY_MASK_STORAGE_LENGTH>;
|
||||||
|
|
||||||
|
pub fn all_required_modifiers_pressed(keyboard_state: &KeyStates, modifiers: &KeyStates) -> bool {
|
||||||
|
// Find which currently pressed keys are also the modifiers in this hotkey entry, then compare those against the required modifiers to see if there are zero missing
|
||||||
|
let pressed_modifiers = *keyboard_state & *modifiers;
|
||||||
|
let all_modifiers_without_pressed_modifiers = *modifiers ^ pressed_modifiers;
|
||||||
|
|
||||||
|
all_modifiers_without_pressed_modifiers.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub enum KeyPosition {
|
pub enum KeyPosition {
|
||||||
Pressed,
|
Pressed,
|
||||||
Released,
|
Released,
|
||||||
@@ -29,10 +37,10 @@ bitflags! {
|
|||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct ModifierKeys: u8 {
|
pub struct ModifierKeys: u8 {
|
||||||
const SHIFT = 0b0000_0001;
|
const SHIFT = 0b_0000_0001;
|
||||||
const ALT = 0b0000_0010;
|
const ALT = 0b_0000_0010;
|
||||||
const CONTROL = 0b0000_0100;
|
const CONTROL = 0b_0000_0100;
|
||||||
const META_OR_COMMAND = 0b0000_1000;
|
const META_OR_COMMAND = 0b_0000_1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +201,7 @@ pub enum Key {
|
|||||||
|
|
||||||
// Other keys that aren't part of the W3C spec
|
// Other keys that aren't part of the W3C spec
|
||||||
Command,
|
Command,
|
||||||
|
Accel,
|
||||||
Lmb,
|
Lmb,
|
||||||
Rmb,
|
Rmb,
|
||||||
Mmb,
|
Mmb,
|
||||||
@@ -228,6 +237,8 @@ impl fmt::Display for Key {
|
|||||||
return write!(f, "{}", key_name.chars().skip(KEY_PREFIX.len()).collect::<String>());
|
return write!(f, "{}", key_name.chars().skip(KEY_PREFIX.len()).collect::<String>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let keyboard_layout = || GLOBAL_PLATFORM.get().expect("Failed to get GLOBAL_PLATFORM").as_keyboard_platform_layout();
|
||||||
|
|
||||||
let name = match self {
|
let name = match self {
|
||||||
// Writing system keys
|
// Writing system keys
|
||||||
Self::Backquote => "`",
|
Self::Backquote => "`",
|
||||||
@@ -243,7 +254,23 @@ impl fmt::Display for Key {
|
|||||||
Self::Slash => "/",
|
Self::Slash => "/",
|
||||||
|
|
||||||
// Functional keys
|
// Functional keys
|
||||||
Self::Control => "Ctrl",
|
Self::Alt => match keyboard_layout() {
|
||||||
|
KeyboardPlatformLayout::Standard => "Alt",
|
||||||
|
KeyboardPlatformLayout::Mac => "⌥",
|
||||||
|
},
|
||||||
|
Self::Meta => match keyboard_layout() {
|
||||||
|
KeyboardPlatformLayout::Standard => "⊞",
|
||||||
|
KeyboardPlatformLayout::Mac => "⌘",
|
||||||
|
},
|
||||||
|
Self::Shift => match keyboard_layout() {
|
||||||
|
KeyboardPlatformLayout::Standard => "Shift",
|
||||||
|
KeyboardPlatformLayout::Mac => "⇧",
|
||||||
|
},
|
||||||
|
Self::Control => match keyboard_layout() {
|
||||||
|
KeyboardPlatformLayout::Standard => "Ctrl",
|
||||||
|
KeyboardPlatformLayout::Mac => "⌃",
|
||||||
|
},
|
||||||
|
Self::Backspace => "⌫",
|
||||||
|
|
||||||
// Control pad keys
|
// Control pad keys
|
||||||
Self::Delete => "Del",
|
Self::Delete => "Del",
|
||||||
@@ -267,6 +294,13 @@ impl fmt::Display for Key {
|
|||||||
Self::Escape => "Esc",
|
Self::Escape => "Esc",
|
||||||
Self::PrintScreen => "PrtScr",
|
Self::PrintScreen => "PrtScr",
|
||||||
|
|
||||||
|
// Other keys that aren't part of the W3C spec
|
||||||
|
Self::Command => "⌘",
|
||||||
|
Self::Accel => match keyboard_layout() {
|
||||||
|
KeyboardPlatformLayout::Standard => "Ctrl",
|
||||||
|
KeyboardPlatformLayout::Mac => "⌘",
|
||||||
|
},
|
||||||
|
|
||||||
_ => key_name.as_str(),
|
_ => key_name.as_str(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -280,36 +314,31 @@ pub const NUMBER_OF_KEYS: usize = Key::NumKeys as usize;
|
|||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct KeysGroup(pub Vec<Key>);
|
pub struct KeysGroup(pub Vec<Key>);
|
||||||
|
|
||||||
impl KeysGroup {
|
impl fmt::Display for KeysGroup {
|
||||||
pub fn keys_text_shortcut(&self, keyboard_platform: KeyboardPlatformLayout) -> String {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
const JOINER_MARK: &str = "+";
|
const JOINER_MARK: &str = " ";
|
||||||
|
|
||||||
let mut joined = self
|
let mut joined = self
|
||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|key| {
|
.map(|key| {
|
||||||
let key_string = key.to_string();
|
let keyboard_layout = GLOBAL_PLATFORM.get().expect("Failed to get GLOBAL_PLATFORM").as_keyboard_platform_layout();
|
||||||
|
let key_is_modifier = matches!(*key, Key::Control | Key::Command | Key::Alt | Key::Shift | Key::Meta | Key::Accel);
|
||||||
|
|
||||||
if keyboard_platform == KeyboardPlatformLayout::Mac {
|
if keyboard_layout == KeyboardPlatformLayout::Mac && key_is_modifier {
|
||||||
match key_string.as_str() {
|
key.to_string()
|
||||||
"Command" => "⌘".to_string(),
|
|
||||||
"Control" => "⌃".to_string(),
|
|
||||||
"Alt" => "⌥".to_string(),
|
|
||||||
"Shift" => "⇧".to_string(),
|
|
||||||
_ => key_string + JOINER_MARK,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
key_string + JOINER_MARK
|
key.to_string() + JOINER_MARK
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
// Truncate to cut the joining character off the end if it's present
|
// Cut the joining character off the end, if present
|
||||||
if joined.ends_with(JOINER_MARK) {
|
if joined.ends_with(JOINER_MARK) {
|
||||||
joined.truncate(joined.len() - JOINER_MARK.len());
|
joined.truncate(joined.len() - JOINER_MARK.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
joined
|
write!(f, "{}", joined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,28 +13,24 @@ macro_rules! modifiers {
|
|||||||
/// Builds a slice of `MappingEntry` struct(s) that are used to:
|
/// Builds a slice of `MappingEntry` struct(s) that are used to:
|
||||||
/// - ...dispatch the given `action_dispatch` as an output `Message` if its discriminant is a currently available action
|
/// - ...dispatch the given `action_dispatch` as an output `Message` if its discriminant is a currently available action
|
||||||
/// - ...when the `InputMapperMessage` enum variant, as specified at the start and followed by a semicolon, is received
|
/// - ...when the `InputMapperMessage` enum variant, as specified at the start and followed by a semicolon, is received
|
||||||
/// - ...while any further conditions are met, like the optional `modifiers` being pressed or `layout` matching the OS.
|
/// - ...while the optional `modifiers` being pressed.
|
||||||
///
|
///
|
||||||
/// Syntax:
|
/// Syntax:
|
||||||
/// ```rs
|
/// ```rs
|
||||||
/// entry_for_layout!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message, layout: Option<KeyboardPlatformLayout>)
|
/// entry_for_layout!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message)
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// To avoid having to specify the final `layout` argument, instead use the wrapper macros: [entry]!, [standard]!, and [mac]!.
|
|
||||||
/// The former sets the layout to `None` which means the key mapping is layout-agnostic and compatible with all platforms.
|
|
||||||
///
|
|
||||||
/// The actions system controls which actions are currently available. Those are provided by the different message handlers based on the current application state and context.
|
/// The actions system controls which actions are currently available. Those are provided by the different message handlers based on the current application state and context.
|
||||||
/// Each handler adds or removes actions in the form of message discriminants. Here, we tie an input condition (such as a hotkey) to an action's full message.
|
/// Each handler adds or removes actions in the form of message discriminants. Here, we tie an input condition (such as a hotkey) to an action's full message.
|
||||||
/// When an action is currently available, and the user enters that input, the action's message is dispatched on the message bus.
|
/// When an action is currently available, and the user enters that input, the action's message is dispatched on the message bus.
|
||||||
macro_rules! entry_for_layout {
|
macro_rules! entry {
|
||||||
($input:expr; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? action_dispatch=$action_dispatch:expr,$(,)? layout=$layout:expr) => {
|
($input:expr; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? action_dispatch=$action_dispatch:expr$(,)?) => {
|
||||||
&[
|
&[&[
|
||||||
// Cause the `action_dispatch` message to be sent when the specified input occurs.
|
// Cause the `action_dispatch` message to be sent when the specified input occurs.
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: $input,
|
input: $input,
|
||||||
modifiers: modifiers!($($($modifier),*)?),
|
modifiers: modifiers!($($($modifier),*)?),
|
||||||
platform_layout: $layout,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Also cause the `action_dispatch` message to be sent when any of the specified refresh keys change.
|
// Also cause the `action_dispatch` message to be sent when any of the specified refresh keys change.
|
||||||
@@ -48,70 +44,15 @@ macro_rules! entry_for_layout {
|
|||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: InputMapperMessage::KeyDown(Key::$refresh),
|
input: InputMapperMessage::KeyDown(Key::$refresh),
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
platform_layout: $layout,
|
|
||||||
},
|
},
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: InputMapperMessage::KeyUp(Key::$refresh),
|
input: InputMapperMessage::KeyUp(Key::$refresh),
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
platform_layout: $layout,
|
|
||||||
},
|
},
|
||||||
)*
|
)*
|
||||||
)*
|
)*
|
||||||
]
|
]]
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps [entry_for_layout]! and calls it with an agnostic (`None`) keyboard platform `layout` to avoid having to specify that argument.
|
|
||||||
///
|
|
||||||
/// Syntax:
|
|
||||||
/// ```rs
|
|
||||||
/// entry!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message)
|
|
||||||
/// ```
|
|
||||||
macro_rules! entry {
|
|
||||||
($($arg:tt)*) => {
|
|
||||||
&[entry_for_layout!($($arg)*, layout=None)]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps [entry_for_layout]! and calls it with a `Standard` keyboard platform `layout` to avoid having to specify that argument.
|
|
||||||
///
|
|
||||||
/// Syntax:
|
|
||||||
/// ```rs
|
|
||||||
/// standard!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message)
|
|
||||||
/// ```
|
|
||||||
macro_rules! standard {
|
|
||||||
($($arg:tt)*) => {
|
|
||||||
entry_for_layout!($($arg)*, layout=Some(KeyboardPlatformLayout::Standard))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps [entry_for_layout]! and calls it with a `Mac` keyboard platform `layout` to avoid having to specify that argument.
|
|
||||||
///
|
|
||||||
/// Syntax:
|
|
||||||
/// ```rs
|
|
||||||
/// mac_only!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message)
|
|
||||||
/// ```
|
|
||||||
macro_rules! mac_only {
|
|
||||||
($($arg:tt)*) => {
|
|
||||||
entry_for_layout!($($arg)*, layout=Some(KeyboardPlatformLayout::Mac))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Groups multiple related entries for different platforms.
|
|
||||||
/// When a keyboard shortcut is not platform-agnostic, this should be used to contain a [mac]! and/or [standard]! entry.
|
|
||||||
///
|
|
||||||
/// Syntax:
|
|
||||||
///
|
|
||||||
/// ```rs
|
|
||||||
/// entry_multiplatform!(
|
|
||||||
/// standard!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message),
|
|
||||||
/// mac_only!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message),
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
macro_rules! entry_multiplatform {
|
|
||||||
{$($arg:expr),*,} => {
|
|
||||||
&[$($arg ),*]
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +100,5 @@ macro_rules! action_keys {
|
|||||||
|
|
||||||
pub(crate) use action_keys;
|
pub(crate) use action_keys;
|
||||||
pub(crate) use entry;
|
pub(crate) use entry;
|
||||||
pub(crate) use entry_for_layout;
|
|
||||||
pub(crate) use entry_multiplatform;
|
|
||||||
pub(crate) use mac_only;
|
|
||||||
pub(crate) use mapping;
|
pub(crate) use mapping;
|
||||||
pub(crate) use modifiers;
|
pub(crate) use modifiers;
|
||||||
pub(crate) use standard;
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use super::input_keyboard::KeysGroup;
|
use super::input_keyboard::{all_required_modifiers_pressed, KeysGroup};
|
||||||
use crate::messages::input_mapper::default_mapping::default_mapping;
|
use crate::messages::input_mapper::default_mapping::default_mapping;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{KeyStates, NUMBER_OF_KEYS};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{KeyStates, NUMBER_OF_KEYS};
|
||||||
use crate::messages::portfolio::document::utility_types::misc::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -16,7 +15,7 @@ pub struct Mapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Mapping {
|
impl Mapping {
|
||||||
pub fn match_input_message(&self, message: InputMapperMessage, keyboard_state: &KeyStates, actions: ActionList, keyboard_platform: KeyboardPlatformLayout) -> Option<Message> {
|
pub fn match_input_message(&self, message: InputMapperMessage, keyboard_state: &KeyStates, actions: ActionList) -> Option<Message> {
|
||||||
let list = match message {
|
let list = match message {
|
||||||
InputMapperMessage::KeyDown(key) => &self.key_down[key as usize],
|
InputMapperMessage::KeyDown(key) => &self.key_down[key as usize],
|
||||||
InputMapperMessage::KeyUp(key) => &self.key_up[key as usize],
|
InputMapperMessage::KeyUp(key) => &self.key_up[key as usize],
|
||||||
@@ -24,7 +23,7 @@ impl Mapping {
|
|||||||
InputMapperMessage::WheelScroll => &self.wheel_scroll,
|
InputMapperMessage::WheelScroll => &self.wheel_scroll,
|
||||||
InputMapperMessage::PointerMove => &self.pointer_move,
|
InputMapperMessage::PointerMove => &self.pointer_move,
|
||||||
};
|
};
|
||||||
list.match_mapping(keyboard_state, actions, keyboard_platform)
|
list.match_mapping(keyboard_state, actions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,26 +37,15 @@ impl Default for Mapping {
|
|||||||
pub struct KeyMappingEntries(pub Vec<MappingEntry>);
|
pub struct KeyMappingEntries(pub Vec<MappingEntry>);
|
||||||
|
|
||||||
impl KeyMappingEntries {
|
impl KeyMappingEntries {
|
||||||
pub fn match_mapping(&self, keyboard_state: &KeyStates, actions: ActionList, keyboard_platform: KeyboardPlatformLayout) -> Option<Message> {
|
pub fn match_mapping(&self, keyboard_state: &KeyStates, actions: ActionList) -> Option<Message> {
|
||||||
for entry in self.0.iter() {
|
for mapping in self.0.iter() {
|
||||||
// Skip this entry if it is platform-specific, and for a layout that does not match the user's keyboard platform layout
|
|
||||||
if let Some(entry_platform_layout) = entry.platform_layout {
|
|
||||||
if entry_platform_layout != keyboard_platform {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find which currently pressed keys are also the modifiers in this hotkey entry, then compare those against the required modifiers to see if there are zero missing
|
|
||||||
let pressed_modifiers = *keyboard_state & entry.modifiers;
|
|
||||||
let all_modifiers_without_pressed_modifiers = entry.modifiers ^ pressed_modifiers;
|
|
||||||
let all_required_modifiers_pressed = all_modifiers_without_pressed_modifiers.is_empty();
|
|
||||||
// Skip this entry if any of the required modifiers are missing
|
// Skip this entry if any of the required modifiers are missing
|
||||||
if !all_required_modifiers_pressed {
|
if all_required_modifiers_pressed(keyboard_state, &mapping.modifiers) {
|
||||||
continue;
|
// Search for the action in the list of available actions to see if it's currently available to activate
|
||||||
}
|
let matching_action_found = actions.iter().flatten().any(|action| mapping.action.to_discriminant() == *action);
|
||||||
|
if matching_action_found {
|
||||||
if actions.iter().flatten().any(|action| entry.action.to_discriminant() == *action) {
|
return Some(mapping.action.clone());
|
||||||
return Some(entry.action.clone());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -87,8 +75,6 @@ pub struct MappingEntry {
|
|||||||
pub input: InputMapperMessage,
|
pub input: InputMapperMessage,
|
||||||
/// Any additional keys that must be also pressed for this input mapping to match
|
/// Any additional keys that must be also pressed for this input mapping to match
|
||||||
pub modifiers: KeyStates,
|
pub modifiers: KeyStates,
|
||||||
/// The keyboard platform layout which this mapping is exclusive to, or `None` if it's platform-agnostic
|
|
||||||
pub platform_layout: Option<KeyboardPlatformLayout>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl MessageHandler<InputPreprocessorMessage, KeyboardPlatformLayout> for InputP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -62,17 +62,17 @@ impl MessageHandler<InputPreprocessorMessage, KeyboardPlatformLayout> for InputP
|
|||||||
responses.push_back(InputMapperMessage::DoubleClick.into());
|
responses.push_back(InputMapperMessage::DoubleClick.into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::KeyDown { key, modifier_keys } => {
|
InputPreprocessorMessage::KeyDown { key, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
self.keyboard.set(key as usize);
|
self.keyboard.set(key as usize);
|
||||||
responses.push_back(InputMapperMessage::KeyDown(key).into());
|
responses.push_back(InputMapperMessage::KeyDown(key).into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::KeyUp { key, modifier_keys } => {
|
InputPreprocessorMessage::KeyUp { key, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
self.keyboard.unset(key as usize);
|
self.keyboard.unset(key as usize);
|
||||||
responses.push_back(InputMapperMessage::KeyUp(key).into());
|
responses.push_back(InputMapperMessage::KeyUp(key).into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -80,7 +80,7 @@ impl MessageHandler<InputPreprocessorMessage, KeyboardPlatformLayout> for InputP
|
|||||||
self.translate_mouse_event(mouse_state, true, responses);
|
self.translate_mouse_event(mouse_state, true, responses);
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -91,7 +91,7 @@ impl MessageHandler<InputPreprocessorMessage, KeyboardPlatformLayout> for InputP
|
|||||||
self.translate_mouse_event(mouse_state, false, responses);
|
self.translate_mouse_event(mouse_state, false, responses);
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -99,7 +99,7 @@ impl MessageHandler<InputPreprocessorMessage, KeyboardPlatformLayout> for InputP
|
|||||||
self.translate_mouse_event(mouse_state, false, responses);
|
self.translate_mouse_event(mouse_state, false, responses);
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -138,18 +138,30 @@ impl InputPreprocessorMessageHandler {
|
|||||||
self.mouse = new_state;
|
self.mouse = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_modifier_keys(&mut self, modifier_keys: ModifierKeys, keyboard_platform: KeyboardPlatformLayout, responses: &mut VecDeque<Message>) {
|
fn update_states_of_modifier_keys(&mut self, pressed_modifier_keys: ModifierKeys, keyboard_platform: KeyboardPlatformLayout, responses: &mut VecDeque<Message>) {
|
||||||
self.handle_modifier_key(Key::Shift, modifier_keys.contains(ModifierKeys::SHIFT), responses);
|
let is_key_pressed = |key_to_check: ModifierKeys| pressed_modifier_keys.contains(key_to_check);
|
||||||
self.handle_modifier_key(Key::Alt, modifier_keys.contains(ModifierKeys::ALT), responses);
|
|
||||||
self.handle_modifier_key(Key::Control, modifier_keys.contains(ModifierKeys::CONTROL), responses);
|
// Update the state of the concrete modifier keys based on the source state
|
||||||
|
self.update_modifier_key(Key::Shift, is_key_pressed(ModifierKeys::SHIFT), responses);
|
||||||
|
self.update_modifier_key(Key::Alt, is_key_pressed(ModifierKeys::ALT), responses);
|
||||||
|
self.update_modifier_key(Key::Control, is_key_pressed(ModifierKeys::CONTROL), responses);
|
||||||
|
|
||||||
|
// Update the state of either the concrete Meta or the Command keys based on which one is applicable for this platform
|
||||||
let meta_or_command = match keyboard_platform {
|
let meta_or_command = match keyboard_platform {
|
||||||
KeyboardPlatformLayout::Mac => Key::Command,
|
KeyboardPlatformLayout::Mac => Key::Command,
|
||||||
KeyboardPlatformLayout::Standard => Key::Meta,
|
KeyboardPlatformLayout::Standard => Key::Meta,
|
||||||
};
|
};
|
||||||
self.handle_modifier_key(meta_or_command, modifier_keys.contains(ModifierKeys::META_OR_COMMAND), responses);
|
self.update_modifier_key(meta_or_command, is_key_pressed(ModifierKeys::META_OR_COMMAND), responses);
|
||||||
|
|
||||||
|
// Update the state of the virtual Accel key (the primary accelerator key) based on the source state of the Control or Command key, whichever is relevant on this platform
|
||||||
|
let accel_virtual_key_state = match keyboard_platform {
|
||||||
|
KeyboardPlatformLayout::Mac => is_key_pressed(ModifierKeys::META_OR_COMMAND),
|
||||||
|
KeyboardPlatformLayout::Standard => is_key_pressed(ModifierKeys::CONTROL),
|
||||||
|
};
|
||||||
|
self.update_modifier_key(Key::Accel, accel_virtual_key_state, responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_modifier_key(&mut self, key: Key, key_is_down: bool, responses: &mut VecDeque<Message>) {
|
fn update_modifier_key(&mut self, key: Key, key_is_down: bool, responses: &mut VecDeque<Message>) {
|
||||||
let key_was_down = self.keyboard.get(key as usize);
|
let key_was_down = self.keyboard.get(key as usize);
|
||||||
|
|
||||||
if key_was_down && !key_is_down {
|
if key_was_down && !key_is_down {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use super::utility_types::misc::LayoutTarget;
|
|||||||
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
|
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
|
||||||
use crate::messages::layout::utility_types::layout_widget::Layout;
|
use crate::messages::layout::utility_types::layout_widget::Layout;
|
||||||
use crate::messages::layout::utility_types::layout_widget::Widget;
|
use crate::messages::layout::utility_types::layout_widget::Widget;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graphene::layers::text_layer::Font;
|
use graphene::layers::text_layer::Font;
|
||||||
@@ -14,21 +13,21 @@ pub struct LayoutMessageHandler {
|
|||||||
layouts: [Layout; LayoutTarget::LayoutTargetLength as usize],
|
layouts: [Layout; LayoutTarget::LayoutTargetLength as usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage, (F, KeyboardPlatformLayout)> for LayoutMessageHandler {
|
impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage, F> for LayoutMessageHandler {
|
||||||
#[remain::check]
|
#[remain::check]
|
||||||
fn process_message(&mut self, message: LayoutMessage, data: (F, KeyboardPlatformLayout), responses: &mut std::collections::VecDeque<Message>) {
|
fn process_message(&mut self, message: LayoutMessage, data: F, responses: &mut std::collections::VecDeque<Message>) {
|
||||||
let (action_input_mapping, keyboard_platform) = data;
|
let action_input_mapping = data;
|
||||||
|
|
||||||
use LayoutMessage::*;
|
use LayoutMessage::*;
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
match message {
|
match message {
|
||||||
RefreshLayout { layout_target } => {
|
RefreshLayout { layout_target } => {
|
||||||
self.send_layout(layout_target, responses, &action_input_mapping, keyboard_platform);
|
self.send_layout(layout_target, responses, &action_input_mapping);
|
||||||
}
|
}
|
||||||
SendLayout { layout, layout_target } => {
|
SendLayout { layout, layout_target } => {
|
||||||
self.layouts[layout_target as usize] = layout;
|
self.layouts[layout_target as usize] = layout;
|
||||||
|
|
||||||
self.send_layout(layout_target, responses, &action_input_mapping, keyboard_platform);
|
self.send_layout(layout_target, responses, &action_input_mapping);
|
||||||
}
|
}
|
||||||
UpdateLayout { layout_target, widget_id, value } => {
|
UpdateLayout { layout_target, widget_id, value } => {
|
||||||
let layout = &mut self.layouts[layout_target as usize];
|
let layout = &mut self.layouts[layout_target as usize];
|
||||||
@@ -152,55 +151,49 @@ impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
|
|||||||
|
|
||||||
impl LayoutMessageHandler {
|
impl LayoutMessageHandler {
|
||||||
#[remain::check]
|
#[remain::check]
|
||||||
fn send_layout(
|
fn send_layout(&self, layout_target: LayoutTarget, responses: &mut VecDeque<Message>, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) {
|
||||||
&self,
|
|
||||||
layout_target: LayoutTarget,
|
|
||||||
responses: &mut VecDeque<Message>,
|
|
||||||
action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>,
|
|
||||||
keyboard_platform: KeyboardPlatformLayout,
|
|
||||||
) {
|
|
||||||
let layout = &self.layouts[layout_target as usize];
|
let layout = &self.layouts[layout_target as usize];
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
let message = match layout_target {
|
let message = match layout_target {
|
||||||
LayoutTarget::DialogDetails => FrontendMessage::UpdateDialogDetails {
|
LayoutTarget::DialogDetails => FrontendMessage::UpdateDialogDetails {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout {
|
LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout {
|
LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::LayerTreeOptions => FrontendMessage::UpdateLayerTreeOptionsLayout {
|
LayoutTarget::LayerTreeOptions => FrontendMessage::UpdateLayerTreeOptionsLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::MenuBar => FrontendMessage::UpdateMenuBarLayout {
|
LayoutTarget::MenuBar => FrontendMessage::UpdateMenuBarLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_menu_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_menu_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::PropertiesOptions => FrontendMessage::UpdatePropertyPanelOptionsLayout {
|
LayoutTarget::PropertiesOptions => FrontendMessage::UpdatePropertyPanelOptionsLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::PropertiesSections => FrontendMessage::UpdatePropertyPanelSectionsLayout {
|
LayoutTarget::PropertiesSections => FrontendMessage::UpdatePropertyPanelSectionsLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::ToolOptions => FrontendMessage::UpdateToolOptionsLayout {
|
LayoutTarget::ToolOptions => FrontendMessage::UpdateToolOptionsLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::ToolShelf => FrontendMessage::UpdateToolShelfLayout {
|
LayoutTarget::ToolShelf => FrontendMessage::UpdateToolShelfLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
LayoutTarget::WorkingColors => FrontendMessage::UpdateWorkingColorsLayout {
|
LayoutTarget::WorkingColors => FrontendMessage::UpdateWorkingColorsLayout {
|
||||||
layout_target,
|
layout_target,
|
||||||
layout: layout.clone().unwrap_widget_layout(action_input_mapping, keyboard_platform).layout,
|
layout: layout.clone().unwrap_widget_layout(action_input_mapping).layout,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use crate::application::generate_uuid;
|
|||||||
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
|
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
|
||||||
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
||||||
use crate::messages::layout::utility_types::misc::LayoutTarget;
|
use crate::messages::layout::utility_types::misc::LayoutTarget;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -35,14 +34,14 @@ pub enum Layout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Layout {
|
impl Layout {
|
||||||
pub fn unwrap_widget_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>, keyboard_platform: KeyboardPlatformLayout) -> WidgetLayout {
|
pub fn unwrap_widget_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) -> WidgetLayout {
|
||||||
if let Layout::WidgetLayout(mut widget_layout) = self {
|
if let Layout::WidgetLayout(mut widget_layout) = self {
|
||||||
// Function used multiple times later in this code block to convert `ActionKeys::Action` to `ActionKeys::Keys` and append its shortcut to the tooltip
|
// Function used multiple times later in this code block to convert `ActionKeys::Action` to `ActionKeys::Keys` and append its shortcut to the tooltip
|
||||||
let apply_shortcut_to_tooltip = |tooltip_shortcut: &mut ActionKeys, tooltip: &mut String| {
|
let apply_shortcut_to_tooltip = |tooltip_shortcut: &mut ActionKeys, tooltip: &mut String| {
|
||||||
tooltip_shortcut.to_keys(action_input_mapping);
|
tooltip_shortcut.to_keys(action_input_mapping);
|
||||||
|
|
||||||
if let ActionKeys::Keys(keys) = tooltip_shortcut {
|
if let ActionKeys::Keys(keys) = tooltip_shortcut {
|
||||||
let shortcut_text = keys.keys_text_shortcut(keyboard_platform);
|
let shortcut_text = keys.to_string();
|
||||||
|
|
||||||
if !shortcut_text.is_empty() {
|
if !shortcut_text.is_empty() {
|
||||||
if !tooltip.is_empty() {
|
if !tooltip.is_empty() {
|
||||||
@@ -90,7 +89,7 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>, _keyboard_platform: KeyboardPlatformLayout) -> MenuLayout {
|
pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) -> MenuLayout {
|
||||||
if let Layout::MenuLayout(mut menu_layout) = self {
|
if let Layout::MenuLayout(mut menu_layout) = self {
|
||||||
for menu_column in &mut menu_layout.layout {
|
for menu_column in &mut menu_layout.layout {
|
||||||
menu_column.children.fill_in_shortcut_actions_with_keys(action_input_mapping);
|
menu_column.children.fill_in_shortcut_actions_with_keys(action_input_mapping);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ pub enum Message {
|
|||||||
#[child]
|
#[child]
|
||||||
Frontend(FrontendMessage),
|
Frontend(FrontendMessage),
|
||||||
#[child]
|
#[child]
|
||||||
|
Globals(GlobalsMessage),
|
||||||
|
#[child]
|
||||||
InputMapper(InputMapperMessage),
|
InputMapper(InputMapperMessage),
|
||||||
#[child]
|
#[child]
|
||||||
InputPreprocessor(InputPreprocessorMessage),
|
InputPreprocessor(InputPreprocessorMessage),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pub mod broadcast;
|
|||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod dialog;
|
pub mod dialog;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
|
pub mod globals;
|
||||||
pub mod input_mapper;
|
pub mod input_mapper;
|
||||||
pub mod input_preprocessor;
|
pub mod input_preprocessor;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ impl Platform {
|
|||||||
match self {
|
match self {
|
||||||
Platform::Mac => KeyboardPlatformLayout::Mac,
|
Platform::Mac => KeyboardPlatformLayout::Mac,
|
||||||
Platform::Unknown => {
|
Platform::Unknown => {
|
||||||
log::warn!("The platform has not been set, remember to send `PortfolioMessage::SetPlatform` during editor initialization.");
|
log::warn!("The platform has not been set, remember to send `GlobalsMessage::SetPlatform` during editor initialization.");
|
||||||
KeyboardPlatformLayout::Standard
|
KeyboardPlatformLayout::Standard
|
||||||
}
|
}
|
||||||
_ => KeyboardPlatformLayout::Standard,
|
_ => KeyboardPlatformLayout::Standard,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::Platform;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graphene::layers::text_layer::Font;
|
use graphene::layers::text_layer::Font;
|
||||||
@@ -84,9 +83,6 @@ pub enum PortfolioMessage {
|
|||||||
SetActiveDocument {
|
SetActiveDocument {
|
||||||
document_id: u64,
|
document_id: u64,
|
||||||
},
|
},
|
||||||
SetPlatform {
|
|
||||||
platform: Platform,
|
|
||||||
},
|
|
||||||
UpdateDocumentWidgets,
|
UpdateDocumentWidgets,
|
||||||
UpdateOpenDocumentsList,
|
UpdateOpenDocumentsList,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use crate::messages::frontend::utility_types::FrontendDocumentDetails;
|
|||||||
use crate::messages::layout::utility_types::layout_widget::PropertyHolder;
|
use crate::messages::layout::utility_types::layout_widget::PropertyHolder;
|
||||||
use crate::messages::layout::utility_types::misc::LayoutTarget;
|
use crate::messages::layout::utility_types::misc::LayoutTarget;
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
||||||
use crate::messages::portfolio::document::utility_types::misc::Platform;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graphene::layers::layer_info::LayerDataTypeDiscriminant;
|
use graphene::layers::layer_info::LayerDataTypeDiscriminant;
|
||||||
@@ -22,7 +21,6 @@ pub struct PortfolioMessageHandler {
|
|||||||
active_document_id: Option<u64>,
|
active_document_id: Option<u64>,
|
||||||
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
||||||
font_cache: FontCache,
|
font_cache: FontCache,
|
||||||
pub platform: Platform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for PortfolioMessageHandler {
|
impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for PortfolioMessageHandler {
|
||||||
@@ -396,7 +394,6 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
responses.push_back(NavigationMessage::TranslateCanvas { delta: (0., 0.).into() }.into());
|
responses.push_back(NavigationMessage::TranslateCanvas { delta: (0., 0.).into() }.into());
|
||||||
}
|
}
|
||||||
SetActiveDocument { document_id } => self.active_document_id = Some(document_id),
|
SetActiveDocument { document_id } => self.active_document_id = Some(document_id),
|
||||||
SetPlatform { platform } => self.platform = platform,
|
|
||||||
UpdateDocumentWidgets => {
|
UpdateDocumentWidgets => {
|
||||||
if let Some(document) = self.active_document() {
|
if let Some(document) = self.active_document() {
|
||||||
document.update_document_widgets(responses);
|
document.update_document_widgets(responses);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDial
|
|||||||
pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler};
|
pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler};
|
||||||
pub use crate::messages::dialog::{DialogMessage, DialogMessageDiscriminant, DialogMessageHandler};
|
pub use crate::messages::dialog::{DialogMessage, DialogMessageDiscriminant, DialogMessageHandler};
|
||||||
pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant};
|
pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant};
|
||||||
|
pub use crate::messages::globals::{GlobalsMessage, GlobalsMessageDiscriminant, GlobalsMessageHandler};
|
||||||
pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageDiscriminant, InputMapperMessageHandler};
|
pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageDiscriminant, InputMapperMessageHandler};
|
||||||
pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler};
|
pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler};
|
||||||
pub use crate::messages::layout::{LayoutMessage, LayoutMessageDiscriminant, LayoutMessageHandler};
|
pub use crate::messages::layout::{LayoutMessage, LayoutMessageDiscriminant, LayoutMessageHandler};
|
||||||
@@ -42,6 +43,8 @@ pub use crate::messages::tool::tool_messages::spline_tool::{SplineToolMessage, S
|
|||||||
pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant};
|
pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant};
|
||||||
|
|
||||||
// Helper
|
// Helper
|
||||||
|
pub use crate::messages::globals::global_variables::*;
|
||||||
|
|
||||||
pub use graphite_proc_macros::*;
|
pub use graphite_proc_macros::*;
|
||||||
|
|
||||||
pub use std::collections::{HashMap, HashSet, VecDeque};
|
pub use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
use crate::application::set_uuid_seed;
|
||||||
use crate::application::Editor;
|
use crate::application::Editor;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
||||||
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
|
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
|
||||||
|
use crate::messages::portfolio::document::utility_types::misc::Platform;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::utility_types::ToolType;
|
use crate::messages::tool::utility_types::ToolType;
|
||||||
|
|
||||||
@@ -8,6 +10,8 @@ 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 create() -> Editor;
|
||||||
|
|
||||||
fn new_document(&mut self);
|
fn new_document(&mut self);
|
||||||
|
|
||||||
fn draw_rect(&mut self, x1: f64, y1: f64, x2: f64, y2: f64);
|
fn draw_rect(&mut self, x1: f64, y1: f64, x2: f64, y2: f64);
|
||||||
@@ -26,6 +30,20 @@ pub trait EditorTestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EditorTestUtils for Editor {
|
impl EditorTestUtils for Editor {
|
||||||
|
fn create() -> Editor {
|
||||||
|
set_uuid_seed(0);
|
||||||
|
|
||||||
|
let mut editor = Editor::new();
|
||||||
|
|
||||||
|
// We have to set this directly instead of using `GlobalsMessage::SetPlatform` because race conditions with multiple tests can cause that message handler to set it more than once, which is a failure.
|
||||||
|
// It isn't sufficient to guard the message dispatch here with a check if the once_cell is empty, because that isn't atomic and the time between checking and handling the dispatch can let multiple through.
|
||||||
|
let _ = GLOBAL_PLATFORM.set(Platform::Windows).is_ok();
|
||||||
|
|
||||||
|
editor.handle_message(Message::Init);
|
||||||
|
|
||||||
|
editor
|
||||||
|
}
|
||||||
|
|
||||||
fn new_document(&mut self) {
|
fn new_document(&mut self) {
|
||||||
self.handle_message(Message::Portfolio(PortfolioMessage::NewDocumentWithName { name: String::from("Test document") }));
|
self.handle_message(Message::Portfolio(PortfolioMessage::NewDocumentWithName { name: String::from("Test document") }));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,8 +195,11 @@ export default defineComponent({
|
|||||||
let key = keyWithLabel.key;
|
let key = keyWithLabel.key;
|
||||||
const label = keyWithLabel.label;
|
const label = keyWithLabel.label;
|
||||||
|
|
||||||
// Replace Alt with Option on Mac
|
// Replace Alt and Accel keys with their Mac-specific equivalents
|
||||||
if (key === "Alt" && platformIsMac()) key = "Option";
|
if (platformIsMac()) {
|
||||||
|
if (key === "Alt") key = "Option";
|
||||||
|
if (key === "Accel") key = "Command";
|
||||||
|
}
|
||||||
|
|
||||||
// Either display an icon...
|
// Either display an icon...
|
||||||
// @ts-expect-error We want undefined if it isn't in the object
|
// @ts-expect-error We want undefined if it isn't in the object
|
||||||
|
|||||||
@@ -66,8 +66,11 @@ impl JsEditorHandle {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the editor instances, dispatch the message, and store the `FrontendMessage` queue response
|
||||||
let frontend_messages = EDITOR_INSTANCES.with(|instances| {
|
let frontend_messages = EDITOR_INSTANCES.with(|instances| {
|
||||||
|
// Mutably borrow the editors, and if successful, we can access them in the closure
|
||||||
instances.try_borrow_mut().map(|mut editors| {
|
instances.try_borrow_mut().map(|mut editors| {
|
||||||
|
// Get the editor instance for this editor ID, then dispatch the message to the backend, and return its response `FrontendMessage` queue
|
||||||
editors
|
editors
|
||||||
.get_mut(&self.editor_id)
|
.get_mut(&self.editor_id)
|
||||||
.expect("EDITOR_INSTANCES does not contain the current editor_id")
|
.expect("EDITOR_INSTANCES does not contain the current editor_id")
|
||||||
@@ -75,9 +78,10 @@ impl JsEditorHandle {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Process any `FrontendMessage` responses resulting from the backend processing the dispatched message
|
||||||
if let Ok(frontend_messages) = frontend_messages {
|
if let Ok(frontend_messages) = frontend_messages {
|
||||||
|
// Send each `FrontendMessage` to the JavaScript frontend
|
||||||
for message in frontend_messages.into_iter() {
|
for message in frontend_messages.into_iter() {
|
||||||
// Send each FrontendMessage to the JavaScript frontend
|
|
||||||
self.send_frontend_message_to_js(message);
|
self.send_frontend_message_to_js(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +119,7 @@ impl JsEditorHandle {
|
|||||||
_ => Platform::Unknown,
|
_ => Platform::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.dispatch(PortfolioMessage::SetPlatform { platform });
|
self.dispatch(GlobalsMessage::SetPlatform { platform });
|
||||||
self.dispatch(Message::Init);
|
self.dispatch(Message::Init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user