diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 55623c1457..93b3feb9e5 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -350,6 +350,12 @@ (when constraint (h/call wasm/internal-module "_set_shape_constraint_v" (sr/translate-constraint-v constraint)))) +(defn set-shape-constraints + [constraint-h constraint-v] + (h/call wasm/internal-module "_clear_shape_constraints") + (set-constraints-h constraint-h) + (set-constraints-v constraint-v)) + (defn set-shape-hidden [hidden] (h/call wasm/internal-module "_set_shape_hidden" hidden)) @@ -588,6 +594,24 @@ is-absolute z-index))) +(defn clear-layout + [] + (h/call wasm/internal-module "_clear_shape_layout")) + +(defn- set-shape-layout + [shape objects] + (clear-layout) + + (when (or (ctl/any-layout? shape) + (ctl/any-layout-immediate-child? objects shape)) + (set-layout-child shape)) + + (when (ctl/flex-layout? shape) + (set-flex-layout shape)) + + (when (ctl/grid-layout? shape) + (set-grid-layout shape))) + (defn set-shape-shadows [shadows] (h/call wasm/internal-module "_clear_shape_shadows") @@ -711,8 +735,8 @@ (set-parent-id parent-id) (set-shape-type type) (set-shape-clip-content clip-content) - (set-constraints-h constraint-h) - (set-constraints-v constraint-v) + (set-shape-constraints constraint-h constraint-v) + (set-shape-rotation rotation) (set-shape-transform transform) (set-shape-blend-mode blend-mode) @@ -738,15 +762,7 @@ (when (= type :text) (set-shape-grow-type grow-type)) - (when (or (ctl/any-layout? shape) - (ctl/any-layout-immediate-child? objects shape)) - (set-layout-child shape)) - - (when (ctl/flex-layout? shape) - (set-flex-layout shape)) - - (when (ctl/grid-layout? shape) - (set-grid-layout shape)) + (set-shape-layout shape objects) (set-shape-selrect selrect) diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs index 466d8afefa..7bd0ba042c 100644 --- a/frontend/src/app/render_wasm/shape.cljs +++ b/frontend/src/app/render_wasm/shape.cljs @@ -209,12 +209,14 @@ :layout-wrap-type :layout-padding-type :layout-padding) - (cond - (ctl/grid-layout? shape) - (api/set-grid-layout-data shape) + (do + (api/clear-layout) + (cond + (ctl/grid-layout? shape) + (api/set-grid-layout-data shape) - (ctl/flex-layout? shape) - (api/set-flex-layout shape)) + (ctl/flex-layout? shape) + (api/set-flex-layout shape))) nil))) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index d7036eb5c5..756d23336e 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -17,10 +17,7 @@ mod wasm; use indexmap::IndexSet; use math::{Bounds, Matrix}; use mem::SerializableResult; -use shapes::{ - BoolType, ConstraintH, ConstraintV, StructureEntry, StructureEntryType, TransformEntry, Type, - VerticalAlign, -}; +use shapes::{BoolType, StructureEntry, StructureEntryType, TransformEntry, Type}; use skia_safe as skia; use state::State; use utils::uuid_from_u32_quartet; @@ -374,13 +371,6 @@ pub extern "C" fn set_shape_blend_mode(mode: i32) { }); } -#[no_mangle] -pub extern "C" fn set_shape_vertical_align(align: u8) { - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_vertical_align(VerticalAlign::from(align)); - }); -} - #[no_mangle] pub extern "C" fn set_shape_opacity(opacity: f32) { with_current_shape_mut!(state, |shape: &mut Shape| { @@ -388,20 +378,6 @@ pub extern "C" fn set_shape_opacity(opacity: f32) { }); } -#[no_mangle] -pub extern "C" fn set_shape_constraint_h(constraint: u8) { - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_constraint_h(ConstraintH::from(constraint)); - }); -} - -#[no_mangle] -pub extern "C" fn set_shape_constraint_v(constraint: u8) { - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_constraint_v(ConstraintV::from(constraint)); - }); -} - #[no_mangle] pub extern "C" fn set_shape_hidden(hidden: bool) { with_current_shape_mut!(state, |shape: &mut Shape| { @@ -583,217 +559,6 @@ pub extern "C" fn update_shape_tiles() { }); } -#[no_mangle] -pub extern "C" fn set_flex_layout_data( - dir: u8, - row_gap: f32, - column_gap: f32, - align_items: u8, - align_content: u8, - justify_items: u8, - justify_content: u8, - wrap_type: u8, - padding_top: f32, - padding_right: f32, - padding_bottom: f32, - padding_left: f32, -) { - let dir = shapes::FlexDirection::from_u8(dir); - let align_items = shapes::AlignItems::from_u8(align_items); - let align_content = shapes::AlignContent::from_u8(align_content); - let justify_items = shapes::JustifyItems::from_u8(justify_items); - let justify_content = shapes::JustifyContent::from_u8(justify_content); - let wrap_type = shapes::WrapType::from_u8(wrap_type); - - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_flex_layout_data( - dir, - row_gap, - column_gap, - align_items, - align_content, - justify_items, - justify_content, - wrap_type, - padding_top, - padding_right, - padding_bottom, - padding_left, - ); - }); -} - -#[no_mangle] -pub extern "C" fn set_layout_child_data( - margin_top: f32, - margin_right: f32, - margin_bottom: f32, - margin_left: f32, - h_sizing: u8, - v_sizing: u8, - has_max_h: bool, - max_h: f32, - has_min_h: bool, - min_h: f32, - has_max_w: bool, - max_w: f32, - has_min_w: bool, - min_w: f32, - has_align_self: bool, - align_self: u8, - is_absolute: bool, - z_index: i32, -) { - let h_sizing = shapes::Sizing::from_u8(h_sizing); - let v_sizing = shapes::Sizing::from_u8(v_sizing); - let max_h = if has_max_h { Some(max_h) } else { None }; - let min_h = if has_min_h { Some(min_h) } else { None }; - let max_w = if has_max_w { Some(max_w) } else { None }; - let min_w = if has_min_w { Some(min_w) } else { None }; - let align_self = if has_align_self { - shapes::AlignSelf::from_u8(align_self) - } else { - None - }; - - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_flex_layout_child_data( - margin_top, - margin_right, - margin_bottom, - margin_left, - h_sizing, - v_sizing, - max_h, - min_h, - max_w, - min_w, - align_self, - is_absolute, - z_index, - ); - }); -} - -#[no_mangle] -pub extern "C" fn set_grid_layout_data( - dir: u8, - row_gap: f32, - column_gap: f32, - align_items: u8, - align_content: u8, - justify_items: u8, - justify_content: u8, - padding_top: f32, - padding_right: f32, - padding_bottom: f32, - padding_left: f32, -) { - let dir = shapes::GridDirection::from_u8(dir); - let align_items = shapes::AlignItems::from_u8(align_items); - let align_content = shapes::AlignContent::from_u8(align_content); - let justify_items = shapes::JustifyItems::from_u8(justify_items); - let justify_content = shapes::JustifyContent::from_u8(justify_content); - - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_grid_layout_data( - dir, - row_gap, - column_gap, - align_items, - align_content, - justify_items, - justify_content, - padding_top, - padding_right, - padding_bottom, - padding_left, - ); - }); -} - -#[no_mangle] -pub extern "C" fn set_grid_columns() { - let bytes = mem::bytes(); - - let entries: Vec<_> = bytes - .chunks(size_of::()) - .map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap())) - .collect(); - - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_grid_columns(entries); - }); - - mem::free_bytes(); -} - -#[no_mangle] -pub extern "C" fn set_grid_rows() { - let bytes = mem::bytes(); - - let entries: Vec<_> = bytes - .chunks(size_of::()) - .map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap())) - .collect(); - - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_grid_rows(entries); - }); - - mem::free_bytes(); -} - -#[no_mangle] -pub extern "C" fn set_grid_cells() { - let bytes = mem::bytes(); - - let entries: Vec<_> = bytes - .chunks(size_of::()) - .map(|data| shapes::RawGridCell::from_bytes(data.try_into().unwrap())) - .collect(); - - with_current_shape_mut!(state, |shape: &mut Shape| { - shape.set_grid_cells(entries); - }); - - mem::free_bytes(); -} - -#[no_mangle] -pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) { - with_state_mut!(state, { - let id = uuid_from_u32_quartet(a, b, c, d); - state.render_state.show_grid = Some(id); - }); -} - -#[no_mangle] -pub extern "C" fn hide_grid() { - with_state_mut!(state, { - state.render_state.show_grid = None; - }); -} - -#[no_mangle] -pub extern "C" fn get_grid_coords(pos_x: f32, pos_y: f32) -> *mut u8 { - let row: i32; - let col: i32; - with_state!(state, { - if let Some((r, c)) = state.get_grid_coords(pos_x, pos_y) { - row = r; - col = c; - } else { - row = -1; - col = -1; - }; - }); - let mut bytes = vec![0; 8]; - bytes[0..4].clone_from_slice(&row.to_le_bytes()); - bytes[4..8].clone_from_slice(&col.to_le_bytes()); - mem::write_bytes(bytes) -} - fn main() { #[cfg(target_arch = "wasm32")] init_gl!(); diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index 64766355ef..0e6ac1728d 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -347,6 +347,11 @@ impl Shape { self.vertical_align } + pub fn clear_constraints(&mut self) { + self.constraint_h = None; + self.constraint_v = None; + } + pub fn set_constraint_h(&mut self, constraint: Option) { self.constraint_h = constraint; } @@ -402,6 +407,13 @@ impl Shape { }); } + pub fn clear_layout(&mut self) { + self.layout_item = None; + if let Type::Frame(data) = &mut self.shape_type { + data.layout = None; + } + } + // FIXME: These arguments could be grouped or simplified #[allow(clippy::too_many_arguments)] pub fn set_flex_layout_data( diff --git a/render-wasm/src/wasm.rs b/render-wasm/src/wasm.rs index 737023935c..b905da4687 100644 --- a/render-wasm/src/wasm.rs +++ b/render-wasm/src/wasm.rs @@ -1,5 +1,6 @@ pub mod fills; pub mod fonts; +pub mod layout; pub mod paths; pub mod strokes; pub mod text; diff --git a/render-wasm/src/wasm/layout.rs b/render-wasm/src/wasm/layout.rs new file mode 100644 index 0000000000..2eb7139433 --- /dev/null +++ b/render-wasm/src/wasm/layout.rs @@ -0,0 +1,249 @@ +use crate::mem; +use crate::shapes::{self, ConstraintH, ConstraintV, VerticalAlign}; +use crate::{uuid_from_u32_quartet, with_current_shape_mut, with_state, with_state_mut, STATE}; + +#[no_mangle] +pub extern "C" fn set_shape_constraint_h(constraint: u8) { + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_constraint_h(ConstraintH::from(constraint)); + }); +} + +#[no_mangle] +pub extern "C" fn set_shape_constraint_v(constraint: u8) { + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_constraint_v(ConstraintV::from(constraint)); + }); +} + +#[no_mangle] +pub extern "C" fn clear_shape_constraints() { + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.clear_constraints(); + }); +} + +#[no_mangle] +pub extern "C" fn set_shape_vertical_align(align: u8) { + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_vertical_align(VerticalAlign::from(align)); + }); +} + +#[no_mangle] +pub extern "C" fn clear_shape_layout() { + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.clear_layout(); + }); +} + +#[no_mangle] +pub extern "C" fn set_flex_layout_data( + dir: u8, + row_gap: f32, + column_gap: f32, + align_items: u8, + align_content: u8, + justify_items: u8, + justify_content: u8, + wrap_type: u8, + padding_top: f32, + padding_right: f32, + padding_bottom: f32, + padding_left: f32, +) { + let dir = shapes::FlexDirection::from_u8(dir); + let align_items = shapes::AlignItems::from_u8(align_items); + let align_content = shapes::AlignContent::from_u8(align_content); + let justify_items = shapes::JustifyItems::from_u8(justify_items); + let justify_content = shapes::JustifyContent::from_u8(justify_content); + let wrap_type = shapes::WrapType::from_u8(wrap_type); + + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_flex_layout_data( + dir, + row_gap, + column_gap, + align_items, + align_content, + justify_items, + justify_content, + wrap_type, + padding_top, + padding_right, + padding_bottom, + padding_left, + ); + }); +} + +#[no_mangle] +pub extern "C" fn set_layout_child_data( + margin_top: f32, + margin_right: f32, + margin_bottom: f32, + margin_left: f32, + h_sizing: u8, + v_sizing: u8, + has_max_h: bool, + max_h: f32, + has_min_h: bool, + min_h: f32, + has_max_w: bool, + max_w: f32, + has_min_w: bool, + min_w: f32, + has_align_self: bool, + align_self: u8, + is_absolute: bool, + z_index: i32, +) { + let h_sizing = shapes::Sizing::from_u8(h_sizing); + let v_sizing = shapes::Sizing::from_u8(v_sizing); + let max_h = if has_max_h { Some(max_h) } else { None }; + let min_h = if has_min_h { Some(min_h) } else { None }; + let max_w = if has_max_w { Some(max_w) } else { None }; + let min_w = if has_min_w { Some(min_w) } else { None }; + let align_self = if has_align_self { + shapes::AlignSelf::from_u8(align_self) + } else { + None + }; + + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_flex_layout_child_data( + margin_top, + margin_right, + margin_bottom, + margin_left, + h_sizing, + v_sizing, + max_h, + min_h, + max_w, + min_w, + align_self, + is_absolute, + z_index, + ); + }); +} + +#[no_mangle] +pub extern "C" fn set_grid_layout_data( + dir: u8, + row_gap: f32, + column_gap: f32, + align_items: u8, + align_content: u8, + justify_items: u8, + justify_content: u8, + padding_top: f32, + padding_right: f32, + padding_bottom: f32, + padding_left: f32, +) { + let dir = shapes::GridDirection::from_u8(dir); + let align_items = shapes::AlignItems::from_u8(align_items); + let align_content = shapes::AlignContent::from_u8(align_content); + let justify_items = shapes::JustifyItems::from_u8(justify_items); + let justify_content = shapes::JustifyContent::from_u8(justify_content); + + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_grid_layout_data( + dir, + row_gap, + column_gap, + align_items, + align_content, + justify_items, + justify_content, + padding_top, + padding_right, + padding_bottom, + padding_left, + ); + }); +} + +#[no_mangle] +pub extern "C" fn set_grid_columns() { + let bytes = mem::bytes(); + + let entries: Vec<_> = bytes + .chunks(size_of::()) + .map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap())) + .collect(); + + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_grid_columns(entries); + }); + + mem::free_bytes(); +} + +#[no_mangle] +pub extern "C" fn set_grid_rows() { + let bytes = mem::bytes(); + + let entries: Vec<_> = bytes + .chunks(size_of::()) + .map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap())) + .collect(); + + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_grid_rows(entries); + }); + + mem::free_bytes(); +} + +#[no_mangle] +pub extern "C" fn set_grid_cells() { + let bytes = mem::bytes(); + + let entries: Vec<_> = bytes + .chunks(size_of::()) + .map(|data| shapes::RawGridCell::from_bytes(data.try_into().unwrap())) + .collect(); + + with_current_shape_mut!(state, |shape: &mut Shape| { + shape.set_grid_cells(entries); + }); + + mem::free_bytes(); +} + +#[no_mangle] +pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) { + with_state_mut!(state, { + let id = uuid_from_u32_quartet(a, b, c, d); + state.render_state.show_grid = Some(id); + }); +} + +#[no_mangle] +pub extern "C" fn hide_grid() { + with_state_mut!(state, { + state.render_state.show_grid = None; + }); +} + +#[no_mangle] +pub extern "C" fn get_grid_coords(pos_x: f32, pos_y: f32) -> *mut u8 { + let row: i32; + let col: i32; + with_state!(state, { + if let Some((r, c)) = state.get_grid_coords(pos_x, pos_y) { + row = r; + col = c; + } else { + row = -1; + col = -1; + }; + }); + let mut bytes = vec![0; 8]; + bytes[0..4].clone_from_slice(&row.to_le_bytes()); + bytes[4..8].clone_from_slice(&col.to_le_bytes()); + mem::write_bytes(bytes) +}