mirror of
https://github.com/penpot/penpot.git
synced 2025-06-12 19:31:39 +02:00
🐛 Fix critical inconsistencies on group handling.
This commit is contained in:
parent
93a967ed8f
commit
b68a076e57
16 changed files with 323 additions and 236 deletions
|
@ -77,16 +77,23 @@
|
||||||
(t/testing "Adds single object"
|
(t/testing "Adds single object"
|
||||||
(let [chg {:type :add-obj
|
(let [chg {:type :add-obj
|
||||||
:id id-a
|
:id id-a
|
||||||
|
:parent-id uuid/zero
|
||||||
:frame-id uuid/zero
|
:frame-id uuid/zero
|
||||||
:obj {:id id-a
|
:obj {:id id-a
|
||||||
:frame-id uuid/zero
|
:frame-id uuid/zero
|
||||||
|
:parent-id uuid/zero
|
||||||
:type :rect
|
:type :rect
|
||||||
:name "rect"}}
|
:name "rect"}}
|
||||||
res (cp/process-changes data [chg])]
|
res (cp/process-changes data [chg])]
|
||||||
|
|
||||||
|
;; (clojure.pprint/pprint data)
|
||||||
|
;; (clojure.pprint/pprint res)
|
||||||
|
|
||||||
(t/is (= 2 (count (:objects res))))
|
(t/is (= 2 (count (:objects res))))
|
||||||
(t/is (= (:obj chg) (get-in res [:objects id-a])))
|
(t/is (= (:obj chg) (get-in res [:objects id-a])))
|
||||||
(t/is (= [id-a] (get-in res [:objects uuid/zero :shapes])))))
|
(t/is (= [id-a] (get-in res [:objects uuid/zero :shapes])))))
|
||||||
|
|
||||||
|
|
||||||
(t/testing "Adds several objects with different indexes"
|
(t/testing "Adds several objects with different indexes"
|
||||||
(let [data cp/default-page-data
|
(let [data cp/default-page-data
|
||||||
|
|
||||||
|
@ -277,36 +284,77 @@
|
||||||
rect-c-id (uuid/custom 7)
|
rect-c-id (uuid/custom 7)
|
||||||
rect-d-id (uuid/custom 8)
|
rect-d-id (uuid/custom 8)
|
||||||
rect-e-id (uuid/custom 9)
|
rect-e-id (uuid/custom 9)
|
||||||
data (-> cp/default-page-data
|
|
||||||
(assoc-in [cp/root :shapes] [frame-a-id])
|
|
||||||
(assoc-in [:objects frame-a-id]
|
|
||||||
{:id frame-a-id :name "Frame a" :type :frame})
|
|
||||||
(assoc-in [:objects frame-b-id]
|
|
||||||
{:id frame-b-id :name "Frame b" :type :frame})
|
|
||||||
|
|
||||||
;; Groups
|
data
|
||||||
(assoc-in [:objects group-a-id]
|
(-> cp/default-page-data
|
||||||
{:id group-a-id :name "Group A" :type :group :frame-id frame-a-id})
|
(assoc-in [:objects uuid/zero :shapes] [frame-a-id frame-b-id])
|
||||||
(assoc-in [:objects group-b-id]
|
(assoc-in [:objects frame-a-id]
|
||||||
{:id group-b-id :name "Group B" :type :group :frame-id frame-a-id})
|
{:id frame-a-id
|
||||||
|
:parent-id uuid/zero
|
||||||
|
:frame-id uuid/zero
|
||||||
|
:name "Frame a"
|
||||||
|
:shapes [group-a-id group-b-id rect-e-id]
|
||||||
|
:type :frame})
|
||||||
|
|
||||||
|
(assoc-in [:objects frame-b-id]
|
||||||
|
{:id frame-b-id
|
||||||
|
:parent-id uuid/zero
|
||||||
|
:frame-id uuid/zero
|
||||||
|
:name "Frame b"
|
||||||
|
:shapes []
|
||||||
|
:type :frame})
|
||||||
|
|
||||||
|
;; Groups
|
||||||
|
(assoc-in [:objects group-a-id]
|
||||||
|
{:id group-a-id
|
||||||
|
:name "Group A"
|
||||||
|
:type :group
|
||||||
|
:parent-id frame-a-id
|
||||||
|
:frame-id frame-a-id
|
||||||
|
:shapes [rect-a-id rect-b-id rect-c-id]})
|
||||||
|
(assoc-in [:objects group-b-id]
|
||||||
|
{:id group-b-id
|
||||||
|
:name "Group B"
|
||||||
|
:type :group
|
||||||
|
:parent-id frame-a-id
|
||||||
|
:frame-id frame-a-id
|
||||||
|
:shapes [rect-d-id]})
|
||||||
|
|
||||||
;; Shapes
|
;; Shapes
|
||||||
(assoc-in [:objects rect-a-id]
|
(assoc-in [:objects rect-a-id]
|
||||||
{:id rect-a-id :name "Rect A" :type :rect :frame-id frame-a-id})
|
{:id rect-a-id
|
||||||
(assoc-in [:objects rect-b-id]
|
:name "Rect A"
|
||||||
{:id rect-b-id :name "Rect B" :type :rect :frame-id frame-a-id})
|
:type :rect
|
||||||
(assoc-in [:objects rect-c-id]
|
:parent-id group-a-id
|
||||||
{:id rect-c-id :name "Rect C" :type :rect :frame-id frame-a-id})
|
:frame-id frame-a-id})
|
||||||
(assoc-in [:objects rect-d-id]
|
|
||||||
{:id rect-d-id :name "Rect D" :type :rect :frame-id frame-a-id})
|
|
||||||
(assoc-in [:objects rect-e-id]
|
|
||||||
{:id rect-e-id :name "Rect E" :type :rect :frame-id frame-a-id})
|
|
||||||
|
|
||||||
;; Relationships
|
(assoc-in [:objects rect-b-id]
|
||||||
(assoc-in [:objects cp/root :shapes] [frame-a-id frame-b-id])
|
{:id rect-b-id
|
||||||
(assoc-in [:objects frame-a-id :shapes] [group-a-id group-b-id rect-e-id])
|
:name "Rect B"
|
||||||
(assoc-in [:objects group-a-id :shapes] [rect-a-id rect-b-id rect-c-id])
|
:type :rect
|
||||||
(assoc-in [:objects group-b-id :shapes] [rect-d-id]))]
|
:parent-id group-a-id
|
||||||
|
:frame-id frame-a-id})
|
||||||
|
|
||||||
|
(assoc-in [:objects rect-c-id]
|
||||||
|
{:id rect-c-id
|
||||||
|
:name "Rect C"
|
||||||
|
:type :rect
|
||||||
|
:parent-id group-a-id
|
||||||
|
:frame-id frame-a-id})
|
||||||
|
|
||||||
|
(assoc-in [:objects rect-d-id]
|
||||||
|
{:id rect-d-id
|
||||||
|
:name "Rect D"
|
||||||
|
:parent-id group-b-id
|
||||||
|
:type :rect
|
||||||
|
:frame-id frame-a-id})
|
||||||
|
|
||||||
|
(assoc-in [:objects rect-e-id]
|
||||||
|
{:id rect-e-id
|
||||||
|
:name "Rect E"
|
||||||
|
:type :rect
|
||||||
|
:parent-id frame-a-id
|
||||||
|
:frame-id frame-a-id}))]
|
||||||
|
|
||||||
(t/testing "Create new group an add objects from the same group"
|
(t/testing "Create new group an add objects from the same group"
|
||||||
(let [new-group-id (uuid/next)
|
(let [new-group-id (uuid/next)
|
||||||
|
@ -322,6 +370,10 @@
|
||||||
:shapes [rect-b-id rect-c-id]}]
|
:shapes [rect-b-id rect-c-id]}]
|
||||||
res (cp/process-changes data changes)]
|
res (cp/process-changes data changes)]
|
||||||
|
|
||||||
|
;; (clojure.pprint/pprint data)
|
||||||
|
;; (println "===============")
|
||||||
|
;; (clojure.pprint/pprint res)
|
||||||
|
|
||||||
(t/is (= [group-a-id group-b-id rect-e-id new-group-id]
|
(t/is (= [group-a-id group-b-id rect-e-id new-group-id]
|
||||||
(get-in res [:objects frame-a-id :shapes])))
|
(get-in res [:objects frame-a-id :shapes])))
|
||||||
(t/is (= [rect-b-id rect-c-id]
|
(t/is (= [rect-b-id rect-c-id]
|
||||||
|
@ -396,10 +448,15 @@
|
||||||
|
|
||||||
(t/testing "Move elements to frame zero"
|
(t/testing "Move elements to frame zero"
|
||||||
(let [changes [{:type :mov-objects
|
(let [changes [{:type :mov-objects
|
||||||
:parent-id cp/root
|
:parent-id uuid/zero
|
||||||
:shapes [group-a-id]
|
:shapes [group-a-id]
|
||||||
:index 0}]
|
:index 0}]
|
||||||
res (cp/process-changes data changes)]
|
res (cp/process-changes data changes)]
|
||||||
|
|
||||||
|
;; (pprint (get-in data [:objects uuid/zero]))
|
||||||
|
;; (println "==========")
|
||||||
|
;; (pprint (get-in res [:objects uuid/zero]))
|
||||||
|
|
||||||
(t/is (= [group-a-id frame-a-id frame-b-id]
|
(t/is (= [group-a-id frame-a-id frame-b-id]
|
||||||
(get-in res [:objects cp/root :shapes])))))
|
(get-in res [:objects cp/root :shapes])))))
|
||||||
|
|
||||||
|
@ -408,7 +465,8 @@
|
||||||
:parent-id group-a-id
|
:parent-id group-a-id
|
||||||
:shapes [group-a-id]}]
|
:shapes [group-a-id]}]
|
||||||
res (cp/process-changes data changes)]
|
res (cp/process-changes data changes)]
|
||||||
(t/is (= data res))))))
|
(t/is (= data res))))
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
(t/deftest process-change-move-objects-regression
|
(t/deftest process-change-move-objects-regression
|
||||||
|
@ -653,4 +711,57 @@
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
(t/deftest idenpotency-regression-1
|
||||||
|
(let [data {:version 5
|
||||||
|
:objects
|
||||||
|
{#uuid "00000000-0000-0000-0000-000000000000"
|
||||||
|
{:id #uuid "00000000-0000-0000-0000-000000000000",
|
||||||
|
:type :frame,
|
||||||
|
:name "root",
|
||||||
|
:shapes
|
||||||
|
[#uuid "f5d51910-ab23-11ea-ac38-e1abed64181a"
|
||||||
|
#uuid "f6a36590-ab23-11ea-ac38-e1abed64181a"]},
|
||||||
|
#uuid "f5d51910-ab23-11ea-ac38-e1abed64181a"
|
||||||
|
{:name "Rect-1",
|
||||||
|
:type :rect,
|
||||||
|
:id #uuid "f5d51910-ab23-11ea-ac38-e1abed64181a",
|
||||||
|
:parent-id #uuid "00000000-0000-0000-0000-000000000000",
|
||||||
|
:frame-id #uuid "00000000-0000-0000-0000-000000000000"}
|
||||||
|
#uuid "f6a36590-ab23-11ea-ac38-e1abed64181a"
|
||||||
|
{:name "Rect-2",
|
||||||
|
:type :rect,
|
||||||
|
:id #uuid "f6a36590-ab23-11ea-ac38-e1abed64181a",
|
||||||
|
:parent-id #uuid "00000000-0000-0000-0000-000000000000",
|
||||||
|
:frame-id #uuid "00000000-0000-0000-0000-000000000000"}}}
|
||||||
|
chgs [{:type :add-obj,
|
||||||
|
:id #uuid "3375ec40-ab24-11ea-b512-b945e8edccf5",
|
||||||
|
:frame-id #uuid "00000000-0000-0000-0000-000000000000",
|
||||||
|
:index 0
|
||||||
|
:obj {:name "Group-1",
|
||||||
|
:type :group,
|
||||||
|
:id #uuid "3375ec40-ab24-11ea-b512-b945e8edccf5",
|
||||||
|
:frame-id #uuid "00000000-0000-0000-0000-000000000000"}}
|
||||||
|
{:type :mov-objects,
|
||||||
|
:parent-id #uuid "3375ec40-ab24-11ea-b512-b945e8edccf5",
|
||||||
|
:shapes
|
||||||
|
[#uuid "f5d51910-ab23-11ea-ac38-e1abed64181a"
|
||||||
|
#uuid "f6a36590-ab23-11ea-ac38-e1abed64181a"]}]
|
||||||
|
|
||||||
|
res1 (cp/process-changes data chgs)
|
||||||
|
res2 (cp/process-changes res1 chgs)]
|
||||||
|
|
||||||
|
;; (clojure.pprint/pprint data)
|
||||||
|
;; (println "==============")
|
||||||
|
;; (clojure.pprint/pprint res2)
|
||||||
|
|
||||||
|
(t/is (= [#uuid "f5d51910-ab23-11ea-ac38-e1abed64181a"
|
||||||
|
#uuid "f6a36590-ab23-11ea-ac38-e1abed64181a"]
|
||||||
|
(get-in data [:objects uuid/zero :shapes])))
|
||||||
|
(t/is (= [#uuid "3375ec40-ab24-11ea-b512-b945e8edccf5"]
|
||||||
|
(get-in res2 [:objects uuid/zero :shapes])))
|
||||||
|
(t/is (= [#uuid "3375ec40-ab24-11ea-b512-b945e8edccf5"]
|
||||||
|
(get-in res1 [:objects uuid/zero :shapes])))
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
(ns uxbox.common.geom.shapes
|
(ns uxbox.common.geom.shapes
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[uxbox.common.pages :as cp]
|
|
||||||
[uxbox.common.spec :as us]
|
[uxbox.common.spec :as us]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.common.geom.matrix :as gmt]
|
[uxbox.common.geom.matrix :as gmt]
|
||||||
[uxbox.common.geom.point :as gpt]
|
[uxbox.common.geom.point :as gpt]
|
||||||
[uxbox.common.math :as mth]
|
[uxbox.common.math :as mth]
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
(defn recursive-move
|
(defn recursive-move
|
||||||
"Move the shape and all its recursive children."
|
"Move the shape and all its recursive children."
|
||||||
[shape dpoint objects]
|
[shape dpoint objects]
|
||||||
(let [children-ids (cp/get-children (:id shape) objects)
|
(let [children-ids (cph/get-children (:id shape) objects)
|
||||||
children (map #(get objects %) children-ids)]
|
children (map #(get objects %) children-ids)]
|
||||||
(map #(move % dpoint) (cons shape children))))
|
(map #(move % dpoint) (cons shape children))))
|
||||||
|
|
||||||
|
@ -253,6 +253,7 @@
|
||||||
;; -- Points
|
;; -- Points
|
||||||
|
|
||||||
(declare transform-shape-point)
|
(declare transform-shape-point)
|
||||||
|
|
||||||
(defn shape->points [shape]
|
(defn shape->points [shape]
|
||||||
(let [points
|
(let [points
|
||||||
(case (:type shape)
|
(case (:type shape)
|
||||||
|
|
|
@ -11,119 +11,15 @@
|
||||||
"A common (clj/cljs) functions and specs for pages."
|
"A common (clj/cljs) functions and specs for pages."
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[uxbox.common.uuid :as uuid]
|
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.common.exceptions :as ex]
|
[uxbox.common.exceptions :as ex]
|
||||||
[uxbox.common.spec :as us]))
|
[uxbox.common.geom.shapes :as geom]
|
||||||
|
[uxbox.common.spec :as us]
|
||||||
|
[uxbox.common.uuid :as uuid]))
|
||||||
|
|
||||||
(def page-version 5)
|
(def page-version 5)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Page Data Structure Helpers
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defn get-children
|
|
||||||
"Retrieve all children ids recursively for a given object"
|
|
||||||
[id objects]
|
|
||||||
(let [shapes (get-in objects [id :shapes])]
|
|
||||||
(if shapes
|
|
||||||
(d/concat shapes (mapcat #(get-children % objects) shapes))
|
|
||||||
[])))
|
|
||||||
|
|
||||||
(defn is-shape-grouped
|
|
||||||
"Checks if a shape is inside a group"
|
|
||||||
[shape-id objects]
|
|
||||||
(let [contains-shape-fn (fn [{:keys [shapes]}] ((set shapes) shape-id))
|
|
||||||
shapes (remove #(= (:type %) :frame) (vals objects))]
|
|
||||||
(some contains-shape-fn shapes)))
|
|
||||||
|
|
||||||
(defn get-parent
|
|
||||||
"Retrieve the id of the parent for the shape-id (if exists)"
|
|
||||||
[shape-id objects]
|
|
||||||
(let [check-parenthood
|
|
||||||
(fn [shape]
|
|
||||||
(when (and (:shapes shape)
|
|
||||||
((set (:shapes shape)) shape-id))
|
|
||||||
(:id shape)))]
|
|
||||||
(some check-parenthood (vals objects))))
|
|
||||||
|
|
||||||
(defn calculate-child-parent-map
|
|
||||||
[objects]
|
|
||||||
(let [red-fn
|
|
||||||
(fn [acc {:keys [id shapes]}]
|
|
||||||
;; Insert every pair shape -> parent into accumulated value
|
|
||||||
(into acc (map #(vector % id) (or shapes []))))]
|
|
||||||
(reduce red-fn {} (vals objects))))
|
|
||||||
|
|
||||||
(defn get-all-parents
|
|
||||||
[shape-id objects]
|
|
||||||
(let [child->parent (calculate-child-parent-map objects)
|
|
||||||
rec-fn (fn [cur result]
|
|
||||||
(if-let [parent (child->parent cur)]
|
|
||||||
(recur parent (conj result parent))
|
|
||||||
(vec (reverse result))))]
|
|
||||||
(rec-fn shape-id [])))
|
|
||||||
|
|
||||||
(defn- calculate-invalid-targets
|
|
||||||
[shape-id objects]
|
|
||||||
(let [result #{shape-id}
|
|
||||||
children (get-in objects [shape-id :shape])
|
|
||||||
reduce-fn (fn [result child-id]
|
|
||||||
(into result (calculate-invalid-targets child-id objects)))]
|
|
||||||
(reduce reduce-fn result children)))
|
|
||||||
|
|
||||||
(defn- valid-frame-target
|
|
||||||
[shape-id parent-id objects]
|
|
||||||
(let [shape (get objects shape-id)]
|
|
||||||
(or (not= (:type shape) :frame)
|
|
||||||
(= parent-id uuid/zero))))
|
|
||||||
|
|
||||||
(defn- insert-at-index
|
|
||||||
[shapes index ids]
|
|
||||||
(let [[before after] (split-at index shapes)
|
|
||||||
p? (set ids)]
|
|
||||||
(d/concat []
|
|
||||||
(remove p? before)
|
|
||||||
ids
|
|
||||||
(remove p? after))))
|
|
||||||
|
|
||||||
(defn select-toplevel-shapes
|
|
||||||
([objects] (select-toplevel-shapes objects nil))
|
|
||||||
([objects {:keys [include-frames?] :or {include-frames? false}}]
|
|
||||||
(let [lookup #(get objects %)
|
|
||||||
root (lookup uuid/zero)
|
|
||||||
childs (:shapes root)]
|
|
||||||
(loop [id (first childs)
|
|
||||||
ids (rest childs)
|
|
||||||
res []]
|
|
||||||
(if (nil? id)
|
|
||||||
res
|
|
||||||
(let [obj (lookup id)
|
|
||||||
typ (:type obj)]
|
|
||||||
(recur (first ids)
|
|
||||||
(rest ids)
|
|
||||||
(if (= :frame typ)
|
|
||||||
(if include-frames?
|
|
||||||
(d/concat res [obj] (map lookup (:shapes obj)))
|
|
||||||
(d/concat res (map lookup (:shapes obj))))
|
|
||||||
(conj res obj)))))))))
|
|
||||||
|
|
||||||
(defn select-frames
|
|
||||||
[objects]
|
|
||||||
(let [root (get objects uuid/zero)
|
|
||||||
loopfn (fn loopfn [ids]
|
|
||||||
(let [obj (get objects (first ids))]
|
|
||||||
(cond
|
|
||||||
(nil? obj)
|
|
||||||
nil
|
|
||||||
|
|
||||||
(= :frame (:type obj))
|
|
||||||
(lazy-seq (cons obj (loopfn (rest ids))))
|
|
||||||
|
|
||||||
:else
|
|
||||||
(lazy-seq (loopfn (rest ids))))))]
|
|
||||||
(loopfn (:shapes root))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Page Transformation Changes
|
;; Page Transformation Changes
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -258,6 +154,7 @@
|
||||||
::options
|
::options
|
||||||
::objects]))
|
::objects]))
|
||||||
|
|
||||||
|
(s/def ::ids (s/coll-of ::us/uuid))
|
||||||
(s/def ::attr keyword?)
|
(s/def ::attr keyword?)
|
||||||
(s/def ::val any?)
|
(s/def ::val any?)
|
||||||
(s/def ::frame-id uuid?)
|
(s/def ::frame-id uuid?)
|
||||||
|
@ -297,6 +194,10 @@
|
||||||
(s/keys :req-un [::id]
|
(s/keys :req-un [::id]
|
||||||
:opt-un [::session-id]))
|
:opt-un [::session-id]))
|
||||||
|
|
||||||
|
(defmethod change-spec-impl :reg-obj [_]
|
||||||
|
(s/keys :req-un [::ids]
|
||||||
|
:opt-un [::session-id]))
|
||||||
|
|
||||||
(defmethod change-spec-impl :mov-objects [_]
|
(defmethod change-spec-impl :mov-objects [_]
|
||||||
(s/keys :req-un [::parent-id ::shapes]
|
(s/keys :req-un [::parent-id ::shapes]
|
||||||
:opt-un [::index]))
|
:opt-un [::index]))
|
||||||
|
@ -402,8 +303,6 @@
|
||||||
(or (process-change %1 %2) %1))
|
(or (process-change %1 %2) %1))
|
||||||
data)))
|
data)))
|
||||||
|
|
||||||
(declare insert-at-index)
|
|
||||||
|
|
||||||
(defmethod process-change :set-option
|
(defmethod process-change :set-option
|
||||||
[data {:keys [option value]}]
|
[data {:keys [option value]}]
|
||||||
(let [path (if (seqable? option) option [option])]
|
(let [path (if (seqable? option) option [option])]
|
||||||
|
@ -418,8 +317,9 @@
|
||||||
(when (and (contains? objects parent-id)
|
(when (and (contains? objects parent-id)
|
||||||
(contains? objects frame-id))
|
(contains? objects frame-id))
|
||||||
(let [obj (assoc obj
|
(let [obj (assoc obj
|
||||||
:frame-id frame-id
|
:frame-id frame-id
|
||||||
:id id)]
|
:parent-id parent-id
|
||||||
|
:id id)]
|
||||||
(-> data
|
(-> data
|
||||||
(update :objects assoc id obj)
|
(update :objects assoc id obj)
|
||||||
(update-in [:objects parent-id :shapes]
|
(update-in [:objects parent-id :shapes]
|
||||||
|
@ -428,7 +328,7 @@
|
||||||
(cond
|
(cond
|
||||||
(some #{id} shapes) shapes
|
(some #{id} shapes) shapes
|
||||||
(nil? index) (conj shapes id)
|
(nil? index) (conj shapes id)
|
||||||
:else (insert-at-index shapes index [id]))))))))))
|
:else (cph/insert-at-index shapes index [id]))))))))))
|
||||||
|
|
||||||
(defmethod process-change :mod-obj
|
(defmethod process-change :mod-obj
|
||||||
[data {:keys [id operations] :as change}]
|
[data {:keys [id operations] :as change}]
|
||||||
|
@ -442,7 +342,7 @@
|
||||||
[data {:keys [id] :as change}]
|
[data {:keys [id] :as change}]
|
||||||
(when-let [{:keys [frame-id shapes] :as obj} (get-in data [:objects id])]
|
(when-let [{:keys [frame-id shapes] :as obj} (get-in data [:objects id])]
|
||||||
(let [objects (:objects data)
|
(let [objects (:objects data)
|
||||||
parent-id (get-parent id objects)
|
parent-id (cph/get-parent id objects)
|
||||||
parent (get objects parent-id)
|
parent (get objects parent-id)
|
||||||
data (update data :objects dissoc id)]
|
data (update data :objects dissoc id)]
|
||||||
(cond-> data
|
(cond-> data
|
||||||
|
@ -456,15 +356,44 @@
|
||||||
(seq shapes) ; Recursive delete all dependend objects
|
(seq shapes) ; Recursive delete all dependend objects
|
||||||
(as-> $ (reduce #(or (process-change %1 {:type :del-obj :id %2}) %1) $ shapes))))))
|
(as-> $ (reduce #(or (process-change %1 {:type :del-obj :id %2}) %1) $ shapes))))))
|
||||||
|
|
||||||
|
(defmethod process-change :reg-obj
|
||||||
|
[data {:keys [ids]}]
|
||||||
|
(let [objects (:objects data)]
|
||||||
|
(loop [ids ids data data]
|
||||||
|
(if (seq ids)
|
||||||
|
(let [item (get objects (first ids))]
|
||||||
|
(if (= :group (:type item))
|
||||||
|
(recur
|
||||||
|
(rest ids)
|
||||||
|
(update-in data [:objects (:id item)]
|
||||||
|
(fn [{:keys [shapes] :as obj}]
|
||||||
|
(let [shapes (->> shapes
|
||||||
|
(map (partial get objects))
|
||||||
|
(filter identity))]
|
||||||
|
(if (seq shapes)
|
||||||
|
(let [selrect (geom/selection-rect shapes)]
|
||||||
|
(as-> obj $
|
||||||
|
(assoc $
|
||||||
|
:x (:x selrect)
|
||||||
|
:y (:y selrect)
|
||||||
|
:width (:width selrect)
|
||||||
|
:height (:height selrect))
|
||||||
|
(assoc $ :points (geom/shape->points $))
|
||||||
|
(assoc $ :selrect (geom/points->selrect (:points $)))))
|
||||||
|
obj)))))
|
||||||
|
(recur (rest ids) data)))
|
||||||
|
data))))
|
||||||
|
|
||||||
(defmethod process-change :mov-objects
|
(defmethod process-change :mov-objects
|
||||||
[data {:keys [parent-id shapes index] :as change}]
|
[data {:keys [parent-id shapes index] :as change}]
|
||||||
(let [child->parent (calculate-child-parent-map (:objects data))
|
(let [
|
||||||
;; Check if the move from shape-id -> parent-id is valid
|
;; Check if the move from shape-id -> parent-id is valid
|
||||||
|
|
||||||
is-valid-move
|
is-valid-move
|
||||||
(fn [shape-id]
|
(fn [shape-id]
|
||||||
(let [invalid-targets (calculate-invalid-targets shape-id (:objects data))]
|
(let [invalid-targets (cph/calculate-invalid-targets shape-id (:objects data))]
|
||||||
(and (not (invalid-targets parent-id))
|
(and (not (invalid-targets parent-id))
|
||||||
(valid-frame-target shape-id parent-id (:objects data)))))
|
(cph/valid-frame-target shape-id parent-id (:objects data)))))
|
||||||
|
|
||||||
valid? (every? is-valid-move shapes)
|
valid? (every? is-valid-move shapes)
|
||||||
|
|
||||||
|
@ -473,7 +402,7 @@
|
||||||
(fn [prev-shapes]
|
(fn [prev-shapes]
|
||||||
(let [prev-shapes (or prev-shapes [])]
|
(let [prev-shapes (or prev-shapes [])]
|
||||||
(if index
|
(if index
|
||||||
(insert-at-index prev-shapes index shapes)
|
(cph/insert-at-index prev-shapes index shapes)
|
||||||
(reduce (fn [acc id]
|
(reduce (fn [acc id]
|
||||||
(if (some #{id} acc)
|
(if (some #{id} acc)
|
||||||
acc
|
acc
|
||||||
|
@ -485,23 +414,31 @@
|
||||||
(fn [id]
|
(fn [id]
|
||||||
(fn [coll] (filterv #(not= % id) coll)))
|
(fn [coll] (filterv #(not= % id) coll)))
|
||||||
|
|
||||||
;; Remove from the old :shapes the references that have been moved
|
cpindex
|
||||||
remove-in-parent
|
(reduce
|
||||||
(fn [data shape-id]
|
(fn [index id]
|
||||||
(let [parent-id' (get child->parent shape-id)]
|
(let [obj (get-in data [:objects id])]
|
||||||
|
(assoc index id (:parent-id obj))))
|
||||||
|
{} (keys (:objects data)))
|
||||||
|
|
||||||
|
remove-from-old-parent
|
||||||
|
(fn remove-from-old-parent [data shape-id]
|
||||||
|
(let [prev-parent-id (get cpindex shape-id)]
|
||||||
;; Do nothing if the parent id of the shape is the same as
|
;; Do nothing if the parent id of the shape is the same as
|
||||||
;; the new destination target parent id.
|
;; the new destination target parent id.
|
||||||
(if (= parent-id' parent-id)
|
(if (= prev-parent-id parent-id)
|
||||||
data
|
data
|
||||||
(let [parent (-> (get-in data [:objects parent-id'])
|
(loop [sid shape-id
|
||||||
(update :shapes (strip-id shape-id)))]
|
pid prev-parent-id
|
||||||
;; When the group is empty we should remove it
|
data data]
|
||||||
(if (and (= :group (:type parent))
|
(let [obj (get-in data [:objects pid])]
|
||||||
(empty? (:shapes parent)))
|
(if (and (= 1 (count (:shapes obj)))
|
||||||
(-> data
|
(= sid (first (:shapes obj)))
|
||||||
(update :objects dissoc (:id parent))
|
(= :group (:type obj)))
|
||||||
(update-in [:objects (:frame-id parent) :shapes] (strip-id (:id parent))))
|
(recur pid
|
||||||
(update data :objects assoc parent-id' parent))))))
|
(:parent-id obj)
|
||||||
|
(update data :objects dissoc pid))
|
||||||
|
(update-in data [:objects pid :shapes] (strip-id sid))))))))
|
||||||
|
|
||||||
parent (get-in data [:objects parent-id])
|
parent (get-in data [:objects parent-id])
|
||||||
frame (if (= :frame (:type parent))
|
frame (if (= :frame (:type parent))
|
||||||
|
@ -510,11 +447,16 @@
|
||||||
|
|
||||||
frame-id (:id frame)
|
frame-id (:id frame)
|
||||||
|
|
||||||
|
;; Update parent-id references.
|
||||||
|
update-parent-id
|
||||||
|
(fn [data id]
|
||||||
|
(update-in data [:objects id] assoc :parent-id parent-id))
|
||||||
|
|
||||||
;; Updates the frame-id references that might be outdated
|
;; Updates the frame-id references that might be outdated
|
||||||
update-frame-ids
|
update-frame-ids
|
||||||
(fn update-frame-ids [data id]
|
(fn update-frame-ids [data id]
|
||||||
(let [data (assoc-in data [:objects id :frame-id] frame-id)
|
(let [data (assoc-in data [:objects id :frame-id] frame-id)
|
||||||
obj (get-in data [:objects id])]
|
obj (get-in data [:objects id])]
|
||||||
(cond-> data
|
(cond-> data
|
||||||
(not= :frame (:type obj))
|
(not= :frame (:type obj))
|
||||||
(as-> $$ (reduce update-frame-ids $$ (:shapes obj))))))]
|
(as-> $$ (reduce update-frame-ids $$ (:shapes obj))))))]
|
||||||
|
@ -522,9 +464,11 @@
|
||||||
(when valid?
|
(when valid?
|
||||||
(as-> data $
|
(as-> data $
|
||||||
(update-in $ [:objects parent-id :shapes] insert-items)
|
(update-in $ [:objects parent-id :shapes] insert-items)
|
||||||
(reduce remove-in-parent $ shapes)
|
(reduce update-parent-id $ shapes)
|
||||||
|
(reduce remove-from-old-parent $ shapes)
|
||||||
(reduce update-frame-ids $ (get-in $ [:objects parent-id :shapes]))))))
|
(reduce update-frame-ids $ (get-in $ [:objects parent-id :shapes]))))))
|
||||||
|
|
||||||
|
|
||||||
(defmethod process-operation :set
|
(defmethod process-operation :set
|
||||||
[shape op]
|
[shape op]
|
||||||
(let [attr (:attr op)
|
(let [attr (:attr op)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
(ns uxbox.common.pages-migrations
|
(ns uxbox.common.pages-migrations
|
||||||
(:require
|
(:require
|
||||||
[uxbox.common.pages :as p]
|
[uxbox.common.pages :as cp]
|
||||||
[uxbox.common.geom.shapes :as gsh]
|
[uxbox.common.geom.shapes :as gsh]
|
||||||
[uxbox.common.geom.point :as gpt]
|
[uxbox.common.geom.point :as gpt]
|
||||||
[uxbox.common.geom.matrix :as gmt]
|
[uxbox.common.geom.matrix :as gmt]
|
||||||
|
@ -8,15 +8,17 @@
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.common.data :as d]))
|
[uxbox.common.data :as d]))
|
||||||
|
|
||||||
|
;; TODO: revisit this
|
||||||
|
|
||||||
(defmulti migrate :version)
|
(defmulti migrate :version)
|
||||||
|
|
||||||
(defn migrate-data
|
(defn migrate-data
|
||||||
([data]
|
([data]
|
||||||
(if (= (:version data) p/page-version)
|
(if (= (:version data) cp/page-version)
|
||||||
data
|
data
|
||||||
(reduce #(migrate-data %1 %2 (inc %2))
|
(reduce #(migrate-data %1 %2 (inc %2))
|
||||||
data
|
data
|
||||||
(range (:version data 0) p/page-version))))
|
(range (:version data 0) cp/page-version))))
|
||||||
|
|
||||||
([data from-version to-version]
|
([data from-version to-version]
|
||||||
(-> data
|
(-> data
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.common.exceptions :as ex]
|
[uxbox.common.exceptions :as ex]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.common.spec :as us]
|
[uxbox.common.spec :as us]
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.config :as cfg]
|
[uxbox.config :as cfg]
|
||||||
|
@ -212,7 +213,7 @@
|
||||||
(initialize [state local]
|
(initialize [state local]
|
||||||
(let [page-id (get-in state [:workspace-page :id])
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
shapes (cp/select-toplevel-shapes objects {:include-frames? true})
|
shapes (cph/select-toplevel-shapes objects {:include-frames? true})
|
||||||
srect (geom/selection-rect shapes)
|
srect (geom/selection-rect shapes)
|
||||||
local (assoc local :vport size)]
|
local (assoc local :vport size)]
|
||||||
(cond
|
(cond
|
||||||
|
@ -286,7 +287,7 @@
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
groups-to-adjust (->> ids
|
groups-to-adjust (->> ids
|
||||||
(mapcat #(reverse (cp/get-all-parents % objects)))
|
(mapcat #(cph/get-parents % objects))
|
||||||
(map #(get objects %))
|
(map #(get objects %))
|
||||||
(filter #(= (:type %) :group))
|
(filter #(= (:type %) :group))
|
||||||
(map #(:id %))
|
(map #(:id %))
|
||||||
|
@ -405,7 +406,7 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [page-id (get-in state [:workspace-page :id])
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
shapes (cp/select-toplevel-shapes objects {:include-frames? true})
|
shapes (cph/select-toplevel-shapes objects {:include-frames? true})
|
||||||
srect (geom/selection-rect shapes)]
|
srect (geom/selection-rect shapes)]
|
||||||
|
|
||||||
(if (or (mth/nan? (:width srect))
|
(if (or (mth/nan? (:width srect))
|
||||||
|
@ -481,7 +482,7 @@
|
||||||
unames (retrieve-used-names objects)
|
unames (retrieve-used-names objects)
|
||||||
name (generate-unique-name unames (:name shape))
|
name (generate-unique-name unames (:name shape))
|
||||||
|
|
||||||
frames (cp/select-frames objects)
|
frames (cph/select-frames objects)
|
||||||
|
|
||||||
frame-id (if (= :frame (:type shape))
|
frame-id (if (= :frame (:type shape))
|
||||||
uuid/zero
|
uuid/zero
|
||||||
|
@ -578,7 +579,7 @@
|
||||||
grouped #{:frame :group}]
|
grouped #{:frame :group}]
|
||||||
(update-in state [:workspace-data page-id :objects]
|
(update-in state [:workspace-data page-id :objects]
|
||||||
(fn [objects]
|
(fn [objects]
|
||||||
(->> (d/concat [id] (cp/get-children id objects))
|
(->> (d/concat [id] (cph/get-children id objects))
|
||||||
(map #(get objects %))
|
(map #(get objects %))
|
||||||
(remove #(grouped (:type %)))
|
(remove #(grouped (:type %)))
|
||||||
(reduce #(update %1 (:id %2) update-shape) objects)))))))))
|
(reduce #(update %1 (:id %2) update-shape) objects)))))))))
|
||||||
|
@ -647,6 +648,7 @@
|
||||||
:right (gpt/point 1 0)))
|
:right (gpt/point 1 0)))
|
||||||
|
|
||||||
;; --- Delete Selected
|
;; --- Delete Selected
|
||||||
|
|
||||||
(defn- delete-shapes
|
(defn- delete-shapes
|
||||||
[ids]
|
[ids]
|
||||||
(us/assert (s/coll-of ::us/uuid) ids)
|
(us/assert (s/coll-of ::us/uuid) ids)
|
||||||
|
@ -655,38 +657,57 @@
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
cpindex (cp/calculate-child-parent-map objects)
|
|
||||||
|
|
||||||
del-change #(array-map :type :del-obj :id %)
|
del-change #(array-map :type :del-obj :id %)
|
||||||
|
reg-change #(array-map :type :reg-obj :id %)
|
||||||
|
|
||||||
get-empty-parents
|
get-empty-parents
|
||||||
(fn get-empty-parents [id]
|
(fn get-empty-parents [parents]
|
||||||
(let [parent (get objects (get cpindex id))]
|
(->> parents
|
||||||
(if (and (= :group (:type parent))
|
(map (fn [id]
|
||||||
(= 1 (count (:shapes parent))))
|
(let [obj (get objects id)]
|
||||||
(lazy-seq (cons (:id parent)
|
(when (and (= :group (:type obj))
|
||||||
(get-empty-parents (:id parent))))
|
(= 1 (count (:shapes obj))))
|
||||||
nil)))
|
obj))))
|
||||||
|
(take-while (complement nil?))
|
||||||
|
(map :id)))
|
||||||
|
|
||||||
rchanges
|
rchanges
|
||||||
(reduce (fn [res id]
|
(reduce (fn [res id]
|
||||||
(let [chd (cp/get-children id objects)]
|
(let [children (cph/get-children id objects)
|
||||||
(into res (d/concat
|
parents (cph/get-parents id objects)]
|
||||||
(mapv del-change (reverse chd))
|
(d/concat res
|
||||||
[(del-change id)]
|
(map del-change (reverse children))
|
||||||
(map del-change (get-empty-parents id))))))
|
[(del-change id)]
|
||||||
|
(map del-change (get-empty-parents parents))
|
||||||
|
[{:type :reg-obj :ids parents}])))
|
||||||
[]
|
[]
|
||||||
ids)
|
ids)
|
||||||
|
|
||||||
uchanges
|
uchanges
|
||||||
(mapv (fn [id]
|
(reduce (fn [res id]
|
||||||
(let [obj (get objects id)]
|
(let [children (cph/get-children id objects)
|
||||||
{:type :add-obj
|
parents (cph/get-parents id objects)
|
||||||
:id id
|
add-chg (fn [id]
|
||||||
:frame-id (:frame-id obj)
|
(let [item (get objects id)]
|
||||||
:parent-id (get cpindex id)
|
{:type :add-obj
|
||||||
:obj obj}))
|
:id (:id item)
|
||||||
(reverse (map :id rchanges)))]
|
:frame-id (:frame-id item)
|
||||||
|
:parent-id (:parent-id item)
|
||||||
|
:obj item}))]
|
||||||
|
(d/concat res
|
||||||
|
(map add-chg (reverse (get-empty-parents parents)))
|
||||||
|
[(add-chg id)]
|
||||||
|
(map add-chg children)
|
||||||
|
[{:type :reg-obj :ids parents}])))
|
||||||
|
[]
|
||||||
|
ids)
|
||||||
|
]
|
||||||
|
|
||||||
|
;; (println "================ rchanges")
|
||||||
|
;; (cljs.pprint/pprint rchanges)
|
||||||
|
;; (println "================ uchanges")
|
||||||
|
;; (cljs.pprint/pprint uchanges)
|
||||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||||
|
|
||||||
(def delete-selected
|
(def delete-selected
|
||||||
|
@ -764,7 +785,7 @@
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
parent (get objects (cp/get-parent id objects))
|
parent (get objects (cph/get-parent id objects))
|
||||||
current-index (d/index-of (:shapes parent) id)
|
current-index (d/index-of (:shapes parent) id)
|
||||||
selected (get-in state [:workspace-local :selected])]
|
selected (get-in state [:workspace-local :selected])]
|
||||||
(rx/of (dwc/commit-changes [{:type :mov-objects
|
(rx/of (dwc/commit-changes [{:type :mov-objects
|
||||||
|
@ -992,7 +1013,7 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [page-id (get-in state [:workspace-page :id])
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
childs (cp/get-children id objects)]
|
childs (cph/get-children id objects)]
|
||||||
(update-in state [:workspace-data page-id :objects]
|
(update-in state [:workspace-data page-id :objects]
|
||||||
(fn [objects]
|
(fn [objects]
|
||||||
(reduce (fn [objects id]
|
(reduce (fn [objects id]
|
||||||
|
@ -1215,7 +1236,6 @@
|
||||||
(when (not-empty selected)
|
(when (not-empty selected)
|
||||||
(let [page-id (get-in state [:workspace-page :id])
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
|
|
||||||
selected-objects (map (partial get objects) selected)
|
selected-objects (map (partial get objects) selected)
|
||||||
selrect (geom/selection-rect selected-objects)
|
selrect (geom/selection-rect selected-objects)
|
||||||
frame-id (-> selected-objects first :frame-id)
|
frame-id (-> selected-objects first :frame-id)
|
||||||
|
@ -1226,7 +1246,6 @@
|
||||||
(map-indexed vector)
|
(map-indexed vector)
|
||||||
(filter #(selected (second %)))
|
(filter #(selected (second %)))
|
||||||
(ffirst))
|
(ffirst))
|
||||||
|
|
||||||
rchanges [{:type :add-obj
|
rchanges [{:type :add-obj
|
||||||
:id id
|
:id id
|
||||||
:frame-id frame-id
|
:frame-id frame-id
|
||||||
|
@ -1255,7 +1274,7 @@
|
||||||
(when (and (= 1 (count selected))
|
(when (and (= 1 (count selected))
|
||||||
(= (:type group) :group))
|
(= (:type group) :group))
|
||||||
(let [shapes (:shapes group)
|
(let [shapes (:shapes group)
|
||||||
parent-id (cp/get-parent group-id objects)
|
parent-id (cph/get-parent group-id objects)
|
||||||
parent (get objects parent-id)
|
parent (get objects parent-id)
|
||||||
index-in-parent (->> (:shapes parent)
|
index-in-parent (->> (:shapes parent)
|
||||||
(map-indexed vector)
|
(map-indexed vector)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.common.spec :as us]
|
[uxbox.common.spec :as us]
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.main.worker :as uw]
|
[uxbox.main.worker :as uw]
|
||||||
|
@ -202,8 +203,8 @@
|
||||||
(let [page-id (get-in state [:workspace-page :id])
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
|
|
||||||
shapes (cp/select-toplevel-shapes objects)
|
shapes (cph/select-toplevel-shapes objects)
|
||||||
frames (cp/select-frames objects)
|
frames (cph/select-frames objects)
|
||||||
|
|
||||||
[rch uch] (calculate-shape-to-frame-relationship-changes frames shapes)]
|
[rch uch] (calculate-shape-to-frame-relationship-changes frames shapes)]
|
||||||
(when-not (empty? rch)
|
(when-not (empty? rch)
|
||||||
|
@ -212,7 +213,7 @@
|
||||||
|
|
||||||
(defn get-frame-at-point
|
(defn get-frame-at-point
|
||||||
[objects point]
|
[objects point]
|
||||||
(let [frames (cp/select-frames objects)]
|
(let [frames (cph/select-frames objects)]
|
||||||
(loop [frame (first frames)
|
(loop [frame (first frames)
|
||||||
rest (rest frames)]
|
rest (rest frames)]
|
||||||
(d/seek #(geom/has-point? % point) frames))))
|
(d/seek #(geom/has-point? % point) frames))))
|
||||||
|
@ -306,7 +307,7 @@
|
||||||
(let [expand-fn (fn [expanded]
|
(let [expand-fn (fn [expanded]
|
||||||
(merge expanded
|
(merge expanded
|
||||||
(->> ids
|
(->> ids
|
||||||
(map #(cp/get-all-parents % objects))
|
(map #(cph/get-parents % objects))
|
||||||
flatten
|
flatten
|
||||||
(filter #(not= % uuid/zero))
|
(filter #(not= % uuid/zero))
|
||||||
(map (fn [id] {id true}))
|
(map (fn [id] {id true}))
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
[uxbox.common.geom.shapes :as geom]
|
[uxbox.common.geom.shapes :as geom]
|
||||||
[uxbox.common.geom.point :as gpt]
|
[uxbox.common.geom.point :as gpt]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.util.geom.path :as path]
|
[uxbox.util.geom.path :as path]
|
||||||
[uxbox.main.snap :as snap]
|
[uxbox.main.snap :as snap]
|
||||||
[uxbox.main.streams :as ms]
|
[uxbox.main.streams :as ms]
|
||||||
|
@ -95,7 +96,7 @@
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
layout (get state :workspace-layout)
|
layout (get state :workspace-layout)
|
||||||
|
|
||||||
frames (cp/select-frames objects)
|
frames (cph/select-frames objects)
|
||||||
fid (or (->> frames
|
fid (or (->> frames
|
||||||
(filter #(geom/has-point? % initial))
|
(filter #(geom/has-point? % initial))
|
||||||
first
|
first
|
||||||
|
|
|
@ -12,16 +12,17 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[uxbox.main.data.workspace.common :as dwc]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.main.worker :as uw]
|
[uxbox.common.geom.point :as gpt]
|
||||||
[uxbox.main.streams :as ms]
|
[uxbox.common.geom.shapes :as geom]
|
||||||
|
[uxbox.common.math :as mth]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.common.spec :as us]
|
[uxbox.common.spec :as us]
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.common.data :as d]
|
[uxbox.main.data.workspace.common :as dwc]
|
||||||
[uxbox.common.geom.shapes :as geom]
|
[uxbox.main.streams :as ms]
|
||||||
[uxbox.common.geom.point :as gpt]
|
[uxbox.main.worker :as uw]))
|
||||||
[uxbox.common.math :as mth]))
|
|
||||||
|
|
||||||
(s/def ::set-of-uuid
|
(s/def ::set-of-uuid
|
||||||
(s/every uuid? :kind set?))
|
(s/every uuid? :kind set?))
|
||||||
|
@ -220,7 +221,7 @@
|
||||||
name (generate-unique-name names (:name obj))
|
name (generate-unique-name names (:name obj))
|
||||||
renamed-obj (assoc obj :id id :name name)
|
renamed-obj (assoc obj :id id :name name)
|
||||||
moved-obj (geom/move renamed-obj delta)
|
moved-obj (geom/move renamed-obj delta)
|
||||||
frames (cp/select-frames objects)
|
frames (cph/select-frames objects)
|
||||||
frame-id (if frame-id
|
frame-id (if frame-id
|
||||||
frame-id
|
frame-id
|
||||||
(dwc/calculate-frame-overlap frames moved-obj))
|
(dwc/calculate-frame-overlap frames moved-obj))
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.common.spec :as us]
|
[uxbox.common.spec :as us]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.main.data.workspace.common :as dwc]
|
[uxbox.main.data.workspace.common :as dwc]
|
||||||
[uxbox.main.data.workspace.selection :as dws]
|
[uxbox.main.data.workspace.selection :as dws]
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
|
@ -346,7 +347,7 @@
|
||||||
(or recurse-frames? (not (= :frame (:type shape))))))
|
(or recurse-frames? (not (= :frame (:type shape))))))
|
||||||
|
|
||||||
;; ID's + Children but remove frame children if the flag is set to false
|
;; ID's + Children but remove frame children if the flag is set to false
|
||||||
ids-with-children (concat ids (mapcat #(cp/get-children % objects)
|
ids-with-children (concat ids (mapcat #(cph/get-children % objects)
|
||||||
(filter not-frame-id? ids)))
|
(filter not-frame-id? ids)))
|
||||||
|
|
||||||
;; For each shape updates the modifiers given as arguments
|
;; For each shape updates the modifiers given as arguments
|
||||||
|
@ -391,7 +392,7 @@
|
||||||
|
|
||||||
(let [objects (get-in state [:workspace-data page-id :objects])
|
(let [objects (get-in state [:workspace-data page-id :objects])
|
||||||
id->obj #(get objects %)
|
id->obj #(get objects %)
|
||||||
get-children (fn [shape] (map id->obj (cp/get-children (:id shape) objects)))
|
get-children (fn [shape] (map id->obj (cph/get-children (:id shape) objects)))
|
||||||
shapes (concat shapes (mapcat get-children shapes))]
|
shapes (concat shapes (mapcat get-children shapes))]
|
||||||
(rotate-around-center state delta-rotation center shapes))))))))
|
(rotate-around-center state delta-rotation center shapes))))))))
|
||||||
|
|
||||||
|
@ -408,7 +409,7 @@
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
|
|
||||||
;; ID's + Children
|
;; ID's + Children
|
||||||
ids-with-children (concat ids (mapcat #(cp/get-children % objects) ids))
|
ids-with-children (concat ids (mapcat #(cph/get-children % objects) ids))
|
||||||
|
|
||||||
;; For each shape applies the modifiers by transforming the objects
|
;; For each shape applies the modifiers by transforming the objects
|
||||||
update-shape
|
update-shape
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.common.math :as mth]
|
[uxbox.common.math :as mth]
|
||||||
[uxbox.common.geom.shapes :as geom]
|
[uxbox.common.geom.shapes :as geom]
|
||||||
[uxbox.common.geom.point :as gpt]
|
[uxbox.common.geom.point :as gpt]
|
||||||
|
@ -39,7 +40,7 @@
|
||||||
|
|
||||||
(defn- calculate-dimensions
|
(defn- calculate-dimensions
|
||||||
[{:keys [objects] :as data} vport]
|
[{:keys [objects] :as data} vport]
|
||||||
(let [shapes (cp/select-toplevel-shapes objects {:include-frames? true})]
|
(let [shapes (cph/select-toplevel-shapes objects {:include-frames? true})]
|
||||||
(->> (geom/selection-rect shapes)
|
(->> (geom/selection-rect shapes)
|
||||||
(geom/adjust-to-viewport vport)
|
(geom/adjust-to-viewport vport)
|
||||||
(geom/fix-invalid-rect-values))))
|
(geom/fix-invalid-rect-values))))
|
||||||
|
@ -132,7 +133,7 @@
|
||||||
|
|
||||||
frame-id (:id frame)
|
frame-id (:id frame)
|
||||||
|
|
||||||
modifier-ids (concat [frame-id] (cp/get-children frame-id objects))
|
modifier-ids (concat [frame-id] (cph/get-children frame-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)
|
objects (reduce update-fn objects modifier-ids)
|
||||||
frame (assoc-in frame [:modifiers :displacement] modifier)
|
frame (assoc-in frame [:modifiers :displacement] modifier)
|
||||||
|
|
|
@ -10,12 +10,13 @@
|
||||||
(ns uxbox.main.refs
|
(ns uxbox.main.refs
|
||||||
"A collection of derived refs."
|
"A collection of derived refs."
|
||||||
(:require
|
(:require
|
||||||
[okulary.core :as l]
|
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
|
[okulary.core :as l]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.main.constants :as c]
|
[uxbox.main.constants :as c]
|
||||||
[uxbox.main.store :as st]
|
[uxbox.main.store :as st]))
|
||||||
[uxbox.common.uuid :as uuid]))
|
|
||||||
|
|
||||||
;; ---- Global refs
|
;; ---- Global refs
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@
|
||||||
(l/derived :objects workspace-data))
|
(l/derived :objects workspace-data))
|
||||||
|
|
||||||
(def workspace-frames
|
(def workspace-frames
|
||||||
(l/derived cp/select-frames workspace-objects))
|
(l/derived cph/select-frames workspace-objects))
|
||||||
|
|
||||||
(defn object-by-id
|
(defn object-by-id
|
||||||
[id]
|
[id]
|
||||||
|
@ -106,7 +107,7 @@
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
selected (get-in state [:workspace-local :selected])
|
selected (get-in state [:workspace-local :selected])
|
||||||
shape (get objects id)
|
shape (get objects id)
|
||||||
children (cp/get-children id objects)]
|
children (cph/get-children id objects)]
|
||||||
(some selected children)))]
|
(some selected children)))]
|
||||||
(l/derived selector st/state)))
|
(l/derived selector st/state)))
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@
|
||||||
(let [selected (get-in state [:workspace-local :selected])
|
(let [selected (get-in state [:workspace-local :selected])
|
||||||
page-id (get-in state [:workspace-page :id])
|
page-id (get-in state [:workspace-page :id])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
children (mapcat #(cp/get-children % objects) selected)]
|
children (mapcat #(cph/get-children % objects) selected)]
|
||||||
(into selected children)))]
|
(into selected children)))]
|
||||||
(l/derived selector st/state)))
|
(l/derived selector st/state)))
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.main.data.viewer :as dv]
|
[uxbox.main.data.viewer :as dv]
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
[uxbox.main.store :as st]
|
[uxbox.main.store :as st]
|
||||||
|
@ -174,7 +175,7 @@
|
||||||
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
||||||
|
|
||||||
frame-id (:id frame)
|
frame-id (:id frame)
|
||||||
modifier-ids (d/concat [frame-id] (cp/get-children frame-id objects))
|
modifier-ids (d/concat [frame-id] (cph/get-children frame-id objects))
|
||||||
objects (reduce update-fn objects modifier-ids)
|
objects (reduce update-fn objects modifier-ids)
|
||||||
frame (assoc-in frame [:modifiers :displacement] modifier)
|
frame (assoc-in frame [:modifiers :displacement] modifier)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.main.data.workspace :as dw]
|
[uxbox.main.data.workspace :as dw]
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
[uxbox.main.store :as st]
|
[uxbox.main.store :as st]
|
||||||
|
@ -154,7 +155,7 @@
|
||||||
(if (= side :center)
|
(if (= side :center)
|
||||||
(st/emit! (dw/relocate-shape id (:id item) 0))
|
(st/emit! (dw/relocate-shape id (:id item) 0))
|
||||||
(let [to-index (if (= side :top) (inc index) index)
|
(let [to-index (if (= side :top) (inc index) index)
|
||||||
parent-id (cp/get-parent (:id item) objects)]
|
parent-id (cph/get-parent (:id item) objects)]
|
||||||
(st/emit! (dw/relocate-shape id parent-id to-index)))))
|
(st/emit! (dw/relocate-shape id parent-id to-index)))))
|
||||||
|
|
||||||
on-hold
|
on-hold
|
||||||
|
@ -223,7 +224,7 @@
|
||||||
old-obs (unchecked-get oprops "objects")]
|
old-obs (unchecked-get oprops "objects")]
|
||||||
(and (= new-itm old-itm)
|
(and (= new-itm old-itm)
|
||||||
(identical? new-idx old-idx)
|
(identical? new-idx old-idx)
|
||||||
(let [childs (cp/get-children (:id new-itm) new-obs)
|
(let [childs (cph/get-children (:id new-itm) new-obs)
|
||||||
childs' (conj childs (:id new-itm))]
|
childs' (conj childs (:id new-itm))]
|
||||||
(and (or (= new-sel old-sel)
|
(and (or (= new-sel old-sel)
|
||||||
(not (or (boolean (some new-sel childs'))
|
(not (or (boolean (some new-sel childs'))
|
||||||
|
@ -273,7 +274,7 @@
|
||||||
|
|
||||||
(defn- strip-objects
|
(defn- strip-objects
|
||||||
[objects]
|
[objects]
|
||||||
(let [strip-data #(select-keys % [:id :name :blocked :hidden :shapes :type :content :metadata])]
|
(let [strip-data #(select-keys % [:id :name :blocked :hidden :shapes :type :content :parent-id :metadata])]
|
||||||
(persistent!
|
(persistent!
|
||||||
(reduce-kv (fn [res id obj]
|
(reduce-kv (fn [res id obj]
|
||||||
(assoc! res id (strip-data obj)))
|
(assoc! res id (strip-data obj)))
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[uxbox.main.ui.icons :as i]
|
[uxbox.main.ui.icons :as i]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.main.data.workspace :as dw]
|
[uxbox.main.data.workspace :as dw]
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
[uxbox.main.store :as st]
|
[uxbox.main.store :as st]
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
destination (get objects (:destination interaction))
|
destination (get objects (:destination interaction))
|
||||||
frames (mf/use-memo (mf/deps objects)
|
frames (mf/use-memo (mf/deps objects)
|
||||||
#(cp/select-frames objects))
|
#(cph/select-frames objects))
|
||||||
|
|
||||||
show-frames-dropdown? (mf/use-state false)
|
show-frames-dropdown? (mf/use-state false)
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,13 @@
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[uxbox.common.exceptions :as ex]
|
[uxbox.common.exceptions :as ex]
|
||||||
[uxbox.common.spec :as us]
|
|
||||||
[uxbox.common.pages :as cp]
|
|
||||||
[uxbox.common.uuid :as uuid]
|
|
||||||
[uxbox.worker.impl :as impl]
|
|
||||||
[uxbox.common.geom.shapes :as geom]
|
[uxbox.common.geom.shapes :as geom]
|
||||||
[uxbox.util.quadtree :as qdt]))
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
|
[uxbox.common.spec :as us]
|
||||||
|
[uxbox.common.uuid :as uuid]
|
||||||
|
[uxbox.util.quadtree :as qdt]
|
||||||
|
[uxbox.worker.impl :as impl]))
|
||||||
|
|
||||||
(defonce state (l/atom {}))
|
(defonce state (l/atom {}))
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@
|
||||||
|
|
||||||
(defn- create-index
|
(defn- create-index
|
||||||
[objects]
|
[objects]
|
||||||
(let [shapes (->> (cp/select-toplevel-shapes objects {:include-frames? true})
|
(let [shapes (->> (cph/select-toplevel-shapes objects {:include-frames? true})
|
||||||
(map #(merge % (select-keys % [:x :y :width :height]))))
|
(map #(merge % (select-keys % [:x :y :width :height]))))
|
||||||
bounds (geom/selection-rect shapes)
|
bounds (geom/selection-rect shapes)
|
||||||
bounds #js {:x (:x bounds)
|
bounds #js {:x (:x bounds)
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[uxbox.common.uuid :as uuid]
|
[uxbox.common.uuid :as uuid]
|
||||||
[uxbox.common.pages :as cp]
|
[uxbox.common.pages :as cp]
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.pages-helpers :as cph]
|
||||||
|
[uxbox.common.data :as d]
|
||||||
[uxbox.worker.impl :as impl]
|
[uxbox.worker.impl :as impl]
|
||||||
[uxbox.util.range-tree :as rt]
|
[uxbox.util.range-tree :as rt]
|
||||||
[uxbox.util.geom.snap-points :as snap]
|
[uxbox.util.geom.snap-points :as snap]
|
||||||
|
@ -45,7 +46,7 @@
|
||||||
(let [frame-shapes (->> (vals objects)
|
(let [frame-shapes (->> (vals objects)
|
||||||
(filter :frame-id)
|
(filter :frame-id)
|
||||||
(group-by :frame-id))
|
(group-by :frame-id))
|
||||||
frame-shapes (->> (cp/select-frames objects)
|
frame-shapes (->> (cph/select-frames objects)
|
||||||
(reduce #(update %1 (:id %2) conj %2) frame-shapes))]
|
(reduce #(update %1 (:id %2) conj %2) frame-shapes))]
|
||||||
(d/mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x)
|
(d/mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x)
|
||||||
:y (create-coord-data frame-id shapes :y)})
|
:y (create-coord-data frame-id shapes :y)})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue