0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-08 16:00:19 -05:00

🐛 Fixes problem with inside-frame calculations

This commit is contained in:
alonso.torres 2020-10-27 16:47:08 +01:00 committed by Hirunatan
parent 4adb79e869
commit d1437997d2
11 changed files with 113 additions and 79 deletions

View file

@ -11,7 +11,6 @@
(:require
[clojure.spec.alpha :as s]
[app.common.spec :as us]
[app.common.pages-helpers :as cph]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.math :as mth]
@ -58,10 +57,17 @@
(update :points #(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
"Move the shape and all its recursive children."
[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)]
(map #(move % dpoint) (cons shape children))))

View file

@ -10,7 +10,8 @@
(ns app.common.pages-helpers
(:require
[app.common.data :as d]
[app.common.uuid :as uuid]))
[app.common.uuid :as uuid]
[app.common.geom.shapes :as gsh]))
(defn walk-pages
"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))))
(map second)
(into #{}))))
(defn frame-id-by-position [objects position]
(let [frames (select-frames objects)]
(or
(->> frames
(d/seek #(gsh/has-point? % position))
:id)
uuid/zero)))

View file

@ -549,11 +549,8 @@
unames (dwc/retrieve-used-names objects)
name (dwc/generate-unique-name unames (:name shape))
frames (cph/select-frames objects)
frame-id (if (= :frame (:type shape))
uuid/zero
(dwc/calculate-frame-overlap frames shape))
frame-id (or (:frame-id attrs)
(cph/frame-id-by-position objects attrs))
shape (merge
(if (= :frame (:type shape))
@ -561,8 +558,7 @@
cp/default-shape-attrs)
(assoc shape
:id id
:name name
:frame-id frame-id))
:name name))
rchange {:type :add-obj
:id id
@ -586,19 +582,25 @@
[(+ x (/ width 2)) (+ y (/ height 2))]))
(defn create-and-add-shape
[type data]
[type frame-x frame-y data]
(ptk/reify ::create-and-add-shape
ptk/WatchEvent
(watch [_ state stream]
(let [{:keys [width height]} data
[vbc-x vbc-y] (viewport-center state)
x (:x data (- vbc-x (/ width 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)
(merge data)
(merge {:x x :y y})
(assoc :frame-id frame-id)
(geom/setup-selrect))]
(rx/of (add-shape shape))))))
@ -1243,16 +1245,26 @@
(def copy-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
:selected selected
:objects data}))
(prepare [result objects id]
(let [obj (get objects id)]
(maybe-translate [shape objects selected]
(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 $$
(assoc $$ id obj)
(reduce #(prepare %1 objects %2) $$ (:shapes obj)))))
(reduce #(prepare %1 objects selected %2) $$ (:shapes obj)))))
(on-copy-error [error]
(js/console.error "Clipboard blocked:" error)
@ -1279,6 +1291,15 @@
wrapper (geom/selection-rect selected-objs)
orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper))
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)
page-id (:current-page-id state)
@ -1309,7 +1330,7 @@
:height height
:id (:id 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
[image]
@ -1378,12 +1399,16 @@
{:keys [x y]} @ms/mouse-position
width (min (* 7 (count text)) 700)
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
{:id id
:type :text
:name "Text"
:x x
:y y
:frame-id frame-id
:width width
:height height
:grow-type (if (> (count text) 100) :auto-height :auto-width)
@ -1391,7 +1416,6 @@
(rx/of dwc/start-undo-transaction
(dws/deselect-all)
(add-shape shape)
(dwc/rehash-shape-frame-relationship [id])
dwc/commit-undo-transaction)))))
(defn update-shape-flags

View file

@ -155,55 +155,6 @@
;; --- 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
[objects point]
(let [frames (cph/select-frames objects)]

View file

@ -241,7 +241,7 @@
objects (dwc/lookup-page-objects state page-id)
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
(fn [new-shape original-shape]
@ -255,8 +255,7 @@
(as-> $
(assoc $ :name new-name)
(geom/move $ delta)
(assoc $ :frame-id
(dwc/calculate-frame-overlap all-frames $))
(assoc $ :frame-id frame-id)
(assoc $ :parent-id
(or (:parent-id $) (:frame-id $)))
(assoc $ :shape-ref (:id original-shape))

View file

@ -304,10 +304,6 @@
renamed-obj (assoc obj :id id :name name)
moved-obj (geom/move renamed-obj delta)
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)
children-changes

View file

@ -233,6 +233,38 @@
(rx/first)
(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
([from-position] (start-move from-position nil))
([from-position ids]
@ -261,6 +293,7 @@
(rx/of (set-modifiers ids)
(apply-modifiers ids)
(calculate-frame-for-move ids)
(fn [state] (update state :workspace-local dissoc :modifiers))
finish-transform)))))))
@ -433,10 +466,8 @@
;; we have 3 different objects references).
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
(dwc/commit-changes rchanges uchanges {:commit-local? true})
(dwc/rehash-shape-frame-relationship ids)
dwc/commit-undo-transaction)))))

View file

@ -42,7 +42,7 @@
:id (:id image)
:path (:path 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
(fn [js-files]

View file

@ -70,6 +70,13 @@
:on-mouse-out on-mouse-out}
(: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
[shape-wrapper]
(let [frame-shape (frame/frame-shape shape-wrapper)]
@ -80,6 +87,11 @@
[props]
(let [shape (unchecked-get props "shape")
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))
#(refs/make-selected-ref (:id shape)))
@ -114,7 +126,9 @@
(fn []
(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")
:on-context-menu on-context-menu
:on-double-click on-double-click

View file

@ -187,6 +187,10 @@
(single? (filter #(= :group (first %)) (:delete operations)))
(-> 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
;; types (i.e: delete various shapes). If that happens we return
;; the operation with `:multiple` id

View file

@ -408,7 +408,7 @@
:id (:id image)
:path (:path 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
(fn [event]