mirror of
https://github.com/penpot/penpot.git
synced 2025-02-03 04:49:03 -05:00
🐛 Fixes problem with inside-frame calculations
This commit is contained in:
parent
4adb79e869
commit
d1437997d2
11 changed files with 113 additions and 79 deletions
|
@ -11,7 +11,6 @@
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.pages-helpers :as cph]
|
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
|
@ -58,10 +57,17 @@
|
||||||
(update :points #(mapv inc-point %))
|
(update :points #(mapv inc-point %))
|
||||||
(update :segments #(mapv inc-point %)))))
|
(update :segments #(mapv inc-point %)))))
|
||||||
|
|
||||||
|
;; Duplicated from pages-helpers to remove cyclic dependencies
|
||||||
|
(defn get-children [id objects]
|
||||||
|
(let [shapes (vec (get-in objects [id :shapes]))]
|
||||||
|
(if shapes
|
||||||
|
(d/concat shapes (mapcat #(get-children % objects) shapes))
|
||||||
|
[])))
|
||||||
|
|
||||||
(defn recursive-move
|
(defn recursive-move
|
||||||
"Move the shape and all its recursive children."
|
"Move the shape and all its recursive children."
|
||||||
[shape dpoint objects]
|
[shape dpoint objects]
|
||||||
(let [children-ids (cph/get-children (:id shape) objects)
|
(let [children-ids (get-children (:id shape) objects)
|
||||||
children (map #(get objects %) children-ids)]
|
children (map #(get objects %) children-ids)]
|
||||||
(map #(move % dpoint) (cons shape children))))
|
(map #(move % dpoint) (cons shape children))))
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
(ns app.common.pages-helpers
|
(ns app.common.pages-helpers
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.uuid :as uuid]))
|
[app.common.uuid :as uuid]
|
||||||
|
[app.common.geom.shapes :as gsh]))
|
||||||
|
|
||||||
(defn walk-pages
|
(defn walk-pages
|
||||||
"Go through all pages of a file and apply a function to each one"
|
"Go through all pages of a file and apply a function to each one"
|
||||||
|
@ -247,3 +248,11 @@
|
||||||
(filter (fn [[idx _]] (and (>= idx from) (<= idx to))))
|
(filter (fn [[idx _]] (and (>= idx from) (<= idx to))))
|
||||||
(map second)
|
(map second)
|
||||||
(into #{}))))
|
(into #{}))))
|
||||||
|
|
||||||
|
(defn frame-id-by-position [objects position]
|
||||||
|
(let [frames (select-frames objects)]
|
||||||
|
(or
|
||||||
|
(->> frames
|
||||||
|
(d/seek #(gsh/has-point? % position))
|
||||||
|
:id)
|
||||||
|
uuid/zero)))
|
||||||
|
|
|
@ -549,11 +549,8 @@
|
||||||
unames (dwc/retrieve-used-names objects)
|
unames (dwc/retrieve-used-names objects)
|
||||||
name (dwc/generate-unique-name unames (:name shape))
|
name (dwc/generate-unique-name unames (:name shape))
|
||||||
|
|
||||||
frames (cph/select-frames objects)
|
frame-id (or (:frame-id attrs)
|
||||||
|
(cph/frame-id-by-position objects attrs))
|
||||||
frame-id (if (= :frame (:type shape))
|
|
||||||
uuid/zero
|
|
||||||
(dwc/calculate-frame-overlap frames shape))
|
|
||||||
|
|
||||||
shape (merge
|
shape (merge
|
||||||
(if (= :frame (:type shape))
|
(if (= :frame (:type shape))
|
||||||
|
@ -561,8 +558,7 @@
|
||||||
cp/default-shape-attrs)
|
cp/default-shape-attrs)
|
||||||
(assoc shape
|
(assoc shape
|
||||||
:id id
|
:id id
|
||||||
:name name
|
:name name))
|
||||||
:frame-id frame-id))
|
|
||||||
|
|
||||||
rchange {:type :add-obj
|
rchange {:type :add-obj
|
||||||
:id id
|
:id id
|
||||||
|
@ -586,19 +582,25 @@
|
||||||
[(+ x (/ width 2)) (+ y (/ height 2))]))
|
[(+ x (/ width 2)) (+ y (/ height 2))]))
|
||||||
|
|
||||||
(defn create-and-add-shape
|
(defn create-and-add-shape
|
||||||
[type data]
|
[type frame-x frame-y data]
|
||||||
(ptk/reify ::create-and-add-shape
|
(ptk/reify ::create-and-add-shape
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [{:keys [width height]} data
|
(let [{:keys [width height]} data
|
||||||
|
|
||||||
[vbc-x vbc-y] (viewport-center state)
|
[vbc-x vbc-y] (viewport-center state)
|
||||||
|
|
||||||
x (:x data (- vbc-x (/ width 2)))
|
x (:x data (- vbc-x (/ width 2)))
|
||||||
y (:y data (- vbc-y (/ height 2)))
|
y (:y data (- vbc-y (/ height 2)))
|
||||||
|
|
||||||
|
page-id (:current-page-id state)
|
||||||
|
frame-id (-> (dwc/lookup-page-objects state page-id)
|
||||||
|
(cph/frame-id-by-position {:x frame-x :y frame-y}))
|
||||||
|
|
||||||
shape (-> (cp/make-minimal-shape type)
|
shape (-> (cp/make-minimal-shape type)
|
||||||
(merge data)
|
(merge data)
|
||||||
(merge {:x x :y y})
|
(merge {:x x :y y})
|
||||||
|
(assoc :frame-id frame-id)
|
||||||
(geom/setup-selrect))]
|
(geom/setup-selrect))]
|
||||||
(rx/of (add-shape shape))))))
|
(rx/of (add-shape shape))))))
|
||||||
|
|
||||||
|
@ -1243,16 +1245,26 @@
|
||||||
|
|
||||||
(def copy-selected
|
(def copy-selected
|
||||||
(letfn [(prepare-selected [objects selected]
|
(letfn [(prepare-selected [objects selected]
|
||||||
(let [data (reduce #(prepare %1 objects %2) {} selected)]
|
(let [data (reduce #(prepare %1 objects selected %2) {} selected)]
|
||||||
{:type :copied-shapes
|
{:type :copied-shapes
|
||||||
:selected selected
|
:selected selected
|
||||||
:objects data}))
|
:objects data}))
|
||||||
|
|
||||||
(prepare [result objects id]
|
(maybe-translate [shape objects selected]
|
||||||
(let [obj (get objects id)]
|
(if (and (not= (:type shape) :frame)
|
||||||
|
(not (contains? selected (:frame-id shape))))
|
||||||
|
;; When the parent frame is not selected we change to relative
|
||||||
|
;; coordinates
|
||||||
|
(let [frame (get objects (:frame-id shape))]
|
||||||
|
(geom/translate-to-frame shape frame))
|
||||||
|
shape))
|
||||||
|
|
||||||
|
(prepare [result objects selected id]
|
||||||
|
(let [obj (-> (get objects id)
|
||||||
|
(maybe-translate objects selected))]
|
||||||
(as-> result $$
|
(as-> result $$
|
||||||
(assoc $$ id obj)
|
(assoc $$ id obj)
|
||||||
(reduce #(prepare %1 objects %2) $$ (:shapes obj)))))
|
(reduce #(prepare %1 objects selected %2) $$ (:shapes obj)))))
|
||||||
|
|
||||||
(on-copy-error [error]
|
(on-copy-error [error]
|
||||||
(js/console.error "Clipboard blocked:" error)
|
(js/console.error "Clipboard blocked:" error)
|
||||||
|
@ -1279,6 +1291,15 @@
|
||||||
wrapper (geom/selection-rect selected-objs)
|
wrapper (geom/selection-rect selected-objs)
|
||||||
orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper))
|
orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper))
|
||||||
mouse-pos @ms/mouse-position
|
mouse-pos @ms/mouse-position
|
||||||
|
|
||||||
|
page-id (:current-page-id state)
|
||||||
|
frame-id (-> (dwc/lookup-page-objects state page-id)
|
||||||
|
(cph/frame-id-by-position mouse-pos))
|
||||||
|
|
||||||
|
objects (d/mapm (fn [_ v] (assoc v
|
||||||
|
:frame-id frame-id
|
||||||
|
:parent-id frame-id)) objects)
|
||||||
|
|
||||||
delta (gpt/subtract mouse-pos orig-pos)
|
delta (gpt/subtract mouse-pos orig-pos)
|
||||||
|
|
||||||
page-id (:current-page-id state)
|
page-id (:current-page-id state)
|
||||||
|
@ -1309,7 +1330,7 @@
|
||||||
:height height
|
:height height
|
||||||
:id (:id image)
|
:id (:id image)
|
||||||
:path (:path image)}}]
|
:path (:path image)}}]
|
||||||
(st/emit! (create-and-add-shape :image shape))))
|
(st/emit! (create-and-add-shape :image x y shape))))
|
||||||
|
|
||||||
(defn- paste-image-impl
|
(defn- paste-image-impl
|
||||||
[image]
|
[image]
|
||||||
|
@ -1378,12 +1399,16 @@
|
||||||
{:keys [x y]} @ms/mouse-position
|
{:keys [x y]} @ms/mouse-position
|
||||||
width (min (* 7 (count text)) 700)
|
width (min (* 7 (count text)) 700)
|
||||||
height 16
|
height 16
|
||||||
|
page-id (:current-page-id state)
|
||||||
|
frame-id (-> (dwc/lookup-page-objects state page-id)
|
||||||
|
(cph/frame-id-by-position @ms/mouse-position))
|
||||||
shape (geom/setup-selrect
|
shape (geom/setup-selrect
|
||||||
{:id id
|
{:id id
|
||||||
:type :text
|
:type :text
|
||||||
:name "Text"
|
:name "Text"
|
||||||
:x x
|
:x x
|
||||||
:y y
|
:y y
|
||||||
|
:frame-id frame-id
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:grow-type (if (> (count text) 100) :auto-height :auto-width)
|
:grow-type (if (> (count text) 100) :auto-height :auto-width)
|
||||||
|
@ -1391,7 +1416,6 @@
|
||||||
(rx/of dwc/start-undo-transaction
|
(rx/of dwc/start-undo-transaction
|
||||||
(dws/deselect-all)
|
(dws/deselect-all)
|
||||||
(add-shape shape)
|
(add-shape shape)
|
||||||
(dwc/rehash-shape-frame-relationship [id])
|
|
||||||
dwc/commit-undo-transaction)))))
|
dwc/commit-undo-transaction)))))
|
||||||
|
|
||||||
(defn update-shape-flags
|
(defn update-shape-flags
|
||||||
|
|
|
@ -155,55 +155,6 @@
|
||||||
|
|
||||||
;; --- Common Helpers & Events
|
;; --- Common Helpers & Events
|
||||||
|
|
||||||
(defn- calculate-frame-overlap
|
|
||||||
[frames shape]
|
|
||||||
(let [xf (comp
|
|
||||||
(filter #(geom/overlaps? % (:selrect shape)))
|
|
||||||
(take 1))
|
|
||||||
frame (first (into [] xf frames))]
|
|
||||||
(or (:id frame) uuid/zero)))
|
|
||||||
|
|
||||||
(defn- calculate-shape-to-frame-relationship-changes
|
|
||||||
[page-id frames shapes]
|
|
||||||
(loop [shape (first shapes)
|
|
||||||
shapes (rest shapes)
|
|
||||||
rch []
|
|
||||||
uch []]
|
|
||||||
(if (nil? shape)
|
|
||||||
[rch uch]
|
|
||||||
(let [fid (calculate-frame-overlap frames shape)]
|
|
||||||
(if (not= fid (:frame-id shape))
|
|
||||||
(recur (first shapes)
|
|
||||||
(rest shapes)
|
|
||||||
(conj rch {:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id fid
|
|
||||||
:shapes [(:id shape)]})
|
|
||||||
(conj uch {:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id (:frame-id shape)
|
|
||||||
:shapes [(:id shape)]}))
|
|
||||||
(recur (first shapes)
|
|
||||||
(rest shapes)
|
|
||||||
rch
|
|
||||||
uch))))))
|
|
||||||
|
|
||||||
(defn rehash-shape-frame-relationship
|
|
||||||
[ids]
|
|
||||||
(ptk/reify ::rehash-shape-frame-relationship
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [page-id (:current-page-id state)
|
|
||||||
objects (lookup-page-objects state page-id)
|
|
||||||
|
|
||||||
shapes (cph/select-toplevel-shapes objects)
|
|
||||||
frames (cph/select-frames objects)
|
|
||||||
|
|
||||||
[rch uch] (calculate-shape-to-frame-relationship-changes page-id frames shapes)]
|
|
||||||
(when-not (empty? rch)
|
|
||||||
(rx/of (commit-changes rch uch {:commit-local? true})))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-frame-at-point
|
(defn get-frame-at-point
|
||||||
[objects point]
|
[objects point]
|
||||||
(let [frames (cph/select-frames objects)]
|
(let [frames (cph/select-frames objects)]
|
||||||
|
|
|
@ -241,7 +241,7 @@
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
unames (atom (dwc/retrieve-used-names objects))
|
unames (atom (dwc/retrieve-used-names objects))
|
||||||
|
|
||||||
all-frames (cph/select-frames objects)
|
frame-id (cph/frame-id-by-position objects (gpt/add orig-pos delta))
|
||||||
|
|
||||||
update-new-shape
|
update-new-shape
|
||||||
(fn [new-shape original-shape]
|
(fn [new-shape original-shape]
|
||||||
|
@ -255,8 +255,7 @@
|
||||||
(as-> $
|
(as-> $
|
||||||
(assoc $ :name new-name)
|
(assoc $ :name new-name)
|
||||||
(geom/move $ delta)
|
(geom/move $ delta)
|
||||||
(assoc $ :frame-id
|
(assoc $ :frame-id frame-id)
|
||||||
(dwc/calculate-frame-overlap all-frames $))
|
|
||||||
(assoc $ :parent-id
|
(assoc $ :parent-id
|
||||||
(or (:parent-id $) (:frame-id $)))
|
(or (:parent-id $) (:frame-id $)))
|
||||||
(assoc $ :shape-ref (:id original-shape))
|
(assoc $ :shape-ref (:id original-shape))
|
||||||
|
|
|
@ -304,10 +304,6 @@
|
||||||
renamed-obj (assoc obj :id id :name name)
|
renamed-obj (assoc obj :id id :name name)
|
||||||
moved-obj (geom/move renamed-obj delta)
|
moved-obj (geom/move renamed-obj delta)
|
||||||
frames (cph/select-frames objects)
|
frames (cph/select-frames objects)
|
||||||
frame-id (if frame-id
|
|
||||||
frame-id
|
|
||||||
(dwc/calculate-frame-overlap frames moved-obj))
|
|
||||||
|
|
||||||
parent-id (or parent-id frame-id)
|
parent-id (or parent-id frame-id)
|
||||||
|
|
||||||
children-changes
|
children-changes
|
||||||
|
|
|
@ -233,6 +233,38 @@
|
||||||
(rx/first)
|
(rx/first)
|
||||||
(rx/map #(start-move from-position))))))
|
(rx/map #(start-move from-position))))))
|
||||||
|
|
||||||
|
(defn calculate-frame-for-move [ids]
|
||||||
|
(ptk/reify ::calculate-frame-for-move
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [position @ms/mouse-position
|
||||||
|
page-id (:current-page-id state)
|
||||||
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
|
frame-id (cph/frame-id-by-position objects position)
|
||||||
|
|
||||||
|
moving-shapes (->> ids
|
||||||
|
(map #(get objects %))
|
||||||
|
(remove #(= (:frame-id %) frame-id)))
|
||||||
|
|
||||||
|
rch [{:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id frame-id
|
||||||
|
:shapes (mapv :id moving-shapes)}]
|
||||||
|
|
||||||
|
moving-shapes-by-frame-id (group-by :frame-id moving-shapes)
|
||||||
|
|
||||||
|
uch (->> moving-shapes-by-frame-id
|
||||||
|
(mapv (fn [[frame-id shapes]]
|
||||||
|
{:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id frame-id
|
||||||
|
:shapes (mapv :id shapes)})))]
|
||||||
|
|
||||||
|
(when-not (empty? rch)
|
||||||
|
(rx/of dwc/pop-undo-into-transaction
|
||||||
|
(dwc/commit-changes rch uch {:commit-local? true})
|
||||||
|
dwc/commit-undo-transaction))))))
|
||||||
|
|
||||||
(defn start-move
|
(defn start-move
|
||||||
([from-position] (start-move from-position nil))
|
([from-position] (start-move from-position nil))
|
||||||
([from-position ids]
|
([from-position ids]
|
||||||
|
@ -261,6 +293,7 @@
|
||||||
|
|
||||||
(rx/of (set-modifiers ids)
|
(rx/of (set-modifiers ids)
|
||||||
(apply-modifiers ids)
|
(apply-modifiers ids)
|
||||||
|
(calculate-frame-for-move ids)
|
||||||
(fn [state] (update state :workspace-local dissoc :modifiers))
|
(fn [state] (update state :workspace-local dissoc :modifiers))
|
||||||
finish-transform)))))))
|
finish-transform)))))))
|
||||||
|
|
||||||
|
@ -433,10 +466,8 @@
|
||||||
;; we have 3 different objects references).
|
;; we have 3 different objects references).
|
||||||
|
|
||||||
rchanges (conj (dwc/generate-changes page-id objects1 objects2) regchg)
|
rchanges (conj (dwc/generate-changes page-id objects1 objects2) regchg)
|
||||||
uchanges (conj (dwc/generate-changes page-id objects2 objects0) regchg)
|
uchanges (conj (dwc/generate-changes page-id objects2 objects0) regchg)]
|
||||||
]
|
|
||||||
|
|
||||||
(rx/of dwc/start-undo-transaction
|
(rx/of dwc/start-undo-transaction
|
||||||
(dwc/commit-changes rchanges uchanges {:commit-local? true})
|
(dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||||
(dwc/rehash-shape-frame-relationship ids)
|
|
||||||
dwc/commit-undo-transaction)))))
|
dwc/commit-undo-transaction)))))
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
:id (:id image)
|
:id (:id image)
|
||||||
:path (:path image)}}
|
:path (:path image)}}
|
||||||
aspect-ratio (/ (:width image) (:height image))]
|
aspect-ratio (/ (:width image) (:height image))]
|
||||||
(st/emit! (dw/create-and-add-shape :image shape))))
|
(st/emit! (dw/create-and-add-shape :image 0 0 shape))))
|
||||||
|
|
||||||
on-files-selected
|
on-files-selected
|
||||||
(fn [js-files]
|
(fn [js-files]
|
||||||
|
|
|
@ -70,6 +70,13 @@
|
||||||
:on-mouse-out on-mouse-out}
|
:on-mouse-out on-mouse-out}
|
||||||
(:name frame)]))
|
(:name frame)]))
|
||||||
|
|
||||||
|
(defn make-is-moving-ref
|
||||||
|
[id]
|
||||||
|
(let [check-moving (fn [local]
|
||||||
|
(and (= :move (:transform local))
|
||||||
|
(contains? (:selected local) id)))]
|
||||||
|
(l/derived check-moving refs/workspace-local)))
|
||||||
|
|
||||||
(defn frame-wrapper-factory
|
(defn frame-wrapper-factory
|
||||||
[shape-wrapper]
|
[shape-wrapper]
|
||||||
(let [frame-shape (frame/frame-shape shape-wrapper)]
|
(let [frame-shape (frame/frame-shape shape-wrapper)]
|
||||||
|
@ -80,6 +87,11 @@
|
||||||
[props]
|
[props]
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
objects (unchecked-get props "objects")
|
objects (unchecked-get props "objects")
|
||||||
|
ghost? (unchecked-get props "ghost?")
|
||||||
|
|
||||||
|
moving-iref (mf/use-memo (mf/deps (:id shape))
|
||||||
|
#(make-is-moving-ref (:id shape)))
|
||||||
|
moving? (mf/deref moving-iref)
|
||||||
|
|
||||||
selected-iref (mf/use-memo (mf/deps (:id shape))
|
selected-iref (mf/use-memo (mf/deps (:id shape))
|
||||||
#(refs/make-selected-ref (:id shape)))
|
#(refs/make-selected-ref (:id shape)))
|
||||||
|
@ -114,7 +126,9 @@
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dws/change-hover-state (:id shape) false))))]
|
(st/emit! (dws/change-hover-state (:id shape) false))))]
|
||||||
|
|
||||||
(when-not (:hidden shape)
|
(when (and shape
|
||||||
|
(or ghost? (not moving?))
|
||||||
|
(not (:hidden shape)))
|
||||||
[:g {:class (when selected? "selected")
|
[:g {:class (when selected? "selected")
|
||||||
:on-context-menu on-context-menu
|
:on-context-menu on-context-menu
|
||||||
:on-double-click on-double-click
|
:on-double-click on-double-click
|
||||||
|
|
|
@ -187,6 +187,10 @@
|
||||||
(single? (filter #(= :group (first %)) (:delete operations)))
|
(single? (filter #(= :group (first %)) (:delete operations)))
|
||||||
(-> entries (get (first (filter #(= :group (first %)) (:delete operations)))) (last))
|
(-> entries (get (first (filter #(= :group (first %)) (:delete operations)))) (last))
|
||||||
|
|
||||||
|
;; If there is a move of shapes will have priority
|
||||||
|
(single? (:move operations))
|
||||||
|
(-> entries (get (first (:move operations))) (last))
|
||||||
|
|
||||||
;; Otherwise we could have the same operation between several
|
;; Otherwise we could have the same operation between several
|
||||||
;; types (i.e: delete various shapes). If that happens we return
|
;; types (i.e: delete various shapes). If that happens we return
|
||||||
;; the operation with `:multiple` id
|
;; the operation with `:multiple` id
|
||||||
|
|
|
@ -408,7 +408,7 @@
|
||||||
:id (:id image)
|
:id (:id image)
|
||||||
:path (:path image)}}
|
:path (:path image)}}
|
||||||
aspect-ratio (/ (:width image) (:height image))]
|
aspect-ratio (/ (:width image) (:height image))]
|
||||||
(st/emit! (dw/create-and-add-shape :image shape))))
|
(st/emit! (dw/create-and-add-shape :image x y shape))))
|
||||||
|
|
||||||
on-drop
|
on-drop
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
|
Loading…
Add table
Reference in a new issue