mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 16:21:57 -05:00
✨ Fix many corner issues related to shape data structure change
This commit is contained in:
parent
4623f36042
commit
96bb282674
9 changed files with 125 additions and 107 deletions
|
@ -499,7 +499,7 @@
|
|||
object
|
||||
(-> object
|
||||
(update :selrect grc/make-rect)
|
||||
(cts/map->Shape))))
|
||||
(cts/create-shape))))
|
||||
(update-container [container]
|
||||
(d/update-when container :objects update-vals update-object))]
|
||||
(-> data
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
:width (mth/abs (- x2 x1))
|
||||
:height (mth/abs (- y2 y1))))
|
||||
|
||||
;; FIXME: looks unused
|
||||
:position
|
||||
(let [x (dm/get-prop rect :x)
|
||||
y (dm/get-prop rect :y)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.geom.shapes.path :as gpa]
|
||||
[app.common.math :as mth]
|
||||
[app.common.record :as cr]
|
||||
[app.common.types.modifiers :as ctm]))
|
||||
|
||||
#?(:clj (set! *warn-on-reflection* true))
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.common.types.shape
|
||||
(:require
|
||||
#?(:clj [app.common.fressian :as fres])
|
||||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
|
@ -14,10 +13,8 @@
|
|||
[app.common.geom.proportions :as gpr]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.record :as cr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.grid :as ctg]
|
||||
[app.common.types.plugins :as ctpg]
|
||||
|
@ -33,8 +30,6 @@
|
|||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]))
|
||||
|
||||
(cr/defrecord Shape [id name type x y width height rotation selrect points transform transform-inverse parent-id frame-id flip-x flip-y])
|
||||
|
||||
(defn shape?
|
||||
[o]
|
||||
(impl/shape? o))
|
||||
|
@ -453,27 +448,30 @@
|
|||
;; NOTE: used for create ephimeral shapes for multiple selection
|
||||
:multiple minimal-multiple-attrs))
|
||||
|
||||
(defn create-shape
|
||||
"A low level function that creates a Shape data structure
|
||||
from a attrs map without performing other transformations"
|
||||
[attrs]
|
||||
(impl/create-shape attrs))
|
||||
|
||||
(defn- make-minimal-shape
|
||||
[type]
|
||||
(let [type (if (= type :curve) :path type)
|
||||
attrs (get-minimal-shape type)]
|
||||
attrs (get-minimal-shape type)
|
||||
attrs (cond-> attrs
|
||||
(and (not= :path type)
|
||||
(not= :bool type))
|
||||
(-> (assoc :x 0)
|
||||
(assoc :y 0)
|
||||
(assoc :width 0.01)
|
||||
(assoc :height 0.01)))
|
||||
attrs (-> attrs
|
||||
(assoc :id (uuid/next))
|
||||
(assoc :frame-id uuid/zero)
|
||||
(assoc :parent-id uuid/zero)
|
||||
(assoc :rotation 0))]
|
||||
|
||||
(cond-> attrs
|
||||
(and (not= :path type)
|
||||
(not= :bool type))
|
||||
(-> (assoc :x 0)
|
||||
(assoc :y 0)
|
||||
(assoc :width 0.01)
|
||||
(assoc :height 0.01))
|
||||
|
||||
:always
|
||||
(assoc :id (uuid/next)
|
||||
:frame-id uuid/zero
|
||||
:parent-id uuid/zero
|
||||
:rotation 0)
|
||||
|
||||
:always
|
||||
(impl/map->Shape))))
|
||||
(impl/create-shape attrs)))
|
||||
|
||||
(defn setup-rect
|
||||
"Initializes the selrect and points for a shape."
|
||||
|
|
|
@ -7,18 +7,14 @@
|
|||
(ns app.common.types.shape.impl
|
||||
(:require
|
||||
#?(:clj [app.common.fressian :as fres])
|
||||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.rect :as grc]
|
||||
#?(:cljs [app.common.data.macros :as dm])
|
||||
#?(:cljs [app.common.geom.rect :as grc])
|
||||
#?(:cljs [cuerdas.core :as str])
|
||||
[app.common.record :as cr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.transit :as t]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.core :as c]
|
||||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]))
|
||||
[clojure.core :as c]))
|
||||
|
||||
(def enabled-wasm-ready-shape false)
|
||||
|
||||
#?(:cljs
|
||||
(do
|
||||
|
@ -52,11 +48,11 @@
|
|||
;; (ShapeWithBuffer. bf32 delegate)))
|
||||
|
||||
IWithMeta
|
||||
(-with-meta [coll meta]
|
||||
(-with-meta [_ meta]
|
||||
(ShapeWithBuffer. buffer (with-meta delegate meta)))
|
||||
|
||||
IMeta
|
||||
(-meta [coll] (meta delegate))
|
||||
(-meta [_] (meta delegate))
|
||||
|
||||
ICollection
|
||||
(-conj [coll entry]
|
||||
|
@ -77,20 +73,20 @@
|
|||
(seq delegate)))
|
||||
|
||||
ICounted
|
||||
(-count [coll]
|
||||
(-count [_]
|
||||
(+ 1 (count delegate)))
|
||||
|
||||
ILookup
|
||||
(-lookup [coll k]
|
||||
(-lookup coll k nil))
|
||||
|
||||
(-lookup [coll k not-found]
|
||||
(-lookup [_ k not-found]
|
||||
(if (= k :selrect)
|
||||
(read-selrect buffer)
|
||||
(c/-lookup delegate k not-found)))
|
||||
|
||||
IFind
|
||||
(-find [coll k]
|
||||
(-find [_ k]
|
||||
(if (= k :selrect)
|
||||
(c/MapEntry. k (read-selrect buffer) nil) ; Replace with lazy MapEntry
|
||||
(c/-find delegate k)))
|
||||
|
@ -99,7 +95,7 @@
|
|||
(-assoc [coll k v]
|
||||
(impl-assoc coll k v))
|
||||
|
||||
(-contains-key? [coll k]
|
||||
(-contains-key? [_ k]
|
||||
(or (= k :selrect)
|
||||
(contains? delegate k)))
|
||||
|
||||
|
@ -115,13 +111,14 @@
|
|||
(-lookup coll k not-found))
|
||||
|
||||
IPrintWithWriter
|
||||
(-pr-writer [coll writer opts]
|
||||
(-pr-writer [_ writer _]
|
||||
(-write writer (str "#penpot/shape " (:id delegate))))))
|
||||
|
||||
(defn shape?
|
||||
[o]
|
||||
(or (instance? Shape o)
|
||||
#?(:cljs (instance? ShapeWithBuffer o))))
|
||||
#?(:clj (instance? Shape o)
|
||||
:cljs (or (instance? Shape o)
|
||||
(instance? ShapeWithBuffer o))))
|
||||
|
||||
;; --- SHAPE IMPL
|
||||
|
||||
|
@ -194,15 +191,18 @@
|
|||
(next es))
|
||||
(throw (js/Error. "conj on a map takes map entries or seqables of map entries")))))))))
|
||||
|
||||
(defn create-shape
|
||||
"Instanciate a shape from a map"
|
||||
[attrs]
|
||||
#?(:cljs
|
||||
(if enabled-wasm-ready-shape
|
||||
(let [selrect (:selrect attrs)
|
||||
buffer (new Float32Array 4)]
|
||||
(write-selrect buffer selrect)
|
||||
(ShapeWithBuffer. buffer (dissoc attrs :selrect)))
|
||||
(map->Shape attrs))
|
||||
|
||||
#?(:cljs
|
||||
(defn create-shape
|
||||
"Instanciate a shape from a map"
|
||||
[data]
|
||||
(let [selrect (:selrect data)
|
||||
buffer (new Float32Array 4)]
|
||||
(write-selrect buffer selrect)
|
||||
(ShapeWithBuffer. buffer (dissoc data :selrect)))))
|
||||
:clj (map->Shape attrs)))
|
||||
|
||||
;; --- SHAPE SERIALIZATION
|
||||
|
||||
|
@ -210,21 +210,18 @@
|
|||
{:id "shape"
|
||||
:class Shape
|
||||
:wfn #(into {} %)
|
||||
:rfn #?(:cljs create-shape
|
||||
:clj map->Shape)})
|
||||
|
||||
#?(:cljs (t/add-handlers!
|
||||
{:id "shape"
|
||||
:class ShapeWithBuffer
|
||||
:wfn #(into {} %)
|
||||
:rfn #?(:cljs create-shape
|
||||
:clj map->Shape)}))
|
||||
|
||||
:rfn create-shape})
|
||||
|
||||
#?(:cljs
|
||||
(t/add-handlers!
|
||||
{:id "shape"
|
||||
:class ShapeWithBuffer
|
||||
:wfn #(into {} %)
|
||||
:rfn create-shape}))
|
||||
|
||||
#?(:clj
|
||||
(fres/add-handlers!
|
||||
{:name "penpot/shape"
|
||||
:class Shape
|
||||
:wfn fres/write-map-like
|
||||
:rfn (comp map->Shape fres/read-map-like)}))
|
||||
:rfn (comp create-shape fres/read-map-like)}))
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.record :as cr]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as dch]
|
||||
|
@ -68,15 +67,15 @@
|
|||
|
||||
calculate-selrect
|
||||
(fn [selrect [delta space?]]
|
||||
(let [selrect (-> (cr/clone selrect)
|
||||
(cr/update! :x2 + (:x delta))
|
||||
(cr/update! :y2 + (:y delta)))
|
||||
(let [selrect (-> selrect
|
||||
(update :x2 + (:x delta))
|
||||
(update :y2 + (:y delta)))
|
||||
selrect (if ^boolean space?
|
||||
(-> (cr/clone selrect)
|
||||
(cr/update! :x1 + (:x delta))
|
||||
(cr/update! :y1 + (:y delta)))
|
||||
(-> selrect
|
||||
(update :x1 + (:x delta))
|
||||
(update :y1 + (:y delta)))
|
||||
selrect)]
|
||||
(grc/update-rect! selrect :corners)))
|
||||
(grc/update-rect selrect :corners)))
|
||||
|
||||
selrect-stream
|
||||
(->> ms/mouse-position
|
||||
|
|
|
@ -6,32 +6,20 @@
|
|||
|
||||
(ns app.main.ui.workspace.shapes.common
|
||||
(:require
|
||||
[app.common.record :as cr]
|
||||
[app.main.ui.shapes.shape :refer [shape-container]]
|
||||
[app.main.ui.workspace.shapes.debug :as wsd]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private excluded-attrs
|
||||
#{:blocked
|
||||
:hide-fill-on-export
|
||||
:collapsed
|
||||
:remote-synced
|
||||
:exports})
|
||||
|
||||
(defn check-shape
|
||||
[new-shape old-shape]
|
||||
(cr/-equiv-with-exceptions old-shape new-shape excluded-attrs))
|
||||
|
||||
(defn check-shape-props
|
||||
[np op]
|
||||
(check-shape (unchecked-get np "shape")
|
||||
(unchecked-get op "shape")))
|
||||
(= (unchecked-get np "shape")
|
||||
(unchecked-get op "shape")))
|
||||
|
||||
(defn generic-wrapper-factory
|
||||
[component]
|
||||
(mf/fnc generic-wrapper
|
||||
{::mf/wrap [#(mf/memo' % check-shape-props)]
|
||||
::mf/wrap-props false}
|
||||
::mf/props :obj}
|
||||
[props]
|
||||
(let [shape (unchecked-get props "shape")]
|
||||
[:> shape-container {:shape shape}
|
||||
|
|
|
@ -261,7 +261,8 @@
|
|||
(= (:layout selected-frame) :flex)
|
||||
(zero? (:rotation first-shape)))
|
||||
|
||||
selecting-first-level-frame? (and single-select? (cfh/root-frame? first-shape))
|
||||
selecting-first-level-frame?
|
||||
(and single-select? (cfh/root-frame? first-shape))
|
||||
|
||||
offset-x (if selecting-first-level-frame?
|
||||
(:x first-shape)
|
||||
|
@ -276,19 +277,20 @@
|
|||
|
||||
(when ^boolean render.wasm/enabled?
|
||||
(mf/with-effect []
|
||||
(time (when-let [canvas (mf/ref-val canvas-ref)]
|
||||
(->> render.wasm/module
|
||||
(p/fmap (fn [ready?]
|
||||
(when ready?
|
||||
(reset! canvas-init? true)
|
||||
(render.wasm/assign-canvas canvas)))))
|
||||
(fn []
|
||||
(render.wasm/clear-canvas)))))
|
||||
(when-let [canvas (mf/ref-val canvas-ref)]
|
||||
(->> render.wasm/module
|
||||
(p/fmap (fn [ready?]
|
||||
(when ready?
|
||||
(reset! canvas-init? true)
|
||||
(render.wasm/assign-canvas canvas)))))
|
||||
(fn []
|
||||
(render.wasm/clear-canvas))))
|
||||
|
||||
(mf/with-effect [objects-modified canvas-init?]
|
||||
(when @canvas-init?
|
||||
(render.wasm/set-objects objects-modified)
|
||||
(render.wasm/draw-objects zoom vbox)))
|
||||
|
||||
(mf/with-effect [vbox canvas-init?]
|
||||
(let [frame-id (when @canvas-init? (do
|
||||
(render.wasm/draw-objects zoom vbox)))]
|
||||
|
@ -300,6 +302,8 @@
|
|||
(hooks/setup-keyboard alt? mod? space? z? shift?)
|
||||
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover measure-hover
|
||||
hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?)
|
||||
|
||||
;; FIXME: this should be removed on canvas viewport
|
||||
(hooks/setup-viewport-modifiers modifiers base-objects)
|
||||
(hooks/setup-shortcuts node-editing? drawing-path? text-editing? grid-editing?)
|
||||
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox)
|
||||
|
|
|
@ -9,26 +9,58 @@
|
|||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.types.shape.impl]
|
||||
[app.config :as cf]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(def enabled?
|
||||
(contains? cf/flags :render-wasm))
|
||||
|
||||
(defonce ^:dynamic internal-module #js {})
|
||||
(defonce ^:dynamic internal-gpu-state #js {})
|
||||
(set! app.common.types.shape.impl/enabled-wasm-ready-shape enabled?)
|
||||
|
||||
(defn set-objects [objects]
|
||||
(let [shapes-buffer (unchecked-get internal-module "_shapes_buffer")
|
||||
heap (unchecked-get internal-module "HEAPF32")
|
||||
;; size *in bytes* for each shapes::Shape
|
||||
rect-size 16
|
||||
;; TODO: remove the `take` once we have the dynamic data structure in Rust
|
||||
supported-shapes (take 2048 (filter #(not (cfh/root? %)) (vals objects)))
|
||||
mem (js/Float32Array. (.-buffer heap) (shapes-buffer) (* rect-size (count supported-shapes)))]
|
||||
(run! (fn [[shape index]]
|
||||
(.set mem (.-buffer shape) (* index rect-size)))
|
||||
(zipmap supported-shapes (range)))))
|
||||
(defonce internal-module #js {})
|
||||
(defonce internal-gpu-state #js {})
|
||||
|
||||
;; TODO: remove the `take` once we have the dynamic data structure in Rust
|
||||
(def xform
|
||||
(comp
|
||||
(remove cfh/root?)
|
||||
(take 2048)))
|
||||
|
||||
;; Size in number of f32 values that represents the shape selrect (
|
||||
(def rect-size 4)
|
||||
|
||||
(defn set-objects
|
||||
[objects]
|
||||
;; FIXME: maybe change the name of `_shapes_buffer` (?)
|
||||
(let [get-shapes-buffer-ptr
|
||||
(unchecked-get internal-module "_shapes_buffer")
|
||||
|
||||
heap
|
||||
(unchecked-get internal-module "HEAPF32")
|
||||
|
||||
shapes
|
||||
(into [] xform (vals objects))
|
||||
|
||||
total-shapes
|
||||
(count shapes)
|
||||
|
||||
heap-offset
|
||||
(get-shapes-buffer-ptr)
|
||||
|
||||
heap-size
|
||||
(* rect-size total-shapes)
|
||||
|
||||
mem
|
||||
(js/Float32Array. (.-buffer heap)
|
||||
heap-offset
|
||||
heap-size)]
|
||||
|
||||
(loop [index 0]
|
||||
(when (< index total-shapes)
|
||||
(let [shape (nth shapes index)]
|
||||
(.set ^js mem (.-buffer shape) (* index rect-size))
|
||||
(recur (inc index)))))))
|
||||
|
||||
(defn draw-objects
|
||||
[zoom vbox]
|
||||
|
|
Loading…
Add table
Reference in a new issue