penpot/frontend/src/app/main/ui/workspace/shapes.cljs
2023-09-13 16:36:49 +02:00

125 lines
4.8 KiB
Clojure

;; 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) KALEIDOS INC
(ns app.main.ui.workspace.shapes
"A workspace specific shapes wrappers.
Shapes that has some peculiarities are defined in its own
namespace under app.ui.workspace.shapes.* prefix, all the
others are defined using a generic wrapper implemented in
common."
(:require
[app.common.data.macros :as dm]
[app.common.geom.rect :as grc]
[app.common.pages.helpers :as cph]
[app.common.uuid :as uuid]
[app.main.ui.context :as ctx]
[app.main.ui.shapes.circle :as circle]
[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.common :as common]
[app.main.ui.workspace.shapes.frame :as frame]
[app.main.ui.workspace.shapes.group :as group]
[app.main.ui.workspace.shapes.path :as path]
[app.main.ui.workspace.shapes.svg-raw :as svg-raw]
[app.main.ui.workspace.shapes.text :as text]
[app.util.object :as obj]
[rumext.v2 :as mf]))
(declare shape-wrapper)
(declare group-wrapper)
(declare svg-raw-wrapper)
(declare bool-wrapper)
(declare root-frame-wrapper)
(declare nested-frame-wrapper)
(def circle-wrapper (common/generic-wrapper-factory circle/circle-shape))
(def image-wrapper (common/generic-wrapper-factory image/image-shape))
(def rect-wrapper (common/generic-wrapper-factory rect/rect-shape))
(mf/defc root-shape
"Draws the root shape of the viewport and recursively all the shapes"
{::mf/wrap [mf/memo]
::mf/wrap-props false}
[props]
(let [objects (obj/get props "objects")
active-frames (obj/get props "active-frames")
shapes (cph/get-immediate-children objects)
vbox (mf/use-ctx ctx/current-vbox)
shapes (mf/with-memo [shapes vbox]
(if (some? vbox)
(filter (fn [shape]
(grc/overlaps-rects? vbox (dm/get-prop shape :selrect)))
shapes)
shapes))]
[:g {:id (dm/str "shape-" uuid/zero)}
[:& (mf/provider ctx/active-frames) {:value active-frames}
;; Render font faces only for shapes that are part of the root
;; frame but don't belongs to any other frame.
(let [xform (comp
(remove cph/frame-shape?)
(mapcat #(cph/get-children-with-self objects (:id %))))]
[:& ff/fontfaces-style {:shapes (into [] xform shapes)}])
[:g.frame-children
(for [shape shapes]
[:g.ws-shape-wrapper {:key (dm/str (dm/get-prop shape :id))}
(if ^boolean (cph/frame-shape? shape)
[:& root-frame-wrapper
{:shape shape
:thumbnail? (not (contains? active-frames (dm/get-prop shape :id)))}]
[:& shape-wrapper {:shape shape}])])]]]))
(mf/defc shape-wrapper
{::mf/wrap [#(mf/memo' % common/check-shape-props)]
::mf/wrap-props false}
[props]
(let [shape (unchecked-get props "shape")
shape-type (dm/get-prop shape :type)
shape-id (dm/get-prop shape :id)
;; FIXME: WARN: this breaks react rule of hooks (hooks can't be under conditional)
active-frames
(when (cph/root-frame? shape)
(mf/use-ctx ctx/active-frames))
thumbnail?
(and (some? active-frames)
(not (contains? active-frames shape-id)))
props #js {:shape shape :thumbnail? thumbnail?}
rawsvg? (= :svg-raw shape-type)
wrapper-elem (if ^boolean rawsvg? mf/Fragment "g")
wrapper-props (if ^boolean rawsvg?
#js {:className "workspace-shape-wrapper"}
#js {})]
(when (and (some? shape)
(not ^boolean (:hidden shape)))
[:> wrapper-elem wrapper-props
(case shape-type
:path [:> path/path-wrapper props]
:text [:> text/text-wrapper props]
:group [:> group-wrapper props]
:rect [:> rect-wrapper props]
:image [:> image-wrapper props]
:circle [:> circle-wrapper props]
:svg-raw [:> svg-raw-wrapper props]
:bool [:> bool-wrapper props]
:frame [:> nested-frame-wrapper props]
nil)])))
(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 root-frame-wrapper (frame/root-frame-wrapper-factory shape-wrapper))
(def nested-frame-wrapper (frame/nested-frame-wrapper-factory shape-wrapper))