mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Merge branch 'master' into spiral-node
This commit is contained in:
commit
0594b49b5b
18 changed files with 182 additions and 155 deletions
|
@ -150,7 +150,7 @@ petgraph = { version = "0.7.1", default-features = false, features = [
|
||||||
"graphmap",
|
"graphmap",
|
||||||
] }
|
] }
|
||||||
half = { version = "2.4.1", default-features = false, features = ["bytemuck", "serde"] }
|
half = { version = "2.4.1", default-features = false, features = ["bytemuck", "serde"] }
|
||||||
tinyvec = { version = "1" }
|
tinyvec = { version = "1", features = ["std"] }
|
||||||
criterion = { version = "0.5", features = ["html_reports"] }
|
criterion = { version = "0.5", features = ["html_reports"] }
|
||||||
iai-callgrind = { version = "0.12.3" }
|
iai-callgrind = { version = "0.12.3" }
|
||||||
ndarray = "0.16.1"
|
ndarray = "0.16.1"
|
||||||
|
|
|
@ -319,12 +319,11 @@ impl Dispatcher {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logs a message that is about to be executed,
|
/// Logs a message that is about to be executed, either as a tree
|
||||||
/// either as a tree with a discriminant or the entire payload (depending on settings)
|
/// with a discriminant or the entire payload (depending on settings)
|
||||||
fn log_message(&self, message: &Message, queues: &[VecDeque<Message>], message_logging_verbosity: MessageLoggingVerbosity) {
|
fn log_message(&self, message: &Message, queues: &[VecDeque<Message>], message_logging_verbosity: MessageLoggingVerbosity) {
|
||||||
let discriminant = MessageDiscriminant::from(message);
|
let discriminant = MessageDiscriminant::from(message);
|
||||||
let is_blocked = DEBUG_MESSAGE_BLOCK_LIST.iter().any(|&blocked_discriminant| discriminant == blocked_discriminant)
|
let is_blocked = DEBUG_MESSAGE_BLOCK_LIST.contains(&discriminant) || DEBUG_MESSAGE_ENDING_BLOCK_LIST.iter().any(|blocked_name| discriminant.local_name().ends_with(blocked_name));
|
||||||
|| DEBUG_MESSAGE_ENDING_BLOCK_LIST.iter().any(|blocked_name| discriminant.local_name().ends_with(blocked_name));
|
|
||||||
|
|
||||||
if !is_blocked {
|
if !is_blocked {
|
||||||
match message_logging_verbosity {
|
match message_logging_verbosity {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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::input_mapper::utility_types::misc::MappingEntry;
|
||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -47,12 +48,12 @@ impl InputMapperMessageHandler {
|
||||||
ma.map(|a| ((i as u8).try_into().unwrap(), a))
|
ma.map(|a| ((i as u8).try_into().unwrap(), a))
|
||||||
})
|
})
|
||||||
.for_each(|(k, a): (Key, _)| {
|
.for_each(|(k, a): (Key, _)| {
|
||||||
let _ = write!(output, "{}: {}, ", k.to_discriminant().local_name(), a.local_name().split('.').last().unwrap());
|
let _ = write!(output, "{}: {}, ", k.to_discriminant().local_name(), a.local_name().split('.').next_back().unwrap());
|
||||||
});
|
});
|
||||||
output.replace("Key", "")
|
output.replace("Key", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Vec<KeysGroup> {
|
pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Option<KeysGroup> {
|
||||||
let all_key_mapping_entries = std::iter::empty()
|
let all_key_mapping_entries = std::iter::empty()
|
||||||
.chain(self.mapping.key_up.iter())
|
.chain(self.mapping.key_up.iter())
|
||||||
.chain(self.mapping.key_down.iter())
|
.chain(self.mapping.key_down.iter())
|
||||||
|
@ -66,55 +67,65 @@ 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);
|
||||||
|
|
||||||
|
// Get the `Key` for this platform's accelerator key
|
||||||
let keyboard_layout = || GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
let keyboard_layout = || GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
||||||
let platform_accel_key = match keyboard_layout() {
|
let platform_accel_key = match keyboard_layout() {
|
||||||
KeyboardPlatformLayout::Standard => Key::Control,
|
KeyboardPlatformLayout::Standard => Key::Control,
|
||||||
KeyboardPlatformLayout::Mac => Key::Command,
|
KeyboardPlatformLayout::Mac => Key::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let entry_to_key = |entry: &MappingEntry| {
|
||||||
|
// Get the modifier keys for the entry (and convert them to Key)
|
||||||
|
let mut keys = entry
|
||||||
|
.modifiers
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
// TODO: Use a safe solution eventually
|
||||||
|
assert!(
|
||||||
|
i < input_keyboard::NUMBER_OF_KEYS,
|
||||||
|
"Attempting to convert a Key with enum index {i}, which is larger than the number of Key enums",
|
||||||
|
);
|
||||||
|
(i as u8).try_into().unwrap()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Append the key button for the entry
|
||||||
|
use InputMapperMessage as IMM;
|
||||||
|
match entry.input {
|
||||||
|
IMM::KeyDown(key) | IMM::KeyUp(key) | IMM::KeyDownNoRepeat(key) | IMM::KeyUpNoRepeat(key) => keys.push(key),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.sort_by(|&a, &b| {
|
||||||
|
// Order according to platform guidelines mentioned at https://ux.stackexchange.com/questions/58185/normative-ordering-for-modifier-key-combinations
|
||||||
|
const ORDER: [Key; 4] = [Key::Control, Key::Alt, Key::Shift, Key::Command];
|
||||||
|
|
||||||
|
// Treat the `Accel` virtual key as the platform's accel key for sorting comparison purposes
|
||||||
|
let a = if a == Key::Accel { platform_accel_key } else { a };
|
||||||
|
let b = if b == Key::Accel { platform_accel_key } else { b };
|
||||||
|
|
||||||
|
// Find where the keys are in the order, or put them at the end if they're not found
|
||||||
|
let a = ORDER.iter().position(|&key| key == a).unwrap_or(ORDER.len());
|
||||||
|
let b = ORDER.iter().position(|&key| key == b).unwrap_or(ORDER.len());
|
||||||
|
|
||||||
|
// Compare the positions of both keys
|
||||||
|
a.cmp(&b)
|
||||||
|
});
|
||||||
|
|
||||||
|
KeysGroup(keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
// If a canonical key combination is found, return it
|
||||||
|
if let Some(canonical) = found_actions.clone().find(|entry| entry.canonical).map(entry_to_key) {
|
||||||
|
return Some(canonical);
|
||||||
|
}
|
||||||
|
|
||||||
// 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>());
|
||||||
found_actions
|
let mut key_sequences = found_actions.map(entry_to_key).collect::<Vec<_>>();
|
||||||
.map(|entry| {
|
|
||||||
// Get the modifier keys for the entry (and convert them to Key)
|
|
||||||
let mut keys = entry
|
|
||||||
.modifiers
|
|
||||||
.iter()
|
|
||||||
.map(|i| {
|
|
||||||
// TODO: Use a safe solution eventually
|
|
||||||
assert!(
|
|
||||||
i < input_keyboard::NUMBER_OF_KEYS,
|
|
||||||
"Attempting to convert a Key with enum index {i}, which is larger than the number of Key enums",
|
|
||||||
);
|
|
||||||
(i as u8).try_into().unwrap()
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Append the key button for the entry
|
// Return the shortest key sequence, if any
|
||||||
use InputMapperMessage as IMM;
|
key_sequences.sort_by_key(|keys| keys.0.len());
|
||||||
match entry.input {
|
key_sequences.first().cloned()
|
||||||
IMM::KeyDown(key) | IMM::KeyUp(key) | IMM::KeyDownNoRepeat(key) | IMM::KeyUpNoRepeat(key) => keys.push(key),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.sort_by(|&a, &b| {
|
|
||||||
// Order according to platform guidelines mentioned at https://ux.stackexchange.com/questions/58185/normative-ordering-for-modifier-key-combinations
|
|
||||||
const ORDER: [Key; 4] = [Key::Control, Key::Alt, Key::Shift, Key::Command];
|
|
||||||
|
|
||||||
// Treat the `Accel` virtual key as the platform's accel key for sorting comparison purposes
|
|
||||||
let a = if a == Key::Accel { platform_accel_key } else { a };
|
|
||||||
let b = if b == Key::Accel { platform_accel_key } else { b };
|
|
||||||
|
|
||||||
// Find where the keys are in the order, or put them at the end if they're not found
|
|
||||||
let a = ORDER.iter().position(|&key| key == a).unwrap_or(ORDER.len());
|
|
||||||
let b = ORDER.iter().position(|&key| key == b).unwrap_or(ORDER.len());
|
|
||||||
|
|
||||||
// Compare the positions of both keys
|
|
||||||
a.cmp(&b)
|
|
||||||
});
|
|
||||||
|
|
||||||
KeysGroup(keys)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapp
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
|
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
|
||||||
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::GroupFolderType;
|
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
|
||||||
use crate::messages::portfolio::document::utility_types::transformation::TransformType;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
|
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
|
||||||
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
|
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
|
||||||
|
@ -221,7 +220,8 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt, break_colinear_molding: Alt }),
|
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt, break_colinear_molding: Alt }),
|
||||||
entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete),
|
entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete),
|
||||||
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors),
|
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors),
|
||||||
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::DeselectAllPoints),
|
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], canonical, action_dispatch=PathToolMessage::DeselectAllPoints),
|
||||||
|
entry!(KeyDown(KeyA); modifiers=[Alt], action_dispatch=PathToolMessage::DeselectAllPoints),
|
||||||
entry!(KeyDown(Backspace); action_dispatch=PathToolMessage::Delete),
|
entry!(KeyDown(Backspace); action_dispatch=PathToolMessage::Delete),
|
||||||
entry!(KeyUp(MouseLeft); action_dispatch=PathToolMessage::DragStop { extend_selection: Shift, shrink_selection: Alt }),
|
entry!(KeyUp(MouseLeft); action_dispatch=PathToolMessage::DragStop { extend_selection: Shift, shrink_selection: Alt }),
|
||||||
entry!(KeyDown(Enter); action_dispatch=PathToolMessage::Enter { extend_selection: Shift, shrink_selection: Alt }),
|
entry!(KeyDown(Enter); action_dispatch=PathToolMessage::Enter { extend_selection: Shift, shrink_selection: Alt }),
|
||||||
|
@ -313,9 +313,10 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolShapeEllipse),
|
entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolShapeEllipse),
|
||||||
entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolShape),
|
entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolShape),
|
||||||
entry!(KeyDown(KeyB); action_dispatch=ToolMessage::ActivateToolBrush),
|
entry!(KeyDown(KeyB); action_dispatch=ToolMessage::ActivateToolBrush),
|
||||||
entry!(KeyDown(KeyX); modifiers=[Accel, Shift], action_dispatch=ToolMessage::ResetColors),
|
entry!(KeyDown(KeyD); 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::SelectRandomWorkingColor { primary: true }),
|
||||||
|
entry!(KeyDown(KeyC); modifiers=[Alt, Shift], action_dispatch=ToolMessage::SelectRandomWorkingColor { primary: false }),
|
||||||
//
|
//
|
||||||
// DocumentMessage
|
// DocumentMessage
|
||||||
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle),
|
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle),
|
||||||
|
@ -327,20 +328,21 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=DocumentMessage::ToggleSelectedVisibility),
|
entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=DocumentMessage::ToggleSelectedVisibility),
|
||||||
entry!(KeyDown(KeyL); modifiers=[Accel], action_dispatch=DocumentMessage::ToggleSelectedLocked),
|
entry!(KeyDown(KeyL); modifiers=[Accel], action_dispatch=DocumentMessage::ToggleSelectedLocked),
|
||||||
entry!(KeyDown(KeyG); modifiers=[Alt], action_dispatch=DocumentMessage::ToggleGridVisibility),
|
entry!(KeyDown(KeyG); modifiers=[Alt], action_dispatch=DocumentMessage::ToggleGridVisibility),
|
||||||
entry!(KeyDown(KeyZ); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::Redo),
|
entry!(KeyDown(KeyZ); modifiers=[Accel, Shift], canonical, action_dispatch=DocumentMessage::Redo),
|
||||||
entry!(KeyDown(KeyY); modifiers=[Accel], action_dispatch=DocumentMessage::Redo),
|
entry!(KeyDown(KeyY); modifiers=[Accel], action_dispatch=DocumentMessage::Redo),
|
||||||
entry!(KeyDown(KeyZ); modifiers=[Accel], action_dispatch=DocumentMessage::Undo),
|
entry!(KeyDown(KeyZ); modifiers=[Accel], action_dispatch=DocumentMessage::Undo),
|
||||||
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=DocumentMessage::SelectAllLayers),
|
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=DocumentMessage::SelectAllLayers),
|
||||||
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::DeselectAllLayers),
|
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], canonical, action_dispatch=DocumentMessage::DeselectAllLayers),
|
||||||
|
entry!(KeyDown(KeyA); modifiers=[Alt], action_dispatch=DocumentMessage::DeselectAllLayers),
|
||||||
entry!(KeyDown(KeyS); modifiers=[Accel], action_dispatch=DocumentMessage::SaveDocument),
|
entry!(KeyDown(KeyS); modifiers=[Accel], action_dispatch=DocumentMessage::SaveDocument),
|
||||||
entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
entry!(KeyDown(KeyD); modifiers=[Accel], canonical, action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
||||||
entry!(KeyDown(KeyJ); modifiers=[Accel], action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
entry!(KeyDown(KeyJ); modifiers=[Accel], action_dispatch=DocumentMessage::DuplicateSelectedLayers),
|
||||||
entry!(KeyDown(KeyG); modifiers=[Accel], action_dispatch=DocumentMessage::GroupSelectedLayers { group_folder_type: GroupFolderType::Layer }),
|
entry!(KeyDown(KeyG); modifiers=[Accel], action_dispatch=DocumentMessage::GroupSelectedLayers { group_folder_type: GroupFolderType::Layer }),
|
||||||
entry!(KeyDown(KeyG); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::UngroupSelectedLayers),
|
entry!(KeyDown(KeyG); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::UngroupSelectedLayers),
|
||||||
entry!(KeyDown(KeyN); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::CreateEmptyFolder),
|
entry!(KeyDown(KeyN); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::CreateEmptyFolder),
|
||||||
entry!(KeyDown(Backslash); modifiers=[Alt], action_dispatch=DocumentMessage::SelectParentLayer),
|
entry!(KeyDown(Escape); modifiers=[Shift], action_dispatch=DocumentMessage::SelectParentLayer),
|
||||||
entry!(KeyDown(BracketLeft); modifiers=[Alt], action_dispatch=DocumentMessage::SelectionStepBack),
|
entry!(KeyDown(BracketLeft); modifiers=[Alt], canonical, action_dispatch=DocumentMessage::SelectionStepBack),
|
||||||
entry!(KeyDown(BracketRight); modifiers=[Alt], action_dispatch=DocumentMessage::SelectionStepForward),
|
entry!(KeyDown(BracketRight); modifiers=[Alt], canonical, action_dispatch=DocumentMessage::SelectionStepForward),
|
||||||
entry!(KeyDown(MouseBack); action_dispatch=DocumentMessage::SelectionStepBack),
|
entry!(KeyDown(MouseBack); action_dispatch=DocumentMessage::SelectionStepBack),
|
||||||
entry!(KeyDown(MouseForward); action_dispatch=DocumentMessage::SelectionStepForward),
|
entry!(KeyDown(MouseForward); action_dispatch=DocumentMessage::SelectionStepForward),
|
||||||
entry!(KeyDown(Digit0); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasToFitAll),
|
entry!(KeyDown(Digit0); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasToFitAll),
|
||||||
|
@ -376,9 +378,9 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(KeyDown(ArrowRight); action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }),
|
entry!(KeyDown(ArrowRight); action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }),
|
||||||
//
|
//
|
||||||
// TransformLayerMessage
|
// TransformLayerMessage
|
||||||
entry!(KeyDown(KeyG); action_dispatch=TransformLayerMessage::BeginGRS { transform_type: TransformType::Grab }),
|
entry!(KeyDown(KeyG); action_dispatch=TransformLayerMessage::BeginGrab),
|
||||||
entry!(KeyDown(KeyR); action_dispatch=TransformLayerMessage::BeginGRS { transform_type: TransformType::Rotate }),
|
entry!(KeyDown(KeyR); action_dispatch=TransformLayerMessage::BeginRotate),
|
||||||
entry!(KeyDown(KeyS); action_dispatch=TransformLayerMessage::BeginGRS { transform_type: TransformType::Scale }),
|
entry!(KeyDown(KeyS); action_dispatch=TransformLayerMessage::BeginScale),
|
||||||
entry!(KeyDown(Digit0); action_dispatch=TransformLayerMessage::TypeDigit { digit: 0 }),
|
entry!(KeyDown(Digit0); action_dispatch=TransformLayerMessage::TypeDigit { digit: 0 }),
|
||||||
entry!(KeyDown(Digit1); action_dispatch=TransformLayerMessage::TypeDigit { digit: 1 }),
|
entry!(KeyDown(Digit1); action_dispatch=TransformLayerMessage::TypeDigit { digit: 1 }),
|
||||||
entry!(KeyDown(Digit2); action_dispatch=TransformLayerMessage::TypeDigit { digit: 2 }),
|
entry!(KeyDown(Digit2); action_dispatch=TransformLayerMessage::TypeDigit { digit: 2 }),
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl MessageHandler<KeyMappingMessage, KeyMappingMessageData<'_>> for KeyMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyMappingMessageHandler {
|
impl KeyMappingMessageHandler {
|
||||||
pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Vec<KeysGroup> {
|
pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Option<KeysGroup> {
|
||||||
self.mapping_handler.action_input_mapping(action_to_find)
|
self.mapping_handler.action_input_mapping(action_to_find)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,44 +24,54 @@ macro_rules! modifiers {
|
||||||
/// 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 {
|
macro_rules! entry {
|
||||||
|
// Pattern with canonical parameter
|
||||||
|
($input:expr_2021; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? canonical, action_dispatch=$action_dispatch:expr_2021$(,)?) => {
|
||||||
|
entry!($input; $($($modifier),*)?; $($($refresh),*)?; $action_dispatch; true)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pattern without canonical parameter
|
||||||
($input:expr_2021; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? action_dispatch=$action_dispatch:expr_2021$(,)?) => {
|
($input:expr_2021; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? action_dispatch=$action_dispatch:expr_2021$(,)?) => {
|
||||||
|
entry!($input; $($($modifier),*)?; $($($refresh),*)?; $action_dispatch; false)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation macro to avoid code duplication
|
||||||
|
($input:expr; $($modifier:ident),*; $($refresh:ident),*; $action_dispatch:expr; $canonical: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),*),
|
||||||
|
canonical: $canonical,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 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.
|
||||||
//
|
|
||||||
// For example, a snapping state bound to the Shift key may change if the user presses or releases that key.
|
|
||||||
// In that case, we want to dispatch the action's message even though the pointer didn't necessarily move so
|
|
||||||
// the input handler can update the snapping state without making the user move the mouse to see the change.
|
|
||||||
$(
|
|
||||||
$(
|
$(
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: InputMapperMessage::KeyDown(Key::$refresh),
|
input: InputMapperMessage::KeyDown(Key::$refresh),
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
|
canonical: $canonical,
|
||||||
},
|
},
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: InputMapperMessage::KeyUp(Key::$refresh),
|
input: InputMapperMessage::KeyUp(Key::$refresh),
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
|
canonical: $canonical,
|
||||||
},
|
},
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: InputMapperMessage::KeyDownNoRepeat(Key::$refresh),
|
input: InputMapperMessage::KeyDownNoRepeat(Key::$refresh),
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
|
canonical: $canonical,
|
||||||
},
|
},
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
action: $action_dispatch.into(),
|
action: $action_dispatch.into(),
|
||||||
input: InputMapperMessage::KeyUpNoRepeat(Key::$refresh),
|
input: InputMapperMessage::KeyUpNoRepeat(Key::$refresh),
|
||||||
modifiers: modifiers!(),
|
modifiers: modifiers!(),
|
||||||
|
canonical: $canonical,
|
||||||
},
|
},
|
||||||
)*
|
)*
|
||||||
)*
|
|
||||||
]]
|
]]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::input_keyboard::{Key, KeysGroup, LayoutKeysGroup, all_required_modifiers_pressed};
|
use super::input_keyboard::{KeysGroup, LayoutKeysGroup, all_required_modifiers_pressed};
|
||||||
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
||||||
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::input_mapper::utility_types::input_mouse::NUMBER_OF_MOUSE_BUTTONS;
|
use crate::messages::input_mapper::utility_types::input_mouse::NUMBER_OF_MOUSE_BUTTONS;
|
||||||
|
@ -120,6 +120,8 @@ 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,
|
||||||
|
/// True indicates that this takes priority as the labeled hotkey shown in UI menus and tooltips instead of an alternate binding for the same action
|
||||||
|
pub canonical: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
@ -130,36 +132,12 @@ pub enum ActionKeys {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionKeys {
|
impl ActionKeys {
|
||||||
pub fn to_keys(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) -> String {
|
pub fn to_keys(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Action(action) => {
|
Self::Action(action) => {
|
||||||
// Take the shortest sequence of keys
|
if let Some(keys) = action_input_mapping(action) {
|
||||||
let mut key_sequences = action_input_mapping(action);
|
let description = keys.to_string();
|
||||||
key_sequences.sort_by_key(|keys| keys.0.len());
|
*self = Self::Keys(keys.into());
|
||||||
let mut secondary_key_sequence = key_sequences.get(1).cloned();
|
|
||||||
let mut key_sequence = key_sequences.get_mut(0);
|
|
||||||
|
|
||||||
// TODO: Replace this exception with a per-action choice of canonical hotkey
|
|
||||||
if let Some(key_sequence) = &mut key_sequence {
|
|
||||||
if key_sequence.0.as_slice() == [Key::MouseBack] {
|
|
||||||
if let Some(replacement) = &mut secondary_key_sequence {
|
|
||||||
std::mem::swap(*key_sequence, replacement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(key_sequence) = &mut key_sequence {
|
|
||||||
if key_sequence.0.as_slice() == [Key::MouseForward] {
|
|
||||||
if let Some(replacement) = &mut secondary_key_sequence {
|
|
||||||
std::mem::swap(*key_sequence, replacement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(keys) = key_sequence {
|
|
||||||
let mut taken_keys = KeysGroup::default();
|
|
||||||
std::mem::swap(keys, &mut taken_keys);
|
|
||||||
let description = taken_keys.to_string();
|
|
||||||
*self = Self::Keys(taken_keys.into());
|
|
||||||
description
|
description
|
||||||
} else {
|
} else {
|
||||||
*self = Self::Keys(KeysGroup::default().into());
|
*self = Self::Keys(KeysGroup::default().into());
|
||||||
|
|
|
@ -342,7 +342,7 @@ impl LayoutMessageHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage, F> for LayoutMessageHandler {
|
impl<F: Fn(&MessageDiscriminant) -> Option<KeysGroup>> MessageHandler<LayoutMessage, F> for LayoutMessageHandler {
|
||||||
fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque<Message>, action_input_mapping: F) {
|
fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque<Message>, action_input_mapping: F) {
|
||||||
match message {
|
match message {
|
||||||
LayoutMessage::ResendActiveWidget { layout_target, widget_id } => {
|
LayoutMessage::ResendActiveWidget { layout_target, widget_id } => {
|
||||||
|
@ -385,7 +385,7 @@ impl LayoutMessageHandler {
|
||||||
layout_target: LayoutTarget,
|
layout_target: LayoutTarget,
|
||||||
new_layout: Layout,
|
new_layout: Layout,
|
||||||
responses: &mut VecDeque<Message>,
|
responses: &mut VecDeque<Message>,
|
||||||
action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>,
|
action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>,
|
||||||
) {
|
) {
|
||||||
match new_layout {
|
match new_layout {
|
||||||
Layout::WidgetLayout(_) => {
|
Layout::WidgetLayout(_) => {
|
||||||
|
@ -419,7 +419,7 @@ impl LayoutMessageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a diff to the frontend based on the layout target.
|
/// Send a diff to the frontend based on the layout target.
|
||||||
fn send_diff(&self, mut diff: Vec<WidgetDiff>, layout_target: LayoutTarget, responses: &mut VecDeque<Message>, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) {
|
fn send_diff(&self, mut diff: Vec<WidgetDiff>, layout_target: LayoutTarget, responses: &mut VecDeque<Message>, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) {
|
||||||
diff.iter_mut().for_each(|diff| diff.new_value.apply_keyboard_shortcut(action_input_mapping));
|
diff.iter_mut().for_each(|diff| diff.new_value.apply_keyboard_shortcut(action_input_mapping));
|
||||||
|
|
||||||
let message = match layout_target {
|
let message = match layout_target {
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub enum Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout {
|
impl Layout {
|
||||||
pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) -> MenuLayout {
|
pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) -> MenuLayout {
|
||||||
if let Self::MenuLayout(mut menu) = self {
|
if let Self::MenuLayout(mut menu) = self {
|
||||||
menu.layout
|
menu.layout
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -589,7 +589,7 @@ pub enum DiffUpdate {
|
||||||
|
|
||||||
impl DiffUpdate {
|
impl DiffUpdate {
|
||||||
/// Append the keyboard shortcut to the tooltip where applicable
|
/// Append the keyboard shortcut to the tooltip where applicable
|
||||||
pub fn apply_keyboard_shortcut(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) {
|
pub fn apply_keyboard_shortcut(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) {
|
||||||
// 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| {
|
||||||
let shortcut_text = tooltip_shortcut.to_keys(action_input_mapping);
|
let shortcut_text = tooltip_shortcut.to_keys(action_input_mapping);
|
||||||
|
|
|
@ -12,7 +12,7 @@ impl MenuBarEntryChildren {
|
||||||
Self(Vec::new())
|
Self(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_in_shortcut_actions_with_keys(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec<KeysGroup>) {
|
pub fn fill_in_shortcut_actions_with_keys(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) {
|
||||||
let entries = self.0.iter_mut().flatten();
|
let entries = self.0.iter_mut().flatten();
|
||||||
|
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
|
|
|
@ -62,6 +62,8 @@ const REPLACEMENTS: &[(&str, &str)] = &[
|
||||||
("graphene_core::ops::NumberValueNode", "graphene_math_nodes::NumberValueNode"),
|
("graphene_core::ops::NumberValueNode", "graphene_math_nodes::NumberValueNode"),
|
||||||
("graphene_core::ops::PercentageValueNode", "graphene_math_nodes::PercentageValueNode"),
|
("graphene_core::ops::PercentageValueNode", "graphene_math_nodes::PercentageValueNode"),
|
||||||
("graphene_core::ops::CoordinateValueNode", "graphene_math_nodes::CoordinateValueNode"),
|
("graphene_core::ops::CoordinateValueNode", "graphene_math_nodes::CoordinateValueNode"),
|
||||||
|
("graphene_core::ops::ConstructVector2", "graphene_math_nodes::CoordinateValueNode"),
|
||||||
|
("graphene_core::ops::Vector2ValueNode", "graphene_math_nodes::CoordinateValueNode"),
|
||||||
("graphene_core::ops::ColorValueNode", "graphene_math_nodes::ColorValueNode"),
|
("graphene_core::ops::ColorValueNode", "graphene_math_nodes::ColorValueNode"),
|
||||||
("graphene_core::ops::GradientValueNode", "graphene_math_nodes::GradientValueNode"),
|
("graphene_core::ops::GradientValueNode", "graphene_math_nodes::GradientValueNode"),
|
||||||
("graphene_core::ops::StringValueNode", "graphene_math_nodes::StringValueNode"),
|
("graphene_core::ops::StringValueNode", "graphene_math_nodes::StringValueNode"),
|
||||||
|
@ -76,8 +78,6 @@ const REPLACEMENTS: &[(&str, &str)] = &[
|
||||||
("graphene_core::logic::LogicAndNode", "graphene_core::ops::LogicAndNode"),
|
("graphene_core::logic::LogicAndNode", "graphene_core::ops::LogicAndNode"),
|
||||||
("graphene_core::logic::LogicNotNode", "graphene_core::ops::LogicNotNode"),
|
("graphene_core::logic::LogicNotNode", "graphene_core::ops::LogicNotNode"),
|
||||||
("graphene_core::logic::LogicOrNode", "graphene_core::ops::LogicOrNode"),
|
("graphene_core::logic::LogicOrNode", "graphene_core::ops::LogicOrNode"),
|
||||||
("graphene_core::ops::ConstructVector2", "graphene_core::ops::CoordinateValueNode"),
|
|
||||||
("graphene_core::ops::Vector2ValueNode", "graphene_core::ops::CoordinateValueNode"),
|
|
||||||
("graphene_core::raster::BlendModeNode", "graphene_core::blending_nodes::BlendModeNode"),
|
("graphene_core::raster::BlendModeNode", "graphene_core::blending_nodes::BlendModeNode"),
|
||||||
("graphene_core::raster::OpacityNode", "graphene_core::blending_nodes::OpacityNode"),
|
("graphene_core::raster::OpacityNode", "graphene_core::blending_nodes::OpacityNode"),
|
||||||
("graphene_core::raster::BlendingNode", "graphene_core::blending_nodes::BlendingNode"),
|
("graphene_core::raster::BlendingNode", "graphene_core::blending_nodes::BlendingNode"),
|
||||||
|
@ -121,8 +121,24 @@ const REPLACEMENTS: &[(&str, &str)] = &[
|
||||||
("graphene_core::raster::PosterizeNode", "graphene_raster_nodes::adjustments::PosterizeNode"),
|
("graphene_core::raster::PosterizeNode", "graphene_raster_nodes::adjustments::PosterizeNode"),
|
||||||
("graphene_core::raster::adjustments::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"),
|
("graphene_core::raster::adjustments::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"),
|
||||||
("graphene_core::raster::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"),
|
("graphene_core::raster::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"),
|
||||||
|
("graphene_core::raster::adjustments::ColorOverlayNode", "graphene_raster_nodes::adjustments::ColorOverlayNode"),
|
||||||
|
("graphene_raster_nodes::generate_curves::ColorOverlayNode", "graphene_raster_nodes::adjustments::ColorOverlayNode"),
|
||||||
|
// raster
|
||||||
("graphene_core::raster::adjustments::GenerateCurvesNode", "graphene_raster_nodes::generate_curves::GenerateCurvesNode"),
|
("graphene_core::raster::adjustments::GenerateCurvesNode", "graphene_raster_nodes::generate_curves::GenerateCurvesNode"),
|
||||||
("graphene_core::raster::adjustments::ColorOverlayNode", "graphene_raster_nodes::generate_curves::ColorOverlayNode"),
|
("graphene_std::dehaze::DehazeNode", "graphene_raster_nodes::dehaze::DehazeNode"),
|
||||||
|
("graphene_std::filter::BlurNode", "graphene_raster_nodes::filter::BlurNode"),
|
||||||
|
(
|
||||||
|
"graphene_std::image_color_palette::ImageColorPaletteNode",
|
||||||
|
"graphene_raster_nodes::image_color_palette::ImageColorPaletteNode",
|
||||||
|
),
|
||||||
|
("graphene_std::raster::SampleImageNode", "graphene_raster_nodes::std_nodes::SampleImageNode"),
|
||||||
|
("graphene_std::raster::CombineChannelsNode", "graphene_raster_nodes::std_nodes::CombineChannelsNode"),
|
||||||
|
("graphene_std::raster::MaskNode", "graphene_raster_nodes::std_nodes::MaskNode"),
|
||||||
|
("graphene_std::raster::ExtendImageToBoundsNode", "graphene_raster_nodes::std_nodes::ExtendImageToBoundsNode"),
|
||||||
|
("graphene_std::raster::EmptyImageNode", "graphene_raster_nodes::std_nodes::EmptyImageNode"),
|
||||||
|
("graphene_std::raster::ImageValueNode", "graphene_raster_nodes::std_nodes::ImageValueNode"),
|
||||||
|
("graphene_std::raster::NoisePatternNode", "graphene_raster_nodes::std_nodes::NoisePatternNode"),
|
||||||
|
("graphene_std::raster::MandelbrotNode", "graphene_raster_nodes::std_nodes::MandelbrotNode"),
|
||||||
// text
|
// text
|
||||||
("graphene_core::text::TextGeneratorNode", "graphene_core::text::TextNode"),
|
("graphene_core::text::TextGeneratorNode", "graphene_core::text::TextNode"),
|
||||||
// transform
|
// transform
|
||||||
|
|
|
@ -80,12 +80,12 @@ pub enum ToolMessage {
|
||||||
Redo,
|
Redo,
|
||||||
RefreshToolOptions,
|
RefreshToolOptions,
|
||||||
ResetColors,
|
ResetColors,
|
||||||
SelectPrimaryColor {
|
SelectWorkingColor {
|
||||||
color: Color,
|
color: Color,
|
||||||
|
primary: bool,
|
||||||
},
|
},
|
||||||
SelectRandomPrimaryColor,
|
SelectRandomWorkingColor {
|
||||||
SelectSecondaryColor {
|
primary: bool,
|
||||||
color: Color,
|
|
||||||
},
|
},
|
||||||
SwapColors,
|
SwapColors,
|
||||||
Undo,
|
Undo,
|
||||||
|
|
|
@ -240,14 +240,8 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
|
||||||
|
|
||||||
document_data.update_working_colors(responses); // TODO: Make this an event
|
document_data.update_working_colors(responses); // TODO: Make this an event
|
||||||
}
|
}
|
||||||
ToolMessage::SelectPrimaryColor { color } => {
|
ToolMessage::SelectRandomWorkingColor { primary } => {
|
||||||
let document_data = &mut self.tool_state.document_tool_data;
|
// Select a random working color (RGBA) based on an UUID
|
||||||
document_data.primary_color = color;
|
|
||||||
|
|
||||||
document_data.update_working_colors(responses); // TODO: Make this an event
|
|
||||||
}
|
|
||||||
ToolMessage::SelectRandomPrimaryColor => {
|
|
||||||
// Select a random primary color (rgba) based on an UUID
|
|
||||||
let document_data = &mut self.tool_state.document_tool_data;
|
let document_data = &mut self.tool_state.document_tool_data;
|
||||||
|
|
||||||
let random_number = generate_uuid();
|
let random_number = generate_uuid();
|
||||||
|
@ -255,13 +249,23 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
|
||||||
let g = (random_number >> 8) as u8;
|
let g = (random_number >> 8) as u8;
|
||||||
let b = random_number as u8;
|
let b = random_number as u8;
|
||||||
let random_color = Color::from_rgba8_srgb(r, g, b, 255);
|
let random_color = Color::from_rgba8_srgb(r, g, b, 255);
|
||||||
document_data.primary_color = random_color;
|
|
||||||
|
if primary {
|
||||||
|
document_data.primary_color = random_color;
|
||||||
|
} else {
|
||||||
|
document_data.secondary_color = random_color;
|
||||||
|
}
|
||||||
|
|
||||||
document_data.update_working_colors(responses); // TODO: Make this an event
|
document_data.update_working_colors(responses); // TODO: Make this an event
|
||||||
}
|
}
|
||||||
ToolMessage::SelectSecondaryColor { color } => {
|
ToolMessage::SelectWorkingColor { color, primary } => {
|
||||||
let document_data = &mut self.tool_state.document_tool_data;
|
let document_data = &mut self.tool_state.document_tool_data;
|
||||||
document_data.secondary_color = color;
|
|
||||||
|
if primary {
|
||||||
|
document_data.primary_color = color;
|
||||||
|
} else {
|
||||||
|
document_data.secondary_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
document_data.update_working_colors(responses); // TODO: Make this an event
|
document_data.update_working_colors(responses); // TODO: Make this an event
|
||||||
}
|
}
|
||||||
|
@ -340,7 +344,7 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
|
||||||
|
|
||||||
ActivateToolBrush,
|
ActivateToolBrush,
|
||||||
|
|
||||||
SelectRandomPrimaryColor,
|
SelectRandomWorkingColor,
|
||||||
ResetColors,
|
ResetColors,
|
||||||
SwapColors,
|
SwapColors,
|
||||||
Undo,
|
Undo,
|
||||||
|
|
|
@ -12,10 +12,11 @@ pub enum TransformLayerMessage {
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
ApplyTransformOperation { final_transform: bool },
|
ApplyTransformOperation { final_transform: bool },
|
||||||
|
BeginTransformOperation { operation: TransformType },
|
||||||
BeginGrab,
|
BeginGrab,
|
||||||
BeginRotate,
|
BeginRotate,
|
||||||
BeginScale,
|
BeginScale,
|
||||||
BeginGRS { transform_type: TransformType },
|
BeginGRS { operation: TransformType },
|
||||||
BeginGrabPen { last_point: DVec2, handle: DVec2 },
|
BeginGrabPen { last_point: DVec2, handle: DVec2 },
|
||||||
BeginRotatePen { last_point: DVec2, handle: DVec2 },
|
BeginRotatePen { last_point: DVec2, handle: DVec2 },
|
||||||
BeginScalePen { last_point: DVec2, handle: DVec2 },
|
BeginScalePen { last_point: DVec2, handle: DVec2 },
|
||||||
|
|
|
@ -368,6 +368,15 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
||||||
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TransformLayerMessage::BeginTransformOperation { operation } => {
|
||||||
|
begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse, &mut self.initial_transform);
|
||||||
|
self.transform_operation = match operation {
|
||||||
|
TransformType::Grab => TransformOperation::Grabbing(Default::default()),
|
||||||
|
TransformType::Rotate => TransformOperation::Rotating(Default::default()),
|
||||||
|
TransformType::Scale => TransformOperation::Scaling(Default::default()),
|
||||||
|
};
|
||||||
|
self.layer_bounding_box = selected.bounding_box();
|
||||||
|
}
|
||||||
TransformLayerMessage::BeginGrabPen { last_point, handle } | TransformLayerMessage::BeginRotatePen { last_point, handle } | TransformLayerMessage::BeginScalePen { last_point, handle } => {
|
TransformLayerMessage::BeginGrabPen { last_point, handle } | TransformLayerMessage::BeginRotatePen { last_point, handle } | TransformLayerMessage::BeginScalePen { last_point, handle } => {
|
||||||
self.typing.clear();
|
self.typing.clear();
|
||||||
|
|
||||||
|
@ -402,9 +411,10 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
||||||
increments_key: INCREMENTS_KEY,
|
increments_key: INCREMENTS_KEY,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
TransformLayerMessage::BeginGRS { transform_type } => {
|
TransformLayerMessage::BeginGRS { operation: transform_type } => {
|
||||||
let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect();
|
let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect();
|
||||||
let selected_segments = shape_editor.selected_segments().collect::<Vec<_>>();
|
let selected_segments = shape_editor.selected_segments().collect::<Vec<_>>();
|
||||||
|
|
||||||
if (using_path_tool && selected_points.is_empty() && selected_segments.is_empty())
|
if (using_path_tool && selected_points.is_empty() && selected_segments.is_empty())
|
||||||
|| (!using_path_tool && !using_select_tool && !using_pen_tool && !using_shape_tool)
|
|| (!using_path_tool && !using_select_tool && !using_pen_tool && !using_shape_tool)
|
||||||
|| selected_layers.is_empty()
|
|| selected_layers.is_empty()
|
||||||
|
@ -439,42 +449,24 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.local = false;
|
||||||
|
self.operation_count += 1;
|
||||||
|
|
||||||
let chain_operation = self.transform_operation != TransformOperation::None;
|
let chain_operation = self.transform_operation != TransformOperation::None;
|
||||||
if chain_operation {
|
if chain_operation {
|
||||||
responses.add(TransformLayerMessage::ApplyTransformOperation { final_transform: false });
|
responses.add(TransformLayerMessage::ApplyTransformOperation { final_transform: false });
|
||||||
} else {
|
} else {
|
||||||
responses.add(OverlaysMessage::AddProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::AddProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
||||||
}
|
}
|
||||||
|
responses.add(TransformLayerMessage::BeginTransformOperation { operation: transform_type });
|
||||||
let response = match transform_type {
|
|
||||||
TransformType::Grab => TransformLayerMessage::BeginGrab,
|
|
||||||
TransformType::Rotate => TransformLayerMessage::BeginRotate,
|
|
||||||
TransformType::Scale => TransformLayerMessage::BeginScale,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.local = false;
|
|
||||||
self.operation_count += 1;
|
|
||||||
responses.add(response);
|
|
||||||
responses.add(TransformLayerMessage::PointerMove {
|
responses.add(TransformLayerMessage::PointerMove {
|
||||||
slow_key: SLOW_KEY,
|
slow_key: SLOW_KEY,
|
||||||
increments_key: INCREMENTS_KEY,
|
increments_key: INCREMENTS_KEY,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
TransformLayerMessage::BeginGrab => {
|
TransformLayerMessage::BeginGrab => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Grab }),
|
||||||
begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse, &mut self.initial_transform);
|
TransformLayerMessage::BeginRotate => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Rotate }),
|
||||||
self.transform_operation = TransformOperation::Grabbing(Default::default());
|
TransformLayerMessage::BeginScale => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Scale }),
|
||||||
self.layer_bounding_box = selected.bounding_box();
|
|
||||||
}
|
|
||||||
TransformLayerMessage::BeginRotate => {
|
|
||||||
begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse, &mut self.initial_transform);
|
|
||||||
self.transform_operation = TransformOperation::Rotating(Default::default());
|
|
||||||
self.layer_bounding_box = selected.bounding_box();
|
|
||||||
}
|
|
||||||
TransformLayerMessage::BeginScale => {
|
|
||||||
begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse, &mut self.initial_transform);
|
|
||||||
self.transform_operation = TransformOperation::Scaling(Default::default());
|
|
||||||
self.layer_bounding_box = selected.bounding_box();
|
|
||||||
}
|
|
||||||
TransformLayerMessage::CancelTransformOperation => {
|
TransformLayerMessage::CancelTransformOperation => {
|
||||||
if using_pen_tool {
|
if using_pen_tool {
|
||||||
self.typing.clear();
|
self.typing.clear();
|
||||||
|
@ -707,7 +699,9 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
||||||
|
|
||||||
fn actions(&self) -> ActionList {
|
fn actions(&self) -> ActionList {
|
||||||
let mut common = actions!(TransformLayerMessageDiscriminant;
|
let mut common = actions!(TransformLayerMessageDiscriminant;
|
||||||
BeginGRS,
|
BeginGrab,
|
||||||
|
BeginRotate,
|
||||||
|
BeginScale,
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.transform_operation != TransformOperation::None {
|
if self.transform_operation != TransformOperation::None {
|
||||||
|
|
|
@ -227,11 +227,11 @@ impl EditorTestUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_primary_color(&mut self, color: Color) {
|
pub async fn select_primary_color(&mut self, color: Color) {
|
||||||
self.handle_message(Message::Tool(ToolMessage::SelectPrimaryColor { color })).await;
|
self.handle_message(Message::Tool(ToolMessage::SelectWorkingColor { color, primary: true })).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_secondary_color(&mut self, color: Color) {
|
pub async fn select_secondary_color(&mut self, color: Color) {
|
||||||
self.handle_message(Message::Tool(ToolMessage::SelectSecondaryColor { color })).await;
|
self.handle_message(Message::Tool(ToolMessage::SelectWorkingColor { color, primary: false })).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_raster_image(&mut self, image: graphene_std::raster::Image<Color>, mouse: Option<(f64, f64)>) {
|
pub async fn create_raster_image(&mut self, image: graphene_std::raster::Image<Color>, mouse: Option<(f64, f64)>) {
|
||||||
|
|
|
@ -467,8 +467,9 @@ impl EditorHandle {
|
||||||
return Err(Error::new("Invalid color").into());
|
return Err(Error::new("Invalid color").into());
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = ToolMessage::SelectPrimaryColor {
|
let message = ToolMessage::SelectWorkingColor {
|
||||||
color: primary_color.to_linear_srgb(),
|
color: primary_color.to_linear_srgb(),
|
||||||
|
primary: true,
|
||||||
};
|
};
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|
||||||
|
@ -482,8 +483,9 @@ impl EditorHandle {
|
||||||
return Err(Error::new("Invalid color").into());
|
return Err(Error::new("Invalid color").into());
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = ToolMessage::SelectSecondaryColor {
|
let message = ToolMessage::SelectWorkingColor {
|
||||||
color: secondary_color.to_linear_srgb(),
|
color: secondary_color.to_linear_srgb(),
|
||||||
|
primary: false,
|
||||||
};
|
};
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|
||||||
|
|
|
@ -97,11 +97,20 @@ impl Raster<GPU> {
|
||||||
let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() };
|
let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() };
|
||||||
gpu.clone()
|
gpu.clone()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Raster<GPU> {
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
let data = self.data();
|
let data = self.data();
|
||||||
data.width() == 0 || data.height() == 0
|
data.width() == 0 || data.height() == 0
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "wgpu"))]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
impl Deref for Raster<GPU> {
|
impl Deref for Raster<GPU> {
|
||||||
type Target = wgpu::Texture;
|
type Target = wgpu::Texture;
|
||||||
|
@ -110,6 +119,7 @@ impl Deref for Raster<GPU> {
|
||||||
self.data()
|
self.data()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type RasterDataTable<Storage> = Instances<Raster<Storage>>;
|
pub type RasterDataTable<Storage> = Instances<Raster<Storage>>;
|
||||||
|
|
||||||
// TODO: Make this not dupliated
|
// TODO: Make this not dupliated
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue