mirror of
https://github.com/penpot/penpot.git
synced 2025-08-03 13:18:21 +02:00
✨ Move auto-layout children
This commit is contained in:
parent
025cac0228
commit
c3ed46d3ab
22 changed files with 457 additions and 329 deletions
|
@ -21,27 +21,37 @@
|
|||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(defn truncate-zero [num default]
|
||||
(if (mth/almost-zero? num) default num))
|
||||
(defn adjust-ratio
|
||||
[point initial]
|
||||
(let [v (gpt/to-vec point initial)
|
||||
dx (mth/abs (:x v))
|
||||
dy (mth/abs (:y v))
|
||||
sx (mth/sign (:x v))
|
||||
sy (mth/sign (:y v))]
|
||||
|
||||
(cond-> point
|
||||
(> dx dy)
|
||||
(assoc :y (- (:y point) (* sy (- dx dy))))
|
||||
|
||||
(> dy dx)
|
||||
(assoc :x (- (:x point) (* sx (- dy dx)))))))
|
||||
|
||||
(defn resize-shape [{:keys [x y width height] :as shape} initial point lock?]
|
||||
(let [draw-rect (gsh/make-rect initial (cond-> point lock? (adjust-ratio initial)))
|
||||
shape-rect (gsh/make-rect x y width height)
|
||||
|
||||
scalev (gpt/point (/ (:width draw-rect) (:width shape-rect))
|
||||
(/ (:height draw-rect) (:height shape-rect)))
|
||||
|
||||
movev (gpt/to-vec (gpt/point shape-rect) (gpt/point draw-rect))]
|
||||
|
||||
(defn resize-shape [{:keys [x y width height] :as shape} point lock?]
|
||||
(let [;; The new shape behaves like a resize on the bottom-right corner
|
||||
initial (gpt/point (+ x width) (+ y height))
|
||||
shapev (gpt/point width height)
|
||||
deltav (gpt/to-vec initial point)
|
||||
scalev (-> (gpt/divide (gpt/add shapev deltav) shapev)
|
||||
(update :x truncate-zero 0.01)
|
||||
(update :y truncate-zero 0.01))
|
||||
scalev (if lock?
|
||||
(let [v (max (:x scalev) (:y scalev))]
|
||||
(gpt/point v v))
|
||||
scalev)]
|
||||
(-> shape
|
||||
(assoc :click-draw? false)
|
||||
(gsh/transform-shape (ctm/resize scalev (gpt/point x y))))))
|
||||
(gsh/transform-shape (ctm/resize scalev (gpt/point x y)))
|
||||
(gsh/transform-shape (ctm/move movev)))))
|
||||
|
||||
(defn update-drawing [state point lock?]
|
||||
(update-in state [:workspace-drawing :object] resize-shape point lock?))
|
||||
(defn update-drawing [state initial point lock?]
|
||||
(update-in state [:workspace-drawing :object] resize-shape initial point lock?))
|
||||
|
||||
(defn move-drawing
|
||||
[{:keys [x y]}]
|
||||
|
@ -57,8 +67,7 @@
|
|||
layout (get state :workspace-layout)
|
||||
snap-pixel? (contains? layout :snap-pixel-grid)
|
||||
|
||||
initial (cond-> @ms/mouse-position
|
||||
snap-pixel? gpt/round)
|
||||
initial (cond-> @ms/mouse-position snap-pixel? gpt/round)
|
||||
|
||||
page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
|
@ -96,7 +105,7 @@
|
|||
(rx/map #(conj current %)))))
|
||||
(rx/map
|
||||
(fn [[_ shift? point]]
|
||||
#(update-drawing % (cond-> point snap-pixel? gpt/round) shift?)))
|
||||
#(update-drawing % initial (cond-> point snap-pixel? gpt/round) shift?)))
|
||||
|
||||
(rx/take-until stoper))
|
||||
(rx/of (common/handle-finish-drawing)))))))
|
||||
|
|
|
@ -51,8 +51,7 @@
|
|||
|
||||
(and click-draw? (not text?))
|
||||
(-> (assoc :width min-side :height min-side)
|
||||
(gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2))))
|
||||
#_(ctm/add-move (- (/ min-side 2)) (- (/ min-side 2))))
|
||||
(gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2)))))
|
||||
|
||||
(and click-draw? text?)
|
||||
(assoc :height 17 :width 4 :grow-type :auto-width)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
[app.main.data.workspace.edition :as dwe]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.features :as features]
|
||||
[app.main.streams :as ms]
|
||||
|
@ -146,6 +147,10 @@
|
|||
ids (cph/clean-loops objects ids)
|
||||
lookup (d/getf objects)
|
||||
|
||||
layout-ids (->> ids
|
||||
(mapcat (partial cph/get-parent-ids objects))
|
||||
(filter (partial cph/layout-shape? objects)))
|
||||
|
||||
components-v2 (features/active-feature? state :components-v2)
|
||||
|
||||
groups-to-unmask
|
||||
|
@ -266,7 +271,8 @@
|
|||
|
||||
(rx/of (dc/detach-comment-thread ids)
|
||||
(dwsl/update-layout-positions all-parents)
|
||||
(dch/commit-changes changes)))))))
|
||||
(dch/commit-changes changes)
|
||||
(dwsl/update-layout-positions layout-ids)))))))
|
||||
|
||||
(defn- viewport-center
|
||||
[state]
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.layout :as gsl]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.common :as cpc]
|
||||
|
@ -137,8 +138,20 @@
|
|||
snap-pixel? (and (not ignore-snap-pixel)
|
||||
(contains? (:workspace-layout state) :snap-pixel-grid))
|
||||
|
||||
workspace-modifiers (:workspace-modifiers state)
|
||||
|
||||
modif-tree
|
||||
(gsh/set-objects-modifiers ids objects (constantly modifiers) ignore-constraints snap-pixel?)]
|
||||
(gsh/set-objects-modifiers
|
||||
;; TODO LAYOUT: I don't like this
|
||||
(concat (keys workspace-modifiers) ids)
|
||||
objects
|
||||
(fn [shape]
|
||||
(let [modifiers (if (contains? ids (:id shape)) modifiers {})
|
||||
old-modifiers-v3 (get-in state [:workspace-modifiers (:id shape) :modifiers :v3])]
|
||||
(cond-> modifiers
|
||||
(some? old-modifiers-v3)
|
||||
(assoc :v3 old-modifiers-v3))))
|
||||
ignore-constraints snap-pixel?)]
|
||||
|
||||
(update state :workspace-modifiers merge modif-tree))))))
|
||||
|
||||
|
@ -619,6 +632,40 @@
|
|||
(rx/take 1)
|
||||
(rx/map #(start-move from-position))))))
|
||||
|
||||
(defn set-change-frame-modifiers
|
||||
[selected target-frame position]
|
||||
|
||||
(ptk/reify ::set-change-frame-modifiers
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
|
||||
origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id])))
|
||||
|
||||
layout? (get-in objects [target-frame :layout])
|
||||
|
||||
drop-index
|
||||
(when layout? (gsl/get-drop-index target-frame objects position))
|
||||
|
||||
modif-tree
|
||||
(into {}
|
||||
(mapcat
|
||||
(fn [original-frame]
|
||||
(let [shapes (->> (get origin-frame-ids original-frame)
|
||||
(d/removev #(= target-frame %)))]
|
||||
(cond
|
||||
(not= original-frame target-frame)
|
||||
[[original-frame {:modifiers {:v3 [{:type :remove-children :value shapes}]}}]
|
||||
[target-frame {:modifiers {:v3 [{:type :add-children
|
||||
:value shapes
|
||||
:index drop-index}]}}]]
|
||||
layout?
|
||||
[[target-frame {:modifiers {:v3 [{:type :add-children
|
||||
:value shapes
|
||||
:index drop-index}]}}]]))))
|
||||
(keys origin-frame-ids))]
|
||||
(assoc state :workspace-modifiers modif-tree)))))
|
||||
|
||||
(defn- start-move
|
||||
([from-position] (start-move from-position nil))
|
||||
([from-position ids]
|
||||
|
@ -664,17 +711,25 @@
|
|||
(if (empty? shapes)
|
||||
(rx/of (finish-transform))
|
||||
(rx/concat
|
||||
(->> position
|
||||
;; We ask for the snap position but we continue even if the result is not available
|
||||
(rx/with-latest vector snap-delta)
|
||||
;; We try to use the previous snap so we don't have to wait for the result of the new
|
||||
(rx/map snap/correct-snap-point)
|
||||
(rx/merge
|
||||
(->> position
|
||||
(rx/map (fn [delta]
|
||||
(let [position (gpt/add from-position delta)
|
||||
target-frame (ctst/top-nested-frame objects position)]
|
||||
(set-change-frame-modifiers selected target-frame position))))
|
||||
(rx/take-until stopper))
|
||||
|
||||
#_(rx/map #(hash-map :displacement (gmt/translate-matrix %)))
|
||||
(rx/map #(array-map :v2 [{:type :move :vector %}]))
|
||||
(->> position
|
||||
;; We ask for the snap position but we continue even if the result is not available
|
||||
(rx/with-latest vector snap-delta)
|
||||
|
||||
(rx/map (partial set-modifiers ids))
|
||||
(rx/take-until stopper))
|
||||
;; We try to use the previous snap so we don't have to wait for the result of the new
|
||||
(rx/map snap/correct-snap-point)
|
||||
|
||||
(rx/map (fn [move-vec] {:v2 [{:type :move :vector move-vec}]}))
|
||||
|
||||
(rx/map (partial set-modifiers ids))
|
||||
(rx/take-until stopper)))
|
||||
|
||||
(rx/of (dwu/start-undo-transaction)
|
||||
(calculate-frame-for-move ids)
|
||||
|
@ -767,18 +822,22 @@
|
|||
page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
frame-id (ctst/top-nested-frame objects position)
|
||||
layout? (get-in objects [frame-id :layout])
|
||||
lookup (d/getf objects)
|
||||
|
||||
shapes (->> ids (cph/clean-loops objects) (keep lookup))
|
||||
|
||||
moving-shapes
|
||||
(->> ids
|
||||
(cph/clean-loops objects)
|
||||
(keep lookup)
|
||||
(remove #(= (:frame-id %) frame-id)))
|
||||
(cond->> shapes
|
||||
(not layout?)
|
||||
(remove #(= (:frame-id %) frame-id)))
|
||||
|
||||
drop-index (when layout? (gsl/get-drop-index frame-id objects position))
|
||||
|
||||
changes
|
||||
(-> (pcb/empty-changes it page-id)
|
||||
(pcb/with-objects objects)
|
||||
(pcb/change-parent frame-id moving-shapes))]
|
||||
(pcb/change-parent frame-id moving-shapes drop-index))]
|
||||
|
||||
(when-not (empty? changes)
|
||||
(rx/of (dch/commit-changes changes)
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
others are defined using a generic wrapper implemented in
|
||||
common."
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.shapes.circle :as circle]
|
||||
[app.main.ui.shapes.image :as image]
|
||||
|
@ -55,33 +57,36 @@
|
|||
(mf/deps objects)
|
||||
#(cph/objects-by-frame objects))]
|
||||
|
||||
[:& (mf/provider ctx/active-frames) {:value active-frames}
|
||||
;; Render font faces only for shapes that are part of the root
|
||||
;; frame but don't belongs to any other frame.
|
||||
(let [xform (comp
|
||||
(remove cph/frame-shape?)
|
||||
(mapcat #(cph/get-children-with-self objects (:id %))))]
|
||||
[:& ff/fontfaces-style {:shapes (into [] xform shapes)}])
|
||||
[:g {:id (dm/str "shape-" uuid/zero)}
|
||||
[:& (mf/provider ctx/active-frames) {:value active-frames}
|
||||
;; Render font faces only for shapes that are part of the root
|
||||
;; frame but don't belongs to any other frame.
|
||||
(let [xform (comp
|
||||
(remove cph/frame-shape?)
|
||||
(mapcat #(cph/get-children-with-self objects (:id %))))]
|
||||
[:& ff/fontfaces-style {:shapes (into [] xform shapes)}])
|
||||
|
||||
(for [shape shapes]
|
||||
(cond
|
||||
(not (cph/frame-shape? shape))
|
||||
[:& shape-wrapper
|
||||
{:shape shape
|
||||
:key (:id shape)}]
|
||||
[:g.frame-children
|
||||
(for [shape shapes]
|
||||
[:g.ws-shape-wrapper
|
||||
(cond
|
||||
(not (cph/frame-shape? shape))
|
||||
[:& shape-wrapper
|
||||
{:shape shape
|
||||
:key (:id shape)}]
|
||||
|
||||
(cph/root-frame? shape)
|
||||
[:& root-frame-wrapper
|
||||
{:shape shape
|
||||
:key (:id shape)
|
||||
:objects (get frame-objects (:id shape))
|
||||
:thumbnail? (not (contains? active-frames (:id shape)))}]
|
||||
(cph/root-frame? shape)
|
||||
[:& root-frame-wrapper
|
||||
{:shape shape
|
||||
:key (:id shape)
|
||||
:objects (get frame-objects (:id shape))
|
||||
:thumbnail? (not (contains? active-frames (:id shape)))}]
|
||||
|
||||
:else
|
||||
[:& nested-frame-wrapper
|
||||
{:shape shape
|
||||
:key (:id shape)
|
||||
:objects (get frame-objects (:id shape))}]))]))
|
||||
:else
|
||||
[:& nested-frame-wrapper
|
||||
{:shape shape
|
||||
:key (:id shape)
|
||||
:objects (get frame-objects (:id shape))}])])]]]))
|
||||
|
||||
(mf/defc shape-wrapper
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
|
||||
|
@ -98,20 +103,21 @@
|
|||
|
||||
opts #js {:shape shape :thumbnail? thumbnail?}]
|
||||
(when (and (some? shape) (not (:hidden shape)))
|
||||
(case (:type shape)
|
||||
:path [:> path/path-wrapper opts]
|
||||
:text [:> text/text-wrapper opts]
|
||||
:group [:> group-wrapper opts]
|
||||
:rect [:> rect-wrapper opts]
|
||||
:image [:> image-wrapper opts]
|
||||
:circle [:> circle-wrapper opts]
|
||||
:svg-raw [:> svg-raw-wrapper opts]
|
||||
:bool [:> bool-wrapper opts]
|
||||
[:g.ws-shape-wrapper
|
||||
(case (:type shape)
|
||||
:path [:> path/path-wrapper opts]
|
||||
:text [:> text/text-wrapper opts]
|
||||
:group [:> group-wrapper opts]
|
||||
:rect [:> rect-wrapper opts]
|
||||
:image [:> image-wrapper opts]
|
||||
:circle [:> circle-wrapper opts]
|
||||
:svg-raw [:> svg-raw-wrapper opts]
|
||||
:bool [:> bool-wrapper opts]
|
||||
|
||||
;; Only used when drawing a new frame.
|
||||
:frame [:> nested-frame-wrapper opts]
|
||||
;; Only used when drawing a new frame.
|
||||
:frame [:> nested-frame-wrapper opts]
|
||||
|
||||
nil))))
|
||||
nil)])))
|
||||
|
||||
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
||||
(def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper))
|
||||
|
|
|
@ -24,87 +24,7 @@
|
|||
[app.main.ui.workspace.shapes.frame.node-store :as fns]
|
||||
[app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr]
|
||||
[beicon.core :as rx]
|
||||
[rumext.v2 :as mf]
|
||||
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.layout :as gsl]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.store :as st]))
|
||||
|
||||
(mf/defc debug-layout
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
||||
(let [shape (unchecked-get props "shape")
|
||||
children (-> (wsh/lookup-page-objects @st/state)
|
||||
(cph/get-immediate-children (:id shape)))
|
||||
|
||||
layout-data (gsl/calc-layout-data shape children)
|
||||
|
||||
drop-areas
|
||||
(gsl/drop-areas shape layout-data children)
|
||||
|
||||
]
|
||||
|
||||
[:g.debug-layout {:pointer-events "none"}
|
||||
(for [[idx drop-area] (d/enumerate drop-areas)]
|
||||
[:rect {:x (:x drop-area)
|
||||
:y (:y drop-area)
|
||||
:width (:width drop-area)
|
||||
:height (:height drop-area)
|
||||
:style {:fill "blue"
|
||||
:fill-opacity 0.3
|
||||
:stroke "red"
|
||||
:stroke-width 1
|
||||
:stroke-dasharray "3 6"}}])
|
||||
|
||||
|
||||
#_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))]
|
||||
(let [col? (gsl/col? shape)
|
||||
row? (gsl/row? shape)
|
||||
h-center? (and row? (gsl/h-center? shape))
|
||||
h-end? (and row? (gsl/h-end? shape))
|
||||
v-center? (and col? (gsl/v-center? shape))
|
||||
v-end? (and row? (gsl/v-end? shape))
|
||||
|
||||
line-width
|
||||
(+ (-> layout-line :line-width)
|
||||
(:margin-x shape)
|
||||
(if col?
|
||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
||||
0))
|
||||
|
||||
line-height
|
||||
(+ (-> layout-line :line-height)
|
||||
(:margin-y shape)
|
||||
(if row?
|
||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
||||
0))
|
||||
]
|
||||
[:g {:key (dm/str "line-" idx)}
|
||||
[:rect {:x (- (-> layout-line :start-p :x)
|
||||
(cond
|
||||
h-center? (/ line-width 2)
|
||||
h-end? line-width
|
||||
:else 0))
|
||||
:y (- (-> layout-line :start-p :y)
|
||||
(cond
|
||||
v-center? (/ line-height 2)
|
||||
v-end? line-height
|
||||
:else 0))
|
||||
:width line-width
|
||||
:height line-height
|
||||
:style {:fill "blue"
|
||||
:fill-opacity 0.3}
|
||||
}]
|
||||
#_[:line {:x1 (-> layout-line :start-p :x)
|
||||
:y1 (-> layout-line :start-p :y)
|
||||
:x2 (+ (-> layout-line :start-p :x) (if col? line-width 0))
|
||||
:y2 (+ (-> layout-line :start-p :y) (if row? line-height 0))
|
||||
:transform (gsh/transform-str shape)
|
||||
:style {:fill "none"
|
||||
:stroke "red"
|
||||
:stroke-width 2}}]]))]))
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn frame-shape-factory
|
||||
[shape-wrapper]
|
||||
|
@ -119,12 +39,9 @@
|
|||
childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape)))
|
||||
childs (mf/deref childs-ref)]
|
||||
|
||||
[:*
|
||||
[:& (mf/provider embed/context) {:value true}
|
||||
[:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)}
|
||||
[:& frame-shape {:shape shape :childs childs} ]]]
|
||||
|
||||
#_[:& debug-layout {:shape shape}]]))))
|
||||
[:& (mf/provider embed/context) {:value true}
|
||||
[:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)}
|
||||
[:& frame-shape {:shape shape :childs childs} ]]]))))
|
||||
|
||||
(defn check-props
|
||||
[new-props old-props]
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.types.modifiers :as ctm]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.workspace.viewport.utils :as vwu]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- transform-no-resize
|
||||
|
@ -78,13 +80,20 @@
|
|||
|
||||
[result width height]))
|
||||
|
||||
(defn get-shape-node
|
||||
([id]
|
||||
(get-shape-node js/document id))
|
||||
|
||||
([base-node id]
|
||||
(if (= (.-id base-node) (dm/str "shape-" id))
|
||||
base-node
|
||||
(dom/query base-node (dm/str "#shape-" id)))))
|
||||
|
||||
(defn get-nodes
|
||||
"Retrieve the DOM nodes to apply the matrix transformation"
|
||||
[base-node {:keys [id type masked-group?] :as shape}]
|
||||
(when (some? base-node)
|
||||
(let [shape-node (if (= (.-id base-node) (dm/str "shape-" id))
|
||||
base-node
|
||||
(dom/query base-node (dm/str "#shape-" id)))
|
||||
(let [shape-node (get-shape-node base-node id)
|
||||
|
||||
frame? (= :frame type)
|
||||
group? (= :group type)
|
||||
|
@ -164,7 +173,7 @@
|
|||
|
||||
(defn set-transform-att!
|
||||
[node att value]
|
||||
|
||||
|
||||
(let [old-att (dom/get-attribute node (dm/str "data-old-" att))
|
||||
new-value (if (some? old-att)
|
||||
(dm/str value " " old-att)
|
||||
|
@ -269,6 +278,33 @@
|
|||
(ctm/modifiers->transform center modifiers)))
|
||||
modifiers))))
|
||||
|
||||
structure-changes
|
||||
(mf/use-memo
|
||||
(mf/deps modifiers)
|
||||
(fn []
|
||||
(into {}
|
||||
(comp (filter (fn [[_ val]] (-> val :modifiers :v3 some?)))
|
||||
(map (fn [[key val]]
|
||||
[key (-> val :modifiers :v3)])))
|
||||
|
||||
modifiers)))
|
||||
|
||||
structure-changes (hooks/use-equal-memo structure-changes)
|
||||
|
||||
add-children
|
||||
(mf/use-memo
|
||||
(mf/deps structure-changes)
|
||||
(fn []
|
||||
(into []
|
||||
(mapcat (fn [[frame-id changes]]
|
||||
(->> changes
|
||||
(filter (fn [{:keys [type]}] (= type :add-children)))
|
||||
(mapcat (fn [{:keys [value]}]
|
||||
(->> value (map (fn [id] {:frame frame-id :shape id}))))))))
|
||||
structure-changes)))
|
||||
|
||||
add-children-prev (hooks/use-previous add-children)
|
||||
|
||||
shapes
|
||||
(mf/use-memo
|
||||
(mf/deps transforms)
|
||||
|
@ -280,6 +316,31 @@
|
|||
prev-modifiers (mf/use-var nil)
|
||||
prev-transforms (mf/use-var nil)]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps add-children)
|
||||
(fn []
|
||||
(doseq [{:keys [frame shape]} add-children-prev]
|
||||
(let [frame-node (get-shape-node node frame)
|
||||
shape-node (get-shape-node shape)
|
||||
mirror-node (dom/query frame-node (dm/fmt ".mirror-shape[href='#shape-%'" shape))]
|
||||
(when mirror-node (.remove mirror-node))
|
||||
(dom/remove-attribute! (dom/get-parent shape-node) "display")))
|
||||
|
||||
(doseq [{:keys [frame shape]} add-children]
|
||||
(let [frame-node (get-shape-node node frame)
|
||||
shape-node (get-shape-node shape)
|
||||
|
||||
use-node
|
||||
(.createElementNS globals/document "http://www.w3.org/2000/svg" "use")
|
||||
|
||||
contents-node
|
||||
(or (dom/query frame-node ".frame-children") frame-node)]
|
||||
|
||||
(dom/set-attribute! use-node "href" (dm/fmt "#shape-%" shape))
|
||||
(dom/add-class! use-node "mirror-shape")
|
||||
(dom/append-child! contents-node use-node)
|
||||
(dom/set-attribute! (dom/get-parent shape-node) "display" "none")))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps transforms)
|
||||
(fn []
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
[app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh]
|
||||
[app.main.ui.workspace.viewport.actions :as actions]
|
||||
[app.main.ui.workspace.viewport.comments :as comments]
|
||||
[app.main.ui.workspace.viewport.debug :as wvd]
|
||||
[app.main.ui.workspace.viewport.drawarea :as drawarea]
|
||||
[app.main.ui.workspace.viewport.frame-grid :as frame-grid]
|
||||
[app.main.ui.workspace.viewport.gradients :as gradients]
|
||||
|
@ -41,85 +42,7 @@
|
|||
[app.main.ui.workspace.viewport.widgets :as widgets]
|
||||
[beicon.core :as rx]
|
||||
[debug :refer [debug?]]
|
||||
[rumext.v2 :as mf]
|
||||
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.layout :as gsl]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.store :as st]
|
||||
|
||||
))
|
||||
|
||||
(mf/defc debug-layout
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
||||
(let [shape (unchecked-get props "shape")
|
||||
objects (unchecked-get props "objects")
|
||||
children (cph/get-immediate-children objects (:id shape))
|
||||
layout-data (gsl/calc-layout-data shape children)
|
||||
drop-areas (gsl/drop-areas shape layout-data children)]
|
||||
|
||||
[:g.debug-layout {:pointer-events "none"}
|
||||
(for [[idx drop-area] (d/enumerate drop-areas)]
|
||||
[:rect {:x (:x drop-area)
|
||||
:y (:y drop-area)
|
||||
:width (:width drop-area)
|
||||
:height (:height drop-area)
|
||||
:style {:fill "blue"
|
||||
:fill-opacity 0.3
|
||||
:stroke "red"
|
||||
:stroke-width 1
|
||||
:stroke-dasharray "3 6"}}])
|
||||
|
||||
|
||||
#_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))]
|
||||
(let [col? (gsl/col? shape)
|
||||
row? (gsl/row? shape)
|
||||
h-center? (and row? (gsl/h-center? shape))
|
||||
h-end? (and row? (gsl/h-end? shape))
|
||||
v-center? (and col? (gsl/v-center? shape))
|
||||
v-end? (and row? (gsl/v-end? shape))
|
||||
|
||||
line-width
|
||||
(+ (-> layout-line :line-width)
|
||||
(:margin-x shape)
|
||||
(if col?
|
||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
||||
0))
|
||||
|
||||
line-height
|
||||
(+ (-> layout-line :line-height)
|
||||
(:margin-y shape)
|
||||
(if row?
|
||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
||||
0))
|
||||
]
|
||||
[:g {:key (dm/str "line-" idx)}
|
||||
[:rect {:x (- (-> layout-line :start-p :x)
|
||||
(cond
|
||||
h-center? (/ line-width 2)
|
||||
h-end? line-width
|
||||
:else 0))
|
||||
:y (- (-> layout-line :start-p :y)
|
||||
(cond
|
||||
v-center? (/ line-height 2)
|
||||
v-end? line-height
|
||||
:else 0))
|
||||
:width line-width
|
||||
:height line-height
|
||||
:style {:fill "blue"
|
||||
:fill-opacity 0.3}
|
||||
}]
|
||||
#_[:line {:x1 (-> layout-line :start-p :x)
|
||||
:y1 (-> layout-line :start-p :y)
|
||||
:x2 (+ (-> layout-line :start-p :x) (if col? line-width 0))
|
||||
:y2 (+ (-> layout-line :start-p :y) (if row? line-height 0))
|
||||
:transform (gsh/transform-str shape)
|
||||
:style {:fill "none"
|
||||
:stroke "red"
|
||||
:stroke-width 2}}]]))]))
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
;; --- Viewport
|
||||
|
||||
|
@ -493,15 +416,12 @@
|
|||
:hover-frame frame-parent
|
||||
:disabled-guides? disabled-guides?}])
|
||||
|
||||
(let [selected-frame (when (= 1 (count selected-shapes))
|
||||
(let [selected-shape (get objects-modified (first selected))]
|
||||
(when (= :frame (:type selected-shape))
|
||||
selected-shape)))
|
||||
;; DEBUG LAYOUT DROP-ZONES
|
||||
(when (debug? :layout-drop-zones)
|
||||
[:& wvd/debug-layout {:selected-shapes selected-shapes
|
||||
:objects objects-modified
|
||||
:hover-top-frame-id @hover-top-frame-id}])
|
||||
|
||||
top-frame (or selected-frame (get objects-modified @hover-top-frame-id))]
|
||||
(when (and top-frame (not= uuid/zero top-frame) (:layout top-frame))
|
||||
[:& debug-layout {:shape top-frame
|
||||
:objects objects-modified}]))
|
||||
|
||||
(when show-selection-handlers?
|
||||
[:g.selection-handlers {:clipPath "url(#clip-handlers)"}
|
||||
|
|
54
frontend/src/app/main/ui/workspace/viewport/debug.cljs
Normal file
54
frontend/src/app/main/ui/workspace/viewport/debug.cljs
Normal file
|
@ -0,0 +1,54 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.workspace.viewport.debug
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.layout :as gsl]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc debug-layout
|
||||
"Debug component to show the auto-layout drop areas"
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
||||
(let [objects (unchecked-get props "objects")
|
||||
selected-shapes (unchecked-get props "selected-shapes")
|
||||
hover-top-frame-id (unchecked-get props "hover-top-frame-id")
|
||||
|
||||
selected-frame
|
||||
(when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type)))
|
||||
(first selected-shapes))
|
||||
|
||||
shape (or selected-frame (get objects hover-top-frame-id))]
|
||||
|
||||
(when (and shape (:layout shape))
|
||||
(let [children (cph/get-immediate-children objects (:id shape))
|
||||
layout-data (gsl/calc-layout-data shape children)
|
||||
drop-areas (gsl/drop-areas shape layout-data children)]
|
||||
[:g.debug-layout {:pointer-events "none"
|
||||
:transform (gsh/transform-str shape)}
|
||||
(for [[idx drop-area] (d/enumerate drop-areas)]
|
||||
[:g.drop-area {:key (dm/str "drop-area-" idx)}
|
||||
[:rect {:x (:x drop-area)
|
||||
:y (:y drop-area)
|
||||
:width (:width drop-area)
|
||||
:height (:height drop-area)
|
||||
:style {:fill "blue"
|
||||
:fill-opacity 0.3
|
||||
:stroke "red"
|
||||
:stroke-width 1
|
||||
:stroke-dasharray "3 6"}}]
|
||||
[:text {:x (:x drop-area)
|
||||
:y (:y drop-area)
|
||||
:width (:width drop-area)
|
||||
:height (:height drop-area)
|
||||
:alignment-baseline "hanging"
|
||||
:fill "black"}
|
||||
(:index drop-area)]])]))))
|
|
@ -11,6 +11,7 @@
|
|||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.shortcuts :as dsc]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.path.shortcuts :as psc]
|
||||
|
@ -28,8 +29,7 @@
|
|||
[beicon.core :as rx]
|
||||
[debug :refer [debug?]]
|
||||
[goog.events :as events]
|
||||
[rumext.v2 :as mf]
|
||||
[app.common.types.shape-tree :as ctst])
|
||||
[rumext.v2 :as mf])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
(defn setup-dom-events [viewport-ref zoom disable-paste in-viewport?]
|
||||
|
@ -217,7 +217,7 @@
|
|||
(get objects))]
|
||||
(reset! hover hover-shape)
|
||||
(reset! hover-ids ids)
|
||||
(reset! hover-top-frame-id (ctst/top-nested-frame objects (deref last-point-ref))))))))
|
||||
(reset! hover-top-frame-id (ctt/top-nested-frame objects (deref last-point-ref))))))))
|
||||
|
||||
(defn setup-viewport-modifiers
|
||||
[modifiers objects]
|
||||
|
@ -225,7 +225,7 @@
|
|||
(mf/use-memo
|
||||
(mf/deps objects)
|
||||
#(ctt/get-root-shapes-ids objects))
|
||||
modifiers (select-keys modifiers root-frame-ids)]
|
||||
modifiers (select-keys modifiers (conj root-frame-ids uuid/zero))]
|
||||
(sfd/use-dynamic-modifiers objects globals/document modifiers)))
|
||||
|
||||
(defn inside-vbox [vbox objects frame-id]
|
||||
|
|
|
@ -67,6 +67,9 @@
|
|||
|
||||
;; Disable frame thumbnails
|
||||
:disable-frame-thumbnails
|
||||
|
||||
;; Enable a widget to show the auto-layout drop-zones
|
||||
:layout-drop-zones
|
||||
})
|
||||
|
||||
;; These events are excluded when we activate the :events flag
|
||||
|
@ -294,9 +297,16 @@
|
|||
num-nodes (->> (dom/seq-nodes root-node) count)]
|
||||
#js {:number num-nodes}))
|
||||
|
||||
#_(defn modif->js
|
||||
(defn modif->js
|
||||
[modif-tree objects]
|
||||
(clj->js (into {}
|
||||
(map (fn [[k v]]
|
||||
[(get-in objects [k :name]) v]))
|
||||
modif-tree)))
|
||||
|
||||
(defn ^:export dump-modifiers
|
||||
[]
|
||||
(let [page-id (get @st/state :current-page-id)
|
||||
objects (get-in @st/state [:workspace-data :pages-index page-id :objects])]
|
||||
(.log js/console (modif->js (:workspace-modifiers @st/state) objects)))
|
||||
nil)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue