mirror of
https://github.com/penpot/penpot.git
synced 2025-07-10 17:27:25 +02:00
✨ Add drop grid cells in wasm
This commit is contained in:
parent
52a4fc6030
commit
8dcb376b18
12 changed files with 215 additions and 119 deletions
|
@ -36,7 +36,9 @@
|
|||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.features :as features]
|
||||
[app.main.snap :as snap]
|
||||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.util.array :as array]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.keyboard :as kbd]
|
||||
|
@ -602,6 +604,15 @@
|
|||
(rx/take 1)
|
||||
(rx/map #(start-move from-position))))))
|
||||
|
||||
(defn get-drop-cell
|
||||
[target-frame objects position]
|
||||
(if (features/active-feature? @st/state "render-wasm/v1")
|
||||
(do
|
||||
(wasm.api/use-shape target-frame)
|
||||
(let [cell (wasm.api/get-grid-coords position)]
|
||||
(when (not= cell [-1 -1]) cell)))
|
||||
(gslg/get-drop-cell target-frame objects position)))
|
||||
|
||||
(defn set-ghost-displacement
|
||||
[move-vector]
|
||||
(ptk/reify ::set-ghost-displacement
|
||||
|
@ -621,7 +632,8 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
(let [prev-cell-data (volatile! nil)
|
||||
page-id (:current-page-id state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
selected (dsh/lookup-selected state {:omit-blocked? true})
|
||||
ids (if (nil? ids) selected ids)
|
||||
|
@ -685,7 +697,7 @@
|
|||
flex-layout? (ctl/flex-layout? objects target-frame)
|
||||
grid-layout? (ctl/grid-layout? objects target-frame)
|
||||
drop-index (when flex-layout? (gslf/get-drop-index target-frame objects position))
|
||||
cell-data (when (and grid-layout? (not mod?)) (gslg/get-drop-cell target-frame objects position))]
|
||||
cell-data (when (and grid-layout? (not mod?)) (get-drop-cell target-frame objects position))]
|
||||
(array move-vector target-frame drop-index cell-data))))
|
||||
|
||||
(rx/take-until stopper))
|
||||
|
@ -693,9 +705,15 @@
|
|||
modifiers-stream
|
||||
(->> move-stream
|
||||
(rx/with-latest-from array/conj ms/mouse-position-shift)
|
||||
(rx/tap
|
||||
(fn [[_ _ _ cell-data _]]
|
||||
(when (some? cell-data)
|
||||
(vreset! prev-cell-data cell-data))))
|
||||
|
||||
(rx/map
|
||||
(fn [[move-vector target-frame drop-index cell-data shift?]]
|
||||
(let [x-disp? (> (mth/abs (:x move-vector)) (mth/abs (:y move-vector)))
|
||||
(let [cell-data (or cell-data @prev-cell-data)
|
||||
x-disp? (> (mth/abs (:x move-vector)) (mth/abs (:y move-vector)))
|
||||
[move-vector snap-ignore-axis]
|
||||
(cond
|
||||
(and shift? x-disp?)
|
||||
|
|
|
@ -1045,6 +1045,18 @@
|
|||
(h/call wasm/internal-module "_hide_grid")
|
||||
(request-render "clear-grid"))
|
||||
|
||||
(defn get-grid-coords
|
||||
[position]
|
||||
(let [offset (h/call wasm/internal-module
|
||||
"_get_grid_coords"
|
||||
(get position :x)
|
||||
(get position :y))
|
||||
heapi32 (mem/get-heap-i32)
|
||||
row (aget heapi32 (mem/ptr8->ptr32 (+ offset 0)))
|
||||
column (aget heapi32 (mem/ptr8->ptr32 (+ offset 4)))]
|
||||
(h/call wasm/internal-module "_free_bytes")
|
||||
[row column]))
|
||||
|
||||
(defonce module
|
||||
(delay
|
||||
(if (exists? js/dynamicImport)
|
||||
|
|
|
@ -50,6 +50,11 @@
|
|||
[]
|
||||
(unchecked-get ^js wasm/internal-module "HEAPU32"))
|
||||
|
||||
(defn get-heap-i32
|
||||
"Returns a Uint32Array view of the heap"
|
||||
[]
|
||||
(unchecked-get ^js wasm/internal-module "HEAP32"))
|
||||
|
||||
(defn get-heap-f32
|
||||
"Returns a Float32Array view of the heap"
|
||||
[]
|
||||
|
|
|
@ -35,7 +35,7 @@ EMCC_CFLAGS="--no-entry \
|
|||
-sMAX_WEBGL_VERSION=2 \
|
||||
-sMODULARIZE=1 \
|
||||
-sEXPORT_NAME=createRustSkiaModule \
|
||||
-sEXPORTED_RUNTIME_METHODS=GL,stringToUTF8,HEAPU8,HEAPU32,HEAPF32 \
|
||||
-sEXPORTED_RUNTIME_METHODS=GL,stringToUTF8,HEAPU8,HEAP32,HEAPU32,HEAPF32 \
|
||||
-sEXPORT_ES6=1"
|
||||
|
||||
export EM_CACHE="/tmp/emsdk_cache";
|
||||
|
|
|
@ -748,6 +748,19 @@ pub extern "C" fn hide_grid() {
|
|||
});
|
||||
}
|
||||
|
||||
#[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, {
|
||||
(row, col) = state.get_grid_coords(pos_x, pos_y);
|
||||
});
|
||||
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!();
|
||||
|
|
|
@ -21,7 +21,7 @@ use options::RenderOptions;
|
|||
use surfaces::{SurfaceId, Surfaces};
|
||||
|
||||
use crate::performance;
|
||||
use crate::shapes::{modified_children_ids, Corners, Fill, Shape, StructureEntry, Type};
|
||||
use crate::shapes::{Corners, Fill, Shape, StructureEntry, Type};
|
||||
use crate::tiles::{self, PendingTiles, TileRect};
|
||||
use crate::uuid::Uuid;
|
||||
use crate::view::Viewbox;
|
||||
|
@ -929,7 +929,7 @@ impl RenderState {
|
|||
node_render_state.get_children_clip_bounds(element, modifiers.get(&element.id));
|
||||
|
||||
let mut children_ids =
|
||||
modified_children_ids(element, structure.get(&element.id), false);
|
||||
element.modified_children_ids(structure.get(&element.id), false);
|
||||
|
||||
// Z-index ordering on Layouts
|
||||
if element.has_layout() {
|
||||
|
@ -1019,7 +1019,7 @@ impl RenderState {
|
|||
let Some(root) = tree.get(&Uuid::nil()) else {
|
||||
return Err(String::from("Root shape not found"));
|
||||
};
|
||||
let root_ids = modified_children_ids(root, structure.get(&root.id), false);
|
||||
let root_ids = root.modified_children_ids(structure.get(&root.id), false);
|
||||
|
||||
// If we finish processing every node rendering is complete
|
||||
// let's check if there are more pending nodes
|
||||
|
@ -1118,7 +1118,7 @@ impl RenderState {
|
|||
self.update_tile_for(&shape);
|
||||
} else {
|
||||
// We only need to rebuild tiles from the first level.
|
||||
let children = modified_children_ids(&shape, structure.get(&shape.id), false);
|
||||
let children = shape.modified_children_ids(structure.get(&shape.id), false);
|
||||
for child_id in children.iter() {
|
||||
nodes.push(*child_id);
|
||||
}
|
||||
|
@ -1148,7 +1148,7 @@ impl RenderState {
|
|||
self.update_tile_for(&shape);
|
||||
}
|
||||
|
||||
let children = modified_children_ids(&shape, structure.get(&shape.id), false);
|
||||
let children = shape.modified_children_ids(structure.get(&shape.id), false);
|
||||
for child_id in children.iter() {
|
||||
nodes.push(*child_id);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use skia_safe::{self as skia};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::shapes::modifiers::common::GetBounds;
|
||||
|
||||
use crate::math::{Bounds, Matrix, Rect};
|
||||
use crate::shapes::modifiers::grid_layout::{calculate_tracks, create_cell_data};
|
||||
use crate::shapes::{modified_children_ids, Frame, Layout, Shape, StructureEntry, Type};
|
||||
use crate::math::{Matrix, Rect};
|
||||
use crate::shapes::modifiers::grid_layout::grid_cell_data;
|
||||
use crate::shapes::{Shape, StructureEntry};
|
||||
use crate::uuid::Uuid;
|
||||
|
||||
pub fn render_overlay(
|
||||
|
@ -16,67 +14,7 @@ pub fn render_overlay(
|
|||
modifiers: &HashMap<Uuid, Matrix>,
|
||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||
) {
|
||||
let Type::Frame(Frame {
|
||||
layout: Some(Layout::GridLayout(layout_data, grid_data)),
|
||||
..
|
||||
}) = &shape.shape_type
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bounds = &mut HashMap::<Uuid, Bounds>::new();
|
||||
|
||||
let shape = &mut shape.clone();
|
||||
if let Some(modifiers) = modifiers.get(&shape.id) {
|
||||
shape.apply_transform(modifiers);
|
||||
}
|
||||
|
||||
let layout_bounds = shape.bounds();
|
||||
let children = modified_children_ids(shape, structure.get(&shape.id), false);
|
||||
|
||||
for child_id in children.iter() {
|
||||
let Some(child) = shapes.get(child_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(modifier) = modifiers.get(child_id) {
|
||||
let mut b = bounds.find(child);
|
||||
b.transform_mut(modifier);
|
||||
bounds.insert(*child_id, b);
|
||||
}
|
||||
}
|
||||
|
||||
let column_tracks = calculate_tracks(
|
||||
true,
|
||||
shape,
|
||||
layout_data,
|
||||
grid_data,
|
||||
&layout_bounds,
|
||||
&grid_data.cells,
|
||||
shapes,
|
||||
bounds,
|
||||
);
|
||||
|
||||
let row_tracks = calculate_tracks(
|
||||
false,
|
||||
shape,
|
||||
layout_data,
|
||||
grid_data,
|
||||
&layout_bounds,
|
||||
&grid_data.cells,
|
||||
shapes,
|
||||
bounds,
|
||||
);
|
||||
|
||||
let cells = create_cell_data(
|
||||
&layout_bounds,
|
||||
&children,
|
||||
shapes,
|
||||
&grid_data.cells,
|
||||
&column_tracks,
|
||||
&row_tracks,
|
||||
true,
|
||||
);
|
||||
let cells = grid_cell_data(shape.clone(), shapes, modifiers, structure, true);
|
||||
|
||||
let mut paint = skia::Paint::default();
|
||||
paint.set_style(skia::PaintStyle::Stroke);
|
||||
|
|
|
@ -967,19 +967,18 @@ impl Shape {
|
|||
pub fn has_inner_strokes(&self) -> bool {
|
||||
self.strokes.iter().any(|s| s.kind == StrokeKind::Inner)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
Returns the list of children taking into account the structure modifiers
|
||||
*/
|
||||
pub fn modified_children_ids(
|
||||
element: &Shape,
|
||||
*/
|
||||
pub fn modified_children_ids(
|
||||
&self,
|
||||
structure: Option<&Vec<StructureEntry>>,
|
||||
include_hidden: bool,
|
||||
) -> IndexSet<Uuid> {
|
||||
) -> IndexSet<Uuid> {
|
||||
if let Some(structure) = structure {
|
||||
let mut result: Vec<Uuid> =
|
||||
Vec::from_iter(element.children_ids(include_hidden).iter().copied());
|
||||
Vec::from_iter(self.children_ids(include_hidden).iter().copied());
|
||||
let mut to_remove = HashSet::<&Uuid>::new();
|
||||
|
||||
for st in structure {
|
||||
|
@ -1002,7 +1001,8 @@ pub fn modified_children_ids(
|
|||
|
||||
ret
|
||||
} else {
|
||||
element.children_ids(include_hidden)
|
||||
self.children_ids(include_hidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ use common::GetBounds;
|
|||
|
||||
use crate::math::{self as math, identitish, Bounds, Matrix, Point};
|
||||
use crate::shapes::{
|
||||
auto_height, modified_children_ids, set_paragraphs_width, ConstraintH, ConstraintV, Frame,
|
||||
Group, GrowType, Layout, Modifier, Shape, StructureEntry, TransformEntry, Type,
|
||||
auto_height, set_paragraphs_width, ConstraintH, ConstraintV, Frame, Group, GrowType, Layout,
|
||||
Modifier, Shape, StructureEntry, TransformEntry, Type,
|
||||
};
|
||||
use crate::state::State;
|
||||
use crate::uuid::Uuid;
|
||||
|
@ -25,7 +25,7 @@ fn propagate_children(
|
|||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||
scale_content: &HashMap<Uuid, f32>,
|
||||
) -> VecDeque<Modifier> {
|
||||
let children_ids = modified_children_ids(shape, structure.get(&shape.id), true);
|
||||
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true);
|
||||
|
||||
if children_ids.is_empty() || identitish(transform) {
|
||||
return VecDeque::new();
|
||||
|
@ -95,7 +95,7 @@ fn calculate_group_bounds(
|
|||
let shape_bounds = bounds.find(shape);
|
||||
let mut result = Vec::<Point>::new();
|
||||
|
||||
let children_ids = modified_children_ids(shape, structure.get(&shape.id), true);
|
||||
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true);
|
||||
for child_id in children_ids.iter() {
|
||||
let Some(child) = shapes.get(child_id) else {
|
||||
continue;
|
||||
|
@ -263,7 +263,7 @@ fn propagate_reflow(
|
|||
}
|
||||
}
|
||||
Type::Group(Group { masked: true }) => {
|
||||
let children_ids = modified_children_ids(shape, state.structure.get(&shape.id), true);
|
||||
let children_ids = shape.modified_children_ids(state.structure.get(&shape.id), true);
|
||||
if let Some(child) = shapes.get(&children_ids[0]) {
|
||||
let child_bounds = bounds.find(child);
|
||||
bounds.insert(shape.id, child_bounds);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#![allow(dead_code)]
|
||||
use crate::math::{self as math, Bounds, Matrix, Point, Vector, VectorExt};
|
||||
use crate::shapes::{
|
||||
modified_children_ids, AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent,
|
||||
LayoutData, LayoutItem, Modifier, Shape, StructureEntry,
|
||||
AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent, LayoutData, LayoutItem,
|
||||
Modifier, Shape, StructureEntry,
|
||||
};
|
||||
use crate::uuid::Uuid;
|
||||
|
||||
|
@ -184,7 +184,7 @@ fn initialize_tracks(
|
|||
) -> Vec<TrackData> {
|
||||
let mut tracks = Vec::<TrackData>::new();
|
||||
let mut current_track = TrackData::default();
|
||||
let mut children = modified_children_ids(shape, structure.get(&shape.id), true);
|
||||
let mut children = shape.modified_children_ids(structure.get(&shape.id), true);
|
||||
let mut first = true;
|
||||
|
||||
if flex_data.is_reverse() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::math::{self as math, intersect_rays, Bounds, Matrix, Point, Ray, Vector, VectorExt};
|
||||
use crate::shapes::{
|
||||
modified_children_ids, AlignContent, AlignItems, AlignSelf, GridCell, GridData, GridTrack,
|
||||
GridTrackType, JustifyContent, JustifyItems, JustifySelf, LayoutData, LayoutItem, Modifier,
|
||||
Shape, StructureEntry,
|
||||
AlignContent, AlignItems, AlignSelf, Frame, GridCell, GridData, GridTrack, GridTrackType,
|
||||
JustifyContent, JustifyItems, JustifySelf, Layout, LayoutData, LayoutItem, Modifier, Shape,
|
||||
StructureEntry, Type,
|
||||
};
|
||||
use crate::uuid::Uuid;
|
||||
use indexmap::IndexSet;
|
||||
|
@ -21,6 +21,8 @@ pub struct CellData<'a> {
|
|||
pub height: f32,
|
||||
pub align_self: Option<AlignSelf>,
|
||||
pub justify_self: Option<JustifySelf>,
|
||||
pub row: usize,
|
||||
pub column: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -590,12 +592,84 @@ pub fn create_cell_data<'a>(
|
|||
height: cell_bounds.height(),
|
||||
align_self: cell.align_self,
|
||||
justify_self: cell.justify_self,
|
||||
row: row_start,
|
||||
column: column_start,
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn grid_cell_data<'a>(
|
||||
shape: Shape,
|
||||
shapes: &'a HashMap<Uuid, &mut Shape>,
|
||||
modifiers: &HashMap<Uuid, Matrix>,
|
||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||
allow_empty: bool,
|
||||
) -> Vec<CellData<'a>> {
|
||||
let Type::Frame(Frame {
|
||||
layout: Some(Layout::GridLayout(layout_data, grid_data)),
|
||||
..
|
||||
}) = &shape.shape_type
|
||||
else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let bounds = &mut HashMap::<Uuid, Bounds>::new();
|
||||
|
||||
let shape = &mut shape.clone();
|
||||
if let Some(modifiers) = modifiers.get(&shape.id) {
|
||||
shape.apply_transform(modifiers);
|
||||
}
|
||||
|
||||
let layout_bounds = shape.bounds();
|
||||
let children = shape.modified_children_ids(structure.get(&shape.id), false);
|
||||
|
||||
for child_id in children.iter() {
|
||||
let Some(child) = shapes.get(child_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(modifier) = modifiers.get(child_id) {
|
||||
let mut b = bounds.find(child);
|
||||
b.transform_mut(modifier);
|
||||
bounds.insert(*child_id, b);
|
||||
}
|
||||
}
|
||||
|
||||
let column_tracks = calculate_tracks(
|
||||
true,
|
||||
shape,
|
||||
layout_data,
|
||||
grid_data,
|
||||
&layout_bounds,
|
||||
&grid_data.cells,
|
||||
shapes,
|
||||
bounds,
|
||||
);
|
||||
|
||||
let row_tracks = calculate_tracks(
|
||||
false,
|
||||
shape,
|
||||
layout_data,
|
||||
grid_data,
|
||||
&layout_bounds,
|
||||
&grid_data.cells,
|
||||
shapes,
|
||||
bounds,
|
||||
);
|
||||
|
||||
create_cell_data(
|
||||
&layout_bounds,
|
||||
&children,
|
||||
shapes,
|
||||
&grid_data.cells,
|
||||
&column_tracks,
|
||||
&row_tracks,
|
||||
allow_empty,
|
||||
)
|
||||
}
|
||||
|
||||
fn child_position(
|
||||
child: &Shape,
|
||||
layout_bounds: &Bounds,
|
||||
|
@ -655,7 +729,7 @@ pub fn reflow_grid_layout(
|
|||
) -> VecDeque<Modifier> {
|
||||
let mut result = VecDeque::new();
|
||||
let layout_bounds = bounds.find(shape);
|
||||
let children = modified_children_ids(shape, structure.get(&shape.id), true);
|
||||
let children = shape.modified_children_ids(structure.get(&shape.id), true);
|
||||
|
||||
let column_tracks = calculate_tracks(
|
||||
true,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::{hash_map::Entry, HashMap};
|
||||
use std::{iter, vec};
|
||||
|
||||
use skia_safe as skia;
|
||||
use skia_safe::{self as skia, Path, Point};
|
||||
|
||||
use crate::performance;
|
||||
use crate::render::RenderState;
|
||||
|
@ -10,6 +10,8 @@ use crate::shapes::StructureEntry;
|
|||
use crate::tiles;
|
||||
use crate::uuid::Uuid;
|
||||
|
||||
use crate::shapes::modifiers::grid_layout::grid_cell_data;
|
||||
|
||||
const SHAPES_POOL_ALLOC_MULTIPLIER: f32 = 1.3;
|
||||
|
||||
/// A pool allocator for `Shape` objects that attempts to minimize memory reallocations.
|
||||
|
@ -224,4 +226,38 @@ impl<'a> State<'a> {
|
|||
self.render_state
|
||||
.rebuild_modifier_tiles(&mut self.shapes, &self.modifiers);
|
||||
}
|
||||
|
||||
pub fn get_grid_coords(&mut self, pos_x: f32, pos_y: f32) -> (i32, i32) {
|
||||
let Some(shape) = self.current_shape() else {
|
||||
return (-1, -1);
|
||||
};
|
||||
|
||||
let bounds = shape.bounds();
|
||||
let position = Point::new(pos_x, pos_y);
|
||||
|
||||
let cells = grid_cell_data(
|
||||
shape.clone(),
|
||||
&self.shapes,
|
||||
&self.modifiers,
|
||||
&self.structure,
|
||||
true,
|
||||
);
|
||||
|
||||
for cell in cells {
|
||||
let points = &[
|
||||
cell.anchor,
|
||||
cell.anchor + bounds.hv(cell.width),
|
||||
cell.anchor + bounds.hv(cell.width) + bounds.vv(cell.height),
|
||||
cell.anchor + bounds.vv(cell.height),
|
||||
];
|
||||
|
||||
let polygon = Path::polygon(points, true, None, None);
|
||||
|
||||
if polygon.contains(position) {
|
||||
return (cell.row as i32 + 1, cell.column as i32 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
(-1, -1)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue