             [uxbox.util.geom.point :as gpt]
             [uxbox.util.data :refer (index-of)]))
 
+;; --- Shapes CRUD
+
 (defn add-shape
   "Create and add shape to the current selected page."
   [shape]

                 merge
                 (when color {:fill color})
                 (when opacity {:fill-opacity opacity})))))

(defn lock-proportions
  "Mark proportions of the shape locked and save the current
  proportion as additional precalculated property."
  [sid]
  {:pre [(uuid? sid)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (let [[width height] (-> (get-in state [:shapes-by-id sid])
                               (geom/size)
                               (keep [:width :height]))
            proportion (/ width height)]
        (update-in state [:shapes-by-id sid] assoc
                   :proportion proportion
                   :proportion-lock true)))))

(defn unlock-proportions
  [sid]
  {:pre [(uuid? sid)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (update-in state [:shapes-by-id sid] assoc
                 :proportion-lock false))))

(defn setup-proportions
  [sid]
  {:pre [(uuid? sid)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (let [[width height] (-> (get-in state [:shapes-by-id sid])
                               (geom/size)
                               (keep [:width :height]))
            proportion (/ width height)]
        (update-in state [:shapes-by-id sid] assoc
                   :proportion proportion)))))

(defn update-font-attrs
  [sid {:keys [family style weight size align

                 merge
                 (when rx {:rx rx})
                 (when ry {:ry ry})))))


;; --- Shape Proportions

(defn lock-proportions
  "Mark proportions of the shape locked and save the current
  proportion as additional precalculated property."
  [sid]
  {:pre [(uuid? sid)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (let [[width height] (-> (get-in state [:shapes-by-id sid])
                               (geom/size)
                               (keep [:width :height]))
            proportion (/ width height)]
        (update-in state [:shapes-by-id sid] assoc
                   :proportion proportion
                   :proportion-lock true)))))

(defn unlock-proportions
  [sid]
  {:pre [(uuid? sid)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (update-in state [:shapes-by-id sid] assoc
                 :proportion-lock false))))

(defn setup-proportions
  [sid]
  {:pre [(uuid? sid)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (let [[width height] (-> (get-in state [:shapes-by-id sid])
                               (geom/size)
                               (keep [:width :height]))
            proportion (/ width height)]
        (update-in state [:shapes-by-id sid] assoc
                   :proportion proportion)))))

;; --- Group Collapsing

(defn collapse-shape
  [id]
  {:pre [(uuid? id)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (update-in state [:shapes-by-id id] assoc :collapsed true))))

(defn uncollapse-shape
  [id]
  {:pre [(uuid? id)]}
  (reify
    udp/IPageUpdate
    rs/UpdateEvent
    (-apply-update [_ state]
      (update-in state [:shapes-by-id id] assoc :collapsed false))))

;; --- Shape Visibility

(defn hide-shape
  [sid]
