Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New plugins APIs #4536

Merged
merged 8 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
129 changes: 66 additions & 63 deletions common/src/app/common/svg/shapes_builder.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
[app.common.svg :as csvg]
[app.common.svg.path :as path]
[app.common.types.shape :as cts]
[app.common.uuid :as uuid]
[cuerdas.core :as str]))

(def default-rect
Expand Down Expand Up @@ -78,67 +79,68 @@
(declare parse-svg-element)

(defn create-svg-shapes
[svg-data {:keys [x y]} objects frame-id parent-id selected center?]
(let [[vb-x vb-y vb-width vb-height] (svg-dimensions svg-data)


unames (cfh/get-used-names objects)
svg-name (str/replace (:name svg-data) ".svg" "")

svg-data (-> svg-data
(assoc :x (mth/round
(if center?
(- x vb-x (/ vb-width 2))
x)))
(assoc :y (mth/round
(if center?
(- y vb-y (/ vb-height 2))
y)))
(assoc :offset-x vb-x)
(assoc :offset-y vb-y)
(assoc :width vb-width)
(assoc :height vb-height)
(assoc :name svg-name))

[def-nodes svg-data]
(-> svg-data
(csvg/fix-default-values)
(csvg/fix-percents)
(csvg/extract-defs))

;; In penpot groups have the size of their children. To
;; respect the imported svg size and empty space let's create
;; a transparent shape as background to respect the imported
;; size
background
{:tag :rect
:attrs {:x (dm/str vb-x)
:y (dm/str vb-y)
:width (dm/str vb-width)
:height (dm/str vb-height)
:fill "none"
:id "base-background"}
:hidden true
:content []}

svg-data (-> svg-data
(assoc :defs def-nodes)
(assoc :content (into [background] (:content svg-data))))

root-shape (create-svg-root frame-id parent-id svg-data)
root-id (:id root-shape)

;; Create the root shape
root-attrs (-> (:attrs svg-data)
(csvg/format-styles))

[_ children]
(reduce (partial create-svg-children objects selected frame-id root-id svg-data)
[unames []]
(d/enumerate (->> (:content svg-data)
(mapv #(csvg/inherit-attributes root-attrs %)))))]

[root-shape children]))
([svg-data pos objects frame-id parent-id selected center?]
(create-svg-shapes (uuid/next) svg-data pos objects frame-id parent-id selected center?))
([id svg-data {:keys [x y]} objects frame-id parent-id selected center?]
(let [[vb-x vb-y vb-width vb-height] (svg-dimensions svg-data)

unames (cfh/get-used-names objects)
svg-name (str/replace (:name svg-data) ".svg" "")

svg-data (-> svg-data
(assoc :x (mth/round
(if center?
(- x vb-x (/ vb-width 2))
x)))
(assoc :y (mth/round
(if center?
(- y vb-y (/ vb-height 2))
y)))
(assoc :offset-x vb-x)
(assoc :offset-y vb-y)
(assoc :width vb-width)
(assoc :height vb-height)
(assoc :name svg-name))

[def-nodes svg-data]
(-> svg-data
(csvg/fix-default-values)
(csvg/fix-percents)
(csvg/extract-defs))

;; In penpot groups have the size of their children. To
;; respect the imported svg size and empty space let's create
;; a transparent shape as background to respect the imported
;; size
background
{:tag :rect
:attrs {:x (dm/str vb-x)
:y (dm/str vb-y)
:width (dm/str vb-width)
:height (dm/str vb-height)
:fill "none"
:id "base-background"}
:hidden true
:content []}

svg-data (-> svg-data
(assoc :defs def-nodes)
(assoc :content (into [background] (:content svg-data))))

root-shape (create-svg-root id frame-id parent-id svg-data)
root-id (:id root-shape)

;; Create the root shape
root-attrs (-> (:attrs svg-data)
(csvg/format-styles))

[_ children]
(reduce (partial create-svg-children objects selected frame-id root-id svg-data)
[unames []]
(d/enumerate (->> (:content svg-data)
(mapv #(csvg/inherit-attributes root-attrs %)))))]

[root-shape children])))

(defn create-raw-svg
[name frame-id {:keys [x y width height offset-x offset-y]} {:keys [attrs] :as data}]
Expand All @@ -157,12 +159,13 @@
:svg-viewbox vbox})))

(defn create-svg-root
[frame-id parent-id {:keys [name x y width height offset-x offset-y attrs]}]
[id frame-id parent-id {:keys [name x y width height offset-x offset-y attrs]}]
(let [props (-> (dissoc attrs :viewBox :view-box :xmlns)
(d/without-keys csvg/inheritable-props)
(csvg/attrs->props))]
(cts/setup-shape
{:type :group
{:id id
:type :group
:name name
:frame-id frame-id
:parent-id parent-id
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/main/data/workspace.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@
(defn relocate-shapes
[ids parent-id to-index & [ignore-parents?]]
(dm/assert! (every? uuid? ids))
(dm/assert! (set? ids))
(dm/assert! (uuid? parent-id))
(dm/assert! (number? to-index))

Expand Down
76 changes: 49 additions & 27 deletions frontend/src/app/main/data/workspace/groups.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
[app.common.types.container :as ctn]
[app.common.types.shape :as cts]
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
Expand Down Expand Up @@ -68,7 +69,7 @@
result)))))))

(defn prepare-create-group
[changes objects page-id shapes base-name keep-name?]
[changes id objects page-id shapes base-name keep-name?]
(let [frame-id (:frame-id (first shapes))
parent-id (:parent-id (first shapes))
gname (if (and keep-name?
Expand All @@ -84,7 +85,8 @@
(cfh/get-position-on-parent objects)
inc)

group (cts/setup-shape {:type :group
group (cts/setup-shape {:id id
:type :group
:name gname
:shapes (mapv :id shapes)
:selrect selrect
Expand Down Expand Up @@ -173,30 +175,43 @@
;; GROUPS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def group-selected
(ptk/reify ::group-selected
(defn group-shapes
[id ids & {:keys [change-selection?] :or {change-selection? false}}]
(ptk/reify ::group-shapes
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
(let [id (d/nilv id (uuid/next))
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (->> (wsh/lookup-selected state)
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %))))
shapes (shapes-for-grouping objects selected)

shapes
(->> ids
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %)))
(shapes-for-grouping objects))
parents (into #{} (map :parent-id) shapes)]
(when-not (empty? shapes)
(let [[group changes]
(prepare-create-group (pcb/empty-changes it) objects page-id shapes "Group" false)]
(prepare-create-group (pcb/empty-changes it) id objects page-id shapes "Group" false)]
(rx/of (dch/commit-changes changes)
(dws/select-shapes (d/ordered-set (:id group)))
(when change-selection?
(dws/select-shapes (d/ordered-set (:id group))))
(ptk/data-event :layout/update {:ids parents}))))))))

(def ungroup-selected
(ptk/reify ::ungroup-selected
(def group-selected
(ptk/reify ::group-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(rx/of (group-shapes nil selected))))))

(defn ungroup-shapes
[ids & {:keys [change-selection?] :or {change-selection? false}}]
(ptk/reify ::ungroup-shapes
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)

prepare
(fn [shape-id]
Expand All @@ -213,35 +228,42 @@
(ctl/grid-layout? objects (:parent-id shape))
(pcb/update-shapes [(:parent-id shape)] ctl/assign-cells {:with-objects? true}))))

selected (->> (wsh/lookup-selected state)
(remove #(ctn/has-any-copy-parent? objects (get objects %)))
;; components can't be ungrouped
(remove #(ctk/instance-head? (get objects %))))
changes-list (sequence
(keep prepare)
selected)
ids (->> ids
(remove #(ctn/has-any-copy-parent? objects (get objects %)))
;; components can't be ungrouped
(remove #(ctk/instance-head? (get objects %))))

changes-list (sequence (keep prepare) ids)

parents (into #{}
(comp (map #(cfh/get-parent objects %))
(keep :id))
selected)
ids)

child-ids
(into (d/ordered-set)
(mapcat #(dm/get-in objects [% :shapes]))
selected)
ids)

changes {:redo-changes (vec (mapcat :redo-changes changes-list))
:undo-changes (vec (mapcat :undo-changes changes-list))
:origin it}
undo-id (js/Symbol)]

(when-not (empty? selected)
(when-not (empty? ids)
(rx/of (dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(ptk/data-event :layout/update {:ids parents})
(dwu/commit-undo-transaction undo-id)
(dws/select-shapes child-ids)))))))
(when change-selection?
(dws/select-shapes child-ids))))))))

(def ungroup-selected
(ptk/reify ::ungroup-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(rx/of (ungroup-shapes selected :change-selection? true))))))

(def mask-group
(ptk/reify ::mask-group
Expand All @@ -262,7 +284,7 @@
(= (:type (first shapes)) :group))
[first-shape (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects))]
(prepare-create-group (pcb/empty-changes it) objects page-id shapes "Mask" true))
(prepare-create-group (pcb/empty-changes it) (uuid/next) objects page-id shapes "Mask" true))

changes (-> changes
(pcb/update-shapes (:shapes group)
Expand Down
21 changes: 20 additions & 1 deletion frontend/src/app/main/data/workspace/media.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,17 @@
(->> (svg/upload-images svg-data file-id)
(rx/map #(svg/add-svg-shapes (assoc svg-data :image-data %) position))))))

(defn- process-uris

(defn upload-media-url
[name file-id url]
(rp/cmd!
:create-file-media-object-from-url
{:name name
:file-id file-id
:url url
:is-local true}))

(defn process-uris
[{:keys [file-id local? name uris mtype on-image on-svg]}]
(letfn [(svg-url? [url]
(or (and mtype (= mtype "image/svg+xml"))
Expand Down Expand Up @@ -449,3 +459,12 @@
(rx/tap on-success)
(rx/catch on-error)
(rx/finalize #(st/emit! (msg/hide-tag :media-loading)))))))))

(defn create-svg-shape
[id name svg-string position]
(ptk/reify ::create-svg-shape
ptk/WatchEvent
(watch [_ _ _]
(->> (svg->clj [name svg-string])
(rx/take 1)
(rx/map #(svg/add-svg-shapes id % position {:change-selection? false}))))))