mirror of
https://github.com/penpot/penpot.git
synced 2025-06-03 22:41:38 +02:00
🐛 Fixed issues with masks when coloring
This commit is contained in:
parent
07d77c1320
commit
4b22615f97
7 changed files with 304 additions and 282 deletions
|
@ -144,38 +144,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-list li.masked {
|
.element-list li.masked > .element-children > li {
|
||||||
.element-children {
|
&:first-child {
|
||||||
li:first-child {
|
position: relative;
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: " ";
|
content: " ";
|
||||||
border-right: 1px solid $color-gray-40;
|
border-right: 1px solid $color-gray-40;
|
||||||
border-top: 1px solid $color-gray-40;
|
border-top: 1px solid $color-gray-40;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
top: -1px;
|
top: -1px;
|
||||||
left: -4px;
|
left: -4px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
li:last-child {
|
&:last-child {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: " ";
|
content: " ";
|
||||||
border-left: 1px solid $color-gray-40;
|
border-left: 1px solid $color-gray-40;
|
||||||
border-bottom: 1px solid $color-gray-40;
|
border-bottom: 1px solid $color-gray-40;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
width: 0.3rem;
|
width: 0.3rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.texts :as dwtxt]
|
[app.main.data.workspace.texts :as dwtxt]
|
||||||
[app.main.data.workspace.transforms :as dwt]
|
[app.main.data.workspace.transforms :as dwt]
|
||||||
|
[app.main.data.workspace.groups :as dwg]
|
||||||
[app.main.data.workspace.drawing :as dwd]
|
[app.main.data.workspace.drawing :as dwd]
|
||||||
[app.main.data.workspace.drawing.path :as dwdp]
|
[app.main.data.workspace.drawing.path :as dwdp]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
|
@ -1011,11 +1012,12 @@
|
||||||
(ptk/reify ::set-shape-proportion-lock
|
(ptk/reify ::set-shape-proportion-lock
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(rx/of (dwc/update-shapes [id] (fn [shape]
|
(letfn [(assign-proportions [shape]
|
||||||
(if-not lock
|
(if-not lock
|
||||||
(assoc shape :proportion-lock false)
|
(assoc shape :proportion-lock false)
|
||||||
(-> (assoc shape :proportion-lock true)
|
(-> (assoc shape :proportion-lock true)
|
||||||
(gpr/assign-proportions)))))))))
|
(gpr/assign-proportions))))]
|
||||||
|
(rx/of (dwc/update-shapes [id] assign-proportions))))))
|
||||||
|
|
||||||
;; --- Update Shape Position
|
;; --- Update Shape Position
|
||||||
|
|
||||||
|
@ -1371,135 +1373,6 @@
|
||||||
(with-meta params
|
(with-meta params
|
||||||
{:on-success image-uploaded})))))))
|
{:on-success image-uploaded})))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; GROUPS
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(def group-selected
|
|
||||||
(ptk/reify ::group-selected
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [page-id (:current-page-id state)
|
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
|
||||||
selected (get-in state [:workspace-local :selected])
|
|
||||||
shapes (dws/shapes-for-grouping objects selected)]
|
|
||||||
(when-not (empty? shapes)
|
|
||||||
(let [[group rchanges uchanges] (dws/prepare-create-group page-id shapes "Group-" false)]
|
|
||||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
|
||||||
(dwc/select-shapes (d/ordered-set (:id group))))))))))
|
|
||||||
|
|
||||||
(def ungroup-selected
|
|
||||||
(ptk/reify ::ungroup-selected
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [page-id (:current-page-id state)
|
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
|
||||||
selected (get-in state [:workspace-local :selected])
|
|
||||||
group-id (first selected)
|
|
||||||
group (get objects group-id)]
|
|
||||||
(when (and (= 1 (count selected))
|
|
||||||
(= (:type group) :group))
|
|
||||||
(let [[rchanges uchanges]
|
|
||||||
(dws/prepare-remove-group page-id group objects)]
|
|
||||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))))
|
|
||||||
|
|
||||||
(def mask-group
|
|
||||||
(ptk/reify ::mask-group
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [page-id (:current-page-id state)
|
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
|
||||||
selected (get-in state [:workspace-local :selected])
|
|
||||||
shapes (dws/shapes-for-grouping objects selected)]
|
|
||||||
(when-not (empty? shapes)
|
|
||||||
(let [;; If the selected shape is a group, we can use it. If not,
|
|
||||||
;; create a new group and set it as masked.
|
|
||||||
[group rchanges uchanges]
|
|
||||||
(if (and (= (count shapes) 1)
|
|
||||||
(= (:type (first shapes)) :group))
|
|
||||||
[(first shapes) [] []]
|
|
||||||
(dws/prepare-create-group page-id shapes "Group-" true))
|
|
||||||
|
|
||||||
rchanges (d/concat rchanges
|
|
||||||
[{:type :mod-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id group)
|
|
||||||
:operations [{:type :set
|
|
||||||
:attr :masked-group?
|
|
||||||
:val true}]}
|
|
||||||
{:type :reg-objects
|
|
||||||
:page-id page-id
|
|
||||||
:shapes [(:id group)]}])
|
|
||||||
|
|
||||||
uchanges (conj uchanges
|
|
||||||
{:type :mod-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id group)
|
|
||||||
:operations [{:type :set
|
|
||||||
:attr :masked-group?
|
|
||||||
:val nil}]})
|
|
||||||
|
|
||||||
;; If the mask has the default color, change it automatically
|
|
||||||
;; to white, to have an opaque mask by default (user may change
|
|
||||||
;; it later to have different degrees of transparency).
|
|
||||||
mask (first shapes)
|
|
||||||
rchanges (if (not= (:fill-color mask) cp/default-color)
|
|
||||||
rchanges
|
|
||||||
(conj rchanges
|
|
||||||
{:type :mod-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id mask)
|
|
||||||
:operations [{:type :set
|
|
||||||
:attr :fill-color
|
|
||||||
:val "#ffffff"}]}))
|
|
||||||
|
|
||||||
uchanges (if (not= (:fill-color mask) cp/default-color)
|
|
||||||
uchanges
|
|
||||||
(conj uchanges
|
|
||||||
{:type :mod-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id mask)
|
|
||||||
:operations [{:type :set
|
|
||||||
:attr :fill-color
|
|
||||||
:val (:fill-color mask)}]}))]
|
|
||||||
|
|
||||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
|
||||||
(dwc/select-shapes (d/ordered-set (:id group))))))))))
|
|
||||||
|
|
||||||
(def unmask-group
|
|
||||||
(ptk/reify ::unmask-group
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [page-id (:current-page-id state)
|
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
|
||||||
selected (get-in state [:workspace-local :selected])]
|
|
||||||
(when (= (count selected) 1)
|
|
||||||
(let [group (get objects (first selected))
|
|
||||||
|
|
||||||
rchanges [{:type :mod-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id group)
|
|
||||||
:operations [{:type :set
|
|
||||||
:attr :masked-group?
|
|
||||||
:val nil}]}
|
|
||||||
{:type :reg-objects
|
|
||||||
:page-id page-id
|
|
||||||
:shapes [(:id group)]}]
|
|
||||||
|
|
||||||
uchanges [{:type :mod-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id group)
|
|
||||||
:operations [{:type :set
|
|
||||||
:attr :masked-group?
|
|
||||||
:val (:masked-group? group)}]}
|
|
||||||
{:type :reg-objects
|
|
||||||
:page-id page-id
|
|
||||||
:shapes [(:id group)]}]]
|
|
||||||
|
|
||||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
|
||||||
(dwc/select-shapes (d/ordered-set (:id group))))))))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Interactions
|
;; Interactions
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -1631,6 +1504,13 @@
|
||||||
(d/export dwc/start-edition-mode)
|
(d/export dwc/start-edition-mode)
|
||||||
(d/export dwdp/start-path-edit)
|
(d/export dwdp/start-path-edit)
|
||||||
|
|
||||||
|
;; Groups
|
||||||
|
|
||||||
|
(d/export dwg/mask-group)
|
||||||
|
(d/export dwg/unmask-group)
|
||||||
|
(d/export dwg/group-selected)
|
||||||
|
(d/export dwg/ungroup-selected)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Shortcuts
|
;; Shortcuts
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
199
frontend/src/app/main/data/workspace/groups.cljs
Normal file
199
frontend/src/app/main/data/workspace/groups.cljs
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
(ns app.main.data.workspace.groups
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.pages :as cp]
|
||||||
|
[app.common.pages-helpers :as cph]
|
||||||
|
[app.main.data.workspace.common :as dwc]
|
||||||
|
[app.main.data.workspace.selection :as dws]
|
||||||
|
[beicon.core :as rx]
|
||||||
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
|
(defn shapes-for-grouping
|
||||||
|
[objects selected]
|
||||||
|
(->> selected
|
||||||
|
(map #(get objects %))
|
||||||
|
(filter #(not= :frame (:type %)))
|
||||||
|
(map #(assoc % ::index (cph/position-on-parent (:id %) objects)))
|
||||||
|
(sort-by ::index)))
|
||||||
|
|
||||||
|
(defn- make-group
|
||||||
|
[shapes prefix keep-name]
|
||||||
|
(let [selrect (gsh/selection-rect shapes)
|
||||||
|
frame-id (-> shapes first :frame-id)
|
||||||
|
parent-id (-> shapes first :parent-id)
|
||||||
|
group-name (if (and keep-name
|
||||||
|
(= (count shapes) 1)
|
||||||
|
(= (:type (first shapes)) :group))
|
||||||
|
(:name (first shapes))
|
||||||
|
(name (gensym prefix)))]
|
||||||
|
(-> (cp/make-minimal-group frame-id selrect group-name)
|
||||||
|
(gsh/setup selrect)
|
||||||
|
(assoc :shapes (mapv :id shapes)))))
|
||||||
|
|
||||||
|
(defn prepare-create-group
|
||||||
|
[page-id shapes prefix keep-name]
|
||||||
|
(let [group (make-group shapes prefix keep-name)
|
||||||
|
rchanges [{:type :add-obj
|
||||||
|
:id (:id group)
|
||||||
|
:page-id page-id
|
||||||
|
:frame-id (:frame-id (first shapes))
|
||||||
|
:parent-id (:parent-id (first shapes))
|
||||||
|
:obj group
|
||||||
|
:index (::index (first shapes))}
|
||||||
|
{:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id (:id group)
|
||||||
|
:shapes (mapv :id shapes)}]
|
||||||
|
|
||||||
|
uchanges (conj
|
||||||
|
(mapv (fn [obj] {:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id (:parent-id obj)
|
||||||
|
:index (::index obj)
|
||||||
|
:shapes [(:id obj)]})
|
||||||
|
shapes)
|
||||||
|
{:type :del-obj
|
||||||
|
:id (:id group)
|
||||||
|
:page-id page-id})]
|
||||||
|
[group rchanges uchanges]))
|
||||||
|
|
||||||
|
(defn prepare-remove-group
|
||||||
|
[page-id group objects]
|
||||||
|
(let [shapes (:shapes group)
|
||||||
|
parent-id (cph/get-parent (:id group) objects)
|
||||||
|
parent (get objects parent-id)
|
||||||
|
index-in-parent (->> (:shapes parent)
|
||||||
|
(map-indexed vector)
|
||||||
|
(filter #(#{(:id group)} (second %)))
|
||||||
|
(ffirst))
|
||||||
|
rchanges [{:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id parent-id
|
||||||
|
:shapes shapes
|
||||||
|
:index index-in-parent}
|
||||||
|
{:type :del-obj
|
||||||
|
:page-id page-id
|
||||||
|
:id (:id group)}]
|
||||||
|
uchanges [{:type :add-obj
|
||||||
|
:page-id page-id
|
||||||
|
:id (:id group)
|
||||||
|
:frame-id (:frame-id group)
|
||||||
|
:obj (assoc group :shapes [])}
|
||||||
|
{:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id (:id group)
|
||||||
|
:shapes shapes}
|
||||||
|
{:type :mov-objects
|
||||||
|
:page-id page-id
|
||||||
|
:parent-id parent-id
|
||||||
|
:shapes [(:id group)]
|
||||||
|
:index index-in-parent}]]
|
||||||
|
[rchanges uchanges]))
|
||||||
|
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; GROUPS
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(def group-selected
|
||||||
|
(ptk/reify ::group-selected
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
|
selected (get-in state [:workspace-local :selected])
|
||||||
|
shapes (shapes-for-grouping objects selected)]
|
||||||
|
(when-not (empty? shapes)
|
||||||
|
(let [[group rchanges uchanges] (prepare-create-group page-id shapes "Group-" false)]
|
||||||
|
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||||
|
(dwc/select-shapes (d/ordered-set (:id group))))))))))
|
||||||
|
|
||||||
|
(def ungroup-selected
|
||||||
|
(ptk/reify ::ungroup-selected
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
|
selected (get-in state [:workspace-local :selected])
|
||||||
|
group-id (first selected)
|
||||||
|
group (get objects group-id)]
|
||||||
|
(when (and (= 1 (count selected))
|
||||||
|
(= (:type group) :group))
|
||||||
|
(let [[rchanges uchanges]
|
||||||
|
(prepare-remove-group page-id group objects)]
|
||||||
|
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))))
|
||||||
|
|
||||||
|
(def mask-group
|
||||||
|
(ptk/reify ::mask-group
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
|
selected (get-in state [:workspace-local :selected])
|
||||||
|
shapes (shapes-for-grouping objects selected)]
|
||||||
|
(when-not (empty? shapes)
|
||||||
|
(let [;; If the selected shape is a group, we can use it. If not,
|
||||||
|
;; create a new group and set it as masked.
|
||||||
|
[group rchanges uchanges]
|
||||||
|
(if (and (= (count shapes) 1)
|
||||||
|
(= (:type (first shapes)) :group))
|
||||||
|
[(first shapes) [] []]
|
||||||
|
(prepare-create-group page-id shapes "Group-" true))
|
||||||
|
|
||||||
|
rchanges (d/concat rchanges
|
||||||
|
[{:type :mod-obj
|
||||||
|
:page-id page-id
|
||||||
|
:id (:id group)
|
||||||
|
:operations [{:type :set
|
||||||
|
:attr :masked-group?
|
||||||
|
:val true}]}
|
||||||
|
{:type :reg-objects
|
||||||
|
:page-id page-id
|
||||||
|
:shapes [(:id group)]}])
|
||||||
|
|
||||||
|
uchanges (conj uchanges
|
||||||
|
{:type :mod-obj
|
||||||
|
:page-id page-id
|
||||||
|
:id (:id group)
|
||||||
|
:operations [{:type :set
|
||||||
|
:attr :masked-group?
|
||||||
|
:val nil}]})]
|
||||||
|
|
||||||
|
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||||
|
(dwc/select-shapes (d/ordered-set (:id group))))))))))
|
||||||
|
|
||||||
|
(def unmask-group
|
||||||
|
(ptk/reify ::unmask-group
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
|
selected (get-in state [:workspace-local :selected])]
|
||||||
|
(when (= (count selected) 1)
|
||||||
|
(let [group (get objects (first selected))
|
||||||
|
|
||||||
|
rchanges [{:type :mod-obj
|
||||||
|
:page-id page-id
|
||||||
|
:id (:id group)
|
||||||
|
:operations [{:type :set
|
||||||
|
:attr :masked-group?
|
||||||
|
:val nil}]}
|
||||||
|
{:type :reg-objects
|
||||||
|
:page-id page-id
|
||||||
|
:shapes [(:id group)]}]
|
||||||
|
|
||||||
|
uchanges [{:type :mod-obj
|
||||||
|
:page-id page-id
|
||||||
|
:id (:id group)
|
||||||
|
:operations [{:type :set
|
||||||
|
:attr :masked-group?
|
||||||
|
:val (:masked-group? group)}]}
|
||||||
|
{:type :reg-objects
|
||||||
|
:page-id page-id
|
||||||
|
:shapes [(:id group)]}]]
|
||||||
|
|
||||||
|
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||||
|
(dwc/select-shapes (d/ordered-set (:id group))))))))))
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
[app.common.geom.shapes :as geom]
|
[app.common.geom.shapes :as geom]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[app.main.data.workspace.common :as dwc]
|
[app.main.data.workspace.common :as dwc]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.groups :as dwg]
|
||||||
[app.main.data.workspace.libraries-helpers :as dwlh]
|
[app.main.data.workspace.libraries-helpers :as dwlh]
|
||||||
[app.common.pages :as cp]
|
[app.common.pages :as cp]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
|
@ -182,7 +182,7 @@
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
selected (get-in state [:workspace-local :selected])
|
selected (get-in state [:workspace-local :selected])
|
||||||
shapes (dws/shapes-for-grouping objects selected)]
|
shapes (dwg/shapes-for-grouping objects selected)]
|
||||||
(when-not (empty? shapes)
|
(when-not (empty? shapes)
|
||||||
(let [;; If the selected shape is a group, we can use it. If not,
|
(let [;; If the selected shape is a group, we can use it. If not,
|
||||||
;; we need to create a group before creating the component.
|
;; we need to create a group before creating the component.
|
||||||
|
@ -190,7 +190,7 @@
|
||||||
(if (and (= (count shapes) 1)
|
(if (and (= (count shapes) 1)
|
||||||
(= (:type (first shapes)) :group))
|
(= (:type (first shapes)) :group))
|
||||||
[(first shapes) [] []]
|
[(first shapes) [] []]
|
||||||
(dws/prepare-create-group page-id shapes "Component-" true))
|
(dwg/prepare-create-group page-id shapes "Component-" true))
|
||||||
|
|
||||||
[new-shape new-shapes updated-shapes]
|
[new-shape new-shapes updated-shapes]
|
||||||
(dwlh/make-component-shape group objects)
|
(dwlh/make-component-shape group objects)
|
||||||
|
|
|
@ -197,91 +197,6 @@
|
||||||
(rx/of (deselect-all) (select-shape (:id selected))))))))
|
(rx/of (deselect-all) (select-shape (:id selected))))))))
|
||||||
|
|
||||||
|
|
||||||
;; --- Group shapes
|
|
||||||
|
|
||||||
(defn shapes-for-grouping
|
|
||||||
[objects selected]
|
|
||||||
(->> selected
|
|
||||||
(map #(get objects %))
|
|
||||||
(filter #(not= :frame (:type %)))
|
|
||||||
(map #(assoc % ::index (cph/position-on-parent (:id %) objects)))
|
|
||||||
(sort-by ::index)))
|
|
||||||
|
|
||||||
(defn- make-group
|
|
||||||
[shapes prefix keep-name]
|
|
||||||
(let [selrect (geom/selection-rect shapes)
|
|
||||||
frame-id (-> shapes first :frame-id)
|
|
||||||
parent-id (-> shapes first :parent-id)
|
|
||||||
group-name (if (and keep-name
|
|
||||||
(= (count shapes) 1)
|
|
||||||
(= (:type (first shapes)) :group))
|
|
||||||
(:name (first shapes))
|
|
||||||
(name (gensym prefix)))]
|
|
||||||
(-> (cp/make-minimal-group frame-id selrect group-name)
|
|
||||||
(geom/setup selrect)
|
|
||||||
(assoc :shapes (mapv :id shapes)))))
|
|
||||||
|
|
||||||
(defn prepare-create-group
|
|
||||||
[page-id shapes prefix keep-name]
|
|
||||||
(let [group (make-group shapes prefix keep-name)
|
|
||||||
rchanges [{:type :add-obj
|
|
||||||
:id (:id group)
|
|
||||||
:page-id page-id
|
|
||||||
:frame-id (:frame-id (first shapes))
|
|
||||||
:parent-id (:parent-id (first shapes))
|
|
||||||
:obj group
|
|
||||||
:index (::index (first shapes))}
|
|
||||||
{:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id (:id group)
|
|
||||||
:shapes (mapv :id shapes)}]
|
|
||||||
|
|
||||||
uchanges (conj
|
|
||||||
(mapv (fn [obj] {:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id (:parent-id obj)
|
|
||||||
:index (::index obj)
|
|
||||||
:shapes [(:id obj)]})
|
|
||||||
shapes)
|
|
||||||
{:type :del-obj
|
|
||||||
:id (:id group)
|
|
||||||
:page-id page-id})]
|
|
||||||
[group rchanges uchanges]))
|
|
||||||
|
|
||||||
(defn prepare-remove-group
|
|
||||||
[page-id group objects]
|
|
||||||
(let [shapes (:shapes group)
|
|
||||||
parent-id (cph/get-parent (:id group) objects)
|
|
||||||
parent (get objects parent-id)
|
|
||||||
index-in-parent (->> (:shapes parent)
|
|
||||||
(map-indexed vector)
|
|
||||||
(filter #(#{(:id group)} (second %)))
|
|
||||||
(ffirst))
|
|
||||||
rchanges [{:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id parent-id
|
|
||||||
:shapes shapes
|
|
||||||
:index index-in-parent}
|
|
||||||
{:type :del-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id group)}]
|
|
||||||
uchanges [{:type :add-obj
|
|
||||||
:page-id page-id
|
|
||||||
:id (:id group)
|
|
||||||
:frame-id (:frame-id group)
|
|
||||||
:obj (assoc group :shapes [])}
|
|
||||||
{:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id (:id group)
|
|
||||||
:shapes shapes}
|
|
||||||
{:type :mov-objects
|
|
||||||
:page-id page-id
|
|
||||||
:parent-id parent-id
|
|
||||||
:shapes [(:id group)]
|
|
||||||
:index index-in-parent}]]
|
|
||||||
[rchanges uchanges]))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Duplicate Shapes
|
;; --- Duplicate Shapes
|
||||||
(declare prepare-duplicate-change)
|
(declare prepare-duplicate-change)
|
||||||
(declare prepare-duplicate-frame-change)
|
(declare prepare-duplicate-frame-change)
|
||||||
|
|
|
@ -10,42 +10,37 @@
|
||||||
(ns app.main.ui.shapes.group
|
(ns app.main.ui.shapes.group
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[cuerdas.core :as str]
|
[app.main.ui.shapes.mask :refer [mask-str mask-factory]]))
|
||||||
[app.main.ui.shapes.attrs :as attrs]
|
|
||||||
[app.common.geom.shapes :as geom]))
|
|
||||||
|
|
||||||
(defn group-shape
|
(defn group-shape
|
||||||
[shape-wrapper]
|
[shape-wrapper]
|
||||||
(mf/fnc group-shape
|
(let [render-mask (mask-factory shape-wrapper)]
|
||||||
{::mf/wrap-props false}
|
(mf/fnc group-shape
|
||||||
[props]
|
{::mf/wrap-props false}
|
||||||
(let [frame (unchecked-get props "frame")
|
[props]
|
||||||
shape (unchecked-get props "shape")
|
(let [frame (unchecked-get props "frame")
|
||||||
childs (unchecked-get props "childs")
|
shape (unchecked-get props "shape")
|
||||||
expand-mask (unchecked-get props "expand-mask")
|
childs (unchecked-get props "childs")
|
||||||
pointer-events (unchecked-get props "pointer-events")
|
expand-mask (unchecked-get props "expand-mask")
|
||||||
mask (if (and (:masked-group? shape) (not expand-mask))
|
pointer-events (unchecked-get props "pointer-events")
|
||||||
(first childs)
|
|
||||||
nil)
|
{:keys [id x y width height]} shape
|
||||||
childs (if (and (:masked-group? shape) (not expand-mask))
|
|
||||||
(rest childs)
|
show-mask? (and (:masked-group? shape) (not expand-mask))
|
||||||
childs)
|
mask (when show-mask? (first childs))
|
||||||
{:keys [id x y width height]} shape
|
childs (if show-mask? (rest childs) childs)]
|
||||||
transform (geom/transform-matrix shape)]
|
|
||||||
[:g.group {:pointer-events pointer-events
|
[:g.group
|
||||||
:mask (when (and mask (not expand-mask))
|
{:pointer-events pointer-events
|
||||||
(str/fmt "url(#%s)" (:id mask)))}
|
:mask (when (and mask (not expand-mask)) (mask-str mask))}
|
||||||
(when mask
|
|
||||||
[:defs
|
(when mask
|
||||||
[:mask {:id (:id mask)
|
[:> render-mask #js {:frame frame :mask mask}])
|
||||||
:width width
|
|
||||||
:height height}
|
(for [item childs]
|
||||||
[:& shape-wrapper {:frame frame
|
[:& shape-wrapper {:frame frame
|
||||||
:shape mask}]]])
|
:shape item
|
||||||
(for [item childs]
|
:key (:id item)}])]))))
|
||||||
[:& shape-wrapper {:frame frame
|
|
||||||
:shape item
|
|
||||||
:key (:id item)}])])))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
35
frontend/src/app/main/ui/shapes/mask.cljs
Normal file
35
frontend/src/app/main/ui/shapes/mask.cljs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.ui.shapes.mask
|
||||||
|
(:require
|
||||||
|
[rumext.alpha :as mf]
|
||||||
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
(defn mask-str [mask]
|
||||||
|
(str/fmt "url(#%s)" (str (:id mask) "-mask")))
|
||||||
|
|
||||||
|
(defn mask-factory
|
||||||
|
[shape-wrapper]
|
||||||
|
(mf/fnc mask-shape
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [frame (unchecked-get props "frame")
|
||||||
|
mask (unchecked-get props "mask")]
|
||||||
|
[:defs
|
||||||
|
[:filter {:id (str (:id mask) "-filter")}
|
||||||
|
[:feFlood {:flood-color "white"}]
|
||||||
|
[:feComposite {:in "BackgroundImage"
|
||||||
|
:in2 "SourceGraphic"
|
||||||
|
:operator "in"
|
||||||
|
:result "comp"}]]
|
||||||
|
[:mask {:id (str (:id mask) "-mask")}
|
||||||
|
[:g {:filter (str/fmt "url(#%s)" (str (:id mask) "-filter"))}
|
||||||
|
[:& shape-wrapper {:frame frame :shape mask}]]]])))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue