mirror of
https://github.com/penpot/penpot.git
synced 2025-05-14 23:26:37 +02:00
✨ Create nested frames from selection
This commit is contained in:
parent
c8ad379bf8
commit
79a46efa35
4 changed files with 46 additions and 40 deletions
|
@ -227,17 +227,19 @@
|
|||
(defn is-shape-over-shape?
|
||||
[objects base-shape-id over-shape-id]
|
||||
|
||||
(let [[base parent-a parent-b] (get-base objects base-shape-id over-shape-id)]
|
||||
(let [[base index-a index-b] (get-base objects base-shape-id over-shape-id)]
|
||||
(cond
|
||||
(= base base-shape-id)
|
||||
;; over-shape is a child of base-shape. Will be over if base is a root-frame
|
||||
(= uuid/zero (get-in objects [base-shape-id :parent-id]))
|
||||
|
||||
(and (frame-shape? objects over-shape-id)
|
||||
(root-frame? objects over-shape-id))
|
||||
|
||||
(= base over-shape-id)
|
||||
(not= uuid/zero (get-in objects [over-shape-id :parent-id]))
|
||||
(or (not (frame-shape? objects over-shape-id))
|
||||
(not (root-frame? objects over-shape-id)))
|
||||
|
||||
:else
|
||||
(< parent-a parent-b))))
|
||||
(> index-a index-b))))
|
||||
|
||||
(defn sort-z-index
|
||||
([objects ids]
|
||||
|
@ -266,17 +268,11 @@
|
|||
|
||||
(defn frame-id-by-position
|
||||
[objects position]
|
||||
(let [frames (->> (get-frames objects)
|
||||
(filter #(and position (gsh/has-point? % position))))
|
||||
|
||||
top-frame
|
||||
(reduce (fn [current-top frame]
|
||||
(if (is-shape-over-shape? objects (:id current-top) (:id frame))
|
||||
frame
|
||||
current-top))
|
||||
(first frames)
|
||||
(rest frames))]
|
||||
(or (:id top-frame) uuid/zero)))
|
||||
(let [top-frame
|
||||
(->> (get-frames-ids objects)
|
||||
(sort-z-index objects)
|
||||
(d/seek #(and position (gsh/has-point? (get objects %) position))))]
|
||||
(or top-frame uuid/zero)))
|
||||
|
||||
(defn frame-by-position
|
||||
[objects position]
|
||||
|
@ -630,3 +626,8 @@
|
|||
|
||||
(-> (select-keys objects selected+parents)
|
||||
(d/update-vals remove-children))))
|
||||
|
||||
(defn is-child?
|
||||
[objects parent-id candidate-child-id]
|
||||
(let [parents (get-parents-seq objects candidate-child-id)]
|
||||
(some? (d/seek #(= % parent-id) parents))))
|
||||
|
|
|
@ -1673,20 +1673,22 @@
|
|||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
shapes (cph/get-immediate-children objects)
|
||||
selected (wsh/lookup-selected state)
|
||||
selected-objs (map #(get objects %) selected)
|
||||
has-frame? (some #(= (:type %) :frame) selected-objs)]
|
||||
(when (not (or (empty? selected) has-frame?))
|
||||
selected-objs (map #(get objects %) selected)]
|
||||
(when (d/not-empty? selected)
|
||||
(let [srect (gsh/selection-rect selected-objs)
|
||||
frame-id (:frame-id (first shapes))
|
||||
frame-id (get-in objects [(first selected) :frame-id])
|
||||
parent-id (get-in objects [(first selected) :parent-id])
|
||||
shape (-> (cp/make-minimal-shape :frame)
|
||||
(merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)})
|
||||
(assoc :frame-id frame-id)
|
||||
(assoc :frame-id frame-id :parent-id parent-id)
|
||||
(cond-> (not= frame-id uuid/zero)
|
||||
(assoc :fills [] :hide-in-viewer true))
|
||||
(cp/setup-rect-selrect))]
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction)
|
||||
(dwc/add-shape shape)
|
||||
|
||||
(dwc/move-shapes-into-frame (:id shape) selected)
|
||||
(dwu/commit-undo-transaction))))))))
|
||||
|
||||
|
|
|
@ -313,7 +313,10 @@
|
|||
selected)
|
||||
|
||||
changes (-> (pcb/empty-changes it page-id)
|
||||
(pcb/add-object shape #_{:index (when (= :frame (:type shape)) 0)}))]
|
||||
(pcb/with-objects objects)
|
||||
(pcb/add-object shape)
|
||||
(cond-> (some? (:parent-id attrs))
|
||||
(pcb/change-parent (:parent-id attrs) [shape])))]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dch/commit-changes changes)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -165,6 +166,7 @@
|
|||
|
||||
(defn on-double-click
|
||||
[hover hover-ids drawing-path? objects edition]
|
||||
|
||||
(mf/use-callback
|
||||
(mf/deps @hover @hover-ids drawing-path? edition)
|
||||
(fn [event]
|
||||
|
@ -174,30 +176,28 @@
|
|||
alt? (kbd/alt? event)
|
||||
meta? (kbd/meta? event)
|
||||
|
||||
{:keys [id type] :as shape} @hover
|
||||
{:keys [id type] :as shape} (or @hover (get objects (first @hover-ids)))
|
||||
|
||||
frame? (= :frame type)
|
||||
group? (= :group type)]
|
||||
editable? (contains? #{:text :rect :path :image :circle} type)]
|
||||
|
||||
(st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt? meta?))
|
||||
|
||||
;; Emit asynchronously so the double click to exit shapes won't break
|
||||
(timers/schedule
|
||||
#(when (and (not drawing-path?) shape)
|
||||
(cond
|
||||
frame?
|
||||
(st/emit! (dw/select-shape id shift?))
|
||||
(fn []
|
||||
(when (and (not drawing-path?) shape)
|
||||
(cond
|
||||
(and editable? (not= id edition))
|
||||
(st/emit! (dw/select-shape id)
|
||||
(dw/start-editing-selected))
|
||||
|
||||
(and group? (> (count @hover-ids) 1))
|
||||
(let [selected (get objects (second @hover-ids))]
|
||||
(reset! hover selected)
|
||||
(reset! hover-ids (into [] (rest @hover-ids)))
|
||||
|
||||
(st/emit! (dw/select-shape (:id selected))))
|
||||
|
||||
(not= id edition)
|
||||
(st/emit! (dw/select-shape id)
|
||||
(dw/start-editing-selected)))))))))
|
||||
:else
|
||||
(let [;; We only get inside childrens of the hovering shape
|
||||
hover-ids (->> @hover-ids (filter (partial cph/is-child? objects id)))
|
||||
selected (get objects (if (> (count hover-ids) 1) (second hover-ids) (first hover-ids)))]
|
||||
(when (some? selected)
|
||||
(reset! hover selected)
|
||||
(st/emit! (dw/select-shape (:id selected)))))))))))))
|
||||
|
||||
(defn on-context-menu
|
||||
[hover hover-ids]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue