mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 19:08:05 +08:00
Massively reorganize and clean up the whole Rust codebase (#478)
* Massively reorganize and clean up the whole Rust codebase * Additional changes during code review
This commit is contained in:
@@ -1,146 +1,38 @@
|
||||
use glam::DVec2;
|
||||
|
||||
use super::{
|
||||
keyboard::{Key, KeyStates, NUMBER_OF_KEYS},
|
||||
InputPreprocessor,
|
||||
};
|
||||
use crate::document::Clipboard::*;
|
||||
use super::keyboard::{Key, KeyStates, NUMBER_OF_KEYS};
|
||||
use crate::document::clipboards::Clipboard;
|
||||
use crate::message_prelude::*;
|
||||
use crate::tool::ToolType;
|
||||
use crate::viewport_tools::tool::ToolType;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Write;
|
||||
use glam::DVec2;
|
||||
|
||||
const NUDGE_AMOUNT: f64 = 1.;
|
||||
const SHIFT_NUDGE_AMOUNT: f64 = 10.;
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, InputMapper)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum InputMapperMessage {
|
||||
#[child]
|
||||
KeyDown(Key),
|
||||
#[child]
|
||||
KeyUp(Key),
|
||||
MouseScroll,
|
||||
PointerMove,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
struct MappingEntry {
|
||||
trigger: InputMapperMessage,
|
||||
modifiers: KeyStates,
|
||||
action: Message,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct KeyMappingEntries(Vec<MappingEntry>);
|
||||
|
||||
impl KeyMappingEntries {
|
||||
fn match_mapping(&self, keys: &KeyStates, actions: ActionList) -> Option<Message> {
|
||||
for entry in self.0.iter() {
|
||||
let all_required_modifiers_pressed = ((*keys & entry.modifiers) ^ entry.modifiers).is_empty();
|
||||
if all_required_modifiers_pressed && actions.iter().flatten().any(|action| entry.action.to_discriminant() == *action) {
|
||||
return Some(entry.action.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn push(&mut self, entry: MappingEntry) {
|
||||
self.0.push(entry)
|
||||
}
|
||||
|
||||
const fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
fn key_array() -> [Self; NUMBER_OF_KEYS] {
|
||||
const DEFAULT: KeyMappingEntries = KeyMappingEntries::new();
|
||||
[DEFAULT; NUMBER_OF_KEYS]
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for KeyMappingEntries {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Mapping {
|
||||
key_up: [KeyMappingEntries; NUMBER_OF_KEYS],
|
||||
key_down: [KeyMappingEntries; NUMBER_OF_KEYS],
|
||||
pointer_move: KeyMappingEntries,
|
||||
mouse_scroll: KeyMappingEntries,
|
||||
}
|
||||
|
||||
macro_rules! modifiers {
|
||||
($($m:ident),*) => {{
|
||||
#[allow(unused_mut)]
|
||||
let mut state = KeyStates::new();
|
||||
$(
|
||||
state.set(Key::$m as usize);
|
||||
)*
|
||||
state
|
||||
}};
|
||||
}
|
||||
macro_rules! entry {
|
||||
{action=$action:expr, key_down=$key:ident $(, modifiers=[$($m:ident),* $(,)?])?} => {{
|
||||
entry!{action=$action, message=InputMapperMessage::KeyDown(Key::$key) $(, modifiers=[$($m),*])?}
|
||||
}};
|
||||
{action=$action:expr, key_up=$key:ident $(, modifiers=[$($m:ident),* $(,)?])?} => {{
|
||||
entry!{action=$action, message=InputMapperMessage::KeyUp(Key::$key) $(, modifiers=[$($m),* ])?}
|
||||
}};
|
||||
{action=$action:expr, message=$message:expr $(, modifiers=[$($m:ident),* $(,)?])?} => {{
|
||||
&[MappingEntry {trigger: $message, modifiers: modifiers!($($($m),*)?), action: $action.into()}]
|
||||
}};
|
||||
{action=$action:expr, triggers=[$($m:ident),* $(,)?]} => {{
|
||||
&[
|
||||
MappingEntry {trigger:InputMapperMessage::PointerMove, action: $action.into(), modifiers: modifiers!()},
|
||||
$(
|
||||
MappingEntry {trigger:InputMapperMessage::KeyDown(Key::$m), action: $action.into(), modifiers: modifiers!()},
|
||||
MappingEntry {trigger:InputMapperMessage::KeyUp(Key::$m), action: $action.into(), modifiers: modifiers!()},
|
||||
)*
|
||||
]
|
||||
}};
|
||||
}
|
||||
macro_rules! mapping {
|
||||
//[$(<action=$action:expr; message=$key:expr; $(modifiers=[$($m:ident),* $(,)?];)?>)*] => {{
|
||||
[$($entry:expr),* $(,)?] => {{
|
||||
let mut key_up = KeyMappingEntries::key_array();
|
||||
let mut key_down = KeyMappingEntries::key_array();
|
||||
let mut pointer_move: KeyMappingEntries = Default::default();
|
||||
let mut mouse_scroll: KeyMappingEntries = Default::default();
|
||||
$(
|
||||
for entry in $entry {
|
||||
let arr = match entry.trigger {
|
||||
InputMapperMessage::KeyDown(key) => &mut key_down[key as usize],
|
||||
InputMapperMessage::KeyUp(key) => &mut key_up[key as usize],
|
||||
InputMapperMessage::MouseScroll => &mut mouse_scroll,
|
||||
InputMapperMessage::PointerMove => &mut pointer_move,
|
||||
};
|
||||
arr.push(entry.clone());
|
||||
}
|
||||
)*
|
||||
(key_up, key_down, pointer_move, mouse_scroll)
|
||||
}};
|
||||
pub struct Mapping {
|
||||
pub key_up: [KeyMappingEntries; NUMBER_OF_KEYS],
|
||||
pub key_down: [KeyMappingEntries; NUMBER_OF_KEYS],
|
||||
pub pointer_move: KeyMappingEntries,
|
||||
pub mouse_scroll: KeyMappingEntries,
|
||||
}
|
||||
|
||||
impl Default for Mapping {
|
||||
fn default() -> Self {
|
||||
use input_mapper_macros::{entry, mapping, modifiers};
|
||||
use Key::*;
|
||||
|
||||
// WARNING!
|
||||
// If a new mapping isn't being handled (and perhaps another lower-precedence one is instead), make sure to advertise
|
||||
// it as an available action in the respective message handler file (such as the bottom of `document_message_handler.rs`)
|
||||
// it as an available action in the respective message handler file (such as the bottom of `document_message_handler.rs`).
|
||||
|
||||
let mappings = mapping![
|
||||
// Higher priority than entries in sections below
|
||||
entry! {action=PortfolioMessage::Paste(User), key_down=KeyV, modifiers=[KeyControl]},
|
||||
entry! {action=PortfolioMessage::Paste(Clipboard::User), key_down=KeyV, modifiers=[KeyControl]},
|
||||
// Transform layers
|
||||
entry! {action=TransformLayerMessage::ApplyOperation, key_down=KeyEnter},
|
||||
entry! {action=TransformLayerMessage::ApplyOperation, key_down=Lmb},
|
||||
entry! {action=TransformLayerMessage::CancelOperation, key_down=KeyEscape},
|
||||
entry! {action=TransformLayerMessage::CancelOperation, key_down=Rmb},
|
||||
entry! {action=TransformLayerMessage::ApplyTransformOperation, key_down=KeyEnter},
|
||||
entry! {action=TransformLayerMessage::ApplyTransformOperation, key_down=Lmb},
|
||||
entry! {action=TransformLayerMessage::CancelTransformOperation, key_down=KeyEscape},
|
||||
entry! {action=TransformLayerMessage::CancelTransformOperation, key_down=Rmb},
|
||||
entry! {action=TransformLayerMessage::ConstrainX, key_down=KeyX},
|
||||
entry! {action=TransformLayerMessage::ConstrainY, key_down=KeyY},
|
||||
entry! {action=TransformLayerMessage::TypeBackspace, key_down=KeyBackspace},
|
||||
@@ -222,7 +114,7 @@ impl Default for Mapping {
|
||||
// Editor Actions
|
||||
entry! {action=FrontendMessage::TriggerFileUpload, key_down=KeyO, modifiers=[KeyControl]},
|
||||
// Document Actions
|
||||
entry! {action=PortfolioMessage::Paste(User), key_down=KeyV, modifiers=[KeyControl]},
|
||||
entry! {action=PortfolioMessage::Paste(Clipboard::User), key_down=KeyV, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::Redo, key_down=KeyZ, modifiers=[KeyControl, KeyShift]},
|
||||
entry! {action=DocumentMessage::Undo, key_down=KeyZ, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::DeselectAllLayers, key_down=KeyA, modifiers=[KeyControl, KeyAlt]},
|
||||
@@ -267,8 +159,8 @@ impl Default for Mapping {
|
||||
entry! {action=PortfolioMessage::CloseAllDocumentsWithConfirmation, key_down=KeyW, modifiers=[KeyControl, KeyAlt]},
|
||||
entry! {action=PortfolioMessage::CloseActiveDocumentWithConfirmation, key_down=KeyW, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::DuplicateSelectedLayers, key_down=KeyD, modifiers=[KeyControl]},
|
||||
entry! {action=PortfolioMessage::Copy(User), key_down=KeyC, modifiers=[KeyControl]},
|
||||
entry! {action=PortfolioMessage::Cut(User), key_down=KeyX, modifiers=[KeyControl]},
|
||||
entry! {action=PortfolioMessage::Copy(Clipboard::User), key_down=KeyC, modifiers=[KeyControl]},
|
||||
entry! {action=PortfolioMessage::Cut(Clipboard::User), key_down=KeyX, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::GroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::UngroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl, KeyShift]},
|
||||
// Nudging
|
||||
@@ -337,7 +229,7 @@ impl Default for Mapping {
|
||||
}
|
||||
|
||||
impl Mapping {
|
||||
fn match_message(&self, message: InputMapperMessage, keys: &KeyStates, actions: ActionList) -> Option<Message> {
|
||||
pub fn match_message(&self, message: InputMapperMessage, keys: &KeyStates, actions: ActionList) -> Option<Message> {
|
||||
use InputMapperMessage::*;
|
||||
let list = match message {
|
||||
KeyDown(key) => &self.key_down[key as usize],
|
||||
@@ -349,40 +241,103 @@ impl Mapping {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct InputMapper {
|
||||
mapping: Mapping,
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub struct MappingEntry {
|
||||
pub trigger: InputMapperMessage,
|
||||
pub modifiers: KeyStates,
|
||||
pub action: Message,
|
||||
}
|
||||
|
||||
impl InputMapper {
|
||||
pub fn hints(&self, actions: ActionList) -> String {
|
||||
let mut output = String::new();
|
||||
let mut actions = actions
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|a| !matches!(*a, MessageDiscriminant::Tool(ToolMessageDiscriminant::ActivateTool) | MessageDiscriminant::Global(_)));
|
||||
self.mapping
|
||||
.key_down
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, m)| {
|
||||
let ma = m.0.iter().find_map(|m| actions.find_map(|a| (a == m.action.to_discriminant()).then(|| m.action.to_discriminant())));
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyMappingEntries(pub Vec<MappingEntry>);
|
||||
|
||||
ma.map(|a| unsafe { (std::mem::transmute_copy::<usize, Key>(&i), a) })
|
||||
})
|
||||
.for_each(|(k, a)| {
|
||||
let _ = write!(output, "{}: {}, ", k.to_discriminant().local_name(), a.local_name().split('.').last().unwrap());
|
||||
});
|
||||
output.replace("Key", "")
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageHandler<InputMapperMessage, (&InputPreprocessor, ActionList)> for InputMapper {
|
||||
fn process_action(&mut self, message: InputMapperMessage, data: (&InputPreprocessor, ActionList), responses: &mut VecDeque<Message>) {
|
||||
let (input, actions) = data;
|
||||
if let Some(message) = self.mapping.match_message(message, &input.keyboard, actions) {
|
||||
responses.push_back(message);
|
||||
impl KeyMappingEntries {
|
||||
fn match_mapping(&self, keys: &KeyStates, actions: ActionList) -> Option<Message> {
|
||||
for entry in self.0.iter() {
|
||||
let all_required_modifiers_pressed = ((*keys & entry.modifiers) ^ entry.modifiers).is_empty();
|
||||
if all_required_modifiers_pressed && actions.iter().flatten().any(|action| entry.action.to_discriminant() == *action) {
|
||||
return Some(entry.action.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn push(&mut self, entry: MappingEntry) {
|
||||
self.0.push(entry)
|
||||
}
|
||||
|
||||
const fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
fn key_array() -> [Self; NUMBER_OF_KEYS] {
|
||||
const DEFAULT: KeyMappingEntries = KeyMappingEntries::new();
|
||||
[DEFAULT; NUMBER_OF_KEYS]
|
||||
}
|
||||
advertise_actions!();
|
||||
}
|
||||
|
||||
impl Default for KeyMappingEntries {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
mod input_mapper_macros {
|
||||
macro_rules! modifiers {
|
||||
($($m:ident),*) => {{
|
||||
#[allow(unused_mut)]
|
||||
let mut state = KeyStates::new();
|
||||
$(
|
||||
state.set(Key::$m as usize);
|
||||
)*
|
||||
state
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! entry {
|
||||
{action=$action:expr, key_down=$key:ident $(, modifiers=[$($m:ident),* $(,)?])?} => {{
|
||||
entry!{action=$action, message=InputMapperMessage::KeyDown(Key::$key) $(, modifiers=[$($m),*])?}
|
||||
}};
|
||||
{action=$action:expr, key_up=$key:ident $(, modifiers=[$($m:ident),* $(,)?])?} => {{
|
||||
entry!{action=$action, message=InputMapperMessage::KeyUp(Key::$key) $(, modifiers=[$($m),* ])?}
|
||||
}};
|
||||
{action=$action:expr, message=$message:expr $(, modifiers=[$($m:ident),* $(,)?])?} => {{
|
||||
&[MappingEntry {trigger: $message, modifiers: modifiers!($($($m),*)?), action: $action.into()}]
|
||||
}};
|
||||
{action=$action:expr, triggers=[$($m:ident),* $(,)?]} => {{
|
||||
&[
|
||||
MappingEntry {trigger:InputMapperMessage::PointerMove, action: $action.into(), modifiers: modifiers!()},
|
||||
$(
|
||||
MappingEntry {trigger:InputMapperMessage::KeyDown(Key::$m), action: $action.into(), modifiers: modifiers!()},
|
||||
MappingEntry {trigger:InputMapperMessage::KeyUp(Key::$m), action: $action.into(), modifiers: modifiers!()},
|
||||
)*
|
||||
]
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! mapping {
|
||||
//[$(<action=$action:expr; message=$key:expr; $(modifiers=[$($m:ident),* $(,)?];)?>)*] => {{
|
||||
[$($entry:expr),* $(,)?] => {{
|
||||
let mut key_up = KeyMappingEntries::key_array();
|
||||
let mut key_down = KeyMappingEntries::key_array();
|
||||
let mut pointer_move: KeyMappingEntries = Default::default();
|
||||
let mut mouse_scroll: KeyMappingEntries = Default::default();
|
||||
$(
|
||||
for entry in $entry {
|
||||
let arr = match entry.trigger {
|
||||
InputMapperMessage::KeyDown(key) => &mut key_down[key as usize],
|
||||
InputMapperMessage::KeyUp(key) => &mut key_up[key as usize],
|
||||
InputMapperMessage::MouseScroll => &mut mouse_scroll,
|
||||
InputMapperMessage::PointerMove => &mut pointer_move,
|
||||
};
|
||||
arr.push(entry.clone());
|
||||
}
|
||||
)*
|
||||
(key_up, key_down, pointer_move, mouse_scroll)
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use entry;
|
||||
pub(crate) use mapping;
|
||||
pub(crate) use modifiers;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user