Improve unique name generation for shapes in a page.

This commit is contained in:
Andrey Antukh 2017-01-05 23:54:29 +01:00
parent 28d18a07a0
commit bfce5f8a00
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
2 changed files with 89 additions and 66 deletions

View file

@ -35,17 +35,17 @@
;; --- Shapes CRUD ;; --- Shapes CRUD
(defn add-shape (deftype AddShape [data]
"Create and add shape to the current selected page."
[shape]
(reify
udp/IPageUpdate udp/IPageUpdate
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [page (get-in state [:workspace :page]) (let [shape (geom/setup-proportions data)
used-names (map #(get-in state [:shapes % :name]) (get-in state [:pages page :shapes])) page (l/focus ul/selected-page state)]
shape (geom/setup-proportions shape)] (impl/assoc-shape-to-page state shape page))))
(impl/assoc-shape-to-page state shape used-names page)))))
(defn add-shape
[data]
(AddShape. data))
(defn delete-shape (defn delete-shape
"Remove the shape using its id." "Remove the shape using its id."
@ -605,18 +605,18 @@
selected (get-in state [:workspace :selected])] selected (get-in state [:workspace :selected])]
(impl/degroup-shapes state selected pid))))) (impl/degroup-shapes state selected pid)))))
;; TODO: maybe split in two separate events ;; --- Duplicate Selected
(defn duplicate-selected
[] (deftype DuplicateSelected []
(reify
udp/IPageUpdate udp/IPageUpdate
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [pid (get-in state [:workspace :page]) (let [selected (get-in state [:workspace :selected])]
selected (get-in state [:workspace :selected]) (impl/duplicate-shapes state selected))))
used-names (map #(get-in state [:shapes % :name])
(get-in state [:pages pid :shapes]))] (defn duplicate-selected
(impl/duplicate-shapes state selected used-names))))) []
(DuplicateSelected.))
(defn delete-selected (defn delete-selected
"Deselect all and remove all selected shapes." "Deselect all and remove all selected shapes."

View file

@ -5,67 +5,89 @@
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.data.shapes-impl (ns uxbox.main.data.shapes-impl
(:require [uxbox.util.uuid :as uuid] (:require [lentes.core :as l]
[uxbox.util.data :refer (index-of)] [uxbox.main.geom :as geom]
[uxbox.main.geom :as geom])) [uxbox.main.lenses :as ul]
[uxbox.util.uuid :as uuid]
[uxbox.util.data :refer (index-of)]))
;; --- Shape Creation ;; --- Shape Creation
(defn generate-uniq-name (defn retrieve-used-names
[used-names new-name counter] "Returns a set of already used names by shapes
(if (nil? counter) in the current page."
(if (some #(= % new-name) used-names) [{:keys [shapes] :as state}]
(generate-uniq-name used-names new-name 1) (let [page (l/focus ul/selected-page state)
new-name) xform (comp (map second)
(if (some #(= % (str new-name "-" counter)) used-names) (filter #(= page (:page %)))
(generate-uniq-name used-names new-name (inc counter)) (map :name))]
(str new-name "-" counter)))) (into #{} xform shapes)))
(defn generate-unique-name
"A unique name generator based on the previous
state of the used names."
[state basename]
(let [used (retrieve-used-names state)]
(loop [counter 1]
(let [candidate (str basename "-" counter)]
(if (contains? used candidate)
(recur (inc counter))
candidate)))))
(defn assoc-shape-to-page (defn assoc-shape-to-page
[state shape used-names page] [state shape page]
(let [sid (uuid/random) (let [shape-id (uuid/random)
shape (merge shape {:id sid :page page :name (generate-uniq-name used-names (:name shape) nil)})] shape-name (generate-unique-name state (:name shape))
(as-> state $ shape (assoc shape
(update-in $ [:pages page :shapes] #(into [] (cons sid %))) :page page
(assoc-in $ [:shapes sid] shape)))) :id shape-id
:name shape-name)]
(-> state
(update-in [:pages page :shapes] #(into [] (cons shape-id %)))
(assoc-in [:shapes shape-id] shape))))
(defn duplicate-shapes' (defn duplicate-shapes'
([state shapes used-names page] ([state shapes page]
(duplicate-shapes' state shapes used-names page nil)) (duplicate-shapes' state shapes page nil))
([state shapes used-names page group] ([state shapes page group]
(letfn [(duplicate-shape [state shape used-names page group] (letfn [(duplicate-shape [state shape page group]
(if (= (:type shape) :group) (if (= (:type shape) :group)
(let [id (uuid/random) (let [id (uuid/random)
items (:items shape) items (:items shape)
shape (assoc shape :id id :page page :items [] :name (generate-uniq-name used-names (str (:name shape) " copy") nil)) name (generate-unique-name state (str (:name shape) "-copy"))
shape (assoc shape
:id id
:page page
:items []
:name name)
state (if (nil? group) state (if (nil? group)
(as-> state $ (-> state
(update-in $ [:pages page :shapes] #(into [] (cons id %))) (update-in [:pages page :shapes] #(into [] (cons id %)))
(assoc-in $ [:shapes id] shape)) (assoc-in [:shapes id] shape))
(as-> state $ (-> state
(update-in $ [:shapes group :items] #(into [] (cons id %))) (update-in [:shapes group :items] #(into [] (cons id %)))
(assoc-in $ [:shapes id] shape)))] (assoc-in [:shapes id] shape)))]
(->> (map #(get-in state [:shapes %]) items) (->> (map #(get-in state [:shapes %]) items)
(reverse) (reverse)
(reduce #(duplicate-shape %1 %2 used-names page id) state))) (reduce #(duplicate-shape %1 %2 page id) state)))
(let [id (uuid/random) (let [id (uuid/random)
name (generate-unique-name state (str (:name shape) "-copy"))
shape (-> (dissoc shape :group) shape (-> (dissoc shape :group)
(assoc :id id :page page :name (generate-uniq-name used-names (str (:name shape) " copy") nil)) (assoc :id id :page page :name name)
(merge (when group {:group group})))] (merge (when group {:group group})))]
(if (nil? group) (if (nil? group)
(as-> state $ (-> state
(update-in $ [:pages page :shapes] #(into [] (cons id %))) (update-in [:pages page :shapes] #(into [] (cons id %)))
(assoc-in $ [:shapes id] shape)) (assoc-in [:shapes id] shape))
(as-> state $ (-> state
(update-in $ [:shapes group :items] #(into [] (cons id %))) (update-in [:shapes group :items] #(into [] (cons id %)))
(assoc-in $ [:shapes id] shape))))))] (assoc-in [:shapes id] shape))))))]
(reduce #(duplicate-shape %1 %2 page group) state shapes))))
(reduce #(duplicate-shape %1 %2 used-names page group) state shapes))))
(defn duplicate-shapes (defn duplicate-shapes
([state shapes used-names] ([state shapes]
(duplicate-shapes state shapes used-names nil)) (duplicate-shapes state shapes nil))
([state shapes used-names page] ([state shapes page]
(letfn [(all-toplevel? [coll] (letfn [(all-toplevel? [coll]
(every? #(nil? (:group %)) coll)) (every? #(nil? (:group %)) coll))
(all-same-group? [coll] (all-same-group? [coll]
@ -75,16 +97,16 @@
(cond (cond
(all-toplevel? shapes) (all-toplevel? shapes)
(let [page (or page (:page (first shapes)))] (let [page (or page (:page (first shapes)))]
(duplicate-shapes' state shapes used-names page)) (duplicate-shapes' state shapes page))
(all-same-group? shapes) (all-same-group? shapes)
(let [page (or page (:page (first shapes))) (let [page (or page (:page (first shapes)))
group (:group (first shapes))] group (:group (first shapes))]
(duplicate-shapes' state shapes used-names page group)) (duplicate-shapes' state shapes page group))
:else :else
(let [page (or page (:page (first shapes)))] (let [page (or page (:page (first shapes)))]
(duplicate-shapes' state shapes used-names page))))))) (duplicate-shapes' state shapes page)))))))
;; --- Delete Shapes ;; --- Delete Shapes
@ -329,8 +351,9 @@
(not= 1 (count distinct-groups)) :multi (not= 1 (count distinct-groups)) :multi
(nil? (first distinct-groups)) :page (nil? (first distinct-groups)) :page
:else (first distinct-groups)) :else (first distinct-groups))
name (generate-unique-name state "Group")
group {:type :group group {:type :group
:name (generate-uniq-name used-names "Group" nil) :name name
:items (into [] shapes) :items (into [] shapes)
:id sid :id sid
:page page}] :page page}]