🐛 Fixes some issues with bool shapes

This commit is contained in:
alonso.torres 2021-12-27 15:22:14 +01:00
parent 99a6142134
commit 4c86d5cfe3
15 changed files with 96 additions and 67 deletions

View file

@ -49,6 +49,8 @@
(update :points move-points move-vec) (update :points move-points move-vec)
(d/update-when :x + dx) (d/update-when :x + dx)
(d/update-when :y + dy) (d/update-when :y + dy)
(cond-> (= :bool (:type shape))
(update :bool-content gpa/move-content move-vec))
(cond-> (= :path (:type shape)) (cond-> (= :path (:type shape))
(update :content gpa/move-content move-vec))))) (update :content gpa/move-content move-vec)))))
@ -256,6 +258,7 @@
(let [points' (:points shape) (let [points' (:points shape)
points (gco/transform-points points' transform-mtx) points (gco/transform-points points' transform-mtx)
bool? (= (:type shape) :bool)
path? (= (:type shape) :path) path? (= (:type shape) :path)
rotated? (is-rotated? points) rotated? (is-rotated? points)
@ -273,6 +276,8 @@
rotation (mod (+ base-rotation modif-rotation) 360)] rotation (mod (+ base-rotation modif-rotation) 360)]
(-> shape (-> shape
(cond-> bool?
(update :bool-content gpa/transform-content transform-mtx))
(cond-> path? (cond-> path?
(update :content gpa/transform-content transform-mtx)) (update :content gpa/transform-content transform-mtx))
(cond-> (not path?) (cond-> (not path?)

View file

@ -252,7 +252,6 @@
(ptk/reify ::select-next-frame (ptk/reify ::select-next-frame
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(prn "select-next-frame")
(let [route (:route state) (let [route (:route state)
pparams (:path-params route) pparams (:path-params route)
qparams (:query-params route) qparams (:query-params route)

View file

@ -24,7 +24,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.bool :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]

View file

@ -4,7 +4,7 @@
;; ;;
;; Copyright (c) UXBOX Labs SL ;; Copyright (c) UXBOX Labs SL
(ns app.main.data.workspace.booleans (ns app.main.data.workspace.bool
(:require (:require
[app.common.colors :as clr] [app.common.colors :as clr]
[app.common.data :as d] [app.common.data :as d]
@ -38,17 +38,20 @@
(and (contains? head :svg-attrs) (nil? (:fill-color head))) (and (contains? head :svg-attrs) (nil? (:fill-color head)))
(assoc :fill-color clr/black)) (assoc :fill-color clr/black))
head-data (select-keys head stp/style-properties)] head-data (select-keys head stp/style-properties)
[(-> {:id (uuid/next)
:type :bool bool-shape
:bool-type bool-type (-> {:id (uuid/next)
:frame-id (:frame-id head) :type :bool
:parent-id (:parent-id head) :bool-type bool-type
:name name :frame-id (:frame-id head)
:shapes []} :parent-id (:parent-id head)
(merge head-data) :name name
(gsh/update-bool-selrect shapes objects)) :shapes (->> shapes (mapv :id))}
(cp/position-on-parent (:id head) objects)])) (merge head-data)
(gsh/update-bool-selrect shapes objects))]
[bool-shape (cp/position-on-parent (:id head) objects)]))
(defn group->bool (defn group->bool
[group bool-type objects] [group bool-type objects]

View file

@ -269,19 +269,19 @@
:type "keyup" :type "keyup"
:fn #(st/emit! (dw/toggle-distances-display false))} :fn #(st/emit! (dw/toggle-distances-display false))}
:boolean-union {:tooltip (ds/meta (ds/alt "U")) :bool-union {:tooltip (ds/meta (ds/alt "U"))
:command (ds/c-mod "alt+u") :command (ds/c-mod "alt+u")
:fn #(st/emit! (dw/create-bool :union))} :fn #(st/emit! (dw/create-bool :union))}
:boolean-difference {:tooltip (ds/meta (ds/alt "D")) :bool-difference {:tooltip (ds/meta (ds/alt "D"))
:command (ds/c-mod "alt+d") :command (ds/c-mod "alt+d")
:fn #(st/emit! (dw/create-bool :difference))} :fn #(st/emit! (dw/create-bool :difference))}
:boolean-intersection {:tooltip (ds/meta (ds/alt "I")) :bool-intersection {:tooltip (ds/meta (ds/alt "I"))
:command (ds/c-mod "alt+i") :command (ds/c-mod "alt+i")
:fn #(st/emit! (dw/create-bool :intersection))} :fn #(st/emit! (dw/create-bool :intersection))}
:boolean-exclude {:tooltip (ds/meta (ds/alt "E")) :bool-exclude {:tooltip (ds/meta (ds/alt "E"))
:command (ds/c-mod "alt+e") :command (ds/c-mod "alt+e")
:fn #(st/emit! (dw/create-bool :exclude))} :fn #(st/emit! (dw/create-bool :exclude))}

View file

@ -237,8 +237,7 @@
[:& wrapper {:shape frame :view-box vbox}]])) [:& wrapper {:shape frame :view-box vbox}]]))
(mf/defc component-svg (mf/defc component-svg
{::mf/wrap [mf/memo {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
#(mf/deferred % ts/idle-then-raf)]}
[{:keys [objects group zoom] :or {zoom 1} :as props}] [{:keys [objects group zoom] :or {zoom 1} :as props}]
(let [modifier (-> (gpt/point (:x group) (:y group)) (let [modifier (-> (gpt/point (:x group) (:y group))
(gpt/negate) (gpt/negate)
@ -249,17 +248,21 @@
include-metadata? (mf/use-ctx use/include-metadata-ctx) include-metadata? (mf/use-ctx use/include-metadata-ctx)
modifier-ids (concat [group-id] (cp/get-children group-id objects)) modifier-ids (concat [group-id] (cp/get-children group-id objects))
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier) update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
objects (reduce update-fn objects modifier-ids) modifiers (reduce update-fn {} modifier-ids)
group (assoc-in group [:modifiers :displacement] modifier) objects (gsh/merge-modifiers objects modifiers)
group (get objects group-id)
width (* (:width group) zoom) width (* (:width group) zoom)
height (* (:height group) zoom) height (* (:height group) zoom)
vbox (str "0 0 " (:width group 0) vbox (str "0 0 " (:width group 0)
" " (:height group 0)) " " (:height group 0))
wrapper (mf/use-memo group-wrapper
(mf/deps objects) (mf/use-memo
#(group-wrapper-factory objects))] (mf/deps objects)
#(group-wrapper-factory objects))]
[:svg {:view-box vbox [:svg {:view-box vbox
:width width :width width
@ -269,7 +272,7 @@
:xmlnsXlink "http://www.w3.org/1999/xlink" :xmlnsXlink "http://www.w3.org/1999/xlink"
:xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")} :xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")}
[:> shape-container {:shape group} [:> shape-container {:shape group}
[:& wrapper {:shape group :view-box vbox}]]])) [:& group-wrapper {:shape group :view-box vbox}]]]))
(mf/defc component-symbol (mf/defc component-symbol
[{:keys [id data] :as props}] [{:keys [id data] :as props}]

View file

@ -8,6 +8,7 @@
"A collection of derived refs." "A collection of derived refs."
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.path.commands :as upc] [app.common.path.commands :as upc]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
@ -246,11 +247,13 @@
(update shape :content upc/apply-content-modifiers content-modifiers) (update shape :content upc/apply-content-modifiers content-modifiers)
shape)))) shape))))
(defn select-children [id] (defn select-bool-children [id]
(let [selector (let [selector
(fn [state] (fn [state]
(let [objects (wsh/lookup-page-objects state)] (let [objects (wsh/lookup-page-objects state)
modifiers (:workspace-modifiers state)]
(as-> (cp/select-children id objects) $ (as-> (cp/select-children id objects) $
(gsh/merge-modifiers $ modifiers)
(d/mapm (set-content-modifiers state) $))))] (d/mapm (set-content-modifiers state) $))))]
(l/derived selector st/state =))) (l/derived selector st/state =)))

View file

@ -29,11 +29,11 @@
(def auto-fix (icon-xref :auto-fix)) (def auto-fix (icon-xref :auto-fix))
(def auto-height (icon-xref :auto-height)) (def auto-height (icon-xref :auto-height))
(def auto-width (icon-xref :auto-width)) (def auto-width (icon-xref :auto-width))
(def boolean-difference (icon-xref :boolean-difference)) (def bool-difference (icon-xref :boolean-difference))
(def boolean-exclude (icon-xref :boolean-exclude)) (def bool-exclude (icon-xref :boolean-exclude))
(def boolean-flatten (icon-xref :boolean-flatten)) (def bool-flatten (icon-xref :boolean-flatten))
(def boolean-intersection (icon-xref :boolean-intersection)) (def bool-intersection (icon-xref :boolean-intersection))
(def boolean-union (icon-xref :boolean-union)) (def bool-union (icon-xref :boolean-union))
(def box (icon-xref :box)) (def box (icon-xref :box))
(def chain (icon-xref :chain)) (def chain (icon-xref :chain))
(def chat (icon-xref :chat)) (def chat (icon-xref :chat))

View file

@ -6,6 +6,7 @@
(ns app.main.ui.shapes.bool (ns app.main.ui.shapes.bool
(:require (:require
[app.common.data :as d]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.main.ui.hooks :refer [use-equal-memo]] [app.main.ui.hooks :refer [use-equal-memo]]
[app.main.ui.shapes.export :as use] [app.main.ui.shapes.export :as use]
@ -26,11 +27,19 @@
bool-content bool-content
(mf/use-memo (mf/use-memo
(mf/deps shape childs) (mf/deps shape childs)
#(or (:bool-content shape) (fn []
(gsh/calc-bool-content shape childs)))] (cond
(some? (:bool-content shape))
(:bool-content shape)
(some? childs)
(->> childs
(d/mapm #(gsh/transform-shape %2))
(gsh/calc-bool-content shape)))))]
[:* [:*
[:& path-shape {:shape (assoc shape :content bool-content)}] (when (some? bool-content)
[:& path-shape {:shape (assoc shape :content bool-content)}])
(when include-metadata? (when include-metadata?
[:> "penpot:bool" {} [:> "penpot:bool" {}

View file

@ -57,8 +57,7 @@
(let [{:keys [hover selected zoom]} local (let [{:keys [hover selected zoom]} local
hover-shape (-> (or (first (resolve-shapes objects [hover])) frame) hover-shape (-> (or (first (resolve-shapes objects [hover])) frame)
(gsh/translate-to-frame frame)) (gsh/translate-to-frame frame))
selected-shapes (->> (resolve-shapes objects selected) selected-shapes (->> (resolve-shapes objects selected))
(map #(gsh/translate-to-frame % frame)))
selrect (gsh/selection-rect selected-shapes) selrect (gsh/selection-rect selected-shapes)
bounds (frame->bounds frame)] bounds (frame->bounds frame)]

View file

@ -250,16 +250,16 @@
(or multiple? (and single? (or is-group? is-bool?)))) (or multiple? (and single? (or is-group? is-bool?))))
[:& menu-entry {:title (tr "workspace.shape.menu.path")} [:& menu-entry {:title (tr "workspace.shape.menu.path")}
[:& menu-entry {:title (tr "workspace.shape.menu.union") [:& menu-entry {:title (tr "workspace.shape.menu.union")
:shortcut (sc/get-tooltip :boolean-union) :shortcut (sc/get-tooltip :bool-union)
:on-click (set-bool :union)}] :on-click (set-bool :union)}]
[:& menu-entry {:title (tr "workspace.shape.menu.difference") [:& menu-entry {:title (tr "workspace.shape.menu.difference")
:shortcut (sc/get-tooltip :boolean-difference) :shortcut (sc/get-tooltip :bool-difference)
:on-click (set-bool :difference)}] :on-click (set-bool :difference)}]
[:& menu-entry {:title (tr "workspace.shape.menu.intersection") [:& menu-entry {:title (tr "workspace.shape.menu.intersection")
:shortcut (sc/get-tooltip :boolean-intersection) :shortcut (sc/get-tooltip :bool-intersection)
:on-click (set-bool :intersection)}] :on-click (set-bool :intersection)}]
[:& menu-entry {:title (tr "workspace.shape.menu.exclude") [:& menu-entry {:title (tr "workspace.shape.menu.exclude")
:shortcut (sc/get-tooltip :boolean-exclude) :shortcut (sc/get-tooltip :bool-exclude)
:on-click (set-bool :exclude)}] :on-click (set-bool :exclude)}]
(when (and single? is-bool? (not disable-flatten?)) (when (and single? is-bool? (not disable-flatten?))

View file

@ -30,15 +30,23 @@
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))] {::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
::mf/wrap-props false} ::mf/wrap-props false}
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
childs-ref (mf/use-memo child-sel-ref (mf/use-memo
(mf/deps (:id shape)) (mf/deps (:id shape))
#(refs/select-children (:id shape))) #(refs/is-child-selected? (:id shape)))
childs (mf/deref childs-ref)] childs-ref (mf/use-memo
(mf/deps (:id shape))
#(refs/select-bool-children (:id shape)))
child-sel? (mf/deref child-sel-ref)
childs (mf/deref childs-ref)
shape (cond-> shape
child-sel?
(dissoc :bool-content))]
[:> shape-container {:shape shape} [:> shape-container {:shape shape}
[:& shape-component [:& shape-component {:shape shape
{:shape shape :childs childs}]]))))
:childs childs}]]))))

View file

@ -42,10 +42,10 @@
i/mask i/mask
i/folder)) i/folder))
:bool (case (:bool-type shape) :bool (case (:bool-type shape)
:difference i/boolean-difference :difference i/bool-difference
:exclude i/boolean-exclude :exclude i/bool-exclude
:intersection i/boolean-intersection :intersection i/bool-intersection
#_:default i/boolean-union) #_:default i/bool-union)
:svg-raw i/file-svg :svg-raw i/file-svg
nil)) nil))

View file

@ -12,7 +12,7 @@
[app.main.ui.components.tab-container :refer [tab-container tab-element]] [app.main.ui.components.tab-container :refer [tab-container tab-element]]
[app.main.ui.context :as ctx] [app.main.ui.context :as ctx]
[app.main.ui.workspace.sidebar.options.menus.align :refer [align-options]] [app.main.ui.workspace.sidebar.options.menus.align :refer [align-options]]
[app.main.ui.workspace.sidebar.options.menus.booleans :refer [booleans-options]] [app.main.ui.workspace.sidebar.options.menus.bool :refer [bool-options]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu]] [app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu]]
[app.main.ui.workspace.sidebar.options.menus.interactions :refer [interactions-menu]] [app.main.ui.workspace.sidebar.options.menus.interactions :refer [interactions-menu]]
[app.main.ui.workspace.sidebar.options.page :as page] [app.main.ui.workspace.sidebar.options.page :as page]
@ -63,7 +63,7 @@
:title (tr "workspace.options.design")} :title (tr "workspace.options.design")}
[:div.element-options [:div.element-options
[:& align-options] [:& align-options]
[:& booleans-options] [:& bool-options]
(case (count selected) (case (count selected)
0 [:& page/options] 0 [:& page/options]
1 [:& shape-options {:shape (first shapes) 1 [:& shape-options {:shape (first shapes)

View file

@ -4,7 +4,7 @@
;; ;;
;; Copyright (c) UXBOX Labs SL ;; Copyright (c) UXBOX Labs SL
(ns app.main.ui.workspace.sidebar.options.menus.booleans (ns app.main.ui.workspace.sidebar.options.menus.bool
(:require (:require
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.shortcuts :as sc] [app.main.data.workspace.shortcuts :as sc]
@ -15,7 +15,7 @@
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.alpha :as mf])) [rumext.alpha :as mf]))
(mf/defc booleans-options (mf/defc bool-options
[] []
(let [selected (mf/deref refs/selected-objects) (let [selected (mf/deref refs/selected-objects)
selected-with-children (mf/deref refs/selected-shapes-with-children) selected-with-children (mf/deref refs/selected-shapes-with-children)
@ -52,37 +52,37 @@
[:div.align-options [:div.align-options
[:div.align-group [:div.align-group
[:div.align-button.tooltip.tooltip-bottom [:div.align-button.tooltip.tooltip-bottom
{:alt (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :boolean-union) ")") {:alt (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :bool-union) ")")
:class (dom/classnames :disabled disabled-bool-btns :class (dom/classnames :disabled disabled-bool-btns
:selected (= head-bool-type :union)) :selected (= head-bool-type :union))
:on-click (set-bool :union)} :on-click (set-bool :union)}
i/boolean-union] i/bool-union]
[:div.align-button.tooltip.tooltip-bottom [:div.align-button.tooltip.tooltip-bottom
{:alt (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :boolean-difference) ")") {:alt (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :bool-difference) ")")
:class (dom/classnames :disabled disabled-bool-btns :class (dom/classnames :disabled disabled-bool-btns
:selected (= head-bool-type :difference)) :selected (= head-bool-type :difference))
:on-click (set-bool :difference)} :on-click (set-bool :difference)}
i/boolean-difference] i/bool-difference]
[:div.align-button.tooltip.tooltip-bottom [:div.align-button.tooltip.tooltip-bottom
{:alt (str (tr "workspace.shape.menu.intersection") " (" (sc/get-tooltip :boolean-intersection) ")") {:alt (str (tr "workspace.shape.menu.intersection") " (" (sc/get-tooltip :bool-intersection) ")")
:class (dom/classnames :disabled disabled-bool-btns :class (dom/classnames :disabled disabled-bool-btns
:selected (= head-bool-type :intersection)) :selected (= head-bool-type :intersection))
:on-click (set-bool :intersection)} :on-click (set-bool :intersection)}
i/boolean-intersection] i/bool-intersection]
[:div.align-button.tooltip.tooltip-bottom [:div.align-button.tooltip.tooltip-bottom
{:alt (str (tr "workspace.shape.menu.exclude") " (" (sc/get-tooltip :boolean-exclude) ")") {:alt (str (tr "workspace.shape.menu.exclude") " (" (sc/get-tooltip :bool-exclude) ")")
:class (dom/classnames :disabled disabled-bool-btns :class (dom/classnames :disabled disabled-bool-btns
:selected (= head-bool-type :exclude)) :selected (= head-bool-type :exclude))
:on-click (set-bool :exclude)} :on-click (set-bool :exclude)}
i/boolean-exclude]] i/bool-exclude]]
[:div.align-group [:div.align-group
[:div.align-button.tooltip.tooltip-bottom [:div.align-button.tooltip.tooltip-bottom
{:alt (tr "workspace.shape.menu.flatten") {:alt (tr "workspace.shape.menu.flatten")
:class (dom/classnames :disabled disabled-flatten) :class (dom/classnames :disabled disabled-flatten)
:on-click (st/emitf (dw/convert-selected-to-path))} :on-click (st/emitf (dw/convert-selected-to-path))}
i/boolean-flatten]]])) i/bool-flatten]]]))