mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 04:58:13 +08:00
Refactor font loading from per-document to the portfolio (#659)
* Cleanup default font loading * Refactor fonts * Fix menulist mouse navigation * Format * Formatting * Move default font into consts.rs Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
committed by
Keavon Chambers
co-authored by
Keavon Chambers
parent
d4539bc304
commit
8923b68e30
@@ -6,28 +6,20 @@ use crate::layout::widgets::{IconButton, LayoutRow, PropertyHolder, Separator, S
|
||||
use crate::message_prelude::*;
|
||||
|
||||
use graphene::color::Color;
|
||||
use graphene::layers::text_layer::FontCache;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
pub type ToolActionHandlerData<'a> = (&'a DocumentMessageHandler, &'a DocumentToolData, &'a InputPreprocessorMessageHandler);
|
||||
pub type ToolActionHandlerData<'a> = (&'a DocumentMessageHandler, &'a DocumentToolData, &'a InputPreprocessorMessageHandler, &'a FontCache);
|
||||
|
||||
pub trait Fsm {
|
||||
type ToolData;
|
||||
type ToolOptions;
|
||||
|
||||
#[must_use]
|
||||
fn transition(
|
||||
self,
|
||||
message: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
messages: &mut VecDeque<Message>,
|
||||
) -> Self;
|
||||
fn transition(self, message: ToolMessage, tool_data: &mut Self::ToolData, transition_data: ToolActionHandlerData, options: &Self::ToolOptions, messages: &mut VecDeque<Message>) -> Self;
|
||||
|
||||
fn update_hints(&self, responses: &mut VecDeque<Message>);
|
||||
fn update_cursor(&self, responses: &mut VecDeque<Message>);
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
|
||||
use graphene::color::Color;
|
||||
use graphene::layers::text_layer::FontCache;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@@ -14,12 +15,12 @@ pub struct ToolMessageHandler {
|
||||
tool_state: ToolFsmState,
|
||||
}
|
||||
|
||||
impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMessageHandler)> for ToolMessageHandler {
|
||||
impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMessageHandler, &FontCache)> for ToolMessageHandler {
|
||||
#[remain::check]
|
||||
fn process_action(&mut self, message: ToolMessage, data: (&DocumentMessageHandler, &InputPreprocessorMessageHandler), responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, message: ToolMessage, data: (&DocumentMessageHandler, &InputPreprocessorMessageHandler, &FontCache), responses: &mut VecDeque<Message>) {
|
||||
use ToolMessage::*;
|
||||
|
||||
let (document, input) = data;
|
||||
let (document, input, font_cache) = data;
|
||||
#[remain::sorted]
|
||||
match message {
|
||||
// Messages
|
||||
@@ -41,11 +42,11 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
||||
// Send the Abort state transition to the tool
|
||||
let mut send_abort_to_tool = |tool_type, message: ToolMessage, update_hints_and_cursor: bool| {
|
||||
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
|
||||
tool.process_action(message, (document, document_data, input), responses);
|
||||
tool.process_action(message, (document, document_data, input, font_cache), responses);
|
||||
|
||||
if update_hints_and_cursor {
|
||||
tool.process_action(ToolMessage::UpdateHints, (document, document_data, input), responses);
|
||||
tool.process_action(ToolMessage::UpdateCursor, (document, document_data, input), responses);
|
||||
tool.process_action(ToolMessage::UpdateHints, (document, document_data, input, font_cache), responses);
|
||||
tool.process_action(ToolMessage::UpdateCursor, (document, document_data, input, font_cache), responses);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -95,8 +96,12 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
||||
tool_data.register_properties(responses, LayoutTarget::ToolShelf);
|
||||
|
||||
// Set initial hints and cursor
|
||||
tool_data.active_tool_mut().process_action(ToolMessage::UpdateHints, (document, document_data, input), responses);
|
||||
tool_data.active_tool_mut().process_action(ToolMessage::UpdateCursor, (document, document_data, input), responses);
|
||||
tool_data
|
||||
.active_tool_mut()
|
||||
.process_action(ToolMessage::UpdateHints, (document, document_data, input, font_cache), responses);
|
||||
tool_data
|
||||
.active_tool_mut()
|
||||
.process_action(ToolMessage::UpdateCursor, (document, document_data, input, font_cache), responses);
|
||||
}
|
||||
ResetColors => {
|
||||
let document_data = &mut self.tool_state.document_tool_data;
|
||||
@@ -157,7 +162,7 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
||||
|
||||
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
|
||||
if tool_type == tool_data.active_tool_type {
|
||||
tool.process_action(tool_message, (document, document_data, input), responses);
|
||||
tool.process_action(tool_message, (document, document_data, input, font_cache), responses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use crate::consts::SELECTION_TOLERANCE;
|
||||
use crate::document::utility_types::TargetDocument;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::snapping::SnapHandler;
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::intersection::Quad;
|
||||
|
||||
@@ -25,7 +23,7 @@ pub struct ArtboardTool {
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Artboard)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum ArtboardToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -55,7 +53,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for ArtboardTool
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.data, data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -99,11 +97,9 @@ impl Fsm for ArtboardToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
_tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
if let ToolMessage::Artboard(event) = event {
|
||||
@@ -111,8 +107,8 @@ impl Fsm for ArtboardToolFsmState {
|
||||
(ArtboardToolFsmState::Ready | ArtboardToolFsmState::ResizingBounds | ArtboardToolFsmState::Dragging, ArtboardToolMessage::DocumentIsDirty) => {
|
||||
let mut buffer = Vec::new();
|
||||
match (
|
||||
data.selected_board.map(|path| document.artboard_bounding_box_and_transform(&[path])).unwrap_or(None),
|
||||
data.bounding_box_overlays.take(),
|
||||
tool_data.selected_board.map(|path| document.artboard_bounding_box_and_transform(&[path], font_cache)).unwrap_or(None),
|
||||
tool_data.bounding_box_overlays.take(),
|
||||
) {
|
||||
(None, Some(bounding_box_overlays)) => bounding_box_overlays.delete(&mut buffer),
|
||||
(Some((bounds, transform)), paths) => {
|
||||
@@ -123,12 +119,12 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
bounding_box_overlays.transform(&mut buffer);
|
||||
|
||||
data.bounding_box_overlays = Some(bounding_box_overlays);
|
||||
tool_data.bounding_box_overlays = Some(bounding_box_overlays);
|
||||
|
||||
responses.push_back(OverlaysMessage::Rerender.into());
|
||||
responses.push_back(
|
||||
PropertiesPanelMessage::SetActiveLayers {
|
||||
paths: vec![vec![data.selected_board.unwrap()]],
|
||||
paths: vec![vec![tool_data.selected_board.unwrap()]],
|
||||
document: TargetDocument::Artboard,
|
||||
}
|
||||
.into(),
|
||||
@@ -140,10 +136,10 @@ impl Fsm for ArtboardToolFsmState {
|
||||
self
|
||||
}
|
||||
(ArtboardToolFsmState::Ready, ArtboardToolMessage::PointerDown) => {
|
||||
data.drag_start = input.mouse.position;
|
||||
data.drag_current = input.mouse.position;
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
tool_data.drag_current = input.mouse.position;
|
||||
|
||||
let dragging_bounds = if let Some(bounding_box) = &mut data.bounding_box_overlays {
|
||||
let dragging_bounds = if let Some(bounding_box) = &mut tool_data.bounding_box_overlays {
|
||||
let edges = bounding_box.check_selected_edges(input.mouse.position);
|
||||
|
||||
bounding_box.selected_edges = edges.map(|(top, bottom, left, right)| {
|
||||
@@ -161,22 +157,25 @@ impl Fsm for ArtboardToolFsmState {
|
||||
let snap_x = selected_edges.2 || selected_edges.3;
|
||||
let snap_y = selected_edges.0 || selected_edges.1;
|
||||
|
||||
data.snap_handler
|
||||
.start_snap(document, document.bounding_boxes(None, Some(data.selected_board.unwrap())), snap_x, snap_y);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
tool_data
|
||||
.snap_handler
|
||||
.start_snap(document, document.bounding_boxes(None, Some(tool_data.selected_board.unwrap()), font_cache), snap_x, snap_y);
|
||||
tool_data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
|
||||
ArtboardToolFsmState::ResizingBounds
|
||||
} else {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
||||
let intersection = document.artboard_message_handler.artboards_graphene_document.intersects_quad_root(quad);
|
||||
let intersection = document.artboard_message_handler.artboards_graphene_document.intersects_quad_root(quad, font_cache);
|
||||
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
if let Some(intersection) = intersection.last() {
|
||||
data.selected_board = Some(intersection[0]);
|
||||
tool_data.selected_board = Some(intersection[0]);
|
||||
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(None, Some(intersection[0])), true, true);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
tool_data
|
||||
.snap_handler
|
||||
.start_snap(document, document.bounding_boxes(None, Some(intersection[0]), font_cache), true, true);
|
||||
tool_data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
|
||||
responses.push_back(
|
||||
PropertiesPanelMessage::SetActiveLayers {
|
||||
@@ -189,10 +188,10 @@ impl Fsm for ArtboardToolFsmState {
|
||||
ArtboardToolFsmState::Dragging
|
||||
} else {
|
||||
let id = generate_uuid();
|
||||
data.selected_board = Some(id);
|
||||
tool_data.selected_board = Some(id);
|
||||
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(None, Some(id)), true, true);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
tool_data.snap_handler.start_snap(document, document.bounding_boxes(None, Some(id), font_cache), true, true);
|
||||
tool_data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
|
||||
responses.push_back(
|
||||
ArtboardMessage::AddArtboard {
|
||||
@@ -210,20 +209,20 @@ impl Fsm for ArtboardToolFsmState {
|
||||
}
|
||||
}
|
||||
(ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => {
|
||||
if let Some(bounds) = &data.bounding_box_overlays {
|
||||
if let Some(bounds) = &tool_data.bounding_box_overlays {
|
||||
if let Some(movement) = &bounds.selected_edges {
|
||||
let from_center = input.keyboard.get(center as usize);
|
||||
let constrain_square = input.keyboard.get(constrain_axis_or_aspect as usize);
|
||||
|
||||
let mouse_position = input.mouse.position;
|
||||
let snapped_mouse_position = data.snap_handler.snap_position(responses, document, mouse_position);
|
||||
let snapped_mouse_position = tool_data.snap_handler.snap_position(responses, document, mouse_position);
|
||||
|
||||
let [position, size] = movement.new_size(snapped_mouse_position, bounds.transform, from_center, constrain_square);
|
||||
let position = movement.center_position(position, size, from_center);
|
||||
|
||||
responses.push_back(
|
||||
ArtboardMessage::ResizeArtboard {
|
||||
artboard: data.selected_board.unwrap(),
|
||||
artboard: tool_data.selected_board.unwrap(),
|
||||
position: position.round().into(),
|
||||
size: size.round().into(),
|
||||
}
|
||||
@@ -236,22 +235,22 @@ impl Fsm for ArtboardToolFsmState {
|
||||
ArtboardToolFsmState::ResizingBounds
|
||||
}
|
||||
(ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, .. }) => {
|
||||
if let Some(bounds) = &data.bounding_box_overlays {
|
||||
if let Some(bounds) = &tool_data.bounding_box_overlays {
|
||||
let axis_align = input.keyboard.get(constrain_axis_or_aspect as usize);
|
||||
|
||||
let mouse_position = axis_align_drag(axis_align, input.mouse.position, data.drag_start);
|
||||
let mouse_delta = mouse_position - data.drag_current;
|
||||
let mouse_position = axis_align_drag(axis_align, input.mouse.position, tool_data.drag_start);
|
||||
let mouse_delta = mouse_position - tool_data.drag_current;
|
||||
|
||||
let snap = bounds.evaluate_transform_handle_positions().into_iter().collect();
|
||||
let closest_move = data.snap_handler.snap_layers(responses, document, snap, mouse_delta);
|
||||
let closest_move = tool_data.snap_handler.snap_layers(responses, document, snap, mouse_delta);
|
||||
|
||||
let size = bounds.bounds[1] - bounds.bounds[0];
|
||||
|
||||
let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_position - data.drag_current + closest_move);
|
||||
let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_position - tool_data.drag_current + closest_move);
|
||||
|
||||
responses.push_back(
|
||||
ArtboardMessage::ResizeArtboard {
|
||||
artboard: data.selected_board.unwrap(),
|
||||
artboard: tool_data.selected_board.unwrap(),
|
||||
position: position.round().into(),
|
||||
size: size.round().into(),
|
||||
}
|
||||
@@ -260,17 +259,17 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
|
||||
data.drag_current = mouse_position + closest_move;
|
||||
tool_data.drag_current = mouse_position + closest_move;
|
||||
}
|
||||
ArtboardToolFsmState::Dragging
|
||||
}
|
||||
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => {
|
||||
let mouse_position = input.mouse.position;
|
||||
let snapped_mouse_position = data.snap_handler.snap_position(responses, document, mouse_position);
|
||||
let snapped_mouse_position = tool_data.snap_handler.snap_position(responses, document, mouse_position);
|
||||
|
||||
let root_transform = document.graphene_document.root.transform.inverse();
|
||||
|
||||
let mut start = data.drag_start;
|
||||
let mut start = tool_data.drag_start;
|
||||
let mut size = snapped_mouse_position - start;
|
||||
// Constrain axis
|
||||
if input.keyboard.get(constrain_axis_or_aspect as usize) {
|
||||
@@ -287,7 +286,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.push_back(
|
||||
ArtboardMessage::ResizeArtboard {
|
||||
artboard: data.selected_board.unwrap(),
|
||||
artboard: tool_data.selected_board.unwrap(),
|
||||
position: start.round().into(),
|
||||
size: size.round().into(),
|
||||
}
|
||||
@@ -298,7 +297,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
// This might result in a few more calls but it is not reliant on the order of messages
|
||||
responses.push_back(
|
||||
PropertiesPanelMessage::SetActiveLayers {
|
||||
paths: vec![vec![data.selected_board.unwrap()]],
|
||||
paths: vec![vec![tool_data.selected_board.unwrap()]],
|
||||
document: TargetDocument::Artboard,
|
||||
}
|
||||
.into(),
|
||||
@@ -309,28 +308,28 @@ impl Fsm for ArtboardToolFsmState {
|
||||
ArtboardToolFsmState::Drawing
|
||||
}
|
||||
(ArtboardToolFsmState::Ready, ArtboardToolMessage::PointerMove { .. }) => {
|
||||
let cursor = data.bounding_box_overlays.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, false));
|
||||
let cursor = tool_data.bounding_box_overlays.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, false));
|
||||
|
||||
if data.cursor != cursor {
|
||||
data.cursor = cursor;
|
||||
if tool_data.cursor != cursor {
|
||||
tool_data.cursor = cursor;
|
||||
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor }.into());
|
||||
}
|
||||
|
||||
ArtboardToolFsmState::Ready
|
||||
}
|
||||
(ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerUp) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
bounds.original_transforms.clear();
|
||||
}
|
||||
|
||||
ArtboardToolFsmState::Ready
|
||||
}
|
||||
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerUp) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
bounds.original_transforms.clear();
|
||||
}
|
||||
|
||||
@@ -339,23 +338,23 @@ impl Fsm for ArtboardToolFsmState {
|
||||
ArtboardToolFsmState::Ready
|
||||
}
|
||||
(ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerUp) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
bounds.original_transforms.clear();
|
||||
}
|
||||
|
||||
ArtboardToolFsmState::Ready
|
||||
}
|
||||
(_, ArtboardToolMessage::DeleteSelected) => {
|
||||
if let Some(artboard) = data.selected_board.take() {
|
||||
if let Some(artboard) = tool_data.selected_board.take() {
|
||||
responses.push_back(ArtboardMessage::DeleteArtboard { artboard }.into());
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
}
|
||||
ArtboardToolFsmState::Ready
|
||||
}
|
||||
(_, ArtboardToolMessage::Abort) => {
|
||||
if let Some(bounding_box_overlays) = data.bounding_box_overlays.take() {
|
||||
if let Some(bounding_box_overlays) = tool_data.bounding_box_overlays.take() {
|
||||
bounding_box_overlays.delete(responses);
|
||||
}
|
||||
|
||||
@@ -368,7 +367,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
.into(),
|
||||
);
|
||||
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
ArtboardToolFsmState::Ready
|
||||
}
|
||||
_ => self,
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use super::shared::resize::Resize;
|
||||
use crate::consts::DRAG_THRESHOLD;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::layers::style;
|
||||
use graphene::Operation;
|
||||
@@ -23,7 +21,7 @@ pub struct EllipseTool {
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Ellipse)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum EllipseToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -52,7 +50,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for EllipseTool
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.data, data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -95,22 +93,20 @@ impl Fsm for EllipseToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use EllipseToolFsmState::*;
|
||||
use EllipseToolMessage::*;
|
||||
|
||||
let mut shape_data = &mut data.data;
|
||||
let mut shape_data = &mut tool_data.data;
|
||||
|
||||
if let ToolMessage::Ellipse(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input.mouse.position);
|
||||
shape_data.start(responses, document, input.mouse.position, font_cache);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
@@ -120,7 +116,7 @@ impl Fsm for EllipseToolFsmState {
|
||||
path: shape_data.path.clone().unwrap(),
|
||||
insert_index: -1,
|
||||
transform: DAffine2::ZERO.to_cols_array(),
|
||||
style: style::PathStyle::new(None, style::Fill::solid(tool_data.primary_color)),
|
||||
style: style::PathStyle::new(None, style::Fill::solid(global_tool_data.primary_color)),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use crate::consts::SELECTION_TOLERANCE;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::MouseMotion;
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::intersection::Quad;
|
||||
use graphene::layers::layer_info::LayerDataType;
|
||||
@@ -22,7 +20,7 @@ pub struct EyedropperTool {
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Eyedropper)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum EyedropperToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -47,7 +45,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for EyedropperTo
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.data, data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -80,11 +78,9 @@ impl Fsm for EyedropperToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
_tool_data: &DocumentToolData,
|
||||
_data: &mut Self::ToolData,
|
||||
_tool_data: &mut Self::ToolData,
|
||||
(document, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use EyedropperToolFsmState::*;
|
||||
@@ -98,7 +94,7 @@ impl Fsm for EyedropperToolFsmState {
|
||||
let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
|
||||
|
||||
// TODO: Destroy this pyramid
|
||||
if let Some(path) = document.graphene_document.intersects_quad_root(quad).last() {
|
||||
if let Some(path) = document.graphene_document.intersects_quad_root(quad, font_cache).last() {
|
||||
if let Ok(layer) = document.graphene_document.layer(path) {
|
||||
if let LayerDataType::Shape(shape) = &layer.data {
|
||||
if shape.style.fill().is_some() {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use crate::consts::SELECTION_TOLERANCE;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::MouseMotion;
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::intersection::Quad;
|
||||
use graphene::Operation;
|
||||
@@ -23,7 +21,7 @@ pub struct FillTool {
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Fill)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum FillToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -48,7 +46,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for FillTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.data, data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -81,11 +79,9 @@ impl Fsm for FillToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
_data: &mut Self::ToolData,
|
||||
_tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use FillToolFsmState::*;
|
||||
@@ -98,10 +94,10 @@ impl Fsm for FillToolFsmState {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
|
||||
|
||||
if let Some(path) = document.graphene_document.intersects_quad_root(quad).last() {
|
||||
if let Some(path) = document.graphene_document.intersects_quad_root(quad, font_cache).last() {
|
||||
let color = match lmb_or_rmb {
|
||||
LeftMouseDown => tool_data.primary_color,
|
||||
RightMouseDown => tool_data.secondary_color,
|
||||
LeftMouseDown => global_tool_data.primary_color,
|
||||
RightMouseDown => global_tool_data.secondary_color,
|
||||
Abort => unreachable!(),
|
||||
};
|
||||
let fill = Fill::Solid(color);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::MouseMotion;
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{LayoutRow, NumberInput, PropertyHolder, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo};
|
||||
@@ -92,7 +90,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for FreehandTool
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.data, data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -130,11 +128,9 @@ impl Fsm for FreehandToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, _font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use FreehandToolFsmState::*;
|
||||
@@ -147,42 +143,42 @@ impl Fsm for FreehandToolFsmState {
|
||||
(Ready, DragStart) => {
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
data.path = Some(document.get_path_for_new_layer());
|
||||
tool_data.path = Some(document.get_path_for_new_layer());
|
||||
|
||||
let pos = transform.inverse().transform_point2(input.mouse.position);
|
||||
|
||||
data.points.push(pos);
|
||||
tool_data.points.push(pos);
|
||||
|
||||
data.weight = tool_options.line_weight;
|
||||
tool_data.weight = tool_options.line_weight;
|
||||
|
||||
responses.push_back(add_polyline(data, tool_data));
|
||||
responses.push_back(add_polyline(tool_data, global_tool_data));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, PointerMove) => {
|
||||
let pos = transform.inverse().transform_point2(input.mouse.position);
|
||||
|
||||
if data.points.last() != Some(&pos) {
|
||||
data.points.push(pos);
|
||||
if tool_data.points.last() != Some(&pos) {
|
||||
tool_data.points.push(pos);
|
||||
}
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_polyline(data, tool_data));
|
||||
responses.push_back(remove_preview(tool_data));
|
||||
responses.push_back(add_polyline(tool_data, global_tool_data));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, DragStop) | (Drawing, Abort) => {
|
||||
if data.points.len() >= 2 {
|
||||
if tool_data.points.len() >= 2 {
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_polyline(data, tool_data));
|
||||
responses.push_back(remove_preview(tool_data));
|
||||
responses.push_back(add_polyline(tool_data, global_tool_data));
|
||||
responses.push_back(DocumentMessage::CommitTransaction.into());
|
||||
} else {
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
}
|
||||
|
||||
data.path = None;
|
||||
data.points.clear();
|
||||
tool_data.path = None;
|
||||
tool_data.points.clear();
|
||||
|
||||
Ready
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@ use crate::consts::{COLOR_ACCENT, LINE_ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE, V
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{LayoutRow, PropertyHolder, RadioEntryData, RadioInput, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::snapping::SnapHandler;
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::color::Color;
|
||||
use graphene::intersection::Quad;
|
||||
@@ -16,6 +15,7 @@ use graphene::layers::style::{Fill, Gradient, GradientType, PathStyle, Stroke};
|
||||
use graphene::Operation;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene::layers::text_layer::FontCache;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -37,7 +37,7 @@ impl Default for GradientOptions {
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Gradient)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum GradientToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -55,7 +55,7 @@ pub enum GradientToolMessage {
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum GradientOptionsUpdate {
|
||||
Type(GradientType),
|
||||
}
|
||||
@@ -78,7 +78,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for GradientTool
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.data, data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -128,8 +128,8 @@ impl Default for GradientToolFsmState {
|
||||
}
|
||||
|
||||
/// Computes the transform from gradient space to layer space (where gradient space is 0..1 in layer space)
|
||||
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler) -> DAffine2 {
|
||||
let bounds = layer.aabounding_box_for_transform(DAffine2::IDENTITY, &document.graphene_document.font_cache).unwrap();
|
||||
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, font_cache: &FontCache) -> DAffine2 {
|
||||
let bounds = layer.aabounding_box_for_transform(DAffine2::IDENTITY, font_cache).unwrap();
|
||||
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
|
||||
|
||||
let multiplied = document.graphene_document.multiply_transforms(path).unwrap();
|
||||
@@ -183,8 +183,8 @@ impl GradientOverlay {
|
||||
path
|
||||
}
|
||||
|
||||
pub fn new(fill: &Gradient, dragging_start: Option<bool>, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document);
|
||||
pub fn new(fill: &Gradient, dragging_start: Option<bool>, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, font_cache: &FontCache) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document, font_cache);
|
||||
let Gradient { start, end, .. } = fill;
|
||||
let [start, end] = [transform.transform_point2(*start), transform.transform_point2(*end)];
|
||||
|
||||
@@ -232,8 +232,8 @@ struct SelectedGradient {
|
||||
}
|
||||
|
||||
impl SelectedGradient {
|
||||
pub fn new(gradient: Gradient, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document);
|
||||
pub fn new(gradient: Gradient, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, font_cache: &FontCache) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document, font_cache);
|
||||
Self {
|
||||
path: path.to_vec(),
|
||||
transform,
|
||||
@@ -291,8 +291,8 @@ struct GradientToolData {
|
||||
snap_handler: SnapHandler,
|
||||
}
|
||||
|
||||
pub fn start_snap(snap_handler: &mut SnapHandler, document: &DocumentMessageHandler) {
|
||||
snap_handler.start_snap(document, document.bounding_boxes(None, None), true, true);
|
||||
pub fn start_snap(snap_handler: &mut SnapHandler, document: &DocumentMessageHandler, font_cache: &FontCache) {
|
||||
snap_handler.start_snap(document, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
}
|
||||
|
||||
@@ -303,17 +303,15 @@ impl Fsm for GradientToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
if let ToolMessage::Gradient(event) = event {
|
||||
match (self, event) {
|
||||
(_, GradientToolMessage::DocumentIsDirty) => {
|
||||
while let Some(overlay) = data.gradient_overlays.pop() {
|
||||
while let Some(overlay) = tool_data.gradient_overlays.pop() {
|
||||
overlay.delete_overlays(responses);
|
||||
}
|
||||
|
||||
@@ -321,11 +319,13 @@ impl Fsm for GradientToolFsmState {
|
||||
let layer = document.graphene_document.layer(path).unwrap();
|
||||
|
||||
if let Ok(Fill::Gradient(gradient)) = layer.style().map(|style| style.fill()) {
|
||||
let dragging_start = data
|
||||
let dragging_start = tool_data
|
||||
.selected_gradient
|
||||
.as_ref()
|
||||
.and_then(|selected| if selected.path == path { Some(selected.dragging_start) } else { None });
|
||||
data.gradient_overlays.push(GradientOverlay::new(gradient, dragging_start, path, layer, document, responses))
|
||||
tool_data
|
||||
.gradient_overlays
|
||||
.push(GradientOverlay::new(gradient, dragging_start, path, layer, document, responses, font_cache))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,11 +338,11 @@ impl Fsm for GradientToolFsmState {
|
||||
let tolerance = VECTOR_MANIPULATOR_ANCHOR_MARKER_SIZE.powi(2);
|
||||
|
||||
let mut dragging = false;
|
||||
for overlay in &data.gradient_overlays {
|
||||
for overlay in &tool_data.gradient_overlays {
|
||||
if overlay.evaluate_gradient_start().distance_squared(mouse) < tolerance {
|
||||
dragging = true;
|
||||
start_snap(&mut data.snap_handler, document);
|
||||
data.selected_gradient = Some(SelectedGradient {
|
||||
start_snap(&mut tool_data.snap_handler, document, font_cache);
|
||||
tool_data.selected_gradient = Some(SelectedGradient {
|
||||
path: overlay.path.clone(),
|
||||
transform: overlay.transform,
|
||||
gradient: overlay.gradient.clone(),
|
||||
@@ -351,8 +351,8 @@ impl Fsm for GradientToolFsmState {
|
||||
}
|
||||
if overlay.evaluate_gradient_end().distance_squared(mouse) < tolerance {
|
||||
dragging = true;
|
||||
start_snap(&mut data.snap_handler, document);
|
||||
data.selected_gradient = Some(SelectedGradient {
|
||||
start_snap(&mut tool_data.snap_handler, document, font_cache);
|
||||
tool_data.selected_gradient = Some(SelectedGradient {
|
||||
path: overlay.path.clone(),
|
||||
transform: overlay.transform,
|
||||
gradient: overlay.gradient.clone(),
|
||||
@@ -365,7 +365,7 @@ impl Fsm for GradientToolFsmState {
|
||||
} else {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
||||
let intersection = document.graphene_document.intersects_quad_root(quad).pop();
|
||||
let intersection = document.graphene_document.intersects_quad_root(quad, font_cache).pop();
|
||||
|
||||
if let Some(intersection) = intersection {
|
||||
if !document.selected_layers_contains(&intersection) {
|
||||
@@ -378,19 +378,19 @@ impl Fsm for GradientToolFsmState {
|
||||
|
||||
let gradient = Gradient::new(
|
||||
DVec2::ZERO,
|
||||
tool_data.secondary_color,
|
||||
global_tool_data.secondary_color,
|
||||
DVec2::ONE,
|
||||
tool_data.primary_color,
|
||||
global_tool_data.primary_color,
|
||||
DAffine2::IDENTITY,
|
||||
generate_uuid(),
|
||||
tool_options.gradient_type,
|
||||
);
|
||||
let mut selected_gradient = SelectedGradient::new(gradient, &intersection, layer, document).with_gradient_start(input.mouse.position);
|
||||
let mut selected_gradient = SelectedGradient::new(gradient, &intersection, layer, document, font_cache).with_gradient_start(input.mouse.position);
|
||||
selected_gradient.update_gradient(input.mouse.position, responses, false, tool_options.gradient_type);
|
||||
|
||||
data.selected_gradient = Some(selected_gradient);
|
||||
tool_data.selected_gradient = Some(selected_gradient);
|
||||
|
||||
start_snap(&mut data.snap_handler, document);
|
||||
start_snap(&mut tool_data.snap_handler, document, font_cache);
|
||||
|
||||
GradientToolFsmState::Drawing
|
||||
} else {
|
||||
@@ -399,23 +399,23 @@ impl Fsm for GradientToolFsmState {
|
||||
}
|
||||
}
|
||||
(GradientToolFsmState::Drawing, GradientToolMessage::PointerMove { constrain_axis }) => {
|
||||
if let Some(selected_gradient) = &mut data.selected_gradient {
|
||||
let mouse = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
if let Some(selected_gradient) = &mut tool_data.selected_gradient {
|
||||
let mouse = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
selected_gradient.update_gradient(mouse, responses, input.keyboard.get(constrain_axis as usize), selected_gradient.gradient.gradient_type);
|
||||
}
|
||||
GradientToolFsmState::Drawing
|
||||
}
|
||||
|
||||
(GradientToolFsmState::Drawing, GradientToolMessage::PointerUp) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
GradientToolFsmState::Ready
|
||||
}
|
||||
|
||||
(_, GradientToolMessage::Abort) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
while let Some(overlay) = data.gradient_overlays.pop() {
|
||||
while let Some(overlay) = tool_data.gradient_overlays.pop() {
|
||||
overlay.delete_overlays(responses);
|
||||
}
|
||||
GradientToolFsmState::Ready
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use crate::consts::{DRAG_THRESHOLD, LINE_ROTATE_SNAP_ANGLE};
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::mouse::ViewportPosition;
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{LayoutRow, NumberInput, PropertyHolder, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::snapping::SnapHandler;
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::layers::style;
|
||||
use graphene::Operation;
|
||||
@@ -19,7 +17,7 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct LineTool {
|
||||
fsm_state: LineToolFsmState,
|
||||
data: LineToolData,
|
||||
tool_data: LineToolData,
|
||||
options: LineOptions,
|
||||
}
|
||||
|
||||
@@ -75,7 +73,7 @@ impl PropertyHolder for LineTool {
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for LineTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -93,7 +91,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for LineTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -141,11 +139,9 @@ impl Fsm for LineToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use LineToolFsmState::*;
|
||||
@@ -154,22 +150,22 @@ impl Fsm for LineToolFsmState {
|
||||
if let ToolMessage::Line(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(None, None), true, true);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
data.drag_start = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.snap_handler.start_snap(document, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
tool_data.drag_start = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
data.path = Some(document.get_path_for_new_layer());
|
||||
tool_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
|
||||
data.weight = tool_options.line_weight;
|
||||
tool_data.weight = tool_options.line_weight;
|
||||
|
||||
responses.push_back(
|
||||
Operation::AddLine {
|
||||
path: data.path.clone().unwrap(),
|
||||
path: tool_data.path.clone().unwrap(),
|
||||
insert_index: -1,
|
||||
transform: DAffine2::ZERO.to_cols_array(),
|
||||
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, data.weight)), style::Fill::None),
|
||||
style: style::PathStyle::new(Some(style::Stroke::new(global_tool_data.primary_color, tool_data.weight)), style::Fill::None),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
@@ -177,30 +173,30 @@ impl Fsm for LineToolFsmState {
|
||||
Drawing
|
||||
}
|
||||
(Drawing, Redraw { center, snap_angle, lock_angle }) => {
|
||||
data.drag_current = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.drag_current = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
|
||||
let values: Vec<_> = [lock_angle, snap_angle, center].iter().map(|k| input.keyboard.get(*k as usize)).collect();
|
||||
responses.push_back(generate_transform(data, values[0], values[1], values[2]));
|
||||
responses.push_back(generate_transform(tool_data, values[0], values[1], values[2]));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
data.drag_current = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.drag_current = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
match data.drag_start.distance(input.mouse.position) <= DRAG_THRESHOLD {
|
||||
match tool_data.drag_start.distance(input.mouse.position) <= DRAG_THRESHOLD {
|
||||
true => responses.push_back(DocumentMessage::AbortTransaction.into()),
|
||||
false => responses.push_back(DocumentMessage::CommitTransaction.into()),
|
||||
}
|
||||
|
||||
data.path = None;
|
||||
tool_data.path = None;
|
||||
|
||||
Ready
|
||||
}
|
||||
(Drawing, Abort) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
data.path = None;
|
||||
tool_data.path = None;
|
||||
Ready
|
||||
}
|
||||
_ => self,
|
||||
@@ -268,16 +264,16 @@ impl Fsm for LineToolFsmState {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: bool) -> Message {
|
||||
let mut start = data.drag_start;
|
||||
let stop = data.drag_current;
|
||||
fn generate_transform(tool_data: &mut LineToolData, lock: bool, snap: bool, center: bool) -> Message {
|
||||
let mut start = tool_data.drag_start;
|
||||
let stop = tool_data.drag_current;
|
||||
|
||||
let dir = stop - start;
|
||||
|
||||
let mut angle = -dir.angle_between(DVec2::X);
|
||||
|
||||
if lock {
|
||||
angle = data.angle
|
||||
angle = tool_data.angle
|
||||
};
|
||||
|
||||
if snap {
|
||||
@@ -285,7 +281,7 @@ fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: b
|
||||
angle = (angle / snap_resolution).round() * snap_resolution;
|
||||
}
|
||||
|
||||
data.angle = angle;
|
||||
tool_data.angle = angle;
|
||||
|
||||
let mut scale = dir.length();
|
||||
|
||||
@@ -300,7 +296,7 @@ fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: b
|
||||
}
|
||||
|
||||
Operation::SetLayerTransformInViewport {
|
||||
path: data.path.clone().unwrap(),
|
||||
path: tool_data.path.clone().unwrap(),
|
||||
transform: glam::DAffine2::from_scale_angle_translation(DVec2::new(scale, 1.), angle, start).to_cols_array(),
|
||||
}
|
||||
.into()
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use glam::DVec2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -13,12 +11,12 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct NavigateTool {
|
||||
fsm_state: NavigateToolFsmState,
|
||||
data: NavigateToolData,
|
||||
tool_data: NavigateToolData,
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Navigate)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum NavigateToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -41,7 +39,7 @@ pub enum NavigateToolMessage {
|
||||
impl PropertyHolder for NavigateTool {}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for NavigateTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -52,7 +50,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for NavigateTool
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -97,11 +95,9 @@ impl Fsm for NavigateToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
message: ToolMessage,
|
||||
_document: &DocumentMessageHandler,
|
||||
_tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(_document, _global_tool_data, input, _font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
messages: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
if let ToolMessage::Navigate(navigate) = message {
|
||||
@@ -112,7 +108,7 @@ impl Fsm for NavigateToolFsmState {
|
||||
messages.push_front(MovementMessage::TransformCanvasEnd.into());
|
||||
|
||||
// Mouse has not moved from pointerdown to pointerup
|
||||
if data.drag_start == input.mouse.position {
|
||||
if tool_data.drag_start == input.mouse.position {
|
||||
messages.push_front(if zoom_in {
|
||||
MovementMessage::IncreaseCanvasZoom { center_on_mouse: true }.into()
|
||||
} else {
|
||||
@@ -128,24 +124,24 @@ impl Fsm for NavigateToolFsmState {
|
||||
snap_angle,
|
||||
wait_for_snap_angle_release: false,
|
||||
snap_zoom,
|
||||
zoom_from_viewport: Some(data.drag_start),
|
||||
zoom_from_viewport: Some(tool_data.drag_start),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
self
|
||||
}
|
||||
TranslateCanvasBegin => {
|
||||
data.drag_start = input.mouse.position;
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
messages.push_front(MovementMessage::TranslateCanvasBegin.into());
|
||||
NavigateToolFsmState::Panning
|
||||
}
|
||||
RotateCanvasBegin => {
|
||||
data.drag_start = input.mouse.position;
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
messages.push_front(MovementMessage::RotateCanvasBegin.into());
|
||||
NavigateToolFsmState::Tilting
|
||||
}
|
||||
ZoomCanvasBegin => {
|
||||
data.drag_start = input.mouse.position;
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
messages.push_front(MovementMessage::ZoomCanvasBegin.into());
|
||||
NavigateToolFsmState::Zooming
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use crate::consts::SELECTION_THRESHOLD;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::snapping::SnapHandler;
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::vector_editor::shape_editor::ShapeEditor;
|
||||
|
||||
use graphene::intersection::Quad;
|
||||
@@ -18,12 +16,12 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct PathTool {
|
||||
fsm_state: PathToolFsmState,
|
||||
data: PathToolData,
|
||||
tool_data: PathToolData,
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Path)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum PathToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -47,7 +45,7 @@ pub enum PathToolMessage {
|
||||
impl PropertyHolder for PathTool {}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for PathTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -58,7 +56,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for PathTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -107,11 +105,9 @@ impl Fsm for PathToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
_tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
if let ToolMessage::Path(event) = event {
|
||||
@@ -122,17 +118,17 @@ impl Fsm for PathToolFsmState {
|
||||
// TODO: Capture a tool event instead of doing this?
|
||||
(_, SelectionChanged) => {
|
||||
// Remove any residual overlays that might exist on selection change
|
||||
data.shape_editor.remove_overlays(responses);
|
||||
tool_data.shape_editor.remove_overlays(responses);
|
||||
|
||||
// This currently creates new VectorManipulatorShapes for every shape, which is not ideal
|
||||
// At least it is only on selection change for now
|
||||
data.shape_editor.set_shapes_to_modify(document.selected_visible_layers_vector_shapes(responses));
|
||||
tool_data.shape_editor.set_shapes_to_modify(document.selected_visible_layers_vector_shapes(responses, font_cache));
|
||||
|
||||
self
|
||||
}
|
||||
(_, DocumentIsDirty) => {
|
||||
// Update the VectorManipulatorShapes by reference so they match the kurbo data
|
||||
for shape in &mut data.shape_editor.shapes_to_modify {
|
||||
// Update the VectorManipulatorShapes by reference so they match the kurbo tool_data
|
||||
for shape in &mut tool_data.shape_editor.shapes_to_modify {
|
||||
shape.update_shape(document, responses);
|
||||
}
|
||||
self
|
||||
@@ -142,16 +138,18 @@ impl Fsm for PathToolFsmState {
|
||||
let add_to_selection = input.keyboard.get(add_to_selection as usize);
|
||||
|
||||
// Select the first point within the threshold (in pixels)
|
||||
if data.shape_editor.select_point(input.mouse.position, SELECTION_THRESHOLD, add_to_selection, responses) {
|
||||
if tool_data.shape_editor.select_point(input.mouse.position, SELECTION_THRESHOLD, add_to_selection, responses) {
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
|
||||
let ignore_document = data.shape_editor.shapes_to_modify.iter().map(|shape| shape.layer_path.clone()).collect::<Vec<_>>();
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(Some(&ignore_document), None), true, true);
|
||||
let ignore_document = tool_data.shape_editor.shapes_to_modify.iter().map(|shape| shape.layer_path.clone()).collect::<Vec<_>>();
|
||||
tool_data
|
||||
.snap_handler
|
||||
.start_snap(document, document.bounding_boxes(Some(&ignore_document), None, font_cache), true, true);
|
||||
|
||||
let include_handles = data.shape_editor.shapes_to_modify.iter().map(|shape| shape.layer_path.as_slice()).collect::<Vec<_>>();
|
||||
data.snap_handler.add_all_document_handles(document, &include_handles, &[]);
|
||||
let include_handles = tool_data.shape_editor.shapes_to_modify.iter().map(|shape| shape.layer_path.as_slice()).collect::<Vec<_>>();
|
||||
tool_data.snap_handler.add_all_document_handles(document, &include_handles, &[]);
|
||||
|
||||
data.drag_start_pos = input.mouse.position;
|
||||
tool_data.drag_start_pos = input.mouse.position;
|
||||
Dragging
|
||||
}
|
||||
// We didn't find a point nearby, so consider selecting the nearest shape instead
|
||||
@@ -160,7 +158,7 @@ impl Fsm for PathToolFsmState {
|
||||
// Select shapes directly under our mouse
|
||||
let intersection = document
|
||||
.graphene_document
|
||||
.intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]));
|
||||
.intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]), font_cache);
|
||||
if !intersection.is_empty() {
|
||||
if add_to_selection {
|
||||
responses.push_back(DocumentMessage::AddSelectedLayers { additional_layers: intersection }.into());
|
||||
@@ -191,33 +189,33 @@ impl Fsm for PathToolFsmState {
|
||||
) => {
|
||||
// Determine when alt state changes
|
||||
let alt_pressed = input.keyboard.get(alt_mirror_angle as usize);
|
||||
if alt_pressed != data.alt_debounce {
|
||||
data.alt_debounce = alt_pressed;
|
||||
if alt_pressed != tool_data.alt_debounce {
|
||||
tool_data.alt_debounce = alt_pressed;
|
||||
// Only on alt down
|
||||
if alt_pressed {
|
||||
data.shape_editor.toggle_selected_mirror_angle();
|
||||
tool_data.shape_editor.toggle_selected_mirror_angle();
|
||||
}
|
||||
}
|
||||
|
||||
// Determine when shift state changes
|
||||
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
|
||||
if shift_pressed != data.shift_debounce {
|
||||
data.shift_debounce = shift_pressed;
|
||||
data.shape_editor.toggle_selected_mirror_distance();
|
||||
if shift_pressed != tool_data.shift_debounce {
|
||||
tool_data.shift_debounce = shift_pressed;
|
||||
tool_data.shape_editor.toggle_selected_mirror_distance();
|
||||
}
|
||||
|
||||
// Move the selected points by the mouse position
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
data.shape_editor.move_selected_points(snapped_position - data.drag_start_pos, true, responses);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.shape_editor.move_selected_points(snapped_position - tool_data.drag_start_pos, true, responses);
|
||||
Dragging
|
||||
}
|
||||
// Mouse up
|
||||
(_, DragStop) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
Ready
|
||||
}
|
||||
(_, Abort) => {
|
||||
data.shape_editor.remove_overlays(responses);
|
||||
tool_data.shape_editor.remove_overlays(responses);
|
||||
Ready
|
||||
}
|
||||
(
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::layout::widgets::{LayoutRow, NumberInput, PropertyHolder, Widget, Wid
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::snapping::SnapHandler;
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::vector_editor::constants::ControlPointType;
|
||||
use crate::viewport_tools::vector_editor::shape_editor::ShapeEditor;
|
||||
use crate::viewport_tools::vector_editor::vector_shape::VectorShape;
|
||||
@@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct PenTool {
|
||||
fsm_state: PenToolFsmState,
|
||||
data: PenToolData,
|
||||
tool_data: PenToolData,
|
||||
options: PenOptions,
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ impl PropertyHolder for PenTool {
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for PenTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -102,7 +102,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for PenTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -144,11 +144,9 @@ impl Fsm for PenToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use PenToolFsmState::*;
|
||||
@@ -159,7 +157,7 @@ impl Fsm for PenToolFsmState {
|
||||
if let ToolMessage::Pen(event) = event {
|
||||
match (self, event) {
|
||||
(_, DocumentIsDirty) => {
|
||||
data.shape_editor.update_shapes(document, responses);
|
||||
tool_data.shape_editor.update_shapes(document, responses);
|
||||
self
|
||||
}
|
||||
(Ready, DragStart) => {
|
||||
@@ -167,76 +165,76 @@ impl Fsm for PenToolFsmState {
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
|
||||
// Create a new layer and prep snap system
|
||||
data.path = Some(document.get_path_for_new_layer());
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(None, None), true, true);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.path = Some(document.get_path_for_new_layer());
|
||||
tool_data.snap_handler.start_snap(document, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
|
||||
// Get the position and set properties
|
||||
let start_position = transform.inverse().transform_point2(snapped_position);
|
||||
data.weight = tool_options.line_weight;
|
||||
tool_data.weight = tool_options.line_weight;
|
||||
|
||||
// Create the initial shape with a `bez_path` (only contains a moveto initially)
|
||||
if let Some(layer_path) = &data.path {
|
||||
data.bez_path = start_bez_path(start_position);
|
||||
if let Some(layer_path) = &tool_data.path {
|
||||
tool_data.bez_path = start_bez_path(start_position);
|
||||
responses.push_back(
|
||||
Operation::AddShape {
|
||||
path: layer_path.clone(),
|
||||
transform: transform.to_cols_array(),
|
||||
insert_index: -1,
|
||||
bez_path: data.bez_path.clone().into_iter().collect(),
|
||||
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, data.weight)), style::Fill::None),
|
||||
bez_path: tool_data.bez_path.clone().into_iter().collect(),
|
||||
style: style::PathStyle::new(Some(style::Stroke::new(global_tool_data.primary_color, tool_data.weight)), style::Fill::None),
|
||||
closed: false,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
add_to_curve(data, input, transform, document, responses);
|
||||
add_to_curve(tool_data, input, transform, document, responses);
|
||||
Drawing
|
||||
}
|
||||
(Drawing, DragStart) => {
|
||||
data.drag_start_position = input.mouse.position;
|
||||
add_to_curve(data, input, transform, document, responses);
|
||||
tool_data.drag_start_position = input.mouse.position;
|
||||
add_to_curve(tool_data, input, transform, document, responses);
|
||||
Drawing
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
// Deselect everything (this means we are no longer dragging the handle)
|
||||
data.shape_editor.deselect_all(responses);
|
||||
tool_data.shape_editor.deselect_all(responses);
|
||||
|
||||
// If the drag does not exceed the threshold, then replace the curve with a line
|
||||
if data.drag_start_position.distance(input.mouse.position) < CREATE_CURVE_THRESHOLD {
|
||||
if tool_data.drag_start_position.distance(input.mouse.position) < CREATE_CURVE_THRESHOLD {
|
||||
// Modify the second to last element (as we have an unplaced element tracing to the cursor as the last element)
|
||||
let replace_index = data.bez_path.len() - 2;
|
||||
let line_from_curve = convert_curve_to_line(data.bez_path[replace_index]);
|
||||
replace_path_element(data, transform, replace_index, line_from_curve, responses);
|
||||
let replace_index = tool_data.bez_path.len() - 2;
|
||||
let line_from_curve = convert_curve_to_line(tool_data.bez_path[replace_index]);
|
||||
replace_path_element(tool_data, transform, replace_index, line_from_curve, responses);
|
||||
}
|
||||
|
||||
// Reselect the last point
|
||||
if let Some(last_anchor) = data.shape_editor.select_last_anchor() {
|
||||
if let Some(last_anchor) = tool_data.shape_editor.select_last_anchor() {
|
||||
last_anchor.select_point(ControlPointType::Anchor as usize, true, responses);
|
||||
}
|
||||
|
||||
// Move the newly selected points to the cursor
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
data.shape_editor.move_selected_points(snapped_position, false, responses);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.shape_editor.move_selected_points(snapped_position, false, responses);
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, PointerMove) => {
|
||||
// Move selected points
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
data.shape_editor.move_selected_points(snapped_position, false, responses);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.shape_editor.move_selected_points(snapped_position, false, responses);
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, Confirm) | (Drawing, Abort) => {
|
||||
// Cleanup, we are either canceling or finished drawing
|
||||
if data.bez_path.len() >= 2 {
|
||||
if tool_data.bez_path.len() >= 2 {
|
||||
// Remove the last segment
|
||||
remove_from_curve(data);
|
||||
if let Some(layer_path) = &data.path {
|
||||
responses.push_back(apply_bez_path(layer_path.clone(), data.bez_path.clone(), transform));
|
||||
remove_from_curve(tool_data);
|
||||
if let Some(layer_path) = &tool_data.path {
|
||||
responses.push_back(apply_bez_path(layer_path.clone(), tool_data.bez_path.clone(), transform));
|
||||
}
|
||||
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
@@ -245,17 +243,17 @@ impl Fsm for PenToolFsmState {
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
}
|
||||
|
||||
data.shape_editor.remove_overlays(responses);
|
||||
data.shape_editor.clear_shapes_to_modify();
|
||||
tool_data.shape_editor.remove_overlays(responses);
|
||||
tool_data.shape_editor.clear_shapes_to_modify();
|
||||
|
||||
data.path = None;
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.path = None;
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
Ready
|
||||
}
|
||||
(_, Abort) => {
|
||||
data.shape_editor.remove_overlays(responses);
|
||||
data.shape_editor.clear_shapes_to_modify();
|
||||
tool_data.shape_editor.remove_overlays(responses);
|
||||
tool_data.shape_editor.clear_shapes_to_modify();
|
||||
Ready
|
||||
}
|
||||
_ => self,
|
||||
@@ -298,56 +296,56 @@ impl Fsm for PenToolFsmState {
|
||||
}
|
||||
|
||||
/// Add to the curve and select the second anchor of the last point and the newly added anchor point
|
||||
fn add_to_curve(data: &mut PenToolData, input: &InputPreprocessorMessageHandler, transform: DAffine2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
// Refresh data's representation of the path
|
||||
update_path_representation(data);
|
||||
fn add_to_curve(tool_data: &mut PenToolData, input: &InputPreprocessorMessageHandler, transform: DAffine2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
// Refresh tool_data's representation of the path
|
||||
update_path_representation(tool_data);
|
||||
|
||||
// Setup our position params
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
let position = transform.inverse().transform_point2(snapped_position);
|
||||
|
||||
// Add a curve to the path
|
||||
if let Some(layer_path) = &data.path {
|
||||
if let Some(layer_path) = &tool_data.path {
|
||||
// Push curve onto path
|
||||
let point = Point { x: position.x, y: position.y };
|
||||
data.bez_path.push(PathEl::CurveTo(point, point, point));
|
||||
tool_data.bez_path.push(PathEl::CurveTo(point, point, point));
|
||||
|
||||
responses.push_back(apply_bez_path(layer_path.clone(), data.bez_path.clone(), transform));
|
||||
responses.push_back(apply_bez_path(layer_path.clone(), tool_data.bez_path.clone(), transform));
|
||||
|
||||
// Clear previous overlays
|
||||
data.shape_editor.remove_overlays(responses);
|
||||
tool_data.shape_editor.remove_overlays(responses);
|
||||
|
||||
// Create a new `shape` from the updated `bez_path`
|
||||
let bez_path = data.bez_path.clone().into_iter().collect();
|
||||
data.curve_shape = VectorShape::new(layer_path.to_vec(), transform, &bez_path, false, responses);
|
||||
data.shape_editor.set_shapes_to_modify(vec![data.curve_shape.clone()]);
|
||||
let bez_path = tool_data.bez_path.clone().into_iter().collect();
|
||||
tool_data.curve_shape = VectorShape::new(layer_path.to_vec(), transform, &bez_path, false, responses);
|
||||
tool_data.shape_editor.set_shapes_to_modify(vec![tool_data.curve_shape.clone()]);
|
||||
|
||||
// Select the second to last `PathEl`'s handle
|
||||
data.shape_editor.set_shape_selected(0);
|
||||
let handle_element = data.shape_editor.select_nth_anchor(0, -2);
|
||||
tool_data.shape_editor.set_shape_selected(0);
|
||||
let handle_element = tool_data.shape_editor.select_nth_anchor(0, -2);
|
||||
handle_element.select_point(ControlPointType::Handle2 as usize, true, responses);
|
||||
|
||||
// Select the last `PathEl`'s anchor point
|
||||
if let Some(last_anchor) = data.shape_editor.select_last_anchor() {
|
||||
if let Some(last_anchor) = tool_data.shape_editor.select_last_anchor() {
|
||||
last_anchor.select_point(ControlPointType::Anchor as usize, true, responses);
|
||||
}
|
||||
data.shape_editor.set_selected_mirror_options(true, true);
|
||||
tool_data.shape_editor.set_selected_mirror_options(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace a `PathEl` with another inside of `bez_path` by index
|
||||
fn replace_path_element(data: &mut PenToolData, transform: DAffine2, replace_index: usize, replacement: PathEl, responses: &mut VecDeque<Message>) {
|
||||
data.bez_path[replace_index] = replacement;
|
||||
if let Some(layer_path) = &data.path {
|
||||
responses.push_back(apply_bez_path(layer_path.clone(), data.bez_path.clone(), transform));
|
||||
fn replace_path_element(tool_data: &mut PenToolData, transform: DAffine2, replace_index: usize, replacement: PathEl, responses: &mut VecDeque<Message>) {
|
||||
tool_data.bez_path[replace_index] = replacement;
|
||||
if let Some(layer_path) = &tool_data.path {
|
||||
responses.push_back(apply_bez_path(layer_path.clone(), tool_data.bez_path.clone(), transform));
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a curve from the end of the `bez_path`
|
||||
fn remove_from_curve(data: &mut PenToolData) {
|
||||
// Refresh data's representation of the path
|
||||
update_path_representation(data);
|
||||
data.bez_path.pop();
|
||||
fn remove_from_curve(tool_data: &mut PenToolData) {
|
||||
// Refresh tool_data's representation of the path
|
||||
update_path_representation(tool_data);
|
||||
tool_data.bez_path.pop();
|
||||
}
|
||||
|
||||
/// Create the initial moveto for the `bez_path`
|
||||
@@ -366,13 +364,13 @@ fn convert_curve_to_line(curve: PathEl) -> PathEl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Update data's version of `bez_path` to match `ShapeEditor`'s version
|
||||
fn update_path_representation(data: &mut PenToolData) {
|
||||
/// Update tool_data's version of `bez_path` to match `ShapeEditor`'s version
|
||||
fn update_path_representation(tool_data: &mut PenToolData) {
|
||||
// TODO Update ShapeEditor to provide similar functionality
|
||||
// We need to make sure we have the most up-to-date bez_path
|
||||
if !data.shape_editor.shapes_to_modify.is_empty() {
|
||||
if !tool_data.shape_editor.shapes_to_modify.is_empty() {
|
||||
// Hacky way of saving the curve changes
|
||||
data.bez_path = data.shape_editor.shapes_to_modify[0].bez_path.elements().to_vec();
|
||||
tool_data.bez_path = tool_data.shape_editor.shapes_to_modify[0].bez_path.elements().to_vec();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use super::shared::resize::Resize;
|
||||
use crate::consts::DRAG_THRESHOLD;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::PropertyHolder;
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::layers::style;
|
||||
use graphene::Operation;
|
||||
@@ -18,12 +16,12 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct RectangleTool {
|
||||
fsm_state: RectangleToolFsmState,
|
||||
data: RectangleToolData,
|
||||
tool_data: RectangleToolData,
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Rectangle)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum RectangleToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -41,7 +39,7 @@ pub enum RectangleToolMessage {
|
||||
impl PropertyHolder for RectangleTool {}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for RectangleTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -52,7 +50,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for RectangleToo
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -94,22 +92,20 @@ impl Fsm for RectangleToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use RectangleToolFsmState::*;
|
||||
use RectangleToolMessage::*;
|
||||
|
||||
let mut shape_data = &mut data.data;
|
||||
let mut shape_data = &mut tool_data.data;
|
||||
|
||||
if let ToolMessage::Rectangle(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input.mouse.position);
|
||||
shape_data.start(responses, document, input.mouse.position, font_cache);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
@@ -119,7 +115,7 @@ impl Fsm for RectangleToolFsmState {
|
||||
path: shape_data.path.clone().unwrap(),
|
||||
insert_index: -1,
|
||||
transform: DAffine2::ZERO.to_cols_array(),
|
||||
style: style::PathStyle::new(None, style::Fill::solid(tool_data.primary_color)),
|
||||
style: style::PathStyle::new(None, style::Fill::solid(global_tool_data.primary_color)),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE};
|
||||
use crate::document::transformation::Selected;
|
||||
use crate::document::utility_types::{AlignAggregate, AlignAxis, FlipAxis};
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::mouse::ViewportPosition;
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{IconButton, LayoutRow, PopoverButton, PropertyHolder, Separator, SeparatorDirection, SeparatorType, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::snapping::{self, SnapHandler};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData, ToolType};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData, ToolType};
|
||||
use graphene::boolean_ops::BooleanOperation;
|
||||
use graphene::document::Document;
|
||||
use graphene::intersection::Quad;
|
||||
@@ -26,12 +24,12 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct SelectTool {
|
||||
fsm_state: SelectToolFsmState,
|
||||
data: SelectToolData,
|
||||
tool_data: SelectToolData,
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Select)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum SelectToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -231,7 +229,7 @@ impl PropertyHolder for SelectTool {
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for SelectTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -242,7 +240,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for SelectTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &(), data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &(), responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -310,11 +308,9 @@ impl Fsm for SelectToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
_tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use SelectToolFsmState::*;
|
||||
@@ -324,7 +320,7 @@ impl Fsm for SelectToolFsmState {
|
||||
match (self, event) {
|
||||
(_, DocumentIsDirty) => {
|
||||
let mut buffer = Vec::new();
|
||||
match (document.selected_visible_layers_bounding_box(), data.bounding_box_overlays.take()) {
|
||||
match (document.selected_visible_layers_bounding_box(font_cache), tool_data.bounding_box_overlays.take()) {
|
||||
(None, Some(bounding_box_overlays)) => bounding_box_overlays.delete(&mut buffer),
|
||||
(Some(bounds), paths) => {
|
||||
let mut bounding_box_overlays = paths.unwrap_or_else(|| BoundingBoxOverlays::new(&mut buffer));
|
||||
@@ -334,13 +330,13 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
bounding_box_overlays.transform(&mut buffer);
|
||||
|
||||
data.bounding_box_overlays = Some(bounding_box_overlays);
|
||||
tool_data.bounding_box_overlays = Some(bounding_box_overlays);
|
||||
}
|
||||
(_, _) => {}
|
||||
};
|
||||
buffer.into_iter().rev().for_each(|message| responses.push_front(message));
|
||||
|
||||
data.path_outlines.update_selected(document.selected_visible_layers(), document, responses);
|
||||
tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, font_cache);
|
||||
|
||||
self
|
||||
}
|
||||
@@ -349,7 +345,12 @@ impl Fsm for SelectToolFsmState {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
|
||||
|
||||
if let Some(Ok(intersect)) = document.graphene_document.intersects_quad_root(quad).last().map(|path| document.graphene_document.layer(path)) {
|
||||
if let Some(Ok(intersect)) = document
|
||||
.graphene_document
|
||||
.intersects_quad_root(quad, font_cache)
|
||||
.last()
|
||||
.map(|path| document.graphene_document.layer(path))
|
||||
{
|
||||
match intersect.data {
|
||||
LayerDataType::Text(_) => {
|
||||
responses.push_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }.into());
|
||||
@@ -365,13 +366,13 @@ impl Fsm for SelectToolFsmState {
|
||||
self
|
||||
}
|
||||
(Ready, DragStart { add_to_selection }) => {
|
||||
data.path_outlines.clear_hovered(responses);
|
||||
tool_data.path_outlines.clear_hovered(responses);
|
||||
|
||||
data.drag_start = input.mouse.position;
|
||||
data.drag_current = input.mouse.position;
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
tool_data.drag_current = input.mouse.position;
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
let dragging_bounds = if let Some(bounding_box) = &mut data.bounding_box_overlays {
|
||||
let dragging_bounds = if let Some(bounding_box) = &mut tool_data.bounding_box_overlays {
|
||||
let edges = bounding_box.check_selected_edges(input.mouse.position);
|
||||
|
||||
bounding_box.selected_edges = edges.map(|(top, bottom, left, right)| {
|
||||
@@ -385,15 +386,15 @@ impl Fsm for SelectToolFsmState {
|
||||
None
|
||||
};
|
||||
|
||||
let rotating_bounds = if let Some(bounding_box) = &mut data.bounding_box_overlays {
|
||||
let rotating_bounds = if let Some(bounding_box) = &mut tool_data.bounding_box_overlays {
|
||||
bounding_box.check_rotate(input.mouse.position)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut selected: Vec<_> = document.selected_visible_layers().map(|path| path.to_vec()).collect();
|
||||
let quad = data.selection_quad();
|
||||
let mut intersection = document.graphene_document.intersects_quad_root(quad);
|
||||
let quad = tool_data.selection_quad();
|
||||
let mut intersection = document.graphene_document.intersects_quad_root(quad, font_cache);
|
||||
// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
|
||||
// If the user is dragging the rotate trigger, go into RotatingBounds mode.
|
||||
// If the user clicks on a layer that is in their current selection, go into the dragging mode.
|
||||
@@ -403,46 +404,52 @@ impl Fsm for SelectToolFsmState {
|
||||
let snap_x = selected_edges.2 || selected_edges.3;
|
||||
let snap_y = selected_edges.0 || selected_edges.1;
|
||||
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(Some(&selected), None), snap_x, snap_y);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &selected.iter().map(|x| x.as_slice()).collect::<Vec<_>>());
|
||||
tool_data.snap_handler.start_snap(document, document.bounding_boxes(Some(&selected), None, font_cache), snap_x, snap_y);
|
||||
tool_data
|
||||
.snap_handler
|
||||
.add_all_document_handles(document, &[], &selected.iter().map(|x| x.as_slice()).collect::<Vec<_>>());
|
||||
|
||||
data.layers_dragging = selected;
|
||||
tool_data.layers_dragging = selected;
|
||||
|
||||
ResizingBounds
|
||||
} else if rotating_bounds {
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
let selected = selected.iter().collect::<Vec<_>>();
|
||||
let mut selected = Selected::new(&mut bounds.original_transforms, &mut bounds.pivot, &selected, responses, &document.graphene_document);
|
||||
|
||||
*selected.pivot = selected.calculate_pivot(&document.graphene_document.font_cache);
|
||||
*selected.pivot = selected.calculate_pivot(font_cache);
|
||||
}
|
||||
|
||||
data.layers_dragging = selected;
|
||||
tool_data.layers_dragging = selected;
|
||||
|
||||
RotatingBounds
|
||||
} else if selected.iter().any(|path| intersection.contains(path)) {
|
||||
buffer.push(DocumentMessage::StartTransaction.into());
|
||||
data.layers_dragging = selected;
|
||||
tool_data.layers_dragging = selected;
|
||||
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(Some(&data.layers_dragging), None), true, true);
|
||||
tool_data
|
||||
.snap_handler
|
||||
.start_snap(document, document.bounding_boxes(Some(&tool_data.layers_dragging), None, font_cache), true, true);
|
||||
|
||||
Dragging
|
||||
} else {
|
||||
if !input.keyboard.get(add_to_selection as usize) {
|
||||
buffer.push(DocumentMessage::DeselectAllLayers.into());
|
||||
data.layers_dragging.clear();
|
||||
tool_data.layers_dragging.clear();
|
||||
}
|
||||
|
||||
if let Some(intersection) = intersection.pop() {
|
||||
selected = vec![intersection];
|
||||
buffer.push(DocumentMessage::AddSelectedLayers { additional_layers: selected.clone() }.into());
|
||||
buffer.push(DocumentMessage::StartTransaction.into());
|
||||
data.layers_dragging.append(&mut selected);
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(Some(&data.layers_dragging), None), true, true);
|
||||
tool_data.layers_dragging.append(&mut selected);
|
||||
tool_data
|
||||
.snap_handler
|
||||
.start_snap(document, document.bounding_boxes(Some(&tool_data.layers_dragging), None, font_cache), true, true);
|
||||
|
||||
Dragging
|
||||
} else {
|
||||
data.drag_box_overlay_layer = Some(add_bounding_box(&mut buffer));
|
||||
tool_data.drag_box_overlay_layer = Some(add_bounding_box(&mut buffer));
|
||||
DrawingBox
|
||||
}
|
||||
};
|
||||
@@ -454,20 +461,20 @@ impl Fsm for SelectToolFsmState {
|
||||
// TODO: This is a cheat. Break out the relevant functionality from the handler above and call it from there and here.
|
||||
responses.push_front(SelectToolMessage::DocumentIsDirty.into());
|
||||
|
||||
let mouse_position = axis_align_drag(input.keyboard.get(axis_align as usize), input.mouse.position, data.drag_start);
|
||||
let mouse_position = axis_align_drag(input.keyboard.get(axis_align as usize), input.mouse.position, tool_data.drag_start);
|
||||
|
||||
let mouse_delta = mouse_position - data.drag_current;
|
||||
let mouse_delta = mouse_position - tool_data.drag_current;
|
||||
|
||||
let snap = data
|
||||
let snap = tool_data
|
||||
.layers_dragging
|
||||
.iter()
|
||||
.filter_map(|path| document.graphene_document.viewport_bounding_box(path).ok()?)
|
||||
.filter_map(|path| document.graphene_document.viewport_bounding_box(path, font_cache).ok()?)
|
||||
.flat_map(snapping::expand_bounds)
|
||||
.collect();
|
||||
|
||||
let closest_move = data.snap_handler.snap_layers(responses, document, snap, mouse_delta);
|
||||
let closest_move = tool_data.snap_handler.snap_layers(responses, document, snap, mouse_delta);
|
||||
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
|
||||
for path in Document::shallowest_unique_layers(data.layers_dragging.iter()) {
|
||||
for path in Document::shallowest_unique_layers(tool_data.layers_dragging.iter()) {
|
||||
responses.push_front(
|
||||
Operation::TransformLayerInViewport {
|
||||
path: path.clone(),
|
||||
@@ -476,22 +483,22 @@ impl Fsm for SelectToolFsmState {
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
data.drag_current = mouse_position + closest_move;
|
||||
tool_data.drag_current = mouse_position + closest_move;
|
||||
Dragging
|
||||
}
|
||||
(ResizingBounds, PointerMove { axis_align, center, .. }) => {
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
if let Some(movement) = &mut bounds.selected_edges {
|
||||
let (center, axis_align) = (input.keyboard.get(center as usize), input.keyboard.get(axis_align as usize));
|
||||
|
||||
let mouse_position = input.mouse.position;
|
||||
|
||||
let snapped_mouse_position = data.snap_handler.snap_position(responses, document, mouse_position);
|
||||
let snapped_mouse_position = tool_data.snap_handler.snap_position(responses, document, mouse_position);
|
||||
|
||||
let [_position, size] = movement.new_size(snapped_mouse_position, bounds.transform, center, axis_align);
|
||||
let delta = movement.bounds_to_scale_transform(center, size);
|
||||
|
||||
let selected = data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
let selected = tool_data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
let mut selected = Selected::new(&mut bounds.original_transforms, &mut bounds.pivot, &selected, responses, &document.graphene_document);
|
||||
|
||||
selected.update_transforms(delta);
|
||||
@@ -500,9 +507,9 @@ impl Fsm for SelectToolFsmState {
|
||||
ResizingBounds
|
||||
}
|
||||
(RotatingBounds, PointerMove { snap_angle, .. }) => {
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
let angle = {
|
||||
let start_offset = data.drag_start - bounds.pivot;
|
||||
let start_offset = tool_data.drag_start - bounds.pivot;
|
||||
let end_offset = input.mouse.position - bounds.pivot;
|
||||
|
||||
start_offset.angle_between(end_offset)
|
||||
@@ -517,7 +524,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
let delta = DAffine2::from_angle(snapped_angle);
|
||||
|
||||
let selected = data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
let selected = tool_data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
let mut selected = Selected::new(&mut bounds.original_transforms, &mut bounds.pivot, &selected, responses, &document.graphene_document);
|
||||
|
||||
selected.update_transforms(delta);
|
||||
@@ -526,13 +533,13 @@ impl Fsm for SelectToolFsmState {
|
||||
RotatingBounds
|
||||
}
|
||||
(DrawingBox, PointerMove { .. }) => {
|
||||
data.drag_current = input.mouse.position;
|
||||
tool_data.drag_current = input.mouse.position;
|
||||
|
||||
responses.push_front(
|
||||
DocumentMessage::Overlays(
|
||||
Operation::SetLayerTransformInViewport {
|
||||
path: data.drag_box_overlay_layer.clone().unwrap(),
|
||||
transform: transform_from_box(data.drag_start, data.drag_current, DAffine2::IDENTITY).to_cols_array(),
|
||||
path: tool_data.drag_box_overlay_layer.clone().unwrap(),
|
||||
transform: transform_from_box(tool_data.drag_start, tool_data.drag_current, DAffine2::IDENTITY).to_cols_array(),
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
@@ -541,73 +548,73 @@ impl Fsm for SelectToolFsmState {
|
||||
DrawingBox
|
||||
}
|
||||
(Ready, PointerMove { .. }) => {
|
||||
let cursor = data.bounding_box_overlays.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true));
|
||||
let cursor = tool_data.bounding_box_overlays.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true));
|
||||
|
||||
// Generate the select outline (but not if the user is going to use the bound overlays)
|
||||
if cursor == MouseCursorIcon::Default {
|
||||
// Get the layer the user is hovering over
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
||||
let mut intersection = document.graphene_document.intersects_quad_root(quad);
|
||||
let mut intersection = document.graphene_document.intersects_quad_root(quad, font_cache);
|
||||
|
||||
// If the user is hovering over a layer they have not already selected, then update outline
|
||||
if let Some(path) = intersection.pop() {
|
||||
if !document.selected_visible_layers().any(|visible| visible == path.as_slice()) {
|
||||
data.path_outlines.update_hovered(path, document, responses)
|
||||
tool_data.path_outlines.update_hovered(path, document, responses, font_cache)
|
||||
} else {
|
||||
data.path_outlines.clear_hovered(responses);
|
||||
tool_data.path_outlines.clear_hovered(responses);
|
||||
}
|
||||
} else {
|
||||
data.path_outlines.clear_hovered(responses);
|
||||
tool_data.path_outlines.clear_hovered(responses);
|
||||
}
|
||||
} else {
|
||||
data.path_outlines.clear_hovered(responses);
|
||||
tool_data.path_outlines.clear_hovered(responses);
|
||||
}
|
||||
|
||||
if data.cursor != cursor {
|
||||
data.cursor = cursor;
|
||||
if tool_data.cursor != cursor {
|
||||
tool_data.cursor = cursor;
|
||||
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor }.into());
|
||||
}
|
||||
|
||||
Ready
|
||||
}
|
||||
(Dragging, DragStop) => {
|
||||
let response = match input.mouse.position.distance(data.drag_start) < 10. * f64::EPSILON {
|
||||
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
||||
true => DocumentMessage::Undo,
|
||||
false => DocumentMessage::CommitTransaction,
|
||||
};
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
responses.push_front(response.into());
|
||||
Ready
|
||||
}
|
||||
(ResizingBounds, DragStop) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
bounds.original_transforms.clear();
|
||||
}
|
||||
|
||||
Ready
|
||||
}
|
||||
(RotatingBounds, DragStop) => {
|
||||
if let Some(bounds) = &mut data.bounding_box_overlays {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
bounds.original_transforms.clear();
|
||||
}
|
||||
|
||||
Ready
|
||||
}
|
||||
(DrawingBox, DragStop) => {
|
||||
let quad = data.selection_quad();
|
||||
let quad = tool_data.selection_quad();
|
||||
responses.push_front(
|
||||
DocumentMessage::AddSelectedLayers {
|
||||
additional_layers: document.graphene_document.intersects_quad_root(quad),
|
||||
additional_layers: document.graphene_document.intersects_quad_root(quad, font_cache),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
responses.push_front(
|
||||
DocumentMessage::Overlays(
|
||||
Operation::DeleteLayer {
|
||||
path: data.drag_box_overlay_layer.take().unwrap(),
|
||||
path: tool_data.drag_box_overlay_layer.take().unwrap(),
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
@@ -616,19 +623,19 @@ impl Fsm for SelectToolFsmState {
|
||||
Ready
|
||||
}
|
||||
(Dragging, Abort) => {
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
responses.push_back(DocumentMessage::Undo.into());
|
||||
|
||||
data.path_outlines.clear_selected(responses);
|
||||
tool_data.path_outlines.clear_selected(responses);
|
||||
|
||||
Ready
|
||||
}
|
||||
(_, Abort) => {
|
||||
if let Some(path) = data.drag_box_overlay_layer.take() {
|
||||
if let Some(path) = tool_data.drag_box_overlay_layer.take() {
|
||||
responses.push_front(DocumentMessage::Overlays(Operation::DeleteLayer { path }.into()).into())
|
||||
};
|
||||
if let Some(mut bounding_box_overlays) = data.bounding_box_overlays.take() {
|
||||
let selected = data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
if let Some(mut bounding_box_overlays) = tool_data.bounding_box_overlays.take() {
|
||||
let selected = tool_data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
let mut selected = Selected::new(
|
||||
&mut bounding_box_overlays.original_transforms,
|
||||
&mut bounding_box_overlays.pivot,
|
||||
@@ -642,10 +649,10 @@ impl Fsm for SelectToolFsmState {
|
||||
bounding_box_overlays.delete(responses);
|
||||
}
|
||||
|
||||
data.path_outlines.clear_hovered(responses);
|
||||
data.path_outlines.clear_selected(responses);
|
||||
tool_data.path_outlines.clear_hovered(responses);
|
||||
tool_data.path_outlines.clear_selected(responses);
|
||||
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
Ready
|
||||
}
|
||||
(_, Align { axis, aggregate }) => {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use super::shared::resize::Resize;
|
||||
use crate::consts::DRAG_THRESHOLD;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{LayoutRow, NumberInput, PropertyHolder, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::layers::style;
|
||||
use graphene::Operation;
|
||||
@@ -18,7 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct ShapeTool {
|
||||
fsm_state: ShapeToolFsmState,
|
||||
data: ShapeToolData,
|
||||
tool_data: ShapeToolData,
|
||||
options: ShapeOptions,
|
||||
}
|
||||
|
||||
@@ -34,7 +32,7 @@ impl Default for ShapeOptions {
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Shape)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum ShapeToolMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -51,7 +49,7 @@ pub enum ShapeToolMessage {
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum ShapeOptionsUpdate {
|
||||
Vertices(u32),
|
||||
}
|
||||
@@ -73,7 +71,7 @@ impl PropertyHolder for ShapeTool {
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for ShapeTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -91,7 +89,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for ShapeTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -134,34 +132,32 @@ impl Fsm for ShapeToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use ShapeToolFsmState::*;
|
||||
use ShapeToolMessage::*;
|
||||
|
||||
let mut shape_data = &mut data.data;
|
||||
let mut shape_data = &mut tool_data.data;
|
||||
|
||||
if let ToolMessage::Shape(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input.mouse.position);
|
||||
shape_data.start(responses, document, input.mouse.position, font_cache);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
data.sides = tool_options.vertices;
|
||||
tool_data.sides = tool_options.vertices;
|
||||
|
||||
responses.push_back(
|
||||
Operation::AddNgon {
|
||||
path: shape_data.path.clone().unwrap(),
|
||||
insert_index: -1,
|
||||
transform: DAffine2::ZERO.to_cols_array(),
|
||||
sides: data.sides,
|
||||
style: style::PathStyle::new(None, style::Fill::solid(tool_data.primary_color)),
|
||||
sides: tool_data.sides,
|
||||
style: style::PathStyle::new(None, style::Fill::solid(global_tool_data.primary_color)),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::message_prelude::*;
|
||||
|
||||
use graphene::layers::layer_info::LayerDataType;
|
||||
use graphene::layers::style::{self, Fill, Stroke};
|
||||
use graphene::layers::text_layer::FontCache;
|
||||
use graphene::{LayerId, Operation};
|
||||
|
||||
use glam::DAffine2;
|
||||
@@ -20,16 +21,22 @@ pub struct PathOutline {
|
||||
|
||||
impl PathOutline {
|
||||
/// Creates an outline of a layer either with a pre-existing overlay or by generating a new one
|
||||
fn create_outline(document_layer_path: Vec<LayerId>, overlay_path: Option<Vec<LayerId>>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Option<Vec<LayerId>> {
|
||||
fn create_outline(
|
||||
document_layer_path: Vec<LayerId>,
|
||||
overlay_path: Option<Vec<LayerId>>,
|
||||
document: &DocumentMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
font_cache: &FontCache,
|
||||
) -> Option<Vec<LayerId>> {
|
||||
// Get layer data
|
||||
let document_layer = document.graphene_document.layer(&document_layer_path).ok()?;
|
||||
|
||||
// Get the bezpath from the shape or text
|
||||
let path = match &document_layer.data {
|
||||
LayerDataType::Shape(shape) => Some(shape.path.clone()),
|
||||
LayerDataType::Text(text) => Some(text.to_bez_path_nonmut(&document.graphene_document.font_cache)),
|
||||
LayerDataType::Text(text) => Some(text.to_bez_path_nonmut(font_cache)),
|
||||
_ => document_layer
|
||||
.aabounding_box_for_transform(DAffine2::IDENTITY, &document.graphene_document.font_cache)
|
||||
.aabounding_box_for_transform(DAffine2::IDENTITY, font_cache)
|
||||
.map(|bounds| kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y).to_path(0.)),
|
||||
}?;
|
||||
|
||||
@@ -78,10 +85,10 @@ impl PathOutline {
|
||||
}
|
||||
|
||||
/// Updates the overlay, generating a new one if necessary
|
||||
pub fn update_hovered(&mut self, new_layer_path: Vec<LayerId>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn update_hovered(&mut self, new_layer_path: Vec<LayerId>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
// Check if we are hovering over a different layer than before
|
||||
if self.hovered_layer_path.as_ref().map_or(true, |old| &new_layer_path != old) {
|
||||
self.hovered_overlay_path = Self::create_outline(new_layer_path.clone(), self.hovered_overlay_path.take(), document, responses);
|
||||
self.hovered_overlay_path = Self::create_outline(new_layer_path.clone(), self.hovered_overlay_path.take(), document, responses, font_cache);
|
||||
if self.hovered_overlay_path.is_none() {
|
||||
self.clear_hovered(responses);
|
||||
}
|
||||
@@ -98,11 +105,11 @@ impl PathOutline {
|
||||
}
|
||||
|
||||
/// Updates the selected overlays, generating or removing overlays if necessary
|
||||
pub fn update_selected<'a>(&mut self, selected: impl Iterator<Item = &'a [LayerId]>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn update_selected<'a>(&mut self, selected: impl Iterator<Item = &'a [LayerId]>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
let mut old_overlay_paths = std::mem::take(&mut self.selected_overlay_paths);
|
||||
|
||||
for document_layer_path in selected {
|
||||
if let Some(overlay_path) = Self::create_outline(document_layer_path.to_vec(), old_overlay_paths.pop(), document, responses) {
|
||||
if let Some(overlay_path) = Self::create_outline(document_layer_path.to_vec(), old_overlay_paths.pop(), document, responses, font_cache) {
|
||||
self.selected_overlay_paths.push(overlay_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::message_prelude::*;
|
||||
use crate::viewport_tools::snapping::SnapHandler;
|
||||
|
||||
use graphene::layers::text_layer::FontCache;
|
||||
use graphene::Operation;
|
||||
|
||||
use glam::{DAffine2, DVec2, Vec2Swizzles};
|
||||
@@ -18,8 +19,8 @@ pub struct Resize {
|
||||
|
||||
impl Resize {
|
||||
/// Starts a resize, assigning the snap targets and snapping the starting position.
|
||||
pub fn start(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, mouse_position: DVec2) {
|
||||
self.snap_handler.start_snap(document, document.bounding_boxes(None, None), true, true);
|
||||
pub fn start(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, mouse_position: DVec2, font_cache: &FontCache) {
|
||||
self.snap_handler.start_snap(document, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
self.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
self.drag_start = self.snap_handler.snap_position(responses, document, mouse_position);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use crate::consts::DRAG_THRESHOLD;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{LayoutRow, NumberInput, PropertyHolder, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
@@ -18,7 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Default)]
|
||||
pub struct SplineTool {
|
||||
fsm_state: SplineToolFsmState,
|
||||
data: SplineToolData,
|
||||
tool_data: SplineToolData,
|
||||
options: SplineOptions,
|
||||
}
|
||||
|
||||
@@ -78,7 +76,7 @@ impl PropertyHolder for SplineTool {
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for SplineTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -96,7 +94,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for SplineTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -136,11 +134,9 @@ impl Fsm for SplineToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use SplineToolFsmState::*;
|
||||
@@ -153,62 +149,62 @@ impl Fsm for SplineToolFsmState {
|
||||
(Ready, DragStart) => {
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
data.path = Some(document.get_path_for_new_layer());
|
||||
tool_data.path = Some(document.get_path_for_new_layer());
|
||||
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(None, None), true, true);
|
||||
data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
tool_data.snap_handler.start_snap(document, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_handler.add_all_document_handles(document, &[], &[]);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
|
||||
data.points.push(pos);
|
||||
data.next_point = pos;
|
||||
tool_data.points.push(pos);
|
||||
tool_data.next_point = pos;
|
||||
|
||||
data.weight = tool_options.line_weight;
|
||||
tool_data.weight = tool_options.line_weight;
|
||||
|
||||
responses.push_back(add_spline(data, tool_data, true));
|
||||
responses.push_back(add_spline(tool_data, global_tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
|
||||
if let Some(last_pos) = data.points.last() {
|
||||
if let Some(last_pos) = tool_data.points.last() {
|
||||
if last_pos.distance(pos) > DRAG_THRESHOLD {
|
||||
data.points.push(pos);
|
||||
data.next_point = pos;
|
||||
tool_data.points.push(pos);
|
||||
tool_data.next_point = pos;
|
||||
}
|
||||
}
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_spline(data, tool_data, true));
|
||||
responses.push_back(remove_preview(tool_data));
|
||||
responses.push_back(add_spline(tool_data, global_tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, PointerMove) => {
|
||||
let snapped_position = data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
let snapped_position = tool_data.snap_handler.snap_position(responses, document, input.mouse.position);
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
data.next_point = pos;
|
||||
tool_data.next_point = pos;
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_spline(data, tool_data, true));
|
||||
responses.push_back(remove_preview(tool_data));
|
||||
responses.push_back(add_spline(tool_data, global_tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, Confirm) | (Drawing, Abort) => {
|
||||
if data.points.len() >= 2 {
|
||||
if tool_data.points.len() >= 2 {
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_spline(data, tool_data, false));
|
||||
responses.push_back(remove_preview(tool_data));
|
||||
responses.push_back(add_spline(tool_data, global_tool_data, false));
|
||||
responses.push_back(DocumentMessage::CommitTransaction.into());
|
||||
} else {
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
}
|
||||
|
||||
data.path = None;
|
||||
data.points.clear();
|
||||
data.snap_handler.cleanup(responses);
|
||||
tool_data.path = None;
|
||||
tool_data.points.clear();
|
||||
tool_data.snap_handler.cleanup(responses);
|
||||
|
||||
Ready
|
||||
}
|
||||
@@ -251,22 +247,25 @@ impl Fsm for SplineToolFsmState {
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_preview(data: &SplineToolData) -> Message {
|
||||
Operation::DeleteLayer { path: data.path.clone().unwrap() }.into()
|
||||
fn remove_preview(tool_data: &SplineToolData) -> Message {
|
||||
Operation::DeleteLayer {
|
||||
path: tool_data.path.clone().unwrap(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn add_spline(data: &SplineToolData, tool_data: &DocumentToolData, show_preview: bool) -> Message {
|
||||
let mut points: Vec<(f64, f64)> = data.points.iter().map(|p| (p.x, p.y)).collect();
|
||||
fn add_spline(tool_data: &SplineToolData, global_tool_data: &DocumentToolData, show_preview: bool) -> Message {
|
||||
let mut points: Vec<(f64, f64)> = tool_data.points.iter().map(|p| (p.x, p.y)).collect();
|
||||
if show_preview {
|
||||
points.push((data.next_point.x, data.next_point.y))
|
||||
points.push((tool_data.next_point.x, tool_data.next_point.y))
|
||||
}
|
||||
|
||||
Operation::AddSpline {
|
||||
path: data.path.clone().unwrap(),
|
||||
path: tool_data.path.clone().unwrap(),
|
||||
insert_index: -1,
|
||||
transform: DAffine2::IDENTITY.to_cols_array(),
|
||||
points,
|
||||
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, data.weight)), style::Fill::None),
|
||||
style: style::PathStyle::new(Some(style::Stroke::new(global_tool_data.primary_color, tool_data.weight)), style::Fill::None),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -2,25 +2,25 @@ use crate::consts::{COLOR_ACCENT, SELECTION_TOLERANCE};
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::layout_message::LayoutTarget;
|
||||
use crate::layout::widgets::{FontInput, LayoutRow, NumberInput, PropertyHolder, Separator, SeparatorDirection, SeparatorType, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
|
||||
use crate::message_prelude::*;
|
||||
use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup};
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
use crate::viewport_tools::tool::{Fsm, ToolActionHandlerData};
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene::document::FontCache;
|
||||
use graphene::intersection::Quad;
|
||||
use graphene::layers::style::{self, Fill, Stroke};
|
||||
use graphene::layers::text_layer::FontCache;
|
||||
use graphene::Operation;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use kurbo::Shape;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TextTool {
|
||||
fsm_state: TextToolFsmState,
|
||||
data: TextToolData,
|
||||
tool_data: TextToolData,
|
||||
options: TextOptions,
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ pub struct TextOptions {
|
||||
font_size: u32,
|
||||
font_name: String,
|
||||
font_style: String,
|
||||
font_file: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for TextOptions {
|
||||
@@ -37,14 +36,13 @@ impl Default for TextOptions {
|
||||
font_size: 24,
|
||||
font_name: "Merriweather".into(),
|
||||
font_style: "Normal (400)".into(),
|
||||
font_file: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Text)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum TextMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
@@ -66,9 +64,9 @@ pub enum TextMessage {
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum TextOptionsUpdate {
|
||||
Font { family: String, style: String, file: String },
|
||||
Font { family: String, style: String },
|
||||
FontSize(u32),
|
||||
}
|
||||
|
||||
@@ -84,11 +82,9 @@ impl PropertyHolder for TextTool {
|
||||
TextMessage::UpdateOptions(TextOptionsUpdate::Font {
|
||||
family: font_input.font_family.clone(),
|
||||
style: font_input.font_style.clone(),
|
||||
file: font_input.font_file_url.clone(),
|
||||
})
|
||||
.into()
|
||||
}),
|
||||
..Default::default()
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
@@ -102,11 +98,9 @@ impl PropertyHolder for TextTool {
|
||||
TextMessage::UpdateOptions(TextOptionsUpdate::Font {
|
||||
family: font_input.font_family.clone(),
|
||||
style: font_input.font_style.clone(),
|
||||
file: font_input.font_file_url.clone(),
|
||||
})
|
||||
.into()
|
||||
}),
|
||||
..Default::default()
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
@@ -127,7 +121,7 @@ impl PropertyHolder for TextTool {
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for TextTool {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
fn process_action(&mut self, action: ToolMessage, tool_data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
@@ -140,10 +134,9 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for TextTool {
|
||||
|
||||
if let ToolMessage::Text(TextMessage::UpdateOptions(action)) = action {
|
||||
match action {
|
||||
TextOptionsUpdate::Font { family, style, file } => {
|
||||
TextOptionsUpdate::Font { family, style } => {
|
||||
self.options.font_name = family;
|
||||
self.options.font_style = style;
|
||||
self.options.font_file = Some(file);
|
||||
|
||||
self.register_properties(responses, LayoutTarget::ToolOptions);
|
||||
}
|
||||
@@ -152,7 +145,7 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for TextTool {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
let new_state = self.fsm_state.transition(action, &mut self.tool_data, tool_data, &self.options, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
@@ -211,13 +204,13 @@ fn resize_overlays(overlays: &mut Vec<Vec<LayerId>>, responses: &mut VecDeque<Me
|
||||
}
|
||||
}
|
||||
|
||||
fn update_overlays(document: &DocumentMessageHandler, data: &mut TextToolData, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
fn update_overlays(document: &DocumentMessageHandler, tool_data: &mut TextToolData, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
let visible_text_layers = document.selected_visible_text_layers().collect::<Vec<_>>();
|
||||
resize_overlays(&mut data.overlays, responses, visible_text_layers.len());
|
||||
resize_overlays(&mut tool_data.overlays, responses, visible_text_layers.len());
|
||||
|
||||
let bounds = visible_text_layers
|
||||
.into_iter()
|
||||
.zip(&data.overlays)
|
||||
.zip(&tool_data.overlays)
|
||||
.filter_map(|(layer_path, overlay_path)| {
|
||||
document
|
||||
.graphene_document
|
||||
@@ -237,7 +230,7 @@ fn update_overlays(document: &DocumentMessageHandler, data: &mut TextToolData, r
|
||||
};
|
||||
responses.push_back(DocumentMessage::Overlays(operation.into()).into());
|
||||
}
|
||||
resize_overlays(&mut data.overlays, responses, new_len);
|
||||
resize_overlays(&mut tool_data.overlays, responses, new_len);
|
||||
}
|
||||
|
||||
impl Fsm for TextToolFsmState {
|
||||
@@ -247,11 +240,9 @@ impl Fsm for TextToolFsmState {
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use TextMessage::*;
|
||||
@@ -260,7 +251,7 @@ impl Fsm for TextToolFsmState {
|
||||
if let ToolMessage::Text(event) = event {
|
||||
match (self, event) {
|
||||
(state, DocumentIsDirty) => {
|
||||
update_overlays(document, data, responses, &document.graphene_document.font_cache);
|
||||
update_overlays(document, tool_data, responses, font_cache);
|
||||
|
||||
state
|
||||
}
|
||||
@@ -271,7 +262,7 @@ impl Fsm for TextToolFsmState {
|
||||
|
||||
let new_state = if let Some(l) = document
|
||||
.graphene_document
|
||||
.intersects_quad_root(quad)
|
||||
.intersects_quad_root(quad, font_cache)
|
||||
.last()
|
||||
.filter(|l| document.graphene_document.layer(l).map(|l| l.as_text().is_ok()).unwrap_or(false))
|
||||
// Editing existing text
|
||||
@@ -279,25 +270,25 @@ impl Fsm for TextToolFsmState {
|
||||
if state == TextToolFsmState::Editing {
|
||||
responses.push_back(
|
||||
DocumentMessage::SetTexboxEditability {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
editable: false,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
data.path = l.clone();
|
||||
tool_data.path = l.clone();
|
||||
|
||||
responses.push_back(
|
||||
DocumentMessage::SetTexboxEditability {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
editable: true,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
responses.push_back(
|
||||
DocumentMessage::SetSelectedLayers {
|
||||
replacement_selected_layers: vec![data.path.clone()],
|
||||
replacement_selected_layers: vec![tool_data.path.clone()],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
@@ -310,28 +301,32 @@ impl Fsm for TextToolFsmState {
|
||||
let font_size = tool_options.font_size;
|
||||
let font_name = tool_options.font_name.clone();
|
||||
let font_style = tool_options.font_style.clone();
|
||||
let font_file = tool_options.font_file.clone();
|
||||
data.path = document.get_path_for_new_layer();
|
||||
tool_data.path = document.get_path_for_new_layer();
|
||||
|
||||
responses.push_back(
|
||||
Operation::AddText {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
transform: DAffine2::ZERO.to_cols_array(),
|
||||
insert_index: -1,
|
||||
text: r#""#.to_string(),
|
||||
style: style::PathStyle::new(None, Fill::solid(tool_data.primary_color)),
|
||||
style: style::PathStyle::new(None, Fill::solid(global_tool_data.primary_color)),
|
||||
size: font_size as f64,
|
||||
font_name,
|
||||
font_style,
|
||||
font_file,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
responses.push_back(Operation::SetLayerTransformInViewport { path: data.path.clone(), transform }.into());
|
||||
responses.push_back(
|
||||
Operation::SetLayerTransformInViewport {
|
||||
path: tool_data.path.clone(),
|
||||
transform,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
responses.push_back(
|
||||
DocumentMessage::SetTexboxEditability {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
editable: true,
|
||||
}
|
||||
.into(),
|
||||
@@ -339,7 +334,7 @@ impl Fsm for TextToolFsmState {
|
||||
|
||||
responses.push_back(
|
||||
DocumentMessage::SetSelectedLayers {
|
||||
replacement_selected_layers: vec![data.path.clone()],
|
||||
replacement_selected_layers: vec![tool_data.path.clone()],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
@@ -349,13 +344,13 @@ impl Fsm for TextToolFsmState {
|
||||
// Removing old text as editable
|
||||
responses.push_back(
|
||||
DocumentMessage::SetTexboxEditability {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
editable: false,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
resize_overlays(&mut data.overlays, responses, 0);
|
||||
resize_overlays(&mut tool_data.overlays, responses, 0);
|
||||
|
||||
Ready
|
||||
};
|
||||
@@ -366,14 +361,14 @@ impl Fsm for TextToolFsmState {
|
||||
if state == TextToolFsmState::Editing {
|
||||
responses.push_back(
|
||||
DocumentMessage::SetTexboxEditability {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
editable: false,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
resize_overlays(&mut data.overlays, responses, 0);
|
||||
resize_overlays(&mut tool_data.overlays, responses, 0);
|
||||
|
||||
Ready
|
||||
}
|
||||
@@ -383,35 +378,41 @@ impl Fsm for TextToolFsmState {
|
||||
Editing
|
||||
}
|
||||
(Editing, TextChange { new_text }) => {
|
||||
responses.push_back(Operation::SetTextContent { path: data.path.clone(), new_text }.into());
|
||||
responses.push_back(
|
||||
Operation::SetTextContent {
|
||||
path: tool_data.path.clone(),
|
||||
new_text,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
responses.push_back(
|
||||
DocumentMessage::SetTexboxEditability {
|
||||
path: data.path.clone(),
|
||||
path: tool_data.path.clone(),
|
||||
editable: false,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
resize_overlays(&mut data.overlays, responses, 0);
|
||||
resize_overlays(&mut tool_data.overlays, responses, 0);
|
||||
|
||||
Ready
|
||||
}
|
||||
(Editing, UpdateBounds { new_text }) => {
|
||||
resize_overlays(&mut data.overlays, responses, 1);
|
||||
let text = document.graphene_document.layer(&data.path).unwrap().as_text().unwrap();
|
||||
let mut path = text.bounding_box(&new_text, text.load_face(&document.graphene_document.font_cache)).to_path(0.1);
|
||||
resize_overlays(&mut tool_data.overlays, responses, 1);
|
||||
let text = document.graphene_document.layer(&tool_data.path).unwrap().as_text().unwrap();
|
||||
let mut path = text.bounding_box(&new_text, text.load_face(font_cache)).to_path(0.1);
|
||||
|
||||
fn glam_to_kurbo(transform: DAffine2) -> kurbo::Affine {
|
||||
kurbo::Affine::new(transform.to_cols_array())
|
||||
}
|
||||
|
||||
path.apply_affine(glam_to_kurbo(document.graphene_document.multiply_transforms(&data.path).unwrap()));
|
||||
path.apply_affine(glam_to_kurbo(document.graphene_document.multiply_transforms(&tool_data.path).unwrap()));
|
||||
|
||||
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
|
||||
|
||||
let operation = Operation::SetLayerTransformInViewport {
|
||||
path: data.overlays[0].clone(),
|
||||
path: tool_data.overlays[0].clone(),
|
||||
transform: transform_from_box(DVec2::new(x0, y0), DVec2::new(x1, y1)),
|
||||
};
|
||||
responses.push_back(DocumentMessage::Overlays(operation.into()).into());
|
||||
|
||||
@@ -6,7 +6,7 @@ pub const ROUNDING_BIAS: f64 = 0.0001;
|
||||
pub const MINIMUM_MIRROR_THRESHOLD: f64 = 0.1;
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum ControlPointType {
|
||||
Anchor = 0,
|
||||
Handle1 = 1,
|
||||
|
||||
Reference in New Issue
Block a user