Refactor the TypeScript data flow for full type safety and auto-generation of Rust types (#3865)

* Migrate Specta to Tsify to auto-generate messages.ts, working except colors and widgets

* Adopt the generated FillColor/Color/GradientStops

* Fix widget typing

* Separate WidgetGroup enum variants into wrapper structs

* Small rename

* Simplify widgets further

* Clean up message type references

* Switch type imports to the auto-generated file

* Remove lowercase serde rename

* Fix FillChoice deserialization

* Fix small regression from #3837

* Improve type safety

* Make WidgetSpan type-safe

* More cleanup and type safety

* More type safety

* More type safety

* Get the rest to type-check without errors; improve widget builder macro to have optional icons; improve Svelte 5 configs

* Cargo fmt

* Fix imports

* Update outdated readme info

* Fix lint command rename references

* Fix typos

* One more typos fix

* Remove unnecessary dep: prefix from the edited Cargo.toml files

* Remove excess parts from Cargo.toml

* Fix compiling on desktop

* Revert "Remove excess parts from Cargo.toml"

This reverts commit 6b711117b3a5d5d8a3ee20f36a43bc74930b7c82.

* Update dev docs with simpler, more accurate instructions
This commit is contained in:
Keavon Chambers
2026-03-09 16:35:04 -07:00
parent fbd2658148
commit 52d2b38a82
199 changed files with 2265 additions and 2811 deletions
@@ -4,7 +4,8 @@ use crate::messages::prelude::*;
use graphene_std::Color;
use graphene_std::vector::style::FillChoice;
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum ToolColorType {
Primary,
Secondary,
@@ -150,7 +150,8 @@ impl PivotGizmo {
}
}
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum PivotGizmoType {
// Pivot
#[default]
@@ -161,7 +162,8 @@ pub enum PivotGizmoType {
// TODO: Add "Individual"
}
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub struct PivotGizmoState {
pub enabled: bool,
pub gizmo_type: PivotGizmoType,
@@ -23,7 +23,8 @@ use kurbo::{BezPath, PathEl, Shape};
use std::collections::VecDeque;
use std::f64::consts::{PI, TAU};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub enum ShapeType {
#[default]
Polygon = 0,
@@ -22,7 +22,8 @@ pub struct ArtboardTool {
}
#[impl_message(Message, ToolMessage, Artboard)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum ArtboardToolMessage {
// Standard messages
Abort,
@@ -13,7 +13,8 @@ use graphene_std::raster::BlendMode;
const BRUSH_MAX_SIZE: f64 = 5000.;
#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum DrawMode {
Draw = 0,
Erase,
@@ -52,7 +53,8 @@ impl Default for BrushOptions {
}
#[impl_message(Message, ToolMessage, Brush)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum BrushToolMessage {
// Standard messages
Abort,
@@ -65,7 +67,8 @@ pub enum BrushToolMessage {
UpdateOptions { options: BrushToolMessageOptionsUpdate },
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum BrushToolMessageOptionsUpdate {
BlendMode(BlendMode),
ChangeDiameter(f64),
@@ -220,7 +223,7 @@ impl LayoutHolder for BrushTool {
.widget_instance(),
);
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -9,7 +9,8 @@ pub struct EyedropperTool {
}
#[impl_message(Message, ToolMessage, Eyedropper)]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum EyedropperToolMessage {
// Standard messages
Abort,
@@ -46,9 +47,9 @@ impl LayoutHolder for EyedropperTool {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for EyedropperTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
if let ToolMessage::Eyedropper(EyedropperToolMessage::PreviewImage { data, width, height }) = message {
let image = EyedropperPreviewImage { data, width, height };
let image = EyedropperPreviewImage { data: data.into(), width, height };
update_cursor_preview_common(responses, Some(image), context.input, context.global_tool_data, self.data.color_choice.clone());
update_cursor_preview_common(responses, Some(image), context.input, context.global_tool_data, self.data.color_choice);
if !self.data.preview {
disable_cursor_preview(responses, &mut self.data);
@@ -87,10 +88,18 @@ enum EyedropperToolFsmState {
SamplingSecondary,
}
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum PrimarySecondary {
#[default]
Primary,
Secondary,
}
#[derive(Clone, Debug, Default)]
struct EyedropperToolData {
preview: bool,
color_choice: Option<String>,
color_choice: Option<PrimarySecondary>,
}
impl Fsm for EyedropperToolFsmState {
@@ -127,7 +136,11 @@ impl Fsm for EyedropperToolFsmState {
}
// Sampling -> Ready
(EyedropperToolFsmState::SamplingPrimary, EyedropperToolMessage::SamplePrimaryColorEnd) | (EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::SampleSecondaryColorEnd) => {
let set_color_choice = if self == EyedropperToolFsmState::SamplingPrimary { "Primary" } else { "Secondary" }.to_string();
let set_color_choice = match self {
EyedropperToolFsmState::SamplingPrimary => PrimarySecondary::Primary,
EyedropperToolFsmState::SamplingSecondary => PrimarySecondary::Secondary,
_ => unreachable!(),
};
update_cursor_preview(responses, tool_data, input, global_tool_data, Some(set_color_choice));
disable_cursor_preview(responses, tool_data);
@@ -185,7 +198,7 @@ fn update_cursor_preview(
tool_data: &mut EyedropperToolData,
_input: &InputPreprocessorMessageHandler,
_global_tool_data: &DocumentToolData,
set_color_choice: Option<String>,
set_color_choice: Option<PrimarySecondary>,
) {
tool_data.preview = true;
tool_data.color_choice = set_color_choice;
@@ -198,7 +211,7 @@ fn update_cursor_preview(
tool_data: &mut EyedropperToolData,
input: &InputPreprocessorMessageHandler,
global_tool_data: &DocumentToolData,
set_color_choice: Option<String>,
set_color_choice: Option<PrimarySecondary>,
) {
tool_data.preview = true;
tool_data.color_choice = set_color_choice.clone();
@@ -211,7 +224,7 @@ fn update_cursor_preview_common(
image: Option<EyedropperPreviewImage>,
input: &InputPreprocessorMessageHandler,
global_tool_data: &DocumentToolData,
set_color_choice: Option<String>,
set_color_choice: Option<PrimarySecondary>,
) {
responses.add(FrontendMessage::UpdateEyedropperSamplingState {
image,
@@ -9,7 +9,8 @@ pub struct FillTool {
}
#[impl_message(Message, ToolMessage, Fill)]
#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum FillToolMessage {
// Standard messages
Abort,
@@ -37,7 +37,8 @@ impl Default for FreehandOptions {
}
#[impl_message(Message, ToolMessage, Freehand)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum FreehandToolMessage {
// Standard messages
Overlays { context: OverlayContext },
@@ -51,7 +52,8 @@ pub enum FreehandToolMessage {
UpdateOptions { options: FreehandOptionsUpdate },
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum FreehandOptionsUpdate {
FillColor(Option<Color>),
FillColorType(ToolColorType),
@@ -151,7 +153,7 @@ impl LayoutHolder for FreehandTool {
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
widgets.push(create_weight_widget(self.options.line_weight));
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -24,7 +24,8 @@ pub struct GradientOptions {
}
#[impl_message(Message, ToolMessage, Gradient)]
#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum GradientToolMessage {
// Standard messages
Abort,
@@ -46,7 +47,8 @@ pub enum GradientToolMessage {
UpdateOptions { options: GradientOptionsUpdate },
}
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum GradientOptionsUpdate {
Type(GradientType),
ReverseStops,
@@ -199,7 +201,7 @@ impl LayoutHolder for GradientTool {
widgets.push(reverse_direction);
}
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -770,8 +772,8 @@ impl Fsm for GradientToolFsmState {
if stop_index < gradient.stops.position.len() {
let color = gradient.stops.color[stop_index].to_gamma_srgb();
let position = gradient.stops.position[stop_index];
let DVec2 { x, y } = transform.transform_point2(gradient.start.lerp(gradient.end, position));
responses.add(FrontendMessage::UpdateGradientStopColorPickerPosition { color, x, y });
let position = transform.transform_point2(gradient.start.lerp(gradient.end, position)).into();
responses.add(FrontendMessage::UpdateGradientStopColorPickerPosition { color, position });
}
}
@@ -824,13 +826,10 @@ impl Fsm for GradientToolFsmState {
let viewport_pos = selected_gradient
.transform
.transform_point2(selected_gradient.gradient.start.lerp(selected_gradient.gradient.end, stop_pos));
let position = viewport_pos.into();
let color = selected_gradient.gradient.stops.color[stop_index].to_gamma_srgb();
tool_data.color_picker_editing_color_stop = Some(stop_index);
responses.add(FrontendMessage::UpdateGradientStopColorPickerPosition {
color,
x: viewport_pos.x,
y: viewport_pos.y,
});
responses.add(FrontendMessage::UpdateGradientStopColorPickerPosition { color, position });
}
}
_ => {}
@@ -7,7 +7,8 @@ pub struct NavigateTool {
}
#[impl_message(Message, ToolMessage, Navigate)]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum NavigateToolMessage {
// Standard messages
Abort,
@@ -50,7 +50,8 @@ pub struct PathToolOptions {
}
#[impl_message(Message, ToolMessage, Path)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum PathToolMessage {
// Standard messages
Abort,
@@ -155,7 +156,8 @@ pub enum PathToolMessage {
ToggleSegmentEditing,
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Default, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub enum PathOverlayMode {
AllHandles = 0,
#[default]
@@ -178,7 +180,8 @@ impl Default for PathEditingMode {
}
}
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum PathOptionsUpdate {
OverlayModeType(PathOverlayMode),
PointEditingMode { enabled: bool },
@@ -326,7 +329,7 @@ impl LayoutHolder for PathTool {
// Works only if a single layer is selected and its type is Vector
let path_node_button = TextButton::new("Make Path Editable")
.icon(Some("NodeShape".into()))
.icon("NodeShape")
.tooltip_label("Make Path Editable")
.tooltip_description(
"Enables the Pen and Path tools to directly edit layer geometry resulting from nondestructive operations. This inserts a 'Path' node as the last operation of the selected layer.",
@@ -349,32 +352,30 @@ impl LayoutHolder for PathTool {
let _pin_pivot = pin_pivot_widget(self.tool_data.pivot_gizmo.pin_active(), false, PivotToolSource::Path);
Layout(vec![LayoutGroup::Row {
widgets: vec![
x_location,
related_seperator.clone(),
y_location,
unrelated_seperator.clone(),
colinear_handle_checkbox,
related_seperator.clone(),
colinear_handles_label,
unrelated_seperator.clone(),
point_editing_mode,
related_seperator.clone(),
segment_editing_mode,
unrelated_seperator.clone(),
path_overlay_mode_widget,
unrelated_seperator.clone(),
path_node_button,
// checkbox.clone(),
// related_seperator.clone(),
// dropdown.clone(),
// unrelated_seperator,
// pivot_reference,
// related_seperator.clone(),
// pin_pivot,
],
}])
Layout(vec![LayoutGroup::row(vec![
x_location,
related_seperator.clone(),
y_location,
unrelated_seperator.clone(),
colinear_handle_checkbox,
related_seperator.clone(),
colinear_handles_label,
unrelated_seperator.clone(),
point_editing_mode,
related_seperator.clone(),
segment_editing_mode,
unrelated_seperator.clone(),
path_overlay_mode_widget,
unrelated_seperator.clone(),
path_node_button,
// checkbox.clone(),
// related_seperator.clone(),
// dropdown.clone(),
// unrelated_seperator,
// pivot_reference,
// related_seperator.clone(),
// pin_pivot,
])])
}
}
@@ -44,7 +44,8 @@ impl Default for PenOptions {
}
#[impl_message(Message, ToolMessage, Pen)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum PenToolMessage {
// Standard messages
Abort,
@@ -107,13 +108,15 @@ enum PenToolFsmState {
GRSHandle,
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum PenOverlayMode {
AllHandles = 0,
FrontierHandles = 1,
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum PenOptionsUpdate {
FillColor(Option<Color>),
FillColorType(ToolColorType),
@@ -238,7 +241,7 @@ impl LayoutHolder for PenTool {
.widget_instance(),
);
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -42,7 +42,8 @@ pub struct SelectOptions {
nested_selection_behavior: NestedSelectionBehavior,
}
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum SelectOptionsUpdate {
NestedSelectionBehavior(NestedSelectionBehavior),
PivotGizmoType(PivotGizmoType),
@@ -50,7 +51,8 @@ pub enum SelectOptionsUpdate {
TogglePivotPinned,
}
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize)]
pub enum NestedSelectionBehavior {
#[default]
Shallowest,
@@ -66,7 +68,8 @@ impl fmt::Display for NestedSelectionBehavior {
}
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct SelectToolPointerKeys {
pub axis_align: Key,
pub snap_angle: Key,
@@ -75,7 +78,8 @@ pub struct SelectToolPointerKeys {
}
#[impl_message(Message, ToolMessage, Select)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum SelectToolMessage {
// Standard messages
Abort,
@@ -265,7 +269,7 @@ impl LayoutHolder for SelectTool {
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
widgets.extend(self.boolean_widgets(self.tool_data.selected_layers_count));
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -68,7 +68,8 @@ impl Default for ShapeToolOptions {
}
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum ShapeOptionsUpdate {
FillColor(Option<Color>),
FillColorType(ToolColorType),
@@ -88,7 +89,8 @@ pub enum ShapeOptionsUpdate {
}
#[impl_message(Message, ToolMessage, Shape)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum ShapeToolMessage {
// Standard messages
Overlays { context: OverlayContext },
@@ -423,7 +425,7 @@ impl LayoutHolder for ShapeTool {
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
widgets.push(create_weight_widget(self.options.line_weight));
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -38,7 +38,8 @@ impl Default for SplineOptions {
}
#[impl_message(Message, ToolMessage, Spline)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum SplineToolMessage {
// Standard messages
Overlays { context: OverlayContext },
@@ -65,7 +66,8 @@ enum SplineToolFsmState {
MergingEndpoints,
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum SplineOptionsUpdate {
FillColor(Option<Color>),
FillColorType(ToolColorType),
@@ -158,7 +160,7 @@ impl LayoutHolder for SplineTool {
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
widgets.push(create_weight_widget(self.options.line_weight));
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -55,7 +55,8 @@ impl Default for TextOptions {
}
#[impl_message(Message, ToolMessage, Text)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum TextToolMessage {
// Standard messages
Abort,
@@ -75,7 +76,8 @@ pub enum TextToolMessage {
RefreshEditingFontData,
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum TextOptionsUpdate {
FillColor(Option<Color>),
FillColorType(ToolColorType),
@@ -271,7 +273,7 @@ impl TextTool {
},
));
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
}
@@ -413,7 +415,7 @@ impl TextToolData {
line_height_ratio: editing_text.typesetting.line_height_ratio,
font_size: editing_text.typesetting.font_size,
color: editing_text.color.map_or("#000000".to_string(), |color| format!("#{}", color.to_rgba_hex_srgb())),
font_data: font_cache.get(&editing_text.font).map(|(data, _)| data.clone()).unwrap_or_default(),
font_data: font_cache.get(&editing_text.font).map(|(data, _)| data.clone()).unwrap_or_default().into(),
transform: editing_text.transform.to_cols_array(),
max_width: editing_text.typesetting.max_width,
max_height: editing_text.typesetting.max_height,
@@ -925,7 +927,7 @@ impl Fsm for TextToolFsmState {
(TextToolFsmState::Editing, TextToolMessage::RefreshEditingFontData) => {
let font = Font::new(tool_options.font.font_family.clone(), tool_options.font.font_style.clone());
responses.add(FrontendMessage::DisplayEditableTextboxUpdateFontData {
font_data: font_cache.get(&font).map(|(data, _)| data.clone()).unwrap_or_default(),
font_data: font_cache.get(&font).map(|(data, _)| data.clone()).unwrap_or_default().into(),
});
TextToolFsmState::Editing
+25 -23
View File
@@ -128,23 +128,21 @@ pub struct DocumentToolData {
impl DocumentToolData {
pub fn update_working_colors(&self, responses: &mut VecDeque<Message>) {
let layout = Layout(vec![
LayoutGroup::Row {
widgets: vec![WorkingColorsInput::new(self.primary_color.to_gamma_srgb(), self.secondary_color.to_gamma_srgb()).widget_instance()],
},
LayoutGroup::Row {
widgets: vec![
IconButton::new("SwapVertical", 16)
.tooltip_label("Swap Working Colors")
.tooltip_shortcut(action_shortcut!(ToolMessageDiscriminant::SwapColors))
.on_update(|_| ToolMessage::SwapColors.into())
.widget_instance(),
IconButton::new("WorkingColors", 16)
.tooltip_label("Reset Working Colors")
.tooltip_shortcut(action_shortcut!(ToolMessageDiscriminant::ResetColors))
.on_update(|_| ToolMessage::ResetColors.into())
.widget_instance(),
],
},
LayoutGroup::row(vec![
WorkingColorsInput::new(self.primary_color.to_gamma_srgb(), self.secondary_color.to_gamma_srgb()).widget_instance(),
]),
LayoutGroup::row(vec![
IconButton::new("SwapVertical", 16)
.tooltip_label("Swap Working Colors")
.tooltip_shortcut(action_shortcut!(ToolMessageDiscriminant::SwapColors))
.on_update(|_| ToolMessage::SwapColors.into())
.widget_instance(),
IconButton::new("WorkingColors", 16)
.tooltip_label("Reset Working Colors")
.tooltip_shortcut(action_shortcut!(ToolMessageDiscriminant::ResetColors))
.on_update(|_| ToolMessage::ResetColors.into())
.widget_instance(),
]),
]);
responses.add(LayoutMessage::SendLayout {
@@ -308,7 +306,7 @@ impl ToolData {
.skip(1)
.collect();
Layout(vec![LayoutGroup::Row { widgets: tool_groups_layout }])
Layout(vec![LayoutGroup::row(tool_groups_layout)])
}
}
@@ -360,7 +358,8 @@ impl ToolFsmState {
}
#[repr(usize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Default, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Default)]
pub enum ToolType {
// General tool group
#[default]
@@ -524,7 +523,8 @@ pub fn tool_type_to_activate_tool_message(tool_type: ToolType) -> ToolMessageDis
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct HintData(pub Vec<HintGroup>);
impl HintData {
@@ -558,7 +558,7 @@ impl HintData {
}
}
Layout(vec![LayoutGroup::Row { widgets }])
Layout(vec![LayoutGroup::row(widgets)])
}
pub fn send_layout(&self, responses: &mut VecDeque<Message>) {
@@ -576,10 +576,12 @@ impl HintData {
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct HintGroup(pub Vec<HintInfo>);
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct HintInfo {
/// A `KeysGroup` specifies all the keys pressed simultaneously to perform an action (like "Ctrl C" to copy).
/// Usually at most one is given, but less commonly, multiple can be used to describe additional hotkeys not used simultaneously (like the four different arrow keys to nudge a layer).