Major overhaul of input and communication systems

* Add input manager

* WIP lifetime hell

* Hell yeah, dark lifetime magic

* Replace events with actions in tools

* Fix borrow in GlobalEventHandler

* Fix typo in response-handler

* Distribute dispatch structure

* Add translation from events to actions

* Port default key actions to input_mapper

* Split actions macro

* Add handling for Ambiguous Mouse events

* Fix warnings and clippy lints

* Add actions macro

* WIP rework

* Add AsMessage macro

* Add implementation for derived enums

* Add macro implementation for top level message

* Add #[child] attribute to indicate derivation

* Replace some mentions of Actions and Responses with Message

* It compiles !!!

* Add functionality to some message handlers

* Add document rendering

* ICE

* Rework the previous code while keeping basic functionality

* Reduce parent-top-level macro args to only two

* Add workaround for ICE

* Fix cyclic reference in document.rs

* Make derive_transitive_child a bit more powerful

This addresses the todo that was left,
enabling arbitrary expressions to be passed as the last
parameter of a #[parent] attribute

* Adapt frontend message format

* Make responses use VecDeque

Our responses are a queue so we should use a queue type for them

* Move traits to sensible location

* Are we rectangle yet?

* Simplify, improve & document `derive_discriminant`

* Change `child` to `sub_discriminant`

This only applies to `ToDiscriminant`.
Code using `#[impl_message]` continues to work.

* Add docs for `derive_transitive_child`

* Finish docs and improve macros

The improvements are that impl_message now uses trait
resolution to obtain the parent's discriminant
and that derive_as_message now allows for non-unit
variants (which we don't use but it's nice to have,
just in case)

* Remove logging call

* Move files around and cleanup structure

* Fix proc macro doc tests

* Improve actions_fn!() macro

* Add ellipse tool

* Pass populated actions list to the input mapper

* Add KeyState bitvector

* Merge mouse buttons into "keyboard"

* Add macro for initialization of key mapper table

* Add syntactic sugar for the macro

* Implement mapping function

* Translate the remaining tools

* Fix shape tool

* Add keybindings for line and pen tool

* Fix modifiers

* Cleanup

* Add doc comments for the actions macro

* Fix formatting

* Rename MouseMove to PointerMove

* Add keybinds for tools

* Apply review suggestions

* Rename KeyMappings -> KeyMappingEntries

* Apply review changes

Co-authored-by: T0mstone <realt0mstone@gmail.com>
Co-authored-by: Paul Kupper <kupper.pa@gmail.com>
This commit is contained in:
TrueDoctor
2021-05-23 01:26:24 +02:00
committed by Keavon Chambers
co-authored by T0mstone Paul Kupper
parent c08b2d4b31
commit 4b19a459b7
72 changed files with 3028 additions and 1856 deletions
@@ -0,0 +1,73 @@
use crate::{frontend::FrontendMessageHandler, message_prelude::*, Callback, EditorError};
pub use crate::document::DocumentMessageHandler;
pub use crate::input::{InputMapper, InputPreprocessor};
pub use crate::tool::ToolMessageHandler;
use crate::global::GlobalMessageHandler;
use std::collections::VecDeque;
pub struct Dispatcher {
frontend_message_handler: FrontendMessageHandler,
input_preprocessor: InputPreprocessor,
input_mapper: InputMapper,
global_message_handler: GlobalMessageHandler,
tool_message_handler: ToolMessageHandler,
document_message_handler: DocumentMessageHandler,
messages: VecDeque<Message>,
}
impl Dispatcher {
pub fn handle_message<T: Into<Message>>(&mut self, message: T) -> Result<(), EditorError> {
let message = message.into();
use Message::*;
if !matches!(
message,
Message::InputPreprocessor(_) | Message::InputMapper(_) | Message::Tool(ToolMessage::Rectangle(RectangleMessage::MouseMove))
) {
log::trace!("Message: {}", message.to_discriminant().global_name());
}
match message {
NoOp => (),
Document(message) => self.document_message_handler.process_action(message, (), &mut self.messages),
Global(message) => self.global_message_handler.process_action(message, (), &mut self.messages),
Tool(message) => self
.tool_message_handler
.process_action(message, (&self.document_message_handler.active_document().document, &self.input_preprocessor), &mut self.messages),
Frontend(message) => self.frontend_message_handler.process_action(message, (), &mut self.messages),
InputPreprocessor(message) => self.input_preprocessor.process_action(message, (), &mut self.messages),
InputMapper(message) => {
let actions = self.collect_actions();
self.input_mapper.process_action(message, (&self.input_preprocessor, actions), &mut self.messages)
}
}
if let Some(message) = self.messages.pop_front() {
self.handle_message(message)?;
}
Ok(())
}
pub fn collect_actions(&self) -> ActionList {
//TODO: reduce the number of heap allocations
let mut list = Vec::new();
list.extend(self.frontend_message_handler.actions());
list.extend(self.input_preprocessor.actions());
list.extend(self.input_mapper.actions());
list.extend(self.global_message_handler.actions());
list.extend(self.tool_message_handler.actions());
list.extend(self.document_message_handler.actions());
list
}
pub fn new(callback: Callback) -> Dispatcher {
Dispatcher {
frontend_message_handler: FrontendMessageHandler::new(callback),
input_preprocessor: InputPreprocessor::default(),
global_message_handler: GlobalMessageHandler::new(),
input_mapper: InputMapper::default(),
document_message_handler: DocumentMessageHandler::default(),
tool_message_handler: ToolMessageHandler::default(),
messages: VecDeque::new(),
}
}
}
+30
View File
@@ -0,0 +1,30 @@
use crate::message_prelude::*;
use graphite_proc_macros::*;
pub trait AsMessage: TransitiveChild
where
Self::TopParent: TransitiveChild<Parent = Self::TopParent, TopParent = Self::TopParent> + AsMessage,
{
fn local_name(self) -> String;
fn global_name(self) -> String {
<Self as Into<Self::TopParent>>::into(self).local_name()
}
}
#[impl_message]
#[derive(PartialEq, Clone, Debug)]
pub enum Message {
NoOp,
#[child]
Document(DocumentMessage),
#[child]
Global(GlobalMessage),
#[child]
Tool(ToolMessage),
#[child]
Frontend(FrontendMessage),
#[child]
InputPreprocessor(InputPreprocessorMessage),
#[child]
InputMapper(InputMapperMessage),
}
+23
View File
@@ -0,0 +1,23 @@
pub mod dispatcher;
pub mod message;
use crate::message_prelude::*;
pub use dispatcher::*;
pub use crate::input::InputPreprocessor;
use std::collections::VecDeque;
pub type ActionList = Vec<Vec<MessageDiscriminant>>;
// TODO: Add Send + Sync requirement
// Use something like rw locks for synchronization
pub trait MessageHandlerData {}
pub trait MessageHandler<A: ToDiscriminant, T>
where
A::Discriminant: AsMessage,
<A::Discriminant as TransitiveChild>::TopParent: TransitiveChild<Parent = <A::Discriminant as TransitiveChild>::TopParent, TopParent = <A::Discriminant as TransitiveChild>::TopParent> + AsMessage,
{
/// Return true if the Action is consumed.
fn process_action(&mut self, action: A, data: T, responses: &mut VecDeque<Message>);
fn actions(&self) -> ActionList;
}