Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement anchor and handle point rendering with the Path Tool #353

Merged
merged 27 commits into from
Aug 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4ec496b
Implement Path Tool
otdavies Aug 21, 2021
643b806
Draw a red rectangle where the first point on the shape is
otdavies Aug 21, 2021
ac60ff3
Correctly render anchors, handles, and connecting lines
Keavon Aug 23, 2021
925425e
Fix drain() which can panic
Keavon Aug 23, 2021
16ffcfc
Refactor frontend messages to work as return values not callbacks
Keavon Aug 23, 2021
9f11043
Reduce the number of unnecessary frontend updates
TrueDoctor Aug 23, 2021
b5c905c
Fix stack overflow by using a loop
TrueDoctor Aug 23, 2021
b7c1e09
Group Document Render calls and put them at the end
TrueDoctor Aug 23, 2021
c34e79b
Speed hacks for dirtification
TrueDoctor Aug 23, 2021
3e58f78
Add performance
TrueDoctor Aug 23, 2021
1e41c12
Bunch folder changed updates
TrueDoctor Aug 24, 2021
96eb5ee
Add triggers to redraw overlays to movement_handler
TrueDoctor Aug 24, 2021
f0e8d34
Polish the pixel-perfect rendering of vector manipulators
Keavon Aug 24, 2021
2482794
Restore scrollbars that were disabled
Keavon Aug 24, 2021
459e935
Cleanup
Keavon Aug 24, 2021
0fb41f4
Merge remote-tracking branch 'origin' into path-tool
Keavon Aug 24, 2021
116c797
WIP Add shape outline rendering
otdavies Aug 25, 2021
b579376
Fix compiling
Keavon Aug 25, 2021
44d70f9
Add outlines to selected shapes
otdavies Aug 25, 2021
8442d85
Fix outlines rendering over handles and anchors
otdavies Aug 25, 2021
c460b73
Fix dirtification
TrueDoctor Aug 25, 2021
cd07c98
Add a comment
Keavon Aug 26, 2021
07a399d
Merge branch 'master' into path-tool
Keavon Aug 28, 2021
87da14f
Address code review feedback
Keavon Aug 28, 2021
864ca40
Merge branch 'master' into path-tool
Keavon Aug 29, 2021
cd64100
Formatting
Keavon Aug 29, 2021
ebd373a
Small tweaks
Keavon Aug 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ members = [
]

[profile.release.package.graphite-wasm]
opt-level = "s"
opt-level = 3

[profile.dev.package.graphite-wasm]
opt-level = 3

[profile.dev]
opt-level = 3
3 changes: 3 additions & 0 deletions editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ graphite-proc-macros = { path = "../proc-macros" }
glam = { version="0.17", features = ["serde"] }
rand_chacha = "0.3.1"
spin = "0.9.2"
kurbo = { git = "https://github.com/GraphiteEditor/kurbo.git", features = [
"serde",
] }

[dependencies.graphene]
path = "../graphene"
Expand Down
85 changes: 46 additions & 39 deletions editor/src/communication/dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{frontend::FrontendMessageHandler, message_prelude::*, Callback, EditorError};
use crate::{message_prelude::*, EditorError};

pub use crate::document::DocumentsMessageHandler;
pub use crate::input::{InputMapper, InputPreprocessor};
Expand All @@ -8,57 +8,54 @@ 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,
documents_message_handler: DocumentsMessageHandler,
messages: VecDeque<Message>,
pub responses: Vec<FrontendMessage>,
}

const GROUP_MESSAGES: &[MessageDiscriminant] = &[
MessageDiscriminant::Documents(DocumentsMessageDiscriminant::Document(DocumentMessageDiscriminant::RenderDocument)),
MessageDiscriminant::Documents(DocumentsMessageDiscriminant::Document(DocumentMessageDiscriminant::FolderChanged)),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateLayer),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::ExpandFolder),
MessageDiscriminant::Tool(ToolMessageDiscriminant::SelectedLayersChanged),
];

impl Dispatcher {
pub fn handle_message<T: Into<Message>>(&mut self, message: T) -> Result<(), EditorError> {
let message = message.into();
self.messages.push_back(message.into());

use Message::*;
if !(matches!(
message,
Message::InputPreprocessor(_)
| Message::InputMapper(_)
| Message::Documents(DocumentsMessage::Document(DocumentMessage::RenderDocument))
| Message::Frontend(FrontendMessage::UpdateCanvas { .. })
| Message::Frontend(FrontendMessage::UpdateScrollbars { .. })
| Message::Frontend(FrontendMessage::SetCanvasZoom { .. })
| Message::Frontend(FrontendMessage::SetCanvasRotation { .. })
) || MessageDiscriminant::from(&message).local_name().ends_with("MouseMove"))
{
log::trace!("Message: {:?}", message);
//log::trace!("Hints:{:?}", self.input_mapper.hints(self.collect_actions()));
}
match message {
NoOp => (),
Documents(message) => self.documents_message_handler.process_action(message, &self.input_preprocessor, &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.documents_message_handler.active_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)
while let Some(message) = self.messages.pop_front() {
if GROUP_MESSAGES.contains(&message.to_discriminant()) && self.messages.contains(&message) {
continue;
}
log_message(&message);
match message {
NoOp => (),
Documents(message) => self.documents_message_handler.process_action(message, &self.input_preprocessor, &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.documents_message_handler.active_document(), &self.input_preprocessor), &mut self.messages),
Frontend(message) => self.responses.push(message),
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());
Expand All @@ -67,24 +64,36 @@ impl Dispatcher {
list
}

pub fn new(callback: Callback) -> Dispatcher {
pub fn new() -> Dispatcher {
Dispatcher {
frontend_message_handler: FrontendMessageHandler::new(callback),
input_preprocessor: InputPreprocessor::default(),
global_message_handler: GlobalMessageHandler::new(),
input_mapper: InputMapper::default(),
documents_message_handler: DocumentsMessageHandler::default(),
tool_message_handler: ToolMessageHandler::default(),
messages: VecDeque::new(),
responses: vec![],
}
}
}

fn log_message(message: &Message) {
use Message::*;
if log::max_level() == log::LevelFilter::Trace
&& !(matches!(
message,
InputPreprocessor(_) | Frontend(FrontendMessage::SetCanvasZoom { .. }) | Frontend(FrontendMessage::SetCanvasRotation { .. })
) || MessageDiscriminant::from(message).local_name().ends_with("MouseMove"))
{
log::trace!("Message: {:?}", message);
//log::trace!("Hints:{:?}", self.input_mapper.hints(self.collect_actions()));
}
}

#[cfg(test)]
mod test {
use crate::{document::DocumentMessageHandler, message_prelude::*, misc::test_utils::EditorTestUtils, Editor};
use graphene::{color::Color, Operation};
use log::info;

fn init_logger() {
let _ = env_logger::builder().is_test(true).try_init();
Expand All @@ -95,9 +104,7 @@ mod test {
/// 2. A blue shape
/// 3. A green ellipse
fn create_editor_with_three_layers() -> Editor {
let mut editor = Editor::new(Box::new(|e| {
info!("Got frontend message: {:?}", e);
}));
let mut editor = Editor::new();

editor.select_primary_color(Color::RED);
editor.draw_rect(100., 200., 300., 400.);
Expand Down
3 changes: 2 additions & 1 deletion editor/src/communication/message.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::message_prelude::*;
use graphite_proc_macros::*;
use serde::{Deserialize, Serialize};
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
Expand All @@ -16,7 +17,7 @@ where
}

#[impl_message]
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Message {
NoOp,
#[child]
Expand Down
14 changes: 11 additions & 3 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use graphene::color::Color;

// VIEWPORT
pub const VIEWPORT_ZOOM_WHEEL_RATE: f64 = 1. / 600.;
pub const VIEWPORT_ZOOM_MOUSE_RATE: f64 = 1. / 400.;
Expand All @@ -13,12 +15,15 @@ pub const VIEWPORT_SCROLL_RATE: f64 = 0.6;

pub const VIEWPORT_ROTATE_SNAP_INTERVAL: f64 = 15.;

// SELECT TOOL
pub const SELECTION_TOLERANCE: f64 = 1.;

// PATH TOOL
pub const VECTOR_MANIPULATOR_ANCHOR_MARKER_SIZE: f64 = 5.;

// LINE TOOL
pub const LINE_ROTATE_SNAP_ANGLE: f64 = 15.;

// SELECT TOOL
pub const SELECTION_TOLERANCE: f64 = 1.0;

// SCROLLBARS
pub const SCROLLBAR_SPACING: f64 = 0.1;
pub const ASYMPTOTIC_EFFECT: f64 = 0.5;
Expand All @@ -27,3 +32,6 @@ pub const SCALE_EFFECT: f64 = 0.5;
pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
pub const FILE_EXPORT_SUFFIX: &str = ".svg";

// COLORS
pub const COLOR_ACCENT: Color = Color::from_unsafe(0x00 as f32 / 255., 0xA8 as f32 / 255., 0xFF as f32 / 255.);
Loading