penpot/frontend/src/app/main/ui/workspace/shapes.cljs
2021-09-27 21:58:29 +02:00

121 lines
4.4 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) UXBOX Labs SL
(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.geom.shapes :as geom]
[app.common.pages :as cp]
[app.common.uuid :as uuid]
[app.main.refs :as refs]
[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.bounding-box :refer [bounding-box]]
[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.debug :refer [debug?]]
[app.util.object :as obj]
[okulary.core :as l]
[rumext.alpha :as mf]))
(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))
(def image-wrapper (common/generic-wrapper-factory image/image-shape))
(def rect-wrapper (common/generic-wrapper-factory rect/rect-shape))
(defn make-is-moving-ref
[id]
(fn []
(let [check-moving (fn [local]
(and (= :move (:transform local))
(contains? (:selected local) id)))]
(l/derived check-moving refs/workspace-local))))
(mf/defc root-shape
"Draws the root shape of the viewport and recursively all the shapes"
{::mf/wrap-props false}
[props]
(let [objects (obj/get props "objects")
active-frames (obj/get props "active-frames")
root-shapes (get-in objects [uuid/zero :shapes])
shapes (->> root-shapes (mapv #(get objects %)))
root-children (->> shapes
(filter #(not= :frame (:type %)))
(mapcat #(cp/get-object-with-children (:id %) objects)))]
[:*
[:& ff/fontfaces-style {:shapes root-children}]
(for [item shapes]
(if (= (:type item) :frame)
[:& frame-wrapper {:shape item
:key (:id item)
:objects objects
:thumbnail? (not (get active-frames (:id item) false))}]
[:& shape-wrapper {:shape item
:key (:id item)}]))]))
(mf/defc shape-wrapper
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "frame"]))]
::mf/wrap-props false}
[props]
(let [shape (obj/get props "shape")
frame (obj/get props "frame")
shape (-> (geom/transform-shape shape {:round-coords? false})
(geom/translate-to-frame frame))
opts #js {:shape shape
:frame frame}
svg-element? (and (= (:type shape) :svg-raw)
(not= :svg (get-in shape [:content :tag])))]
(when (and shape (not (:hidden shape)))
[:*
(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]
:svg-raw [:> svg-raw-wrapper opts]
:bool [:> bool-wrapper opts]
;; Only used when drawing a new frame.
:frame [:> frame-wrapper {:shape shape}]
nil)
;; Don't wrap svg elements inside a <g> otherwise some can break
[:> svg-raw-wrapper opts])
(when (debug? :bounding-boxes)
[:& bounding-box {:shape shape :frame frame}])])))
(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))