From 9f08153a85c5ea003ae908e9f4c17b73738fe7c0 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 9 Sep 2021 14:48:32 +0200 Subject: [PATCH] :sparkles: Created bool shapes --- .../src/app/common/pages/changes_builder.cljc | 59 +++++++++++++++ frontend/src/app/main/data/workspace.cljs | 11 ++- .../src/app/main/data/workspace/booleans.cljs | 66 ++++++++++++++++ .../app/main/data/workspace/shortcuts.cljs | 5 ++ frontend/src/app/main/ui/shapes/bool.cljs | 75 +++++++++++++++++++ .../app/main/ui/workspace/context_menu.cljs | 8 +- .../src/app/main/ui/workspace/shapes.cljs | 16 ++-- .../app/main/ui/workspace/shapes/bool.cljs | 44 +++++++++++ 8 files changed, 276 insertions(+), 8 deletions(-) create mode 100644 common/src/app/common/pages/changes_builder.cljc create mode 100644 frontend/src/app/main/data/workspace/booleans.cljs create mode 100644 frontend/src/app/main/ui/shapes/bool.cljs create mode 100644 frontend/src/app/main/ui/workspace/shapes/bool.cljs diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc new file mode 100644 index 000000000..b16e984fb --- /dev/null +++ b/common/src/app/common/pages/changes_builder.cljc @@ -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 %))))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index a53fdcee3..476046781 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -23,6 +23,7 @@ [app.config :as cfg] [app.main.data.events :as ev] [app.main.data.messages :as dm] + [app.main.data.workspace.booleans :as dwb] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.common :as dwc] [app.main.data.workspace.drawing :as dwd] @@ -48,7 +49,8 @@ [cljs.spec.alpha :as s] [clojure.set :as set] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.core :as ptk] + )) ;; (log/set-level! :trace) @@ -1100,6 +1102,10 @@ :group (rx/of (dwc/select-shapes (into (d/ordered-set) [(last shapes)]))) + :bool + ;; TODO + (js/alert "TODO") + :svg-raw nil @@ -1987,3 +1993,6 @@ (d/export dwg/unmask-group) (d/export dwg/group-selected) (d/export dwg/ungroup-selected) + +;; Boolean +(d/export dwb/create-bool) diff --git a/frontend/src/app/main/data/workspace/booleans.cljs b/frontend/src/app/main/data/workspace/booleans.cljs new file mode 100644 index 000000000..6702af71d --- /dev/null +++ b/frontend/src/app/main/data/workspace/booleans.cljs @@ -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))))))))) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index d589df2e8..7373d6e76 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -260,6 +260,11 @@ :command ["alt" "."] :type "keyup" :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] diff --git a/frontend/src/app/main/ui/shapes/bool.cljs b/frontend/src/app/main/ui/shapes/bool.cljs new file mode 100644 index 000000000..be7337084 --- /dev/null +++ b/frontend/src/app/main/ui/shapes/bool.cljs @@ -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"}] + + + ]))) + + + diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 29180d9a1..ed9933297 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -98,8 +98,14 @@ :on-accept confirm-update-remote-component})) do-show-component (st/emitf (dw/go-to-layout :assets)) 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") :shortcut (sc/get-tooltip :copy) :on-click do-copy}] diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index b310d2118..70efd1f49 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -20,6 +20,7 @@ [app.main.ui.shapes.image :as image] [app.main.ui.shapes.rect :as rect] [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.common :as common] [app.main.ui.workspace.shapes.frame :as frame] @@ -35,6 +36,7 @@ (declare shape-wrapper) (declare group-wrapper) (declare svg-raw-wrapper) +(declare bool-wrapper) (declare frame-wrapper) (def circle-wrapper (common/generic-wrapper-factory circle/circle-shape)) @@ -92,13 +94,14 @@ [:* (if-not svg-element? (case (:type shape) - :path [:> path/path-wrapper opts] - :text [:> text/text-wrapper opts] - :group [:> group-wrapper opts] - :rect [:> rect-wrapper opts] - :image [:> image-wrapper opts] - :circle [:> circle-wrapper opts] + :path [:> path/path-wrapper opts] + :text [:> text/text-wrapper opts] + :group [:> group-wrapper opts] + :rect [:> rect-wrapper opts] + :image [:> image-wrapper opts] + :circle [:> circle-wrapper opts] :svg-raw [:> svg-raw-wrapper opts] + :bool [:> bool-wrapper opts] ;; Only used when drawing a new frame. :frame [:> frame-wrapper {:shape shape}] @@ -113,5 +116,6 @@ (def group-wrapper (group/group-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)) diff --git a/frontend/src/app/main/ui/workspace/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/shapes/bool.cljs new file mode 100644 index 000000000..a226eff57 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/shapes/bool.cljs @@ -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}]])))) +