0
Fork 0
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:
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 (: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))))

View file

@ -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)))

View file

@ -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

View file

@ -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)]

View file

@ -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))

View file

@ -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

View file

@ -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)))))

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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]