mirror of
https://github.com/penpot/penpot.git
synced 2025-04-12 23:11:23 -05:00
🎉 Scaffolding to write unit tests of common types
This commit is contained in:
parent
165cdd871f
commit
54e0071c9c
35 changed files with 724 additions and 228 deletions
|
@ -11,6 +11,7 @@
|
|||
[app.common.pages :as cp]
|
||||
[app.common.pages.migrations :as pmg]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.db :as db]
|
||||
|
@ -69,7 +70,7 @@
|
|||
:or {is-shared false revn 0}
|
||||
:as params}]
|
||||
(let [id (or id (:id data) (uuid/next))
|
||||
data (or data (cp/make-file-data id))
|
||||
data (or data (ctf/make-file-data id))
|
||||
file (db/insert! conn :file
|
||||
(d/without-nils
|
||||
{:id id
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.pages.migrations :as pmg]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.db :as db]
|
||||
[app.db.sql :as sql]
|
||||
[app.rpc.helpers :as rpch]
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.logging :as l]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.pages.migrations :as pmg]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.db :as db]
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.changes :as ch]
|
||||
[app.common.pages.changes-spec :as pcs]
|
||||
[app.common.pages.init :as init]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
|
@ -169,7 +169,7 @@
|
|||
([id name]
|
||||
{:id id
|
||||
:name name
|
||||
:data (-> init/empty-file-data
|
||||
:data (-> ctf/empty-file-data
|
||||
(assoc :id id))
|
||||
|
||||
;; We keep the changes so we can send them to the backend
|
||||
|
@ -209,7 +209,7 @@
|
|||
|
||||
(defn add-artboard [file data]
|
||||
(assert (nil? (:current-component-id file)))
|
||||
(let [obj (-> (init/make-minimal-shape :frame)
|
||||
(let [obj (-> (cts/make-minimal-shape :frame)
|
||||
(merge data)
|
||||
(check-name file :frame)
|
||||
(setup-selrect)
|
||||
|
@ -233,9 +233,9 @@
|
|||
|
||||
(defn add-group [file data]
|
||||
(let [frame-id (:current-frame-id file)
|
||||
selrect init/empty-selrect
|
||||
selrect cts/empty-selrect
|
||||
name (:name data)
|
||||
obj (-> (init/make-minimal-group frame-id selrect name)
|
||||
obj (-> (cts/make-minimal-group frame-id selrect name)
|
||||
(merge data)
|
||||
(check-name file :group)
|
||||
(d/without-nils))]
|
||||
|
@ -347,7 +347,7 @@
|
|||
(update :parent-stack pop))))
|
||||
|
||||
(defn create-shape [file type data]
|
||||
(let [obj (-> (init/make-minimal-shape type)
|
||||
(let [obj (-> (cts/make-minimal-shape type)
|
||||
(merge data)
|
||||
(check-name file :type)
|
||||
(setup-selrect)
|
||||
|
@ -515,10 +515,10 @@
|
|||
(defn start-component
|
||||
[file data]
|
||||
|
||||
(let [selrect init/empty-selrect
|
||||
(let [selrect cts/empty-selrect
|
||||
name (:name data)
|
||||
path (:path data)
|
||||
obj (-> (init/make-minimal-group nil selrect name)
|
||||
obj (-> (cts/make-minimal-group nil selrect name)
|
||||
(merge data)
|
||||
(check-name file :group)
|
||||
(d/without-nils))]
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[app.common.pages.common :as common]
|
||||
[app.common.pages.focus :as focus]
|
||||
[app.common.pages.indices :as indices]
|
||||
[app.common.pages.init :as init]))
|
||||
[app.common.types.file :as ctf]))
|
||||
|
||||
;; Common
|
||||
(dm/export common/root)
|
||||
|
@ -36,11 +36,5 @@
|
|||
(dm/export changes/process-changes)
|
||||
|
||||
;; Initialization
|
||||
(dm/export init/default-frame-attrs)
|
||||
(dm/export init/default-shape-attrs)
|
||||
(dm/export init/make-file-data)
|
||||
(dm/export init/make-minimal-shape)
|
||||
(dm/export init/make-minimal-group)
|
||||
(dm/export init/empty-file-data)
|
||||
(dm/export init/setup-shape)
|
||||
(dm/export init/setup-rect-selrect)
|
||||
(dm/export ctf/make-file-data)
|
||||
(dm/export ctf/empty-file-data)
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.pages.common :refer [component-sync-attrs]]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.pages.init :as init]
|
||||
[app.common.spec :as us]
|
||||
[app.common.pages.changes-spec :as pcs]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
|
@ -346,13 +346,13 @@
|
|||
|
||||
(defmethod process-change :add-component
|
||||
[data {:keys [id name path main-instance-id main-instance-page shapes]}]
|
||||
(assoc-in data [:components id]
|
||||
{:id id
|
||||
:name name
|
||||
:path path
|
||||
:main-instance-id main-instance-id
|
||||
:main-instance-page main-instance-page
|
||||
:objects (d/index-by :id shapes)}))
|
||||
(ctkl/add-component data
|
||||
id
|
||||
name
|
||||
path
|
||||
main-instance-id
|
||||
main-instance-page
|
||||
shapes))
|
||||
|
||||
(defmethod process-change :mod-component
|
||||
[data {:keys [id name path objects]}]
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
;; Auxiliary functions to help create a set of changes (undo + redo)
|
||||
|
@ -49,7 +50,7 @@
|
|||
|
||||
(defn with-objects
|
||||
[changes objects]
|
||||
(let [file-data (-> (cp/make-file-data (uuid/next) uuid/zero)
|
||||
(let [file-data (-> (ctf/make-file-data (uuid/next) uuid/zero)
|
||||
(assoc-in [:pages-index uuid/zero :objects] objects))]
|
||||
(vary-meta changes assoc ::file-data file-data
|
||||
::applied-changes-count 0)))
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.path :as gsp]
|
||||
[app.common.geom.shapes.text :as gsht]
|
||||
|
@ -16,9 +15,10 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.container :as ctc]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.uuid :as uuid]
|
||||
[cuerdas.core :as str]))
|
||||
|
@ -89,7 +89,7 @@
|
|||
|
||||
(fix-empty-points [shape]
|
||||
(let [shape (cond-> shape
|
||||
(empty? (:selrect shape)) (cp/setup-rect-selrect))]
|
||||
(empty? (:selrect shape)) (cts/setup-rect-selrect))]
|
||||
(cond-> shape
|
||||
(empty? (:points shape))
|
||||
(assoc :points (gsh/rect->points (:selrect shape))))))
|
||||
|
@ -456,7 +456,7 @@
|
|||
(let [page (ctpl/get-page data page-id)
|
||||
|
||||
[new-shape new-shapes]
|
||||
(ctc/instantiate-component page
|
||||
(ctn/instantiate-component page
|
||||
component
|
||||
(:id data)
|
||||
position)
|
||||
|
|
28
common/src/app/common/types/components_list.cljc
Normal file
28
common/src/app/common/types/components_list.cljc
Normal file
|
@ -0,0 +1,28 @@
|
|||
;; 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.types.components-list
|
||||
(:require
|
||||
[app.common.data :as d]))
|
||||
|
||||
(defn components-seq
|
||||
[file-data]
|
||||
(vals (:components file-data)))
|
||||
|
||||
(defn add-component
|
||||
[file-data id name path main-instance-id main-instance-page shapes]
|
||||
(assoc-in file-data [:components id]
|
||||
{:id id
|
||||
:name name
|
||||
:path path
|
||||
:main-instance-id main-instance-id
|
||||
:main-instance-page main-instance-page
|
||||
:objects (d/index-by :id shapes)}))
|
||||
|
||||
(defn get-component
|
||||
[file-data component-id]
|
||||
(get-in file-data [:components component-id]))
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
(s/def ::type #{:page :component})
|
||||
|
@ -18,9 +18,32 @@
|
|||
(s/def ::path (s/nilable string?))
|
||||
|
||||
(s/def ::container
|
||||
(s/keys :req-un [::id ::name ::ctt/objects]
|
||||
(s/keys :req-un [::id ::name ::ctst/objects]
|
||||
:opt-un [::type ::path]))
|
||||
|
||||
(defn make-container
|
||||
[page-or-component type]
|
||||
(assoc page-or-component :type type))
|
||||
|
||||
(defn page?
|
||||
[container]
|
||||
(= (:type container) :page))
|
||||
|
||||
(defn component?
|
||||
[container]
|
||||
(= (:type container) :component))
|
||||
|
||||
(defn get-container
|
||||
[file type id]
|
||||
(us/assert map? file)
|
||||
(us/assert ::type type)
|
||||
(us/assert uuid? id)
|
||||
|
||||
(-> (if (= type :page)
|
||||
(get-in file [:pages-index id])
|
||||
(get-in file [:components id]))
|
||||
(assoc :type type)))
|
||||
|
||||
(defn get-shape
|
||||
[container shape-id]
|
||||
(us/assert ::container container)
|
||||
|
@ -29,21 +52,65 @@
|
|||
(get :objects)
|
||||
(get shape-id)))
|
||||
|
||||
(defn shapes-seq
|
||||
[container]
|
||||
(vals (:objects container)))
|
||||
|
||||
(defn make-component-shape
|
||||
"Clone the shape and all children. Generate new ids and detach
|
||||
from parent and frame. Update the original shapes to have links
|
||||
to the new ones."
|
||||
[shape objects file-id]
|
||||
(assert (nil? (:component-id shape)))
|
||||
(assert (nil? (:component-file shape)))
|
||||
(assert (nil? (:shape-ref shape)))
|
||||
(let [;; Ensure that the component root is not an instance and
|
||||
;; it's no longer tied to a frame.
|
||||
update-new-shape (fn [new-shape _original-shape]
|
||||
(cond-> new-shape
|
||||
true
|
||||
(-> (assoc :frame-id nil)
|
||||
(dissoc :component-root?))
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(dissoc :component-id
|
||||
:component-file
|
||||
:shape-ref)))
|
||||
|
||||
;; Make the original shape an instance of the new component.
|
||||
;; If one of the original shape children already was a component
|
||||
;; instance, maintain this instanceness untouched.
|
||||
update-original-shape (fn [original-shape new-shape]
|
||||
(cond-> original-shape
|
||||
(nil? (:shape-ref original-shape))
|
||||
(-> (assoc :shape-ref (:id new-shape))
|
||||
(dissoc :touched))
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(assoc :component-id (:id new-shape)
|
||||
:component-file file-id
|
||||
:component-root? true)
|
||||
|
||||
(some? (:parent-id new-shape))
|
||||
(dissoc :component-root?)))]
|
||||
|
||||
(ctst/clone-object shape nil objects update-new-shape update-original-shape)))
|
||||
|
||||
(defn instantiate-component
|
||||
[container component component-file position]
|
||||
[container component component-file-id position]
|
||||
(let [component-shape (get-shape component (:id component))
|
||||
|
||||
orig-pos (gpt/point (:x component-shape) (:y component-shape))
|
||||
delta (gpt/subtract position orig-pos)
|
||||
|
||||
objects (:objects container)
|
||||
unames (volatile! (ctt/retrieve-used-names objects))
|
||||
unames (volatile! (ctst/retrieve-used-names objects))
|
||||
|
||||
frame-id (ctt/frame-id-by-position objects (gpt/add orig-pos delta))
|
||||
frame-id (ctst/frame-id-by-position objects (gpt/add orig-pos delta))
|
||||
|
||||
update-new-shape
|
||||
(fn [new-shape original-shape]
|
||||
(let [new-name (ctt/generate-unique-name @unames (:name new-shape))]
|
||||
(let [new-name (ctst/generate-unique-name @unames (:name new-shape))]
|
||||
|
||||
(when (nil? (:parent-id original-shape))
|
||||
(vswap! unames conj new-name))
|
||||
|
@ -62,7 +129,7 @@
|
|||
|
||||
(nil? (:parent-id original-shape))
|
||||
(assoc :component-id (:id original-shape)
|
||||
:component-file component-file
|
||||
:component-file component-file-id
|
||||
:component-root? true
|
||||
:name new-name)
|
||||
|
||||
|
@ -70,10 +137,10 @@
|
|||
(dissoc :component-root?))))
|
||||
|
||||
[new-shape new-shapes _]
|
||||
(ctt/clone-object component-shape
|
||||
nil
|
||||
(get component :objects)
|
||||
update-new-shape)]
|
||||
(ctst/clone-object component-shape
|
||||
nil
|
||||
(get component :objects)
|
||||
update-new-shape)]
|
||||
|
||||
[new-shape new-shapes]))
|
||||
|
||||
|
|
|
@ -6,10 +6,20 @@
|
|||
|
||||
(ns app.common.types.file
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.pages.common :refer [file-version]]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.page :as ctp]
|
||||
[clojure.spec.alpha :as s]))
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.spec.alpha :as s]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
;; Specs
|
||||
|
||||
(s/def :internal.media-object/name string?)
|
||||
(s/def :internal.media-object/width ::us/safe-integer)
|
||||
|
@ -57,3 +67,158 @@
|
|||
::recent-colors
|
||||
::typographies
|
||||
::media]))
|
||||
|
||||
;; Initialization
|
||||
|
||||
(def empty-file-data
|
||||
{:version file-version
|
||||
:pages []
|
||||
:pages-index {}})
|
||||
|
||||
(defn make-file-data
|
||||
([file-id]
|
||||
(make-file-data file-id (uuid/next)))
|
||||
|
||||
([file-id page-id]
|
||||
(let [page (ctp/make-empty-page page-id "Page-1")]
|
||||
(-> empty-file-data
|
||||
(assoc :id file-id)
|
||||
(ctpl/add-page page)))))
|
||||
|
||||
;; Helpers
|
||||
|
||||
(defn update-file-data
|
||||
[file f]
|
||||
(update file :data f))
|
||||
|
||||
(defn containers-seq
|
||||
"Generate a sequence of all pages and all components, wrapped as containers"
|
||||
[file-data]
|
||||
(concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data))
|
||||
(map #(ctn/make-container % :component) (ctkl/components-seq file-data))))
|
||||
|
||||
(defn absorb-assets
|
||||
"Find all assets of a library that are used in the file, and
|
||||
move them to the file local library."
|
||||
[file-data library-data]
|
||||
(let [library-page-id (uuid/next)
|
||||
|
||||
add-library-page
|
||||
(fn [file-data]
|
||||
(let [page (ctp/make-empty-page library-page-id "Library page")]
|
||||
(-> file-data
|
||||
(ctpl/add-page page))))
|
||||
|
||||
find-instances-in-container
|
||||
(fn [container component]
|
||||
(let [instances (filter #(= (:component-id %) (:id component))
|
||||
(ctn/shapes-seq container))]
|
||||
(when (d/not-empty? instances)
|
||||
[[container instances]])))
|
||||
|
||||
find-instances
|
||||
(fn [file-data component]
|
||||
(mapcat #(find-instances-in-container % component) (containers-seq file-data)))
|
||||
|
||||
absorb-component
|
||||
(fn [file-data _component]
|
||||
;; TODO: complete this
|
||||
file-data)
|
||||
|
||||
used-components
|
||||
(mapcat (fn [component]
|
||||
(let [instances (find-instances file-data component)]
|
||||
(when instances
|
||||
[[component instances]])))
|
||||
(ctkl/components-seq library-data))]
|
||||
|
||||
(if (empty? used-components)
|
||||
file-data
|
||||
(as-> file-data $
|
||||
(add-library-page $)
|
||||
(reduce absorb-component
|
||||
$
|
||||
used-components)))))
|
||||
|
||||
;; Debug helpers
|
||||
|
||||
(defn dump-tree
|
||||
([file-data page-id libraries]
|
||||
(dump-tree file-data page-id libraries false false))
|
||||
|
||||
([file-data page-id libraries show-ids]
|
||||
(dump-tree file-data page-id libraries show-ids false))
|
||||
|
||||
([file-data page-id libraries show-ids show-touched]
|
||||
(let [page (ctpl/get-page file-data page-id)
|
||||
objects (:objects page)
|
||||
components (:components file-data)
|
||||
root (d/seek #(nil? (:parent-id %)) (vals objects))]
|
||||
|
||||
(letfn [(show-shape [shape-id level objects]
|
||||
(let [shape (get objects shape-id)]
|
||||
(println (str/pad (str (str/repeat " " level)
|
||||
(:name shape)
|
||||
(when (seq (:touched shape)) "*")
|
||||
(when show-ids (str/format " <%s>" (:id shape))))
|
||||
{:length 20
|
||||
:type :right})
|
||||
(show-component shape objects))
|
||||
(when show-touched
|
||||
(when (seq (:touched shape))
|
||||
(println (str (str/repeat " " level)
|
||||
" "
|
||||
(str (:touched shape)))))
|
||||
(when (:remote-synced? shape)
|
||||
(println (str (str/repeat " " level)
|
||||
" (remote-synced)"))))
|
||||
(when (:shapes shape)
|
||||
(dorun (for [shape-id (:shapes shape)]
|
||||
(show-shape shape-id (inc level) objects))))))
|
||||
|
||||
(show-component [shape objects]
|
||||
(if (nil? (:shape-ref shape))
|
||||
""
|
||||
(let [root-shape (cph/get-component-shape objects shape)
|
||||
component-id (when root-shape (:component-id root-shape))
|
||||
component-file-id (when root-shape (:component-file root-shape))
|
||||
component-file (when component-file-id (get libraries component-file-id nil))
|
||||
component (when component-id
|
||||
(if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id)))
|
||||
component-shape (when (and component (:shape-ref shape))
|
||||
(get-in component [:objects (:shape-ref shape)]))]
|
||||
(str/format " %s--> %s%s%s"
|
||||
(cond (:component-root? shape) "#"
|
||||
(:component-id shape) "@"
|
||||
:else "-")
|
||||
(when component-file (str/format "<%s> " (:name component-file)))
|
||||
(or (:name component-shape) "?")
|
||||
(if (or (:component-root? shape)
|
||||
(nil? (:component-id shape))
|
||||
true)
|
||||
""
|
||||
(let [component-id (:component-id shape)
|
||||
component-file-id (:component-file shape)
|
||||
component-file (when component-file-id (get libraries component-file-id nil))
|
||||
component (if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id))]
|
||||
(str/format " (%s%s)"
|
||||
(when component-file (str/format "<%s> " (:name component-file)))
|
||||
(:name component))))))))]
|
||||
|
||||
(println "[Page]")
|
||||
(show-shape (:id root) 0 objects)
|
||||
|
||||
(dorun (for [component (vals components)]
|
||||
(do
|
||||
(println)
|
||||
(println (str/format "[%s]" (:name component))
|
||||
(when show-ids
|
||||
(str/format " (main: %s/%s)"
|
||||
(:main-instance-page component)
|
||||
(:main-instance-id component))))
|
||||
(show-shape (:id component) 0 (:objects component)))))))))
|
||||
|
||||
|
|
|
@ -24,3 +24,11 @@
|
|||
(update :pages conj-if-not-exists (:id page))
|
||||
(update :pages-index assoc (:id page) page))))
|
||||
|
||||
(defn pages-seq
|
||||
[file-data]
|
||||
(vals (:pages-index file-data)))
|
||||
|
||||
(defn update-page
|
||||
[file-data page-id f]
|
||||
(update-in file-data [:pages-index page-id] f))
|
||||
|
||||
|
|
|
@ -6,8 +6,13 @@
|
|||
|
||||
(ns app.common.types.shape
|
||||
(:require
|
||||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.common :refer [default-color]]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.shape.blur :as ctsb]
|
||||
|
@ -16,6 +21,7 @@
|
|||
[app.common.types.shape.layout :as ctsl]
|
||||
[app.common.types.shape.radius :as ctsr]
|
||||
[app.common.types.shape.shadow :as ctss]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
|
@ -316,3 +322,155 @@
|
|||
(s/and (s/multi-spec shape-spec :type)
|
||||
#(contains? % :type)
|
||||
#(contains? % :name)))
|
||||
|
||||
|
||||
;; --- Initialization
|
||||
|
||||
(def default-shape-attrs
|
||||
{})
|
||||
|
||||
(def default-frame-attrs
|
||||
{:frame-id uuid/zero
|
||||
:fills [{:fill-color clr/white
|
||||
:fill-opacity 1}]
|
||||
:strokes []
|
||||
:shapes []
|
||||
:hide-fill-on-export false})
|
||||
|
||||
(def ^:private minimal-shapes
|
||||
[{:type :rect
|
||||
:name "Rect-1"
|
||||
:fills [{:fill-color default-color
|
||||
:fill-opacity 1}]
|
||||
:strokes []
|
||||
:rx 0
|
||||
:ry 0}
|
||||
|
||||
{:type :image
|
||||
:rx 0
|
||||
:ry 0
|
||||
:fills []
|
||||
:strokes []}
|
||||
|
||||
{:type :circle
|
||||
:name "Circle-1"
|
||||
:fills [{:fill-color default-color
|
||||
:fill-opacity 1}]
|
||||
:strokes []}
|
||||
|
||||
{:type :path
|
||||
:name "Path-1"
|
||||
:fills []
|
||||
:strokes [{:stroke-style :solid
|
||||
:stroke-alignment :center
|
||||
:stroke-width 2
|
||||
:stroke-color clr/black
|
||||
:stroke-opacity 1}]}
|
||||
|
||||
{:type :frame
|
||||
:name "Board-1"
|
||||
:fills [{:fill-color clr/white
|
||||
:fill-opacity 1}]
|
||||
:strokes []
|
||||
:stroke-style :none
|
||||
:stroke-alignment :center
|
||||
:stroke-width 0
|
||||
:stroke-color clr/black
|
||||
:stroke-opacity 0
|
||||
:rx 0
|
||||
:ry 0}
|
||||
|
||||
{:type :text
|
||||
:name "Text-1"
|
||||
:content nil}
|
||||
|
||||
{:type :svg-raw}])
|
||||
|
||||
(def empty-selrect
|
||||
{:x 0 :y 0
|
||||
:x1 0 :y1 0
|
||||
:x2 0.01 :y2 0.01
|
||||
:width 0.01 :height 0.01})
|
||||
|
||||
(defn make-minimal-shape
|
||||
[type]
|
||||
(let [type (cond (= type :curve) :path
|
||||
:else type)
|
||||
shape (d/seek #(= type (:type %)) minimal-shapes)]
|
||||
(when-not shape
|
||||
(ex/raise :type :assertion
|
||||
:code :shape-type-not-implemented
|
||||
:context {:type type}))
|
||||
|
||||
(cond-> shape
|
||||
:always
|
||||
(assoc :id (uuid/next))
|
||||
|
||||
(not= :path (:type shape))
|
||||
(assoc :x 0
|
||||
:y 0
|
||||
:width 0.01
|
||||
:height 0.01
|
||||
:selrect {:x 0
|
||||
:y 0
|
||||
:x1 0
|
||||
:y1 0
|
||||
:x2 0.01
|
||||
:y2 0.01
|
||||
:width 0.01
|
||||
:height 0.01}))))
|
||||
|
||||
(defn make-minimal-group
|
||||
[frame-id rect group-name]
|
||||
{:id (uuid/next)
|
||||
:type :group
|
||||
:name group-name
|
||||
:shapes []
|
||||
:frame-id frame-id
|
||||
:x (:x rect)
|
||||
:y (:y rect)
|
||||
:width (:width rect)
|
||||
:height (:height rect)})
|
||||
|
||||
(defn setup-rect-selrect
|
||||
"Initializes the selrect and points for a shape."
|
||||
[shape]
|
||||
(let [selrect (gsh/rect->selrect shape)
|
||||
points (gsh/rect->points shape)]
|
||||
(-> shape
|
||||
(assoc :selrect selrect
|
||||
:points points))))
|
||||
|
||||
(defn- setup-rect
|
||||
"A specialized function for setup rect-like shapes."
|
||||
[shape {:keys [x y width height]}]
|
||||
(-> shape
|
||||
(assoc :x x :y y :width width :height height)
|
||||
(setup-rect-selrect)))
|
||||
|
||||
(defn- setup-image
|
||||
[{:keys [metadata] :as shape} props]
|
||||
(-> (setup-rect shape props)
|
||||
(assoc
|
||||
:proportion (/ (:width metadata)
|
||||
(:height metadata))
|
||||
:proportion-lock true)))
|
||||
|
||||
(defn setup-shape
|
||||
"A function that initializes the geometric data of
|
||||
the shape. The props must have :x :y :width :height."
|
||||
([props]
|
||||
(setup-shape {:type :rect} props))
|
||||
|
||||
([shape props]
|
||||
(case (:type shape)
|
||||
:image (setup-image shape props)
|
||||
(setup-rect shape props))))
|
||||
|
||||
(defn make-shape
|
||||
"Make a non group shape, ready to use."
|
||||
[type geom-props attrs]
|
||||
(-> (make-minimal-shape type)
|
||||
(setup-shape geom-props)
|
||||
(merge attrs)))
|
||||
|
||||
|
|
|
@ -65,6 +65,11 @@
|
|||
|
||||
(update container :objects update-objects parent-id)))
|
||||
|
||||
(defn set-shape
|
||||
"Replace a shape in the tree with a new one"
|
||||
[container shape]
|
||||
(assoc-in container [:objects (:id shape)] shape))
|
||||
|
||||
(defn get-frames
|
||||
"Retrieves all frame objects as vector"
|
||||
[objects]
|
||||
|
@ -149,7 +154,6 @@
|
|||
|
||||
[base index-base-a index-base-b]))
|
||||
|
||||
|
||||
(defn is-shape-over-shape?
|
||||
[objects base-shape-id over-shape-id {:keys [top-frames?]}]
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth :refer [close?]]
|
||||
[app.common.pages :refer [make-minimal-shape]]
|
||||
[app.common.types.shape :as cts]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(def default-path
|
||||
|
@ -41,7 +41,7 @@
|
|||
(defn create-test-shape
|
||||
([type] (create-test-shape type {}))
|
||||
([type params]
|
||||
(-> (make-minimal-shape type)
|
||||
(-> (cts/make-minimal-shape type)
|
||||
(merge params)
|
||||
(cond->
|
||||
(= type :path) (add-path-data)
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
[clojure.test :as t]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(t/deftest process-change-set-option
|
||||
(let [file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
data (cp/make-file-data file-id page-id)]
|
||||
data (ctf/make-file-data file-id page-id)]
|
||||
(t/testing "Sets option single"
|
||||
(let [chg {:type :set-option
|
||||
:page-id page-id
|
||||
|
@ -80,7 +81,7 @@
|
|||
(t/deftest process-change-add-obj
|
||||
(let [file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
data (cp/make-file-data file-id page-id)
|
||||
data (ctf/make-file-data file-id page-id)
|
||||
id-a (uuid/custom 2 1)
|
||||
id-b (uuid/custom 2 2)
|
||||
id-c (uuid/custom 2 3)]
|
||||
|
@ -134,7 +135,7 @@
|
|||
(t/deftest process-change-mod-obj
|
||||
(let [file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
data (cp/make-file-data file-id page-id)]
|
||||
data (ctf/make-file-data file-id page-id)]
|
||||
(t/testing "simple mod-obj"
|
||||
(let [chg {:type :mod-obj
|
||||
:page-id page-id
|
||||
|
@ -161,7 +162,7 @@
|
|||
(let [file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
id (uuid/custom 2 1)
|
||||
data (cp/make-file-data file-id page-id)
|
||||
data (ctf/make-file-data file-id page-id)
|
||||
data (-> data
|
||||
(assoc-in [:pages-index page-id :objects uuid/zero :shapes] [id])
|
||||
(assoc-in [:pages-index page-id :objects id]
|
||||
|
@ -205,7 +206,7 @@
|
|||
|
||||
file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
data (cp/make-file-data file-id page-id)
|
||||
data (ctf/make-file-data file-id page-id)
|
||||
|
||||
data (update-in data [:pages-index page-id :objects]
|
||||
#(-> %
|
||||
|
@ -449,7 +450,7 @@
|
|||
:obj {:type :rect
|
||||
:name "Shape 3"}}
|
||||
]
|
||||
data (cp/make-file-data file-id page-id)
|
||||
data (ctf/make-file-data file-id page-id)
|
||||
data (cp/process-changes data changes)]
|
||||
|
||||
(t/testing "preserve order on multiple shape mov 1"
|
||||
|
@ -556,7 +557,7 @@
|
|||
:parent-id group-1-id
|
||||
:shapes [shape-1-id shape-2-id]}]
|
||||
|
||||
data (cp/make-file-data file-id page-id)
|
||||
data (ctf/make-file-data file-id page-id)
|
||||
data (cp/process-changes data changes)]
|
||||
|
||||
(t/testing "case 1"
|
||||
|
|
110
common/test/app/common/test_helpers/files.cljc
Normal file
110
common/test/app/common/test_helpers/files.cljc
Normal file
|
@ -0,0 +1,110 @@
|
|||
;; 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.test-helpers.files
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(def ^:private idmap (atom {}))
|
||||
|
||||
(defn reset-idmap! []
|
||||
(reset! idmap {}))
|
||||
|
||||
(defn id
|
||||
[label]
|
||||
(get @idmap label))
|
||||
|
||||
(defn sample-file
|
||||
([file-id page-id] (sample-file file-id page-id nil))
|
||||
([file-id page-id props]
|
||||
(merge {:id file-id
|
||||
:name (get props :name "File1")
|
||||
:data (ctf/make-file-data file-id page-id)}
|
||||
props)))
|
||||
|
||||
(defn sample-shape
|
||||
[file label type page-id props]
|
||||
(ctf/update-file-data
|
||||
file
|
||||
(fn [file-data]
|
||||
(let [frame-id (get props :frame-id uuid/zero)
|
||||
parent-id (get props :parent-id uuid/zero)
|
||||
shape (if (= type :group)
|
||||
(cts/make-minimal-group frame-id
|
||||
{:x 0 :y 0 :width 1 :height 1}
|
||||
(get props :name "Group1"))
|
||||
(cts/make-shape type
|
||||
{:x 0 :y 0 :width 1 :height 1}
|
||||
props))]
|
||||
|
||||
(swap! idmap assoc label (:id shape))
|
||||
(ctpl/update-page file-data
|
||||
page-id
|
||||
#(ctst/add-shape (:id shape)
|
||||
shape
|
||||
%
|
||||
frame-id
|
||||
parent-id
|
||||
0
|
||||
true))))))
|
||||
|
||||
(defn sample-component
|
||||
[file label page-id shape-id]
|
||||
(ctf/update-file-data
|
||||
file
|
||||
(fn [file-data]
|
||||
(let [page (ctpl/get-page file-data page-id)
|
||||
|
||||
[component-shape component-shapes updated-shapes]
|
||||
(ctn/make-component-shape (ctn/get-shape page shape-id)
|
||||
(:objects page)
|
||||
(:id file))]
|
||||
|
||||
(swap! idmap assoc label (:id component-shape))
|
||||
(-> file-data
|
||||
(ctpl/update-page page-id
|
||||
#(reduce (fn [page shape] (ctst/set-shape page shape))
|
||||
%
|
||||
updated-shapes))
|
||||
(ctkl/add-component (:id component-shape)
|
||||
(:name component-shape)
|
||||
""
|
||||
shape-id
|
||||
page-id
|
||||
component-shapes))))))
|
||||
|
||||
(defn sample-instance
|
||||
[file label page-id library component-id]
|
||||
(ctf/update-file-data
|
||||
file
|
||||
(fn [file-data]
|
||||
(let [[instance-shape instance-shapes]
|
||||
(ctn/instantiate-component (ctpl/get-page file-data page-id)
|
||||
(ctkl/get-component (:data library) component-id)
|
||||
(:id library)
|
||||
(gpt/point 0 0))]
|
||||
|
||||
(swap! idmap assoc label (:id instance-shape))
|
||||
(-> file-data
|
||||
(ctpl/update-page page-id
|
||||
#(reduce (fn [page shape]
|
||||
(ctst/add-shape (:id shape)
|
||||
shape
|
||||
page
|
||||
uuid/zero
|
||||
(:parent-id shape)
|
||||
0
|
||||
true))
|
||||
%
|
||||
instance-shapes)))))))
|
||||
|
79
common/test/app/common/types/file_test.cljc
Normal file
79
common/test/app/common/types/file_test.cljc
Normal file
|
@ -0,0 +1,79 @@
|
|||
;; 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.types.file-test
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
|
||||
[app.common.data :as d]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[cuerdas.core :as str]
|
||||
))
|
||||
|
||||
(t/use-fixtures :each
|
||||
{:before thf/reset-idmap!})
|
||||
|
||||
(t/deftest test-absorb-assets
|
||||
(let [library-id (uuid/custom 1 1)
|
||||
library-page-id (uuid/custom 2 2)
|
||||
file-id (uuid/custom 3 3)
|
||||
file-page-id (uuid/custom 4 4)
|
||||
|
||||
library (-> (thf/sample-file library-id library-page-id {:is-shared true})
|
||||
(thf/sample-shape :group1
|
||||
:group
|
||||
library-page-id
|
||||
{:name "Group1"})
|
||||
(thf/sample-shape :shape1
|
||||
:rect
|
||||
library-page-id
|
||||
{:name "Rect1"
|
||||
:parent-id (thf/id :group1)})
|
||||
(thf/sample-component :component1
|
||||
library-page-id
|
||||
(thf/id :group1)))
|
||||
|
||||
file (-> (thf/sample-file file-id file-page-id)
|
||||
(thf/sample-instance :instance1
|
||||
file-page-id
|
||||
library
|
||||
(thf/id :component1)))
|
||||
|
||||
absorbed-file (ctf/update-file-data
|
||||
file
|
||||
#(ctf/absorb-assets % (:data library)))]
|
||||
|
||||
(println "\n===== library")
|
||||
(ctf/dump-tree (:data library)
|
||||
library-page-id
|
||||
{}
|
||||
true)
|
||||
|
||||
(println "\n===== file")
|
||||
(ctf/dump-tree (:data file)
|
||||
file-page-id
|
||||
{library-id {:id library-id
|
||||
:name "Library 1"
|
||||
:data library}}
|
||||
true)
|
||||
|
||||
(println "\n===== absorbed file")
|
||||
(ctf/dump-tree (:data absorbed-file)
|
||||
file-page-id
|
||||
{}
|
||||
true)
|
||||
|
||||
(t/is (= library-id (:id library)))
|
||||
(t/is (= file-id (:id absorbed-file)))))
|
||||
|
|
@ -4,20 +4,20 @@
|
|||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.common.spec-interactions-test
|
||||
(ns app.common.types.shape.spec-interactions-test
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.pages.init :as cpi]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.geom.point :as gpt]))
|
||||
|
||||
(t/deftest set-event-type
|
||||
(let [interaction ctsi/default-interaction
|
||||
shape (cpi/make-minimal-shape :rect)
|
||||
frame (cpi/make-minimal-shape :frame)]
|
||||
shape (cts/make-minimal-shape :rect)
|
||||
frame (cts/make-minimal-shape :frame)]
|
||||
|
||||
(t/testing "Set event type unchanged"
|
||||
(let [new-interaction
|
||||
|
@ -148,7 +148,7 @@
|
|||
|
||||
|
||||
(t/deftest option-delay
|
||||
(let [frame (cpi/make-minimal-shape :frame)
|
||||
(let [frame (cts/make-minimal-shape :frame)
|
||||
i1 ctsi/default-interaction
|
||||
i2 (ctsi/set-event-type i1 :after-delay frame)]
|
||||
|
||||
|
@ -211,10 +211,10 @@
|
|||
|
||||
|
||||
(t/deftest option-overlay-opts
|
||||
(let [base-frame (-> (cpi/make-minimal-shape :frame)
|
||||
(let [base-frame (-> (cts/make-minimal-shape :frame)
|
||||
(assoc-in [:selrect :width] 100)
|
||||
(assoc-in [:selrect :height] 100))
|
||||
overlay-frame (-> (cpi/make-minimal-shape :frame)
|
||||
overlay-frame (-> (cts/make-minimal-shape :frame)
|
||||
(assoc-in [:selrect :width] 30)
|
||||
(assoc-in [:selrect :height] 20))
|
||||
objects {(:id base-frame) base-frame
|
||||
|
@ -542,12 +542,12 @@
|
|||
|
||||
|
||||
(t/deftest remap-interactions
|
||||
(let [frame1 (cpi/make-minimal-shape :frame)
|
||||
frame2 (cpi/make-minimal-shape :frame)
|
||||
frame3 (cpi/make-minimal-shape :frame)
|
||||
frame4 (cpi/make-minimal-shape :frame)
|
||||
frame5 (cpi/make-minimal-shape :frame)
|
||||
frame6 (cpi/make-minimal-shape :frame)
|
||||
(let [frame1 (cts/make-minimal-shape :frame)
|
||||
frame2 (cts/make-minimal-shape :frame)
|
||||
frame3 (cts/make-minimal-shape :frame)
|
||||
frame4 (cts/make-minimal-shape :frame)
|
||||
frame5 (cts/make-minimal-shape :frame)
|
||||
frame6 (cts/make-minimal-shape :frame)
|
||||
|
||||
objects {(:id frame3) frame3
|
||||
(:id frame4) frame4
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
[app.common.geom.proportions :as gpr]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
|
@ -1591,7 +1590,7 @@
|
|||
page-id (:current-page-id state)
|
||||
frame-id (-> (wsh/lookup-page-objects state page-id)
|
||||
(ctst/frame-id-by-position @ms/mouse-position))
|
||||
shape (cp/setup-rect-selrect
|
||||
shape (cts/setup-rect-selrect
|
||||
{:id id
|
||||
:type :text
|
||||
:name "Text"
|
||||
|
@ -1681,12 +1680,12 @@
|
|||
(let [srect (gsh/selection-rect selected-objs)
|
||||
frame-id (get-in objects [(first selected) :frame-id])
|
||||
parent-id (get-in objects [(first selected) :parent-id])
|
||||
shape (-> (cp/make-minimal-shape :frame)
|
||||
shape (-> (cts/make-minimal-shape :frame)
|
||||
(merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)})
|
||||
(assoc :frame-id frame-id :parent-id parent-id)
|
||||
(cond-> (not= frame-id uuid/zero)
|
||||
(assoc :fills [] :hide-in-viewer true))
|
||||
(cp/setup-rect-selrect))]
|
||||
(cts/setup-rect-selrect))]
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction)
|
||||
(dwsh/add-shape shape)
|
||||
|
|
|
@ -7,15 +7,6 @@
|
|||
(ns app.main.data.workspace.common
|
||||
(:require
|
||||
[app.common.logging :as log]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.worker :as uw]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
(ns app.main.data.workspace.drawing
|
||||
"Drawing interactions."
|
||||
(:require
|
||||
[app.common.pages :as cp]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.drawing.box :as box]
|
||||
|
@ -91,7 +91,7 @@
|
|||
(ptk/reify ::handle-drawing
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [data (cp/make-minimal-shape type)]
|
||||
(let [data (cts/make-minimal-shape type)]
|
||||
(update-in state [:workspace-drawing :object] merge data)))
|
||||
|
||||
ptk/WatchEvent
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.drawing.common :as common]
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
shape (get-in state [:workspace-drawing :object])
|
||||
shape (-> shape
|
||||
(cp/setup-shape {:x (:x initial)
|
||||
(cts/setup-shape {:x (:x initial)
|
||||
:y (:y initial)
|
||||
:width 0.01
|
||||
:height 0.01})
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
|
@ -55,7 +56,7 @@
|
|||
(assoc :height 17 :width 4 :grow-type :auto-width)
|
||||
|
||||
click-draw?
|
||||
(cp/setup-rect-selrect)
|
||||
(cts/setup-rect-selrect)
|
||||
|
||||
:always
|
||||
(-> (gsh/transform-shape)
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
|
@ -75,8 +75,8 @@
|
|||
(ctt/generate-unique-name base-name)))
|
||||
|
||||
selrect (gsh/selection-rect shapes)
|
||||
group (-> (cp/make-minimal-group frame-id selrect gname)
|
||||
(cp/setup-shape selrect)
|
||||
group (-> (cts/make-minimal-group frame-id selrect gname)
|
||||
(cts/setup-shape selrect)
|
||||
(assoc :shapes (mapv :id shapes)
|
||||
:parent-id parent-id
|
||||
:frame-id frame-id
|
||||
|
|
|
@ -56,46 +56,6 @@
|
|||
|
||||
;; ---- Components and instances creation ----
|
||||
|
||||
(defn make-component-shape
|
||||
"Clone the shape and all children. Generate new ids and detach
|
||||
from parent and frame. Update the original shapes to have links
|
||||
to the new ones."
|
||||
[shape objects file-id]
|
||||
(assert (nil? (:component-id shape)))
|
||||
(assert (nil? (:component-file shape)))
|
||||
(assert (nil? (:shape-ref shape)))
|
||||
(let [;; Ensure that the component root is not an instance and
|
||||
;; it's no longer tied to a frame.
|
||||
update-new-shape (fn [new-shape _original-shape]
|
||||
(cond-> new-shape
|
||||
true
|
||||
(-> (assoc :frame-id nil)
|
||||
(dissoc :component-root?))
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(dissoc :component-id
|
||||
:component-file
|
||||
:shape-ref)))
|
||||
|
||||
;; Make the original shape an instance of the new component.
|
||||
;; If one of the original shape children already was a component
|
||||
;; instance, maintain this instanceness untouched.
|
||||
update-original-shape (fn [original-shape new-shape]
|
||||
(cond-> original-shape
|
||||
(nil? (:shape-ref original-shape))
|
||||
(-> (assoc :shape-ref (:id new-shape))
|
||||
(dissoc :touched))
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(assoc :component-id (:id new-shape)
|
||||
:component-file file-id
|
||||
:component-root? true)
|
||||
|
||||
(some? (:parent-id new-shape))
|
||||
(dissoc :component-root?)))]
|
||||
|
||||
(ctst/clone-object shape nil objects update-new-shape update-original-shape)))
|
||||
|
||||
(defn generate-add-component
|
||||
"If there is exactly one id, and it's a group, use it as root. Otherwise,
|
||||
create a group that contains all ids. Then, make a component with it,
|
||||
|
@ -115,7 +75,7 @@
|
|||
(dwg/prepare-create-group it objects page-id shapes name true))
|
||||
|
||||
[new-shape new-shapes updated-shapes]
|
||||
(make-component-shape group objects file-id)
|
||||
(ctn/make-component-shape group objects file-id)
|
||||
|
||||
changes (-> changes
|
||||
(pcb/add-component (:id new-shape)
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.spec :refer [max-safe-int min-safe-int]]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
|
@ -182,7 +182,7 @@
|
|||
(assoc :svg-attrs attrs)
|
||||
(assoc :svg-viewbox (-> (select-keys svg-data [:width :height])
|
||||
(assoc :x offset-x :y offset-y)))
|
||||
(cp/setup-rect-selrect))))
|
||||
(cts/setup-rect-selrect))))
|
||||
|
||||
(defn create-svg-root [frame-id svg-data]
|
||||
(let [{:keys [name x y width height offset-x offset-y]} svg-data]
|
||||
|
@ -194,7 +194,7 @@
|
|||
:height height
|
||||
:x (+ x offset-x)
|
||||
:y (+ y offset-y)}
|
||||
(cp/setup-rect-selrect)
|
||||
(cts/setup-rect-selrect)
|
||||
(assoc :svg-attrs (-> (:attrs svg-data)
|
||||
(dissoc :viewBox :xmlns)
|
||||
(d/without-keys usvg/inheritable-props))))))
|
||||
|
@ -214,7 +214,7 @@
|
|||
(assoc :svg-attrs (d/without-keys attrs usvg/inheritable-props))
|
||||
(assoc :svg-viewbox (-> (select-keys svg-data [:width :height])
|
||||
(assoc :x offset-x :y offset-y)))
|
||||
(cp/setup-rect-selrect))))
|
||||
(cts/setup-rect-selrect))))
|
||||
|
||||
(defn create-path-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
||||
(when (and (contains? attrs :d) (seq (:d attrs)))
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -343,7 +343,7 @@
|
|||
#(->> shapes
|
||||
(map gsh/transform-shape)
|
||||
(gsh/selection-rect)
|
||||
(cp/setup-shape)))
|
||||
(cts/setup-shape)))
|
||||
on-resize
|
||||
(fn [current-position _initial-position event]
|
||||
(when (dom/left-mouse? event)
|
||||
|
@ -371,7 +371,7 @@
|
|||
#(->> shapes
|
||||
(map gsh/transform-shape)
|
||||
(gsh/selection-rect)
|
||||
(cp/setup-shape)))]
|
||||
(cts/setup-shape)))]
|
||||
|
||||
[:& controls-selection
|
||||
{:shape shape
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
[app.common.geom.shapes.path :as gpa]
|
||||
[app.common.logging :as log]
|
||||
[app.common.media :as cm]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.text :as ct]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.http :as http]
|
||||
|
@ -133,7 +133,7 @@
|
|||
:name (:name context)
|
||||
:is-shared (:shared context)
|
||||
:project-id (:project-id context)
|
||||
:data (-> cp/empty-file-data (assoc :id file-id))})))
|
||||
:data (-> ctf/empty-file-data (assoc :id file-id))})))
|
||||
|
||||
(defn link-file-libraries
|
||||
"Create a new file on the back-end"
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.logging :as l]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.dashboard.shortcuts]
|
||||
[app.main.data.viewer.shortcuts]
|
||||
|
@ -211,77 +211,9 @@
|
|||
([state show-ids] (dump-tree' state show-ids false))
|
||||
([state show-ids show-touched]
|
||||
(let [page-id (get state :current-page-id)
|
||||
objects (get-in state [:workspace-data :pages-index page-id :objects])
|
||||
components (get-in state [:workspace-data :components])
|
||||
libraries (get state :workspace-libraries)
|
||||
root (d/seek #(nil? (:parent-id %)) (vals objects))]
|
||||
|
||||
(letfn [(show-shape [shape-id level objects]
|
||||
(let [shape (get objects shape-id)]
|
||||
(println (str/pad (str (str/repeat " " level)
|
||||
(:name shape)
|
||||
(when (seq (:touched shape)) "*")
|
||||
(when show-ids (str/format " <%s>" (:id shape))))
|
||||
{:length 20
|
||||
:type :right})
|
||||
(show-component shape objects))
|
||||
(when show-touched
|
||||
(when (seq (:touched shape))
|
||||
(println (str (str/repeat " " level)
|
||||
" "
|
||||
(str (:touched shape)))))
|
||||
(when (:remote-synced? shape)
|
||||
(println (str (str/repeat " " level)
|
||||
" (remote-synced)"))))
|
||||
(when (:shapes shape)
|
||||
(dorun (for [shape-id (:shapes shape)]
|
||||
(show-shape shape-id (inc level) objects))))))
|
||||
|
||||
(show-component [shape objects]
|
||||
(if (nil? (:shape-ref shape))
|
||||
""
|
||||
(let [root-shape (cph/get-component-shape objects shape)
|
||||
component-id (when root-shape (:component-id root-shape))
|
||||
component-file-id (when root-shape (:component-file root-shape))
|
||||
component-file (when component-file-id (get libraries component-file-id nil))
|
||||
component (when component-id
|
||||
(if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id)))
|
||||
component-shape (when (and component (:shape-ref shape))
|
||||
(get-in component [:objects (:shape-ref shape)]))]
|
||||
(str/format " %s--> %s%s%s"
|
||||
(cond (:component-root? shape) "#"
|
||||
(:component-id shape) "@"
|
||||
:else "-")
|
||||
(when component-file (str/format "<%s> " (:name component-file)))
|
||||
(or (:name component-shape) "?")
|
||||
(if (or (:component-root? shape)
|
||||
(nil? (:component-id shape))
|
||||
true)
|
||||
""
|
||||
(let [component-id (:component-id shape)
|
||||
component-file-id (:component-file shape)
|
||||
component-file (when component-file-id (get libraries component-file-id nil))
|
||||
component (if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id))]
|
||||
(str/format " (%s%s)"
|
||||
(when component-file (str/format "<%s> " (:name component-file)))
|
||||
(:name component))))))))]
|
||||
|
||||
(println "[Page]")
|
||||
(show-shape (:id root) 0 objects)
|
||||
|
||||
(dorun (for [component (vals components)]
|
||||
(do
|
||||
(println)
|
||||
(println (str/format "[%s]" (:name component))
|
||||
(when show-ids
|
||||
(str/format " (main: %s/%s)"
|
||||
(:main-instance-page component)
|
||||
(:main-instance-id component))))
|
||||
(show-shape (:id component) 0 (:objects component)))))))))
|
||||
file-data (get state :workspace-data)
|
||||
libraries (get state :workspace-libraries)]
|
||||
(ctf/dump-tree file-data page-id libraries show-ids show-touched))))
|
||||
|
||||
(defn ^:export dump-tree
|
||||
([] (dump-tree' @st/state))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.container :as ctc]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.groups :as dwg]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
|
@ -521,7 +521,7 @@
|
|||
;
|
||||
(let [page (thp/current-page new-state)
|
||||
shape1 (thp/get-shape new-state :shape1)
|
||||
parent1 (ctc/get-shape page (:parent-id shape1))
|
||||
parent1 (ctn/get-shape page (:parent-id shape1))
|
||||
|
||||
[[group shape1 shape2]
|
||||
[c-group c-shape1 c-shape2]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.container :as ctc]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
|
@ -1353,7 +1353,7 @@
|
|||
instance1 (thp/get-shape state :instance1)
|
||||
instance2 (thp/get-shape state :instance2)
|
||||
|
||||
shape2 (ctc/get-shape (wsh/lookup-page state)
|
||||
shape2 (ctn/get-shape (wsh/lookup-page state)
|
||||
(first (:shapes instance2)))
|
||||
|
||||
update-fn1 (fn [shape]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.container :as ctc]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.libraries-helpers :as dwlh]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
|
@ -60,7 +60,7 @@
|
|||
verify that they are a well constructed instance tree."
|
||||
[state root-inst-id]
|
||||
(let [page (thp/current-page state)
|
||||
root-inst (ctc/get-shape page root-inst-id)
|
||||
root-inst (ctn/get-shape page root-inst-id)
|
||||
shapes-inst (cph/get-children-with-self (:objects page)
|
||||
root-inst-id)]
|
||||
(is-instance-root (first shapes-inst))
|
||||
|
@ -73,7 +73,7 @@
|
|||
verify that they are not a component instance."
|
||||
[state root-inst-id]
|
||||
(let [page (thp/current-page state)
|
||||
root-inst (ctc/get-shape page root-inst-id)
|
||||
root-inst (ctn/get-shape page root-inst-id)
|
||||
shapes-inst (cph/get-children-with-self (:objects page)
|
||||
root-inst-id)]
|
||||
(run! is-noninstance shapes-inst)
|
||||
|
@ -85,7 +85,7 @@
|
|||
the main component and all its shapes."
|
||||
[state root-inst-id]
|
||||
(let [page (thp/current-page state)
|
||||
root-inst (ctc/get-shape page root-inst-id)
|
||||
root-inst (ctn/get-shape page root-inst-id)
|
||||
|
||||
libs (wsh/get-libraries state)
|
||||
component (cph/get-component libs (:component-id root-inst))
|
||||
|
@ -103,7 +103,7 @@
|
|||
(cph/get-component libs (:component-id component-shape))
|
||||
|
||||
main-shape
|
||||
(ctc/get-shape component (:shape-ref shape))]
|
||||
(ctn/get-shape component (:shape-ref shape))]
|
||||
|
||||
(t/is (some? main-shape))))]
|
||||
|
||||
|
@ -123,7 +123,7 @@
|
|||
corresponding component shape missing."
|
||||
[state root-inst-id]
|
||||
(let [page (thp/current-page state)
|
||||
root-inst (ctc/get-shape page root-inst-id)
|
||||
root-inst (ctn/get-shape page root-inst-id)
|
||||
|
||||
libs (wsh/get-libraries state)
|
||||
component (cph/get-component libs (:component-id root-inst))
|
||||
|
@ -141,7 +141,7 @@
|
|||
(cph/get-component libs (:component-id component-shape))
|
||||
|
||||
main-shape
|
||||
(ctc/get-shape component (:shape-ref shape))]
|
||||
(ctn/get-shape component (:shape-ref shape))]
|
||||
|
||||
(t/is (some? main-shape))))]
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.groups :as dwg]
|
||||
[app.main.data.workspace.layout :as layout]
|
||||
|
@ -69,9 +70,7 @@
|
|||
([state label type props]
|
||||
(let [page (current-page state)
|
||||
frame (cph/get-frame (:objects page))
|
||||
shape (-> (cp/make-minimal-shape type)
|
||||
(cp/setup-shape {:x 0 :y 0 :width 1 :height 1})
|
||||
(merge props))]
|
||||
shape (cts/make-shape type {:x 0 :y 0 :width 1 :height 1} props)]
|
||||
(swap! idmap assoc label (:id shape))
|
||||
(update state :workspace-data
|
||||
cp/process-changes
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
[app.common.uuid :as uuid]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[cljs.pprint :refer [pprint]]
|
||||
[app.common.pages.init :as init]
|
||||
[app.common.file-builder :as fb]
|
||||
[app.util.snap-data :as sd]))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue