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:
Keavon Chambers
2022-01-14 14:58:08 -08:00
parent f63424b676
commit 40d5960571
85 changed files with 2515 additions and 2189 deletions

View File

@@ -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;
}

View File

@@ -0,0 +1,16 @@
use super::keyboard::Key;
use crate::message_prelude::*;
use serde::{Deserialize, Serialize};
#[remain::sorted]
#[impl_message(Message, InputMapper)]
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
pub enum InputMapperMessage {
#[child]
KeyDown(Key),
#[child]
KeyUp(Key),
MouseScroll,
PointerMove,
}

View File

@@ -0,0 +1,44 @@
use super::input_mapper::Mapping;
use super::keyboard::Key;
use super::InputPreprocessorMessageHandler;
use crate::message_prelude::*;
use std::fmt::Write;
#[derive(Debug, Default)]
pub struct InputMapperMessageHandler {
mapping: Mapping,
}
impl InputMapperMessageHandler {
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())));
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, (&InputPreprocessorMessageHandler, ActionList)> for InputMapperMessageHandler {
fn process_action(&mut self, message: InputMapperMessage, data: (&InputPreprocessorMessageHandler, 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);
}
}
advertise_actions!();
}

View File

@@ -1,25 +1,12 @@
use std::usize;
use super::keyboard::{Key, KeyStates};
use super::mouse::{EditorMouseState, MouseKeys, MouseState, ViewportBounds};
use crate::message_prelude::*;
use bitflags::bitflags;
#[doc(inline)]
pub use graphene::DocumentResponse;
use bitflags::bitflags;
use serde::{Deserialize, Serialize};
#[remain::sorted]
#[impl_message(Message, InputPreprocessor)]
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum InputPreprocessorMessage {
BoundsOfViewports(Vec<ViewportBounds>),
KeyDown(Key, ModifierKeys),
KeyUp(Key, ModifierKeys),
MouseDown(EditorMouseState, ModifierKeys),
MouseMove(EditorMouseState, ModifierKeys),
MouseScroll(EditorMouseState, ModifierKeys),
MouseUp(EditorMouseState, ModifierKeys),
pub enum KeyPosition {
Pressed,
Released,
}
bitflags! {
@@ -32,167 +19,20 @@ bitflags! {
}
}
#[derive(Debug, Default)]
pub struct InputPreprocessor {
pub keyboard: KeyStates,
pub mouse: MouseState,
pub viewport_bounds: ViewportBounds,
}
enum KeyPosition {
Pressed,
Released,
}
impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessor {
#[remain::check]
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
#[remain::sorted]
match message {
InputPreprocessorMessage::BoundsOfViewports(bounds_of_viewports) => {
assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported");
for bounds in bounds_of_viewports {
let new_size = bounds.size();
let existing_size = self.viewport_bounds.size();
let translation = (new_size - existing_size) / 2.;
// TODO: Extend this to multiple viewports instead of setting it to the value of this last loop iteration
self.viewport_bounds = bounds;
responses.push_back(
graphene::Operation::TransformLayer {
path: vec![],
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
}
.into(),
);
responses.push_back(
DocumentMessage::Overlay(
graphene::Operation::TransformLayer {
path: vec![],
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
}
.into(),
)
.into(),
);
responses.push_back(
DocumentMessage::Artboard(
graphene::Operation::TransformLayer {
path: vec![],
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
}
.into(),
)
.into(),
);
}
}
InputPreprocessorMessage::KeyDown(key, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.keyboard.set(key as usize);
responses.push_back(InputMapperMessage::KeyDown(key).into());
}
InputPreprocessorMessage::KeyUp(key, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.keyboard.unset(key as usize);
responses.push_back(InputMapperMessage::KeyUp(key).into());
}
InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Pressed) {
responses.push_back(message);
}
}
InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
responses.push_back(InputMapperMessage::PointerMove.into());
}
InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
self.mouse.scroll_delta = mouse_state.scroll_delta;
responses.push_back(InputMapperMessage::MouseScroll.into());
}
InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Released) {
responses.push_back(message);
}
}
};
}
// clean user input and if possible reconstruct it
// store the changes in the keyboard if it is a key event
// transform canvas coordinates to document coordinates
advertise_actions!();
}
impl InputPreprocessor {
fn translate_mouse_event(&mut self, new_state: MouseState, position: KeyPosition) -> Option<Message> {
// Calculate the difference between the two key states (binary xor)
let diff = self.mouse.mouse_keys ^ new_state.mouse_keys;
self.mouse = new_state;
let key = match diff {
MouseKeys::LEFT => Key::Lmb,
MouseKeys::RIGHT => Key::Rmb,
MouseKeys::MIDDLE => Key::Mmb,
MouseKeys::NONE => return None, // self.mouse.mouse_keys was invalid, e.g. when a drag began outside the client
_ => {
log::warn!("The number of buttons modified at the same time was greater than 1. Modification: {:#010b}", diff);
Key::UnknownKey
}
};
Some(match position {
KeyPosition::Pressed => InputMapperMessage::KeyDown(key).into(),
KeyPosition::Released => InputMapperMessage::KeyUp(key).into(),
})
}
fn handle_modifier_keys(&mut self, modifier_keys: ModifierKeys, responses: &mut VecDeque<Message>) {
self.handle_modifier_key(Key::KeyControl, modifier_keys.contains(ModifierKeys::CONTROL), responses);
self.handle_modifier_key(Key::KeyShift, modifier_keys.contains(ModifierKeys::SHIFT), responses);
self.handle_modifier_key(Key::KeyAlt, modifier_keys.contains(ModifierKeys::ALT), responses);
}
fn handle_modifier_key(&mut self, key: Key, key_is_down: bool, responses: &mut VecDeque<Message>) {
let key_was_down = self.keyboard.get(key as usize);
if key_was_down && !key_is_down {
self.keyboard.unset(key as usize);
responses.push_back(InputMapperMessage::KeyUp(key).into());
} else if !key_was_down && key_is_down {
self.keyboard.set(key as usize);
responses.push_back(InputMapperMessage::KeyDown(key).into());
}
}
}
#[cfg(test)]
mod test {
use crate::input::mouse::ViewportPosition;
use crate::input::input_preprocessor::ModifierKeys;
use crate::input::keyboard::Key;
use crate::input::mouse::{EditorMouseState, ViewportPosition};
use crate::input::InputPreprocessorMessageHandler;
use crate::message_prelude::MessageHandler;
use crate::message_prelude::*;
use super::*;
use std::collections::VecDeque;
#[test]
fn process_action_mouse_move_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let mut editor_mouse_state = EditorMouseState::new();
editor_mouse_state.editor_position = ViewportPosition::new(4., 809.);
let message = InputPreprocessorMessage::MouseMove(editor_mouse_state, ModifierKeys::ALT);
@@ -206,7 +46,7 @@ mod test {
#[test]
fn process_action_mouse_down_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let message = InputPreprocessorMessage::MouseDown(EditorMouseState::new(), ModifierKeys::CONTROL);
let mut responses = VecDeque::new();
@@ -218,7 +58,7 @@ mod test {
#[test]
fn process_action_mouse_up_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let message = InputPreprocessorMessage::MouseUp(EditorMouseState::new(), ModifierKeys::SHIFT);
let mut responses = VecDeque::new();
@@ -230,7 +70,7 @@ mod test {
#[test]
fn process_action_key_down_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
input_preprocessor.keyboard.set(Key::KeyControl as usize);
let message = InputPreprocessorMessage::KeyDown(Key::KeyA, ModifierKeys::empty());
let mut responses = VecDeque::new();
@@ -243,7 +83,7 @@ mod test {
#[test]
fn process_action_key_up_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let message = InputPreprocessorMessage::KeyUp(Key::KeyS, ModifierKeys::CONTROL | ModifierKeys::SHIFT);
let mut responses = VecDeque::new();

View File

@@ -0,0 +1,22 @@
use super::input_preprocessor::ModifierKeys;
use super::keyboard::Key;
use super::mouse::{EditorMouseState, ViewportBounds};
use crate::message_prelude::*;
#[doc(inline)]
pub use graphene::DocumentResponse;
use serde::{Deserialize, Serialize};
#[remain::sorted]
#[impl_message(Message, InputPreprocessor)]
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum InputPreprocessorMessage {
BoundsOfViewports(Vec<ViewportBounds>),
KeyDown(Key, ModifierKeys),
KeyUp(Key, ModifierKeys),
MouseDown(EditorMouseState, ModifierKeys),
MouseMove(EditorMouseState, ModifierKeys),
MouseScroll(EditorMouseState, ModifierKeys),
MouseUp(EditorMouseState, ModifierKeys),
}

View File

@@ -0,0 +1,159 @@
use super::input_preprocessor::{KeyPosition, ModifierKeys};
use super::keyboard::{Key, KeyStates};
use super::mouse::{MouseKeys, MouseState, ViewportBounds};
use crate::message_prelude::*;
#[doc(inline)]
pub use graphene::DocumentResponse;
#[derive(Debug, Default)]
pub struct InputPreprocessorMessageHandler {
pub keyboard: KeyStates,
pub mouse: MouseState,
pub viewport_bounds: ViewportBounds,
}
impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHandler {
#[remain::check]
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
#[remain::sorted]
match message {
InputPreprocessorMessage::BoundsOfViewports(bounds_of_viewports) => {
assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported");
for bounds in bounds_of_viewports {
let new_size = bounds.size();
let existing_size = self.viewport_bounds.size();
let translation = (new_size - existing_size) / 2.;
// TODO: Extend this to multiple viewports instead of setting it to the value of this last loop iteration
self.viewport_bounds = bounds;
responses.push_back(
graphene::Operation::TransformLayer {
path: vec![],
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
}
.into(),
);
responses.push_back(
DocumentMessage::Overlays(
graphene::Operation::TransformLayer {
path: vec![],
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
}
.into(),
)
.into(),
);
responses.push_back(
DocumentMessage::Artboard(
graphene::Operation::TransformLayer {
path: vec![],
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
}
.into(),
)
.into(),
);
}
}
InputPreprocessorMessage::KeyDown(key, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.keyboard.set(key as usize);
responses.push_back(InputMapperMessage::KeyDown(key).into());
}
InputPreprocessorMessage::KeyUp(key, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.keyboard.unset(key as usize);
responses.push_back(InputMapperMessage::KeyUp(key).into());
}
InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Pressed) {
responses.push_back(message);
}
}
InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
responses.push_back(InputMapperMessage::PointerMove.into());
}
InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
self.mouse.scroll_delta = mouse_state.scroll_delta;
responses.push_back(InputMapperMessage::MouseScroll.into());
}
InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
self.mouse.position = mouse_state.position;
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Released) {
responses.push_back(message);
}
}
};
}
// Clean user input and if possible reconstruct it.
// Store the changes in the keyboard if it is a key event.
// Transform canvas coordinates to document coordinates.
advertise_actions!();
}
impl InputPreprocessorMessageHandler {
fn translate_mouse_event(&mut self, new_state: MouseState, position: KeyPosition) -> Option<Message> {
// Calculate the difference between the two key states (binary xor)
let difference = self.mouse.mouse_keys ^ new_state.mouse_keys;
self.mouse = new_state;
let key = match difference {
MouseKeys::LEFT => Key::Lmb,
MouseKeys::RIGHT => Key::Rmb,
MouseKeys::MIDDLE => Key::Mmb,
MouseKeys::NONE => return None, // self.mouse.mouse_keys was invalid, e.g. when a drag began outside the client
_ => {
log::warn!("The number of buttons modified at the same time was greater than 1. Modification: {:#010b}", difference);
Key::UnknownKey
}
};
Some(match position {
KeyPosition::Pressed => InputMapperMessage::KeyDown(key).into(),
KeyPosition::Released => InputMapperMessage::KeyUp(key).into(),
})
}
fn handle_modifier_keys(&mut self, modifier_keys: ModifierKeys, responses: &mut VecDeque<Message>) {
self.handle_modifier_key(Key::KeyControl, modifier_keys.contains(ModifierKeys::CONTROL), responses);
self.handle_modifier_key(Key::KeyShift, modifier_keys.contains(ModifierKeys::SHIFT), responses);
self.handle_modifier_key(Key::KeyAlt, modifier_keys.contains(ModifierKeys::ALT), responses);
}
fn handle_modifier_key(&mut self, key: Key, key_is_down: bool, responses: &mut VecDeque<Message>) {
let key_was_down = self.keyboard.get(key as usize);
if key_was_down && !key_is_down {
self.keyboard.unset(key as usize);
responses.push_back(InputMapperMessage::KeyUp(key).into());
} else if !key_was_down && key_is_down {
self.keyboard.set(key as usize);
responses.push_back(InputMapperMessage::KeyDown(key).into());
}
}
}

View File

@@ -1,15 +1,18 @@
use crate::message_prelude::*;
use serde::{Deserialize, Serialize};
pub const NUMBER_OF_KEYS: usize = Key::NumKeys as usize;
// Edit this to specify the storage type used
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign};
// TODO: Increase size of type
/// Edit this to specify the storage type used.
pub type StorageType = u128;
// base 2 logarithm of the storage type used to represents how many bits you need to fully address every bit in that storage type
// Base-2 logarithm of the storage type used to represents how many bits you need to fully address every bit in that storage type
const STORAGE_SIZE: u32 = (std::mem::size_of::<StorageType>() * 8).trailing_zeros();
const STORAGE_SIZE_BITS: usize = 1 << STORAGE_SIZE;
const KEY_MASK_STORAGE_LENGTH: usize = (NUMBER_OF_KEYS + STORAGE_SIZE_BITS - 1) >> STORAGE_SIZE;
pub type KeyStates = BitVector<KEY_MASK_STORAGE_LENGTH>;
#[impl_message(Message, InputMapperMessage, KeyDown)]
@@ -84,10 +87,12 @@ pub enum Key {
KeyComma,
KeyPeriod,
// This has to be the last element in the enum.
// This has to be the last element in the enum
NumKeys,
}
pub const NUMBER_OF_KEYS: usize = Key::NumKeys as usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MouseMotion {
None,
@@ -105,12 +110,6 @@ pub enum MouseMotion {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BitVector<const LENGTH: usize>([StorageType; LENGTH]);
use std::{
fmt::{Display, Formatter},
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign},
usize,
};
impl<const LENGTH: usize> BitVector<LENGTH> {
#[inline]
fn convert_index(bitvector_index: usize) -> (usize, StorageType) {
@@ -118,37 +117,48 @@ impl<const LENGTH: usize> BitVector<LENGTH> {
let offset = bitvector_index >> STORAGE_SIZE;
(offset, bit)
}
pub const fn new() -> Self {
Self([0; LENGTH])
}
pub fn set(&mut self, bitvector_index: usize) {
let (offset, bit) = Self::convert_index(bitvector_index);
self.0[offset] |= bit;
}
pub fn unset(&mut self, bitvector_index: usize) {
let (offset, bit) = Self::convert_index(bitvector_index);
self.0[offset] &= !bit;
}
pub fn toggle(&mut self, bitvector_index: usize) {
let (offset, bit) = Self::convert_index(bitvector_index);
self.0[offset] ^= bit;
}
pub fn get(&self, bitvector_index: usize) -> bool {
let (offset, bit) = Self::convert_index(bitvector_index);
(self.0[offset] & bit) != 0
}
pub fn is_empty(&self) -> bool {
let mut result = 0;
for storage in self.0.iter() {
result |= storage;
}
result == 0
}
pub fn ones(&self) -> u32 {
let mut result = 0;
for storage in self.0.iter() {
result += storage.count_ones();
}
result
}
}
@@ -164,6 +174,7 @@ impl<const LENGTH: usize> Display for BitVector<LENGTH> {
for storage in self.0.iter().rev() {
write!(f, "{:0width$b}", storage, width = STORAGE_SIZE_BITS)?;
}
Ok(())
}
}
@@ -181,6 +192,7 @@ macro_rules! bit_ops {
result
}
}
impl<const LENGTH: usize> $op for &BitVector<LENGTH> {
type Output = BitVector<LENGTH>;
fn $func(self, right: Self) -> Self::Output {

View File

@@ -3,7 +3,17 @@ pub mod input_preprocessor;
pub mod keyboard;
pub mod mouse;
pub use {
input_mapper::{InputMapper, InputMapperMessage, InputMapperMessageDiscriminant},
input_preprocessor::{InputPreprocessor, InputPreprocessorMessage, InputPreprocessorMessageDiscriminant, ModifierKeys},
};
mod input_mapper_message;
mod input_mapper_message_handler;
mod input_preprocessor_message;
mod input_preprocessor_message_handler;
#[doc(inline)]
pub use input_mapper_message::{InputMapperMessage, InputMapperMessageDiscriminant};
#[doc(inline)]
pub use input_mapper_message_handler::InputMapperMessageHandler;
#[doc(inline)]
pub use input_preprocessor_message::{InputPreprocessorMessage, InputPreprocessorMessageDiscriminant};
#[doc(inline)]
pub use input_preprocessor_message_handler::InputPreprocessorMessageHandler;

View File

@@ -36,13 +36,16 @@ pub struct ScrollDelta {
pub y: i32,
pub z: i32,
}
impl ScrollDelta {
pub fn new(x: i32, y: i32, z: i32) -> ScrollDelta {
ScrollDelta { x, y, z }
}
pub fn as_dvec2(&self) -> DVec2 {
DVec2::new(self.x as f64, self.y as f64)
}
pub fn scroll_delta(&self) -> f64 {
let (dx, dy) = (self.x, self.y);
dy.signum() as f64 * ((dy * dy + i32::min(dy.abs(), dx.abs()).pow(2)) as f64).sqrt()
@@ -70,7 +73,8 @@ impl MouseState {
}
pub fn from_keys_and_editor_position(keys: u8, position: ViewportPosition) -> Self {
let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys");
let mouse_keys = MouseKeys::from_bits(keys).expect("Invalid modifier keys");
Self {
position,
mouse_keys,
@@ -100,7 +104,8 @@ impl EditorMouseState {
}
pub fn from_keys_and_editor_position(keys: u8, editor_position: EditorPosition) -> Self {
let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys");
let mouse_keys = MouseKeys::from_bits(keys).expect("Invalid modifier keys");
Self {
editor_position,
mouse_keys,