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