mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 07:41:43 -05:00
✨ Adds ungroup shapes
This commit is contained in:
parent
f79e902762
commit
a3a889339b
3 changed files with 96 additions and 37 deletions
|
@ -27,3 +27,43 @@
|
||||||
|
|
||||||
shapes (remove #(= (:type %) :frame) (vals objects))]
|
shapes (remove #(= (:type %) :frame) (vals objects))]
|
||||||
(some contains-shape-fn shapes)))
|
(some contains-shape-fn shapes)))
|
||||||
|
|
||||||
|
(defn get-parent
|
||||||
|
"Retrieve the id of the parent for the shape-id (if exists"
|
||||||
|
[shape-id objects]
|
||||||
|
(let [check-parenthood
|
||||||
|
(fn [shape] (when (and (:shapes shape)
|
||||||
|
((set (:shapes shape)) shape-id))
|
||||||
|
(:id shape)))]
|
||||||
|
(some check-parenthood (vals objects))))
|
||||||
|
|
||||||
|
(defn replace-shapes
|
||||||
|
"Replace inside shapes the value `to-replace-id` for the value in items keeping the same order.
|
||||||
|
`to-replace-id` can be a set, a sequable or a single value. Any of these will be changed into a
|
||||||
|
set to make the replacement"
|
||||||
|
[shape to-replace-id items]
|
||||||
|
(let [should-replace
|
||||||
|
(cond
|
||||||
|
(set? to-replace-id) to-replace-id
|
||||||
|
(seqable? to-replace-id) (set to-replace-id)
|
||||||
|
:else #{to-replace-id})
|
||||||
|
|
||||||
|
;; This function replaces the first ocurrence of the set `should-replace` for the
|
||||||
|
;; value in `items`. Next elements that match are removed but not replaced again
|
||||||
|
;; so for example:
|
||||||
|
;; should-replace = #{2 3 5}
|
||||||
|
;; (replace-fn [ 1 2 3 4 5] ["a" "b"] [])
|
||||||
|
;; => [ 1 "a" "b" 4 ]
|
||||||
|
replace-fn
|
||||||
|
(fn [to-replace acc shapes]
|
||||||
|
(if (empty? shapes)
|
||||||
|
acc
|
||||||
|
(let [cur (first shapes)
|
||||||
|
rest (subvec shapes 1)]
|
||||||
|
(if (should-replace cur)
|
||||||
|
(recur [] (into acc to-replace) rest)
|
||||||
|
(recur to-replace (conj acc cur) rest)))))
|
||||||
|
|
||||||
|
replace-shapes (partial replace-fn (if (seqable? items) items [items]) [])]
|
||||||
|
|
||||||
|
(update shape :shapes replace-shapes)))
|
||||||
|
|
|
@ -2192,52 +2192,71 @@
|
||||||
(defn create-group []
|
(defn create-group []
|
||||||
(let [id (uuid/next)]
|
(let [id (uuid/next)]
|
||||||
(ptk/reify ::create-group
|
(ptk/reify ::create-group
|
||||||
ptk/UpdateEvent
|
ptk/WatchEvent
|
||||||
(update [_ state]
|
(watch [_ state stream]
|
||||||
(let [selected (get-in state [:workspace-local :selected])]
|
(let [selected (get-in state [:workspace-local :selected])]
|
||||||
(if (and selected (-> selected count (> 1)))
|
(if (not-empty selected)
|
||||||
(let [page-id (get-in state [:workspace-page :id])
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
parent (get-parent (first selected) (vals objects))
|
parent (get-parent (first selected) (vals objects))
|
||||||
|
parent-id (:id parent)
|
||||||
selected-objects (map (partial get objects) selected)
|
selected-objects (map (partial get objects) selected)
|
||||||
selection-rect (geom/selection-rect selected-objects)
|
selection-rect (geom/selection-rect selected-objects)
|
||||||
frame-id (-> selected-objects first :frame-id)
|
frame-id (-> selected-objects first :frame-id)
|
||||||
new-shape (group-shape id frame-id selected selection-rect)
|
group-shape (group-shape id frame-id selected selection-rect)]
|
||||||
objects-removed (-> objects
|
|
||||||
(assoc (:id new-shape) new-shape)
|
|
||||||
(update-in [(:id parent) :shapes]
|
|
||||||
(fn [shapes] (filter #(not (selected %)) shapes)))
|
|
||||||
(update-in [(:id parent) :shapes] conj (:id new-shape)))]
|
|
||||||
(-> state
|
|
||||||
(assoc-in [:workspace-data page-id :objects] objects-removed )
|
|
||||||
(assoc-in [:workspace-local :selected] #{(:id new-shape)})))
|
|
||||||
state)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
(let [updated-parent (helpers/replace-shapes parent selected id)
|
||||||
(watch [_ state stream]
|
rchanges [{:type :add-obj
|
||||||
(let [obj (get-in state [:workspace-data (::page-id state) :objects id])
|
:id id
|
||||||
frame-id (:frame-id obj)
|
:frame-id frame-id
|
||||||
frame (get-in state [:workspace-data (::page-id state) :objects frame-id])]
|
:obj group-shape}
|
||||||
(rx/of (commit-changes [{:type :add-obj
|
{:type :mod-obj
|
||||||
:id id
|
:id parent-id
|
||||||
:frame-id (:frame-id obj)
|
:operations [{:type :set
|
||||||
:obj obj}
|
:attr :shapes
|
||||||
{:type :mod-obj
|
:val (:shapes updated-parent)}]}]
|
||||||
:id frame-id
|
uchanges [{:type :del-obj
|
||||||
:operations [{:type :set
|
:id id}
|
||||||
:attr :shapes
|
{:type :mod-obj
|
||||||
:val (:shapes frame)}]}]
|
:id parent-id
|
||||||
[{:type :del-obj :id id}
|
:operations [{:type :set
|
||||||
{:type :mod-obj
|
:attr :shapes
|
||||||
:id frame-id
|
:val (:shapes parent)}]}]]
|
||||||
:operations [{:type :set
|
(rx/of (commit-changes rchanges uchanges {:commit-local? true})
|
||||||
:attr :shapes
|
(fn [state] (assoc-in state [:workspace-local :selected] #{id})))))
|
||||||
:val (into (:shapes frame) (:shapes obj))}]}])))))))
|
rx/empty))))))
|
||||||
|
|
||||||
(defn remove-group []
|
(defn remove-group []
|
||||||
(ptk/reify ::remove-group
|
(ptk/reify ::remove-group
|
||||||
ptk/UpdateEvent
|
ptk/WatchEvent
|
||||||
(update [_ state] state)))
|
(watch [_ state stream]
|
||||||
|
(let [selected (get-in state [:workspace-local :selected])
|
||||||
|
group-id (first selected)
|
||||||
|
group (get-in state [:workspace-data (::page-id state) :objects group-id])]
|
||||||
|
(if (and (= (count selected) 1) (= (:type group) :group))
|
||||||
|
(let [objects (get-in state [:workspace-data (::page-id state) :objects])
|
||||||
|
parent-id (helpers/get-parent group-id objects)
|
||||||
|
parent (get objects parent-id)]
|
||||||
|
(let [changed-parent (helpers/replace-shapes parent group-id (:shapes group))
|
||||||
|
rchanges [{:type :mod-obj
|
||||||
|
:id parent-id
|
||||||
|
:operations [{:type :set :attr :shapes :val (:shapes changed-parent)}]}
|
||||||
|
|
||||||
|
;; Need to modify the object otherwise the children will be deleted
|
||||||
|
{:type :mod-obj
|
||||||
|
:id group-id
|
||||||
|
:operations [{:type :set :attr :shapes :val []}]}
|
||||||
|
{:type :del-obj
|
||||||
|
:id group-id}]
|
||||||
|
uchanges [{:type :add-obj
|
||||||
|
:id group-id
|
||||||
|
:frame-id (:frame-id group)
|
||||||
|
:obj group}
|
||||||
|
{:type :mod-obj
|
||||||
|
:id parent-id
|
||||||
|
:operations [{:type :set :attr :shapes :val (:shapes parent)}]}]]
|
||||||
|
(rx/of (commit-changes rchanges uchanges {:commit-local? true}))))
|
||||||
|
rx/empty)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Shortcuts
|
;; Shortcuts
|
||||||
|
|
|
@ -91,11 +91,11 @@
|
||||||
:transform (str
|
:transform (str
|
||||||
"scale(" inv-zoom ", " inv-zoom ") "
|
"scale(" inv-zoom ", " inv-zoom ") "
|
||||||
"translate(" (* zoom (:x label-pos)) ", " (* zoom (:y label-pos)) ")")
|
"translate(" (* zoom (:x label-pos)) ", " (* zoom (:y label-pos)) ")")
|
||||||
; User may also select the frame with single click in the label
|
;; User may also select the frame with single click in the label
|
||||||
:on-click on-double-click}
|
:on-click on-double-click}
|
||||||
(:name shape)]
|
(:name shape)]
|
||||||
[:& (frame-shape shape-wrapper) {:shape shape
|
[:& (frame-shape shape-wrapper) {:shape shape
|
||||||
:childs childs}]]))))
|
:childs childs}]])))))
|
||||||
|
|
||||||
(defn frame-shape [shape-wrapper]
|
(defn frame-shape [shape-wrapper]
|
||||||
(mf/fnc frame-shape
|
(mf/fnc frame-shape
|
||||||
|
|
Loading…
Add table
Reference in a new issue