mirror of
https://github.com/penpot/penpot.git
synced 2025-06-01 20:21:39 +02:00
✨ Set selrect for new render modifiers
This commit is contained in:
parent
6831acb71d
commit
fef08dfa18
13 changed files with 200 additions and 72 deletions
|
@ -195,6 +195,7 @@
|
|||
|
||||
;; Rect
|
||||
(dm/export grc/rect->points)
|
||||
(dm/export grc/center->rect)
|
||||
|
||||
;;
|
||||
(dm/export gsff/fit-frame-modifiers)
|
||||
|
|
|
@ -504,6 +504,13 @@
|
|||
(filter (fn [[_ {:keys [type]}]]
|
||||
(= type :change-property)))))
|
||||
|
||||
(defn set-temporary-selrect
|
||||
[selrect]
|
||||
(ptk/reify ::set-temporary-selrect
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :workspace-selrect selrect))))
|
||||
|
||||
#_:clj-kondo/ignore
|
||||
(defn set-wasm-modifiers
|
||||
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel]
|
||||
|
@ -519,8 +526,8 @@
|
|||
(assoc :prev-wasm-props (:wasm-props state))
|
||||
(assoc :wasm-props property-changes))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(wasm.api/clean-modifiers)
|
||||
|
||||
(let [prev-wasm-props (:prev-wasm-props state)
|
||||
|
@ -531,8 +538,9 @@
|
|||
|
||||
(let [structure-entries (parse-structure-modifiers modif-tree)]
|
||||
(wasm.api/set-structure-modifiers structure-entries)
|
||||
(let [geometry-entries (parse-geometry-modifiers modif-tree)]
|
||||
(wasm.api/propagate-apply geometry-entries)))))))
|
||||
(let [geometry-entries (parse-geometry-modifiers modif-tree)
|
||||
selrect (wasm.api/propagate-apply geometry-entries)]
|
||||
(rx/of (set-temporary-selrect selrect))))))))
|
||||
|
||||
#_:clj-kondo/ignore
|
||||
(defn apply-wasm-modifiers
|
||||
|
@ -567,14 +575,6 @@
|
|||
(clear-local-transform)
|
||||
(dwsh/update-shapes ids update-shape))))))
|
||||
|
||||
|
||||
(defn set-selrect-transform
|
||||
[modifiers]
|
||||
(ptk/reify ::set-selrect-transform
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :workspace-selrect-transform (ctm/modifiers->transform modifiers)))))
|
||||
|
||||
(def ^:private
|
||||
xf-rotation-shape
|
||||
(comp
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
[app.main.data.workspace.modifiers :as dwm]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.features :as features]
|
||||
[app.main.fonts :as fonts]
|
||||
|
@ -945,14 +946,17 @@
|
|||
new-shape))
|
||||
{:undo-group (when new-shape? id)})
|
||||
|
||||
(if finalize?
|
||||
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
||||
(dwm/apply-wasm-modifiers
|
||||
(resize-wasm-text-modifiers shape content)
|
||||
{:undo-group (when new-shape? id)})
|
||||
|
||||
(dwm/set-wasm-modifiers
|
||||
(resize-wasm-text-modifiers shape content)
|
||||
{:undo-group (when new-shape? id)}))))
|
||||
{:undo-group (when new-shape? id)}))
|
||||
|
||||
(when finalize?
|
||||
(dwt/finish-transform))))
|
||||
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-local dissoc :transform :duplicate-move-started?)
|
||||
(dissoc :workspace-selrect-transform)))))
|
||||
(dissoc :workspace-selrect)))))
|
||||
|
||||
;; -- Resize --------------------------------------------------------
|
||||
|
||||
|
@ -296,7 +296,6 @@
|
|||
(fn [modifiers]
|
||||
(let [modif-tree (dwm/create-modif-tree ids modifiers)]
|
||||
(rx/of
|
||||
(dwm/set-selrect-transform modifiers)
|
||||
(dwm/set-wasm-modifiers
|
||||
modif-tree
|
||||
:ignore-constraints (contains? layout :scale-text))))))
|
||||
|
|
|
@ -147,9 +147,6 @@
|
|||
(def workspace-drawing
|
||||
(l/derived :workspace-drawing st/state))
|
||||
|
||||
(def workspace-selrect-transform
|
||||
(l/derived :workspace-selrect-transform st/state))
|
||||
|
||||
(def workspace-tokens
|
||||
"All tokens related ephimeral state"
|
||||
(l/derived :workspace-tokens st/state))
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
[{:keys [shape zoom modifiers]}]
|
||||
(if (features/active-feature? @st/state "render-wasm/v1")
|
||||
(let [transform (gsh/transform-str shape)
|
||||
{:keys [id x y]} shape
|
||||
{:keys [width height]} (wasm.api/text-dimensions id)]
|
||||
{:keys [id x y grow-type]} shape
|
||||
{:keys [width height]} (if (= :fixed grow-type) shape (wasm.api/text-dimensions id))]
|
||||
[:rect.main.viewport-selrect
|
||||
{:x x
|
||||
:y y
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
[app.config :as cf]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.features :as features]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.css-cursors :as cur]
|
||||
[app.main.ui.hooks :as h]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as global]
|
||||
[app.util.keyboard :as kbd]
|
||||
|
@ -34,6 +38,20 @@
|
|||
result (.-textContent editor-root)]
|
||||
(when (not= result "") result))))
|
||||
|
||||
(defn- get-fonts
|
||||
[content]
|
||||
(let [extract-fn (juxt :font-id :font-variant-id)
|
||||
default (extract-fn txt/default-text-attrs)]
|
||||
(->> (tree-seq map? :children content)
|
||||
(into #{default} (keep extract-fn)))))
|
||||
|
||||
(defn- load-fonts!
|
||||
[fonts]
|
||||
(->> fonts
|
||||
(run! (fn [[font-id variant-id]]
|
||||
(when (some? font-id)
|
||||
(fonts/ensure-loaded! font-id variant-id))))))
|
||||
|
||||
(defn- initialize-event-handlers
|
||||
"Internal editor events handler initializer/destructor"
|
||||
[shape-id content selection-ref editor-ref container-ref]
|
||||
|
@ -137,7 +155,14 @@
|
|||
|
||||
;; This reference is to the container
|
||||
container-ref (mf/use-ref nil)
|
||||
selection-ref (mf/use-ref nil)]
|
||||
selection-ref (mf/use-ref nil)
|
||||
|
||||
fonts
|
||||
(-> (mf/use-memo (mf/deps content) #(get-fonts content))
|
||||
(h/use-equal-memo))]
|
||||
|
||||
(mf/with-effect [fonts]
|
||||
(load-fonts! fonts))
|
||||
|
||||
;; WARN: we explicitly do not pass content on effect dependency
|
||||
;; array because we only need to initialize this once with initial
|
||||
|
@ -235,16 +260,24 @@
|
|||
(some? modifiers)
|
||||
(gsh/transform-shape modifiers))
|
||||
|
||||
bounds (gst/shape->rect shape)
|
||||
[x y width height]
|
||||
(if (features/active-feature? @st/state "render-wasm/v1")
|
||||
(let [{:keys [width height]} (wasm.api/text-dimensions shape-id)
|
||||
{:keys [x y]} (:selrect shape)]
|
||||
|
||||
[x y width height])
|
||||
|
||||
(let [bounds (gst/shape->rect shape)
|
||||
x (mth/min (dm/get-prop bounds :x)
|
||||
(dm/get-prop shape :x))
|
||||
y (mth/min (dm/get-prop bounds :y)
|
||||
(dm/get-prop shape :y))
|
||||
width (mth/max (dm/get-prop bounds :width)
|
||||
(dm/get-prop shape :width))
|
||||
height (mth/max (dm/get-prop bounds :height)
|
||||
(dm/get-prop shape :height))]
|
||||
[x y width height]))
|
||||
|
||||
x (mth/min (dm/get-prop bounds :x)
|
||||
(dm/get-prop shape :x))
|
||||
y (mth/min (dm/get-prop bounds :y)
|
||||
(dm/get-prop shape :y))
|
||||
width (mth/max (dm/get-prop bounds :width)
|
||||
(dm/get-prop shape :width))
|
||||
height (mth/max (dm/get-prop bounds :height)
|
||||
(dm/get-prop shape :height))
|
||||
style
|
||||
(cond-> #js {:pointerEvents "all"}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
[app.util.debug :as dbg]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.object :as obj]
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def rotation-handler-size 20)
|
||||
|
@ -313,17 +314,23 @@
|
|||
:style {:fill (if (dbg/enabled? :handlers) "yellow" "none")
|
||||
:stroke-width 0}}]]))
|
||||
|
||||
(def workspace-selrect-transform
|
||||
(l/derived :workspace-selrect st/state))
|
||||
|
||||
(defn get-selrect
|
||||
[selrect-transform shape]
|
||||
(if (some? selrect-transform)
|
||||
(let [{:keys [center width height transform]} selrect-transform]
|
||||
[(gsh/center->rect center width height)
|
||||
(gmt/transform-in center transform)])
|
||||
[(dm/get-prop shape :selrect)
|
||||
(gsh/transform-matrix shape)]))
|
||||
|
||||
(mf/defc controls-selection*
|
||||
[{:keys [shape zoom color on-move-selected on-context-menu disabled]}]
|
||||
(let [selrect (dm/get-prop shape :selrect)
|
||||
transform-type (mf/deref refs/current-transform)
|
||||
sr-transform (mf/deref refs/workspace-selrect-transform)
|
||||
|
||||
transform
|
||||
(dm/str
|
||||
(cond->> (gsh/transform-matrix shape)
|
||||
(some? sr-transform)
|
||||
(gmt/multiply sr-transform)))]
|
||||
(let [selrect-transform (mf/deref workspace-selrect-transform)
|
||||
transform-type (mf/deref refs/current-transform)
|
||||
[selrect transform] (get-selrect selrect-transform shape)]
|
||||
|
||||
(when (and (some? selrect)
|
||||
(not (or (= transform-type :move)
|
||||
|
@ -340,19 +347,15 @@
|
|||
(mf/defc controls-handlers*
|
||||
{::mf/private true}
|
||||
[{:keys [shape zoom color on-resize on-rotate disabled]}]
|
||||
(let [transform-type (mf/deref refs/current-transform)
|
||||
sr-transform (mf/deref refs/workspace-selrect-transform)
|
||||
(let [selrect-transform (mf/deref workspace-selrect-transform)
|
||||
transform-type (mf/deref refs/current-transform)
|
||||
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
|
||||
layout (mf/deref refs/workspace-layout)
|
||||
scale-text? (contains? layout :scale-text)
|
||||
|
||||
selrect (dm/get-prop shape :selrect)
|
||||
|
||||
transform (cond->> (gsh/transform-matrix shape)
|
||||
(some? sr-transform)
|
||||
(gmt/multiply sr-transform))
|
||||
[selrect transform] (get-selrect selrect-transform shape)
|
||||
|
||||
rotation (-> (gpt/point 1 0)
|
||||
(gpt/transform (:transform shape))
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
["react-dom/server" :as rds]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.uuid :as uuid]
|
||||
|
@ -808,8 +810,29 @@
|
|||
(sr/heapu32-set-uuid id heapu32 current-offset)
|
||||
(sr/heapf32-set-matrix transform heapf32 (+ current-offset (mem/ptr8->ptr32 MODIFIER-ENTRY-TRANSFORM-OFFSET)))
|
||||
(recur (rest entries) (+ current-offset (mem/ptr8->ptr32 MODIFIER-ENTRY-SIZE))))))
|
||||
(h/call wasm/internal-module "_propagate_apply")
|
||||
(request-render "set-modifiers"))))
|
||||
|
||||
(let [offset (h/call wasm/internal-module "_propagate_apply")
|
||||
heapf32 (mem/get-heap-f32)
|
||||
width (aget heapf32 (mem/ptr8->ptr32 (+ offset 0)))
|
||||
height (aget heapf32 (mem/ptr8->ptr32 (+ offset 4)))
|
||||
cx (aget heapf32 (mem/ptr8->ptr32 (+ offset 8)))
|
||||
cy (aget heapf32 (mem/ptr8->ptr32 (+ offset 12)))
|
||||
|
||||
a (aget heapf32 (mem/ptr8->ptr32 (+ offset 16)))
|
||||
b (aget heapf32 (mem/ptr8->ptr32 (+ offset 20)))
|
||||
c (aget heapf32 (mem/ptr8->ptr32 (+ offset 24)))
|
||||
d (aget heapf32 (mem/ptr8->ptr32 (+ offset 28)))
|
||||
e (aget heapf32 (mem/ptr8->ptr32 (+ offset 32)))
|
||||
f (aget heapf32 (mem/ptr8->ptr32 (+ offset 36)))
|
||||
transform (gmt/matrix a b c d e f)]
|
||||
|
||||
(h/call wasm/internal-module "_free_bytes")
|
||||
(request-render "set-modifiers")
|
||||
|
||||
{:width width
|
||||
:height height
|
||||
:center (gpt/point cx cy)
|
||||
:transform transform}))))
|
||||
|
||||
(defn set-canvas-background
|
||||
[background]
|
||||
|
|
|
@ -20,6 +20,7 @@ use crate::shapes::{BoolType, ConstraintH, ConstraintV, StructureEntry, Transfor
|
|||
use crate::utils::uuid_from_u32_quartet;
|
||||
use crate::uuid::Uuid;
|
||||
use indexmap::IndexSet;
|
||||
use math::{Bounds, Matrix};
|
||||
use state::State;
|
||||
|
||||
pub(crate) static mut STATE: Option<Box<State>> = None;
|
||||
|
@ -397,13 +398,13 @@ pub extern "C" fn propagate_modifiers() -> *mut u8 {
|
|||
.collect();
|
||||
|
||||
with_state!(state, {
|
||||
let result = shapes::propagate_modifiers(state, entries);
|
||||
let (result, _) = shapes::propagate_modifiers(state, &entries);
|
||||
mem::write_vec(result)
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn propagate_apply() {
|
||||
pub extern "C" fn propagate_apply() -> *mut u8 {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let entries: Vec<_> = bytes
|
||||
|
@ -412,15 +413,42 @@ pub extern "C" fn propagate_apply() {
|
|||
.collect();
|
||||
|
||||
with_state!(state, {
|
||||
let result = shapes::propagate_modifiers(state, entries);
|
||||
let (result, bounds) = shapes::propagate_modifiers(state, &entries);
|
||||
|
||||
for entry in result {
|
||||
state.modifiers.insert(entry.id, entry.transform);
|
||||
}
|
||||
state.rebuild_modifier_tiles();
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
mem::free_bytes();
|
||||
|
||||
let bbs: Vec<_> = entries.iter().flat_map(|e| bounds.get(&e.id)).collect();
|
||||
|
||||
let result_bound = if bbs.len() == 1 {
|
||||
bbs[0]
|
||||
} else {
|
||||
&Bounds::join_bounds(&bbs)
|
||||
};
|
||||
|
||||
let width = result_bound.width();
|
||||
let height = result_bound.height();
|
||||
let center = result_bound.center();
|
||||
let transform = result_bound.transform_matrix().unwrap_or(Matrix::default());
|
||||
|
||||
let mut bytes = Vec::<u8>::with_capacity(40);
|
||||
bytes.resize(40, 0);
|
||||
bytes[0..4].clone_from_slice(&width.to_le_bytes());
|
||||
bytes[4..8].clone_from_slice(&height.to_le_bytes());
|
||||
bytes[8..12].clone_from_slice(¢er.x.to_le_bytes());
|
||||
bytes[12..16].clone_from_slice(¢er.y.to_le_bytes());
|
||||
bytes[16..20].clone_from_slice(&transform[0].to_le_bytes());
|
||||
bytes[20..24].clone_from_slice(&transform[3].to_le_bytes());
|
||||
bytes[24..28].clone_from_slice(&transform[1].to_le_bytes());
|
||||
bytes[28..32].clone_from_slice(&transform[4].to_le_bytes());
|
||||
bytes[32..36].clone_from_slice(&transform[2].to_le_bytes());
|
||||
bytes[36..40].clone_from_slice(&transform[5].to_le_bytes());
|
||||
return mem::write_bytes(bytes);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
@ -64,6 +64,29 @@ impl Bounds {
|
|||
Self { nw, ne, se, sw }
|
||||
}
|
||||
|
||||
pub fn join_bounds(bounds: &Vec<&Bounds>) -> Self {
|
||||
let (min_x, min_y, max_x, max_y) =
|
||||
bounds
|
||||
.iter()
|
||||
.fold((f32::MAX, f32::MAX, f32::MIN, f32::MIN), {
|
||||
|(min_x, min_y, max_x, max_y), bound| {
|
||||
(
|
||||
f32::min(bound.min_x(), min_x),
|
||||
f32::min(bound.min_y(), min_y),
|
||||
f32::max(bound.max_x(), max_x),
|
||||
f32::max(bound.max_y(), max_y),
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
Self::new(
|
||||
Point::new(min_x, min_y),
|
||||
Point::new(max_x, min_y),
|
||||
Point::new(max_x, max_y),
|
||||
Point::new(min_x, max_y),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn horizontal_vec(&self) -> Vector {
|
||||
Vector::new_points(&self.nw, &self.ne)
|
||||
}
|
||||
|
@ -249,7 +272,10 @@ impl Bounds {
|
|||
|
||||
pub fn center(&self) -> Point {
|
||||
// Calculates the centroid of the four points
|
||||
Point::new(self.nw.x + self.se.x / 2.0, self.nw.y + self.se.y / 2.0)
|
||||
Point::new(
|
||||
self.nw.x + (self.se.x - self.nw.x) / 2.0,
|
||||
self.nw.y + (self.se.y - self.nw.y) / 2.0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn transform_matrix(&self) -> Option<Matrix> {
|
||||
|
@ -297,11 +323,23 @@ impl Bounds {
|
|||
}
|
||||
|
||||
pub fn to_rect(&self) -> Rect {
|
||||
let minx = self.nw.x.min(self.ne.x).min(self.sw.x).min(self.se.x);
|
||||
let miny = self.nw.y.min(self.ne.y).min(self.sw.y).min(self.se.y);
|
||||
let maxx = self.nw.x.max(self.ne.x).max(self.sw.x).max(self.se.x);
|
||||
let maxy = self.nw.y.max(self.ne.y).max(self.sw.y).max(self.se.y);
|
||||
Rect::from_ltrb(minx, miny, maxx, maxy)
|
||||
Rect::from_ltrb(self.min_x(), self.min_y(), self.max_x(), self.max_y())
|
||||
}
|
||||
|
||||
pub fn min_x(&self) -> f32 {
|
||||
self.nw.x.min(self.ne.x).min(self.sw.x).min(self.se.x)
|
||||
}
|
||||
|
||||
pub fn min_y(&self) -> f32 {
|
||||
self.nw.y.min(self.ne.y).min(self.sw.y).min(self.se.y)
|
||||
}
|
||||
|
||||
pub fn max_x(&self) -> f32 {
|
||||
self.nw.x.max(self.ne.x).max(self.sw.x).max(self.se.x)
|
||||
}
|
||||
|
||||
pub fn max_y(&self) -> f32 {
|
||||
self.nw.y.max(self.ne.y).max(self.sw.y).max(self.se.y)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,10 @@ fn calculate_group_bounds(
|
|||
shape_bounds.from_points(result)
|
||||
}
|
||||
|
||||
pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec<TransformEntry> {
|
||||
pub fn propagate_modifiers(
|
||||
state: &State,
|
||||
modifiers: &Vec<TransformEntry>,
|
||||
) -> (Vec<TransformEntry>, HashMap<Uuid, Bounds>) {
|
||||
let shapes = &state.shapes;
|
||||
|
||||
let font_col = state.render_state.fonts.font_collection();
|
||||
|
@ -306,10 +309,13 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
|
|||
layout_reflows = Vec::new();
|
||||
}
|
||||
|
||||
modifiers
|
||||
.iter()
|
||||
.map(|(key, val)| TransformEntry::new(*key, *val))
|
||||
.collect()
|
||||
(
|
||||
modifiers
|
||||
.iter()
|
||||
.map(|(key, val)| TransformEntry::new(*key, *val))
|
||||
.collect(),
|
||||
bounds,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -47,15 +47,11 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 {
|
|||
height = shape.selrect.height();
|
||||
|
||||
if let Type::Text(content) = &shape.shape_type {
|
||||
let paragraphs = content.get_skia_paragraphs(font_col);
|
||||
height = auto_height(¶graphs).ceil();
|
||||
match content.grow_type() {
|
||||
GrowType::AutoWidth => {
|
||||
let paragraphs = content.get_skia_paragraphs(font_col);
|
||||
width = auto_width(¶graphs);
|
||||
height = auto_height(¶graphs);
|
||||
}
|
||||
GrowType::AutoHeight => {
|
||||
let paragraphs = content.get_skia_paragraphs(font_col);
|
||||
height = auto_height(¶graphs);
|
||||
width = auto_width(¶graphs).ceil();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue