0
Fork 0
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:
alonso.torres 2021-09-09 14:48:32 +02:00
parent 5031700af6
commit 9f08153a85
8 changed files with 276 additions and 8 deletions

View 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 %)))))

View file

@ -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)

View 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)))))))))

View file

@ -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]

View 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"}]
])))

View file

@ -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}]

View file

@ -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))

View 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}]]))))