mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 12:08:11 +08:00
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:
@@ -228,42 +228,38 @@ pub fn overlay_options(grid: &GridSnapping) -> Vec<LayoutGroup> {
|
||||
})
|
||||
};
|
||||
|
||||
widgets.push(LayoutGroup::Row {
|
||||
widgets: vec![TextLabel::new("Grid").bold(true).widget_instance()],
|
||||
});
|
||||
widgets.push(LayoutGroup::row(vec![TextLabel::new("Grid").bold(true).widget_instance()]));
|
||||
|
||||
widgets.push(LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
TextLabel::new("Type").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
RadioInput::new(vec![
|
||||
RadioEntryData::new("rectangular").label("Rectangular").on_update(update_val(grid, |grid, _| {
|
||||
if let GridType::Isometric { y_axis_spacing, angle_a, angle_b } = grid.grid_type {
|
||||
grid.isometric_y_spacing = y_axis_spacing;
|
||||
grid.isometric_angle_a = angle_a;
|
||||
grid.isometric_angle_b = angle_b;
|
||||
}
|
||||
grid.grid_type = GridType::Rectangular { spacing: grid.rectangular_spacing };
|
||||
})),
|
||||
RadioEntryData::new("isometric").label("Isometric").on_update(update_val(grid, |grid, _| {
|
||||
if let GridType::Rectangular { spacing } = grid.grid_type {
|
||||
grid.rectangular_spacing = spacing;
|
||||
}
|
||||
grid.grid_type = GridType::Isometric {
|
||||
y_axis_spacing: grid.isometric_y_spacing,
|
||||
angle_a: grid.isometric_angle_a,
|
||||
angle_b: grid.isometric_angle_b,
|
||||
};
|
||||
})),
|
||||
])
|
||||
.min_width(200)
|
||||
.selected_index(Some(match grid.grid_type {
|
||||
GridType::Rectangular { .. } => 0,
|
||||
GridType::Isometric { .. } => 1,
|
||||
}))
|
||||
.widget_instance(),
|
||||
],
|
||||
});
|
||||
widgets.push(LayoutGroup::row(vec![
|
||||
TextLabel::new("Type").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
RadioInput::new(vec![
|
||||
RadioEntryData::new("rectangular").label("Rectangular").on_update(update_val(grid, |grid, _| {
|
||||
if let GridType::Isometric { y_axis_spacing, angle_a, angle_b } = grid.grid_type {
|
||||
grid.isometric_y_spacing = y_axis_spacing;
|
||||
grid.isometric_angle_a = angle_a;
|
||||
grid.isometric_angle_b = angle_b;
|
||||
}
|
||||
grid.grid_type = GridType::Rectangular { spacing: grid.rectangular_spacing };
|
||||
})),
|
||||
RadioEntryData::new("isometric").label("Isometric").on_update(update_val(grid, |grid, _| {
|
||||
if let GridType::Rectangular { spacing } = grid.grid_type {
|
||||
grid.rectangular_spacing = spacing;
|
||||
}
|
||||
grid.grid_type = GridType::Isometric {
|
||||
y_axis_spacing: grid.isometric_y_spacing,
|
||||
angle_a: grid.isometric_angle_a,
|
||||
angle_b: grid.isometric_angle_b,
|
||||
};
|
||||
})),
|
||||
])
|
||||
.min_width(200)
|
||||
.selected_index(Some(match grid.grid_type {
|
||||
GridType::Rectangular { .. } => 0,
|
||||
GridType::Isometric { .. } => 1,
|
||||
}))
|
||||
.widget_instance(),
|
||||
]));
|
||||
|
||||
let mut color_widgets = vec![
|
||||
TextLabel::new("Display").table_align(true).widget_instance(),
|
||||
@@ -288,80 +284,72 @@ pub fn overlay_options(grid: &GridSnapping) -> Vec<LayoutGroup> {
|
||||
}))
|
||||
.widget_instance(),
|
||||
);
|
||||
widgets.push(LayoutGroup::Row { widgets: color_widgets });
|
||||
widgets.push(LayoutGroup::row(color_widgets));
|
||||
|
||||
widgets.push(LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
TextLabel::new("Origin").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(grid.origin.x))
|
||||
.label("X")
|
||||
.unit(" px")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| Some(&mut grid.origin.x)))
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
NumberInput::new(Some(grid.origin.y))
|
||||
.label("Y")
|
||||
.unit(" px")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| Some(&mut grid.origin.y)))
|
||||
.widget_instance(),
|
||||
],
|
||||
});
|
||||
widgets.push(LayoutGroup::row(vec![
|
||||
TextLabel::new("Origin").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(grid.origin.x))
|
||||
.label("X")
|
||||
.unit(" px")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| Some(&mut grid.origin.x)))
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
NumberInput::new(Some(grid.origin.y))
|
||||
.label("Y")
|
||||
.unit(" px")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| Some(&mut grid.origin.y)))
|
||||
.widget_instance(),
|
||||
]));
|
||||
|
||||
match grid.grid_type {
|
||||
GridType::Rectangular { spacing } => widgets.push(LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
TextLabel::new("Spacing").table_align(true).widget_instance(),
|
||||
GridType::Rectangular { spacing } => widgets.push(LayoutGroup::row(vec![
|
||||
TextLabel::new("Spacing").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(spacing.x))
|
||||
.label("X")
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.rectangular_spacing().map(|spacing| &mut spacing.x)))
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
NumberInput::new(Some(spacing.y))
|
||||
.label("Y")
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.rectangular_spacing().map(|spacing| &mut spacing.y)))
|
||||
.widget_instance(),
|
||||
])),
|
||||
GridType::Isometric { y_axis_spacing, angle_a, angle_b } => {
|
||||
widgets.push(LayoutGroup::row(vec![
|
||||
TextLabel::new("Y Spacing").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(spacing.x))
|
||||
.label("X")
|
||||
NumberInput::new(Some(y_axis_spacing))
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
.min_width(200)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.isometric_y_spacing()))
|
||||
.widget_instance(),
|
||||
]));
|
||||
widgets.push(LayoutGroup::row(vec![
|
||||
TextLabel::new("Angles").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(angle_a))
|
||||
.unit("°")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.rectangular_spacing().map(|spacing| &mut spacing.x)))
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.angle_a()))
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
NumberInput::new(Some(spacing.y))
|
||||
.label("Y")
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
NumberInput::new(Some(angle_b))
|
||||
.unit("°")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.rectangular_spacing().map(|spacing| &mut spacing.y)))
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.angle_b()))
|
||||
.widget_instance(),
|
||||
],
|
||||
}),
|
||||
GridType::Isometric { y_axis_spacing, angle_a, angle_b } => {
|
||||
widgets.push(LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
TextLabel::new("Y Spacing").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(y_axis_spacing))
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
.min_width(200)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.isometric_y_spacing()))
|
||||
.widget_instance(),
|
||||
],
|
||||
});
|
||||
widgets.push(LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
TextLabel::new("Angles").table_align(true).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
NumberInput::new(Some(angle_a))
|
||||
.unit("°")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.angle_a()))
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
NumberInput::new(Some(angle_b))
|
||||
.unit("°")
|
||||
.min_width(98)
|
||||
.on_update(update_origin(grid, |grid| grid.grid_type.angle_b()))
|
||||
.widget_instance(),
|
||||
],
|
||||
});
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ pub enum GizmoEmphasis {
|
||||
|
||||
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||
/// Types of overlays used by DocumentMessage to enable/disable the selected set of viewport overlays.
|
||||
#[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 OverlaysType {
|
||||
ArtboardName,
|
||||
CompassRose,
|
||||
@@ -60,7 +61,8 @@ pub enum OverlaysType {
|
||||
}
|
||||
|
||||
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||
#[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)]
|
||||
#[serde(default)]
|
||||
pub struct OverlaysVisibilitySettings {
|
||||
pub all: bool,
|
||||
@@ -160,11 +162,11 @@ impl OverlaysVisibilitySettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct OverlayContext {
|
||||
// Serde functionality isn't used but is required by the message system macros
|
||||
#[serde(skip)]
|
||||
#[specta(skip)]
|
||||
internal: Arc<Mutex<OverlayContextInternal>>,
|
||||
pub viewport: ViewportMessageHandler,
|
||||
pub visibility_settings: OverlaysVisibilitySettings,
|
||||
|
||||
@@ -35,7 +35,8 @@ pub enum GizmoEmphasis {
|
||||
}
|
||||
|
||||
/// Types of overlays used by DocumentMessage to enable/disable the selected set of viewport overlays.
|
||||
#[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 OverlaysType {
|
||||
ArtboardName,
|
||||
CompassRose,
|
||||
@@ -52,7 +53,8 @@ pub enum OverlaysType {
|
||||
Handles,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[serde(default)]
|
||||
pub struct OverlaysVisibilitySettings {
|
||||
pub all: bool,
|
||||
@@ -150,11 +152,11 @@ impl OverlaysVisibilitySettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[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 OverlayContext {
|
||||
// Serde functionality isn't used but is required by the message system macros
|
||||
#[serde(skip, default = "overlay_canvas_context")]
|
||||
#[specta(skip)]
|
||||
pub render_context: web_sys::CanvasRenderingContext2d,
|
||||
pub viewport: ViewportMessageHandler,
|
||||
pub visibility_settings: OverlaysVisibilitySettings,
|
||||
|
||||
Reference in New Issue
Block a user