mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 15:51:37 -05:00
✨ Created bool shapes
This commit is contained in:
parent
5031700af6
commit
9f08153a85
8 changed files with 276 additions and 8 deletions
59
common/src/app/common/pages/changes_builder.cljc
Normal file
59
common/src/app/common/pages/changes_builder.cljc
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.common.pages.changes-builder)
|
||||||
|
|
||||||
|
;; Auxiliary functions to help create a set of changes (undo + redo)
|
||||||
|
|
||||||
|
(defn empty-changes [origin page-id]
|
||||||
|
(with-meta
|
||||||
|
{:redo-changes []
|
||||||
|
:undo-changes []
|
||||||
|
:origin origin}
|
||||||
|
{::page-id page-id}))
|
||||||
|
|
||||||
|
(defn add-obj
|
||||||
|
[changes obj]
|
||||||
|
(let [add-change
|
||||||
|
{:type :add-obj
|
||||||
|
:id (:id obj)
|
||||||
|
:page-id (::page-id (meta changes))
|
||||||
|
:parent-id (:parent-id obj)
|
||||||
|
:frame-id (:frame-id obj)
|
||||||
|
:index (::index obj)
|
||||||
|
:obj (dissoc obj ::index :parent-id)}
|
||||||
|
|
||||||
|
del-change
|
||||||
|
{:type :del-obj
|
||||||
|
:id (:id obj)
|
||||||
|
:page-id (::page-id (meta changes))}]
|
||||||
|
|
||||||
|
(-> changes
|
||||||
|
(update :redo-changes conj add-change)
|
||||||
|
(update :undo-changes #(into [del-change] %)))))
|
||||||
|
|
||||||
|
(defn change-parent
|
||||||
|
[changes parent-id shapes]
|
||||||
|
(let [set-parent-change
|
||||||
|
{:type :mov-objects
|
||||||
|
:parent-id parent-id
|
||||||
|
:page-id (::page-id (meta changes))
|
||||||
|
:shapes (->> shapes (mapv :id))}
|
||||||
|
|
||||||
|
mk-undo-change
|
||||||
|
(fn [shape]
|
||||||
|
{:type :mov-objects
|
||||||
|
:page-id (::page-id (meta changes))
|
||||||
|
:parent-id (:parent-id shape)
|
||||||
|
:shapes [(:id shape)]
|
||||||
|
:index (::index shape)})
|
||||||
|
|
||||||
|
undo-moves
|
||||||
|
(->> shapes (mapv mk-undo-change))]
|
||||||
|
|
||||||
|
(-> changes
|
||||||
|
(update :redo-changes conj set-parent-change)
|
||||||
|
(update :undo-changes #(into undo-moves %)))))
|
|
@ -23,6 +23,7 @@
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
|
[app.main.data.workspace.booleans :as dwb]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.changes :as dch]
|
||||||
[app.main.data.workspace.common :as dwc]
|
[app.main.data.workspace.common :as dwc]
|
||||||
[app.main.data.workspace.drawing :as dwd]
|
[app.main.data.workspace.drawing :as dwd]
|
||||||
|
@ -48,7 +49,8 @@
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]
|
||||||
|
))
|
||||||
|
|
||||||
;; (log/set-level! :trace)
|
;; (log/set-level! :trace)
|
||||||
|
|
||||||
|
@ -1100,6 +1102,10 @@
|
||||||
:group
|
:group
|
||||||
(rx/of (dwc/select-shapes (into (d/ordered-set) [(last shapes)])))
|
(rx/of (dwc/select-shapes (into (d/ordered-set) [(last shapes)])))
|
||||||
|
|
||||||
|
:bool
|
||||||
|
;; TODO
|
||||||
|
(js/alert "TODO")
|
||||||
|
|
||||||
:svg-raw
|
:svg-raw
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
@ -1987,3 +1993,6 @@
|
||||||
(d/export dwg/unmask-group)
|
(d/export dwg/unmask-group)
|
||||||
(d/export dwg/group-selected)
|
(d/export dwg/group-selected)
|
||||||
(d/export dwg/ungroup-selected)
|
(d/export dwg/ungroup-selected)
|
||||||
|
|
||||||
|
;; Boolean
|
||||||
|
(d/export dwb/create-bool)
|
||||||
|
|
66
frontend/src/app/main/data/workspace/booleans.cljs
Normal file
66
frontend/src/app/main/data/workspace/booleans.cljs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.data.workspace.booleans
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.pages :as cp]
|
||||||
|
[app.common.pages.changes-builder :as cb]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.workspace.changes :as dch]
|
||||||
|
[app.main.data.workspace.common :as dwc]
|
||||||
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
|
[beicon.core :as rx]
|
||||||
|
[cuerdas.core :as str]
|
||||||
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
|
(defn selected-shapes
|
||||||
|
[state]
|
||||||
|
(let [objects (wsh/lookup-page-objects state)]
|
||||||
|
(->> (wsh/lookup-selected state)
|
||||||
|
(cp/clean-loops objects)
|
||||||
|
(map #(get objects %))
|
||||||
|
(filter #(not= :frame (:type %)))
|
||||||
|
(map #(assoc % ::index (cp/position-on-parent (:id %) objects)))
|
||||||
|
(sort-by ::index))))
|
||||||
|
|
||||||
|
(defn create-bool-data
|
||||||
|
[type name shapes]
|
||||||
|
(let [head (first shapes)
|
||||||
|
selrect (gsh/selection-rect shapes)]
|
||||||
|
(-> {:id (uuid/next)
|
||||||
|
:type :bool
|
||||||
|
:bool-type type
|
||||||
|
:frame-id (:frame-id head)
|
||||||
|
:parent-id (:parent-id head)
|
||||||
|
:name name
|
||||||
|
::index (::index head)
|
||||||
|
:shapes []}
|
||||||
|
(gsh/setup selrect))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn create-bool
|
||||||
|
[bool-type]
|
||||||
|
(ptk/reify ::create-bool-union
|
||||||
|
ptk/WatchEvent
|
||||||
|
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
|
base-name (-> bool-type d/name str/capital (str "-1"))
|
||||||
|
name (-> (dwc/retrieve-used-names objects)
|
||||||
|
(dwc/generate-unique-name base-name))
|
||||||
|
shapes (selected-shapes state)]
|
||||||
|
|
||||||
|
(when-not (empty? shapes)
|
||||||
|
(let [boolean-data (create-bool-data bool-type name shapes)
|
||||||
|
shape-id (:id boolean-data)
|
||||||
|
changes (-> (cb/empty-changes it page-id)
|
||||||
|
(cb/add-obj boolean-data)
|
||||||
|
(cb/change-parent shape-id shapes))]
|
||||||
|
(rx/of (dch/commit-changes changes)
|
||||||
|
(dwc/select-shapes (d/ordered-set shape-id)))))))))
|
|
@ -260,6 +260,11 @@
|
||||||
:command ["alt" "."]
|
:command ["alt" "."]
|
||||||
:type "keyup"
|
:type "keyup"
|
||||||
:fn #(st/emit! (dw/toggle-distances-display false))}
|
:fn #(st/emit! (dw/toggle-distances-display false))}
|
||||||
|
|
||||||
|
:create-union {:tooltip (ds/alt "U")
|
||||||
|
:command ["alt" "u"]
|
||||||
|
:fn #(st/emit! (dw/create-bool :union))}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
(defn get-tooltip [shortcut]
|
(defn get-tooltip [shortcut]
|
||||||
|
|
75
frontend/src/app/main/ui/shapes/bool.cljs
Normal file
75
frontend/src/app/main/ui/shapes/bool.cljs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.ui.shapes.bool
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.math :as mth]
|
||||||
|
[app.util.object :as obj]
|
||||||
|
[app.util.path.bool :as pb]
|
||||||
|
[app.util.path.geom :as upg]
|
||||||
|
[app.util.path.shapes-to-path :as stp]
|
||||||
|
[clojure.set :as set]
|
||||||
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
(mf/defc path-points
|
||||||
|
[{:keys [points color]}]
|
||||||
|
|
||||||
|
[:*
|
||||||
|
(for [[idx {:keys [x y]}] (d/enumerate points)]
|
||||||
|
[:circle {:key (str "circle-" idx)
|
||||||
|
:cx x
|
||||||
|
:cy y
|
||||||
|
:r 5
|
||||||
|
:style {:fill color
|
||||||
|
;;:fillOpacity 0.5
|
||||||
|
}}])])
|
||||||
|
|
||||||
|
(defn bool-shape
|
||||||
|
[shape-wrapper]
|
||||||
|
(mf/fnc bool-shape
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [frame (obj/get props "frame")
|
||||||
|
childs (obj/get props "childs")
|
||||||
|
shape-1 (stp/convert-to-path (nth childs 0))
|
||||||
|
shape-2 (stp/convert-to-path (nth childs 1))
|
||||||
|
|
||||||
|
content-1 (-> shape-1 gsh/transform-shape (gsh/translate-to-frame frame) :content)
|
||||||
|
content-2 (-> shape-2 gsh/transform-shape (gsh/translate-to-frame frame) :content)
|
||||||
|
|
||||||
|
|
||||||
|
[content-1' content-2'] (pb/content-intersect-split content-1 content-2)
|
||||||
|
|
||||||
|
points-1 (->> (upg/content->points content-1')
|
||||||
|
(map #(hash-map :x (mth/round (:x %))
|
||||||
|
:y (mth/round (:y %))))
|
||||||
|
(into #{}))
|
||||||
|
|
||||||
|
points-2 (->> (upg/content->points content-2')
|
||||||
|
(map #(hash-map :x (mth/round (:x %))
|
||||||
|
:y (mth/round (:y %))))
|
||||||
|
(into #{}))
|
||||||
|
|
||||||
|
points-3 (set/intersection points-1 points-2)]
|
||||||
|
|
||||||
|
[:*
|
||||||
|
[:& shape-wrapper {:shape (-> shape-1 #_(assoc :content content-1'))
|
||||||
|
:frame frame}]
|
||||||
|
|
||||||
|
[:& shape-wrapper {:shape (-> shape-2 #_(assoc :content content-2'))
|
||||||
|
:frame frame}]
|
||||||
|
|
||||||
|
[:& path-points {:points points-1 :color "#FF0000"}]
|
||||||
|
[:& path-points {:points points-2 :color "#0000FF"}]
|
||||||
|
[:& path-points {:points points-3 :color "#FF00FF"}]
|
||||||
|
|
||||||
|
|
||||||
|
])))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,14 @@
|
||||||
:on-accept confirm-update-remote-component}))
|
:on-accept confirm-update-remote-component}))
|
||||||
do-show-component (st/emitf (dw/go-to-layout :assets))
|
do-show-component (st/emitf (dw/go-to-layout :assets))
|
||||||
do-navigate-component-file (st/emitf (dwl/nav-to-component-file
|
do-navigate-component-file (st/emitf (dwl/nav-to-component-file
|
||||||
(:component-file shape)))]
|
(:component-file shape)))
|
||||||
|
|
||||||
|
do-create-bool-shape (st/emitf (dw/create-bool :union))]
|
||||||
[:*
|
[:*
|
||||||
|
;;
|
||||||
|
[:& menu-entry {:title ">BOOL"
|
||||||
|
:on-click do-create-bool-shape}]
|
||||||
|
;;
|
||||||
[:& menu-entry {:title (tr "workspace.shape.menu.copy")
|
[:& menu-entry {:title (tr "workspace.shape.menu.copy")
|
||||||
:shortcut (sc/get-tooltip :copy)
|
:shortcut (sc/get-tooltip :copy)
|
||||||
:on-click do-copy}]
|
:on-click do-copy}]
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
[app.main.ui.shapes.image :as image]
|
[app.main.ui.shapes.image :as image]
|
||||||
[app.main.ui.shapes.rect :as rect]
|
[app.main.ui.shapes.rect :as rect]
|
||||||
[app.main.ui.shapes.text.fontfaces :as ff]
|
[app.main.ui.shapes.text.fontfaces :as ff]
|
||||||
|
[app.main.ui.workspace.shapes.bool :as bool]
|
||||||
[app.main.ui.workspace.shapes.bounding-box :refer [bounding-box]]
|
[app.main.ui.workspace.shapes.bounding-box :refer [bounding-box]]
|
||||||
[app.main.ui.workspace.shapes.common :as common]
|
[app.main.ui.workspace.shapes.common :as common]
|
||||||
[app.main.ui.workspace.shapes.frame :as frame]
|
[app.main.ui.workspace.shapes.frame :as frame]
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
(declare shape-wrapper)
|
(declare shape-wrapper)
|
||||||
(declare group-wrapper)
|
(declare group-wrapper)
|
||||||
(declare svg-raw-wrapper)
|
(declare svg-raw-wrapper)
|
||||||
|
(declare bool-wrapper)
|
||||||
(declare frame-wrapper)
|
(declare frame-wrapper)
|
||||||
|
|
||||||
(def circle-wrapper (common/generic-wrapper-factory circle/circle-shape))
|
(def circle-wrapper (common/generic-wrapper-factory circle/circle-shape))
|
||||||
|
@ -92,13 +94,14 @@
|
||||||
[:*
|
[:*
|
||||||
(if-not svg-element?
|
(if-not svg-element?
|
||||||
(case (:type shape)
|
(case (:type shape)
|
||||||
:path [:> path/path-wrapper opts]
|
:path [:> path/path-wrapper opts]
|
||||||
:text [:> text/text-wrapper opts]
|
:text [:> text/text-wrapper opts]
|
||||||
:group [:> group-wrapper opts]
|
:group [:> group-wrapper opts]
|
||||||
:rect [:> rect-wrapper opts]
|
:rect [:> rect-wrapper opts]
|
||||||
:image [:> image-wrapper opts]
|
:image [:> image-wrapper opts]
|
||||||
:circle [:> circle-wrapper opts]
|
:circle [:> circle-wrapper opts]
|
||||||
:svg-raw [:> svg-raw-wrapper opts]
|
:svg-raw [:> svg-raw-wrapper opts]
|
||||||
|
:bool [:> bool-wrapper opts]
|
||||||
|
|
||||||
;; Only used when drawing a new frame.
|
;; Only used when drawing a new frame.
|
||||||
:frame [:> frame-wrapper {:shape shape}]
|
:frame [:> frame-wrapper {:shape shape}]
|
||||||
|
@ -113,5 +116,6 @@
|
||||||
|
|
||||||
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
||||||
(def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper))
|
(def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper))
|
||||||
|
(def bool-wrapper (bool/bool-wrapper-factory shape-wrapper))
|
||||||
(def frame-wrapper (frame/frame-wrapper-factory shape-wrapper))
|
(def frame-wrapper (frame/frame-wrapper-factory shape-wrapper))
|
||||||
|
|
||||||
|
|
44
frontend/src/app/main/ui/workspace/shapes/bool.cljs
Normal file
44
frontend/src/app/main/ui/workspace/shapes/bool.cljs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.ui.workspace.shapes.bool
|
||||||
|
(:require
|
||||||
|
[app.main.data.workspace :as dw]
|
||||||
|
[app.main.refs :as refs]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.main.streams :as ms]
|
||||||
|
[app.main.ui.shapes.bool :as bool]
|
||||||
|
[app.main.ui.shapes.shape :refer [shape-container]]
|
||||||
|
[app.util.dom :as dom]
|
||||||
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
(defn use-double-click [{:keys [id]}]
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps id)
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(dom/prevent-default event)
|
||||||
|
(st/emit! (dw/select-inside-group id @ms/mouse-position)))))
|
||||||
|
|
||||||
|
(defn bool-wrapper-factory
|
||||||
|
[shape-wrapper]
|
||||||
|
(let [shape-component (bool/bool-shape shape-wrapper)]
|
||||||
|
(mf/fnc bool-wrapper
|
||||||
|
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "frame"]))]
|
||||||
|
::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [shape (unchecked-get props "shape")
|
||||||
|
frame (unchecked-get props "frame")
|
||||||
|
|
||||||
|
childs-ref (mf/use-memo (mf/deps shape) #(refs/objects-by-id (:shapes shape) {:with-modifiers? true}))
|
||||||
|
childs (mf/deref childs-ref)]
|
||||||
|
|
||||||
|
[:> shape-container {:shape shape}
|
||||||
|
[:& shape-component
|
||||||
|
{:frame frame
|
||||||
|
:shape shape
|
||||||
|
:childs childs}]]))))
|
||||||
|
|
Loading…
Add table
Reference in a new issue