Fix guides, grids and constraints for nested frames

This commit is contained in:
alonso.torres 2022-06-16 17:48:50 +02:00
parent 2e3f443758
commit a774f4d4fa
8 changed files with 135 additions and 93 deletions

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.spec.page :as spec.page] [app.common.spec.page :as spec.page]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@ -718,3 +719,7 @@
(defn update-object-indices (defn update-object-indices
[file page-id] [file page-id]
(update-in file [:pages-index page-id :objects] update-page-index)) (update-in file [:pages-index page-id :objects] update-page-index))
(defn rotated-frame?
[frame]
(not (mth/almost-zero? (:rotation frame 0))))

View file

@ -181,50 +181,58 @@
(assoc :grow-type :fixed)))) (assoc :grow-type :fixed))))
(defn- apply-modifiers (defn- apply-modifiers
[ids] ([ids]
(us/verify (s/coll-of uuid?) ids) (apply-modifiers ids nil))
(ptk/reify ::apply-modifiers
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
ids-with-children (into (vec ids) (mapcat #(cph/get-children-ids objects %)) ids)
object-modifiers (get state :workspace-modifiers)
shapes (map (d/getf objects) ids)
ignore-tree (->> (map #(get-ignore-tree object-modifiers objects %) shapes)
(reduce merge {}))]
(rx/of (dwu/start-undo-transaction) ([ids {:keys [undo-transation?] :or {undo-transation? true}}]
(dwg/move-frame-guides ids-with-children) (us/verify (s/coll-of uuid?) ids)
(dch/update-shapes (ptk/reify ::apply-modifiers
ids-with-children ptk/WatchEvent
(fn [shape] (watch [_ state _]
(let [modif (get object-modifiers (:id shape)) (let [objects (wsh/lookup-page-objects state)
text-shape? (cph/text-shape? shape)] ids-with-children (into (vec ids) (mapcat #(cph/get-children-ids objects %)) ids)
(-> shape object-modifiers (get state :workspace-modifiers)
(merge modif) shapes (map (d/getf objects) ids)
(gsh/transform-shape) ignore-tree (->> (map #(get-ignore-tree object-modifiers objects %) shapes)
(cond-> text-shape? (reduce merge {}))]
(update-grow-type shape)))))
{:reg-objects? true (rx/concat
:ignore-tree ignore-tree (if undo-transation?
;; Attributes that can change in the transform. This way we don't have to check (rx/of (dwu/start-undo-transaction))
;; all the attributes (rx/empty))
:attrs [:selrect (rx/of (dwg/move-frame-guides ids-with-children)
:points (dch/update-shapes
:x ids-with-children
:y (fn [shape]
:width (let [modif (get object-modifiers (:id shape))
:height text-shape? (cph/text-shape? shape)]
:content (-> shape
:transform (merge modif)
:transform-inverse (gsh/transform-shape)
:rotation (cond-> text-shape?
:position-data (update-grow-type shape)))))
:flip-x {:reg-objects? true
:flip-y :ignore-tree ignore-tree
:grow-type]}) ;; Attributes that can change in the transform. This way we don't have to check
(clear-local-transform) ;; all the attributes
(dwu/commit-undo-transaction)))))) :attrs [:selrect
:points
:x
:y
:width
:height
:content
:transform
:transform-inverse
:rotation
:position-data
:flip-x
:flip-y
:grow-type]})
(clear-local-transform))
(if undo-transation?
(rx/of (dwu/commit-undo-transaction))
(rx/empty))))))))
(defn- check-delta (defn- check-delta
"If the shape is a component instance, check its relative position respect the "If the shape is a component instance, check its relative position respect the
@ -762,9 +770,11 @@
(rx/map (partial set-modifiers ids)) (rx/map (partial set-modifiers ids))
(rx/take-until stopper)) (rx/take-until stopper))
(rx/of (calculate-frame-for-move ids) (rx/of (dwu/start-undo-transaction)
(apply-modifiers ids) (calculate-frame-for-move ids)
(finish-transform))))))))) (apply-modifiers ids {:undo-transation? false})
(finish-transform)
(dwu/commit-undo-transaction)))))))))
(s/def ::direction #{:up :down :right :left}) (s/def ::direction #{:up :down :right :left})
@ -842,6 +852,14 @@
(rx/of (set-modifiers [id] {:displacement displ} false true) (rx/of (set-modifiers [id] {:displacement displ} false true)
(apply-modifiers [id])))))) (apply-modifiers [id]))))))
(defn check-frame-move?
[target-frame-id objects position shape]
(let [current-frame (get objects (:frame-id shape))]
;; If the current frame contains the point and it's a child of the target
(and (gsh/has-point? current-frame position)
(cph/is-child? objects target-frame-id (:id current-frame)))))
(defn- calculate-frame-for-move (defn- calculate-frame-for-move
[ids] [ids]
(ptk/reify ::calculate-frame-for-move (ptk/reify ::calculate-frame-for-move
@ -855,16 +873,14 @@
moving-shapes (->> ids moving-shapes (->> ids
(cph/clean-loops objects) (cph/clean-loops objects)
(keep #(get objects %)) (keep #(get objects %))
(remove #(= (:frame-id %) frame-id))) (remove (partial check-frame-move? frame-id objects position)))
changes (-> (pcb/empty-changes it page-id) changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects) (pcb/with-objects objects)
(pcb/change-parent frame-id moving-shapes))] (pcb/change-parent frame-id moving-shapes))]
(when-not (empty? changes) (when-not (empty? changes)
(rx/of dwu/pop-undo-into-transaction (rx/of (dch/commit-changes changes)
(dch/commit-changes changes)
(dwu/commit-undo-transaction)
(dwc/expand-collapse frame-id))))))) (dwc/expand-collapse frame-id)))))))
(defn- get-displacement (defn- get-displacement

View file

@ -191,7 +191,6 @@
has-group? (->> shapes (d/seek #(= :group (:type %)))) has-group? (->> shapes (d/seek #(= :group (:type %))))
has-bool? (->> shapes (d/seek #(= :bool (:type %)))) has-bool? (->> shapes (d/seek #(= :bool (:type %))))
has-mask? (->> shapes (d/seek :masked-group?)) has-mask? (->> shapes (d/seek :masked-group?))
has-frame? (->> shapes (d/seek #(= :frame (:type %))))
is-group? (and single? has-group?) is-group? (and single? has-group?)
is-bool? (and single? has-bool?) is-bool? (and single? has-bool?)
@ -207,10 +206,9 @@
:shortcut (sc/get-tooltip :ungroup) :shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}]) :on-click do-remove-group}])
(when (not has-frame?) [:& menu-entry {:title (tr "workspace.shape.menu.group")
[:& menu-entry {:title (tr "workspace.shape.menu.group") :shortcut (sc/get-tooltip :group)
:shortcut (sc/get-tooltip :group) :on-click do-create-group}]
:on-click do-create-group}])
(when (or multiple? (and is-group? (not has-mask?)) is-bool?) (when (or multiple? (and is-group? (not has-mask?)) is-bool?)
[:& menu-entry {:title (tr "workspace.shape.menu.mask") [:& menu-entry {:title (tr "workspace.shape.menu.mask")
@ -222,12 +220,10 @@
:shortcut (sc/get-tooltip :unmask) :shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}]) :on-click do-unmask-group}])
(when (not has-frame?) [:& menu-entry {:title (tr "workspace.shape.menu.create-artboard-from-selection")
[:* :shortcut (sc/get-tooltip :artboard-selection)
[:& menu-entry {:title (tr "workspace.shape.menu.create-artboard-from-selection") :on-click do-create-artboard-from-selection}]
:shortcut (sc/get-tooltip :artboard-selection) [:& menu-separator]]))
:on-click do-create-artboard-from-selection}]
[:& menu-separator]])]))
(mf/defc context-focus-mode-menu (mf/defc context-focus-mode-menu
[{:keys []}] [{:keys []}]

View file

@ -8,6 +8,7 @@
(:require (:require
[app.main.constants :refer [has-layout-item]] [app.main.constants :refer [has-layout-item]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs-shape fill-menu]] [app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs-shape fill-menu]]
[app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid]] [app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid]]
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]] [app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
@ -25,6 +26,7 @@
stroke-values (select-keys shape stroke-attrs) stroke-values (select-keys shape stroke-attrs)
layer-values (select-keys shape layer-attrs) layer-values (select-keys shape layer-attrs)
measure-values (select-keys shape measure-attrs) measure-values (select-keys shape measure-attrs)
constraint-values (select-keys shape constraint-attrs)
layout-values (select-keys shape layout-attrs) layout-values (select-keys shape layout-attrs)
layout-item-values (select-keys shape layout-item-attrs)] layout-item-values (select-keys shape layout-item-attrs)]
[:* [:*
@ -32,6 +34,8 @@
:values measure-values :values measure-values
:type type :type type
:shape shape}] :shape shape}]
[:& constraints-menu {:ids ids
:values constraint-values}]
(when has-layout-item (when has-layout-item
[:& layout-menu {:type type :ids [(:id shape)] :values layout-values}]) [:& layout-menu {:type type :ids [(:id shape)] :values layout-values}])

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.helpers :as cph]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.util.geom.grid :as gg] [app.util.geom.grid :as gg]
@ -126,13 +127,15 @@
(mf/defc frame-grid (mf/defc frame-grid
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [zoom transform selected focus]}] [{:keys [zoom transform selected focus]}]
(let [frames (mf/deref refs/workspace-frames) (let [frames (mf/deref refs/workspace-frames)
moving (when (= :move transform) selected) transforming (when (some? transform) selected)
is-moving? #(contains? moving (:id %))] is-transform? #(contains? transforming (:id %))]
[:g.grid-display {:style {:pointer-events "none"}} [:g.grid-display {:style {:pointer-events "none"}}
(for [frame (remove is-moving? frames)] (for [frame frames]
(when (or (empty? focus) (contains? focus (:id frame))) (when (and (not (is-transform? frame))
(not (cph/rotated-frame? frame))
(or (empty? focus) (contains? focus (:id frame))))
[:& grid-display-frame {:key (str "grid-" (:id frame)) [:& grid-display-frame {:key (str "grid-" (:id frame))
:zoom zoom :zoom zoom
:frame (gsh/transform-shape frame)}]))])) :frame (gsh/transform-shape frame)}]))]))

View file

@ -10,6 +10,7 @@
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.helpers :as cph]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -286,8 +287,9 @@
guide-pill-corner-radius (/ guide-pill-corner-radius zoom)] guide-pill-corner-radius (/ guide-pill-corner-radius zoom)]
(when (or (nil? frame) (when (or (nil? frame)
(is-guide-inside-frame? (assoc guide :position pos) frame) (and (is-guide-inside-frame? (assoc guide :position pos) frame)
(:hover @state true)) (cph/root-frame? frame)
(not (cph/rotated-frame? frame))))
[:g.guide-area [:g.guide-area
(when-not disabled-guides? (when-not disabled-guides?
(let [{:keys [x y width height]} (guide-area-axis pos vbox zoom frame axis)] (let [{:keys [x y width height]} (guide-area-axis pos vbox zoom frame axis)]

View file

@ -7,7 +7,8 @@
(ns app.util.geom.snap-points (ns app.util.geom.snap-points
(:require (:require
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh])) [app.common.geom.shapes :as gsh]
[app.common.pages.helpers :as cph]))
(defn selrect-snap-points [{:keys [x y width height] :as selrect}] (defn selrect-snap-points [{:keys [x y width height] :as selrect}]
#{(gpt/point x y) #{(gpt/point x y)
@ -29,11 +30,20 @@
(when (and (not blocked) (not hidden)) (when (and (not blocked) (not hidden))
(let [shape (gsh/transform-shape shape)] (let [shape (gsh/transform-shape shape)]
(case (:type shape) (case (:type shape)
:frame (-> shape :selrect frame-snap-points) :frame (-> shape :points gsh/points->selrect frame-snap-points)
(into #{(gsh/center-shape shape)} (:points shape)))))) (into #{(gsh/center-shape shape)} (:points shape))))))
(defn guide-snap-points (defn guide-snap-points
[guide] [guide frame]
(if (= :x (:axis guide))
(cond
(and (some? frame)
(not (cph/rotated-frame? frame))
(not (cph/root-frame? frame)))
#{}
(= :x (:axis guide))
#{(gpt/point (:position guide) 0)} #{(gpt/point (:position guide) 0)}
:else
#{(gpt/point 0 (:position guide))})) #{(gpt/point 0 (:position guide))}))

View file

@ -55,16 +55,18 @@
(defn get-grids-snap-points (defn get-grids-snap-points
[frame coord] [frame coord]
(let [grid->snap (fn [[grid-type position]] (if (not (cph/rotated-frame? frame))
{:type :layout []
:id (:id frame) (let [grid->snap (fn [[grid-type position]]
:grid grid-type {:type :layout
:pt position})] :id (:id frame)
(->> (:grids frame) :grid grid-type
(mapcat (fn [grid] :pt position})]
(->> (gg/grid-snap-points frame grid coord) (->> (:grids frame)
(mapv #(vector (:type grid) %))))) (mapcat (fn [grid]
(mapv grid->snap)))) (->> (gg/grid-snap-points frame grid coord)
(mapv #(vector (:type grid) %)))))
(mapv grid->snap)))))
(defn- add-frame (defn- add-frame
[page-data frame] [page-data frame]
@ -105,9 +107,10 @@
(defn- add-guide (defn- add-guide
[page-data guide] [objects page-data guide]
(let [guide-data (->> (snap/guide-snap-points guide) (let [frame (get objects (:frame-id guide))
guide-data (->> (snap/guide-snap-points guide frame)
(mapv #(array-map (mapv #(array-map
:type :guide :type :guide
:id (:id guide) :id (:id guide)
@ -178,10 +181,10 @@
(add-shape new-shape))) (add-shape new-shape)))
(defn- update-guide (defn- update-guide
[page-data [old-guide new-guide]] [objects page-data [old-guide new-guide]]
(-> page-data (as-> page-data $
(remove-guide old-guide) (remove-guide $ old-guide)
(add-guide new-guide))) (add-guide objects $ new-guide)))
;; PUBLIC API ;; PUBLIC API
@ -203,7 +206,7 @@
(add-root-frame $) (add-root-frame $)
(reduce add-frame $ frames) (reduce add-frame $ frames)
(reduce add-shape $ shapes) (reduce add-shape $ shapes)
(reduce add-guide $ guides))] (reduce (partial add-guide objects) $ guides))]
(assoc snap-data (:id page) page-data))) (assoc snap-data (:id page) page-data)))
(defn update-page (defn update-page
@ -214,7 +217,8 @@
;; Update page ;; Update page
(update snap-data (:id page) (update snap-data (:id page)
(fn [page-data] (fn [page-data]
(let [{:keys [change-frame-shapes (let [{:keys [objects]} page
{:keys [change-frame-shapes
change-frame-guides change-frame-guides
removed-frames removed-frames
removed-shapes removed-shapes
@ -235,10 +239,12 @@
(reduce update-shape $ updated-shapes) (reduce update-shape $ updated-shapes)
(reduce add-frame $ new-frames) (reduce add-frame $ new-frames)
(reduce add-shape $ new-shapes) (reduce add-shape $ new-shapes)
(reduce update-guide $ change-frame-guides)
(reduce remove-guide $ removed-guides) (reduce remove-guide $ removed-guides)
(reduce update-guide $ updated-guides)
(reduce add-guide $ new-guides))))) ;; Guides functions. Need objects to get its frame data
(reduce (partial update-guide objects) $ change-frame-guides)
(reduce (partial update-guide objects) $ updated-guides)
(reduce (partial add-guide objects) $ new-guides)))))
;; Page doesn't exist, we create a new entry ;; Page doesn't exist, we create a new entry
(add-page snap-data page))) (add-page snap-data page)))