mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Implement the Spline Tool (#512)
* Add Spline Tool * Adapt to changes from master * Apply review feedback * Fixes Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
committed by
Keavon Chambers
parent
45edeb2a2b
commit
f8e72be492
@@ -19,6 +19,8 @@ pub const SNAP_TOLERANCE: f64 = 3.;
|
||||
pub const SNAP_OVERLAY_FADE_DISTANCE: f64 = 20.;
|
||||
pub const SNAP_OVERLAY_UNSNAPPED_OPACITY: f64 = 0.4;
|
||||
|
||||
pub const DRAG_THRESHOLD: f64 = 1.;
|
||||
|
||||
// Transforming layer
|
||||
pub const ROTATE_SNAP_ANGLE: f64 = 15.;
|
||||
pub const SCALE_SNAP_INTERVAL: f64 = 0.1;
|
||||
|
||||
@@ -109,6 +109,13 @@ impl Default for Mapping {
|
||||
entry! {action=FreehandMessage::PointerMove, message=InputMapperMessage::PointerMove},
|
||||
entry! {action=FreehandMessage::DragStart, key_down=Lmb},
|
||||
entry! {action=FreehandMessage::DragStop, key_up=Lmb},
|
||||
// Spline
|
||||
entry! {action=SplineMessage::PointerMove, message=InputMapperMessage::PointerMove},
|
||||
entry! {action=SplineMessage::DragStart, key_down=Lmb},
|
||||
entry! {action=SplineMessage::DragStop, key_up=Lmb},
|
||||
entry! {action=SplineMessage::Confirm, key_down=Rmb},
|
||||
entry! {action=SplineMessage::Confirm, key_down=KeyEscape},
|
||||
entry! {action=SplineMessage::Confirm, key_down=KeyEnter},
|
||||
// Fill
|
||||
entry! {action=FillMessage::LeftMouseDown, key_down=Lmb},
|
||||
entry! {action=FillMessage::RightMouseDown, key_down=Rmb},
|
||||
|
||||
@@ -83,6 +83,7 @@ pub mod message_prelude {
|
||||
pub use crate::viewport_tools::tools::rectangle::{RectangleMessage, RectangleMessageDiscriminant};
|
||||
pub use crate::viewport_tools::tools::select::{SelectMessage, SelectMessageDiscriminant};
|
||||
pub use crate::viewport_tools::tools::shape::{ShapeMessage, ShapeMessageDiscriminant};
|
||||
pub use crate::viewport_tools::tools::spline::{SplineMessage, SplineMessageDiscriminant};
|
||||
pub use crate::viewport_tools::tools::text::{TextMessage, TextMessageDiscriminant};
|
||||
pub use graphite_proc_macros::*;
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ impl Default for ToolFsmState {
|
||||
Path => path::Path,
|
||||
Pen => pen::Pen,
|
||||
Freehand => freehand::Freehand,
|
||||
// Spline => spline::Spline,
|
||||
Spline => spline::Spline,
|
||||
Line => line::Line,
|
||||
Rectangle => rectangle::Rectangle,
|
||||
Ellipse => ellipse::Ellipse,
|
||||
@@ -225,7 +225,7 @@ pub fn standard_tool_message(tool: ToolType, message_type: StandardToolMessageTy
|
||||
ToolType::Path => Some(PathMessage::Abort.into()),
|
||||
ToolType::Pen => Some(PenMessage::Abort.into()),
|
||||
ToolType::Freehand => Some(FreehandMessage::Abort.into()),
|
||||
// ToolType::Spline => Some(SplineMessage::Abort.into()),
|
||||
ToolType::Spline => Some(SplineMessage::Abort.into()),
|
||||
ToolType::Line => Some(LineMessage::Abort.into()),
|
||||
ToolType::Rectangle => Some(RectangleMessage::Abort.into()),
|
||||
ToolType::Ellipse => Some(EllipseMessage::Abort.into()),
|
||||
@@ -259,7 +259,7 @@ pub fn message_to_tool_type(message: &ToolMessage) -> ToolType {
|
||||
Path(_) => ToolType::Path,
|
||||
Pen(_) => ToolType::Pen,
|
||||
Freehand(_) => ToolType::Freehand,
|
||||
// Spline(_) => ToolType::Spline,
|
||||
Spline(_) => ToolType::Spline,
|
||||
Line(_) => ToolType::Line,
|
||||
Rectangle(_) => ToolType::Rectangle,
|
||||
Ellipse(_) => ToolType::Ellipse,
|
||||
|
||||
@@ -61,9 +61,9 @@ pub enum ToolMessage {
|
||||
#[remain::unsorted]
|
||||
#[child]
|
||||
Freehand(FreehandMessage),
|
||||
// #[remain::unsorted]
|
||||
// #[child]
|
||||
// Spline(SplineMessage),
|
||||
#[remain::unsorted]
|
||||
#[child]
|
||||
Spline(SplineMessage),
|
||||
#[remain::unsorted]
|
||||
#[child]
|
||||
Line(LineMessage),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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};
|
||||
@@ -134,8 +135,7 @@ impl Fsm for EllipseToolFsmState {
|
||||
state
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
// TODO: introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
|
||||
match shape_data.drag_start == input.mouse.position {
|
||||
match shape_data.drag_start.distance(input.mouse.position) <= DRAG_THRESHOLD {
|
||||
true => responses.push_back(DocumentMessage::AbortTransaction.into()),
|
||||
false => responses.push_back(DocumentMessage::CommitTransaction.into()),
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ impl Fsm for FreehandToolFsmState {
|
||||
|
||||
data.weight = tool_options.line_weight;
|
||||
|
||||
responses.push_back(make_operation(data, tool_data));
|
||||
responses.push_back(add_polyline(data, tool_data));
|
||||
|
||||
Drawing
|
||||
}
|
||||
@@ -168,7 +168,7 @@ impl Fsm for FreehandToolFsmState {
|
||||
}
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(make_operation(data, tool_data));
|
||||
responses.push_back(add_polyline(data, tool_data));
|
||||
|
||||
Drawing
|
||||
}
|
||||
@@ -176,7 +176,7 @@ impl Fsm for FreehandToolFsmState {
|
||||
if data.points.len() >= 2 {
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(make_operation(data, tool_data));
|
||||
responses.push_back(add_polyline(data, tool_data));
|
||||
responses.push_back(DocumentMessage::CommitTransaction.into());
|
||||
} else {
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
@@ -217,7 +217,7 @@ fn remove_preview(data: &FreehandToolData) -> Message {
|
||||
Operation::DeleteLayer { path: data.path.clone().unwrap() }.into()
|
||||
}
|
||||
|
||||
fn make_operation(data: &FreehandToolData, tool_data: &DocumentToolData) -> Message {
|
||||
fn add_polyline(data: &FreehandToolData, tool_data: &DocumentToolData) -> Message {
|
||||
let points: Vec<(f64, f64)> = data.points.iter().map(|p| (p.x, p.y)).collect();
|
||||
|
||||
Operation::AddPolyline {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::consts::LINE_ROTATE_SNAP_ANGLE;
|
||||
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};
|
||||
@@ -188,8 +188,7 @@ impl Fsm for LineToolFsmState {
|
||||
data.drag_current = data.snap_handler.snap_position(responses, input.viewport_bounds.size(), document, input.mouse.position);
|
||||
data.snap_handler.cleanup(responses);
|
||||
|
||||
// TODO: introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
|
||||
match data.drag_start == input.mouse.position {
|
||||
match data.drag_start.distance(input.mouse.position) <= DRAG_THRESHOLD {
|
||||
true => responses.push_back(DocumentMessage::AbortTransaction.into()),
|
||||
false => responses.push_back(DocumentMessage::CommitTransaction.into()),
|
||||
}
|
||||
|
||||
@@ -11,4 +11,5 @@ pub mod rectangle;
|
||||
pub mod select;
|
||||
pub mod shape;
|
||||
pub mod shared;
|
||||
pub mod spline;
|
||||
pub mod text;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::consts::DRAG_THRESHOLD;
|
||||
use crate::document::DocumentMessageHandler;
|
||||
use crate::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::input::keyboard::{Key, MouseMotion};
|
||||
@@ -165,7 +166,7 @@ impl Fsm for PenToolFsmState {
|
||||
|
||||
data.weight = tool_options.line_weight;
|
||||
|
||||
responses.push_back(make_operation(data, tool_data, true));
|
||||
responses.push_back(add_polyline(data, tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
@@ -173,14 +174,15 @@ impl Fsm for PenToolFsmState {
|
||||
let snapped_position = data.snap_handler.snap_position(responses, input.viewport_bounds.size(), document, input.mouse.position);
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
|
||||
// TODO: introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
|
||||
if data.points.last() != Some(&pos) {
|
||||
data.points.push(pos);
|
||||
data.next_point = pos;
|
||||
if let Some(last_pos) = data.points.last() {
|
||||
if last_pos.distance(pos) > DRAG_THRESHOLD {
|
||||
data.points.push(pos);
|
||||
data.next_point = pos;
|
||||
}
|
||||
}
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(make_operation(data, tool_data, true));
|
||||
responses.push_back(add_polyline(data, tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
@@ -190,7 +192,7 @@ impl Fsm for PenToolFsmState {
|
||||
data.next_point = pos;
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(make_operation(data, tool_data, true));
|
||||
responses.push_back(add_polyline(data, tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
@@ -198,7 +200,7 @@ impl Fsm for PenToolFsmState {
|
||||
if data.points.len() >= 2 {
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(make_operation(data, tool_data, false));
|
||||
responses.push_back(add_polyline(data, tool_data, false));
|
||||
responses.push_back(DocumentMessage::CommitTransaction.into());
|
||||
} else {
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
@@ -253,7 +255,7 @@ fn remove_preview(data: &PenToolData) -> Message {
|
||||
Operation::DeleteLayer { path: data.path.clone().unwrap() }.into()
|
||||
}
|
||||
|
||||
fn make_operation(data: &PenToolData, tool_data: &DocumentToolData, show_preview: bool) -> Message {
|
||||
fn add_polyline(data: &PenToolData, tool_data: &DocumentToolData, show_preview: bool) -> Message {
|
||||
let mut points: Vec<(f64, f64)> = data.points.iter().map(|p| (p.x, p.y)).collect();
|
||||
if show_preview {
|
||||
points.push((data.next_point.x, data.next_point.y))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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};
|
||||
@@ -133,8 +134,7 @@ impl Fsm for RectangleToolFsmState {
|
||||
state
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
// TODO: introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
|
||||
match shape_data.drag_start == input.mouse.position {
|
||||
match shape_data.drag_start.distance(input.mouse.position) <= DRAG_THRESHOLD {
|
||||
true => responses.push_back(DocumentMessage::AbortTransaction.into()),
|
||||
false => responses.push_back(DocumentMessage::CommitTransaction.into()),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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};
|
||||
@@ -176,8 +177,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
state
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
// TODO: introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
|
||||
match shape_data.drag_start == input.mouse.position {
|
||||
match shape_data.drag_start.distance(input.mouse.position) <= DRAG_THRESHOLD {
|
||||
true => responses.push_back(DocumentMessage::AbortTransaction.into()),
|
||||
false => responses.push_back(DocumentMessage::CommitTransaction.into()),
|
||||
}
|
||||
|
||||
272
editor/src/viewport_tools/tools/spline.rs
Normal file
272
editor/src/viewport_tools/tools/spline.rs
Normal file
@@ -0,0 +1,272 @@
|
||||
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::snapping::SnapHandler;
|
||||
use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
|
||||
|
||||
use graphene::layers::style;
|
||||
use graphene::Operation;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Spline {
|
||||
fsm_state: SplineToolFsmState,
|
||||
data: SplineToolData,
|
||||
options: SplineOptions,
|
||||
}
|
||||
|
||||
pub struct SplineOptions {
|
||||
line_weight: u32,
|
||||
}
|
||||
|
||||
impl Default for SplineOptions {
|
||||
fn default() -> Self {
|
||||
Self { line_weight: 5 }
|
||||
}
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[impl_message(Message, ToolMessage, Spline)]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum SplineMessage {
|
||||
// Standard messages
|
||||
#[remain::unsorted]
|
||||
Abort,
|
||||
|
||||
// Tool-specific messages
|
||||
Confirm,
|
||||
DragStart,
|
||||
DragStop,
|
||||
PointerMove,
|
||||
Undo,
|
||||
UpdateOptions(SplineOptionsUpdate),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum SplineToolFsmState {
|
||||
Ready,
|
||||
Drawing,
|
||||
}
|
||||
|
||||
#[remain::sorted]
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub enum SplineOptionsUpdate {
|
||||
LineWeight(u32),
|
||||
}
|
||||
|
||||
impl PropertyHolder for Spline {
|
||||
fn properties(&self) -> WidgetLayout {
|
||||
WidgetLayout::new(vec![LayoutRow::Row {
|
||||
name: "".into(),
|
||||
widgets: vec![WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
unit: " px".into(),
|
||||
label: "Weight".into(),
|
||||
value: self.options.line_weight as f64,
|
||||
is_integer: true,
|
||||
min: Some(0.),
|
||||
on_update: WidgetCallback::new(|number_input| SplineMessage::UpdateOptions(SplineOptionsUpdate::LineWeight(number_input.value as u32)).into()),
|
||||
..NumberInput::default()
|
||||
}))],
|
||||
}])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Spline {
|
||||
fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque<Message>) {
|
||||
if action == ToolMessage::UpdateHints {
|
||||
self.fsm_state.update_hints(responses);
|
||||
return;
|
||||
}
|
||||
|
||||
if action == ToolMessage::UpdateCursor {
|
||||
self.fsm_state.update_cursor(responses);
|
||||
return;
|
||||
}
|
||||
|
||||
if let ToolMessage::Spline(SplineMessage::UpdateOptions(action)) = action {
|
||||
match action {
|
||||
SplineOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight,
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, &self.options, data.2, responses);
|
||||
|
||||
if self.fsm_state != new_state {
|
||||
self.fsm_state = new_state;
|
||||
self.fsm_state.update_hints(responses);
|
||||
self.fsm_state.update_cursor(responses);
|
||||
}
|
||||
}
|
||||
|
||||
fn actions(&self) -> ActionList {
|
||||
use SplineToolFsmState::*;
|
||||
|
||||
match self.fsm_state {
|
||||
Ready => actions!(SplineMessageDiscriminant; Undo, DragStart, DragStop, Confirm, Abort),
|
||||
Drawing => actions!(SplineMessageDiscriminant; DragStop, PointerMove, Confirm, Abort),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SplineToolFsmState {
|
||||
fn default() -> Self {
|
||||
SplineToolFsmState::Ready
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct SplineToolData {
|
||||
points: Vec<DVec2>,
|
||||
next_point: DVec2,
|
||||
weight: u32,
|
||||
path: Option<Vec<LayerId>>,
|
||||
snap_handler: SnapHandler,
|
||||
}
|
||||
|
||||
impl Fsm for SplineToolFsmState {
|
||||
type ToolData = SplineToolData;
|
||||
type ToolOptions = SplineOptions;
|
||||
|
||||
fn transition(
|
||||
self,
|
||||
event: ToolMessage,
|
||||
document: &DocumentMessageHandler,
|
||||
tool_data: &DocumentToolData,
|
||||
data: &mut Self::ToolData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
use SplineMessage::*;
|
||||
use SplineToolFsmState::*;
|
||||
|
||||
let transform = document.graphene_document.root.transform;
|
||||
|
||||
if let ToolMessage::Spline(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
data.path = Some(document.get_path_for_new_layer());
|
||||
|
||||
data.snap_handler.start_snap(document, document.bounding_boxes(None, None), true, true);
|
||||
let snapped_position = data.snap_handler.snap_position(responses, input.viewport_bounds.size(), document, input.mouse.position);
|
||||
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
|
||||
data.points.push(pos);
|
||||
data.next_point = pos;
|
||||
|
||||
data.weight = tool_options.line_weight;
|
||||
|
||||
responses.push_back(add_spline(data, tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, DragStop) => {
|
||||
let snapped_position = data.snap_handler.snap_position(responses, input.viewport_bounds.size(), document, input.mouse.position);
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
|
||||
if let Some(last_pos) = data.points.last() {
|
||||
if last_pos.distance(pos) > DRAG_THRESHOLD {
|
||||
data.points.push(pos);
|
||||
data.next_point = pos;
|
||||
}
|
||||
}
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_spline(data, tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, PointerMove) => {
|
||||
let snapped_position = data.snap_handler.snap_position(responses, input.viewport_bounds.size(), document, input.mouse.position);
|
||||
let pos = transform.inverse().transform_point2(snapped_position);
|
||||
data.next_point = pos;
|
||||
|
||||
responses.push_back(remove_preview(data));
|
||||
responses.push_back(add_spline(data, tool_data, true));
|
||||
|
||||
Drawing
|
||||
}
|
||||
(Drawing, Confirm) | (Drawing, Abort) => {
|
||||
if 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(DocumentMessage::CommitTransaction.into());
|
||||
} else {
|
||||
responses.push_back(DocumentMessage::AbortTransaction.into());
|
||||
}
|
||||
|
||||
data.path = None;
|
||||
data.points.clear();
|
||||
data.snap_handler.cleanup(responses);
|
||||
|
||||
Ready
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn update_hints(&self, responses: &mut VecDeque<Message>) {
|
||||
let hint_data = match self {
|
||||
SplineToolFsmState::Ready => HintData(vec![HintGroup(vec![HintInfo {
|
||||
key_groups: vec![],
|
||||
mouse: Some(MouseMotion::Lmb),
|
||||
label: String::from("Draw Spline"),
|
||||
plus: false,
|
||||
}])]),
|
||||
SplineToolFsmState::Drawing => HintData(vec![
|
||||
HintGroup(vec![HintInfo {
|
||||
key_groups: vec![],
|
||||
mouse: Some(MouseMotion::Lmb),
|
||||
label: String::from("Extend Spline"),
|
||||
plus: false,
|
||||
}]),
|
||||
HintGroup(vec![HintInfo {
|
||||
key_groups: vec![KeysGroup(vec![Key::KeyEnter])],
|
||||
mouse: None,
|
||||
label: String::from("End Spline"),
|
||||
plus: false,
|
||||
}]),
|
||||
]),
|
||||
};
|
||||
|
||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||
}
|
||||
|
||||
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_preview(data: &SplineToolData) -> Message {
|
||||
Operation::DeleteLayer { path: 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();
|
||||
if show_preview {
|
||||
points.push((data.next_point.x, data.next_point.y))
|
||||
}
|
||||
|
||||
Operation::AddSpline {
|
||||
path: 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 as f32)), None),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Reference in New Issue
Block a user