mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-30 01:44:07 +00:00
Add struct field visualization to the editor message hierarchy tree visualization on the website (#2917)
* Fix Message Tree: Enforce Structure and Visibility * Code review * fix the erroreous ouputs * error handling for MessageHandler * Fix website visualization HTML generation * error handling for tuple-style message enum variant * cleanup * Update messages * Normalize BroadcastEvent --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
5ed45ead6f
commit
17d70dc60e
59 changed files with 988 additions and 506 deletions
|
@ -61,8 +61,8 @@ impl WinitApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_messages_to_editor(&mut self, mut responses: Vec<FrontendMessage>) {
|
fn send_messages_to_editor(&mut self, mut responses: Vec<FrontendMessage>) {
|
||||||
for message in responses.extract_if(.., |m| matches!(m, FrontendMessage::RenderOverlays(_))) {
|
for message in responses.extract_if(.., |m| matches!(m, FrontendMessage::RenderOverlays { .. })) {
|
||||||
let FrontendMessage::RenderOverlays(overlay_context) = message else { unreachable!() };
|
let FrontendMessage::RenderOverlays { context: overlay_context } = message else { unreachable!() };
|
||||||
if let Some(graphics_state) = &mut self.graphics_state {
|
if let Some(graphics_state) = &mut self.graphics_state {
|
||||||
let scene = overlay_context.take_scene();
|
let scene = overlay_context.take_scene();
|
||||||
graphics_state.set_overlays_scene(scene);
|
graphics_state.set_overlays_scene(scene);
|
||||||
|
|
|
@ -52,7 +52,7 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
|
||||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
|
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
|
||||||
];
|
];
|
||||||
const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[
|
const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[
|
||||||
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::AnimationFrame)),
|
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(EventMessageDiscriminant::AnimationFrame)),
|
||||||
MessageDiscriminant::Animation(AnimationMessageDiscriminant::IncrementFrameCounter),
|
MessageDiscriminant::Animation(AnimationMessageDiscriminant::IncrementFrameCounter),
|
||||||
];
|
];
|
||||||
// TODO: Find a way to combine these with the list above. We use strings for now since these are the standard variant names used by multiple messages. But having these also type-checked would be best.
|
// TODO: Find a way to combine these with the list above. We use strings for now since these are the standard variant names used by multiple messages. But having these also type-checked would be best.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::messages::prelude::*;
|
|
||||||
|
|
||||||
use super::animation_message_handler::AnimationTimeMode;
|
use super::animation_message_handler::AnimationTimeMode;
|
||||||
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
#[impl_message(Message, Animation)]
|
#[impl_message(Message, Animation)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
|
|
@ -5,15 +5,15 @@ use crate::messages::prelude::*;
|
||||||
pub enum BroadcastMessage {
|
pub enum BroadcastMessage {
|
||||||
// Sub-messages
|
// Sub-messages
|
||||||
#[child]
|
#[child]
|
||||||
TriggerEvent(BroadcastEvent),
|
TriggerEvent(EventMessage),
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
SubscribeEvent {
|
SubscribeEvent {
|
||||||
on: BroadcastEvent,
|
on: EventMessage,
|
||||||
send: Box<Message>,
|
send: Box<Message>,
|
||||||
},
|
},
|
||||||
UnsubscribeEvent {
|
UnsubscribeEvent {
|
||||||
on: BroadcastEvent,
|
on: EventMessage,
|
||||||
message: Box<Message>,
|
send: Box<Message>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ use crate::messages::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, ExtractField)]
|
#[derive(Debug, Clone, Default, ExtractField)]
|
||||||
pub struct BroadcastMessageHandler {
|
pub struct BroadcastMessageHandler {
|
||||||
listeners: HashMap<BroadcastEvent, Vec<Message>>,
|
event: EventMessageHandler,
|
||||||
|
listeners: HashMap<EventMessage, Vec<Message>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
|
@ -10,19 +11,15 @@ impl MessageHandler<BroadcastMessage, ()> for BroadcastMessageHandler {
|
||||||
fn process_message(&mut self, message: BroadcastMessage, responses: &mut VecDeque<Message>, _: ()) {
|
fn process_message(&mut self, message: BroadcastMessage, responses: &mut VecDeque<Message>, _: ()) {
|
||||||
match message {
|
match message {
|
||||||
// Sub-messages
|
// Sub-messages
|
||||||
BroadcastMessage::TriggerEvent(event) => {
|
BroadcastMessage::TriggerEvent(message) => self.event.process_message(message, responses, EventMessageContext { listeners: &mut self.listeners }),
|
||||||
for message in self.listeners.entry(event).or_default() {
|
|
||||||
responses.add_front(message.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
BroadcastMessage::SubscribeEvent { on, send } => self.listeners.entry(on).or_default().push(*send),
|
BroadcastMessage::SubscribeEvent { on, send } => self.listeners.entry(on).or_default().push(*send),
|
||||||
BroadcastMessage::UnsubscribeEvent { on, message } => self.listeners.entry(on).or_default().retain(|msg| *msg != *message),
|
BroadcastMessage::UnsubscribeEvent { on, send } => self.listeners.entry(on).or_default().retain(|msg| *msg != *send),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn actions(&self) -> ActionList {
|
fn actions(&self) -> ActionList {
|
||||||
actions!(BroadcastEventDiscriminant;)
|
actions!(EventMessageDiscriminant;)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)]
|
|
||||||
#[impl_message(Message, BroadcastMessage, TriggerEvent)]
|
#[impl_message(Message, BroadcastMessage, TriggerEvent)]
|
||||||
pub enum BroadcastEvent {
|
#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)]
|
||||||
|
pub enum EventMessage {
|
||||||
/// Triggered by requestAnimationFrame in JS
|
/// Triggered by requestAnimationFrame in JS
|
||||||
AnimationFrame,
|
AnimationFrame,
|
||||||
CanvasTransformed,
|
CanvasTransformed,
|
22
editor/src/messages/broadcast/event/event_message_handler.rs
Normal file
22
editor/src/messages/broadcast/event/event_message_handler.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
|
#[derive(ExtractField)]
|
||||||
|
pub struct EventMessageContext<'a> {
|
||||||
|
pub listeners: &'a mut HashMap<EventMessage, Vec<Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, ExtractField)]
|
||||||
|
pub struct EventMessageHandler {}
|
||||||
|
|
||||||
|
#[message_handler_data]
|
||||||
|
impl MessageHandler<EventMessage, EventMessageContext<'_>> for EventMessageHandler {
|
||||||
|
fn process_message(&mut self, message: EventMessage, responses: &mut VecDeque<Message>, context: EventMessageContext) {
|
||||||
|
for message in context.listeners.entry(message).or_default() {
|
||||||
|
responses.add_front(message.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn actions(&self) -> ActionList {
|
||||||
|
actions!(EventMessageDiscriminant;)
|
||||||
|
}
|
||||||
|
}
|
7
editor/src/messages/broadcast/event/mod.rs
Normal file
7
editor/src/messages/broadcast/event/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
mod event_message;
|
||||||
|
mod event_message_handler;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use event_message::{EventMessage, EventMessageDiscriminant};
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use event_message_handler::{EventMessageContext, EventMessageHandler};
|
|
@ -1,7 +1,7 @@
|
||||||
mod broadcast_message;
|
mod broadcast_message;
|
||||||
mod broadcast_message_handler;
|
mod broadcast_message_handler;
|
||||||
|
|
||||||
pub mod broadcast_event;
|
pub mod event;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use broadcast_message::{BroadcastMessage, BroadcastMessageDiscriminant};
|
pub use broadcast_message::{BroadcastMessage, BroadcastMessageDiscriminant};
|
||||||
|
|
|
@ -3,8 +3,8 @@ use crate::messages::prelude::*;
|
||||||
#[impl_message(Message, Defer)]
|
#[impl_message(Message, Defer)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum DeferMessage {
|
pub enum DeferMessage {
|
||||||
SetGraphSubmissionIndex(u64),
|
SetGraphSubmissionIndex { execution_id: u64 },
|
||||||
TriggerGraphRun(u64, DocumentId),
|
TriggerGraphRun { execution_id: u64, document_id: DocumentId },
|
||||||
AfterGraphRun { messages: Vec<Message> },
|
AfterGraphRun { messages: Vec<Message> },
|
||||||
TriggerNavigationReady,
|
TriggerNavigationReady,
|
||||||
AfterNavigationReady { messages: Vec<Message> },
|
AfterNavigationReady { messages: Vec<Message> },
|
||||||
|
|
|
@ -24,10 +24,10 @@ impl MessageHandler<DeferMessage, DeferMessageContext<'_>> for DeferMessageHandl
|
||||||
DeferMessage::AfterNavigationReady { messages } => {
|
DeferMessage::AfterNavigationReady { messages } => {
|
||||||
self.after_viewport_resize.extend_from_slice(&messages);
|
self.after_viewport_resize.extend_from_slice(&messages);
|
||||||
}
|
}
|
||||||
DeferMessage::SetGraphSubmissionIndex(execution_id) => {
|
DeferMessage::SetGraphSubmissionIndex { execution_id } => {
|
||||||
self.current_graph_submission_id = execution_id + 1;
|
self.current_graph_submission_id = execution_id + 1;
|
||||||
}
|
}
|
||||||
DeferMessage::TriggerGraphRun(execution_id, document_id) => {
|
DeferMessage::TriggerGraphRun { execution_id, document_id } => {
|
||||||
let after_graph_run = self.after_graph_run.entry(document_id).or_default();
|
let after_graph_run = self.after_graph_run.entry(document_id).or_default();
|
||||||
if after_graph_run.is_empty() {
|
if after_graph_run.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -4,10 +4,10 @@ use crate::messages::prelude::*;
|
||||||
#[impl_message(Message, DialogMessage, ExportDialog)]
|
#[impl_message(Message, DialogMessage, ExportDialog)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum ExportDialogMessage {
|
pub enum ExportDialogMessage {
|
||||||
FileType(FileType),
|
FileType { file_type: FileType },
|
||||||
ScaleFactor(f64),
|
ScaleFactor { factor: f64 },
|
||||||
TransparentBackground(bool),
|
TransparentBackground { transparent: bool },
|
||||||
ExportBounds(ExportBounds),
|
ExportBounds { bounds: ExportBounds },
|
||||||
|
|
||||||
Submit,
|
Submit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ impl MessageHandler<ExportDialogMessage, ExportDialogMessageContext<'_>> for Exp
|
||||||
let ExportDialogMessageContext { portfolio } = context;
|
let ExportDialogMessageContext { portfolio } = context;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
ExportDialogMessage::FileType(export_type) => self.file_type = export_type,
|
ExportDialogMessage::FileType { file_type } => self.file_type = file_type,
|
||||||
ExportDialogMessage::ScaleFactor(factor) => self.scale_factor = factor,
|
ExportDialogMessage::ScaleFactor { factor } => self.scale_factor = factor,
|
||||||
ExportDialogMessage::TransparentBackground(transparent_background) => self.transparent_background = transparent_background,
|
ExportDialogMessage::TransparentBackground { transparent } => self.transparent_background = transparent,
|
||||||
ExportDialogMessage::ExportBounds(export_area) => self.bounds = export_area,
|
ExportDialogMessage::ExportBounds { bounds } => self.bounds = bounds,
|
||||||
|
|
||||||
ExportDialogMessage::Submit => responses.add_front(PortfolioMessage::SubmitDocumentExport {
|
ExportDialogMessage::Submit => responses.add_front(PortfolioMessage::SubmitDocumentExport {
|
||||||
file_name: portfolio.active_document().map(|document| document.name.clone()).unwrap_or_default(),
|
file_name: portfolio.active_document().map(|document| document.name.clone()).unwrap_or_default(),
|
||||||
|
@ -84,7 +84,11 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
||||||
fn layout(&self) -> Layout {
|
fn layout(&self) -> Layout {
|
||||||
let entries = [(FileType::Png, "PNG"), (FileType::Jpg, "JPG"), (FileType::Svg, "SVG")]
|
let entries = [(FileType::Png, "PNG"), (FileType::Jpg, "JPG"), (FileType::Svg, "SVG")]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(val, name)| RadioEntryData::new(format!("{val:?}")).label(name).on_update(move |_| ExportDialogMessage::FileType(val).into()))
|
.map(|(file_type, name)| {
|
||||||
|
RadioEntryData::new(format!("{file_type:?}"))
|
||||||
|
.label(name)
|
||||||
|
.on_update(move |_| ExportDialogMessage::FileType { file_type }.into())
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let export_type = vec![
|
let export_type = vec![
|
||||||
|
@ -101,7 +105,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.disabled(self.file_type == FileType::Svg)
|
.disabled(self.file_type == FileType::Svg)
|
||||||
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into())
|
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor { factor: number_input.value.unwrap() }.into())
|
||||||
.min_width(200)
|
.min_width(200)
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
@ -125,10 +129,10 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
||||||
.map(|choice| {
|
.map(|choice| {
|
||||||
choice
|
choice
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(val, name, disabled)| {
|
.map(|(bounds, name, disabled)| {
|
||||||
MenuListEntry::new(format!("{val:?}"))
|
MenuListEntry::new(format!("{bounds:?}"))
|
||||||
.label(name)
|
.label(name)
|
||||||
.on_commit(move |_| ExportDialogMessage::ExportBounds(val).into())
|
.on_commit(move |_| ExportDialogMessage::ExportBounds { bounds }.into())
|
||||||
.disabled(disabled)
|
.disabled(disabled)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -151,7 +155,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
CheckboxInput::new(self.transparent_background)
|
CheckboxInput::new(self.transparent_background)
|
||||||
.disabled(self.file_type == FileType::Jpg)
|
.disabled(self.file_type == FileType::Jpg)
|
||||||
.on_update(move |value: &CheckboxInput| ExportDialogMessage::TransparentBackground(value.checked).into())
|
.on_update(move |value: &CheckboxInput| ExportDialogMessage::TransparentBackground { transparent: value.checked }.into())
|
||||||
.for_label(checkbox_id)
|
.for_label(checkbox_id)
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
|
|
@ -3,10 +3,10 @@ use crate::messages::prelude::*;
|
||||||
#[impl_message(Message, DialogMessage, NewDocumentDialog)]
|
#[impl_message(Message, DialogMessage, NewDocumentDialog)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum NewDocumentDialogMessage {
|
pub enum NewDocumentDialogMessage {
|
||||||
Name(String),
|
Name { name: String },
|
||||||
Infinite(bool),
|
Infinite { infinite: bool },
|
||||||
DimensionsX(f64),
|
DimensionsX { width: f64 },
|
||||||
DimensionsY(f64),
|
DimensionsY { height: f64 },
|
||||||
|
|
||||||
Submit,
|
Submit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ pub struct NewDocumentDialogMessageHandler {
|
||||||
impl<'a> MessageHandler<NewDocumentDialogMessage, NewDocumentDialogMessageContext<'a>> for NewDocumentDialogMessageHandler {
|
impl<'a> MessageHandler<NewDocumentDialogMessage, NewDocumentDialogMessageContext<'a>> for NewDocumentDialogMessageHandler {
|
||||||
fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque<Message>, context: NewDocumentDialogMessageContext<'a>) {
|
fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque<Message>, context: NewDocumentDialogMessageContext<'a>) {
|
||||||
match message {
|
match message {
|
||||||
NewDocumentDialogMessage::Name(name) => self.name = name,
|
NewDocumentDialogMessage::Name { name } => self.name = name,
|
||||||
NewDocumentDialogMessage::Infinite(infinite) => self.infinite = infinite,
|
NewDocumentDialogMessage::Infinite { infinite } => self.infinite = infinite,
|
||||||
NewDocumentDialogMessage::DimensionsX(x) => self.dimensions.x = x as u32,
|
NewDocumentDialogMessage::DimensionsX { width } => self.dimensions.x = width as u32,
|
||||||
NewDocumentDialogMessage::DimensionsY(y) => self.dimensions.y = y as u32,
|
NewDocumentDialogMessage::DimensionsY { height } => self.dimensions.y = height as u32,
|
||||||
NewDocumentDialogMessage::Submit => {
|
NewDocumentDialogMessage::Submit => {
|
||||||
responses.add(PortfolioMessage::NewDocumentWithName { name: self.name.clone() });
|
responses.add(PortfolioMessage::NewDocumentWithName { name: self.name.clone() });
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
||||||
TextLabel::new("Name").table_align(true).min_width(90).widget_holder(),
|
TextLabel::new("Name").table_align(true).min_width(90).widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
TextInput::new(&self.name)
|
TextInput::new(&self.name)
|
||||||
.on_update(|text_input: &TextInput| NewDocumentDialogMessage::Name(text_input.value.clone()).into())
|
.on_update(|text_input: &TextInput| NewDocumentDialogMessage::Name { name: text_input.value.clone() }.into())
|
||||||
.min_width(204) // Matches the 100px of both NumberInputs below + the 4px of the Unrelated-type separator
|
.min_width(204) // Matches the 100px of both NumberInputs below + the 4px of the Unrelated-type separator
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
@ -92,7 +92,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
||||||
TextLabel::new("Infinite Canvas").table_align(true).min_width(90).for_checkbox(checkbox_id).widget_holder(),
|
TextLabel::new("Infinite Canvas").table_align(true).min_width(90).for_checkbox(checkbox_id).widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
CheckboxInput::new(self.infinite)
|
CheckboxInput::new(self.infinite)
|
||||||
.on_update(|checkbox_input: &CheckboxInput| NewDocumentDialogMessage::Infinite(checkbox_input.checked).into())
|
.on_update(|checkbox_input: &CheckboxInput| NewDocumentDialogMessage::Infinite { infinite: checkbox_input.checked }.into())
|
||||||
.for_label(checkbox_id)
|
.for_label(checkbox_id)
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
@ -108,7 +108,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
||||||
.is_integer(true)
|
.is_integer(true)
|
||||||
.disabled(self.infinite)
|
.disabled(self.infinite)
|
||||||
.min_width(100)
|
.min_width(100)
|
||||||
.on_update(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsX(number_input.value.unwrap()).into())
|
.on_update(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsX { width: number_input.value.unwrap() }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(self.dimensions.y as f64))
|
NumberInput::new(Some(self.dimensions.y as f64))
|
||||||
|
@ -119,7 +119,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
||||||
.is_integer(true)
|
.is_integer(true)
|
||||||
.disabled(self.infinite)
|
.disabled(self.infinite)
|
||||||
.min_width(100)
|
.min_width(100)
|
||||||
.on_update(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsY(number_input.value.unwrap()).into())
|
.on_update(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsY { height: number_input.value.unwrap() }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::messages::broadcast::broadcast_event::BroadcastEvent;
|
use crate::messages::broadcast::event::EventMessage;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ impl DialogLayoutHolder for CloseDocumentDialog {
|
||||||
TextButton::new("Discard")
|
TextButton::new("Discard")
|
||||||
.on_update(move |_| {
|
.on_update(move |_| {
|
||||||
DialogMessage::CloseDialogAndThen {
|
DialogMessage::CloseDialogAndThen {
|
||||||
followups: vec![BroadcastEvent::ToolAbort.into(), PortfolioMessage::CloseDocument { document_id }.into()],
|
followups: vec![EventMessage::ToolAbort.into(), PortfolioMessage::CloseDocument { document_id }.into()],
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
|
|
|
@ -335,9 +335,9 @@ pub enum FrontendMessage {
|
||||||
active: bool,
|
active: bool,
|
||||||
},
|
},
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
RenderOverlays(
|
RenderOverlays {
|
||||||
#[serde(skip, default = "OverlayContext::default")]
|
#[serde(skip, default = "OverlayContext::default")]
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
OverlayContext,
|
context: OverlayContext,
|
||||||
),
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(PointerMove; refresh_keys=[Control, Shift], action_dispatch=TransformLayerMessage::PointerMove { slow_key: Shift, increments_key: Control }),
|
entry!(PointerMove; refresh_keys=[Control, Shift], action_dispatch=TransformLayerMessage::PointerMove { slow_key: Shift, increments_key: Control }),
|
||||||
//
|
//
|
||||||
// SelectToolMessage
|
// SelectToolMessage
|
||||||
entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=SelectToolMessage::PointerMove(SelectToolPointerKeys { axis_align: Shift, snap_angle: Shift, center: Alt, duplicate: Alt })),
|
entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=SelectToolMessage::PointerMove { modifier_keys: SelectToolPointerKeys { axis_align: Shift, snap_angle: Shift, center: Alt, duplicate: Alt } }),
|
||||||
entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { extend_selection: Shift, remove_from_selection: Alt, select_deepest: Accel, lasso_select: Control, skew: Control }),
|
entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { extend_selection: Shift, remove_from_selection: Alt, select_deepest: Accel, lasso_select: Control, skew: Control }),
|
||||||
entry!(KeyUp(MouseLeft); action_dispatch=SelectToolMessage::DragStop { remove_from_selection: Alt }),
|
entry!(KeyUp(MouseLeft); action_dispatch=SelectToolMessage::DragStop { remove_from_selection: Alt }),
|
||||||
entry!(KeyDown(Enter); action_dispatch=SelectToolMessage::Enter),
|
entry!(KeyDown(Enter); action_dispatch=SelectToolMessage::Enter),
|
||||||
|
@ -178,7 +178,7 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(KeyDown(Escape); action_dispatch=ShapeToolMessage::Abort),
|
entry!(KeyDown(Escape); action_dispatch=ShapeToolMessage::Abort),
|
||||||
entry!(KeyDown(BracketLeft); action_dispatch=ShapeToolMessage::DecreaseSides),
|
entry!(KeyDown(BracketLeft); action_dispatch=ShapeToolMessage::DecreaseSides),
|
||||||
entry!(KeyDown(BracketRight); action_dispatch=ShapeToolMessage::IncreaseSides),
|
entry!(KeyDown(BracketRight); action_dispatch=ShapeToolMessage::IncreaseSides),
|
||||||
entry!(PointerMove; refresh_keys=[Alt, Shift, Control], action_dispatch=ShapeToolMessage::PointerMove([Alt, Shift, Control])),
|
entry!(PointerMove; refresh_keys=[Alt, Shift, Control], action_dispatch=ShapeToolMessage::PointerMove { modifier: [Alt, Shift, Control] }),
|
||||||
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
||||||
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
||||||
entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
||||||
|
@ -297,8 +297,8 @@ pub fn input_mappings() -> Mapping {
|
||||||
entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove),
|
entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove),
|
||||||
entry!(KeyDown(MouseLeft); action_dispatch=BrushToolMessage::DragStart),
|
entry!(KeyDown(MouseLeft); action_dispatch=BrushToolMessage::DragStart),
|
||||||
entry!(KeyUp(MouseLeft); action_dispatch=BrushToolMessage::DragStop),
|
entry!(KeyUp(MouseLeft); action_dispatch=BrushToolMessage::DragStop),
|
||||||
entry!(KeyDown(BracketLeft); action_dispatch=BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ChangeDiameter(-BRUSH_SIZE_CHANGE_KEYBOARD))),
|
entry!(KeyDown(BracketLeft); action_dispatch=BrushToolMessage::UpdateOptions { options: BrushToolMessageOptionsUpdate::ChangeDiameter(-BRUSH_SIZE_CHANGE_KEYBOARD) }),
|
||||||
entry!(KeyDown(BracketRight); action_dispatch=BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ChangeDiameter(BRUSH_SIZE_CHANGE_KEYBOARD))),
|
entry!(KeyDown(BracketRight); action_dispatch=BrushToolMessage::UpdateOptions { options: BrushToolMessageOptionsUpdate::ChangeDiameter(BRUSH_SIZE_CHANGE_KEYBOARD) }),
|
||||||
entry!(KeyDown(MouseRight); action_dispatch=BrushToolMessage::Abort),
|
entry!(KeyDown(MouseRight); action_dispatch=BrushToolMessage::Abort),
|
||||||
entry!(KeyDown(Escape); action_dispatch=BrushToolMessage::Abort),
|
entry!(KeyDown(Escape); action_dispatch=BrushToolMessage::Abort),
|
||||||
//
|
//
|
||||||
|
|
|
@ -3,13 +3,16 @@ use crate::messages::prelude::*;
|
||||||
#[impl_message(Message, KeyMapping)]
|
#[impl_message(Message, KeyMapping)]
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum KeyMappingMessage {
|
pub enum KeyMappingMessage {
|
||||||
|
// Sub-messages
|
||||||
#[child]
|
#[child]
|
||||||
Lookup(InputMapperMessage),
|
Lookup(InputMapperMessage),
|
||||||
#[child]
|
|
||||||
ModifyMapping(MappingVariant),
|
// Messages
|
||||||
|
ModifyMapping {
|
||||||
|
mapping: MappingVariant,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[impl_message(Message, KeyMappingMessage, ModifyMapping)]
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Default, Hash, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Eq, Clone, Debug, Default, Hash, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum MappingVariant {
|
pub enum MappingVariant {
|
||||||
#[default]
|
#[default]
|
||||||
|
|
|
@ -19,8 +19,11 @@ impl MessageHandler<KeyMappingMessage, KeyMappingMessageContext<'_>> for KeyMapp
|
||||||
let KeyMappingMessageContext { input, actions } = context;
|
let KeyMappingMessageContext { input, actions } = context;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
|
// Sub-messages
|
||||||
KeyMappingMessage::Lookup(input_message) => self.mapping_handler.process_message(input_message, responses, InputMapperMessageContext { input, actions }),
|
KeyMappingMessage::Lookup(input_message) => self.mapping_handler.process_message(input_message, responses, InputMapperMessageContext { input, actions }),
|
||||||
KeyMappingMessage::ModifyMapping(new_layout) => self.mapping_handler.set_mapping(new_layout.into()),
|
|
||||||
|
// Messages
|
||||||
|
KeyMappingMessage::ModifyMapping { mapping } => self.mapping_handler.set_mapping(mapping.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
advertise_actions!();
|
advertise_actions!();
|
||||||
|
|
|
@ -2,6 +2,6 @@ mod key_mapping_message;
|
||||||
mod key_mapping_message_handler;
|
mod key_mapping_message_handler;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use key_mapping_message::{KeyMappingMessage, KeyMappingMessageDiscriminant, MappingVariant, MappingVariantDiscriminant};
|
pub use key_mapping_message::{KeyMappingMessage, KeyMappingMessageDiscriminant, MappingVariant};
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use key_mapping_message_handler::{KeyMappingMessageContext, KeyMappingMessageHandler};
|
pub use key_mapping_message_handler::{KeyMappingMessageContext, KeyMappingMessageHandler};
|
||||||
|
|
|
@ -35,10 +35,10 @@ pub enum Message {
|
||||||
Tool(ToolMessage),
|
Tool(ToolMessage),
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
NoOp,
|
|
||||||
Batched {
|
Batched {
|
||||||
messages: Box<[Message]>,
|
messages: Box<[Message]>,
|
||||||
},
|
},
|
||||||
|
NoOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`.
|
/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`.
|
||||||
|
@ -94,6 +94,17 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print message field if any
|
||||||
|
if let Some(fields) = tree.fields() {
|
||||||
|
let len = fields.len();
|
||||||
|
for (i, field) in fields.iter().enumerate() {
|
||||||
|
let is_last_field = i == len - 1;
|
||||||
|
let branch = if is_last_field { "└── " } else { "├── " };
|
||||||
|
|
||||||
|
file.write_all(format!("{}{}{}\n", child_prefix, branch, field).as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Print handler field if any
|
// Print handler field if any
|
||||||
if let Some(data) = tree.message_handler_fields() {
|
if let Some(data) = tree.message_handler_fields() {
|
||||||
let len = data.fields().len();
|
let len = data.fields().len();
|
||||||
|
@ -102,16 +113,19 @@ mod test {
|
||||||
} else {
|
} else {
|
||||||
("└── ", format!("{} ", prefix))
|
("└── ", format!("{} ", prefix))
|
||||||
};
|
};
|
||||||
if data.path().is_empty() {
|
|
||||||
file.write_all(format!("{}{}{}\n", prefix, branch, data.name()).as_bytes()).unwrap();
|
|
||||||
} else {
|
|
||||||
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap();
|
|
||||||
}
|
|
||||||
for (i, field) in data.fields().iter().enumerate() {
|
|
||||||
let is_last_field = i == len - 1;
|
|
||||||
let branch = if is_last_field { "└── " } else { "├── " };
|
|
||||||
|
|
||||||
file.write_all(format!("{}{}{}\n", child_prefix, branch, field.0).as_bytes()).unwrap();
|
const FRONTEND_MESSAGE_STR: &str = "FrontendMessage";
|
||||||
|
if data.name().is_empty() && tree.name() != FRONTEND_MESSAGE_STR {
|
||||||
|
panic!("{}'s MessageHandler is missing #[message_handler_data]", tree.name());
|
||||||
|
} else if tree.name() != FRONTEND_MESSAGE_STR {
|
||||||
|
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap();
|
||||||
|
|
||||||
|
for (i, field) in data.fields().iter().enumerate() {
|
||||||
|
let is_last_field = i == len - 1;
|
||||||
|
let branch = if is_last_field { "└── " } else { "├── " };
|
||||||
|
|
||||||
|
file.write_all(format!("{}{}{}\n", child_prefix, branch, field.0).as_bytes()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,9 @@ pub enum DocumentMessage {
|
||||||
DocumentHistoryBackward,
|
DocumentHistoryBackward,
|
||||||
DocumentHistoryForward,
|
DocumentHistoryForward,
|
||||||
DocumentStructureChanged,
|
DocumentStructureChanged,
|
||||||
DrawArtboardOverlays(OverlayContext),
|
DrawArtboardOverlays {
|
||||||
|
context: OverlayContext,
|
||||||
|
},
|
||||||
DuplicateSelectedLayers,
|
DuplicateSelectedLayers,
|
||||||
EnterNestedNetwork {
|
EnterNestedNetwork {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
@ -72,9 +74,15 @@ pub enum DocumentMessage {
|
||||||
open: bool,
|
open: bool,
|
||||||
},
|
},
|
||||||
GraphViewOverlayToggle,
|
GraphViewOverlayToggle,
|
||||||
GridOptions(GridSnapping),
|
GridOptions {
|
||||||
GridOverlays(OverlayContext),
|
options: GridSnapping,
|
||||||
GridVisibility(bool),
|
},
|
||||||
|
GridOverlays {
|
||||||
|
context: OverlayContext,
|
||||||
|
},
|
||||||
|
GridVisibility {
|
||||||
|
visible: bool,
|
||||||
|
},
|
||||||
GroupSelectedLayers {
|
GroupSelectedLayers {
|
||||||
group_folder_type: GroupFolderType,
|
group_folder_type: GroupFolderType,
|
||||||
},
|
},
|
||||||
|
|
|
@ -391,7 +391,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentMessage::DrawArtboardOverlays(overlay_context) => {
|
DocumentMessage::DrawArtboardOverlays { context: overlay_context } => {
|
||||||
if !overlay_context.visibility_settings.artboard_name() {
|
if !overlay_context.visibility_settings.artboard_name() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -588,19 +588,19 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
DocumentMessage::GraphViewOverlayToggle => {
|
DocumentMessage::GraphViewOverlayToggle => {
|
||||||
responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open });
|
responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open });
|
||||||
}
|
}
|
||||||
DocumentMessage::GridOptions(grid) => {
|
DocumentMessage::GridOptions { options } => {
|
||||||
self.snapping_state.grid = grid;
|
self.snapping_state.grid = options;
|
||||||
self.snapping_state.grid_snapping = true;
|
self.snapping_state.grid_snapping = true;
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||||
}
|
}
|
||||||
DocumentMessage::GridOverlays(mut overlay_context) => {
|
DocumentMessage::GridOverlays { context: mut overlay_context } => {
|
||||||
if self.snapping_state.grid_snapping {
|
if self.snapping_state.grid_snapping {
|
||||||
grid_overlay(self, &mut overlay_context)
|
grid_overlay(self, &mut overlay_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentMessage::GridVisibility(enabled) => {
|
DocumentMessage::GridVisibility { visible } => {
|
||||||
self.snapping_state.grid_snapping = enabled;
|
self.snapping_state.grid_snapping = visible;
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
}
|
}
|
||||||
DocumentMessage::GroupSelectedLayers { group_folder_type } => {
|
DocumentMessage::GroupSelectedLayers { group_folder_type } => {
|
||||||
|
@ -1062,7 +1062,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
if !parent_layers.is_empty() {
|
if !parent_layers.is_empty() {
|
||||||
let nodes = parent_layers.into_iter().collect();
|
let nodes = parent_layers.into_iter().collect();
|
||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes });
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentMessage::SelectAllLayers => {
|
DocumentMessage::SelectAllLayers => {
|
||||||
|
@ -1137,7 +1137,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
} else {
|
} else {
|
||||||
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
||||||
}
|
}
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
} else {
|
} else {
|
||||||
nodes.push(id);
|
nodes.push(id);
|
||||||
}
|
}
|
||||||
|
@ -1206,7 +1206,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
Some(overlays_type) => overlays_type,
|
Some(overlays_type) => overlays_type,
|
||||||
None => {
|
None => {
|
||||||
visibility_settings.all = visible;
|
visibility_settings.all = visible;
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1229,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
OverlaysType::Handles => visibility_settings.handles = visible,
|
OverlaysType::Handles => visibility_settings.handles = visible,
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
}
|
}
|
||||||
DocumentMessage::SetRangeSelectionLayer { new_layer } => {
|
DocumentMessage::SetRangeSelectionLayer { new_layer } => {
|
||||||
|
@ -1443,12 +1443,14 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
let transform = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz);
|
let transform = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz);
|
||||||
self.network_interface.set_document_to_viewport_transform(transform);
|
self.network_interface.set_document_to_viewport_transform(transform);
|
||||||
// Ensure selection box is kept in sync with the pointer when the PTZ changes
|
// Ensure selection box is kept in sync with the pointer when the PTZ changes
|
||||||
responses.add(SelectToolMessage::PointerMove(SelectToolPointerKeys {
|
responses.add(SelectToolMessage::PointerMove {
|
||||||
axis_align: Key::Shift,
|
modifier_keys: SelectToolPointerKeys {
|
||||||
snap_angle: Key::Shift,
|
axis_align: Key::Shift,
|
||||||
center: Key::Alt,
|
snap_angle: Key::Shift,
|
||||||
duplicate: Key::Alt,
|
center: Key::Alt,
|
||||||
}));
|
duplicate: Key::Alt,
|
||||||
|
},
|
||||||
|
});
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
} else {
|
} else {
|
||||||
let Some(network_metadata) = self.network_interface.network_metadata(&self.breadcrumb_network_path) else {
|
let Some(network_metadata) = self.network_interface.network_metadata(&self.breadcrumb_network_path) else {
|
||||||
|
@ -1477,11 +1479,11 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
}
|
}
|
||||||
DocumentMessage::SelectionStepBack => {
|
DocumentMessage::SelectionStepBack => {
|
||||||
self.network_interface.selection_step_back(&self.selection_network_path);
|
self.network_interface.selection_step_back(&self.selection_network_path);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
DocumentMessage::SelectionStepForward => {
|
DocumentMessage::SelectionStepForward => {
|
||||||
self.network_interface.selection_step_forward(&self.selection_network_path);
|
self.network_interface.selection_step_forward(&self.selection_network_path);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
DocumentMessage::WrapContentInArtboard { place_artboard_at_origin } => {
|
DocumentMessage::WrapContentInArtboard { place_artboard_at_origin } => {
|
||||||
// Get bounding box of all layers
|
// Get bounding box of all layers
|
||||||
|
@ -2484,7 +2486,7 @@ impl DocumentMessageHandler {
|
||||||
.icon("Grid")
|
.icon("Grid")
|
||||||
.tooltip("Grid")
|
.tooltip("Grid")
|
||||||
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleGridVisibility))
|
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleGridVisibility))
|
||||||
.on_update(|optional_input: &CheckboxInput| DocumentMessage::GridVisibility(optional_input.checked).into())
|
.on_update(|optional_input: &CheckboxInput| DocumentMessage::GridVisibility { visible: optional_input.checked }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
PopoverButton::new()
|
PopoverButton::new()
|
||||||
.popover_layout(overlay_options(&self.snapping_state.grid))
|
.popover_layout(overlay_options(&self.snapping_state.grid))
|
||||||
|
|
|
@ -139,7 +139,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||||
let transformed_delta = document_to_viewport.inverse().transform_vector2(delta);
|
let transformed_delta = document_to_viewport.inverse().transform_vector2(delta);
|
||||||
|
|
||||||
ptz.pan += transformed_delta;
|
ptz.pan += transformed_delta;
|
||||||
responses.add(BroadcastEvent::CanvasTransformed);
|
responses.add(EventMessage::CanvasTransformed);
|
||||||
responses.add(DocumentMessage::PTZUpdate);
|
responses.add(DocumentMessage::PTZUpdate);
|
||||||
}
|
}
|
||||||
NavigationMessage::CanvasPanAbortPrepare { x_not_y_axis } => {
|
NavigationMessage::CanvasPanAbortPrepare { x_not_y_axis } => {
|
||||||
|
@ -286,7 +286,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||||
ptz.flip = !ptz.flip;
|
ptz.flip = !ptz.flip;
|
||||||
|
|
||||||
responses.add(DocumentMessage::PTZUpdate);
|
responses.add(DocumentMessage::PTZUpdate);
|
||||||
responses.add(BroadcastEvent::CanvasTransformed);
|
responses.add(EventMessage::CanvasTransformed);
|
||||||
responses.add(MenuBarMessage::SendLayout);
|
responses.add(MenuBarMessage::SendLayout);
|
||||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||||
self.navigation_operation = NavigationOperation::None;
|
self.navigation_operation = NavigationOperation::None;
|
||||||
|
|
||||||
// Send the final messages to close out the operation
|
// Send the final messages to close out the operation
|
||||||
responses.add(BroadcastEvent::CanvasTransformed);
|
responses.add(EventMessage::CanvasTransformed);
|
||||||
responses.add(ToolMessage::UpdateCursor);
|
responses.add(ToolMessage::UpdateCursor);
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
responses.add(NavigateToolMessage::End);
|
responses.add(NavigateToolMessage::End);
|
||||||
|
|
|
@ -129,7 +129,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
NodeGraphMessage::AddPathNode => {
|
NodeGraphMessage::AddPathNode => {
|
||||||
if let Some(layer) = make_path_editable_is_allowed(network_interface, network_interface.document_metadata()) {
|
if let Some(layer) = make_path_editable_is_allowed(network_interface, network_interface.document_metadata()) {
|
||||||
responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: "Path".to_string(), layer });
|
responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: "Path".to_string(), layer });
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::AddImport => {
|
NodeGraphMessage::AddImport => {
|
||||||
|
@ -142,7 +142,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
}
|
}
|
||||||
NodeGraphMessage::Init => {
|
NodeGraphMessage::Init => {
|
||||||
responses.add(BroadcastMessage::SubscribeEvent {
|
responses.add(BroadcastMessage::SubscribeEvent {
|
||||||
on: BroadcastEvent::SelectionChanged,
|
on: EventMessage::SelectionChanged,
|
||||||
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
|
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
|
||||||
});
|
});
|
||||||
network_interface.load_structure();
|
network_interface.load_structure();
|
||||||
|
@ -1472,7 +1472,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
selected_nodes.add_selected_nodes(nodes);
|
selected_nodes.add_selected_nodes(nodes);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SelectedNodesRemove { nodes } => {
|
NodeGraphMessage::SelectedNodesRemove { nodes } => {
|
||||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||||
|
@ -1480,7 +1480,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
selected_nodes.retain_selected_nodes(|node| !nodes.contains(node));
|
selected_nodes.retain_selected_nodes(|node| !nodes.contains(node));
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SelectedNodesSet { nodes } => {
|
NodeGraphMessage::SelectedNodesSet { nodes } => {
|
||||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||||
|
@ -1488,7 +1488,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
selected_nodes.set_selected_nodes(nodes);
|
selected_nodes.set_selected_nodes(nodes);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SendClickTargets => responses.add(FrontendMessage::UpdateClickTargets {
|
NodeGraphMessage::SendClickTargets => responses.add(FrontendMessage::UpdateClickTargets {
|
||||||
click_targets: Some(network_interface.collect_frontend_click_targets(breadcrumb_network_path)),
|
click_targets: Some(network_interface.collect_frontend_click_targets(breadcrumb_network_path)),
|
||||||
|
@ -1888,7 +1888,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
selected_nodes.clear_selected_nodes();
|
selected_nodes.clear_selected_nodes();
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@ pub fn overlay_options(grid: &GridSnapping) -> Vec<LayoutGroup> {
|
||||||
move |input: &I| {
|
move |input: &I| {
|
||||||
let mut grid = grid.clone();
|
let mut grid = grid.clone();
|
||||||
update(&mut grid, input);
|
update(&mut grid, input);
|
||||||
DocumentMessage::GridOptions(grid).into()
|
DocumentMessage::GridOptions { options: grid }.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let update_origin = |grid, update: fn(&mut GridSnapping) -> Option<&mut f64>| {
|
let update_origin = |grid, update: fn(&mut GridSnapping) -> Option<&mut f64>| {
|
||||||
|
|
|
@ -7,14 +7,14 @@ use crate::messages::prelude::*;
|
||||||
pub enum OverlaysMessage {
|
pub enum OverlaysMessage {
|
||||||
Draw,
|
Draw,
|
||||||
// Serde functionality isn't used but is required by the message system macros
|
// Serde functionality isn't used but is required by the message system macros
|
||||||
AddProvider(
|
AddProvider {
|
||||||
#[serde(skip, default = "empty_provider")]
|
#[serde(skip, default = "empty_provider")]
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
OverlayProvider,
|
provider: OverlayProvider,
|
||||||
),
|
},
|
||||||
RemoveProvider(
|
RemoveProvider {
|
||||||
#[serde(skip, default = "empty_provider")]
|
#[serde(skip, default = "empty_provider")]
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
OverlayProvider,
|
provider: OverlayProvider,
|
||||||
),
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,12 +56,14 @@ impl MessageHandler<OverlaysMessage, OverlaysMessageContext<'_>> for OverlaysMes
|
||||||
let _ = canvas_context.reset_transform();
|
let _ = canvas_context.reset_transform();
|
||||||
|
|
||||||
if visibility_settings.all() {
|
if visibility_settings.all() {
|
||||||
responses.add(DocumentMessage::GridOverlays(OverlayContext {
|
responses.add(DocumentMessage::GridOverlays {
|
||||||
render_context: canvas_context.clone(),
|
context: OverlayContext {
|
||||||
size: size.as_dvec2(),
|
render_context: canvas_context.clone(),
|
||||||
device_pixel_ratio,
|
size: size.as_dvec2(),
|
||||||
visibility_settings: visibility_settings.clone(),
|
device_pixel_ratio,
|
||||||
}));
|
visibility_settings: visibility_settings.clone(),
|
||||||
|
},
|
||||||
|
});
|
||||||
for provider in &self.overlay_providers {
|
for provider in &self.overlay_providers {
|
||||||
responses.add(provider(OverlayContext {
|
responses.add(provider(OverlayContext {
|
||||||
render_context: canvas_context.clone(),
|
render_context: canvas_context.clone(),
|
||||||
|
@ -81,22 +83,22 @@ impl MessageHandler<OverlaysMessage, OverlaysMessageContext<'_>> for OverlaysMes
|
||||||
let overlay_context = OverlayContext::new(size, device_pixel_ratio, visibility_settings);
|
let overlay_context = OverlayContext::new(size, device_pixel_ratio, visibility_settings);
|
||||||
|
|
||||||
if visibility_settings.all() {
|
if visibility_settings.all() {
|
||||||
responses.add(DocumentMessage::GridOverlays(overlay_context.clone()));
|
responses.add(DocumentMessage::GridOverlays { context: overlay_context.clone() });
|
||||||
|
|
||||||
for provider in &self.overlay_providers {
|
for provider in &self.overlay_providers {
|
||||||
responses.add(provider(overlay_context.clone()));
|
responses.add(provider(overlay_context.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
responses.add(FrontendMessage::RenderOverlays(overlay_context));
|
responses.add(FrontendMessage::RenderOverlays { context: overlay_context });
|
||||||
}
|
}
|
||||||
#[cfg(all(not(target_family = "wasm"), test))]
|
#[cfg(all(not(target_family = "wasm"), test))]
|
||||||
OverlaysMessage::Draw => {
|
OverlaysMessage::Draw => {
|
||||||
let _ = (responses, visibility_settings, ipp, device_pixel_ratio);
|
let _ = (responses, visibility_settings, ipp, device_pixel_ratio);
|
||||||
}
|
}
|
||||||
OverlaysMessage::AddProvider(message) => {
|
OverlaysMessage::AddProvider { provider: message } => {
|
||||||
self.overlay_providers.insert(message);
|
self.overlay_providers.insert(message);
|
||||||
}
|
}
|
||||||
OverlaysMessage::RemoveProvider(message) => {
|
OverlaysMessage::RemoveProvider { provider: message } => {
|
||||||
self.overlay_providers.remove(&message);
|
self.overlay_providers.remove(&message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
}
|
}
|
||||||
PortfolioMessage::CloseAllDocuments => {
|
PortfolioMessage::CloseAllDocuments => {
|
||||||
if self.active_document_id.is_some() {
|
if self.active_document_id.is_some() {
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
responses.add(ToolMessage::DeactivateTools);
|
responses.add(ToolMessage::DeactivateTools);
|
||||||
|
|
||||||
// Clear relevant UI layouts if there are no documents
|
// Clear relevant UI layouts if there are no documents
|
||||||
|
@ -250,7 +250,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
PortfolioMessage::CloseDocumentWithConfirmation { document_id } => {
|
PortfolioMessage::CloseDocumentWithConfirmation { document_id } => {
|
||||||
let target_document = self.documents.get(&document_id).unwrap();
|
let target_document = self.documents.get(&document_id).unwrap();
|
||||||
if target_document.is_saved() {
|
if target_document.is_saved() {
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
responses.add(PortfolioMessage::CloseDocument { document_id });
|
responses.add(PortfolioMessage::CloseDocument { document_id });
|
||||||
} else {
|
} else {
|
||||||
let dialog = simple_dialogs::CloseDocumentDialog {
|
let dialog = simple_dialogs::CloseDocumentDialog {
|
||||||
|
@ -395,7 +395,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
|
|
||||||
let document_id = DocumentId(generate_uuid());
|
let document_id = DocumentId(generate_uuid());
|
||||||
if self.active_document().is_some() {
|
if self.active_document().is_some() {
|
||||||
new_responses.add(BroadcastEvent::ToolAbort);
|
new_responses.add(EventMessage::ToolAbort);
|
||||||
new_responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
new_responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,8 +874,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
responses.add(ToolMessage::InitTools);
|
responses.add(ToolMessage::InitTools);
|
||||||
responses.add(NodeGraphMessage::Init);
|
responses.add(NodeGraphMessage::Init);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open });
|
responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open });
|
||||||
|
@ -1132,7 +1132,7 @@ impl PortfolioMessageHandler {
|
||||||
self.documents.insert(document_id, new_document);
|
self.documents.insert(document_id, new_document);
|
||||||
|
|
||||||
if self.active_document().is_some() {
|
if self.active_document().is_some() {
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
responses.add(ToolMessage::DeactivateTools);
|
responses.add(ToolMessage::DeactivateTools);
|
||||||
} else {
|
} else {
|
||||||
// Load the default font upon creating the first document
|
// Load the default font upon creating the first document
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
|
||||||
}
|
}
|
||||||
PreferencesMessage::ResetToDefaults => {
|
PreferencesMessage::ResetToDefaults => {
|
||||||
refresh_dialog(responses);
|
refresh_dialog(responses);
|
||||||
responses.add(KeyMappingMessage::ModifyMapping(MappingVariant::Default));
|
responses.add(KeyMappingMessage::ModifyMapping { mapping: MappingVariant::Default });
|
||||||
|
|
||||||
*self = Self::default()
|
*self = Self::default()
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
|
||||||
self.zoom_with_scroll = zoom_with_scroll;
|
self.zoom_with_scroll = zoom_with_scroll;
|
||||||
|
|
||||||
let variant = if zoom_with_scroll { MappingVariant::ZoomWithScroll } else { MappingVariant::Default };
|
let variant = if zoom_with_scroll { MappingVariant::ZoomWithScroll } else { MappingVariant::Default };
|
||||||
responses.add(KeyMappingMessage::ModifyMapping(variant));
|
responses.add(KeyMappingMessage::ModifyMapping { mapping: variant });
|
||||||
}
|
}
|
||||||
PreferencesMessage::SelectionMode { selection_mode } => {
|
PreferencesMessage::SelectionMode { selection_mode } => {
|
||||||
self.selection_mode = selection_mode;
|
self.selection_mode = selection_mode;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// Root
|
// Message-related
|
||||||
pub use crate::utility_traits::{ActionList, AsMessage, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild};
|
pub use crate::utility_traits::{ActionList, AsMessage, ExtractField, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild};
|
||||||
pub use crate::utility_types::{DebugMessageTree, MessageData};
|
pub use crate::utility_types::{DebugMessageTree, MessageData};
|
||||||
|
|
||||||
// Message, MessageData, MessageDiscriminant, MessageHandler
|
// Message, MessageData, MessageDiscriminant, MessageHandler
|
||||||
pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler};
|
pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler};
|
||||||
pub use crate::messages::app_window::{AppWindowMessage, AppWindowMessageDiscriminant, AppWindowMessageHandler};
|
pub use crate::messages::app_window::{AppWindowMessage, AppWindowMessageDiscriminant, AppWindowMessageHandler};
|
||||||
|
pub use crate::messages::broadcast::event::{EventMessage, EventMessageContext, EventMessageDiscriminant, EventMessageHandler};
|
||||||
pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler};
|
pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler};
|
||||||
pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler};
|
pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler};
|
||||||
pub use crate::messages::defer::{DeferMessage, DeferMessageDiscriminant, DeferMessageHandler};
|
pub use crate::messages::defer::{DeferMessage, DeferMessageDiscriminant, DeferMessageHandler};
|
||||||
|
@ -31,7 +33,6 @@ pub use crate::messages::tool::transform_layer::{TransformLayerMessage, Transfor
|
||||||
pub use crate::messages::tool::{ToolMessage, ToolMessageContext, ToolMessageDiscriminant, ToolMessageHandler};
|
pub use crate::messages::tool::{ToolMessage, ToolMessageContext, ToolMessageDiscriminant, ToolMessageHandler};
|
||||||
|
|
||||||
// Message, MessageDiscriminant
|
// Message, MessageDiscriminant
|
||||||
pub use crate::messages::broadcast::broadcast_event::{BroadcastEvent, BroadcastEventDiscriminant};
|
|
||||||
pub use crate::messages::message::{Message, MessageDiscriminant};
|
pub use crate::messages::message::{Message, MessageDiscriminant};
|
||||||
pub use crate::messages::tool::tool_messages::artboard_tool::{ArtboardToolMessage, ArtboardToolMessageDiscriminant};
|
pub use crate::messages::tool::tool_messages::artboard_tool::{ArtboardToolMessage, ArtboardToolMessageDiscriminant};
|
||||||
pub use crate::messages::tool::tool_messages::brush_tool::{BrushToolMessage, BrushToolMessageDiscriminant};
|
pub use crate::messages::tool::tool_messages::brush_tool::{BrushToolMessage, BrushToolMessageDiscriminant};
|
||||||
|
@ -47,7 +48,7 @@ pub use crate::messages::tool::tool_messages::shape_tool::{ShapeToolMessage, Sha
|
||||||
pub use crate::messages::tool::tool_messages::spline_tool::{SplineToolMessage, SplineToolMessageDiscriminant};
|
pub use crate::messages::tool::tool_messages::spline_tool::{SplineToolMessage, SplineToolMessageDiscriminant};
|
||||||
pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant};
|
pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant};
|
||||||
|
|
||||||
// Helper
|
// Helper/miscellaneous
|
||||||
pub use crate::messages::globals::global_variables::*;
|
pub use crate::messages::globals::global_variables::*;
|
||||||
pub use crate::messages::portfolio::document::utility_types::misc::DocumentId;
|
pub use crate::messages::portfolio::document::utility_types::misc::DocumentId;
|
||||||
pub use graphite_proc_macros::*;
|
pub use graphite_proc_macros::*;
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl AutoPanning {
|
||||||
|
|
||||||
for message in messages {
|
for message in messages {
|
||||||
responses.add(BroadcastMessage::SubscribeEvent {
|
responses.add(BroadcastMessage::SubscribeEvent {
|
||||||
on: BroadcastEvent::AnimationFrame,
|
on: EventMessage::AnimationFrame,
|
||||||
send: Box::new(message.clone()),
|
send: Box::new(message.clone()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ impl AutoPanning {
|
||||||
|
|
||||||
for message in messages {
|
for message in messages {
|
||||||
responses.add(BroadcastMessage::UnsubscribeEvent {
|
responses.add(BroadcastMessage::UnsubscribeEvent {
|
||||||
on: BroadcastEvent::AnimationFrame,
|
on: EventMessage::AnimationFrame,
|
||||||
message: Box::new(message.clone()),
|
send: Box::new(message.clone()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,14 @@ pub fn pin_pivot_widget(active: bool, enabled: bool, source: PivotToolSource) ->
|
||||||
.tooltip(String::from(if active { "Unpin Custom Pivot" } else { "Pin Custom Pivot" }) + "\n\nUnless pinned, the pivot will return to its prior reference point when a new selection is made.")
|
.tooltip(String::from(if active { "Unpin Custom Pivot" } else { "Pin Custom Pivot" }) + "\n\nUnless pinned, the pivot will return to its prior reference point when a new selection is made.")
|
||||||
.disabled(!enabled)
|
.disabled(!enabled)
|
||||||
.on_update(move |_| match source {
|
.on_update(move |_| match source {
|
||||||
PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned).into(),
|
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||||
PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned).into(),
|
options: SelectOptionsUpdate::TogglePivotPinned,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::TogglePivotPinned,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
})
|
})
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
@ -41,8 +47,14 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
|
||||||
MenuListEntry::new(format!("{gizmo_type:?}")).label(gizmo_type.to_string()).on_commit({
|
MenuListEntry::new(format!("{gizmo_type:?}")).label(gizmo_type.to_string()).on_commit({
|
||||||
let value = source.clone();
|
let value = source.clone();
|
||||||
move |_| match value {
|
move |_| match value {
|
||||||
PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::PivotGizmoType(*gizmo_type)).into(),
|
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||||
PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::PivotGizmoType(*gizmo_type)).into(),
|
options: SelectOptionsUpdate::PivotGizmoType(*gizmo_type),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::PivotGizmoType(*gizmo_type),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -57,8 +69,14 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
|
||||||
Disabled: rotation and scaling occurs about the center of the selection bounds.",
|
Disabled: rotation and scaling occurs about the center of the selection bounds.",
|
||||||
)
|
)
|
||||||
.on_update(move |optional_input: &CheckboxInput| match source {
|
.on_update(move |optional_input: &CheckboxInput| match source {
|
||||||
PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(),
|
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||||
PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(),
|
options: SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::messages::tool::utility_types::ToolType;
|
||||||
use crate::node_graph_executor::NodeGraphExecutor;
|
use crate::node_graph_executor::NodeGraphExecutor;
|
||||||
use graphene_std::raster::color::Color;
|
use graphene_std::raster::color::Color;
|
||||||
|
|
||||||
const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |overlay_context| DocumentMessage::DrawArtboardOverlays(overlay_context).into();
|
const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |context| DocumentMessage::DrawArtboardOverlays { context }.into();
|
||||||
|
|
||||||
#[derive(ExtractField)]
|
#[derive(ExtractField)]
|
||||||
pub struct ToolMessageContext<'a> {
|
pub struct ToolMessageContext<'a> {
|
||||||
|
@ -75,8 +75,8 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||||
self.tool_state.tool_data.active_tool_type = ToolType::Shape;
|
self.tool_state.tool_data.active_tool_type = ToolType::Shape;
|
||||||
}
|
}
|
||||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape });
|
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape });
|
||||||
responses.add(ShapeToolMessage::SetShape(ShapeType::Polygon));
|
responses.add(ShapeToolMessage::SetShape { shape: ShapeType::Polygon });
|
||||||
responses.add(ShapeToolMessage::HideShapeTypeWidget(false))
|
responses.add(ShapeToolMessage::HideShapeTypeWidget { hide: false })
|
||||||
}
|
}
|
||||||
ToolMessage::ActivateToolBrush => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Brush }),
|
ToolMessage::ActivateToolBrush => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Brush }),
|
||||||
ToolMessage::ActivateToolShapeLine | ToolMessage::ActivateToolShapeRectangle | ToolMessage::ActivateToolShapeEllipse => {
|
ToolMessage::ActivateToolShapeLine | ToolMessage::ActivateToolShapeRectangle | ToolMessage::ActivateToolShapeEllipse => {
|
||||||
|
@ -89,8 +89,8 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||||
|
|
||||||
self.tool_state.tool_data.active_shape_type = Some(shape.tool_type());
|
self.tool_state.tool_data.active_shape_type = Some(shape.tool_type());
|
||||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape });
|
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape });
|
||||||
responses.add(ShapeToolMessage::HideShapeTypeWidget(true));
|
responses.add(ShapeToolMessage::HideShapeTypeWidget { hide: true });
|
||||||
responses.add(ShapeToolMessage::SetShape(shape));
|
responses.add(ShapeToolMessage::SetShape { shape });
|
||||||
}
|
}
|
||||||
ToolMessage::ActivateTool { tool_type } => {
|
ToolMessage::ActivateTool { tool_type } => {
|
||||||
let tool_data = &mut self.tool_state.tool_data;
|
let tool_data = &mut self.tool_state.tool_data;
|
||||||
|
@ -157,13 +157,13 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||||
tool_data.tools.get(&tool_type).unwrap().activate(responses);
|
tool_data.tools.get(&tool_type).unwrap().activate(responses);
|
||||||
|
|
||||||
// Re-add the artboard overlay provider when tools are reactivated
|
// Re-add the artboard overlay provider when tools are reactivated
|
||||||
responses.add(OverlaysMessage::AddProvider(ARTBOARD_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::AddProvider { provider: ARTBOARD_OVERLAY_PROVIDER });
|
||||||
|
|
||||||
// Send the SelectionChanged message to the active tool, this will ensure the selection is updated
|
// Send the SelectionChanged message to the active tool, this will ensure the selection is updated
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(EventMessage::SelectionChanged);
|
||||||
|
|
||||||
// Update the working colors for the active tool
|
// Update the working colors for the active tool
|
||||||
responses.add(BroadcastEvent::WorkingColorChanged);
|
responses.add(EventMessage::WorkingColorChanged);
|
||||||
|
|
||||||
// Send tool options to the frontend
|
// Send tool options to the frontend
|
||||||
responses.add(ToolMessage::RefreshToolOptions);
|
responses.add(ToolMessage::RefreshToolOptions);
|
||||||
|
@ -176,11 +176,12 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||||
tool_data.tools.get(&tool_data.active_tool_type).unwrap().deactivate(responses);
|
tool_data.tools.get(&tool_data.active_tool_type).unwrap().deactivate(responses);
|
||||||
|
|
||||||
// Unsubscribe the transform layer to selection change events
|
// Unsubscribe the transform layer to selection change events
|
||||||
let message = Box::new(TransformLayerMessage::SelectionChanged.into());
|
responses.add(BroadcastMessage::UnsubscribeEvent {
|
||||||
let on = BroadcastEvent::SelectionChanged;
|
on: EventMessage::SelectionChanged,
|
||||||
responses.add(BroadcastMessage::UnsubscribeEvent { message, on });
|
send: Box::new(TransformLayerMessage::SelectionChanged.into()),
|
||||||
|
});
|
||||||
|
|
||||||
responses.add(OverlaysMessage::RemoveProvider(ARTBOARD_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::RemoveProvider { provider: ARTBOARD_OVERLAY_PROVIDER });
|
||||||
|
|
||||||
responses.add(FrontendMessage::UpdateInputHints { hint_data: Default::default() });
|
responses.add(FrontendMessage::UpdateInputHints { hint_data: Default::default() });
|
||||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: Default::default() });
|
responses.add(FrontendMessage::UpdateMouseCursor { cursor: Default::default() });
|
||||||
|
@ -190,12 +191,12 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||||
ToolMessage::InitTools => {
|
ToolMessage::InitTools => {
|
||||||
// Subscribe the transform layer to selection change events
|
// Subscribe the transform layer to selection change events
|
||||||
responses.add(BroadcastMessage::SubscribeEvent {
|
responses.add(BroadcastMessage::SubscribeEvent {
|
||||||
on: BroadcastEvent::SelectionChanged,
|
on: EventMessage::SelectionChanged,
|
||||||
send: Box::new(TransformLayerMessage::SelectionChanged.into()),
|
send: Box::new(TransformLayerMessage::SelectionChanged.into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(BroadcastMessage::SubscribeEvent {
|
responses.add(BroadcastMessage::SubscribeEvent {
|
||||||
on: BroadcastEvent::SelectionChanged,
|
on: EventMessage::SelectionChanged,
|
||||||
send: Box::new(SelectToolMessage::SyncHistory.into()),
|
send: Box::new(SelectToolMessage::SyncHistory.into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -232,12 +233,12 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||||
tool_data.active_tool_mut().process_message(ToolMessage::UpdateHints, responses, &mut data);
|
tool_data.active_tool_mut().process_message(ToolMessage::UpdateHints, responses, &mut data);
|
||||||
tool_data.active_tool_mut().process_message(ToolMessage::UpdateCursor, responses, &mut data);
|
tool_data.active_tool_mut().process_message(ToolMessage::UpdateCursor, responses, &mut data);
|
||||||
|
|
||||||
responses.add(OverlaysMessage::AddProvider(ARTBOARD_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::AddProvider { provider: ARTBOARD_OVERLAY_PROVIDER });
|
||||||
}
|
}
|
||||||
ToolMessage::PreUndo => {
|
ToolMessage::PreUndo => {
|
||||||
let tool_data = &mut self.tool_state.tool_data;
|
let tool_data = &mut self.tool_state.tool_data;
|
||||||
if tool_data.active_tool_type != ToolType::Pen {
|
if tool_data.active_tool_type != ToolType::Pen {
|
||||||
responses.add(BroadcastEvent::ToolAbort);
|
responses.add(EventMessage::ToolAbort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToolMessage::Redo => {
|
ToolMessage::Redo => {
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub struct ArtboardTool {
|
||||||
pub enum ArtboardToolMessage {
|
pub enum ArtboardToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Abort,
|
Abort,
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
UpdateSelectedArtboard,
|
UpdateSelectedArtboard,
|
||||||
|
@ -83,7 +83,7 @@ impl ToolTransition for ArtboardTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
tool_abort: Some(ArtboardToolMessage::Abort.into()),
|
tool_abort: Some(ArtboardToolMessage::Abort.into()),
|
||||||
overlay_provider: Some(|overlay_context| ArtboardToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| ArtboardToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||||
|
|
||||||
let ToolMessage::Artboard(event) = event else { return self };
|
let ToolMessage::Artboard(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(state, ArtboardToolMessage::Overlays(mut overlay_context)) => {
|
(state, ArtboardToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
let display_transform_cage = overlay_context.visibility_settings.transform_cage();
|
let display_transform_cage = overlay_context.visibility_settings.transform_cage();
|
||||||
if display_transform_cage && state != ArtboardToolFsmState::Drawing {
|
if display_transform_cage && state != ArtboardToolFsmState::Drawing {
|
||||||
if let Some(bounds) = tool_data.selected_artboard.and_then(|layer| document.metadata().bounding_box_document(layer)) {
|
if let Some(bounds) = tool_data.selected_artboard.and_then(|layer| document.metadata().bounding_box_document(layer)) {
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub enum BrushToolMessage {
|
||||||
DragStart,
|
DragStart,
|
||||||
DragStop,
|
DragStop,
|
||||||
PointerMove,
|
PointerMove,
|
||||||
UpdateOptions(BrushToolMessageOptionsUpdate),
|
UpdateOptions { options: BrushToolMessageOptionsUpdate },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
@ -106,7 +106,7 @@ impl LayoutHolder for BrushTool {
|
||||||
.min(1.)
|
.min(1.)
|
||||||
.max(BRUSH_MAX_SIZE) /* Anything bigger would cause the application to be unresponsive and eventually die */
|
.max(BRUSH_MAX_SIZE) /* Anything bigger would cause the application to be unresponsive and eventually die */
|
||||||
.unit(" px")
|
.unit(" px")
|
||||||
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Diameter(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions { options: BrushToolMessageOptionsUpdate::Diameter(number_input.value.unwrap()) }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(self.options.hardness))
|
NumberInput::new(Some(self.options.hardness))
|
||||||
|
@ -115,7 +115,12 @@ impl LayoutHolder for BrushTool {
|
||||||
.max(100.)
|
.max(100.)
|
||||||
.mode_range()
|
.mode_range()
|
||||||
.unit("%")
|
.unit("%")
|
||||||
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Hardness(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
BrushToolMessage::UpdateOptions {
|
||||||
|
options: BrushToolMessageOptionsUpdate::Hardness(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(self.options.flow))
|
NumberInput::new(Some(self.options.flow))
|
||||||
|
@ -124,7 +129,12 @@ impl LayoutHolder for BrushTool {
|
||||||
.max(100.)
|
.max(100.)
|
||||||
.mode_range()
|
.mode_range()
|
||||||
.unit("%")
|
.unit("%")
|
||||||
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Flow(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
BrushToolMessage::UpdateOptions {
|
||||||
|
options: BrushToolMessageOptionsUpdate::Flow(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(self.options.spacing))
|
NumberInput::new(Some(self.options.spacing))
|
||||||
|
@ -133,7 +143,12 @@ impl LayoutHolder for BrushTool {
|
||||||
.max(100.)
|
.max(100.)
|
||||||
.mode_range()
|
.mode_range()
|
||||||
.unit("%")
|
.unit("%")
|
||||||
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Spacing(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
BrushToolMessage::UpdateOptions {
|
||||||
|
options: BrushToolMessageOptionsUpdate::Spacing(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -142,9 +157,12 @@ impl LayoutHolder for BrushTool {
|
||||||
let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore]
|
let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|draw_mode| {
|
.map(|draw_mode| {
|
||||||
RadioEntryData::new(format!("{draw_mode:?}"))
|
RadioEntryData::new(format!("{draw_mode:?}")).label(format!("{draw_mode:?}")).on_update(move |_| {
|
||||||
.label(format!("{draw_mode:?}"))
|
BrushToolMessage::UpdateOptions {
|
||||||
.on_update(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::DrawMode(draw_mode)).into())
|
options: BrushToolMessageOptionsUpdate::DrawMode(draw_mode),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
widgets.push(RadioInput::new(draw_mode_entries).selected_index(Some(self.options.draw_mode as u32)).widget_holder());
|
widgets.push(RadioInput::new(draw_mode_entries).selected_index(Some(self.options.draw_mode as u32)).widget_holder());
|
||||||
|
@ -154,9 +172,26 @@ impl LayoutHolder for BrushTool {
|
||||||
widgets.append(&mut self.options.color.create_widgets(
|
widgets.append(&mut self.options.color.create_widgets(
|
||||||
"Color",
|
"Color",
|
||||||
false,
|
false,
|
||||||
|_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Color(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ColorType(color_type.clone())).into()),
|
BrushToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Color(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: BrushToolMessageOptionsUpdate::Color(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
BrushToolMessage::UpdateOptions {
|
||||||
|
options: BrushToolMessageOptionsUpdate::ColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
BrushToolMessage::UpdateOptions {
|
||||||
|
options: BrushToolMessageOptionsUpdate::Color(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
||||||
|
@ -167,9 +202,12 @@ impl LayoutHolder for BrushTool {
|
||||||
section
|
section
|
||||||
.iter()
|
.iter()
|
||||||
.map(|blend_mode| {
|
.map(|blend_mode| {
|
||||||
MenuListEntry::new(format!("{blend_mode:?}"))
|
MenuListEntry::new(format!("{blend_mode:?}")).label(blend_mode.to_string()).on_commit(|_| {
|
||||||
.label(blend_mode.to_string())
|
BrushToolMessage::UpdateOptions {
|
||||||
.on_commit(|_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::BlendMode(*blend_mode)).into())
|
options: BrushToolMessageOptionsUpdate::BlendMode(*blend_mode),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
|
@ -189,11 +227,11 @@ impl LayoutHolder for BrushTool {
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for BrushTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for BrushTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Brush(BrushToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, true);
|
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, true);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match action {
|
match options {
|
||||||
BrushToolMessageOptionsUpdate::BlendMode(blend_mode) => self.options.blend_mode = blend_mode,
|
BrushToolMessageOptionsUpdate::BlendMode(blend_mode) => self.options.blend_mode = blend_mode,
|
||||||
BrushToolMessageOptionsUpdate::ChangeDiameter(change) => {
|
BrushToolMessageOptionsUpdate::ChangeDiameter(change) => {
|
||||||
let needs_rounding = ((self.options.diameter + change.abs() / 2.) % change.abs() - change.abs() / 2.).abs() > 0.5;
|
let needs_rounding = ((self.options.diameter + change.abs() / 2.) % change.abs() - change.abs() / 2.).abs() > 0.5;
|
||||||
|
@ -408,10 +446,9 @@ impl Fsm for BrushToolFsmState {
|
||||||
BrushToolFsmState::Ready
|
BrushToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, BrushToolMessage::WorkingColorChanged) => {
|
(_, BrushToolMessage::WorkingColorChanged) => {
|
||||||
responses.add(BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::WorkingColors(
|
responses.add(BrushToolMessage::UpdateOptions {
|
||||||
Some(global_tool_data.primary_color),
|
options: BrushToolMessageOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||||
Some(global_tool_data.secondary_color),
|
});
|
||||||
)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
_ => self,
|
_ => self,
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub enum FillToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Abort,
|
Abort,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
PointerMove,
|
PointerMove,
|
||||||
|
@ -67,7 +67,7 @@ impl ToolTransition for FillTool {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
tool_abort: Some(FillToolMessage::Abort.into()),
|
tool_abort: Some(FillToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(FillToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(FillToolMessage::WorkingColorChanged.into()),
|
||||||
overlay_provider: Some(|overlay_context| FillToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| FillToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ impl Fsm for FillToolFsmState {
|
||||||
|
|
||||||
let ToolMessage::Fill(event) = event else { return self };
|
let ToolMessage::Fill(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, FillToolMessage::Overlays(mut overlay_context)) => {
|
(_, FillToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
// Choose the working color to preview
|
// Choose the working color to preview
|
||||||
let use_secondary = input.keyboard.get(Key::Shift as usize);
|
let use_secondary = input.keyboard.get(Key::Shift as usize);
|
||||||
let preview_color = if use_secondary { global_tool_data.secondary_color } else { global_tool_data.primary_color };
|
let preview_color = if use_secondary { global_tool_data.secondary_color } else { global_tool_data.primary_color };
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl Default for FreehandOptions {
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum FreehandToolMessage {
|
pub enum FreehandToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
Abort,
|
Abort,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ pub enum FreehandToolMessage {
|
||||||
DragStart { append_to_selected: Key },
|
DragStart { append_to_selected: Key },
|
||||||
DragStop,
|
DragStop,
|
||||||
PointerMove,
|
PointerMove,
|
||||||
UpdateOptions(FreehandOptionsUpdate),
|
UpdateOptions { options: FreehandOptionsUpdate },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
@ -86,7 +86,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(1.)
|
.min(1.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
FreehandToolMessage::UpdateOptions {
|
||||||
|
options: FreehandOptionsUpdate::LineWeight(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +100,26 @@ impl LayoutHolder for FreehandTool {
|
||||||
let mut widgets = self.options.fill.create_widgets(
|
let mut widgets = self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
true,
|
true,
|
||||||
|_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColorType(color_type.clone())).into()),
|
FreehandToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: FreehandOptionsUpdate::FillColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
FreehandToolMessage::UpdateOptions {
|
||||||
|
options: FreehandOptionsUpdate::FillColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
FreehandToolMessage::UpdateOptions {
|
||||||
|
options: FreehandOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
@ -105,9 +127,26 @@ impl LayoutHolder for FreehandTool {
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
true,
|
true,
|
||||||
|_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
FreehandToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: FreehandOptionsUpdate::StrokeColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
FreehandToolMessage::UpdateOptions {
|
||||||
|
options: FreehandOptionsUpdate::StrokeColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
FreehandToolMessage::UpdateOptions {
|
||||||
|
options: FreehandOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
widgets.push(create_weight_widget(self.options.line_weight));
|
widgets.push(create_weight_widget(self.options.line_weight));
|
||||||
|
@ -119,11 +158,11 @@ impl LayoutHolder for FreehandTool {
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for FreehandTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for FreehandTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, true);
|
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, true);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match action {
|
match options {
|
||||||
FreehandOptionsUpdate::FillColor(color) => {
|
FreehandOptionsUpdate::FillColor(color) => {
|
||||||
self.options.fill.custom_color = color;
|
self.options.fill.custom_color = color;
|
||||||
self.options.fill.color_type = ToolColorType::Custom;
|
self.options.fill.color_type = ToolColorType::Custom;
|
||||||
|
@ -164,7 +203,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Free
|
||||||
impl ToolTransition for FreehandTool {
|
impl ToolTransition for FreehandTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
overlay_provider: Some(|overlay_context: OverlayContext| FreehandToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context: OverlayContext| FreehandToolMessage::Overlays { context }.into()),
|
||||||
tool_abort: Some(FreehandToolMessage::Abort.into()),
|
tool_abort: Some(FreehandToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(FreehandToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(FreehandToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -203,7 +242,7 @@ impl Fsm for FreehandToolFsmState {
|
||||||
|
|
||||||
let ToolMessage::Freehand(event) = event else { return self };
|
let ToolMessage::Freehand(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, FreehandToolMessage::Overlays(mut overlay_context)) => {
|
(_, FreehandToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
path_endpoint_overlays(document, shape_editor, &mut overlay_context, tool_action_data.preferences);
|
path_endpoint_overlays(document, shape_editor, &mut overlay_context, tool_action_data.preferences);
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -287,10 +326,9 @@ impl Fsm for FreehandToolFsmState {
|
||||||
FreehandToolFsmState::Ready
|
FreehandToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, FreehandToolMessage::WorkingColorChanged) => {
|
(_, FreehandToolMessage::WorkingColorChanged) => {
|
||||||
responses.add(FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::WorkingColors(
|
responses.add(FreehandToolMessage::UpdateOptions {
|
||||||
Some(global_tool_data.primary_color),
|
options: FreehandOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||||
Some(global_tool_data.secondary_color),
|
});
|
||||||
)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
_ => self,
|
_ => self,
|
||||||
|
@ -679,7 +717,9 @@ mod test_freehand {
|
||||||
|
|
||||||
let custom_line_weight = 5.;
|
let custom_line_weight = 5.;
|
||||||
editor
|
editor
|
||||||
.handle_message(ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(custom_line_weight))))
|
.handle_message(ToolMessage::Freehand(FreehandToolMessage::UpdateOptions {
|
||||||
|
options: FreehandOptionsUpdate::LineWeight(custom_line_weight),
|
||||||
|
}))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let points = [DVec2::new(100., 100.), DVec2::new(200., 200.), DVec2::new(300., 100.)];
|
let points = [DVec2::new(100., 100.), DVec2::new(200., 200.), DVec2::new(300., 100.)];
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub struct GradientOptions {
|
||||||
pub enum GradientToolMessage {
|
pub enum GradientToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Abort,
|
Abort,
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
DeleteStop,
|
DeleteStop,
|
||||||
|
@ -33,7 +33,7 @@ pub enum GradientToolMessage {
|
||||||
PointerMove { constrain_axis: Key },
|
PointerMove { constrain_axis: Key },
|
||||||
PointerOutsideViewport { constrain_axis: Key },
|
PointerOutsideViewport { constrain_axis: Key },
|
||||||
PointerUp,
|
PointerUp,
|
||||||
UpdateOptions(GradientOptionsUpdate),
|
UpdateOptions { options: GradientOptionsUpdate },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
@ -56,11 +56,11 @@ impl ToolMetadata for GradientTool {
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for GradientTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for GradientTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Gradient(GradientToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Gradient(GradientToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, false);
|
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, false);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match action {
|
match options {
|
||||||
GradientOptionsUpdate::Type(gradient_type) => {
|
GradientOptionsUpdate::Type(gradient_type) => {
|
||||||
self.options.gradient_type = gradient_type;
|
self.options.gradient_type = gradient_type;
|
||||||
// Update the selected gradient if it exists
|
// Update the selected gradient if it exists
|
||||||
|
@ -91,14 +91,18 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Grad
|
||||||
impl LayoutHolder for GradientTool {
|
impl LayoutHolder for GradientTool {
|
||||||
fn layout(&self) -> Layout {
|
fn layout(&self) -> Layout {
|
||||||
let gradient_type = RadioInput::new(vec![
|
let gradient_type = RadioInput::new(vec![
|
||||||
RadioEntryData::new("Linear")
|
RadioEntryData::new("Linear").label("Linear").tooltip("Linear gradient").on_update(move |_| {
|
||||||
.label("Linear")
|
GradientToolMessage::UpdateOptions {
|
||||||
.tooltip("Linear gradient")
|
options: GradientOptionsUpdate::Type(GradientType::Linear),
|
||||||
.on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Linear)).into()),
|
}
|
||||||
RadioEntryData::new("Radial")
|
.into()
|
||||||
.label("Radial")
|
}),
|
||||||
.tooltip("Radial gradient")
|
RadioEntryData::new("Radial").label("Radial").tooltip("Radial gradient").on_update(move |_| {
|
||||||
.on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Radial)).into()),
|
GradientToolMessage::UpdateOptions {
|
||||||
|
options: GradientOptionsUpdate::Type(GradientType::Radial),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
.selected_index(Some((self.selected_gradient().unwrap_or(self.options.gradient_type) == GradientType::Radial) as u32))
|
.selected_index(Some((self.selected_gradient().unwrap_or(self.options.gradient_type) == GradientType::Radial) as u32))
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
@ -224,7 +228,7 @@ impl ToolTransition for GradientTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
tool_abort: Some(GradientToolMessage::Abort.into()),
|
tool_abort: Some(GradientToolMessage::Abort.into()),
|
||||||
overlay_provider: Some(|overlay_context| GradientToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| GradientToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +260,7 @@ impl Fsm for GradientToolFsmState {
|
||||||
|
|
||||||
let ToolMessage::Gradient(event) = event else { return self };
|
let ToolMessage::Gradient(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
(_, GradientToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
let selected = tool_data.selected_gradient.as_ref();
|
let selected = tool_data.selected_gradient.as_ref();
|
||||||
|
|
||||||
for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) {
|
for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) {
|
||||||
|
|
|
@ -51,8 +51,10 @@ pub struct PathToolOptions {
|
||||||
pub enum PathToolMessage {
|
pub enum PathToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Abort,
|
Abort,
|
||||||
Overlays(OverlayContext),
|
|
||||||
SelectionChanged,
|
SelectionChanged,
|
||||||
|
Overlays {
|
||||||
|
context: OverlayContext,
|
||||||
|
},
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
BreakPath,
|
BreakPath,
|
||||||
|
@ -123,7 +125,9 @@ pub enum PathToolMessage {
|
||||||
position: ReferencePoint,
|
position: ReferencePoint,
|
||||||
},
|
},
|
||||||
SwapSelectedHandles,
|
SwapSelectedHandles,
|
||||||
UpdateOptions(PathOptionsUpdate),
|
UpdateOptions {
|
||||||
|
options: PathOptionsUpdate,
|
||||||
|
},
|
||||||
UpdateSelectedPointsStatus {
|
UpdateSelectedPointsStatus {
|
||||||
overlay_context: OverlayContext,
|
overlay_context: OverlayContext,
|
||||||
},
|
},
|
||||||
|
@ -275,15 +279,30 @@ impl LayoutHolder for PathTool {
|
||||||
RadioEntryData::new("all")
|
RadioEntryData::new("all")
|
||||||
.icon("HandleVisibilityAll")
|
.icon("HandleVisibilityAll")
|
||||||
.tooltip("Show all handles regardless of selection")
|
.tooltip("Show all handles regardless of selection")
|
||||||
.on_update(move |_| PathToolMessage::UpdateOptions(PathOptionsUpdate::OverlayModeType(PathOverlayMode::AllHandles)).into()),
|
.on_update(move |_| {
|
||||||
|
PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::OverlayModeType(PathOverlayMode::AllHandles),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
RadioEntryData::new("selected")
|
RadioEntryData::new("selected")
|
||||||
.icon("HandleVisibilitySelected")
|
.icon("HandleVisibilitySelected")
|
||||||
.tooltip("Show only handles of the segments connected to selected points")
|
.tooltip("Show only handles of the segments connected to selected points")
|
||||||
.on_update(move |_| PathToolMessage::UpdateOptions(PathOptionsUpdate::OverlayModeType(PathOverlayMode::SelectedPointHandles)).into()),
|
.on_update(move |_| {
|
||||||
|
PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::OverlayModeType(PathOverlayMode::SelectedPointHandles),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
RadioEntryData::new("frontier")
|
RadioEntryData::new("frontier")
|
||||||
.icon("HandleVisibilityFrontier")
|
.icon("HandleVisibilityFrontier")
|
||||||
.tooltip("Show only handles at the frontiers of the segments connected to selected points")
|
.tooltip("Show only handles at the frontiers of the segments connected to selected points")
|
||||||
.on_update(move |_| PathToolMessage::UpdateOptions(PathOptionsUpdate::OverlayModeType(PathOverlayMode::FrontierHandles)).into()),
|
.on_update(move |_| {
|
||||||
|
PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::OverlayModeType(PathOverlayMode::FrontierHandles),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
.selected_index(Some(self.options.path_overlay_mode as u32))
|
.selected_index(Some(self.options.path_overlay_mode as u32))
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
@ -345,7 +364,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Path
|
||||||
let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated);
|
let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated);
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
ToolMessage::Path(PathToolMessage::UpdateOptions(action)) => match action {
|
ToolMessage::Path(PathToolMessage::UpdateOptions { options }) => match options {
|
||||||
PathOptionsUpdate::OverlayModeType(overlay_mode_type) => {
|
PathOptionsUpdate::OverlayModeType(overlay_mode_type) => {
|
||||||
self.options.path_overlay_mode = overlay_mode_type;
|
self.options.path_overlay_mode = overlay_mode_type;
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
@ -478,7 +497,7 @@ impl ToolTransition for PathTool {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
tool_abort: Some(PathToolMessage::Abort.into()),
|
tool_abort: Some(PathToolMessage::Abort.into()),
|
||||||
selection_changed: Some(PathToolMessage::SelectionChanged.into()),
|
selection_changed: Some(PathToolMessage::SelectionChanged.into()),
|
||||||
overlay_provider: Some(|overlay_context| PathToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| PathToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1557,14 +1576,22 @@ impl Fsm for PathToolFsmState {
|
||||||
|
|
||||||
match (multiple_toggle, point_edit) {
|
match (multiple_toggle, point_edit) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::PointEditingMode { enabled: false }));
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::PointEditingMode { enabled: false },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::PointEditingMode { enabled: true }));
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::PointEditingMode { enabled: true },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::PointEditingMode { enabled: true }));
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::SegmentEditingMode { enabled: false }));
|
options: PathOptionsUpdate::PointEditingMode { enabled: true },
|
||||||
|
});
|
||||||
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::SegmentEditingMode { enabled: false },
|
||||||
|
});
|
||||||
|
|
||||||
// Select all of the end points of selected segments
|
// Select all of the end points of selected segments
|
||||||
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||||
|
@ -1602,14 +1629,22 @@ impl Fsm for PathToolFsmState {
|
||||||
|
|
||||||
match (multiple_toggle, segment_edit) {
|
match (multiple_toggle, segment_edit) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::SegmentEditingMode { enabled: false }));
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::SegmentEditingMode { enabled: false },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::SegmentEditingMode { enabled: true }));
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::SegmentEditingMode { enabled: true },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::PointEditingMode { enabled: false }));
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::SegmentEditingMode { enabled: true }));
|
options: PathOptionsUpdate::PointEditingMode { enabled: false },
|
||||||
|
});
|
||||||
|
responses.add(PathToolMessage::UpdateOptions {
|
||||||
|
options: PathOptionsUpdate::SegmentEditingMode { enabled: true },
|
||||||
|
});
|
||||||
|
|
||||||
// Select all the segments which have both of the ends selected
|
// Select all the segments which have both of the ends selected
|
||||||
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||||
|
@ -1632,7 +1667,7 @@ impl Fsm for PathToolFsmState {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::Overlays(mut overlay_context)) => {
|
(_, PathToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
// Set this to show ghost line only if drag actually happened
|
// Set this to show ghost line only if drag actually happened
|
||||||
if matches!(self, Self::Dragging(_)) && tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD {
|
if matches!(self, Self::Dragging(_)) && tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD {
|
||||||
for (outline, layer) in &tool_data.ghost_outline {
|
for (outline, layer) in &tool_data.ghost_outline {
|
||||||
|
|
|
@ -50,7 +50,9 @@ pub enum PenToolMessage {
|
||||||
Abort,
|
Abort,
|
||||||
SelectionChanged,
|
SelectionChanged,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
Overlays(OverlayContext),
|
Overlays {
|
||||||
|
context: OverlayContext,
|
||||||
|
},
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
|
|
||||||
|
@ -80,7 +82,9 @@ pub enum PenToolMessage {
|
||||||
},
|
},
|
||||||
Redo,
|
Redo,
|
||||||
Undo,
|
Undo,
|
||||||
UpdateOptions(PenOptionsUpdate),
|
UpdateOptions {
|
||||||
|
options: PenOptionsUpdate,
|
||||||
|
},
|
||||||
RecalculateLatestPointsPosition,
|
RecalculateLatestPointsPosition,
|
||||||
RemovePreviousHandle,
|
RemovePreviousHandle,
|
||||||
GRS {
|
GRS {
|
||||||
|
@ -138,7 +142,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::LineWeight(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,9 +156,26 @@ impl LayoutHolder for PenTool {
|
||||||
let mut widgets = self.options.fill.create_widgets(
|
let mut widgets = self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
true,
|
true,
|
||||||
|_| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColorType(color_type.clone())).into()),
|
PenToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: PenOptionsUpdate::FillColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::FillColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
@ -157,9 +183,26 @@ impl LayoutHolder for PenTool {
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
true,
|
true,
|
||||||
|_| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
PenToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: PenOptionsUpdate::StrokeColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::StrokeColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
@ -173,11 +216,21 @@ impl LayoutHolder for PenTool {
|
||||||
RadioEntryData::new("all")
|
RadioEntryData::new("all")
|
||||||
.icon("HandleVisibilityAll")
|
.icon("HandleVisibilityAll")
|
||||||
.tooltip("Show all handles regardless of selection")
|
.tooltip("Show all handles regardless of selection")
|
||||||
.on_update(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::OverlayModeType(PenOverlayMode::AllHandles)).into()),
|
.on_update(move |_| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::OverlayModeType(PenOverlayMode::AllHandles),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
RadioEntryData::new("frontier")
|
RadioEntryData::new("frontier")
|
||||||
.icon("HandleVisibilityFrontier")
|
.icon("HandleVisibilityFrontier")
|
||||||
.tooltip("Show only handles at the frontiers of the segments connected to selected points")
|
.tooltip("Show only handles at the frontiers of the segments connected to selected points")
|
||||||
.on_update(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::OverlayModeType(PenOverlayMode::FrontierHandles)).into()),
|
.on_update(move |_| {
|
||||||
|
PenToolMessage::UpdateOptions {
|
||||||
|
options: PenOptionsUpdate::OverlayModeType(PenOverlayMode::FrontierHandles),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
.selected_index(Some(self.options.pen_overlay_mode as u32))
|
.selected_index(Some(self.options.pen_overlay_mode as u32))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
|
@ -190,12 +243,12 @@ impl LayoutHolder for PenTool {
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for PenTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for PenTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Pen(PenToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
match action {
|
match options {
|
||||||
PenOptionsUpdate::OverlayModeType(overlay_mode_type) => {
|
PenOptionsUpdate::OverlayModeType(overlay_mode_type) => {
|
||||||
self.options.pen_overlay_mode = overlay_mode_type;
|
self.options.pen_overlay_mode = overlay_mode_type;
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
@ -253,7 +306,7 @@ impl ToolTransition for PenTool {
|
||||||
tool_abort: Some(PenToolMessage::Abort.into()),
|
tool_abort: Some(PenToolMessage::Abort.into()),
|
||||||
selection_changed: Some(PenToolMessage::SelectionChanged.into()),
|
selection_changed: Some(PenToolMessage::SelectionChanged.into()),
|
||||||
working_color_changed: Some(PenToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(PenToolMessage::WorkingColorChanged.into()),
|
||||||
overlay_provider: Some(|overlay_context| PenToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| PenToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1547,7 +1600,7 @@ impl Fsm for PenToolFsmState {
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(PenToolFsmState::Ready, PenToolMessage::Overlays(mut overlay_context)) => {
|
(PenToolFsmState::Ready, PenToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
match tool_options.pen_overlay_mode {
|
match tool_options.pen_overlay_mode {
|
||||||
PenOverlayMode::AllHandles => {
|
PenOverlayMode::AllHandles => {
|
||||||
path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context);
|
path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context);
|
||||||
|
@ -1575,7 +1628,7 @@ impl Fsm for PenToolFsmState {
|
||||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, PenToolMessage::Overlays(mut overlay_context)) => {
|
(_, PenToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
let display_anchors = overlay_context.visibility_settings.anchors();
|
let display_anchors = overlay_context.visibility_settings.anchors();
|
||||||
let display_handles = overlay_context.visibility_settings.handles();
|
let display_handles = overlay_context.visibility_settings.handles();
|
||||||
|
|
||||||
|
@ -1753,10 +1806,9 @@ impl Fsm for PenToolFsmState {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, PenToolMessage::WorkingColorChanged) => {
|
(_, PenToolMessage::WorkingColorChanged) => {
|
||||||
responses.add(PenToolMessage::UpdateOptions(PenOptionsUpdate::WorkingColors(
|
responses.add(PenToolMessage::UpdateOptions {
|
||||||
Some(global_tool_data.primary_color),
|
options: PenOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||||
Some(global_tool_data.secondary_color),
|
});
|
||||||
)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(PenToolFsmState::Ready, PenToolMessage::DragStart { append_to_selected }) => {
|
(PenToolFsmState::Ready, PenToolMessage::DragStart { append_to_selected }) => {
|
||||||
|
|
|
@ -78,7 +78,9 @@ pub struct SelectToolPointerKeys {
|
||||||
pub enum SelectToolMessage {
|
pub enum SelectToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Abort,
|
Abort,
|
||||||
Overlays(OverlayContext),
|
Overlays {
|
||||||
|
context: OverlayContext,
|
||||||
|
},
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
DragStart {
|
DragStart {
|
||||||
|
@ -94,9 +96,15 @@ pub enum SelectToolMessage {
|
||||||
EditLayer,
|
EditLayer,
|
||||||
EditLayerExec,
|
EditLayerExec,
|
||||||
Enter,
|
Enter,
|
||||||
PointerMove(SelectToolPointerKeys),
|
PointerMove {
|
||||||
PointerOutsideViewport(SelectToolPointerKeys),
|
modifier_keys: SelectToolPointerKeys,
|
||||||
SelectOptions(SelectOptionsUpdate),
|
},
|
||||||
|
PointerOutsideViewport {
|
||||||
|
modifier_keys: SelectToolPointerKeys,
|
||||||
|
},
|
||||||
|
SelectOptions {
|
||||||
|
options: SelectOptionsUpdate,
|
||||||
|
},
|
||||||
SetPivot {
|
SetPivot {
|
||||||
position: ReferencePoint,
|
position: ReferencePoint,
|
||||||
},
|
},
|
||||||
|
@ -127,9 +135,12 @@ impl SelectTool {
|
||||||
let layer_selection_behavior_entries = [NestedSelectionBehavior::Shallowest, NestedSelectionBehavior::Deepest]
|
let layer_selection_behavior_entries = [NestedSelectionBehavior::Shallowest, NestedSelectionBehavior::Deepest]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|mode| {
|
.map(|mode| {
|
||||||
MenuListEntry::new(format!("{mode:?}"))
|
MenuListEntry::new(format!("{mode:?}")).label(mode.to_string()).on_commit(move |_| {
|
||||||
.label(mode.to_string())
|
SelectToolMessage::SelectOptions {
|
||||||
.on_commit(move |_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::NestedSelectionBehavior(*mode)).into())
|
options: SelectOptionsUpdate::NestedSelectionBehavior(*mode),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -278,7 +289,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Sele
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let mut redraw_reference_pivot = false;
|
let mut redraw_reference_pivot = false;
|
||||||
|
|
||||||
if let ToolMessage::Select(SelectToolMessage::SelectOptions(ref option_update)) = message {
|
if let ToolMessage::Select(SelectToolMessage::SelectOptions { options: ref option_update }) = message {
|
||||||
match option_update {
|
match option_update {
|
||||||
SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => {
|
SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => {
|
||||||
self.tool_data.nested_selection_behavior = *nested_selection_behavior;
|
self.tool_data.nested_selection_behavior = *nested_selection_behavior;
|
||||||
|
@ -342,7 +353,7 @@ impl ToolTransition for SelectTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
tool_abort: Some(SelectToolMessage::Abort.into()),
|
tool_abort: Some(SelectToolMessage::Abort.into()),
|
||||||
overlay_provider: Some(|overlay_context| SelectToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| SelectToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,7 +602,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
let ToolMessage::Select(event) = event else { return self };
|
let ToolMessage::Select(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, SelectToolMessage::Overlays(mut overlay_context)) => {
|
(_, SelectToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||||
|
|
||||||
let selected_layers_count = document.network_interface.selected_nodes().selected_unlocked_layers(&document.network_interface).count();
|
let selected_layers_count = document.network_interface.selected_nodes().selected_unlocked_layers(&document.network_interface).count();
|
||||||
|
@ -1142,7 +1153,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
deepest,
|
deepest,
|
||||||
remove,
|
remove,
|
||||||
},
|
},
|
||||||
SelectToolMessage::PointerMove(modifier_keys),
|
SelectToolMessage::PointerMove { modifier_keys },
|
||||||
) => {
|
) => {
|
||||||
if !has_dragged {
|
if !has_dragged {
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
|
@ -1187,8 +1198,8 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let messages = [
|
let messages = [
|
||||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||||
];
|
];
|
||||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||||
|
|
||||||
|
@ -1200,7 +1211,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
remove,
|
remove,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove(modifier_keys)) => {
|
(SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove { modifier_keys }) => {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
resize_bounds(
|
resize_bounds(
|
||||||
document,
|
document,
|
||||||
|
@ -1215,14 +1226,14 @@ impl Fsm for SelectToolFsmState {
|
||||||
ToolType::Select,
|
ToolType::Select,
|
||||||
);
|
);
|
||||||
let messages = [
|
let messages = [
|
||||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||||
];
|
];
|
||||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||||
}
|
}
|
||||||
SelectToolFsmState::ResizingBounds
|
SelectToolFsmState::ResizingBounds
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::SkewingBounds { skew }, SelectToolMessage::PointerMove(_)) => {
|
(SelectToolFsmState::SkewingBounds { skew }, SelectToolMessage::PointerMove { .. }) => {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
skew_bounds(
|
skew_bounds(
|
||||||
document,
|
document,
|
||||||
|
@ -1236,7 +1247,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
}
|
}
|
||||||
SelectToolFsmState::SkewingBounds { skew }
|
SelectToolFsmState::SkewingBounds { skew }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::RotatingBounds, SelectToolMessage::PointerMove(_)) => {
|
(SelectToolFsmState::RotatingBounds, SelectToolMessage::PointerMove { .. }) => {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
rotate_bounds(
|
rotate_bounds(
|
||||||
document,
|
document,
|
||||||
|
@ -1252,7 +1263,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
SelectToolFsmState::RotatingBounds
|
SelectToolFsmState::RotatingBounds
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => {
|
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove { modifier_keys }) => {
|
||||||
let mouse_position = input.mouse.position;
|
let mouse_position = input.mouse.position;
|
||||||
let snapped_mouse_position = mouse_position;
|
let snapped_mouse_position = mouse_position;
|
||||||
|
|
||||||
|
@ -1262,14 +1273,14 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let messages = [
|
let messages = [
|
||||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||||
];
|
];
|
||||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||||
|
|
||||||
SelectToolFsmState::DraggingPivot
|
SelectToolFsmState::DraggingPivot
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Drawing { selection_shape, has_drawn }, SelectToolMessage::PointerMove(modifier_keys)) => {
|
(SelectToolFsmState::Drawing { selection_shape, has_drawn }, SelectToolMessage::PointerMove { modifier_keys }) => {
|
||||||
if !has_drawn {
|
if !has_drawn {
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
}
|
}
|
||||||
|
@ -1283,14 +1294,14 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let messages = [
|
let messages = [
|
||||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||||
];
|
];
|
||||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||||
|
|
||||||
SelectToolFsmState::Drawing { selection_shape, has_drawn: true }
|
SelectToolFsmState::Drawing { selection_shape, has_drawn: true }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => {
|
(SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove { .. }) => {
|
||||||
let dragging_bounds = tool_data
|
let dragging_bounds = tool_data
|
||||||
.bounding_box_manager
|
.bounding_box_manager
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -1326,7 +1337,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
deepest,
|
deepest,
|
||||||
remove,
|
remove,
|
||||||
},
|
},
|
||||||
SelectToolMessage::PointerOutsideViewport(_),
|
SelectToolMessage::PointerOutsideViewport { .. },
|
||||||
) => {
|
) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||||
|
@ -1342,7 +1353,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
remove,
|
remove,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
|
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
|
@ -1353,13 +1364,13 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => {
|
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport { .. }) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let _ = tool_data.auto_panning.shift_viewport(input, responses);
|
let _ = tool_data.auto_panning.shift_viewport(input, responses);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
|
(SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||||
tool_data.drag_start += shift;
|
tool_data.drag_start += shift;
|
||||||
|
@ -1367,11 +1378,11 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(state, SelectToolMessage::PointerOutsideViewport(modifier_keys)) => {
|
(state, SelectToolMessage::PointerOutsideViewport { modifier_keys }) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let messages = [
|
let messages = [
|
||||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||||
];
|
];
|
||||||
tool_data.auto_panning.stop(&messages, responses);
|
tool_data.auto_panning.stop(&messages, responses);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use graphene_std::renderer::Quad;
|
||||||
use graphene_std::vector::misc::ArcType;
|
use graphene_std::vector::misc::ArcType;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, ExtractField)]
|
||||||
pub struct ShapeTool {
|
pub struct ShapeTool {
|
||||||
fsm_state: ShapeToolFsmState,
|
fsm_state: ShapeToolFsmState,
|
||||||
tool_data: ShapeToolData,
|
tool_data: ShapeToolData,
|
||||||
|
@ -73,18 +73,18 @@ pub enum ShapeOptionsUpdate {
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum ShapeToolMessage {
|
pub enum ShapeToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
Abort,
|
Abort,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
DragStart,
|
DragStart,
|
||||||
DragStop,
|
DragStop,
|
||||||
HideShapeTypeWidget(bool),
|
HideShapeTypeWidget { hide: bool },
|
||||||
PointerMove(ShapeToolModifierKey),
|
PointerMove { modifier: ShapeToolModifierKey },
|
||||||
PointerOutsideViewport(ShapeToolModifierKey),
|
PointerOutsideViewport { modifier: ShapeToolModifierKey },
|
||||||
UpdateOptions(ShapeOptionsUpdate),
|
UpdateOptions { options: ShapeOptionsUpdate },
|
||||||
SetShape(ShapeType),
|
SetShape { shape: ShapeType },
|
||||||
|
|
||||||
IncreaseSides,
|
IncreaseSides,
|
||||||
DecreaseSides,
|
DecreaseSides,
|
||||||
|
@ -99,39 +99,65 @@ fn create_sides_widget(vertices: u32) -> WidgetHolder {
|
||||||
.min(3.)
|
.min(3.)
|
||||||
.max(1000.)
|
.max(1000.)
|
||||||
.mode(NumberInputMode::Increment)
|
.mode(NumberInputMode::Increment)
|
||||||
.on_update(|number_input: &NumberInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(number_input.value.unwrap() as u32)).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::Vertices(number_input.value.unwrap() as u32),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder {
|
fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder {
|
||||||
let entries = vec![vec![
|
let entries = vec![vec![
|
||||||
MenuListEntry::new("Polygon")
|
MenuListEntry::new("Polygon").label("Polygon").on_commit(move |_| {
|
||||||
.label("Polygon")
|
ShapeToolMessage::UpdateOptions {
|
||||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Polygon)).into()),
|
options: ShapeOptionsUpdate::ShapeType(ShapeType::Polygon),
|
||||||
MenuListEntry::new("Star")
|
}
|
||||||
.label("Star")
|
.into()
|
||||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Star)).into()),
|
}),
|
||||||
MenuListEntry::new("Circle")
|
MenuListEntry::new("Star").label("Star").on_commit(move |_| {
|
||||||
.label("Circle")
|
ShapeToolMessage::UpdateOptions {
|
||||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Circle)).into()),
|
options: ShapeOptionsUpdate::ShapeType(ShapeType::Star),
|
||||||
MenuListEntry::new("Arc")
|
}
|
||||||
.label("Arc")
|
.into()
|
||||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Arc)).into()),
|
}),
|
||||||
|
MenuListEntry::new("Circle").label("Circle").on_commit(move |_| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::ShapeType(ShapeType::Circle),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
|
MenuListEntry::new("Arc").label("Arc").on_commit(move |_| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::ShapeType(ShapeType::Arc),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
]];
|
]];
|
||||||
DropdownInput::new(entries).selected_index(Some(shape_type as u32)).widget_holder()
|
DropdownInput::new(entries).selected_index(Some(shape_type as u32)).widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_arc_type_widget(arc_type: ArcType) -> WidgetHolder {
|
fn create_arc_type_widget(arc_type: ArcType) -> WidgetHolder {
|
||||||
let entries = vec![
|
let entries = vec![
|
||||||
RadioEntryData::new("Open")
|
RadioEntryData::new("Open").label("Open").on_update(move |_| {
|
||||||
.label("Open")
|
ShapeToolMessage::UpdateOptions {
|
||||||
.on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ArcType(ArcType::Open)).into()),
|
options: ShapeOptionsUpdate::ArcType(ArcType::Open),
|
||||||
RadioEntryData::new("Closed")
|
}
|
||||||
.label("Closed")
|
.into()
|
||||||
.on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ArcType(ArcType::Closed)).into()),
|
}),
|
||||||
RadioEntryData::new("Pie")
|
RadioEntryData::new("Closed").label("Closed").on_update(move |_| {
|
||||||
.label("Pie")
|
ShapeToolMessage::UpdateOptions {
|
||||||
.on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ArcType(ArcType::PieSlice)).into()),
|
options: ShapeOptionsUpdate::ArcType(ArcType::Closed),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
|
RadioEntryData::new("Pie").label("Pie").on_update(move |_| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::ArcType(ArcType::PieSlice),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
RadioInput::new(entries).selected_index(Some(arc_type as u32)).widget_holder()
|
RadioInput::new(entries).selected_index(Some(arc_type as u32)).widget_holder()
|
||||||
}
|
}
|
||||||
|
@ -142,7 +168,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::LineWeight(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +200,26 @@ impl LayoutHolder for ShapeTool {
|
||||||
widgets.append(&mut self.options.fill.create_widgets(
|
widgets.append(&mut self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
true,
|
true,
|
||||||
|_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColorType(color_type.clone())).into()),
|
ShapeToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: ShapeOptionsUpdate::FillColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::FillColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
@ -180,9 +228,26 @@ impl LayoutHolder for ShapeTool {
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
true,
|
true,
|
||||||
|_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
ShapeToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: ShapeOptionsUpdate::StrokeColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::StrokeColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
widgets.push(create_weight_widget(self.options.line_weight));
|
widgets.push(create_weight_widget(self.options.line_weight));
|
||||||
|
@ -191,13 +256,14 @@ impl LayoutHolder for ShapeTool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for ShapeTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for ShapeTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Shape(ShapeToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Shape(ShapeToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match action {
|
match options {
|
||||||
ShapeOptionsUpdate::FillColor(color) => {
|
ShapeOptionsUpdate::FillColor(color) => {
|
||||||
self.options.fill.custom_color = color;
|
self.options.fill.custom_color = color;
|
||||||
self.options.fill.color_type = ToolColorType::Custom;
|
self.options.fill.color_type = ToolColorType::Custom;
|
||||||
|
@ -285,7 +351,7 @@ impl ToolMetadata for ShapeTool {
|
||||||
impl ToolTransition for ShapeTool {
|
impl ToolTransition for ShapeTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
overlay_provider: Some(|overlay_context| ShapeToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| ShapeToolMessage::Overlays { context }.into()),
|
||||||
tool_abort: Some(ShapeToolMessage::Abort.into()),
|
tool_abort: Some(ShapeToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(ShapeToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(ShapeToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -402,7 +468,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
let ToolMessage::Shape(event) = event else { return self };
|
let ToolMessage::Shape(event) = event else { return self };
|
||||||
|
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, ShapeToolMessage::Overlays(mut overlay_context)) => {
|
(_, ShapeToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
let mouse_position = tool_data
|
let mouse_position = tool_data
|
||||||
.data
|
.data
|
||||||
.snap_manager
|
.snap_manager
|
||||||
|
@ -484,11 +550,15 @@ impl Fsm for ShapeToolFsmState {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::Ready(_), ShapeToolMessage::IncreaseSides) => {
|
(ShapeToolFsmState::Ready(_), ShapeToolMessage::IncreaseSides) => {
|
||||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(tool_options.vertices + 1)));
|
responses.add(ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::Vertices(tool_options.vertices + 1),
|
||||||
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::Ready(_), ShapeToolMessage::DecreaseSides) => {
|
(ShapeToolFsmState::Ready(_), ShapeToolMessage::DecreaseSides) => {
|
||||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices((tool_options.vertices - 1).max(3))));
|
responses.add(ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::Vertices((tool_options.vertices - 1).max(3)),
|
||||||
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
|
@ -542,7 +612,9 @@ impl Fsm for ShapeToolFsmState {
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
|
|
||||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(n + 1)));
|
responses.add(ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::Vertices(n + 1),
|
||||||
|
});
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SetInput {
|
responses.add(NodeGraphMessage::SetInput {
|
||||||
input_connector: InputConnector::node(node_id, 1),
|
input_connector: InputConnector::node(node_id, 1),
|
||||||
|
@ -571,7 +643,9 @@ impl Fsm for ShapeToolFsmState {
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
|
|
||||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices((n - 1).max(3))));
|
responses.add(ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::Vertices((n - 1).max(3)),
|
||||||
|
});
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SetInput {
|
responses.add(NodeGraphMessage::SetInput {
|
||||||
input_connector: InputConnector::node(node_id, 1),
|
input_connector: InputConnector::node(node_id, 1),
|
||||||
|
@ -603,7 +677,9 @@ impl Fsm for ShapeToolFsmState {
|
||||||
tool_data.cursor = cursor;
|
tool_data.cursor = cursor;
|
||||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||||
// Send a PointerMove message to refresh the cursor icon
|
// Send a PointerMove message to refresh the cursor icon
|
||||||
responses.add(ShapeToolMessage::PointerMove(ShapeToolData::shape_tool_modifier_keys()));
|
responses.add(ShapeToolMessage::PointerMove {
|
||||||
|
modifier: ShapeToolData::shape_tool_modifier_keys(),
|
||||||
|
});
|
||||||
|
|
||||||
return ShapeToolFsmState::ModifyingGizmo;
|
return ShapeToolFsmState::ModifyingGizmo;
|
||||||
}
|
}
|
||||||
|
@ -630,7 +706,9 @@ impl Fsm for ShapeToolFsmState {
|
||||||
let cursor = tool_data.transform_cage_mouse_icon(input);
|
let cursor = tool_data.transform_cage_mouse_icon(input);
|
||||||
tool_data.cursor = cursor;
|
tool_data.cursor = cursor;
|
||||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||||
responses.add(ShapeToolMessage::PointerMove(ShapeToolData::shape_tool_modifier_keys()));
|
responses.add(ShapeToolMessage::PointerMove {
|
||||||
|
modifier: ShapeToolData::shape_tool_modifier_keys(),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
match (resize, rotate, skew) {
|
match (resize, rotate, skew) {
|
||||||
|
@ -710,7 +788,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
|
|
||||||
ShapeToolFsmState::Drawing(tool_data.current_shape)
|
ShapeToolFsmState::Drawing(tool_data.current_shape)
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::Drawing(shape), ShapeToolMessage::PointerMove(modifier)) => {
|
(ShapeToolFsmState::Drawing(shape), ShapeToolMessage::PointerMove { modifier }) => {
|
||||||
let Some(layer) = tool_data.data.layer else {
|
let Some(layer) = tool_data.data.layer else {
|
||||||
return ShapeToolFsmState::Ready(shape);
|
return ShapeToolFsmState::Ready(shape);
|
||||||
};
|
};
|
||||||
|
@ -726,33 +804,33 @@ impl Fsm for ShapeToolFsmState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let messages = [ShapeToolMessage::PointerOutsideViewport(modifier).into(), ShapeToolMessage::PointerMove(modifier).into()];
|
let messages = [ShapeToolMessage::PointerOutsideViewport { modifier }.into(), ShapeToolMessage::PointerMove { modifier }.into()];
|
||||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::DraggingLineEndpoints, ShapeToolMessage::PointerMove(modifier)) => {
|
(ShapeToolFsmState::DraggingLineEndpoints, ShapeToolMessage::PointerMove { modifier }) => {
|
||||||
let Some(layer) = tool_data.line_data.editing_layer else {
|
let Some(layer) = tool_data.line_data.editing_layer else {
|
||||||
return ShapeToolFsmState::Ready(tool_data.current_shape);
|
return ShapeToolFsmState::Ready(tool_data.current_shape);
|
||||||
};
|
};
|
||||||
|
|
||||||
Line::update_shape(document, input, layer, tool_data, modifier, responses);
|
Line::update_shape(document, input, layer, tool_data, modifier, responses);
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let messages = [ShapeToolMessage::PointerOutsideViewport(modifier).into(), ShapeToolMessage::PointerMove(modifier).into()];
|
let messages = [ShapeToolMessage::PointerOutsideViewport { modifier }.into(), ShapeToolMessage::PointerMove { modifier }.into()];
|
||||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove(..)) => {
|
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove { .. }) => {
|
||||||
tool_data.gizmo_manager.handle_update(tool_data.data.viewport_drag_start(document), document, input, responses);
|
tool_data.gizmo_manager.handle_update(tool_data.data.viewport_drag_start(document), document, input, responses);
|
||||||
|
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|
||||||
ShapeToolFsmState::ModifyingGizmo
|
ShapeToolFsmState::ModifyingGizmo
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::ResizingBounds, ShapeToolMessage::PointerMove(modifier)) => {
|
(ShapeToolFsmState::ResizingBounds, ShapeToolMessage::PointerMove { modifier }) => {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
let messages = [ShapeToolMessage::PointerOutsideViewport(modifier).into(), ShapeToolMessage::PointerMove(modifier).into()];
|
let messages = [ShapeToolMessage::PointerOutsideViewport { modifier }.into(), ShapeToolMessage::PointerMove { modifier }.into()];
|
||||||
resize_bounds(
|
resize_bounds(
|
||||||
document,
|
document,
|
||||||
responses,
|
responses,
|
||||||
|
@ -771,7 +849,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
ShapeToolFsmState::ResizingBounds
|
ShapeToolFsmState::ResizingBounds
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::RotatingBounds, ShapeToolMessage::PointerMove(modifier)) => {
|
(ShapeToolFsmState::RotatingBounds, ShapeToolMessage::PointerMove { modifier }) => {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
rotate_bounds(
|
rotate_bounds(
|
||||||
document,
|
document,
|
||||||
|
@ -787,7 +865,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
|
|
||||||
ShapeToolFsmState::RotatingBounds
|
ShapeToolFsmState::RotatingBounds
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::SkewingBounds { skew }, ShapeToolMessage::PointerMove(_)) => {
|
(ShapeToolFsmState::SkewingBounds { skew }, ShapeToolMessage::PointerMove { .. }) => {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
skew_bounds(
|
skew_bounds(
|
||||||
document,
|
document,
|
||||||
|
@ -803,7 +881,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
ShapeToolFsmState::SkewingBounds { skew }
|
ShapeToolFsmState::SkewingBounds { skew }
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, ShapeToolMessage::PointerMove(_)) => {
|
(_, ShapeToolMessage::PointerMove { .. }) => {
|
||||||
let dragging_bounds = tool_data
|
let dragging_bounds = tool_data
|
||||||
.bounding_box_manager
|
.bounding_box_manager
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -825,7 +903,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. }, ShapeToolMessage::PointerOutsideViewport(_)) => {
|
(ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. }, ShapeToolMessage::PointerOutsideViewport { .. }) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
|
@ -836,7 +914,7 @@ impl Fsm for ShapeToolFsmState {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::Ready(_), ShapeToolMessage::PointerOutsideViewport(..)) => self,
|
(ShapeToolFsmState::Ready(_), ShapeToolMessage::PointerOutsideViewport { .. }) => self,
|
||||||
(_, ShapeToolMessage::PointerOutsideViewport { .. }) => {
|
(_, ShapeToolMessage::PointerOutsideViewport { .. }) => {
|
||||||
// Auto-panning
|
// Auto-panning
|
||||||
let _ = tool_data.auto_panning.shift_viewport(input, responses);
|
let _ = tool_data.auto_panning.shift_viewport(input, responses);
|
||||||
|
@ -891,21 +969,22 @@ impl Fsm for ShapeToolFsmState {
|
||||||
ShapeToolFsmState::Ready(tool_data.current_shape)
|
ShapeToolFsmState::Ready(tool_data.current_shape)
|
||||||
}
|
}
|
||||||
(_, ShapeToolMessage::WorkingColorChanged) => {
|
(_, ShapeToolMessage::WorkingColorChanged) => {
|
||||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::WorkingColors(
|
responses.add(ShapeToolMessage::UpdateOptions {
|
||||||
Some(global_tool_data.primary_color),
|
options: ShapeOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||||
Some(global_tool_data.secondary_color),
|
});
|
||||||
)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, ShapeToolMessage::SetShape(shape)) => {
|
(_, ShapeToolMessage::SetShape { shape }) => {
|
||||||
responses.add(DocumentMessage::AbortTransaction);
|
responses.add(DocumentMessage::AbortTransaction);
|
||||||
tool_data.data.cleanup(responses);
|
tool_data.data.cleanup(responses);
|
||||||
tool_data.current_shape = shape;
|
tool_data.current_shape = shape;
|
||||||
|
|
||||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(shape)));
|
responses.add(ShapeToolMessage::UpdateOptions {
|
||||||
|
options: ShapeOptionsUpdate::ShapeType(shape),
|
||||||
|
});
|
||||||
ShapeToolFsmState::Ready(shape)
|
ShapeToolFsmState::Ready(shape)
|
||||||
}
|
}
|
||||||
(_, ShapeToolMessage::HideShapeTypeWidget(hide)) => {
|
(_, ShapeToolMessage::HideShapeTypeWidget { hide }) => {
|
||||||
tool_data.hide_shape_option_widget = hide;
|
tool_data.hide_shape_option_widget = hide;
|
||||||
responses.add(ToolMessage::RefreshToolOptions);
|
responses.add(ToolMessage::RefreshToolOptions);
|
||||||
self
|
self
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl Default for SplineOptions {
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum SplineToolMessage {
|
pub enum SplineToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
CanvasTransformed,
|
CanvasTransformed,
|
||||||
Abort,
|
Abort,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
|
@ -54,7 +54,7 @@ pub enum SplineToolMessage {
|
||||||
PointerMove,
|
PointerMove,
|
||||||
PointerOutsideViewport,
|
PointerOutsideViewport,
|
||||||
Undo,
|
Undo,
|
||||||
UpdateOptions(SplineOptionsUpdate),
|
UpdateOptions { options: SplineOptionsUpdate },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
@ -93,7 +93,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
SplineToolMessage::UpdateOptions {
|
||||||
|
options: SplineOptionsUpdate::LineWeight(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,9 +107,26 @@ impl LayoutHolder for SplineTool {
|
||||||
let mut widgets = self.options.fill.create_widgets(
|
let mut widgets = self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
true,
|
true,
|
||||||
|_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColorType(color_type.clone())).into()),
|
SplineToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: SplineOptionsUpdate::FillColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
SplineToolMessage::UpdateOptions {
|
||||||
|
options: SplineOptionsUpdate::FillColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
SplineToolMessage::UpdateOptions {
|
||||||
|
options: SplineOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
@ -112,9 +134,26 @@ impl LayoutHolder for SplineTool {
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
true,
|
true,
|
||||||
|_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
SplineToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: SplineOptionsUpdate::StrokeColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
SplineToolMessage::UpdateOptions {
|
||||||
|
options: SplineOptionsUpdate::StrokeColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
SplineToolMessage::UpdateOptions {
|
||||||
|
options: SplineOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
widgets.push(create_weight_widget(self.options.line_weight));
|
widgets.push(create_weight_widget(self.options.line_weight));
|
||||||
|
@ -126,11 +165,11 @@ impl LayoutHolder for SplineTool {
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for SplineTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for SplineTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Spline(SplineToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Spline(SplineToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match action {
|
match options {
|
||||||
SplineOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight,
|
SplineOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight,
|
||||||
SplineOptionsUpdate::FillColor(color) => {
|
SplineOptionsUpdate::FillColor(color) => {
|
||||||
self.options.fill.custom_color = color;
|
self.options.fill.custom_color = color;
|
||||||
|
@ -179,7 +218,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Spli
|
||||||
impl ToolTransition for SplineTool {
|
impl ToolTransition for SplineTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
overlay_provider: Some(|overlay_context: OverlayContext| SplineToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context: OverlayContext| SplineToolMessage::Overlays { context }.into()),
|
||||||
canvas_transformed: Some(SplineToolMessage::CanvasTransformed.into()),
|
canvas_transformed: Some(SplineToolMessage::CanvasTransformed.into()),
|
||||||
tool_abort: Some(SplineToolMessage::Abort.into()),
|
tool_abort: Some(SplineToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()),
|
||||||
|
@ -262,7 +301,7 @@ impl Fsm for SplineToolFsmState {
|
||||||
let ToolMessage::Spline(event) = event else { return self };
|
let ToolMessage::Spline(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, SplineToolMessage::CanvasTransformed) => self,
|
(_, SplineToolMessage::CanvasTransformed) => self,
|
||||||
(_, SplineToolMessage::Overlays(mut overlay_context)) => {
|
(_, SplineToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
path_endpoint_overlays(document, shape_editor, &mut overlay_context, preferences);
|
path_endpoint_overlays(document, shape_editor, &mut overlay_context, preferences);
|
||||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||||
self
|
self
|
||||||
|
@ -440,10 +479,9 @@ impl Fsm for SplineToolFsmState {
|
||||||
SplineToolFsmState::Ready
|
SplineToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, SplineToolMessage::WorkingColorChanged) => {
|
(_, SplineToolMessage::WorkingColorChanged) => {
|
||||||
responses.add(SplineToolMessage::UpdateOptions(SplineOptionsUpdate::WorkingColors(
|
responses.add(SplineToolMessage::UpdateOptions {
|
||||||
Some(global_tool_data.primary_color),
|
options: SplineOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||||
Some(global_tool_data.secondary_color),
|
});
|
||||||
)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
_ => self,
|
_ => self,
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub enum TextToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
Abort,
|
Abort,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
Overlays(OverlayContext),
|
Overlays { context: OverlayContext },
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
DragStart,
|
DragStart,
|
||||||
|
@ -70,7 +70,7 @@ pub enum TextToolMessage {
|
||||||
PointerOutsideViewport { center: Key, lock_ratio: Key },
|
PointerOutsideViewport { center: Key, lock_ratio: Key },
|
||||||
TextChange { new_text: String, is_left_or_right_click: bool },
|
TextChange { new_text: String, is_left_or_right_click: bool },
|
||||||
UpdateBounds { new_text: String },
|
UpdateBounds { new_text: String },
|
||||||
UpdateOptions(TextOptionsUpdate),
|
UpdateOptions { options: TextOptionsUpdate },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
@ -100,20 +100,24 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
|
||||||
let font = FontInput::new(&tool.options.font_name, &tool.options.font_style)
|
let font = FontInput::new(&tool.options.font_name, &tool.options.font_style)
|
||||||
.is_style_picker(false)
|
.is_style_picker(false)
|
||||||
.on_update(|font_input: &FontInput| {
|
.on_update(|font_input: &FontInput| {
|
||||||
TextToolMessage::UpdateOptions(TextOptionsUpdate::Font {
|
TextToolMessage::UpdateOptions {
|
||||||
family: font_input.font_family.clone(),
|
options: TextOptionsUpdate::Font {
|
||||||
style: font_input.font_style.clone(),
|
family: font_input.font_family.clone(),
|
||||||
})
|
style: font_input.font_style.clone(),
|
||||||
|
},
|
||||||
|
}
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
let style = FontInput::new(&tool.options.font_name, &tool.options.font_style)
|
let style = FontInput::new(&tool.options.font_name, &tool.options.font_style)
|
||||||
.is_style_picker(true)
|
.is_style_picker(true)
|
||||||
.on_update(|font_input: &FontInput| {
|
.on_update(|font_input: &FontInput| {
|
||||||
TextToolMessage::UpdateOptions(TextOptionsUpdate::Font {
|
TextToolMessage::UpdateOptions {
|
||||||
family: font_input.font_family.clone(),
|
options: TextOptionsUpdate::Font {
|
||||||
style: font_input.font_style.clone(),
|
family: font_input.font_family.clone(),
|
||||||
})
|
style: font_input.font_style.clone(),
|
||||||
|
},
|
||||||
|
}
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
@ -123,7 +127,12 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
|
||||||
.int()
|
.int()
|
||||||
.min(1.)
|
.min(1.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FontSize(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
TextToolMessage::UpdateOptions {
|
||||||
|
options: TextOptionsUpdate::FontSize(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
let line_height_ratio = NumberInput::new(Some(tool.options.line_height_ratio))
|
let line_height_ratio = NumberInput::new(Some(tool.options.line_height_ratio))
|
||||||
.label("Line Height")
|
.label("Line Height")
|
||||||
|
@ -131,14 +140,22 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.step(0.1)
|
.step(0.1)
|
||||||
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::LineHeightRatio(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| {
|
||||||
|
TextToolMessage::UpdateOptions {
|
||||||
|
options: TextOptionsUpdate::LineHeightRatio(number_input.value.unwrap()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
let align_entries: Vec<_> = [TextAlign::Left, TextAlign::Center, TextAlign::Right, TextAlign::JustifyLeft]
|
let align_entries: Vec<_> = [TextAlign::Left, TextAlign::Center, TextAlign::Right, TextAlign::JustifyLeft]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|align| {
|
.map(|align| {
|
||||||
RadioEntryData::new(format!("{align:?}"))
|
RadioEntryData::new(format!("{align:?}")).label(align.to_string()).on_update(move |_| {
|
||||||
.label(align.to_string())
|
TextToolMessage::UpdateOptions {
|
||||||
.on_update(move |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::Align(align)).into())
|
options: TextOptionsUpdate::Align(align),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let align = RadioInput::new(align_entries).selected_index(Some(tool.options.align as u32)).widget_holder();
|
let align = RadioInput::new(align_entries).selected_index(Some(tool.options.align as u32)).widget_holder();
|
||||||
|
@ -164,9 +181,26 @@ impl LayoutHolder for TextTool {
|
||||||
widgets.append(&mut self.options.fill.create_widgets(
|
widgets.append(&mut self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
true,
|
true,
|
||||||
|_| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColor(None)).into(),
|
|_| {
|
||||||
|color_type: ToolColorType| WidgetCallback::new(move |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColorType(color_type.clone())).into()),
|
TextToolMessage::UpdateOptions {
|
||||||
|color: &ColorInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
options: TextOptionsUpdate::FillColor(None),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
|color_type: ToolColorType| {
|
||||||
|
WidgetCallback::new(move |_| {
|
||||||
|
TextToolMessage::UpdateOptions {
|
||||||
|
options: TextOptionsUpdate::FillColorType(color_type.clone()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|color: &ColorInput| {
|
||||||
|
TextToolMessage::UpdateOptions {
|
||||||
|
options: TextOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb())),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
|
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
|
||||||
|
@ -176,11 +210,11 @@ impl LayoutHolder for TextTool {
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for TextTool {
|
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for TextTool {
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||||
let ToolMessage::Text(TextToolMessage::UpdateOptions(action)) = message else {
|
let ToolMessage::Text(TextToolMessage::UpdateOptions { options }) = message else {
|
||||||
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match action {
|
match options {
|
||||||
TextOptionsUpdate::Font { family, style } => {
|
TextOptionsUpdate::Font { family, style } => {
|
||||||
self.options.font_name = family;
|
self.options.font_name = family;
|
||||||
self.options.font_style = style;
|
self.options.font_style = style;
|
||||||
|
@ -237,7 +271,7 @@ impl ToolTransition for TextTool {
|
||||||
canvas_transformed: None,
|
canvas_transformed: None,
|
||||||
tool_abort: Some(TextToolMessage::Abort.into()),
|
tool_abort: Some(TextToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(TextToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(TextToolMessage::WorkingColorChanged.into()),
|
||||||
overlay_provider: Some(|overlay_context| TextToolMessage::Overlays(overlay_context).into()),
|
overlay_provider: Some(|context| TextToolMessage::Overlays { context }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,7 +508,7 @@ impl Fsm for TextToolFsmState {
|
||||||
|
|
||||||
let ToolMessage::Text(event) = event else { return self };
|
let ToolMessage::Text(event) = event else { return self };
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(TextToolFsmState::Editing, TextToolMessage::Overlays(mut overlay_context)) => {
|
(TextToolFsmState::Editing, TextToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
responses.add(FrontendMessage::DisplayEditableTextboxTransform {
|
responses.add(FrontendMessage::DisplayEditableTextboxTransform {
|
||||||
transform: document.metadata().transform_to_viewport(tool_data.layer).to_cols_array(),
|
transform: document.metadata().transform_to_viewport(tool_data.layer).to_cols_array(),
|
||||||
});
|
});
|
||||||
|
@ -490,7 +524,7 @@ impl Fsm for TextToolFsmState {
|
||||||
|
|
||||||
TextToolFsmState::Editing
|
TextToolFsmState::Editing
|
||||||
}
|
}
|
||||||
(_, TextToolMessage::Overlays(mut overlay_context)) => {
|
(_, TextToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
if matches!(self, Self::Placing) {
|
if matches!(self, Self::Placing) {
|
||||||
// Get the updated selection box bounds
|
// Get the updated selection box bounds
|
||||||
let quad = Quad::from_box(tool_data.cached_resize_bounds);
|
let quad = Quad::from_box(tool_data.cached_resize_bounds);
|
||||||
|
@ -852,10 +886,9 @@ impl Fsm for TextToolFsmState {
|
||||||
TextToolFsmState::Editing
|
TextToolFsmState::Editing
|
||||||
}
|
}
|
||||||
(_, TextToolMessage::WorkingColorChanged) => {
|
(_, TextToolMessage::WorkingColorChanged) => {
|
||||||
responses.add(TextToolMessage::UpdateOptions(TextOptionsUpdate::WorkingColors(
|
responses.add(TextToolMessage::UpdateOptions {
|
||||||
Some(global_tool_data.primary_color),
|
options: TextOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||||
Some(global_tool_data.secondary_color),
|
});
|
||||||
)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(TextToolFsmState::Editing, TextToolMessage::Abort) => {
|
(TextToolFsmState::Editing, TextToolMessage::Abort) => {
|
||||||
|
|
|
@ -8,10 +8,8 @@ use glam::DVec2;
|
||||||
#[impl_message(Message, ToolMessage, TransformLayer)]
|
#[impl_message(Message, ToolMessage, TransformLayer)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum TransformLayerMessage {
|
pub enum TransformLayerMessage {
|
||||||
// Overlays
|
|
||||||
Overlays(OverlayContext),
|
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
|
Overlays { context: OverlayContext },
|
||||||
ApplyTransformOperation { final_transform: bool },
|
ApplyTransformOperation { final_transform: bool },
|
||||||
BeginTransformOperation { operation: TransformType },
|
BeginTransformOperation { operation: TransformType },
|
||||||
BeginGrab,
|
BeginGrab,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use graphene_std::vector::misc::ManipulatorPointId;
|
||||||
use graphene_std::vector::{Vector, VectorModificationType};
|
use graphene_std::vector::{Vector, VectorModificationType};
|
||||||
use std::f64::consts::{PI, TAU};
|
use std::f64::consts::{PI, TAU};
|
||||||
|
|
||||||
const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayerMessage::Overlays(context).into();
|
const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayerMessage::Overlays { context }.into();
|
||||||
|
|
||||||
// TODO: Get these from the input mapper
|
// TODO: Get these from the input mapper
|
||||||
const SLOW_KEY: Key = Key::Shift;
|
const SLOW_KEY: Key = Key::Shift;
|
||||||
|
@ -69,6 +69,7 @@ pub struct TransformLayerMessageHandler {
|
||||||
was_grabbing: bool,
|
was_grabbing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[message_handler_data]
|
||||||
impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for TransformLayerMessageHandler {
|
impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for TransformLayerMessageHandler {
|
||||||
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, context: TransformLayerMessageContext) {
|
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, context: TransformLayerMessageContext) {
|
||||||
let TransformLayerMessageContext {
|
let TransformLayerMessageContext {
|
||||||
|
@ -172,7 +173,7 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
// Overlays
|
// Overlays
|
||||||
TransformLayerMessage::Overlays(mut overlay_context) => {
|
TransformLayerMessage::Overlays { context: mut overlay_context } => {
|
||||||
if !overlay_context.visibility_settings.transform_measurement() {
|
if !overlay_context.visibility_settings.transform_measurement() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -304,7 +305,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||||
|
|
||||||
if final_transform {
|
if final_transform {
|
||||||
self.was_grabbing = false;
|
self.was_grabbing = false;
|
||||||
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::RemoveProvider {
|
||||||
|
provider: TRANSFORM_GRS_OVERLAY_PROVIDER,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TransformLayerMessage::BeginTransformOperation { operation } => {
|
TransformLayerMessage::BeginTransformOperation { operation } => {
|
||||||
|
@ -343,7 +346,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||||
_ => unreachable!(), // Safe because the match arms are exhaustive
|
_ => unreachable!(), // Safe because the match arms are exhaustive
|
||||||
};
|
};
|
||||||
|
|
||||||
responses.add(OverlaysMessage::AddProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::AddProvider {
|
||||||
|
provider: TRANSFORM_GRS_OVERLAY_PROVIDER,
|
||||||
|
});
|
||||||
// Find a way better than this hack
|
// Find a way better than this hack
|
||||||
responses.add(TransformLayerMessage::PointerMove {
|
responses.add(TransformLayerMessage::PointerMove {
|
||||||
slow_key: SLOW_KEY,
|
slow_key: SLOW_KEY,
|
||||||
|
@ -428,7 +433,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||||
if chain_operation {
|
if chain_operation {
|
||||||
responses.add(TransformLayerMessage::ApplyTransformOperation { final_transform: false });
|
responses.add(TransformLayerMessage::ApplyTransformOperation { final_transform: false });
|
||||||
} else {
|
} else {
|
||||||
responses.add(OverlaysMessage::AddProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::AddProvider {
|
||||||
|
provider: TRANSFORM_GRS_OVERLAY_PROVIDER,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
responses.add(TransformLayerMessage::BeginTransformOperation { operation: transform_type });
|
responses.add(TransformLayerMessage::BeginTransformOperation { operation: transform_type });
|
||||||
responses.add(TransformLayerMessage::PointerMove {
|
responses.add(TransformLayerMessage::PointerMove {
|
||||||
|
@ -465,7 +472,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(SelectToolMessage::PivotShift { offset: None, flush: false });
|
responses.add(SelectToolMessage::PivotShift { offset: None, flush: false });
|
||||||
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
responses.add(OverlaysMessage::RemoveProvider {
|
||||||
|
provider: TRANSFORM_GRS_OVERLAY_PROVIDER,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
TransformLayerMessage::ConstrainX => {
|
TransformLayerMessage::ConstrainX => {
|
||||||
let pivot = document_to_viewport.transform_point2(self.local_pivot);
|
let pivot = document_to_viewport.transform_point2(self.local_pivot);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use super::common_functionality::shape_editor::ShapeState;
|
use super::common_functionality::shape_editor::ShapeState;
|
||||||
use super::tool_messages::*;
|
use super::tool_messages::*;
|
||||||
use crate::messages::broadcast::BroadcastMessage;
|
use crate::messages::broadcast::BroadcastMessage;
|
||||||
use crate::messages::broadcast::broadcast_event::BroadcastEvent;
|
use crate::messages::broadcast::event::EventMessage;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, LayoutKeysGroup, MouseMotion};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, LayoutKeysGroup, MouseMotion};
|
||||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||||
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
||||||
|
@ -141,7 +141,7 @@ impl DocumentToolData {
|
||||||
layout_target: LayoutTarget::WorkingColors,
|
layout_target: LayoutTarget::WorkingColors,
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(BroadcastMessage::TriggerEvent(BroadcastEvent::WorkingColorChanged));
|
responses.add(BroadcastMessage::TriggerEvent(EventMessage::WorkingColorChanged));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ pub trait ToolTransition {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap;
|
fn event_to_message_map(&self) -> EventToMessageMap;
|
||||||
|
|
||||||
fn activate(&self, responses: &mut VecDeque<Message>) {
|
fn activate(&self, responses: &mut VecDeque<Message>) {
|
||||||
let mut subscribe_message = |broadcast_to_tool_mapping: Option<ToolMessage>, event: BroadcastEvent| {
|
let mut subscribe_message = |broadcast_to_tool_mapping: Option<ToolMessage>, event: EventMessage| {
|
||||||
if let Some(mapping) = broadcast_to_tool_mapping {
|
if let Some(mapping) = broadcast_to_tool_mapping {
|
||||||
responses.add(BroadcastMessage::SubscribeEvent {
|
responses.add(BroadcastMessage::SubscribeEvent {
|
||||||
on: event,
|
on: event,
|
||||||
|
@ -168,32 +168,32 @@ pub trait ToolTransition {
|
||||||
};
|
};
|
||||||
|
|
||||||
let event_to_tool_map = self.event_to_message_map();
|
let event_to_tool_map = self.event_to_message_map();
|
||||||
subscribe_message(event_to_tool_map.canvas_transformed, BroadcastEvent::CanvasTransformed);
|
subscribe_message(event_to_tool_map.canvas_transformed, EventMessage::CanvasTransformed);
|
||||||
subscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
|
subscribe_message(event_to_tool_map.tool_abort, EventMessage::ToolAbort);
|
||||||
subscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
subscribe_message(event_to_tool_map.selection_changed, EventMessage::SelectionChanged);
|
||||||
subscribe_message(event_to_tool_map.working_color_changed, BroadcastEvent::WorkingColorChanged);
|
subscribe_message(event_to_tool_map.working_color_changed, EventMessage::WorkingColorChanged);
|
||||||
if let Some(overlay_provider) = event_to_tool_map.overlay_provider {
|
if let Some(overlay_provider) = event_to_tool_map.overlay_provider {
|
||||||
responses.add(OverlaysMessage::AddProvider(overlay_provider));
|
responses.add(OverlaysMessage::AddProvider { provider: overlay_provider });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deactivate(&self, responses: &mut VecDeque<Message>) {
|
fn deactivate(&self, responses: &mut VecDeque<Message>) {
|
||||||
let mut unsubscribe_message = |broadcast_to_tool_mapping: Option<ToolMessage>, event: BroadcastEvent| {
|
let mut unsubscribe_message = |broadcast_to_tool_mapping: Option<ToolMessage>, event: EventMessage| {
|
||||||
if let Some(mapping) = broadcast_to_tool_mapping {
|
if let Some(mapping) = broadcast_to_tool_mapping {
|
||||||
responses.add(BroadcastMessage::UnsubscribeEvent {
|
responses.add(BroadcastMessage::UnsubscribeEvent {
|
||||||
on: event,
|
on: event,
|
||||||
message: Box::new(mapping.into()),
|
send: Box::new(mapping.into()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let event_to_tool_map = self.event_to_message_map();
|
let event_to_tool_map = self.event_to_message_map();
|
||||||
unsubscribe_message(event_to_tool_map.canvas_transformed, BroadcastEvent::CanvasTransformed);
|
unsubscribe_message(event_to_tool_map.canvas_transformed, EventMessage::CanvasTransformed);
|
||||||
unsubscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
|
unsubscribe_message(event_to_tool_map.tool_abort, EventMessage::ToolAbort);
|
||||||
unsubscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
unsubscribe_message(event_to_tool_map.selection_changed, EventMessage::SelectionChanged);
|
||||||
unsubscribe_message(event_to_tool_map.working_color_changed, BroadcastEvent::WorkingColorChanged);
|
unsubscribe_message(event_to_tool_map.working_color_changed, EventMessage::WorkingColorChanged);
|
||||||
if let Some(overlay_provider) = event_to_tool_map.overlay_provider {
|
if let Some(overlay_provider) = event_to_tool_map.overlay_provider {
|
||||||
responses.add(OverlaysMessage::RemoveProvider(overlay_provider));
|
responses.add(OverlaysMessage::RemoveProvider { provider: overlay_provider });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ impl NodeGraphExecutor {
|
||||||
|
|
||||||
self.futures.insert(execution_id, ExecutionContext { export_config: None, document_id });
|
self.futures.insert(execution_id, ExecutionContext { export_config: None, document_id });
|
||||||
|
|
||||||
Ok(DeferMessage::SetGraphSubmissionIndex(execution_id).into())
|
Ok(DeferMessage::SetGraphSubmissionIndex { execution_id }.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates a node graph, computing the entire graph
|
/// Evaluates a node graph, computing the entire graph
|
||||||
|
@ -288,7 +288,10 @@ impl NodeGraphExecutor {
|
||||||
} else {
|
} else {
|
||||||
self.process_node_graph_output(node_graph_output, responses)?;
|
self.process_node_graph_output(node_graph_output, responses)?;
|
||||||
}
|
}
|
||||||
responses.add(DeferMessage::TriggerGraphRun(execution_id, execution_context.document_id));
|
responses.add(DeferMessage::TriggerGraphRun {
|
||||||
|
execution_id,
|
||||||
|
document_id: execution_context.document_id,
|
||||||
|
});
|
||||||
|
|
||||||
// Update the Data panel on the frontend using the value of the inspect result.
|
// Update the Data panel on the frontend using the value of the inspect result.
|
||||||
if let Some(inspect_result) = (self.previous_node_to_inspect.is_some()).then_some(inspect_result).flatten() {
|
if let Some(inspect_result) = (self.previous_node_to_inspect.is_some()).then_some(inspect_result).flatten() {
|
||||||
|
|
|
@ -60,3 +60,9 @@ pub trait HierarchicalTree {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ExtractField {
|
||||||
|
fn field_types() -> Vec<(String, usize)>;
|
||||||
|
fn path() -> &'static str;
|
||||||
|
fn print_field_types();
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ impl MessageData {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DebugMessageTree {
|
pub struct DebugMessageTree {
|
||||||
name: String,
|
name: String,
|
||||||
|
fields: Option<Vec<String>>,
|
||||||
variants: Option<Vec<DebugMessageTree>>,
|
variants: Option<Vec<DebugMessageTree>>,
|
||||||
message_handler: Option<MessageData>,
|
message_handler: Option<MessageData>,
|
||||||
message_handler_data: Option<MessageData>,
|
message_handler_data: Option<MessageData>,
|
||||||
|
@ -36,6 +37,7 @@ impl DebugMessageTree {
|
||||||
pub fn new(name: &str) -> DebugMessageTree {
|
pub fn new(name: &str) -> DebugMessageTree {
|
||||||
DebugMessageTree {
|
DebugMessageTree {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
fields: None,
|
||||||
variants: None,
|
variants: None,
|
||||||
message_handler: None,
|
message_handler: None,
|
||||||
message_handler_data: None,
|
message_handler_data: None,
|
||||||
|
@ -43,6 +45,10 @@ impl DebugMessageTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_fields(&mut self, fields: Vec<String>) {
|
||||||
|
self.fields = Some(fields);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_path(&mut self, path: &'static str) {
|
pub fn set_path(&mut self, path: &'static str) {
|
||||||
self.path = path;
|
self.path = path;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +73,10 @@ impl DebugMessageTree {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fields(&self) -> Option<&Vec<String>> {
|
||||||
|
self.fields.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> &'static str {
|
pub fn path(&self) -> &'static str {
|
||||||
self.path
|
self.path
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ impl EditorHandle {
|
||||||
|
|
||||||
// Used by auto-panning, but this could possibly be refactored in the future, see:
|
// Used by auto-panning, but this could possibly be refactored in the future, see:
|
||||||
// <https://github.com/GraphiteEditor/Graphite/pull/2562#discussion_r2041102786>
|
// <https://github.com/GraphiteEditor/Graphite/pull/2562#discussion_r2041102786>
|
||||||
handle.dispatch(BroadcastMessage::TriggerEvent(BroadcastEvent::AnimationFrame));
|
handle.dispatch(BroadcastMessage::TriggerEvent(EventMessage::AnimationFrame));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,23 +31,23 @@ pub fn derive_extract_field_impl(input: TokenStream) -> syn::Result<TokenStream>
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let field_str = field_info.into_iter().map(|(name, ty)| (format!("{}: {}", name, ty)));
|
let field_str = field_info.into_iter().map(|(name, ty)| (format!("{name}: {ty}")));
|
||||||
|
|
||||||
let res = quote! {
|
let res = quote! {
|
||||||
impl #impl_generics #struct_name #ty_generics #where_clause {
|
impl #impl_generics ExtractField for #struct_name #ty_generics #where_clause {
|
||||||
pub fn field_types() -> Vec<(String, usize)> {
|
fn field_types() -> Vec<(String, usize)> {
|
||||||
vec![
|
vec![
|
||||||
#((String::from(#field_str), #field_line)),*
|
#((String::from(#field_str), #field_line)),*
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_field_types() {
|
fn print_field_types() {
|
||||||
for (field, line) in Self::field_types() {
|
for (field, line) in Self::field_types() {
|
||||||
println!("{} at line {}", field, line);
|
println!("{} at line {}", field, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path() -> &'static str {
|
fn path() -> &'static str {
|
||||||
file!()
|
file!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::helpers::clean_rust_type_syntax;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{ToTokens, quote};
|
use quote::{ToTokens, quote};
|
||||||
use syn::{Data, DeriveInput, Fields, Type, parse2};
|
use syn::{Data, DeriveInput, Fields, Type, parse2};
|
||||||
|
@ -11,51 +12,89 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result<TokenStream
|
||||||
_ => return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")),
|
_ => return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let build_message_tree = data.variants.iter().map(|variant| {
|
let build_message_tree: Result<Vec<_>, syn::Error> = data
|
||||||
let variant_type = &variant.ident;
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|variant| {
|
||||||
|
let variant_type = &variant.ident;
|
||||||
|
|
||||||
let has_child = variant
|
let has_child = variant
|
||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
.any(|attr| attr.path().get_ident().is_some_and(|ident| ident == "sub_discriminant" || ident == "child"));
|
.any(|attr| attr.path().get_ident().is_some_and(|ident| ident == "sub_discriminant" || ident == "child"));
|
||||||
|
|
||||||
if has_child {
|
match &variant.fields {
|
||||||
if let Fields::Unnamed(fields) = &variant.fields {
|
Fields::Unit => Ok(quote! {
|
||||||
let field_type = &fields.unnamed.first().unwrap().ty;
|
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
|
||||||
quote! {
|
}),
|
||||||
{
|
Fields::Unnamed(fields) => {
|
||||||
let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));
|
if has_child {
|
||||||
let field_name = stringify!(#field_type);
|
let field_type = &fields.unnamed.first().unwrap().ty;
|
||||||
const message_string: &str = "Message";
|
Ok(quote! {
|
||||||
if message_string == &field_name[field_name.len().saturating_sub(message_string.len())..] {
|
{
|
||||||
// The field is a Message type, recursively build its tree
|
let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));
|
||||||
let sub_tree = #field_type::build_message_tree();
|
let field_name = stringify!(#field_type);
|
||||||
variant_tree.add_variant(sub_tree);
|
const MESSAGE_SUFFIX: &str = "Message";
|
||||||
}
|
if MESSAGE_SUFFIX == &field_name[field_name.len().saturating_sub(MESSAGE_SUFFIX.len())..] {
|
||||||
message_tree.add_variant(variant_tree);
|
// The field is a Message type, recursively build its tree
|
||||||
|
let sub_tree = #field_type::build_message_tree();
|
||||||
|
variant_tree.add_variant(sub_tree);
|
||||||
|
} else {
|
||||||
|
variant_tree.add_fields(vec![format!("{field_name}")]);
|
||||||
|
}
|
||||||
|
message_tree.add_variant(variant_tree);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let error_msg = match fields.unnamed.len() {
|
||||||
|
0 => format!("Remove the unnecessary `()` from the `{}` message enum variant.", variant_type),
|
||||||
|
1 => {
|
||||||
|
let field_type = &fields.unnamed.first().unwrap().ty;
|
||||||
|
format!(
|
||||||
|
"The `{}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\n\
|
||||||
|
Replace `{}` with a named field using {{curly braces}} instead of a positional field using (parentheses).",
|
||||||
|
variant_type,
|
||||||
|
field_type.to_token_stream()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let field_types = fields.unnamed.iter().map(|f| f.ty.to_token_stream().to_string()).collect::<Vec<_>>().join(", ");
|
||||||
|
format!(
|
||||||
|
"The `{}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\n\
|
||||||
|
Replace `{}` with named fields using {{curly braces}} instead of positional fields using (parentheses).",
|
||||||
|
variant_type, field_types
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Err(syn::Error::new(Span::call_site(), error_msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
Fields::Named(fields) => {
|
||||||
quote! {
|
let names = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
|
||||||
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
|
let ty = fields.named.iter().map(|f| clean_rust_type_syntax(f.ty.to_token_stream().to_string()));
|
||||||
|
Ok(quote! {
|
||||||
|
{
|
||||||
|
let mut field_names = Vec::new();
|
||||||
|
#(field_names.push(format!("{}: {}",stringify!(#names), #ty));)*
|
||||||
|
let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));
|
||||||
|
variant_tree.add_fields(field_names);
|
||||||
|
message_tree.add_variant(variant_tree);
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
quote! {
|
.collect();
|
||||||
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
|
let build_message_tree = build_message_tree?;
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let res = quote! {
|
let res = quote! {
|
||||||
impl HierarchicalTree for #input_type {
|
impl HierarchicalTree for #input_type {
|
||||||
fn build_message_tree() -> DebugMessageTree {
|
fn build_message_tree() -> DebugMessageTree {
|
||||||
let mut message_tree = DebugMessageTree::new(stringify!(#input_type));
|
let mut message_tree = DebugMessageTree::new(stringify!(#input_type));
|
||||||
#(#build_message_tree)*
|
#(#build_message_tree)*
|
||||||
|
|
||||||
let message_handler_str = #input_type::message_handler_str();
|
let message_handler_str = #input_type::message_handler_str();
|
||||||
if message_handler_str.fields().len() > 0 {
|
message_tree.add_message_handler_field(message_handler_str);
|
||||||
message_tree.add_message_handler_field(message_handler_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
let message_handler_data_str = #input_type::message_handler_data_str();
|
let message_handler_data_str = #input_type::message_handler_data_str();
|
||||||
if message_handler_data_str.fields().len() > 0 {
|
if message_handler_data_str.fields().len() > 0 {
|
||||||
|
|
|
@ -43,10 +43,8 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream
|
||||||
quote! {
|
quote! {
|
||||||
#input_item
|
#input_item
|
||||||
impl #message_type {
|
impl #message_type {
|
||||||
pub fn message_handler_data_str() -> MessageData
|
pub fn message_handler_data_str() -> MessageData {
|
||||||
{
|
|
||||||
MessageData::new(format!("{}", stringify!(#type_name)), #type_name::field_types(), #type_name::path())
|
MessageData::new(format!("{}", stringify!(#type_name)), #type_name::field_types(), #type_name::path())
|
||||||
|
|
||||||
}
|
}
|
||||||
pub fn message_handler_str() -> MessageData {
|
pub fn message_handler_str() -> MessageData {
|
||||||
MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path())
|
MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path())
|
||||||
|
|
|
@ -110,7 +110,7 @@ pub fn derive_widget_builder_impl(input_item: TokenStream2) -> syn::Result<Token
|
||||||
// Construct the `widget_holder` function
|
// Construct the `widget_holder` function
|
||||||
quote::quote! {
|
quote::quote! {
|
||||||
#[doc = #widget_holder_doc_comment]
|
#[doc = #widget_holder_doc_comment]
|
||||||
pub fn widget_holder(self) -> crate::messages::layout::utility_types::layout_widget::WidgetHolder{
|
pub fn widget_holder(self) -> crate::messages::layout::utility_types::layout_widget::WidgetHolder {
|
||||||
crate::messages::layout::utility_types::layout_widget::WidgetHolder::new( crate::messages::layout::utility_types::layout_widget::Widget::#struct_name_ident(self))
|
crate::messages::layout::utility_types::layout_widget::WidgetHolder::new( crate::messages::layout::utility_types::layout_widget::Widget::#struct_name_ident(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,31 +57,37 @@ function buildHtmlList(nodes, currentIndex, currentLevel) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasChildren = (i + 1 < nodes.length) && (nodes[i + 1].level > node.level);
|
const hasDirectChildren = i + 1 < nodes.length && nodes[i + 1].level > node.level;
|
||||||
|
const hasDeeperChildren = hasDirectChildren && i + 2 < nodes.length && nodes[i + 2].level > nodes[i + 1].level;
|
||||||
|
|
||||||
const linkHtml = node.link ? `<a href="${node.link}" target="_blank">${path.basename(node.link)}</a>` : "";
|
const linkHtml = node.link ? `<a href="${node.link}" target="_blank">${path.basename(node.link)}</a>` : "";
|
||||||
const fieldPieces = node.text.match(/([^:]*):(.*)/);
|
const fieldPieces = node.text.match(/([^:]*):(.*)/);
|
||||||
const partOfMessageFromNamingConvention = ["Message", "MessageHandler", "MessageContext"].some((suffix) => node.text.replace(/(.*)<.*>/g, "$1").endsWith(suffix));
|
|
||||||
const partOfMessageViolatesNamingConvention = node.link && !partOfMessageFromNamingConvention;
|
|
||||||
const partOfMessage = node.link ? "subsystem" : "";
|
|
||||||
const messageParent = (hasChildren && !node.link) ? " submessage": "";
|
|
||||||
const violatesNamingConvention = partOfMessageViolatesNamingConvention ? "<span class=\"warn\">(violates naming convention — should end with 'Message', 'MessageHandler', or 'MessageContext')</span>" : "";
|
|
||||||
let escapedText;
|
let escapedText;
|
||||||
if (fieldPieces && fieldPieces.length === 3) {
|
if (fieldPieces && fieldPieces.length === 3) {
|
||||||
escapedText = [escapeHtml(fieldPieces[1].trim()), escapeHtml(fieldPieces[2].trim())];
|
escapedText = [escapeHtml(fieldPieces[1].trim()), escapeHtml(fieldPieces[2].trim())];
|
||||||
} else {
|
} else {
|
||||||
escapedText = [escapeHtml(node.text)];
|
escapedText = [escapeHtml(node.text)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let role = "message";
|
||||||
|
if (node.link) role = "subsystem";
|
||||||
|
else if (hasDeeperChildren) role = "submessage";
|
||||||
|
else if (escapedText.length === 2) role = "field";
|
||||||
|
|
||||||
if (hasChildren) {
|
const partOfMessageFromNamingConvention = ["Message", "MessageHandler", "MessageContext"].some((suffix) => node.text.replace(/(.*)<.*>/g, "$1").endsWith(suffix));
|
||||||
html += `<li><span class="tree-node"><span class="${partOfMessage}${messageParent}">${escapedText}</span>${linkHtml}${violatesNamingConvention}</span>`;
|
const partOfMessageViolatesNamingConvention = node.link && !partOfMessageFromNamingConvention;
|
||||||
|
const violatesNamingConvention = partOfMessageViolatesNamingConvention ? "<span class=\"warn\">(violates naming convention — should end with 'Message', 'MessageHandler', or 'MessageContext')</span>" : "";
|
||||||
|
|
||||||
|
if (hasDirectChildren) {
|
||||||
|
html += `<li><span class="tree-node"><span class="${role}">${escapedText}</span>${linkHtml}${violatesNamingConvention}</span>`;
|
||||||
const childResult = buildHtmlList(nodes, i + 1, node.level + 1);
|
const childResult = buildHtmlList(nodes, i + 1, node.level + 1);
|
||||||
html += `<div class="nested">${childResult.html}</div></li>\n`;
|
html += `<div class="nested">${childResult.html}</div></li>\n`;
|
||||||
i = childResult.nextIndex;
|
i = childResult.nextIndex;
|
||||||
} else if (escapedText.length === 2) {
|
} else if (role === "field") {
|
||||||
html += `<li><span class="tree-leaf field">${escapedText[0]}</span><span>: ${escapedText[1]}</span>${linkHtml}</li>\n`;
|
html += `<li><span class="tree-leaf field">${escapedText[0]}</span>: <span>${escapedText[1]}</span>${linkHtml}</li>\n`;
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
html += `<li><span class="tree-leaf${partOfMessage}">${escapedText[0]}</span>${linkHtml}${violatesNamingConvention}</li>\n`;
|
html += `<li><span class="tree-leaf ${role}">${escapedText[0]}</span>${linkHtml}${violatesNamingConvention}</li>\n`;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,8 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><polygon fill="%2316323f" points="4,0 1,0 6,5 1,10 4,10 9,5 4,0" /></svg>\
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><polygon fill="%2316323f" points="4,0 1,0 6,5 1,10 4,10 9,5 4,0" /></svg>\
|
||||||
');
|
');
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: auto;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
left: 0;
|
||||||
|
margin: calc((1.5em - 10px) / 2) auto;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
@ -41,34 +39,10 @@
|
||||||
&.expanded::before {
|
&.expanded::before {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
margin-left: 12px;
|
|
||||||
color: var(--color-crimson);
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:hover::after {
|
|
||||||
content: "↗";
|
|
||||||
margin-left: 4px;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-leaf {
|
.tree-leaf {
|
||||||
margin-left: calc(10px + 8px);
|
margin-left: calc(10px + 8px);
|
||||||
|
|
||||||
&.field {
|
|
||||||
padding-left: 4px;
|
|
||||||
color: var(--color-storm);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.field) {
|
|
||||||
padding: 0 4px;
|
|
||||||
background: var(--color-fog);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nested {
|
.nested {
|
||||||
|
@ -80,6 +54,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.warn {
|
.warn {
|
||||||
|
display: inline;
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
color: var(--color-flamingo);
|
color: var(--color-flamingo);
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
|
@ -87,6 +62,20 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin-left: 12px;
|
||||||
|
color: var(--color-crimson);
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover::after {
|
||||||
|
content: "↗";
|
||||||
|
margin-left: 4px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.subsystem,
|
.subsystem,
|
||||||
|
@ -94,13 +83,27 @@
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
|
|
||||||
|
&.subsystem {
|
||||||
|
color: #ffffff;
|
||||||
|
background: var(--color-crimson);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.submessage {
|
||||||
|
background: var(--color-mustard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.subsystem {
|
.message {
|
||||||
color: #ffffff;
|
padding: 0 4px;
|
||||||
background: var(--color-storm);
|
background: var(--color-fog);
|
||||||
}
|
}
|
||||||
|
|
||||||
.submessage {
|
.field {
|
||||||
background: var(--color-lilac);
|
padding-left: 4px;
|
||||||
|
color: #8887c0;
|
||||||
|
|
||||||
|
+ span {
|
||||||
|
color: #457297;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue