mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 07:48:11 +08: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:
co-authored by
Keavon Chambers
parent
5ed45ead6f
commit
17d70dc60e
@@ -14,7 +14,7 @@ impl AutoPanning {
|
||||
|
||||
for message in messages {
|
||||
responses.add(BroadcastMessage::SubscribeEvent {
|
||||
on: BroadcastEvent::AnimationFrame,
|
||||
on: EventMessage::AnimationFrame,
|
||||
send: Box::new(message.clone()),
|
||||
});
|
||||
}
|
||||
@@ -27,8 +27,8 @@ impl AutoPanning {
|
||||
|
||||
for message in messages {
|
||||
responses.add(BroadcastMessage::UnsubscribeEvent {
|
||||
on: BroadcastEvent::AnimationFrame,
|
||||
message: Box::new(message.clone()),
|
||||
on: EventMessage::AnimationFrame,
|
||||
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.")
|
||||
.disabled(!enabled)
|
||||
.on_update(move |_| match source {
|
||||
PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned).into(),
|
||||
PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned).into(),
|
||||
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||
options: SelectOptionsUpdate::TogglePivotPinned,
|
||||
}
|
||||
.into(),
|
||||
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
||||
options: PathOptionsUpdate::TogglePivotPinned,
|
||||
}
|
||||
.into(),
|
||||
})
|
||||
.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({
|
||||
let value = source.clone();
|
||||
move |_| match value {
|
||||
PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::PivotGizmoType(*gizmo_type)).into(),
|
||||
PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::PivotGizmoType(*gizmo_type)).into(),
|
||||
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||
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.",
|
||||
)
|
||||
.on_update(move |optional_input: &CheckboxInput| match source {
|
||||
PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(),
|
||||
PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(),
|
||||
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||
options: SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
|
||||
}
|
||||
.into(),
|
||||
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
||||
options: PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
|
||||
}
|
||||
.into(),
|
||||
})
|
||||
.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 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)]
|
||||
pub struct ToolMessageContext<'a> {
|
||||
@@ -75,8 +75,8 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||
self.tool_state.tool_data.active_tool_type = ToolType::Shape;
|
||||
}
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape });
|
||||
responses.add(ShapeToolMessage::SetShape(ShapeType::Polygon));
|
||||
responses.add(ShapeToolMessage::HideShapeTypeWidget(false))
|
||||
responses.add(ShapeToolMessage::SetShape { shape: ShapeType::Polygon });
|
||||
responses.add(ShapeToolMessage::HideShapeTypeWidget { hide: false })
|
||||
}
|
||||
ToolMessage::ActivateToolBrush => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Brush }),
|
||||
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());
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape });
|
||||
responses.add(ShapeToolMessage::HideShapeTypeWidget(true));
|
||||
responses.add(ShapeToolMessage::SetShape(shape));
|
||||
responses.add(ShapeToolMessage::HideShapeTypeWidget { hide: true });
|
||||
responses.add(ShapeToolMessage::SetShape { shape });
|
||||
}
|
||||
ToolMessage::ActivateTool { tool_type } => {
|
||||
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);
|
||||
|
||||
// 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
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
responses.add(EventMessage::SelectionChanged);
|
||||
|
||||
// Update the working colors for the active tool
|
||||
responses.add(BroadcastEvent::WorkingColorChanged);
|
||||
responses.add(EventMessage::WorkingColorChanged);
|
||||
|
||||
// Send tool options to the frontend
|
||||
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);
|
||||
|
||||
// Unsubscribe the transform layer to selection change events
|
||||
let message = Box::new(TransformLayerMessage::SelectionChanged.into());
|
||||
let on = BroadcastEvent::SelectionChanged;
|
||||
responses.add(BroadcastMessage::UnsubscribeEvent { message, on });
|
||||
responses.add(BroadcastMessage::UnsubscribeEvent {
|
||||
on: EventMessage::SelectionChanged,
|
||||
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::UpdateMouseCursor { cursor: Default::default() });
|
||||
@@ -190,12 +191,12 @@ impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler
|
||||
ToolMessage::InitTools => {
|
||||
// Subscribe the transform layer to selection change events
|
||||
responses.add(BroadcastMessage::SubscribeEvent {
|
||||
on: BroadcastEvent::SelectionChanged,
|
||||
on: EventMessage::SelectionChanged,
|
||||
send: Box::new(TransformLayerMessage::SelectionChanged.into()),
|
||||
});
|
||||
|
||||
responses.add(BroadcastMessage::SubscribeEvent {
|
||||
on: BroadcastEvent::SelectionChanged,
|
||||
on: EventMessage::SelectionChanged,
|
||||
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::UpdateCursor, responses, &mut data);
|
||||
|
||||
responses.add(OverlaysMessage::AddProvider(ARTBOARD_OVERLAY_PROVIDER));
|
||||
responses.add(OverlaysMessage::AddProvider { provider: ARTBOARD_OVERLAY_PROVIDER });
|
||||
}
|
||||
ToolMessage::PreUndo => {
|
||||
let tool_data = &mut self.tool_state.tool_data;
|
||||
if tool_data.active_tool_type != ToolType::Pen {
|
||||
responses.add(BroadcastEvent::ToolAbort);
|
||||
responses.add(EventMessage::ToolAbort);
|
||||
}
|
||||
}
|
||||
ToolMessage::Redo => {
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct ArtboardTool {
|
||||
pub enum ArtboardToolMessage {
|
||||
// Standard messages
|
||||
Abort,
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
|
||||
// Tool-specific messages
|
||||
UpdateSelectedArtboard,
|
||||
@@ -83,7 +83,7 @@ impl ToolTransition for ArtboardTool {
|
||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||
EventToMessageMap {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -227,7 +227,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
let ToolMessage::Artboard(event) = event else { return self };
|
||||
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();
|
||||
if display_transform_cage && state != ArtboardToolFsmState::Drawing {
|
||||
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,
|
||||
DragStop,
|
||||
PointerMove,
|
||||
UpdateOptions(BrushToolMessageOptionsUpdate),
|
||||
UpdateOptions { options: BrushToolMessageOptionsUpdate },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
@@ -106,7 +106,7 @@ impl LayoutHolder for BrushTool {
|
||||
.min(1.)
|
||||
.max(BRUSH_MAX_SIZE) /* Anything bigger would cause the application to be unresponsive and eventually die */
|
||||
.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(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(self.options.hardness))
|
||||
@@ -115,7 +115,12 @@ impl LayoutHolder for BrushTool {
|
||||
.max(100.)
|
||||
.mode_range()
|
||||
.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(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(self.options.flow))
|
||||
@@ -124,7 +129,12 @@ impl LayoutHolder for BrushTool {
|
||||
.max(100.)
|
||||
.mode_range()
|
||||
.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(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(self.options.spacing))
|
||||
@@ -133,7 +143,12 @@ impl LayoutHolder for BrushTool {
|
||||
.max(100.)
|
||||
.mode_range()
|
||||
.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(),
|
||||
];
|
||||
|
||||
@@ -142,9 +157,12 @@ impl LayoutHolder for BrushTool {
|
||||
let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore]
|
||||
.into_iter()
|
||||
.map(|draw_mode| {
|
||||
RadioEntryData::new(format!("{draw_mode:?}"))
|
||||
.label(format!("{draw_mode:?}"))
|
||||
.on_update(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::DrawMode(draw_mode)).into())
|
||||
RadioEntryData::new(format!("{draw_mode:?}")).label(format!("{draw_mode:?}")).on_update(move |_| {
|
||||
BrushToolMessage::UpdateOptions {
|
||||
options: BrushToolMessageOptionsUpdate::DrawMode(draw_mode),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
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(
|
||||
"Color",
|
||||
false,
|
||||
|_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Color(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Color(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
BrushToolMessage::UpdateOptions {
|
||||
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());
|
||||
@@ -167,9 +202,12 @@ impl LayoutHolder for BrushTool {
|
||||
section
|
||||
.iter()
|
||||
.map(|blend_mode| {
|
||||
MenuListEntry::new(format!("{blend_mode:?}"))
|
||||
.label(blend_mode.to_string())
|
||||
.on_commit(|_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::BlendMode(*blend_mode)).into())
|
||||
MenuListEntry::new(format!("{blend_mode:?}")).label(blend_mode.to_string()).on_commit(|_| {
|
||||
BrushToolMessage::UpdateOptions {
|
||||
options: BrushToolMessageOptionsUpdate::BlendMode(*blend_mode),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
@@ -189,11 +227,11 @@ impl LayoutHolder for BrushTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for BrushTool {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
match action {
|
||||
match options {
|
||||
BrushToolMessageOptionsUpdate::BlendMode(blend_mode) => self.options.blend_mode = blend_mode,
|
||||
BrushToolMessageOptionsUpdate::ChangeDiameter(change) => {
|
||||
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
|
||||
}
|
||||
(_, BrushToolMessage::WorkingColorChanged) => {
|
||||
responses.add(BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::WorkingColors(
|
||||
Some(global_tool_data.primary_color),
|
||||
Some(global_tool_data.secondary_color),
|
||||
)));
|
||||
responses.add(BrushToolMessage::UpdateOptions {
|
||||
options: BrushToolMessageOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||
});
|
||||
self
|
||||
}
|
||||
_ => self,
|
||||
|
||||
@@ -14,7 +14,7 @@ pub enum FillToolMessage {
|
||||
// Standard messages
|
||||
Abort,
|
||||
WorkingColorChanged,
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
|
||||
// Tool-specific messages
|
||||
PointerMove,
|
||||
@@ -67,7 +67,7 @@ impl ToolTransition for FillTool {
|
||||
EventToMessageMap {
|
||||
tool_abort: Some(FillToolMessage::Abort.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()
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ impl Fsm for FillToolFsmState {
|
||||
|
||||
let ToolMessage::Fill(event) = event else { return self };
|
||||
match (self, event) {
|
||||
(_, FillToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, FillToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
// Choose the working color to preview
|
||||
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 };
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Default for FreehandOptions {
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub enum FreehandToolMessage {
|
||||
// Standard messages
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
Abort,
|
||||
WorkingColorChanged,
|
||||
|
||||
@@ -48,7 +48,7 @@ pub enum FreehandToolMessage {
|
||||
DragStart { append_to_selected: Key },
|
||||
DragStop,
|
||||
PointerMove,
|
||||
UpdateOptions(FreehandOptionsUpdate),
|
||||
UpdateOptions { options: FreehandOptionsUpdate },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
@@ -86,7 +86,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||
.label("Weight")
|
||||
.min(1.)
|
||||
.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()
|
||||
}
|
||||
|
||||
@@ -95,9 +100,26 @@ impl LayoutHolder for FreehandTool {
|
||||
let mut widgets = self.options.fill.create_widgets(
|
||||
"Fill",
|
||||
true,
|
||||
|_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
FreehandToolMessage::UpdateOptions {
|
||||
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());
|
||||
@@ -105,9 +127,26 @@ impl LayoutHolder for FreehandTool {
|
||||
widgets.append(&mut self.options.stroke.create_widgets(
|
||||
"Stroke",
|
||||
true,
|
||||
|_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
FreehandToolMessage::UpdateOptions {
|
||||
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(create_weight_widget(self.options.line_weight));
|
||||
@@ -119,11 +158,11 @@ impl LayoutHolder for FreehandTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for FreehandTool {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
match action {
|
||||
match options {
|
||||
FreehandOptionsUpdate::FillColor(color) => {
|
||||
self.options.fill.custom_color = color;
|
||||
self.options.fill.color_type = ToolColorType::Custom;
|
||||
@@ -164,7 +203,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Free
|
||||
impl ToolTransition for FreehandTool {
|
||||
fn event_to_message_map(&self) -> 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()),
|
||||
working_color_changed: Some(FreehandToolMessage::WorkingColorChanged.into()),
|
||||
..Default::default()
|
||||
@@ -203,7 +242,7 @@ impl Fsm for FreehandToolFsmState {
|
||||
|
||||
let ToolMessage::Freehand(event) = event else { return self };
|
||||
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);
|
||||
|
||||
self
|
||||
@@ -287,10 +326,9 @@ impl Fsm for FreehandToolFsmState {
|
||||
FreehandToolFsmState::Ready
|
||||
}
|
||||
(_, FreehandToolMessage::WorkingColorChanged) => {
|
||||
responses.add(FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::WorkingColors(
|
||||
Some(global_tool_data.primary_color),
|
||||
Some(global_tool_data.secondary_color),
|
||||
)));
|
||||
responses.add(FreehandToolMessage::UpdateOptions {
|
||||
options: FreehandOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||
});
|
||||
self
|
||||
}
|
||||
_ => self,
|
||||
@@ -679,7 +717,9 @@ mod test_freehand {
|
||||
|
||||
let custom_line_weight = 5.;
|
||||
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;
|
||||
|
||||
let points = [DVec2::new(100., 100.), DVec2::new(200., 200.), DVec2::new(300., 100.)];
|
||||
|
||||
@@ -24,7 +24,7 @@ pub struct GradientOptions {
|
||||
pub enum GradientToolMessage {
|
||||
// Standard messages
|
||||
Abort,
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
|
||||
// Tool-specific messages
|
||||
DeleteStop,
|
||||
@@ -33,7 +33,7 @@ pub enum GradientToolMessage {
|
||||
PointerMove { constrain_axis: Key },
|
||||
PointerOutsideViewport { constrain_axis: Key },
|
||||
PointerUp,
|
||||
UpdateOptions(GradientOptionsUpdate),
|
||||
UpdateOptions { options: GradientOptionsUpdate },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
@@ -56,11 +56,11 @@ impl ToolMetadata for GradientTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for GradientTool {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
match action {
|
||||
match options {
|
||||
GradientOptionsUpdate::Type(gradient_type) => {
|
||||
self.options.gradient_type = gradient_type;
|
||||
// Update the selected gradient if it exists
|
||||
@@ -91,14 +91,18 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Grad
|
||||
impl LayoutHolder for GradientTool {
|
||||
fn layout(&self) -> Layout {
|
||||
let gradient_type = RadioInput::new(vec![
|
||||
RadioEntryData::new("Linear")
|
||||
.label("Linear")
|
||||
.tooltip("Linear gradient")
|
||||
.on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Linear)).into()),
|
||||
RadioEntryData::new("Radial")
|
||||
.label("Radial")
|
||||
.tooltip("Radial gradient")
|
||||
.on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Radial)).into()),
|
||||
RadioEntryData::new("Linear").label("Linear").tooltip("Linear gradient").on_update(move |_| {
|
||||
GradientToolMessage::UpdateOptions {
|
||||
options: GradientOptionsUpdate::Type(GradientType::Linear),
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
RadioEntryData::new("Radial").label("Radial").tooltip("Radial gradient").on_update(move |_| {
|
||||
GradientToolMessage::UpdateOptions {
|
||||
options: GradientOptionsUpdate::Type(GradientType::Radial),
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
])
|
||||
.selected_index(Some((self.selected_gradient().unwrap_or(self.options.gradient_type) == GradientType::Radial) as u32))
|
||||
.widget_holder();
|
||||
@@ -224,7 +228,7 @@ impl ToolTransition for GradientTool {
|
||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||
EventToMessageMap {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -256,7 +260,7 @@ impl Fsm for GradientToolFsmState {
|
||||
|
||||
let ToolMessage::Gradient(event) = event else { return self };
|
||||
match (self, event) {
|
||||
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, GradientToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
let selected = tool_data.selected_gradient.as_ref();
|
||||
|
||||
for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) {
|
||||
|
||||
@@ -51,8 +51,10 @@ pub struct PathToolOptions {
|
||||
pub enum PathToolMessage {
|
||||
// Standard messages
|
||||
Abort,
|
||||
Overlays(OverlayContext),
|
||||
SelectionChanged,
|
||||
Overlays {
|
||||
context: OverlayContext,
|
||||
},
|
||||
|
||||
// Tool-specific messages
|
||||
BreakPath,
|
||||
@@ -123,7 +125,9 @@ pub enum PathToolMessage {
|
||||
position: ReferencePoint,
|
||||
},
|
||||
SwapSelectedHandles,
|
||||
UpdateOptions(PathOptionsUpdate),
|
||||
UpdateOptions {
|
||||
options: PathOptionsUpdate,
|
||||
},
|
||||
UpdateSelectedPointsStatus {
|
||||
overlay_context: OverlayContext,
|
||||
},
|
||||
@@ -275,15 +279,30 @@ impl LayoutHolder for PathTool {
|
||||
RadioEntryData::new("all")
|
||||
.icon("HandleVisibilityAll")
|
||||
.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")
|
||||
.icon("HandleVisibilitySelected")
|
||||
.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")
|
||||
.icon("HandleVisibilityFrontier")
|
||||
.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))
|
||||
.widget_holder();
|
||||
@@ -345,7 +364,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Path
|
||||
let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated);
|
||||
|
||||
match message {
|
||||
ToolMessage::Path(PathToolMessage::UpdateOptions(action)) => match action {
|
||||
ToolMessage::Path(PathToolMessage::UpdateOptions { options }) => match options {
|
||||
PathOptionsUpdate::OverlayModeType(overlay_mode_type) => {
|
||||
self.options.path_overlay_mode = overlay_mode_type;
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
@@ -478,7 +497,7 @@ impl ToolTransition for PathTool {
|
||||
EventToMessageMap {
|
||||
tool_abort: Some(PathToolMessage::Abort.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()
|
||||
}
|
||||
}
|
||||
@@ -1557,14 +1576,22 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
match (multiple_toggle, point_edit) {
|
||||
(true, true) => {
|
||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::PointEditingMode { enabled: false }));
|
||||
responses.add(PathToolMessage::UpdateOptions {
|
||||
options: PathOptionsUpdate::PointEditingMode { enabled: 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(PathOptionsUpdate::SegmentEditingMode { enabled: false }));
|
||||
responses.add(PathToolMessage::UpdateOptions {
|
||||
options: PathOptionsUpdate::PointEditingMode { enabled: true },
|
||||
});
|
||||
responses.add(PathToolMessage::UpdateOptions {
|
||||
options: PathOptionsUpdate::SegmentEditingMode { enabled: false },
|
||||
});
|
||||
|
||||
// Select all of the end points of selected segments
|
||||
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||
@@ -1602,14 +1629,22 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
match (multiple_toggle, segment_edit) {
|
||||
(true, true) => {
|
||||
responses.add(PathToolMessage::UpdateOptions(PathOptionsUpdate::SegmentEditingMode { enabled: false }));
|
||||
responses.add(PathToolMessage::UpdateOptions {
|
||||
options: PathOptionsUpdate::SegmentEditingMode { enabled: 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(PathOptionsUpdate::SegmentEditingMode { enabled: true }));
|
||||
responses.add(PathToolMessage::UpdateOptions {
|
||||
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
|
||||
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||
@@ -1632,7 +1667,7 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
self
|
||||
}
|
||||
(_, PathToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, PathToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
// 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 {
|
||||
for (outline, layer) in &tool_data.ghost_outline {
|
||||
|
||||
@@ -50,7 +50,9 @@ pub enum PenToolMessage {
|
||||
Abort,
|
||||
SelectionChanged,
|
||||
WorkingColorChanged,
|
||||
Overlays(OverlayContext),
|
||||
Overlays {
|
||||
context: OverlayContext,
|
||||
},
|
||||
|
||||
// Tool-specific messages
|
||||
|
||||
@@ -80,7 +82,9 @@ pub enum PenToolMessage {
|
||||
},
|
||||
Redo,
|
||||
Undo,
|
||||
UpdateOptions(PenOptionsUpdate),
|
||||
UpdateOptions {
|
||||
options: PenOptionsUpdate,
|
||||
},
|
||||
RecalculateLatestPointsPosition,
|
||||
RemovePreviousHandle,
|
||||
GRS {
|
||||
@@ -138,7 +142,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||
.label("Weight")
|
||||
.min(0.)
|
||||
.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()
|
||||
}
|
||||
|
||||
@@ -147,9 +156,26 @@ impl LayoutHolder for PenTool {
|
||||
let mut widgets = self.options.fill.create_widgets(
|
||||
"Fill",
|
||||
true,
|
||||
|_| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
PenToolMessage::UpdateOptions {
|
||||
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());
|
||||
@@ -157,9 +183,26 @@ impl LayoutHolder for PenTool {
|
||||
widgets.append(&mut self.options.stroke.create_widgets(
|
||||
"Stroke",
|
||||
true,
|
||||
|_| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
PenToolMessage::UpdateOptions {
|
||||
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());
|
||||
@@ -173,11 +216,21 @@ impl LayoutHolder for PenTool {
|
||||
RadioEntryData::new("all")
|
||||
.icon("HandleVisibilityAll")
|
||||
.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")
|
||||
.icon("HandleVisibilityFrontier")
|
||||
.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))
|
||||
.widget_holder(),
|
||||
@@ -190,12 +243,12 @@ impl LayoutHolder for PenTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for PenTool {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
|
||||
match action {
|
||||
match options {
|
||||
PenOptionsUpdate::OverlayModeType(overlay_mode_type) => {
|
||||
self.options.pen_overlay_mode = overlay_mode_type;
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
@@ -253,7 +306,7 @@ impl ToolTransition for PenTool {
|
||||
tool_abort: Some(PenToolMessage::Abort.into()),
|
||||
selection_changed: Some(PenToolMessage::SelectionChanged.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()
|
||||
}
|
||||
}
|
||||
@@ -1547,7 +1600,7 @@ impl Fsm for PenToolFsmState {
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
self
|
||||
}
|
||||
(PenToolFsmState::Ready, PenToolMessage::Overlays(mut overlay_context)) => {
|
||||
(PenToolFsmState::Ready, PenToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
match tool_options.pen_overlay_mode {
|
||||
PenOverlayMode::AllHandles => {
|
||||
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);
|
||||
self
|
||||
}
|
||||
(_, PenToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, PenToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
let display_anchors = overlay_context.visibility_settings.anchors();
|
||||
let display_handles = overlay_context.visibility_settings.handles();
|
||||
|
||||
@@ -1753,10 +1806,9 @@ impl Fsm for PenToolFsmState {
|
||||
self
|
||||
}
|
||||
(_, PenToolMessage::WorkingColorChanged) => {
|
||||
responses.add(PenToolMessage::UpdateOptions(PenOptionsUpdate::WorkingColors(
|
||||
Some(global_tool_data.primary_color),
|
||||
Some(global_tool_data.secondary_color),
|
||||
)));
|
||||
responses.add(PenToolMessage::UpdateOptions {
|
||||
options: PenOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||
});
|
||||
self
|
||||
}
|
||||
(PenToolFsmState::Ready, PenToolMessage::DragStart { append_to_selected }) => {
|
||||
|
||||
@@ -78,7 +78,9 @@ pub struct SelectToolPointerKeys {
|
||||
pub enum SelectToolMessage {
|
||||
// Standard messages
|
||||
Abort,
|
||||
Overlays(OverlayContext),
|
||||
Overlays {
|
||||
context: OverlayContext,
|
||||
},
|
||||
|
||||
// Tool-specific messages
|
||||
DragStart {
|
||||
@@ -94,9 +96,15 @@ pub enum SelectToolMessage {
|
||||
EditLayer,
|
||||
EditLayerExec,
|
||||
Enter,
|
||||
PointerMove(SelectToolPointerKeys),
|
||||
PointerOutsideViewport(SelectToolPointerKeys),
|
||||
SelectOptions(SelectOptionsUpdate),
|
||||
PointerMove {
|
||||
modifier_keys: SelectToolPointerKeys,
|
||||
},
|
||||
PointerOutsideViewport {
|
||||
modifier_keys: SelectToolPointerKeys,
|
||||
},
|
||||
SelectOptions {
|
||||
options: SelectOptionsUpdate,
|
||||
},
|
||||
SetPivot {
|
||||
position: ReferencePoint,
|
||||
},
|
||||
@@ -127,9 +135,12 @@ impl SelectTool {
|
||||
let layer_selection_behavior_entries = [NestedSelectionBehavior::Shallowest, NestedSelectionBehavior::Deepest]
|
||||
.iter()
|
||||
.map(|mode| {
|
||||
MenuListEntry::new(format!("{mode:?}"))
|
||||
.label(mode.to_string())
|
||||
.on_commit(move |_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::NestedSelectionBehavior(*mode)).into())
|
||||
MenuListEntry::new(format!("{mode:?}")).label(mode.to_string()).on_commit(move |_| {
|
||||
SelectToolMessage::SelectOptions {
|
||||
options: SelectOptionsUpdate::NestedSelectionBehavior(*mode),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
})
|
||||
.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>) {
|
||||
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 {
|
||||
SelectOptionsUpdate::NestedSelectionBehavior(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 {
|
||||
EventToMessageMap {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -591,7 +602,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
let ToolMessage::Select(event) = event else { return self };
|
||||
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);
|
||||
|
||||
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,
|
||||
remove,
|
||||
},
|
||||
SelectToolMessage::PointerMove(modifier_keys),
|
||||
SelectToolMessage::PointerMove { modifier_keys },
|
||||
) => {
|
||||
if !has_dragged {
|
||||
responses.add(ToolMessage::UpdateHints);
|
||||
@@ -1187,8 +1198,8 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
// Auto-panning
|
||||
let messages = [
|
||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
||||
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||
];
|
||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||
|
||||
@@ -1200,7 +1211,7 @@ impl Fsm for SelectToolFsmState {
|
||||
remove,
|
||||
}
|
||||
}
|
||||
(SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove(modifier_keys)) => {
|
||||
(SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove { modifier_keys }) => {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
resize_bounds(
|
||||
document,
|
||||
@@ -1215,14 +1226,14 @@ impl Fsm for SelectToolFsmState {
|
||||
ToolType::Select,
|
||||
);
|
||||
let messages = [
|
||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
||||
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||
];
|
||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||
}
|
||||
SelectToolFsmState::ResizingBounds
|
||||
}
|
||||
(SelectToolFsmState::SkewingBounds { skew }, SelectToolMessage::PointerMove(_)) => {
|
||||
(SelectToolFsmState::SkewingBounds { skew }, SelectToolMessage::PointerMove { .. }) => {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
skew_bounds(
|
||||
document,
|
||||
@@ -1236,7 +1247,7 @@ impl Fsm for SelectToolFsmState {
|
||||
}
|
||||
SelectToolFsmState::SkewingBounds { skew }
|
||||
}
|
||||
(SelectToolFsmState::RotatingBounds, SelectToolMessage::PointerMove(_)) => {
|
||||
(SelectToolFsmState::RotatingBounds, SelectToolMessage::PointerMove { .. }) => {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
rotate_bounds(
|
||||
document,
|
||||
@@ -1252,7 +1263,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
SelectToolFsmState::RotatingBounds
|
||||
}
|
||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => {
|
||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove { modifier_keys }) => {
|
||||
let mouse_position = input.mouse.position;
|
||||
let snapped_mouse_position = mouse_position;
|
||||
|
||||
@@ -1262,14 +1273,14 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
// Auto-panning
|
||||
let messages = [
|
||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
||||
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||
];
|
||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||
|
||||
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 {
|
||||
responses.add(ToolMessage::UpdateHints);
|
||||
}
|
||||
@@ -1283,14 +1294,14 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
// Auto-panning
|
||||
let messages = [
|
||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
||||
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||
];
|
||||
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
|
||||
|
||||
SelectToolFsmState::Drawing { selection_shape, has_drawn: true }
|
||||
}
|
||||
(SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => {
|
||||
(SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove { .. }) => {
|
||||
let dragging_bounds = tool_data
|
||||
.bounding_box_manager
|
||||
.as_mut()
|
||||
@@ -1326,7 +1337,7 @@ impl Fsm for SelectToolFsmState {
|
||||
deepest,
|
||||
remove,
|
||||
},
|
||||
SelectToolMessage::PointerOutsideViewport(_),
|
||||
SelectToolMessage::PointerOutsideViewport { .. },
|
||||
) => {
|
||||
// Auto-panning
|
||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||
@@ -1342,7 +1353,7 @@ impl Fsm for SelectToolFsmState {
|
||||
remove,
|
||||
}
|
||||
}
|
||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => {
|
||||
// Auto-panning
|
||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
@@ -1353,13 +1364,13 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
self
|
||||
}
|
||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport { .. }) => {
|
||||
// Auto-panning
|
||||
let _ = tool_data.auto_panning.shift_viewport(input, responses);
|
||||
|
||||
self
|
||||
}
|
||||
(SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||
(SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => {
|
||||
// Auto-panning
|
||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||
tool_data.drag_start += shift;
|
||||
@@ -1367,11 +1378,11 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
self
|
||||
}
|
||||
(state, SelectToolMessage::PointerOutsideViewport(modifier_keys)) => {
|
||||
(state, SelectToolMessage::PointerOutsideViewport { modifier_keys }) => {
|
||||
// Auto-panning
|
||||
let messages = [
|
||||
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
|
||||
SelectToolMessage::PointerMove(modifier_keys).into(),
|
||||
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
|
||||
SelectToolMessage::PointerMove { modifier_keys }.into(),
|
||||
];
|
||||
tool_data.auto_panning.stop(&messages, responses);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ use graphene_std::renderer::Quad;
|
||||
use graphene_std::vector::misc::ArcType;
|
||||
use std::vec;
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, ExtractField)]
|
||||
pub struct ShapeTool {
|
||||
fsm_state: ShapeToolFsmState,
|
||||
tool_data: ShapeToolData,
|
||||
@@ -73,18 +73,18 @@ pub enum ShapeOptionsUpdate {
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub enum ShapeToolMessage {
|
||||
// Standard messages
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
Abort,
|
||||
WorkingColorChanged,
|
||||
|
||||
// Tool-specific messages
|
||||
DragStart,
|
||||
DragStop,
|
||||
HideShapeTypeWidget(bool),
|
||||
PointerMove(ShapeToolModifierKey),
|
||||
PointerOutsideViewport(ShapeToolModifierKey),
|
||||
UpdateOptions(ShapeOptionsUpdate),
|
||||
SetShape(ShapeType),
|
||||
HideShapeTypeWidget { hide: bool },
|
||||
PointerMove { modifier: ShapeToolModifierKey },
|
||||
PointerOutsideViewport { modifier: ShapeToolModifierKey },
|
||||
UpdateOptions { options: ShapeOptionsUpdate },
|
||||
SetShape { shape: ShapeType },
|
||||
|
||||
IncreaseSides,
|
||||
DecreaseSides,
|
||||
@@ -99,39 +99,65 @@ fn create_sides_widget(vertices: u32) -> WidgetHolder {
|
||||
.min(3.)
|
||||
.max(1000.)
|
||||
.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()
|
||||
}
|
||||
|
||||
fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder {
|
||||
let entries = vec![vec![
|
||||
MenuListEntry::new("Polygon")
|
||||
.label("Polygon")
|
||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Polygon)).into()),
|
||||
MenuListEntry::new("Star")
|
||||
.label("Star")
|
||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Star)).into()),
|
||||
MenuListEntry::new("Circle")
|
||||
.label("Circle")
|
||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Circle)).into()),
|
||||
MenuListEntry::new("Arc")
|
||||
.label("Arc")
|
||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Arc)).into()),
|
||||
MenuListEntry::new("Polygon").label("Polygon").on_commit(move |_| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ShapeType(ShapeType::Polygon),
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
MenuListEntry::new("Star").label("Star").on_commit(move |_| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ShapeType(ShapeType::Star),
|
||||
}
|
||||
.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()
|
||||
}
|
||||
|
||||
fn create_arc_type_widget(arc_type: ArcType) -> WidgetHolder {
|
||||
let entries = vec![
|
||||
RadioEntryData::new("Open")
|
||||
.label("Open")
|
||||
.on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ArcType(ArcType::Open)).into()),
|
||||
RadioEntryData::new("Closed")
|
||||
.label("Closed")
|
||||
.on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ArcType(ArcType::Closed)).into()),
|
||||
RadioEntryData::new("Pie")
|
||||
.label("Pie")
|
||||
.on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ArcType(ArcType::PieSlice)).into()),
|
||||
RadioEntryData::new("Open").label("Open").on_update(move |_| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ArcType(ArcType::Open),
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
RadioEntryData::new("Closed").label("Closed").on_update(move |_| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
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()
|
||||
}
|
||||
@@ -142,7 +168,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||
.label("Weight")
|
||||
.min(0.)
|
||||
.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()
|
||||
}
|
||||
|
||||
@@ -169,9 +200,26 @@ impl LayoutHolder for ShapeTool {
|
||||
widgets.append(&mut self.options.fill.create_widgets(
|
||||
"Fill",
|
||||
true,
|
||||
|_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
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());
|
||||
@@ -180,9 +228,26 @@ impl LayoutHolder for ShapeTool {
|
||||
widgets.append(&mut self.options.stroke.create_widgets(
|
||||
"Stroke",
|
||||
true,
|
||||
|_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
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(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 {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
match action {
|
||||
match options {
|
||||
ShapeOptionsUpdate::FillColor(color) => {
|
||||
self.options.fill.custom_color = color;
|
||||
self.options.fill.color_type = ToolColorType::Custom;
|
||||
@@ -285,7 +351,7 @@ impl ToolMetadata for ShapeTool {
|
||||
impl ToolTransition for ShapeTool {
|
||||
fn event_to_message_map(&self) -> 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()),
|
||||
working_color_changed: Some(ShapeToolMessage::WorkingColorChanged.into()),
|
||||
..Default::default()
|
||||
@@ -402,7 +468,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
let ToolMessage::Shape(event) = event else { return self };
|
||||
|
||||
match (self, event) {
|
||||
(_, ShapeToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, ShapeToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
let mouse_position = tool_data
|
||||
.data
|
||||
.snap_manager
|
||||
@@ -484,11 +550,15 @@ impl Fsm for ShapeToolFsmState {
|
||||
self
|
||||
}
|
||||
(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
|
||||
}
|
||||
(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
|
||||
}
|
||||
(
|
||||
@@ -542,7 +612,9 @@ impl Fsm for ShapeToolFsmState {
|
||||
return self;
|
||||
};
|
||||
|
||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(n + 1)));
|
||||
responses.add(ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::Vertices(n + 1),
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 1),
|
||||
@@ -571,7 +643,9 @@ impl Fsm for ShapeToolFsmState {
|
||||
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 {
|
||||
input_connector: InputConnector::node(node_id, 1),
|
||||
@@ -603,7 +677,9 @@ impl Fsm for ShapeToolFsmState {
|
||||
tool_data.cursor = cursor;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||
// 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;
|
||||
}
|
||||
@@ -630,7 +706,9 @@ impl Fsm for ShapeToolFsmState {
|
||||
let cursor = tool_data.transform_cage_mouse_icon(input);
|
||||
tool_data.cursor = 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) {
|
||||
@@ -710,7 +788,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
|
||||
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 {
|
||||
return ShapeToolFsmState::Ready(shape);
|
||||
};
|
||||
@@ -726,33 +804,33 @@ impl Fsm for ShapeToolFsmState {
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
self
|
||||
}
|
||||
(ShapeToolFsmState::DraggingLineEndpoints, ShapeToolMessage::PointerMove(modifier)) => {
|
||||
(ShapeToolFsmState::DraggingLineEndpoints, ShapeToolMessage::PointerMove { modifier }) => {
|
||||
let Some(layer) = tool_data.line_data.editing_layer else {
|
||||
return ShapeToolFsmState::Ready(tool_data.current_shape);
|
||||
};
|
||||
|
||||
Line::update_shape(document, input, layer, tool_data, modifier, responses);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
|
||||
ShapeToolFsmState::ModifyingGizmo
|
||||
}
|
||||
(ShapeToolFsmState::ResizingBounds, ShapeToolMessage::PointerMove(modifier)) => {
|
||||
(ShapeToolFsmState::ResizingBounds, ShapeToolMessage::PointerMove { modifier }) => {
|
||||
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(
|
||||
document,
|
||||
responses,
|
||||
@@ -771,7 +849,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
ShapeToolFsmState::ResizingBounds
|
||||
}
|
||||
(ShapeToolFsmState::RotatingBounds, ShapeToolMessage::PointerMove(modifier)) => {
|
||||
(ShapeToolFsmState::RotatingBounds, ShapeToolMessage::PointerMove { modifier }) => {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
rotate_bounds(
|
||||
document,
|
||||
@@ -787,7 +865,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
|
||||
ShapeToolFsmState::RotatingBounds
|
||||
}
|
||||
(ShapeToolFsmState::SkewingBounds { skew }, ShapeToolMessage::PointerMove(_)) => {
|
||||
(ShapeToolFsmState::SkewingBounds { skew }, ShapeToolMessage::PointerMove { .. }) => {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
skew_bounds(
|
||||
document,
|
||||
@@ -803,7 +881,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
ShapeToolFsmState::SkewingBounds { skew }
|
||||
}
|
||||
|
||||
(_, ShapeToolMessage::PointerMove(_)) => {
|
||||
(_, ShapeToolMessage::PointerMove { .. }) => {
|
||||
let dragging_bounds = tool_data
|
||||
.bounding_box_manager
|
||||
.as_mut()
|
||||
@@ -825,7 +903,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
self
|
||||
}
|
||||
(ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. }, ShapeToolMessage::PointerOutsideViewport(_)) => {
|
||||
(ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. }, ShapeToolMessage::PointerOutsideViewport { .. }) => {
|
||||
// Auto-panning
|
||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
@@ -836,7 +914,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
|
||||
self
|
||||
}
|
||||
(ShapeToolFsmState::Ready(_), ShapeToolMessage::PointerOutsideViewport(..)) => self,
|
||||
(ShapeToolFsmState::Ready(_), ShapeToolMessage::PointerOutsideViewport { .. }) => self,
|
||||
(_, ShapeToolMessage::PointerOutsideViewport { .. }) => {
|
||||
// Auto-panning
|
||||
let _ = tool_data.auto_panning.shift_viewport(input, responses);
|
||||
@@ -891,21 +969,22 @@ impl Fsm for ShapeToolFsmState {
|
||||
ShapeToolFsmState::Ready(tool_data.current_shape)
|
||||
}
|
||||
(_, ShapeToolMessage::WorkingColorChanged) => {
|
||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::WorkingColors(
|
||||
Some(global_tool_data.primary_color),
|
||||
Some(global_tool_data.secondary_color),
|
||||
)));
|
||||
responses.add(ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||
});
|
||||
self
|
||||
}
|
||||
(_, ShapeToolMessage::SetShape(shape)) => {
|
||||
(_, ShapeToolMessage::SetShape { shape }) => {
|
||||
responses.add(DocumentMessage::AbortTransaction);
|
||||
tool_data.data.cleanup(responses);
|
||||
tool_data.current_shape = shape;
|
||||
|
||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(shape)));
|
||||
responses.add(ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ShapeType(shape),
|
||||
});
|
||||
ShapeToolFsmState::Ready(shape)
|
||||
}
|
||||
(_, ShapeToolMessage::HideShapeTypeWidget(hide)) => {
|
||||
(_, ShapeToolMessage::HideShapeTypeWidget { hide }) => {
|
||||
tool_data.hide_shape_option_widget = hide;
|
||||
responses.add(ToolMessage::RefreshToolOptions);
|
||||
self
|
||||
|
||||
@@ -41,7 +41,7 @@ impl Default for SplineOptions {
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub enum SplineToolMessage {
|
||||
// Standard messages
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
CanvasTransformed,
|
||||
Abort,
|
||||
WorkingColorChanged,
|
||||
@@ -54,7 +54,7 @@ pub enum SplineToolMessage {
|
||||
PointerMove,
|
||||
PointerOutsideViewport,
|
||||
Undo,
|
||||
UpdateOptions(SplineOptionsUpdate),
|
||||
UpdateOptions { options: SplineOptionsUpdate },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
@@ -93,7 +93,12 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||
.label("Weight")
|
||||
.min(0.)
|
||||
.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()
|
||||
}
|
||||
|
||||
@@ -102,9 +107,26 @@ impl LayoutHolder for SplineTool {
|
||||
let mut widgets = self.options.fill.create_widgets(
|
||||
"Fill",
|
||||
true,
|
||||
|_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
SplineToolMessage::UpdateOptions {
|
||||
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());
|
||||
@@ -112,9 +134,26 @@ impl LayoutHolder for SplineTool {
|
||||
widgets.append(&mut self.options.stroke.create_widgets(
|
||||
"Stroke",
|
||||
true,
|
||||
|_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
SplineToolMessage::UpdateOptions {
|
||||
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(create_weight_widget(self.options.line_weight));
|
||||
@@ -126,11 +165,11 @@ impl LayoutHolder for SplineTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for SplineTool {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
match action {
|
||||
match options {
|
||||
SplineOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight,
|
||||
SplineOptionsUpdate::FillColor(color) => {
|
||||
self.options.fill.custom_color = color;
|
||||
@@ -179,7 +218,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Spli
|
||||
impl ToolTransition for SplineTool {
|
||||
fn event_to_message_map(&self) -> 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()),
|
||||
tool_abort: Some(SplineToolMessage::Abort.into()),
|
||||
working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()),
|
||||
@@ -262,7 +301,7 @@ impl Fsm for SplineToolFsmState {
|
||||
let ToolMessage::Spline(event) = event else { return self };
|
||||
match (self, event) {
|
||||
(_, SplineToolMessage::CanvasTransformed) => self,
|
||||
(_, SplineToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, SplineToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
path_endpoint_overlays(document, shape_editor, &mut overlay_context, preferences);
|
||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||
self
|
||||
@@ -440,10 +479,9 @@ impl Fsm for SplineToolFsmState {
|
||||
SplineToolFsmState::Ready
|
||||
}
|
||||
(_, SplineToolMessage::WorkingColorChanged) => {
|
||||
responses.add(SplineToolMessage::UpdateOptions(SplineOptionsUpdate::WorkingColors(
|
||||
Some(global_tool_data.primary_color),
|
||||
Some(global_tool_data.secondary_color),
|
||||
)));
|
||||
responses.add(SplineToolMessage::UpdateOptions {
|
||||
options: SplineOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||
});
|
||||
self
|
||||
}
|
||||
_ => self,
|
||||
|
||||
@@ -59,7 +59,7 @@ pub enum TextToolMessage {
|
||||
// Standard messages
|
||||
Abort,
|
||||
WorkingColorChanged,
|
||||
Overlays(OverlayContext),
|
||||
Overlays { context: OverlayContext },
|
||||
|
||||
// Tool-specific messages
|
||||
DragStart,
|
||||
@@ -70,7 +70,7 @@ pub enum TextToolMessage {
|
||||
PointerOutsideViewport { center: Key, lock_ratio: Key },
|
||||
TextChange { new_text: String, is_left_or_right_click: bool },
|
||||
UpdateBounds { new_text: String },
|
||||
UpdateOptions(TextOptionsUpdate),
|
||||
UpdateOptions { options: TextOptionsUpdate },
|
||||
}
|
||||
|
||||
#[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)
|
||||
.is_style_picker(false)
|
||||
.on_update(|font_input: &FontInput| {
|
||||
TextToolMessage::UpdateOptions(TextOptionsUpdate::Font {
|
||||
family: font_input.font_family.clone(),
|
||||
style: font_input.font_style.clone(),
|
||||
})
|
||||
TextToolMessage::UpdateOptions {
|
||||
options: TextOptionsUpdate::Font {
|
||||
family: font_input.font_family.clone(),
|
||||
style: font_input.font_style.clone(),
|
||||
},
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_holder();
|
||||
let style = FontInput::new(&tool.options.font_name, &tool.options.font_style)
|
||||
.is_style_picker(true)
|
||||
.on_update(|font_input: &FontInput| {
|
||||
TextToolMessage::UpdateOptions(TextOptionsUpdate::Font {
|
||||
family: font_input.font_family.clone(),
|
||||
style: font_input.font_style.clone(),
|
||||
})
|
||||
TextToolMessage::UpdateOptions {
|
||||
options: TextOptionsUpdate::Font {
|
||||
family: font_input.font_family.clone(),
|
||||
style: font_input.font_style.clone(),
|
||||
},
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_holder();
|
||||
@@ -123,7 +127,12 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
|
||||
.int()
|
||||
.min(1.)
|
||||
.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();
|
||||
let line_height_ratio = NumberInput::new(Some(tool.options.line_height_ratio))
|
||||
.label("Line Height")
|
||||
@@ -131,14 +140,22 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
|
||||
.min(0.)
|
||||
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||
.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();
|
||||
let align_entries: Vec<_> = [TextAlign::Left, TextAlign::Center, TextAlign::Right, TextAlign::JustifyLeft]
|
||||
.into_iter()
|
||||
.map(|align| {
|
||||
RadioEntryData::new(format!("{align:?}"))
|
||||
.label(align.to_string())
|
||||
.on_update(move |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::Align(align)).into())
|
||||
RadioEntryData::new(format!("{align:?}")).label(align.to_string()).on_update(move |_| {
|
||||
TextToolMessage::UpdateOptions {
|
||||
options: TextOptionsUpdate::Align(align),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
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(
|
||||
"Fill",
|
||||
true,
|
||||
|_| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColor(None)).into(),
|
||||
|color_type: ToolColorType| WidgetCallback::new(move |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColorType(color_type.clone())).into()),
|
||||
|color: &ColorInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
|
||||
|_| {
|
||||
TextToolMessage::UpdateOptions {
|
||||
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 }]))
|
||||
@@ -176,11 +210,11 @@ impl LayoutHolder for TextTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for TextTool {
|
||||
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);
|
||||
return;
|
||||
};
|
||||
match action {
|
||||
match options {
|
||||
TextOptionsUpdate::Font { family, style } => {
|
||||
self.options.font_name = family;
|
||||
self.options.font_style = style;
|
||||
@@ -237,7 +271,7 @@ impl ToolTransition for TextTool {
|
||||
canvas_transformed: None,
|
||||
tool_abort: Some(TextToolMessage::Abort.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()
|
||||
}
|
||||
}
|
||||
@@ -474,7 +508,7 @@ impl Fsm for TextToolFsmState {
|
||||
|
||||
let ToolMessage::Text(event) = event else { return self };
|
||||
match (self, event) {
|
||||
(TextToolFsmState::Editing, TextToolMessage::Overlays(mut overlay_context)) => {
|
||||
(TextToolFsmState::Editing, TextToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
responses.add(FrontendMessage::DisplayEditableTextboxTransform {
|
||||
transform: document.metadata().transform_to_viewport(tool_data.layer).to_cols_array(),
|
||||
});
|
||||
@@ -490,7 +524,7 @@ impl Fsm for TextToolFsmState {
|
||||
|
||||
TextToolFsmState::Editing
|
||||
}
|
||||
(_, TextToolMessage::Overlays(mut overlay_context)) => {
|
||||
(_, TextToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
if matches!(self, Self::Placing) {
|
||||
// Get the updated selection box bounds
|
||||
let quad = Quad::from_box(tool_data.cached_resize_bounds);
|
||||
@@ -852,10 +886,9 @@ impl Fsm for TextToolFsmState {
|
||||
TextToolFsmState::Editing
|
||||
}
|
||||
(_, TextToolMessage::WorkingColorChanged) => {
|
||||
responses.add(TextToolMessage::UpdateOptions(TextOptionsUpdate::WorkingColors(
|
||||
Some(global_tool_data.primary_color),
|
||||
Some(global_tool_data.secondary_color),
|
||||
)));
|
||||
responses.add(TextToolMessage::UpdateOptions {
|
||||
options: TextOptionsUpdate::WorkingColors(Some(global_tool_data.primary_color), Some(global_tool_data.secondary_color)),
|
||||
});
|
||||
self
|
||||
}
|
||||
(TextToolFsmState::Editing, TextToolMessage::Abort) => {
|
||||
|
||||
@@ -8,10 +8,8 @@ use glam::DVec2;
|
||||
#[impl_message(Message, ToolMessage, TransformLayer)]
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum TransformLayerMessage {
|
||||
// Overlays
|
||||
Overlays(OverlayContext),
|
||||
|
||||
// Messages
|
||||
Overlays { context: OverlayContext },
|
||||
ApplyTransformOperation { final_transform: bool },
|
||||
BeginTransformOperation { operation: TransformType },
|
||||
BeginGrab,
|
||||
|
||||
@@ -16,7 +16,7 @@ use graphene_std::vector::misc::ManipulatorPointId;
|
||||
use graphene_std::vector::{Vector, VectorModificationType};
|
||||
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
|
||||
const SLOW_KEY: Key = Key::Shift;
|
||||
@@ -69,6 +69,7 @@ pub struct TransformLayerMessageHandler {
|
||||
was_grabbing: bool,
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for TransformLayerMessageHandler {
|
||||
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, context: TransformLayerMessageContext) {
|
||||
let TransformLayerMessageContext {
|
||||
@@ -172,7 +173,7 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
|
||||
match message {
|
||||
// Overlays
|
||||
TransformLayerMessage::Overlays(mut overlay_context) => {
|
||||
TransformLayerMessage::Overlays { context: mut overlay_context } => {
|
||||
if !overlay_context.visibility_settings.transform_measurement() {
|
||||
return;
|
||||
}
|
||||
@@ -304,7 +305,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
|
||||
if final_transform {
|
||||
self.was_grabbing = false;
|
||||
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
|
||||
responses.add(OverlaysMessage::RemoveProvider {
|
||||
provider: TRANSFORM_GRS_OVERLAY_PROVIDER,
|
||||
});
|
||||
}
|
||||
}
|
||||
TransformLayerMessage::BeginTransformOperation { operation } => {
|
||||
@@ -343,7 +346,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
_ => 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
|
||||
responses.add(TransformLayerMessage::PointerMove {
|
||||
slow_key: SLOW_KEY,
|
||||
@@ -428,7 +433,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
if chain_operation {
|
||||
responses.add(TransformLayerMessage::ApplyTransformOperation { final_transform: false });
|
||||
} 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::PointerMove {
|
||||
@@ -465,7 +472,9 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
}
|
||||
|
||||
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 => {
|
||||
let pivot = document_to_viewport.transform_point2(self.local_pivot);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use super::common_functionality::shape_editor::ShapeState;
|
||||
use super::tool_messages::*;
|
||||
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::macros::action_keys;
|
||||
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
||||
@@ -141,7 +141,7 @@ impl DocumentToolData {
|
||||
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 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 {
|
||||
responses.add(BroadcastMessage::SubscribeEvent {
|
||||
on: event,
|
||||
@@ -168,32 +168,32 @@ pub trait ToolTransition {
|
||||
};
|
||||
|
||||
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.tool_abort, BroadcastEvent::ToolAbort);
|
||||
subscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
||||
subscribe_message(event_to_tool_map.working_color_changed, BroadcastEvent::WorkingColorChanged);
|
||||
subscribe_message(event_to_tool_map.canvas_transformed, EventMessage::CanvasTransformed);
|
||||
subscribe_message(event_to_tool_map.tool_abort, EventMessage::ToolAbort);
|
||||
subscribe_message(event_to_tool_map.selection_changed, EventMessage::SelectionChanged);
|
||||
subscribe_message(event_to_tool_map.working_color_changed, EventMessage::WorkingColorChanged);
|
||||
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>) {
|
||||
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 {
|
||||
responses.add(BroadcastMessage::UnsubscribeEvent {
|
||||
on: event,
|
||||
message: Box::new(mapping.into()),
|
||||
send: Box::new(mapping.into()),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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.tool_abort, BroadcastEvent::ToolAbort);
|
||||
unsubscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
||||
unsubscribe_message(event_to_tool_map.working_color_changed, BroadcastEvent::WorkingColorChanged);
|
||||
unsubscribe_message(event_to_tool_map.canvas_transformed, EventMessage::CanvasTransformed);
|
||||
unsubscribe_message(event_to_tool_map.tool_abort, EventMessage::ToolAbort);
|
||||
unsubscribe_message(event_to_tool_map.selection_changed, EventMessage::SelectionChanged);
|
||||
unsubscribe_message(event_to_tool_map.working_color_changed, EventMessage::WorkingColorChanged);
|
||||
if let Some(overlay_provider) = event_to_tool_map.overlay_provider {
|
||||
responses.add(OverlaysMessage::RemoveProvider(overlay_provider));
|
||||
responses.add(OverlaysMessage::RemoveProvider { provider: overlay_provider });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user