From 9d522bc72a3226c1b0d8c9fa8cdc77aac6247fa6 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:05:56 +0300 Subject: [PATCH 01/31] rename primary-tool to cached-tool --- src/renderer/app/db.cljs | 2 +- src/renderer/app/views.cljs | 2 +- .../element/impl/container/canvas.cljs | 4 ++-- src/renderer/event/handlers.cljs | 18 +++++++++--------- src/renderer/tool/subs.cljs | 4 ++-- src/renderer/toolbar/tools.cljs | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/renderer/app/db.cljs b/src/renderer/app/db.cljs index a8d407dc..897b6b55 100644 --- a/src/renderer/app/db.cljs +++ b/src/renderer/app/db.cljs @@ -36,7 +36,7 @@ (def App [:map {:closed true} [:tool {:default :transform} Tool] - [:primary-tool {:optional true} Tool] + [:cached-tool {:optional true} Tool] [:pointer-pos {:default [0 0]} Vec2] [:pointer-offset {:optional true} Vec2] [:adjusted-pointer-pos {:default [0 0]} Vec2] diff --git a/src/renderer/app/views.cljs b/src/renderer/app/views.cljs index dc5fcd6a..989e008c 100644 --- a/src/renderer/app/views.cljs +++ b/src/renderer/app/views.cljs @@ -58,7 +58,7 @@ ["Pointer drag?" (str @(rf/subscribe [::tool.subs/drag?]))] ["Pan" (coll->str @(rf/subscribe [::document.subs/pan]))] ["Active tool" @(rf/subscribe [::tool.subs/active])] - ["Primary tool" @(rf/subscribe [::tool.subs/primary])] + ["Cached tool" @(rf/subscribe [::tool.subs/cached])] ["State" @(rf/subscribe [::tool.subs/state])] ["Clicked element" (:id @(rf/subscribe [::app.subs/clicked-element]))] ["Ignored elements" @(rf/subscribe [::document.subs/ignored-ids])] diff --git a/src/renderer/element/impl/container/canvas.cljs b/src/renderer/element/impl/container/canvas.cljs index a94fa947..badc7f31 100644 --- a/src/renderer/element/impl/container/canvas.cljs +++ b/src/renderer/element/impl/container/canvas.cljs @@ -34,7 +34,7 @@ read-only? @(rf/subscribe [::document.subs/read-only?]) cursor @(rf/subscribe [::tool.subs/cursor]) active-tool @(rf/subscribe [::tool.subs/active]) - primary-tool @(rf/subscribe [::tool.subs/primary]) + cached-tool @(rf/subscribe [::tool.subs/cached]) rotate @(rf/subscribe [::document.subs/rotate]) grid @(rf/subscribe [::app.subs/grid]) pointer-handler #(event.pointer/handler! % el) @@ -75,7 +75,7 @@ (when nearest-neighbor [snap.views/canvas-label nearest-neighbor])]) - (when-not read-only? [tool.hierarchy/render (or primary-tool active-tool)])])) + (when-not read-only? [tool.hierarchy/render (or cached-tool active-tool)])])) (defmethod element.hierarchy/render-to-string :canvas [el] diff --git a/src/renderer/event/handlers.cljs b/src/renderer/event/handlers.cljs index 09cfb54d..53360462 100644 --- a/src/renderer/event/handlers.cljs +++ b/src/renderer/event/handlers.cljs @@ -22,7 +22,7 @@ (m/=> pointer [:-> App PointerEvent App]) (defn pointer [db e] - (let [{:keys [pointer-offset tool dom-rect drag primary-tool + (let [{:keys [pointer-offset tool dom-rect drag cached-tool drag-threshold nearest-neighbor]} db {:keys [button pointer-pos timestamp pointer-id]} e adjusted-pointer-pos (frame.handlers/adjusted-pointer-pos db pointer-pos) @@ -50,7 +50,7 @@ "pointerdown" (cond-> db (= button :middle) - (-> (assoc :primary-tool tool) + (-> (assoc :cached-tool tool) (tool.handlers/activate :pan)) (not= button :right) @@ -73,9 +73,9 @@ (tool.hierarchy/on-double-click e)) (-> (assoc db :event-timestamp timestamp) (tool.hierarchy/on-pointer-up e))))) - (and primary-tool (= button :middle)) - (-> (tool.handlers/activate primary-tool) - (dissoc :primary-tool)) + (and cached-tool (= button :middle)) + (-> (tool.handlers/activate cached-tool) + (dissoc :cached-tool)) :always (dissoc :pointer-offset :drag :nearest-neighbor)) @@ -91,7 +91,7 @@ (and (= (:code e) "Space") (not= (:tool db) :pan) (= (:state db) :idle)) - (-> (assoc :primary-tool (:tool db)) + (-> (assoc :cached-tool (:tool db)) (tool.handlers/activate :pan)) :always @@ -100,9 +100,9 @@ "keyup" (cond-> db (and (= (:code e) "Space") - (:primary-tool db)) - (-> (tool.handlers/activate (:primary-tool db)) - (dissoc :primary-tool)) + (:cached-tool db)) + (-> (tool.handlers/activate (:cached-tool db)) + (dissoc :cached-tool)) :always (tool.hierarchy/on-key-up e)) diff --git a/src/renderer/tool/subs.cljs b/src/renderer/tool/subs.cljs index cd19b8b1..b4aba581 100644 --- a/src/renderer/tool/subs.cljs +++ b/src/renderer/tool/subs.cljs @@ -8,8 +8,8 @@ :-> :tool) (rf/reg-sub - ::primary - :-> :primary-tool) + ::cached + :-> :cached-tool) (rf/reg-sub ::pivot-point diff --git a/src/renderer/toolbar/tools.cljs b/src/renderer/toolbar/tools.cljs index b3b90e41..fb304976 100644 --- a/src/renderer/toolbar/tools.cljs +++ b/src/renderer/toolbar/tools.cljs @@ -11,9 +11,9 @@ (defn button [tool] (let [active-tool @(rf/subscribe [::tool.subs/active]) - primary-tool @(rf/subscribe [::tool.subs/primary]) + cached-tool @(rf/subscribe [::tool.subs/cached]) active (= active-tool tool) - primary (= primary-tool tool) + primary (= cached-tool tool) properties (tool.hierarchy/properties tool) label (or (:label properties) (string/capitalize (name tool)))] (when (:icon properties) From 00d3edd5881507901c6b01b2692f9935bf7598b4 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:11:44 +0300 Subject: [PATCH 02/31] enhance circle tool --- src/renderer/tool/impl/element/circle.cljs | 62 ++++++++++++++++++---- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index 675f0f02..73718a10 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -3,6 +3,8 @@ (:require [clojure.core.matrix :as matrix] [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] + [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -12,21 +14,61 @@ [] {:icon "circle-tool"}) -(defmethod tool.hierarchy/on-drag :circle - [db _e] +(defn create + [db] + (let [offset (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) + position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) + radius (matrix/distance position offset) + [cx cy] offset + fill (document.handlers/attr db :fill) + stroke (document.handlers/attr db :stroke)] + (-> (tool.handlers/set-state db :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :circle + :attrs {:cx cx + :cy cy + :fill fill + :stroke stroke + :r radius}})))) + +(defn update-radius + [db] (let [offset (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - [x y] offset radius (matrix/distance position offset) - attrs {:cx x - :cy y - :fill (document.handlers/attr db :fill) - :stroke (document.handlers/attr db :stroke) - :r radius}] - (tool.handlers/set-temp db {:type :element :tag :circle :attrs attrs}))) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id #(assoc-in % [:attrs :r] (str radius))))) + +(defmethod tool.hierarchy/on-pointer-up :circle + [db _e] + (if (= (:state db) :create) + (-> (tool.handlers/activate db :transform) + (history.handlers/finalize "Create circle")) + (create db))) + +(defmethod tool.hierarchy/on-pointer-move :circle + [db _e] + (cond-> db + (= (:state db) :create) + (update-radius))) + +(defmethod tool.hierarchy/on-drag-start :circle + [db _e] + (create db)) + +(defmethod tool.hierarchy/on-drag :circle + [db _e] + (update-radius db)) + +(defmethod tool.hierarchy/on-drag-end :circle + [db _e] + (-> db + (tool.handlers/activate :transform) + (history.handlers/finalize "Create circle"))) (defmethod tool.hierarchy/snapping-points :circle [db] [(with-meta (:adjusted-pointer-pos db) - {:label (str (name (:tool db)) " " (if (tool.handlers/temp db) "radius" "center"))})]) + {:label (str "Circle " (if (tool.handlers/temp db) "radius" "center"))})]) From ee3fcb96c91a61ccdd889044747d7b7c619b1a27 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:11:50 +0300 Subject: [PATCH 03/31] enhance ellipse tool --- src/renderer/tool/impl/element/ellipse.cljs | 74 +++++++++++++++++---- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/src/renderer/tool/impl/element/ellipse.cljs b/src/renderer/tool/impl/element/ellipse.cljs index 109b2bdd..c87e3eaa 100644 --- a/src/renderer/tool/impl/element/ellipse.cljs +++ b/src/renderer/tool/impl/element/ellipse.cljs @@ -2,6 +2,8 @@ "https://www.w3.org/TR/SVG/shapes.html#EllipseElement" (:require [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] + [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -15,19 +17,65 @@ [] [:div "Hold " [:span.shortcut-key "Ctrl"] " to lock proportions."]) -(defmethod tool.hierarchy/on-drag :ellipse - [db e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) +(defn create + [db lock-ratio] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) + [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) + rx (abs (- x offset-x)) + ry (abs (- y offset-y)) + rx (cond-> rx lock-ratio (min ry)) + ry (cond-> ry lock-ratio (min rx)) + fill (document.handlers/attr db :fill) + stroke (document.handlers/attr db :stroke)] + (-> (tool.handlers/set-state db :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :ellipse + :attrs {:cx offset-x + :cy offset-y + :fill fill + :stroke stroke + :rx rx + :ry ry}})))) + +(defn update-radius + [db lock-ratio] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - lock-ratio (:ctrl-key e) rx (abs (- x offset-x)) ry (abs (- y offset-y)) - attrs {:cx offset-x - :cy offset-y - :fill (document.handlers/attr db :fill) - :stroke (document.handlers/attr db :stroke) - :rx (if lock-ratio (min rx ry) rx) - :ry (if lock-ratio (min rx ry) ry)}] - (tool.handlers/set-temp db {:type :element - :tag :ellipse - :attrs attrs}))) + rx (cond-> rx lock-ratio (min ry)) + ry (cond-> ry lock-ratio (min rx)) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id #(-> % + (assoc-in [:attrs :rx] (str rx)) + (assoc-in [:attrs :ry] (str ry)))))) + +(defmethod tool.hierarchy/on-pointer-up :ellipse + [db e] + (if (= (:state db) :create) + (-> (tool.handlers/activate db :transform) + (history.handlers/finalize "Create ellipse")) + (create db (:ctrl-key e)))) + +(defmethod tool.hierarchy/on-pointer-move :ellipse + [db e] + (cond-> db + (= (:state db) :create) + (update-radius (:ctrl-key e)))) + +(defmethod tool.hierarchy/on-drag-start :ellipse + [db e] + (create db (:ctrl-key e))) + +(defmethod tool.hierarchy/on-drag :ellipse + [db e] + (update-radius db (:ctrl-key e))) + +(defmethod tool.hierarchy/on-drag-end :ellipse + [db _e] + (-> db + (tool.handlers/activate :transform) + (history.handlers/finalize "Create ellipse"))) From 48ee3394fef3045e04352fc28b6498d4c759914f Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:11:56 +0300 Subject: [PATCH 04/31] enhance line tool --- src/renderer/tool/impl/element/line.cljs | 64 ++++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/renderer/tool/impl/element/line.cljs b/src/renderer/tool/impl/element/line.cljs index 2056f637..7fdf9245 100644 --- a/src/renderer/tool/impl/element/line.cljs +++ b/src/renderer/tool/impl/element/line.cljs @@ -2,6 +2,7 @@ "https://www.w3.org/TR/SVG/shapes.html#LineElement" (:require [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -12,53 +13,52 @@ [] {:icon "line-tool"}) -(defn create-line +(defn create [db] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - attrs {:x1 offset-x - :y1 offset-y - :x2 x - :y2 y - :stroke (document.handlers/attr db :stroke)}] - (tool.handlers/set-temp db {:type :element - :tag :line - :attrs attrs}))) + stroke (document.handlers/attr db :stroke)] + (-> (tool.handlers/set-state db :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :line + :attrs {:x1 offset-x + :y1 offset-y + :x2 x + :y2 y + :stroke stroke}})))) -(defn update-line-end +(defn update-end [db] (let [[x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - temp (-> (tool.handlers/temp db) - (assoc-in [:attrs :x2] x) - (assoc-in [:attrs :y2] y))] - (tool.handlers/set-temp db temp))) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id #(-> % + (assoc-in [:attrs :x2] (str x)) + (assoc-in [:attrs :y2] (str y)))))) (defmethod tool.hierarchy/on-pointer-move :line [db _e] (cond-> db - (tool.handlers/temp db) - (update-line-end))) + (= (:state db) :create) + (update-end))) (defmethod tool.hierarchy/on-pointer-up :line [db _e] - (cond - (tool.handlers/temp db) - (-> (tool.handlers/create-temp-element db) - (tool.handlers/activate :transform) + (if (= (:state db) :create) + (-> (tool.handlers/activate db :transform) (history.handlers/finalize "Create line")) + (create db))) - (:pointer-offset db) - (-> (tool.handlers/set-state db :create) - (create-line)) - - :else db)) - -(defmethod tool.hierarchy/on-pointer-down :line +(defmethod tool.hierarchy/on-drag-start :line [db _e] - (cond-> db - (tool.handlers/temp db) - (history.handlers/finalize "Create line"))) + (create db)) (defmethod tool.hierarchy/on-drag :line [db _e] - (create-line db)) + (update-end db)) + +(defmethod tool.hierarchy/on-drag-end :line + [db _e] + (-> (tool.handlers/activate db :transform) + (history.handlers/finalize "Create line"))) From 9168f16b6fa5df895df03fc160f7a64ca0614ccf Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:21:40 +0300 Subject: [PATCH 05/31] enhance rect tool --- src/renderer/tool/impl/element/rect.cljs | 76 ++++++++++++++++++++---- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index 467cb70a..367532f7 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -2,6 +2,8 @@ "https://www.w3.org/TR/SVG/shapes.html#RectElement" (:require [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] + [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -16,17 +18,67 @@ [] [:div "Hold " [:span.shortcut-key "Ctrl"] " to lock proportions."]) -(defmethod tool.hierarchy/on-drag :rect - [db e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) +(defn create + [db lock-ratio] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) + [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) + width (abs (- x offset-x)) + height (abs (- y offset-y)) + width (cond-> width lock-ratio (min height)) + height (cond-> height lock-ratio (min width)) + fill (document.handlers/attr db :fill) + stroke (document.handlers/attr db :stroke)] + (-> (tool.handlers/set-state db :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :rect + :attrs {:x (min x offset-x) + :y (min y offset-y) + :width width + :height height + :fill fill + :stroke stroke}})))) + +(defn update-size + [db lock-ratio] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) width (abs (- x offset-x)) - height (abs (- y offset-y))] - (tool.handlers/set-temp db {:type :element - :tag :rect - :attrs {:x (min x offset-x) - :y (min y offset-y) - :width (if (:ctrl-key e) (min width height) width) - :height (if (:ctrl-key e) (min width height) height) - :fill (document.handlers/attr db :fill) - :stroke (document.handlers/attr db :stroke)}}))) + height (abs (- y offset-y)) + width (cond-> width lock-ratio (min height)) + height (cond-> height lock-ratio (min width)) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id #(-> % + (assoc-in [:attrs :x] (str (min x offset-x))) + (assoc-in [:attrs :y] (str (min y offset-y))) + (assoc-in [:attrs :width] (str width)) + (assoc-in [:attrs :height] (str height)))))) + +(defmethod tool.hierarchy/on-pointer-up :rect + [db e] + (if (= (:state db) :create) + (-> (tool.handlers/activate db :transform) + (history.handlers/finalize "Create rectangle")) + (create db (:ctrl-key e)))) + +(defmethod tool.hierarchy/on-pointer-move :rect + [db e] + (cond-> db + (= (:state db) :create) + (update-size (:ctrl-key e)))) + +(defmethod tool.hierarchy/on-drag-start :rect + [db e] + (create db (:ctrl-key e))) + +(defmethod tool.hierarchy/on-drag :rect + [db e] + (update-size db (:ctrl-key e))) + +(defmethod tool.hierarchy/on-drag-end :rect + [db _e] + (-> db + (tool.handlers/activate :transform) + (history.handlers/finalize "Create rectangle"))) From 013ba3254618691f9a44ac43f7ccb8185377faef Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:25:46 +0300 Subject: [PATCH 06/31] enhance svg tool --- src/renderer/tool/impl/element/svg.cljs | 70 +++++++++++++++++++++---- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/src/renderer/tool/impl/element/svg.cljs b/src/renderer/tool/impl/element/svg.cljs index eba325ac..8c402adf 100644 --- a/src/renderer/tool/impl/element/svg.cljs +++ b/src/renderer/tool/impl/element/svg.cljs @@ -1,6 +1,8 @@ (ns renderer.tool.impl.element.svg "https://www.w3.org/TR/SVG/struct.html#SVGElement" (:require + [renderer.element.handlers :as element.handlers] + [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -14,17 +16,63 @@ [] [:div "Hold " [:span.shortcut-key "Ctrl"] " to lock proportions."]) -(defmethod tool.hierarchy/on-drag :svg - [db e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) +(defn create + [db lock-ratio] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) + [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) + width (abs (- x offset-x)) + height (abs (- y offset-y)) + width (cond-> width lock-ratio (min height)) + height (cond-> height lock-ratio (min width))] + (-> (tool.handlers/set-state db :create) + (element.handlers/deselect-all) + (element.handlers/add {:tag :svg + :type :element + :attrs {:x (min x offset-x) + :y (min y offset-y) + :width width + :height height}})))) + +(defn update-size + [db lock-ratio] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - lock-ratio (:ctrl-key e) width (abs (- x offset-x)) height (abs (- y offset-y)) - attrs {:x (min x offset-x) - :y (min y offset-y) - :width (if lock-ratio (min width height) width) - :height (if lock-ratio (min width height) height)}] - (tool.handlers/set-temp db {:tag :svg - :type :element - :attrs attrs}))) + width (cond-> width lock-ratio (min height)) + height (cond-> height lock-ratio (min width)) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id #(-> % + (assoc-in [:attrs :x] (str (min x offset-x))) + (assoc-in [:attrs :y] (str (min y offset-y))) + (assoc-in [:attrs :width] (str width)) + (assoc-in [:attrs :height] (str height)))))) + +(defmethod tool.hierarchy/on-pointer-up :svg + [db e] + (if (= (:state db) :create) + (-> (tool.handlers/activate db :transform) + (history.handlers/finalize "Create SVG")) + (create db (:ctrl-key e)))) + +(defmethod tool.hierarchy/on-pointer-move :svg + [db e] + (cond-> db + (= (:state db) :create) + (update-size (:ctrl-key e)))) + +(defmethod tool.hierarchy/on-drag-start :svg + [db e] + (create db (:ctrl-key e))) + +(defmethod tool.hierarchy/on-drag :svg + [db e] + (update-size db (:ctrl-key e))) + +(defmethod tool.hierarchy/on-drag-end :svg + [db _e] + (-> db + (tool.handlers/activate :transform) + (history.handlers/finalize "Create SVG"))) From d6df665a4fbfb7cedc5cbd6042aa43a9b0ba5d32 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:31:46 +0300 Subject: [PATCH 07/31] enhance blob tool --- src/renderer/tool/impl/extension/blob.cljs | 72 ++++++++++++++++------ 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/src/renderer/tool/impl/extension/blob.cljs b/src/renderer/tool/impl/extension/blob.cljs index 51ea0965..7642681e 100644 --- a/src/renderer/tool/impl/extension/blob.cljs +++ b/src/renderer/tool/impl/extension/blob.cljs @@ -3,6 +3,8 @@ (:require [clojure.core.matrix :as matrix] [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] + [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -17,27 +19,59 @@ (matrix/distance (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)))) +(defn create + [db] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) + radius (pointer-delta db) + fill (document.handlers/attr db :fill) + stroke (document.handlers/attr db :stroke)] + (-> (tool.handlers/set-state db :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :blob + :attrs {:x (- offset-x radius) + :y (- offset-y radius) + :seed (rand-int 1000000) + :extraPoints 8 + :randomness 4 + :size (* radius 2) + :fill fill + :stroke stroke}})))) + +(defn update-size + [db] + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) + radius (pointer-delta db) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id #(-> % + (assoc-in [:attrs :x] (str (- offset-x radius))) + (assoc-in [:attrs :y] (str (- offset-y radius))) + (assoc-in [:attrs :size] (str (* radius 2))))))) + +(defmethod tool.hierarchy/on-pointer-up :blob + [db _e] + (if (= (:state db) :create) + (-> (tool.handlers/activate db :transform) + (history.handlers/finalize "Create blob")) + (create db))) + +(defmethod tool.hierarchy/on-pointer-move :blob + [db _e] + (cond-> db + (= (:state db) :create) + (update-size))) + (defmethod tool.hierarchy/on-drag-start :blob [db _e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) - radius (pointer-delta db)] - (tool.handlers/set-temp db {:type :element - :tag :blob - :attrs {:x (- offset-x radius) - :y (- offset-y radius) - :seed (rand-int 1000000) - :extraPoints 8 - :randomness 4 - :size (* radius 2) - :fill (document.handlers/attr db :fill) - :stroke (document.handlers/attr db :stroke)}}))) + (create db)) (defmethod tool.hierarchy/on-drag :blob [db _e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) - radius (pointer-delta db) - temp (-> (tool.handlers/temp db) - (assoc-in [:attrs :x] (- offset-x radius)) - (assoc-in [:attrs :y] (- offset-y radius)) - (assoc-in [:attrs :size] (* radius 2)))] - (tool.handlers/set-temp db temp))) + (update-size db)) + +(defmethod tool.hierarchy/on-drag-end :blob + [db _e] + (-> db + (tool.handlers/activate :transform) + (history.handlers/finalize "Create blob"))) From f57f6e8078dbabeef901dba52f672326f9f454c8 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 08:59:42 +0300 Subject: [PATCH 08/31] reset history on tool activation --- src/renderer/tool/handlers.cljs | 1 + src/renderer/tool/impl/draw/brush.cljs | 4 ++-- src/renderer/tool/impl/element/circle.cljs | 9 +++++---- src/renderer/tool/impl/element/core.cljs | 4 ++-- src/renderer/tool/impl/element/ellipse.cljs | 12 +++++++----- src/renderer/tool/impl/element/line.cljs | 14 +++++++++----- src/renderer/tool/impl/element/polyshape.cljs | 4 ++-- src/renderer/tool/impl/element/rect.cljs | 9 +++++---- src/renderer/tool/impl/element/svg.cljs | 9 +++++---- src/renderer/tool/impl/extension/blob.cljs | 9 +++++---- src/renderer/tool/impl/misc/dropper.cljs | 13 ++++++++----- 11 files changed, 51 insertions(+), 37 deletions(-) diff --git a/src/renderer/tool/handlers.cljs b/src/renderer/tool/handlers.cljs index 78883ebe..e9f90eb5 100644 --- a/src/renderer/tool/handlers.cljs +++ b/src/renderer/tool/handlers.cljs @@ -38,6 +38,7 @@ (set-state :idle) (set-cursor "default") (dissoc :drag :pointer-offset :clicked-element) + (history.handlers/reset-state) (snap.handlers/rebuild-tree) (tool.hierarchy/on-activate))) diff --git a/src/renderer/tool/impl/draw/brush.cljs b/src/renderer/tool/impl/draw/brush.cljs index e4de7e18..0cf89bfd 100644 --- a/src/renderer/tool/impl/draw/brush.cljs +++ b/src/renderer/tool/impl/draw/brush.cljs @@ -46,5 +46,5 @@ [db _e] (-> db (tool.handlers/create-temp-element) - (tool.handlers/activate :transform) - (history.handlers/finalize "Draw line"))) + (history.handlers/finalize "Draw line") + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index 73718a10..a53d085c 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -43,8 +43,9 @@ (defmethod tool.hierarchy/on-pointer-up :circle [db _e] (if (= (:state db) :create) - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create circle")) + (-> db + (history.handlers/finalize "Create circle") + (tool.handlers/activate :transform)) (create db))) (defmethod tool.hierarchy/on-pointer-move :circle @@ -64,8 +65,8 @@ (defmethod tool.hierarchy/on-drag-end :circle [db _e] (-> db - (tool.handlers/activate :transform) - (history.handlers/finalize "Create circle"))) + (history.handlers/finalize "Create circle") + (tool.handlers/activate :transform))) (defmethod tool.hierarchy/snapping-points :circle [db] diff --git a/src/renderer/tool/impl/element/core.cljs b/src/renderer/tool/impl/element/core.cljs index a6ff9e08..59a24266 100644 --- a/src/renderer/tool/impl/element/core.cljs +++ b/src/renderer/tool/impl/element/core.cljs @@ -33,8 +33,8 @@ [db _e] (-> db (tool.handlers/create-temp-element) - (tool.handlers/activate :transform) - (history.handlers/finalize (str "Create " (name (:tag (tool.handlers/temp db))))))) + (history.handlers/finalize (str "Create " (name (:tag (tool.handlers/temp db))))) + (tool.handlers/activate :transform))) (defmethod tool.hierarchy/snapping-points ::tool.hierarchy/element [db] diff --git a/src/renderer/tool/impl/element/ellipse.cljs b/src/renderer/tool/impl/element/ellipse.cljs index c87e3eaa..9b45ce01 100644 --- a/src/renderer/tool/impl/element/ellipse.cljs +++ b/src/renderer/tool/impl/element/ellipse.cljs @@ -28,7 +28,8 @@ ry (cond-> ry lock-ratio (min rx)) fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] - (-> (tool.handlers/set-state db :create) + (-> db + (tool.handlers/set-state :create) (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :ellipse @@ -56,8 +57,9 @@ (defmethod tool.hierarchy/on-pointer-up :ellipse [db e] (if (= (:state db) :create) - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create ellipse")) + (-> db + (history.handlers/finalize "Create ellipse") + (tool.handlers/activate :transform)) (create db (:ctrl-key e)))) (defmethod tool.hierarchy/on-pointer-move :ellipse @@ -77,5 +79,5 @@ (defmethod tool.hierarchy/on-drag-end :ellipse [db _e] (-> db - (tool.handlers/activate :transform) - (history.handlers/finalize "Create ellipse"))) + (history.handlers/finalize "Create ellipse") + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/element/line.cljs b/src/renderer/tool/impl/element/line.cljs index 7fdf9245..95f4fcff 100644 --- a/src/renderer/tool/impl/element/line.cljs +++ b/src/renderer/tool/impl/element/line.cljs @@ -4,6 +4,7 @@ [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] [renderer.history.handlers :as history.handlers] + [renderer.reepl.db :as db] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -19,7 +20,8 @@ (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) stroke (document.handlers/attr db :stroke)] - (-> (tool.handlers/set-state db :create) + (-> db + (tool.handlers/set-state :create) (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :line @@ -46,8 +48,9 @@ (defmethod tool.hierarchy/on-pointer-up :line [db _e] (if (= (:state db) :create) - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create line")) + (-> db + (history.handlers/finalize "Create line") + (tool.handlers/activate :transform)) (create db))) (defmethod tool.hierarchy/on-drag-start :line @@ -60,5 +63,6 @@ (defmethod tool.hierarchy/on-drag-end :line [db _e] - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create line"))) + (-> db + (history.handlers/finalize "Create line") + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/element/polyshape.cljs b/src/renderer/tool/impl/element/polyshape.cljs index 8d6b8cb7..a24fd45e 100644 --- a/src/renderer/tool/impl/element/polyshape.cljs +++ b/src/renderer/tool/impl/element/polyshape.cljs @@ -72,5 +72,5 @@ [db _e] (-> (drop-last-point db) (tool.handlers/create-temp-element) - (tool.handlers/activate :transform) - (history.handlers/finalize (str "Create " (name (:tool db)))))) + (history.handlers/finalize (str "Create " (name (:tool db)))) + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index 367532f7..3e99a590 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -59,8 +59,9 @@ (defmethod tool.hierarchy/on-pointer-up :rect [db e] (if (= (:state db) :create) - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create rectangle")) + (-> db + (history.handlers/finalize "Create rectangle") + (tool.handlers/activate :transform)) (create db (:ctrl-key e)))) (defmethod tool.hierarchy/on-pointer-move :rect @@ -80,5 +81,5 @@ (defmethod tool.hierarchy/on-drag-end :rect [db _e] (-> db - (tool.handlers/activate :transform) - (history.handlers/finalize "Create rectangle"))) + (history.handlers/finalize "Create rectangle") + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/element/svg.cljs b/src/renderer/tool/impl/element/svg.cljs index 8c402adf..b2a6dba5 100644 --- a/src/renderer/tool/impl/element/svg.cljs +++ b/src/renderer/tool/impl/element/svg.cljs @@ -53,8 +53,9 @@ (defmethod tool.hierarchy/on-pointer-up :svg [db e] (if (= (:state db) :create) - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create SVG")) + (-> db + (history.handlers/finalize "Create SVG") + (tool.handlers/activate :transform)) (create db (:ctrl-key e)))) (defmethod tool.hierarchy/on-pointer-move :svg @@ -74,5 +75,5 @@ (defmethod tool.hierarchy/on-drag-end :svg [db _e] (-> db - (tool.handlers/activate :transform) - (history.handlers/finalize "Create SVG"))) + (history.handlers/finalize "Create SVG") + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/extension/blob.cljs b/src/renderer/tool/impl/extension/blob.cljs index 7642681e..b0ac409b 100644 --- a/src/renderer/tool/impl/extension/blob.cljs +++ b/src/renderer/tool/impl/extension/blob.cljs @@ -52,8 +52,9 @@ (defmethod tool.hierarchy/on-pointer-up :blob [db _e] (if (= (:state db) :create) - (-> (tool.handlers/activate db :transform) - (history.handlers/finalize "Create blob")) + (-> db + (history.handlers/finalize "Create blob") + (tool.handlers/activate :transform)) (create db))) (defmethod tool.hierarchy/on-pointer-move :blob @@ -73,5 +74,5 @@ (defmethod tool.hierarchy/on-drag-end :blob [db _e] (-> db - (tool.handlers/activate :transform) - (history.handlers/finalize "Create blob"))) + (history.handlers/finalize "Create blob") + (tool.handlers/activate :transform))) diff --git a/src/renderer/tool/impl/misc/dropper.cljs b/src/renderer/tool/impl/misc/dropper.cljs index 9a7a79a2..41855ffc 100644 --- a/src/renderer/tool/impl/misc/dropper.cljs +++ b/src/renderer/tool/impl/misc/dropper.cljs @@ -25,7 +25,8 @@ (if (.-EyeDropper js/window) (tool.handlers/add-fx db [::effects/eye-dropper {:on-success [::success] :on-error [::error]}]) - (-> (tool.handlers/activate db :transform) + (-> db + (tool.handlers/activate :transform) (notification.handlers/add (notification.views/unavailable-feature "EyeDropper" @@ -35,13 +36,15 @@ ::success (fn [db [_ ^js color]] (let [srgb-color (.-sRGBHex color)] - (-> (document.handlers/assoc-attr db :fill srgb-color) + (-> db + (document.handlers/assoc-attr :fill srgb-color) (element.handlers/assoc-attr :fill srgb-color) - (tool.handlers/activate :transform) - (history.handlers/finalize "Pick color"))))) + (history.handlers/finalize "Pick color") + (tool.handlers/activate :transform))))) (rf/reg-event-db ::error (fn [db [_ error]] - (-> (tool.handlers/activate db :transform) + (-> db + (tool.handlers/activate :transform) (notification.handlers/add (notification.views/exception error))))) From 63fd55dacd437ef479a58382c82077c933b6f086 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 09:16:01 +0300 Subject: [PATCH 09/31] fix reset state --- src/renderer/tool/handlers.cljs | 1 - src/renderer/tool/impl/draw/core.cljs | 5 ++++- src/renderer/tool/impl/element/core.cljs | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/renderer/tool/handlers.cljs b/src/renderer/tool/handlers.cljs index e9f90eb5..78883ebe 100644 --- a/src/renderer/tool/handlers.cljs +++ b/src/renderer/tool/handlers.cljs @@ -38,7 +38,6 @@ (set-state :idle) (set-cursor "default") (dissoc :drag :pointer-offset :clicked-element) - (history.handlers/reset-state) (snap.handlers/rebuild-tree) (tool.hierarchy/on-activate))) diff --git a/src/renderer/tool/impl/draw/core.cljs b/src/renderer/tool/impl/draw/core.cljs index 5bfc8f9f..e271daf1 100644 --- a/src/renderer/tool/impl/draw/core.cljs +++ b/src/renderer/tool/impl/draw/core.cljs @@ -1,5 +1,6 @@ (ns renderer.tool.impl.draw.core (:require + [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] [renderer.tool.impl.draw.brush] @@ -13,4 +14,6 @@ (defmethod tool.hierarchy/on-activate ::tool.hierarchy/draw [db] - (tool.handlers/set-cursor db "crosshair")) + (-> db + (history.handlers/reset-state) + (tool.handlers/set-cursor "crosshair"))) diff --git a/src/renderer/tool/impl/element/core.cljs b/src/renderer/tool/impl/element/core.cljs index 59a24266..ed279bae 100644 --- a/src/renderer/tool/impl/element/core.cljs +++ b/src/renderer/tool/impl/element/core.cljs @@ -23,7 +23,9 @@ (defmethod tool.hierarchy/on-activate ::tool.hierarchy/element [db] - (tool.handlers/set-cursor db "crosshair")) + (-> db + (history.handlers/reset-state) + (tool.handlers/set-cursor "crosshair"))) (defmethod tool.hierarchy/on-drag-start ::tool.hierarchy/element [db _e] From d63aee26abaaaf0fc7d33b902d6c5ca17062617b Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 09:44:44 +0300 Subject: [PATCH 10/31] precision fixes --- src/renderer/app/views.cljs | 2 +- src/renderer/element/impl/custom/measure.cljs | 4 ++-- src/renderer/element/impl/shape/circle.cljs | 2 +- src/renderer/element/impl/shape/ellipse.cljs | 4 ++-- src/renderer/element/impl/shape/line.cljs | 2 +- src/renderer/element/impl/shape/polyshape.cljs | 2 +- src/renderer/tool/impl/base/transform.cljs | 4 ++-- src/renderer/tool/impl/element/circle.cljs | 2 +- src/renderer/tool/impl/element/core.cljs | 11 ----------- src/renderer/tool/impl/element/ellipse.cljs | 7 ++++--- src/renderer/tool/impl/element/line.cljs | 5 +++-- src/renderer/tool/impl/element/rect.cljs | 13 ++++++++----- src/renderer/toolbar/status.cljs | 6 +++--- src/renderer/utils/length.cljs | 2 +- 14 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/renderer/app/views.cljs b/src/renderer/app/views.cljs index 989e008c..77d0fc9f 100644 --- a/src/renderer/app/views.cljs +++ b/src/renderer/app/views.cljs @@ -44,7 +44,7 @@ (interpose ", " (map (fn [[k v]] ^{:key k} [:span (str (name k) ": " (if (number? v) - (.toFixed v 2) + (.toFixed v 3) (coll->str v)))]) m))) (defn debug-rows diff --git a/src/renderer/element/impl/custom/measure.cljs b/src/renderer/element/impl/custom/measure.cljs index aa701988..a5e9501c 100644 --- a/src/renderer/element/impl/custom/measure.cljs +++ b/src/renderer/element/impl/custom/measure.cljs @@ -28,10 +28,10 @@ [utils.svg/line [x1 y1] [(+ x1 (/ 30 zoom)) y1]] [utils.svg/label - (str (.toFixed straight-angle 2) "°") + (str (.toFixed straight-angle 3) "°") [(+ x1 (/ 40 zoom)) y1] "start"] [utils.svg/label - (-> hypotenuse js/parseFloat (.toFixed 2) str) + (-> hypotenuse js/parseFloat (.toFixed 3) str) [(/ (+ x1 x2) 2) (/ (+ y1 y2) 2)]]])) diff --git a/src/renderer/element/impl/shape/circle.cljs b/src/renderer/element/impl/shape/circle.cljs index c2958bd5..46917336 100644 --- a/src/renderer/element/impl/shape/circle.cljs +++ b/src/renderer/element/impl/shape/circle.cljs @@ -77,7 +77,7 @@ r (/ (first (utils.bounds/->dimensions bbox)) 2)] [:g [utils.svg/line [cx cy] [(+ cx r) cy]] - [utils.svg/label (str (.toFixed r 2)) [(+ cx (/ r 2)) cy]] + [utils.svg/label (str (.toFixed r 3)) [(+ cx (/ r 2)) cy]] [utils.svg/times [cx cy]] [tool.views/square-handle {:x (+ cx r) :y cy diff --git a/src/renderer/element/impl/shape/ellipse.cljs b/src/renderer/element/impl/shape/ellipse.cljs index 1b3586f4..9c272b30 100644 --- a/src/renderer/element/impl/shape/ellipse.cljs +++ b/src/renderer/element/impl/shape/ellipse.cljs @@ -84,9 +84,9 @@ [:g ::edit-handles [utils.svg/times [cx cy]] [utils.svg/line [cx cy] [(+ cx rx) cy]] - [utils.svg/label (str (.toFixed rx 2)) [(+ cx (/ rx 2)) cy]] + [utils.svg/label (str (.toFixed rx 3)) [(+ cx (/ rx 2)) cy]] [utils.svg/line [cx cy] [cx (- cy ry)]] - [utils.svg/label (str (.toFixed ry 2)) [cx (- cy (/ ry 2))]] + [utils.svg/label (str (.toFixed ry 3)) [cx (- cy (/ ry 2))]] (map (fn [handle] ^{:key (:id handle)} [tool.views/square-handle diff --git a/src/renderer/element/impl/shape/line.cljs b/src/renderer/element/impl/shape/line.cljs index f2686b26..64c73026 100644 --- a/src/renderer/element/impl/shape/line.cljs +++ b/src/renderer/element/impl/shape/line.cljs @@ -72,7 +72,7 @@ [:title {:key (str id "-title")} (name id)]] (when is-active [utils.svg/label - (string/join " " [(.toFixed x 2) (.toFixed y 2)]) + (string/join " " [(.toFixed x 3) (.toFixed y 3)]) [(- x margin) (+ y margin)] "end"])])) [{:x x1 diff --git a/src/renderer/element/impl/shape/polyshape.cljs b/src/renderer/element/impl/shape/polyshape.cljs index f2816169..3d34a8ae 100644 --- a/src/renderer/element/impl/shape/polyshape.cljs +++ b/src/renderer/element/impl/shape/polyshape.cljs @@ -82,7 +82,7 @@ :element (:id el)}] (when is-active [utils.svg/label - (string/join " " [(.toFixed x 2) (.toFixed y 2)]) + (string/join " " [(.toFixed x 3) (.toFixed y 3)]) [(- x margin) (+ y margin)] "end"])])) (utils.attribute/points->vec (-> el :attrs :points)))])) diff --git a/src/renderer/tool/impl/base/transform.cljs b/src/renderer/tool/impl/base/transform.cljs index 8885fdf3..6e26d2fd 100644 --- a/src/renderer/tool/impl/base/transform.cljs +++ b/src/renderer/tool/impl/base/transform.cljs @@ -403,7 +403,7 @@ x (+ min-x (/ (- max-x min-x) 2)) y (+ y2 (/ (+ (/ theme.db/handle-size 2) 15) zoom)) [w h] (utils.bounds/->dimensions bbox) - text (str (.toFixed w 2) " x " (.toFixed h 2))] + text (str (.toFixed w 3) " x " (.toFixed h 3))] [utils.svg/label text [x y]])) (m/=> area-label [:-> number? BBox any?]) @@ -414,7 +414,7 @@ [min-x min-y max-x] bbox x (+ min-x (/ (- max-x min-x) 2)) y (+ min-y (/ (- -15 (/ theme.db/handle-size 2)) zoom)) - text (str (.toFixed area 2) " px²")] + text (str (.toFixed area 3) " px²")] [utils.svg/label text [x y]]))) (defmethod tool.hierarchy/render :transform diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index a53d085c..2b8171ca 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -36,7 +36,7 @@ [db] (let [offset (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - radius (matrix/distance position offset) + radius (.toFixed (matrix/distance position offset) 3) id (:id (first (element.handlers/selected db)))] (element.handlers/update-el db id #(assoc-in % [:attrs :r] (str radius))))) diff --git a/src/renderer/tool/impl/element/core.cljs b/src/renderer/tool/impl/element/core.cljs index ed279bae..3e666550 100644 --- a/src/renderer/tool/impl/element/core.cljs +++ b/src/renderer/tool/impl/element/core.cljs @@ -27,17 +27,6 @@ (history.handlers/reset-state) (tool.handlers/set-cursor "crosshair"))) -(defmethod tool.hierarchy/on-drag-start ::tool.hierarchy/element - [db _e] - (tool.handlers/set-state db :create)) - -(defmethod tool.hierarchy/on-drag-end ::tool.hierarchy/element - [db _e] - (-> db - (tool.handlers/create-temp-element) - (history.handlers/finalize (str "Create " (name (:tag (tool.handlers/temp db))))) - (tool.handlers/activate :transform))) - (defmethod tool.hierarchy/snapping-points ::tool.hierarchy/element [db] [(with-meta diff --git a/src/renderer/tool/impl/element/ellipse.cljs b/src/renderer/tool/impl/element/ellipse.cljs index 9b45ce01..f7df94e6 100644 --- a/src/renderer/tool/impl/element/ellipse.cljs +++ b/src/renderer/tool/impl/element/ellipse.cljs @@ -11,7 +11,8 @@ (defmethod tool.hierarchy/properties :ellipse [] - {:icon "ellipse-tool"}) + {:icon "ellipse-tool" + :label "Ellipse"}) (defmethod tool.hierarchy/help [:ellipse :create] [] @@ -45,8 +46,8 @@ (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - rx (abs (- x offset-x)) - ry (abs (- y offset-y)) + rx (.toFixed (abs (- x offset-x)) 3) + ry (.toFixed (abs (- y offset-y)) 3) rx (cond-> rx lock-ratio (min ry)) ry (cond-> ry lock-ratio (min rx)) id (:id (first (element.handlers/selected db)))] diff --git a/src/renderer/tool/impl/element/line.cljs b/src/renderer/tool/impl/element/line.cljs index 95f4fcff..57e1ca26 100644 --- a/src/renderer/tool/impl/element/line.cljs +++ b/src/renderer/tool/impl/element/line.cljs @@ -4,7 +4,6 @@ [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] [renderer.history.handlers :as history.handlers] - [renderer.reepl.db :as db] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -34,7 +33,9 @@ (defn update-end [db] (let [[x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - id (:id (first (element.handlers/selected db)))] + id (:id (first (element.handlers/selected db))) + x (.toFixed x 3) + y (.toFixed y 3)] (element.handlers/update-el db id #(-> % (assoc-in [:attrs :x2] (str x)) (assoc-in [:attrs :y2] (str y)))))) diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index 3e99a590..8d15ea05 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -29,7 +29,8 @@ height (cond-> height lock-ratio (min width)) fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] - (-> (tool.handlers/set-state db :create) + (-> db + (tool.handlers/set-state :create) (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :rect @@ -45,14 +46,16 @@ (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - width (abs (- x offset-x)) - height (abs (- y offset-y)) + width (.toFixed (abs (- x offset-x)) 3) + height (.toFixed (abs (- y offset-y)) 3) width (cond-> width lock-ratio (min height)) height (cond-> height lock-ratio (min width)) + x (.toFixed (min x offset-x) 3) + y (.toFixed (min y offset-y) 3) id (:id (first (element.handlers/selected db)))] (element.handlers/update-el db id #(-> % - (assoc-in [:attrs :x] (str (min x offset-x))) - (assoc-in [:attrs :y] (str (min y offset-y))) + (assoc-in [:attrs :x] (str x)) + (assoc-in [:attrs :y] (str y)) (assoc-in [:attrs :width] (str width)) (assoc-in [:attrs :height] (str height)))))) diff --git a/src/renderer/toolbar/status.cljs b/src/renderer/toolbar/status.cljs index f5bcc526..fda97a00 100644 --- a/src/renderer/toolbar/status.cljs +++ b/src/renderer/toolbar/status.cljs @@ -21,11 +21,11 @@ (let [[x y] @(rf/subscribe [::app.subs/adjusted-pointer-pos])] [:div.flex-col.font-mono.leading-tight.hidden {:class "xl:flex" - :style {:min-width "90px"}} + :style {:min-width "100px"}} [:div.flex.justify-between - [:span.mr-1 "X:"] [:span (.toFixed x 2)]] + [:span.mr-1 "X:"] [:span (.toFixed x 3)]] [:div.flex.justify-between - [:span.mr-1 "Y:"] [:span (.toFixed y 2)]]])) + [:span.mr-1 "Y:"] [:span (.toFixed y 3)]]])) (def zoom-options [{:label "Set to 50%" diff --git a/src/renderer/utils/length.cljs b/src/renderer/utils/length.cljs index e425501c..6b81297b 100644 --- a/src/renderer/utils/length.cljs +++ b/src/renderer/utils/length.cljs @@ -60,7 +60,7 @@ ([v f & more] (let [[n unit] (utils.unit/parse v)] (-> (apply f (->px n unit) more) - (.toFixed 2) + (.toFixed 3) (js/parseFloat) (->unit unit) (str (when (valid-unit? unit) unit)))))) From e706181d37337cf490f588a7d1b354d9f797b42c Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 09:44:54 +0300 Subject: [PATCH 11/31] enhance pen tool --- src/renderer/tool/impl/draw/pen.cljs | 40 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/renderer/tool/impl/draw/pen.cljs b/src/renderer/tool/impl/draw/pen.cljs index 5971f53d..a32ebf33 100644 --- a/src/renderer/tool/impl/draw/pen.cljs +++ b/src/renderer/tool/impl/draw/pen.cljs @@ -2,6 +2,7 @@ (:require [clojure.string :as string] [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] @@ -14,26 +15,37 @@ [] {:icon "pencil"}) +(defmethod tool.hierarchy/on-drag-start :pen + [db _e] + (let [stroke (document.handlers/attr db :stroke) + point-1 (string/join " " (:adjusted-pointer-offset db)) + point-2 (string/join " " (:adjusted-pointer-pos db))] + (-> db + (tool.handlers/set-state :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :polyline + :attrs {:points (str point-1 " " point-2) + :stroke stroke + :fill "transparent"}})))) + (defmethod tool.hierarchy/on-drag :pen [db _e] - (let [{:keys [active-document adjusted-pointer-pos]} db - points-path [:documents active-document :temp-element :attrs :points]] - (if (get-in db points-path) - (update-in db points-path #(str % " " (string/join " " adjusted-pointer-pos))) - (tool.handlers/set-temp db {:type :element - :tag :polyline - :attrs {:points (string/join " " adjusted-pointer-pos) - :stroke (document.handlers/attr db :stroke) - :fill "transparent"}})))) + (let [{:keys [adjusted-pointer-pos]} db + point (string/join " " adjusted-pointer-pos) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id (fn [el] + (update-in el + [:attrs :points] + #(str % " " point)))))) (defmethod tool.hierarchy/on-drag-end :pen [db _e] - (let [path (-> (tool.handlers/temp db) + (let [path (-> (first (element.handlers/selected db)) (utils.element/->path) (update-in [:attrs :d] utils.path/manipulate :smooth) (update-in [:attrs :d] utils.path/manipulate :simplify))] (-> db - (tool.handlers/set-temp path) - (tool.handlers/create-temp-element) - (tool.handlers/activate :transform) - (history.handlers/finalize "Draw line")))) + (element.handlers/swap path) + (history.handlers/finalize "Draw line") + (tool.handlers/activate :transform)))) From 7bbfa5a328191d9ec1026174c7d0a4d64d347e61 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 09:58:16 +0300 Subject: [PATCH 12/31] enhance measure tool --- src/renderer/element/impl/custom/core.cljs | 3 +- src/renderer/element/impl/custom/measure.cljs | 37 ------------ src/renderer/tool/impl/misc/measure.cljs | 60 +++++++++++++++---- 3 files changed, 50 insertions(+), 50 deletions(-) delete mode 100644 src/renderer/element/impl/custom/measure.cljs diff --git a/src/renderer/element/impl/custom/core.cljs b/src/renderer/element/impl/custom/core.cljs index 1259b9e7..11a55450 100644 --- a/src/renderer/element/impl/custom/core.cljs +++ b/src/renderer/element/impl/custom/core.cljs @@ -1,5 +1,4 @@ (ns renderer.element.impl.custom.core (:require [renderer.element.impl.custom.blob] - [renderer.element.impl.custom.brush] - [renderer.element.impl.custom.measure])) + [renderer.element.impl.custom.brush])) diff --git a/src/renderer/element/impl/custom/measure.cljs b/src/renderer/element/impl/custom/measure.cljs deleted file mode 100644 index a5e9501c..00000000 --- a/src/renderer/element/impl/custom/measure.cljs +++ /dev/null @@ -1,37 +0,0 @@ -(ns renderer.element.impl.custom.measure - (:require - [re-frame.core :as rf] - [renderer.document.subs :as-alias document.subs] - [renderer.element.hierarchy :as element.hierarchy] - [renderer.utils.length :as utils.length] - [renderer.utils.math :as utils.math] - [renderer.utils.svg :as utils.svg])) - -(derive :measure ::element.hierarchy/element) - -(defmethod element.hierarchy/render :measure - [el] - (let [{:keys [attrs id]} el - {:keys [x1 x2 y1 y2 hypotenuse]} attrs - [x1 y1 x2 y2] (map utils.length/unit->px [x1 y1 x2 y2]) - angle (utils.math/angle [x1 y1] [x2 y2]) - zoom @(rf/subscribe [::document.subs/zoom]) - straight? (< angle 180) - straight-angle (if straight? angle (- angle 360))] - [:g {:key id} - [utils.svg/cross [x1 y1]] - [utils.svg/cross [x2 y2]] - - [utils.svg/arc [x1 y1] 20 (if straight? 0 angle) (abs straight-angle)] - - [utils.svg/line [x1 y1] [x2 y2] false] - [utils.svg/line [x1 y1] [(+ x1 (/ 30 zoom)) y1]] - - [utils.svg/label - (str (.toFixed straight-angle 3) "°") - [(+ x1 (/ 40 zoom)) y1] - "start"] - - [utils.svg/label - (-> hypotenuse js/parseFloat (.toFixed 3) str) - [(/ (+ x1 x2) 2) (/ (+ y1 y2) 2)]]])) diff --git a/src/renderer/tool/impl/misc/measure.cljs b/src/renderer/tool/impl/misc/measure.cljs index 2821b6f6..e8eeec9c 100644 --- a/src/renderer/tool/impl/misc/measure.cljs +++ b/src/renderer/tool/impl/misc/measure.cljs @@ -1,12 +1,20 @@ (ns renderer.tool.impl.misc.measure (:require [clojure.core.matrix :as matrix] + [re-frame.core :as rf] + [reagent.core :as reagent] + [renderer.document.subs :as-alias document.subs] [renderer.element.handlers :as element.handlers] [renderer.tool.handlers :as tool.handlers] - [renderer.tool.hierarchy :as tool.hierarchy])) + [renderer.tool.hierarchy :as tool.hierarchy] + [renderer.utils.length :as utils.length] + [renderer.utils.math :as utils.math] + [renderer.utils.svg :as utils.svg])) (derive :measure ::tool.hierarchy/tool) +(defonce element (reagent/atom nil)) + (defmethod tool.hierarchy/properties :measure [] {:icon "ruler-triangle"}) @@ -21,7 +29,8 @@ (defmethod tool.hierarchy/on-deactivate :measure [db] - (tool.handlers/dissoc-temp db)) + (reset! element nil) + db) (defmethod tool.hierarchy/on-drag :measure [db _e] @@ -29,20 +38,49 @@ [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) [adjacent opposite] (matrix/sub [offset-x offset-y] [x y]) hypotenuse (Math/hypot adjacent opposite)] - (tool.handlers/set-temp db {:type :element - :tag :measure - :attrs {:x1 offset-x - :y1 offset-y - :x2 x - :y2 y - :hypotenuse hypotenuse - :stroke "gray"}}))) + (reset! element {:type :element + :tag :measure + :attrs {:x1 offset-x + :y1 offset-y + :x2 x + :y2 y + :hypotenuse hypotenuse + :stroke "gray"}}) + db)) + +(defmethod tool.hierarchy/render :measure + [] + (when @element + (let [{:keys [attrs id]} @element + {:keys [x1 x2 y1 y2 hypotenuse]} attrs + [x1 y1 x2 y2] (map utils.length/unit->px [x1 y1 x2 y2]) + angle (utils.math/angle [x1 y1] [x2 y2]) + zoom @(rf/subscribe [::document.subs/zoom]) + straight? (< angle 180) + straight-angle (if straight? angle (- angle 360))] + [:g {:key id} + [utils.svg/cross [x1 y1]] + [utils.svg/cross [x2 y2]] + + [utils.svg/arc [x1 y1] 20 (if straight? 0 angle) (abs straight-angle)] + + [utils.svg/line [x1 y1] [x2 y2] false] + [utils.svg/line [x1 y1] [(+ x1 (/ 30 zoom)) y1]] + + [utils.svg/label + (str (.toFixed straight-angle 3) "°") + [(+ x1 (/ 40 zoom)) y1] + "start"] + + [utils.svg/label + (-> hypotenuse js/parseFloat (.toFixed 3) str) + [(/ (+ x1 x2) 2) (/ (+ y1 y2) 2)]]]))) (defmethod tool.hierarchy/snapping-points :measure [db] [(with-meta (:adjusted-pointer-pos db) - {:label (str "measure " (if (tool.handlers/temp db) "end" "start"))})]) + {:label (str "measure " (if @element "end" "start"))})]) (defmethod tool.hierarchy/snapping-elements :measure [db] From 28b301a0060b443f1b477b63a5b81f60f3d9af41 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 09:58:33 +0300 Subject: [PATCH 13/31] fix circle snap meta --- src/renderer/tool/impl/element/circle.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index 2b8171ca..f1f3ee5c 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -72,4 +72,4 @@ [db] [(with-meta (:adjusted-pointer-pos db) - {:label (str "Circle " (if (tool.handlers/temp db) "radius" "center"))})]) + {:label (str "Circle " (if (= (:state db) :create) "radius" "center"))})]) From 6a6de4391c94e02a568207a826c772a8b3126469 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 10:13:13 +0300 Subject: [PATCH 14/31] enhance zoom tool --- src/renderer/tool/impl/base/zoom.cljs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/renderer/tool/impl/base/zoom.cljs b/src/renderer/tool/impl/base/zoom.cljs index f2393a73..976d3fbc 100644 --- a/src/renderer/tool/impl/base/zoom.cljs +++ b/src/renderer/tool/impl/base/zoom.cljs @@ -1,6 +1,8 @@ (ns renderer.tool.impl.base.zoom (:require + [reagent.core :as reagent] [renderer.app.effects :as-alias app.effects] + [renderer.element.hierarchy :as element.hierarchy] [renderer.frame.handlers :as frame.handlers] [renderer.snap.handlers :as snap.handlers] [renderer.tool.handlers :as tool.handlers] @@ -9,6 +11,8 @@ (derive :zoom ::tool.hierarchy/tool) +(defonce element (reagent/atom nil)) + (defmethod tool.hierarchy/properties :zoom [] {:icon "magnifier"}) @@ -23,6 +27,11 @@ [db] (tool.handlers/set-cursor db "zoom-in")) +(defmethod tool.hierarchy/on-deactivate :zoom + [db] + (reset! element nil) + db) + (defmethod tool.hierarchy/on-key-down :zoom [db e] (cond-> db @@ -37,7 +46,8 @@ (defmethod tool.hierarchy/on-drag :zoom [db _e] - (tool.handlers/set-temp db (utils.svg/select-box db))) + (reset! element (utils.svg/select-box db)) + db) (defmethod tool.hierarchy/on-drag-end :zoom [db e] @@ -52,7 +62,8 @@ zoom (min width-ratio height-ratio) factor (if (:shift-key e) (:zoom-sensitivity db) (/ zoom current-zoom)) cursor (if (:shift-key e) "zoom-out" "zoom-in")] - (-> (tool.handlers/dissoc-temp db) + (reset! element nil) + (-> db (tool.handlers/set-cursor cursor) (frame.handlers/zoom-in-place factor) (frame.handlers/pan-to-bbox [x y offset-x offset-y]) @@ -65,3 +76,7 @@ (-> (frame.handlers/zoom-at-pointer db factor) (snap.handlers/update-viewport-tree) (tool.handlers/add-fx [::app.effects/persist])))) + +(defmethod tool.hierarchy/render :zoom + [] + [element.hierarchy/render @element]) From f9d6c60ab096e62608afdcb5d33efc899506a4c1 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 10:52:04 +0300 Subject: [PATCH 15/31] remove side effects from events --- src/renderer/tool/impl/base/zoom.cljs | 14 ++++++---- src/renderer/tool/impl/misc/measure.cljs | 34 ++++++++++++------------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/renderer/tool/impl/base/zoom.cljs b/src/renderer/tool/impl/base/zoom.cljs index 976d3fbc..265fca0a 100644 --- a/src/renderer/tool/impl/base/zoom.cljs +++ b/src/renderer/tool/impl/base/zoom.cljs @@ -1,5 +1,6 @@ (ns renderer.tool.impl.base.zoom (:require + [re-frame.core :as rf] [reagent.core :as reagent] [renderer.app.effects :as-alias app.effects] [renderer.element.hierarchy :as element.hierarchy] @@ -13,6 +14,11 @@ (defonce element (reagent/atom nil)) +(rf/reg-fx + ::update + (fn [value] + (reset! element value))) + (defmethod tool.hierarchy/properties :zoom [] {:icon "magnifier"}) @@ -29,8 +35,7 @@ (defmethod tool.hierarchy/on-deactivate :zoom [db] - (reset! element nil) - db) + (tool.handlers/add-fx db [::update nil])) (defmethod tool.hierarchy/on-key-down :zoom [db e] @@ -46,8 +51,7 @@ (defmethod tool.hierarchy/on-drag :zoom [db _e] - (reset! element (utils.svg/select-box db)) - db) + (tool.handlers/add-fx db [::update (utils.svg/select-box db)])) (defmethod tool.hierarchy/on-drag-end :zoom [db e] @@ -62,8 +66,8 @@ zoom (min width-ratio height-ratio) factor (if (:shift-key e) (:zoom-sensitivity db) (/ zoom current-zoom)) cursor (if (:shift-key e) "zoom-out" "zoom-in")] - (reset! element nil) (-> db + (tool.handlers/add-fx [::update nil]) (tool.handlers/set-cursor cursor) (frame.handlers/zoom-in-place factor) (frame.handlers/pan-to-bbox [x y offset-x offset-y]) diff --git a/src/renderer/tool/impl/misc/measure.cljs b/src/renderer/tool/impl/misc/measure.cljs index e8eeec9c..33b48684 100644 --- a/src/renderer/tool/impl/misc/measure.cljs +++ b/src/renderer/tool/impl/misc/measure.cljs @@ -13,7 +13,12 @@ (derive :measure ::tool.hierarchy/tool) -(defonce element (reagent/atom nil)) +(defonce attrs (reagent/atom nil)) + +(rf/reg-fx + ::update + (fn [value] + (reset! attrs value))) (defmethod tool.hierarchy/properties :measure [] @@ -29,8 +34,7 @@ (defmethod tool.hierarchy/on-deactivate :measure [db] - (reset! element nil) - db) + (tool.handlers/add-fx db [::update nil])) (defmethod tool.hierarchy/on-drag :measure [db _e] @@ -38,27 +42,23 @@ [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) [adjacent opposite] (matrix/sub [offset-x offset-y] [x y]) hypotenuse (Math/hypot adjacent opposite)] - (reset! element {:type :element - :tag :measure - :attrs {:x1 offset-x - :y1 offset-y - :x2 x - :y2 y - :hypotenuse hypotenuse - :stroke "gray"}}) - db)) + (tool.handlers/add-fx db [::update {:x1 offset-x + :y1 offset-y + :x2 x + :y2 y + :hypotenuse hypotenuse + :stroke "gray"}]))) (defmethod tool.hierarchy/render :measure [] - (when @element - (let [{:keys [attrs id]} @element - {:keys [x1 x2 y1 y2 hypotenuse]} attrs + (when @attrs + (let [{:keys [x1 x2 y1 y2 hypotenuse]} @attrs [x1 y1 x2 y2] (map utils.length/unit->px [x1 y1 x2 y2]) angle (utils.math/angle [x1 y1] [x2 y2]) zoom @(rf/subscribe [::document.subs/zoom]) straight? (< angle 180) straight-angle (if straight? angle (- angle 360))] - [:g {:key id} + [:g [utils.svg/cross [x1 y1]] [utils.svg/cross [x2 y2]] @@ -80,7 +80,7 @@ [db] [(with-meta (:adjusted-pointer-pos db) - {:label (str "measure " (if @element "end" "start"))})]) + {:label (str "measure " (if @attrs "end" "start"))})]) (defmethod tool.hierarchy/snapping-elements :measure [db] From 21943d98a1ce176521c3e0e3d6a15dd1092ec5ec Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 11:01:18 +0300 Subject: [PATCH 16/31] enhance transform tool --- src/renderer/tool/impl/base/transform.cljs | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/renderer/tool/impl/base/transform.cljs b/src/renderer/tool/impl/base/transform.cljs index 6e26d2fd..35ca57a4 100644 --- a/src/renderer/tool/impl/base/transform.cljs +++ b/src/renderer/tool/impl/base/transform.cljs @@ -3,6 +3,7 @@ [clojure.core.matrix :as matrix] [malli.core :as m] [re-frame.core :as rf] + [reagent.core :as reagent] [renderer.app.db :refer [App]] [renderer.document.subs :as-alias document.subs] [renderer.element.db :refer [Element]] @@ -33,6 +34,15 @@ (derive :transform ::tool.hierarchy/tool) +(derive :zoom ::tool.hierarchy/tool) + +(defonce bbox-element (reagent/atom nil)) + +(rf/reg-fx + ::update + (fn [value] + (reset! bbox-element value))) + (defmethod tool.hierarchy/properties :transform [] {:icon "pointer"}) @@ -66,8 +76,8 @@ (m/=> hovered? [:-> App Element boolean? boolean?]) (defn hovered? - [db el intersecting?] - (let [selection-bbox (element.hierarchy/bbox (tool.handlers/temp db))] + [el intersecting?] + (let [selection-bbox (element.hierarchy/bbox @bbox-element)] (if-let [el-bbox (:bbox el)] (if intersecting? (utils.bounds/intersect? el-bbox selection-bbox) @@ -82,7 +92,7 @@ (filter :visible) (reduce (fn [db el] (cond-> db - (hovered? db el intersecting?) + (hovered? el intersecting?) (f (:id el)))) db))) (defmethod tool.hierarchy/on-pointer-move :transform @@ -324,7 +334,7 @@ (case (:state db) :select (-> (element.handlers/clear-hovered db) - (tool.handlers/set-temp (select-rect db (:alt-key e))) + (tool.handlers/add-fx [::update (select-rect db (:alt-key e))]) (reduce-by-area (:alt-key e) element.handlers/hover)) :translate @@ -361,7 +371,7 @@ (-> (case (:state db) :select (-> (cond-> db (not (:shift-key e)) element.handlers/deselect-all) (reduce-by-area (:alt-key e) element.handlers/select) - (tool.handlers/dissoc-temp) + (tool.handlers/add-fx [::update nil]) (history.handlers/finalize "Modify selection")) :translate (history.handlers/finalize db "Move selection") :scale (history.handlers/finalize db "Scale selection") @@ -446,4 +456,6 @@ (when (= state :scale) [size-label bbox])]) (when pivot-point - [utils.svg/times pivot-point])])) + [utils.svg/times pivot-point]) + + [element.hierarchy/render @bbox-element]])) From 2c9354ed88e4f9a0c8d2a1d9663e12c40511c907 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 11:10:48 +0300 Subject: [PATCH 17/31] enhance brush tool --- src/renderer/tool/impl/draw/brush.cljs | 68 +++++++++++++++++--------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/src/renderer/tool/impl/draw/brush.cljs b/src/renderer/tool/impl/draw/brush.cljs index 0cf89bfd..9de34721 100644 --- a/src/renderer/tool/impl/draw/brush.cljs +++ b/src/renderer/tool/impl/draw/brush.cljs @@ -2,7 +2,11 @@ "https://github.com/steveruizok/perfect-freehand" (:require [clojure.string :as string] + [re-frame.core :as rf] + [reagent.core :as reagent] [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] + [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -13,38 +17,58 @@ [] {:icon "brush"}) +(defonce brush-element (reagent/atom nil)) + +(rf/reg-fx + ::update-brush + (fn [value] + (reset! brush-element value))) + (defmethod tool.hierarchy/on-pointer-move :brush [db e] (let [[x y] (:adjusted-pointer-pos db) pressure (:pressure e) pressure (if (zero? pressure) 1 pressure) - r (* (/ 16 2) pressure)] - (tool.handlers/set-temp db {:type :element - :tag :circle - :attrs {:cx x - :cy y - :r r - :fill (document.handlers/attr db :stroke)}}))) + r (* (/ 16 2) pressure) + stroke (document.handlers/attr db :stroke)] + (tool.handlers/add-fx db [::update-brush {:type :element + :tag :circle + :attrs {:cx x + :cy y + :r r + :fill stroke}}]))) + +(defmethod tool.hierarchy/on-drag-start :brush + [db e] + (let [point (string/join " " (conj (:adjusted-pointer-pos db) (:pressure e))) + stroke (document.handlers/attr db :stroke)] + (-> db + (tool.handlers/set-state :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag :brush + :attrs {:points point + :stroke stroke + :size 16 + :thinning 0.5 + :smoothing 0.5 + :streamline 0.5}})))) (defmethod tool.hierarchy/on-drag :brush [db e] - (let [active-document (:active-document db) - point (string/join " " (conj (:adjusted-pointer-pos db) (:pressure e))) - points-path [:documents active-document :temp-element :attrs :points]] - (if (get-in db points-path) - (update-in db points-path #(str % " " point)) - (tool.handlers/set-temp db {:type :element - :tag :brush - :attrs {:points point - :stroke (document.handlers/attr db :stroke) - :size 16 - :thinning 0.5 - :smoothing 0.5 - :streamline 0.5}})))) + (let [point (string/join " " (conj (:adjusted-pointer-pos db) (:pressure e))) + id (:id (first (element.handlers/selected db)))] + (element.handlers/update-el db id (fn [el] + (update-in el + [:attrs :points] + #(str % " " point)))))) (defmethod tool.hierarchy/on-drag-end :brush [db _e] (-> db - (tool.handlers/create-temp-element) - (history.handlers/finalize "Draw line") + (history.handlers/finalize "Draw brush") (tool.handlers/activate :transform))) + +(defmethod tool.hierarchy/render :brush + [] + [element.hierarchy/render @brush-element]) From 1d8401724096b66b0c2724ea523ad91f3e70e72e Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 11:33:56 +0300 Subject: [PATCH 18/31] enhance polyshape tool --- src/renderer/tool/impl/element/polyshape.cljs | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/src/renderer/tool/impl/element/polyshape.cljs b/src/renderer/tool/impl/element/polyshape.cljs index a24fd45e..b22e4572 100644 --- a/src/renderer/tool/impl/element/polyshape.cljs +++ b/src/renderer/tool/impl/element/polyshape.cljs @@ -4,6 +4,7 @@ (:require [clojure.string :as string] [renderer.document.handlers :as document.handlers] + [renderer.element.handlers :as element.handlers] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] @@ -11,10 +12,6 @@ (derive ::tool.hierarchy/polyshape ::tool.hierarchy/element) -(defn points-path - [db] - [:documents (:active-document db) :temp-element :attrs :points]) - (defmethod tool.hierarchy/help [::tool.hierarchy/polyshape :idle] [] [:<> @@ -23,54 +20,62 @@ (defn create-polyline [db points] - (tool.handlers/set-temp db {:type :element - :tag (:tool db) - :attrs {:points (string/join " " points) - :stroke (document.handlers/attr db :stroke) - :fill (document.handlers/attr db :fill)}})) + (let [stroke (document.handlers/attr db :stroke) + fill (document.handlers/attr db :fill)] + (-> db + (tool.handlers/set-state :create) + (element.handlers/deselect-all) + (element.handlers/add {:type :element + :tag (:tool db) + :attrs {:points (string/join " " points) + :stroke stroke + :fill fill}})))) (defn add-point [db point] - (update-in db (points-path db) #(str % " " (string/join " " point)))) + (let [id (:id (first (element.handlers/selected db))) + point (string/join " " point)] + (element.handlers/update-attr db id :points str " " point))) (defn drop-last-point [db] - (let [points (get-in db (points-path db)) - point-vector (utils.attribute/points->vec points)] - (assoc-in db - (points-path db) - (->> point-vector drop-last flatten (string/join " "))))) + (let [id (:id (first (element.handlers/selected db)))] + (element.handlers/update-attr db id :points #(->> % + utils.attribute/points->vec + drop-last + flatten + (string/join " "))))) (defmethod tool.hierarchy/on-pointer-up ::tool.hierarchy/polyshape [db _e] (let [point (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db))] - (if (tool.handlers/temp db) + (if (= (:state db) :create) (add-point db point) - (-> (tool.handlers/set-state db :create) - (create-polyline point))))) + (create-polyline db point)))) (defmethod tool.hierarchy/on-drag-end ::tool.hierarchy/polyshape [db _e] - (if (tool.handlers/temp db) + (if (= (:state db) :create) (add-point db (:adjusted-pointer-pos db)) - (-> (tool.handlers/set-state db :create) - (create-polyline (:adjusted-pointer-pos db))))) + (create-polyline db (:adjusted-pointer-pos db)))) (defmethod tool.hierarchy/on-pointer-move ::tool.hierarchy/polyshape [db _e] - (let [point (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db))] - (if-let [points (get-in db (points-path db))] - (let [point-vector (utils.attribute/points->vec points)] - (assoc-in db - (points-path db) - (string/join " " (concat (apply concat (if (second point-vector) - (drop-last point-vector) - point-vector)) - point)))) db))) + (let [point (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) + id (:id (first (element.handlers/selected db)))] + (if (= (:state db) :create) + (element.handlers/update-attr + db id :points + #(let [point-vector (utils.attribute/points->vec %)] + (string/join " " (concat (apply concat (if (second point-vector) + (drop-last point-vector) + point-vector)) + point)))) + + db))) (defmethod tool.hierarchy/on-double-click ::tool.hierarchy/polyshape [db _e] (-> (drop-last-point db) - (tool.handlers/create-temp-element) (history.handlers/finalize (str "Create " (name (:tool db)))) (tool.handlers/activate :transform))) From 7bea508c61d721385996abbeefc71f42387ff1b5 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 11:34:48 +0300 Subject: [PATCH 19/31] remove temp element leftovers --- src/renderer/document/db.cljs | 1 - src/renderer/document/subs.cljs | 5 ---- .../element/impl/container/canvas.cljs | 3 -- src/renderer/tool/handlers.cljs | 29 ------------------- src/renderer/tool/impl/draw/pen.cljs | 3 +- 5 files changed, 1 insertion(+), 40 deletions(-) diff --git a/src/renderer/document/db.cljs b/src/renderer/document/db.cljs index 5158d249..c8b84726 100644 --- a/src/renderer/document/db.cljs +++ b/src/renderer/document/db.cljs @@ -23,7 +23,6 @@ [:zoom {:default 1} ZoomFactor] [:rotate {:default 0} number?] [:history {:optional true} History] - [:temp-element {:optional true} Element] [:pan {:default [0 0]} Vec2] [:elements {:default {} :persist true} [:map-of uuid? Element]] [:focused {:optional true} boolean?] diff --git a/src/renderer/document/subs.cljs b/src/renderer/document/subs.cljs index e3433a18..3c5197ee 100644 --- a/src/renderer/document/subs.cljs +++ b/src/renderer/document/subs.cljs @@ -103,11 +103,6 @@ :<- [::active] :-> :elements) -(rf/reg-sub - ::temp-element - :<- [::active] - :-> :temp-element) - (rf/reg-sub ::filter :<- [::active] diff --git a/src/renderer/element/impl/container/canvas.cljs b/src/renderer/element/impl/container/canvas.cljs index badc7f31..4e10ed06 100644 --- a/src/renderer/element/impl/container/canvas.cljs +++ b/src/renderer/element/impl/container/canvas.cljs @@ -30,7 +30,6 @@ (let [child-elements @(rf/subscribe [::element.subs/filter-visible (:children el)]) viewbox-attr @(rf/subscribe [::frame.subs/viewbox-attr]) {:keys [width height]} @(rf/subscribe [::app.subs/dom-rect]) - temp-element @(rf/subscribe [::document.subs/temp-element]) read-only? @(rf/subscribe [::document.subs/read-only?]) cursor @(rf/subscribe [::tool.subs/cursor]) active-tool @(rf/subscribe [::tool.subs/active]) @@ -66,8 +65,6 @@ (when grid [ruler.views/grid]) - (when-not read-only? [element.hierarchy/render temp-element]) - (when snap? [:<> (when snapped-el diff --git a/src/renderer/tool/handlers.cljs b/src/renderer/tool/handlers.cljs index 78883ebe..8c882c15 100644 --- a/src/renderer/tool/handlers.cljs +++ b/src/renderer/tool/handlers.cljs @@ -3,15 +3,12 @@ [clojure.core.matrix :as matrix] [malli.core :as m] [renderer.app.db :refer [App]] - [renderer.element.db :refer [Element]] - [renderer.element.handlers :as element.handlers] [renderer.frame.db :refer [DomRect]] [renderer.frame.handlers :as frame.handlers] [renderer.history.handlers :as history.handlers] [renderer.snap.handlers :as snap.handlers] [renderer.tool.db :refer [Tool State Cursor]] [renderer.tool.hierarchy :as tool.hierarchy] - [renderer.utils.element :as utils.element] [renderer.utils.math :refer [Vec2]])) (m/=> add-fx [:-> App vector? App]) @@ -46,31 +43,6 @@ [db] (matrix/sub (:adjusted-pointer-pos db) (:adjusted-pointer-offset db))) -(m/=> dissoc-temp [:-> App App]) -(defn dissoc-temp - [db] - (cond-> db - (:active-document db) - (update-in [:documents (:active-document db)] dissoc :temp-element))) - -(m/=> set-temp [:-> App map? App]) -(defn set-temp - [db el] - (->> (utils.element/normalize-attrs el) - (assoc-in db [:documents (:active-document db) :temp-element]))) - -(m/=> temp [:-> App [:maybe Element]]) -(defn temp - [db] - (get-in db [:documents (:active-document db) :temp-element])) - -(m/=> create-temp-element [:-> App App]) -(defn create-temp-element - [db] - (->> (temp db) - (element.handlers/add db) - (dissoc-temp))) - (m/=> axis-pan-offset [:-> number? number? number? number?]) (defn axis-pan-offset [position offset size] @@ -106,7 +78,6 @@ (cond-> db :always (-> (activate (:tool db)) - (dissoc-temp) (history.handlers/reset-state)) (= (:state db) :idle) diff --git a/src/renderer/tool/impl/draw/pen.cljs b/src/renderer/tool/impl/draw/pen.cljs index a32ebf33..bffb0d1d 100644 --- a/src/renderer/tool/impl/draw/pen.cljs +++ b/src/renderer/tool/impl/draw/pen.cljs @@ -31,8 +31,7 @@ (defmethod tool.hierarchy/on-drag :pen [db _e] - (let [{:keys [adjusted-pointer-pos]} db - point (string/join " " adjusted-pointer-pos) + (let [point (string/join " " (:adjusted-pointer-pos db)) id (:id (first (element.handlers/selected db)))] (element.handlers/update-el db id (fn [el] (update-in el From ef4d589fe4ddbd9d4db6a32cbc0a725806b1e091 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 11:52:38 +0300 Subject: [PATCH 20/31] introduce cached state --- src/renderer/app/db.cljs | 1 + src/renderer/event/handlers.cljs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/renderer/app/db.cljs b/src/renderer/app/db.cljs index 897b6b55..89524639 100644 --- a/src/renderer/app/db.cljs +++ b/src/renderer/app/db.cljs @@ -49,6 +49,7 @@ [:event-timestamp {:optional true} number?] [:double-click-delta {:default 250} [:and number? pos?]] [:state {:default :idle} State] + [:cached-state {:optional true} State] [:grid {:default false :persist true} boolean?] [:ruler {:default {} :persist true} Ruler] [:snap {:default {} :persist true} Snap] diff --git a/src/renderer/event/handlers.cljs b/src/renderer/event/handlers.cljs index 53360462..48b1f1bd 100644 --- a/src/renderer/event/handlers.cljs +++ b/src/renderer/event/handlers.cljs @@ -22,8 +22,8 @@ (m/=> pointer [:-> App PointerEvent App]) (defn pointer [db e] - (let [{:keys [pointer-offset tool dom-rect drag cached-tool - drag-threshold nearest-neighbor]} db + (let [{:keys [pointer-offset tool state cached-tool cached-state + dom-rect drag drag-threshold nearest-neighbor]} db {:keys [button pointer-pos timestamp pointer-id]} e adjusted-pointer-pos (frame.handlers/adjusted-pointer-pos db pointer-pos) db (snap.handlers/update-nearest-neighbors db)] @@ -50,7 +50,8 @@ "pointerdown" (cond-> db (= button :middle) - (-> (assoc :cached-tool tool) + (-> (assoc :cached-tool tool + :cached-state state) (tool.handlers/activate :pan)) (not= button :right) @@ -75,7 +76,8 @@ (tool.hierarchy/on-pointer-up e))))) (and cached-tool (= button :middle)) (-> (tool.handlers/activate cached-tool) - (dissoc :cached-tool)) + (tool.handlers/set-state cached-state) + (dissoc :cached-tool :cached-state)) :always (dissoc :pointer-offset :drag :nearest-neighbor)) From 582a82899e7dc03011d96a2bae540bf45cbef01b Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 12:51:55 +0300 Subject: [PATCH 21/31] remove unneeded deselect --- src/renderer/tool/impl/draw/brush.cljs | 1 - src/renderer/tool/impl/draw/pen.cljs | 1 - src/renderer/tool/impl/element/circle.cljs | 1 - src/renderer/tool/impl/element/ellipse.cljs | 1 - src/renderer/tool/impl/element/line.cljs | 1 - src/renderer/tool/impl/element/polyshape.cljs | 1 - src/renderer/tool/impl/element/rect.cljs | 1 - src/renderer/tool/impl/element/svg.cljs | 1 - src/renderer/tool/impl/extension/blob.cljs | 1 - 9 files changed, 9 deletions(-) diff --git a/src/renderer/tool/impl/draw/brush.cljs b/src/renderer/tool/impl/draw/brush.cljs index 9de34721..490cc172 100644 --- a/src/renderer/tool/impl/draw/brush.cljs +++ b/src/renderer/tool/impl/draw/brush.cljs @@ -44,7 +44,6 @@ stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :brush :attrs {:points point diff --git a/src/renderer/tool/impl/draw/pen.cljs b/src/renderer/tool/impl/draw/pen.cljs index bffb0d1d..3f0627bf 100644 --- a/src/renderer/tool/impl/draw/pen.cljs +++ b/src/renderer/tool/impl/draw/pen.cljs @@ -22,7 +22,6 @@ point-2 (string/join " " (:adjusted-pointer-pos db))] (-> db (tool.handlers/set-state :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :polyline :attrs {:points (str point-1 " " point-2) diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index f1f3ee5c..95d82857 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -23,7 +23,6 @@ fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] (-> (tool.handlers/set-state db :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :circle :attrs {:cx cx diff --git a/src/renderer/tool/impl/element/ellipse.cljs b/src/renderer/tool/impl/element/ellipse.cljs index f7df94e6..389d390c 100644 --- a/src/renderer/tool/impl/element/ellipse.cljs +++ b/src/renderer/tool/impl/element/ellipse.cljs @@ -31,7 +31,6 @@ stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :ellipse :attrs {:cx offset-x diff --git a/src/renderer/tool/impl/element/line.cljs b/src/renderer/tool/impl/element/line.cljs index 57e1ca26..e0b84d20 100644 --- a/src/renderer/tool/impl/element/line.cljs +++ b/src/renderer/tool/impl/element/line.cljs @@ -21,7 +21,6 @@ stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :line :attrs {:x1 offset-x diff --git a/src/renderer/tool/impl/element/polyshape.cljs b/src/renderer/tool/impl/element/polyshape.cljs index b22e4572..dd037163 100644 --- a/src/renderer/tool/impl/element/polyshape.cljs +++ b/src/renderer/tool/impl/element/polyshape.cljs @@ -24,7 +24,6 @@ fill (document.handlers/attr db :fill)] (-> db (tool.handlers/set-state :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag (:tool db) :attrs {:points (string/join " " points) diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index 8d15ea05..b4ca7219 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -31,7 +31,6 @@ stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :rect :attrs {:x (min x offset-x) diff --git a/src/renderer/tool/impl/element/svg.cljs b/src/renderer/tool/impl/element/svg.cljs index b2a6dba5..ad3aad5a 100644 --- a/src/renderer/tool/impl/element/svg.cljs +++ b/src/renderer/tool/impl/element/svg.cljs @@ -26,7 +26,6 @@ width (cond-> width lock-ratio (min height)) height (cond-> height lock-ratio (min width))] (-> (tool.handlers/set-state db :create) - (element.handlers/deselect-all) (element.handlers/add {:tag :svg :type :element :attrs {:x (min x offset-x) diff --git a/src/renderer/tool/impl/extension/blob.cljs b/src/renderer/tool/impl/extension/blob.cljs index b0ac409b..28146a70 100644 --- a/src/renderer/tool/impl/extension/blob.cljs +++ b/src/renderer/tool/impl/extension/blob.cljs @@ -27,7 +27,6 @@ fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] (-> (tool.handlers/set-state db :create) - (element.handlers/deselect-all) (element.handlers/add {:type :element :tag :blob :attrs {:x (- offset-x radius) From ba247a1be47fa52a0766d1f5ca36782ca1d04587 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 12:56:11 +0300 Subject: [PATCH 22/31] fix reset state --- src/renderer/tool/handlers.cljs | 22 ++++++++++++++-------- src/renderer/tool/impl/draw/core.cljs | 5 +---- src/renderer/tool/impl/element/core.cljs | 5 +---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/renderer/tool/handlers.cljs b/src/renderer/tool/handlers.cljs index 8c882c15..472d446f 100644 --- a/src/renderer/tool/handlers.cljs +++ b/src/renderer/tool/handlers.cljs @@ -29,14 +29,20 @@ (m/=> activate [:-> App Tool App]) (defn activate [db tool] - (-> db - (tool.hierarchy/on-deactivate) - (assoc :tool tool) - (set-state :idle) - (set-cursor "default") - (dissoc :drag :pointer-offset :clicked-element) - (snap.handlers/rebuild-tree) - (tool.hierarchy/on-activate))) + (cond-> db + :always + (-> (tool.hierarchy/on-deactivate) + (assoc :tool tool) + (set-state :idle) + (set-cursor "default") + (dissoc :drag :pointer-offset :clicked-element) + (snap.handlers/rebuild-tree)) + + (not (:cached-tool db)) + (history.handlers/reset-state) + + :always + (tool.hierarchy/on-activate))) (m/=> pointer-delta [:-> App Vec2]) (defn pointer-delta diff --git a/src/renderer/tool/impl/draw/core.cljs b/src/renderer/tool/impl/draw/core.cljs index e271daf1..5bfc8f9f 100644 --- a/src/renderer/tool/impl/draw/core.cljs +++ b/src/renderer/tool/impl/draw/core.cljs @@ -1,6 +1,5 @@ (ns renderer.tool.impl.draw.core (:require - [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] [renderer.tool.impl.draw.brush] @@ -14,6 +13,4 @@ (defmethod tool.hierarchy/on-activate ::tool.hierarchy/draw [db] - (-> db - (history.handlers/reset-state) - (tool.handlers/set-cursor "crosshair"))) + (tool.handlers/set-cursor db "crosshair")) diff --git a/src/renderer/tool/impl/element/core.cljs b/src/renderer/tool/impl/element/core.cljs index 3e666550..930e68f0 100644 --- a/src/renderer/tool/impl/element/core.cljs +++ b/src/renderer/tool/impl/element/core.cljs @@ -1,7 +1,6 @@ (ns renderer.tool.impl.element.core (:require [renderer.element.handlers :as element.handlers] - [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] [renderer.tool.impl.element.circle] @@ -23,9 +22,7 @@ (defmethod tool.hierarchy/on-activate ::tool.hierarchy/element [db] - (-> db - (history.handlers/reset-state) - (tool.handlers/set-cursor "crosshair"))) + (tool.handlers/set-cursor db "crosshair")) (defmethod tool.hierarchy/snapping-points ::tool.hierarchy/element [db] From a15c6f2261f2f1bfd3d9b8cbce6bd5acda0bc7bc Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 13:31:44 +0300 Subject: [PATCH 23/31] fix offset on create --- src/renderer/tool/impl/draw/brush.cljs | 12 ++++++------ src/renderer/tool/impl/draw/pen.cljs | 13 +++++++------ src/renderer/tool/impl/element/line.cljs | 8 ++++++-- src/renderer/tool/impl/element/polyshape.cljs | 9 ++++++--- src/renderer/tool/impl/element/rect.cljs | 16 ++++++++++------ src/renderer/tool/impl/extension/blob.cljs | 14 +++++++++----- 6 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/renderer/tool/impl/draw/brush.cljs b/src/renderer/tool/impl/draw/brush.cljs index 490cc172..2dd64a84 100644 --- a/src/renderer/tool/impl/draw/brush.cljs +++ b/src/renderer/tool/impl/draw/brush.cljs @@ -1,6 +1,7 @@ (ns renderer.tool.impl.draw.brush "https://github.com/steveruizok/perfect-freehand" (:require + [clojure.core.matrix :as matrix] [clojure.string :as string] [re-frame.core :as rf] [reagent.core :as reagent] @@ -55,12 +56,11 @@ (defmethod tool.hierarchy/on-drag :brush [db e] - (let [point (string/join " " (conj (:adjusted-pointer-pos db) (:pressure e))) - id (:id (first (element.handlers/selected db)))] - (element.handlers/update-el db id (fn [el] - (update-in el - [:attrs :points] - #(str % " " point)))))) + (let [{:keys [id parent]} (first (element.handlers/selected db)) + [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent)) + point (matrix/sub (:adjusted-pointer-pos db) [min-x min-y]) + point (string/join " " (conj point (:pressure e)))] + (element.handlers/update-attr db id :points str " " point))) (defmethod tool.hierarchy/on-drag-end :brush [db _e] diff --git a/src/renderer/tool/impl/draw/pen.cljs b/src/renderer/tool/impl/draw/pen.cljs index 3f0627bf..3f652999 100644 --- a/src/renderer/tool/impl/draw/pen.cljs +++ b/src/renderer/tool/impl/draw/pen.cljs @@ -1,8 +1,10 @@ (ns renderer.tool.impl.draw.pen (:require + [clojure.core.matrix :as matrix] [clojure.string :as string] [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] + [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] @@ -30,12 +32,11 @@ (defmethod tool.hierarchy/on-drag :pen [db _e] - (let [point (string/join " " (:adjusted-pointer-pos db)) - id (:id (first (element.handlers/selected db)))] - (element.handlers/update-el db id (fn [el] - (update-in el - [:attrs :points] - #(str % " " point)))))) + (let [{:keys [id parent]} (first (element.handlers/selected db)) + [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent)) + point (matrix/sub (:adjusted-pointer-pos db) [min-x min-y]) + point (string/join " " point)] + (element.handlers/update-attr db id :points str " " point))) (defmethod tool.hierarchy/on-drag-end :pen [db _e] diff --git a/src/renderer/tool/impl/element/line.cljs b/src/renderer/tool/impl/element/line.cljs index e0b84d20..3d6a9fd7 100644 --- a/src/renderer/tool/impl/element/line.cljs +++ b/src/renderer/tool/impl/element/line.cljs @@ -1,8 +1,10 @@ (ns renderer.tool.impl.element.line "https://www.w3.org/TR/SVG/shapes.html#LineElement" (:require + [clojure.core.matrix :as matrix] [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] + [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -31,8 +33,10 @@ (defn update-end [db] - (let [[x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - id (:id (first (element.handlers/selected db))) + (let [position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) + {:keys [id parent]} (first (element.handlers/selected db)) + [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent)) + [x y] (matrix/sub position [min-x min-y]) x (.toFixed x 3) y (.toFixed y 3)] (element.handlers/update-el db id #(-> % diff --git a/src/renderer/tool/impl/element/polyshape.cljs b/src/renderer/tool/impl/element/polyshape.cljs index dd037163..0469fc62 100644 --- a/src/renderer/tool/impl/element/polyshape.cljs +++ b/src/renderer/tool/impl/element/polyshape.cljs @@ -2,9 +2,11 @@ "This serves as an abstraction for polygons and polylines that have similar attributes and hehavior" (:require + [clojure.core.matrix :as matrix] [clojure.string :as string] [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] + [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy] @@ -32,8 +34,7 @@ (defn add-point [db point] - (let [id (:id (first (element.handlers/selected db))) - point (string/join " " point)] + (let [id (:id (first (element.handlers/selected db)))] (element.handlers/update-attr db id :points str " " point))) (defn drop-last-point @@ -61,7 +62,9 @@ (defmethod tool.hierarchy/on-pointer-move ::tool.hierarchy/polyshape [db _e] (let [point (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - id (:id (first (element.handlers/selected db)))] + {:keys [id parent]} (first (element.handlers/selected db)) + [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent)) + point (matrix/sub point [min-x min-y])] (if (= (:state db) :create) (element.handlers/update-attr db id :points diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index b4ca7219..ed6c30b7 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -3,6 +3,7 @@ (:require [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] + [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -51,12 +52,15 @@ height (cond-> height lock-ratio (min width)) x (.toFixed (min x offset-x) 3) y (.toFixed (min y offset-y) 3) - id (:id (first (element.handlers/selected db)))] - (element.handlers/update-el db id #(-> % - (assoc-in [:attrs :x] (str x)) - (assoc-in [:attrs :y] (str y)) - (assoc-in [:attrs :width] (str width)) - (assoc-in [:attrs :height] (str height)))))) + {:keys [id parent]} (first (element.handlers/selected db)) + [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent))] + (-> db + (element.handlers/update-el id #(-> % + (assoc-in [:attrs :x] (str x)) + (assoc-in [:attrs :y] (str y)) + (assoc-in [:attrs :width] (str width)) + (assoc-in [:attrs :height] (str height)))) + (element.handlers/translate [(- min-x) (- min-y)])))) (defmethod tool.hierarchy/on-pointer-up :rect [db e] diff --git a/src/renderer/tool/impl/extension/blob.cljs b/src/renderer/tool/impl/extension/blob.cljs index 28146a70..6f3f9465 100644 --- a/src/renderer/tool/impl/extension/blob.cljs +++ b/src/renderer/tool/impl/extension/blob.cljs @@ -4,6 +4,7 @@ [clojure.core.matrix :as matrix] [renderer.document.handlers :as document.handlers] [renderer.element.handlers :as element.handlers] + [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -42,11 +43,14 @@ [db] (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) radius (pointer-delta db) - id (:id (first (element.handlers/selected db)))] - (element.handlers/update-el db id #(-> % - (assoc-in [:attrs :x] (str (- offset-x radius))) - (assoc-in [:attrs :y] (str (- offset-y radius))) - (assoc-in [:attrs :size] (str (* radius 2))))))) + {:keys [id parent]} (first (element.handlers/selected db)) + [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent))] + (-> db + (element.handlers/update-el id #(-> % + (assoc-in [:attrs :x] (str (- offset-x radius))) + (assoc-in [:attrs :y] (str (- offset-y radius))) + (assoc-in [:attrs :size] (str (* radius 2))))) + (element.handlers/translate [(- min-x) (- min-y)])))) (defmethod tool.hierarchy/on-pointer-up :blob [db _e] From 666edcacd59a1d95e364620f6fc00473682f1f7b Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 16:23:50 +0300 Subject: [PATCH 24/31] refactor --- src/renderer/tool/handlers.cljs | 17 +++--- src/renderer/tool/impl/element/circle.cljs | 14 ++--- src/renderer/tool/impl/element/ellipse.cljs | 53 +++++++++---------- src/renderer/tool/impl/element/rect.cljs | 57 +++++++++----------- src/renderer/tool/impl/element/svg.cljs | 58 ++++++++++----------- 5 files changed, 95 insertions(+), 104 deletions(-) diff --git a/src/renderer/tool/handlers.cljs b/src/renderer/tool/handlers.cljs index 472d446f..f3e572a7 100644 --- a/src/renderer/tool/handlers.cljs +++ b/src/renderer/tool/handlers.cljs @@ -31,18 +31,19 @@ [db tool] (cond-> db :always - (-> (tool.hierarchy/on-deactivate) - (assoc :tool tool) - (set-state :idle) - (set-cursor "default") - (dissoc :drag :pointer-offset :clicked-element) - (snap.handlers/rebuild-tree)) + (tool.hierarchy/on-deactivate) - (not (:cached-tool db)) + (and (not= (:cached-state db) :create) + (not= (:state db) :type)) (history.handlers/reset-state) :always - (tool.hierarchy/on-activate))) + (-> (assoc :tool tool) + (set-state :idle) + (set-cursor "default") + (dissoc :drag :pointer-offset :clicked-element) + (snap.handlers/rebuild-tree) + (tool.hierarchy/on-activate)))) (m/=> pointer-delta [:-> App Vec2]) (defn pointer-delta diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index 95d82857..37ec8de3 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -39,12 +39,16 @@ id (:id (first (element.handlers/selected db)))] (element.handlers/update-el db id #(assoc-in % [:attrs :r] (str radius))))) +(defn finalize + [db] + (-> db + (history.handlers/finalize "Create circle") + (tool.handlers/activate :transform))) + (defmethod tool.hierarchy/on-pointer-up :circle [db _e] (if (= (:state db) :create) - (-> db - (history.handlers/finalize "Create circle") - (tool.handlers/activate :transform)) + (finalize db) (create db))) (defmethod tool.hierarchy/on-pointer-move :circle @@ -63,9 +67,7 @@ (defmethod tool.hierarchy/on-drag-end :circle [db _e] - (-> db - (history.handlers/finalize "Create circle") - (tool.handlers/activate :transform))) + (finalize db)) (defmethod tool.hierarchy/snapping-points :circle [db] diff --git a/src/renderer/tool/impl/element/ellipse.cljs b/src/renderer/tool/impl/element/ellipse.cljs index 389d390c..22e6acba 100644 --- a/src/renderer/tool/impl/element/ellipse.cljs +++ b/src/renderer/tool/impl/element/ellipse.cljs @@ -18,48 +18,49 @@ [] [:div "Hold " [:span.shortcut-key "Ctrl"] " to lock proportions."]) -(defn create +(defn attributes [db lock-ratio] (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - rx (abs (- x offset-x)) - ry (abs (- y offset-y)) - rx (cond-> rx lock-ratio (min ry)) - ry (cond-> ry lock-ratio (min rx)) + rx (.toFixed (abs (- x offset-x)) 3) + ry (.toFixed (abs (- y offset-y)) 3)] + {:rx (cond-> rx lock-ratio (min ry)) + :ry (cond-> ry lock-ratio (min rx))})) + +(defn create + [db lock-ratio] + (let [[x y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) (element.handlers/add {:type :element :tag :ellipse - :attrs {:cx offset-x - :cy offset-y - :fill fill - :stroke stroke - :rx rx - :ry ry}})))) + :attrs (merge (attributes db lock-ratio) + {:cx x + :cy y + :fill fill + :stroke stroke})})))) (defn update-radius [db lock-ratio] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) - (:adjusted-pointer-offset db)) - [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - rx (.toFixed (abs (- x offset-x)) 3) - ry (.toFixed (abs (- y offset-y)) 3) - rx (cond-> rx lock-ratio (min ry)) - ry (cond-> ry lock-ratio (min rx)) + (let [attrs (attributes db lock-ratio) + assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v))) id (:id (first (element.handlers/selected db)))] - (element.handlers/update-el db id #(-> % - (assoc-in [:attrs :rx] (str rx)) - (assoc-in [:attrs :ry] (str ry)))))) + (element.handlers/update-el db id #(reduce assoc-attr % attrs)))) + +(defn finalize + [db] + (-> db + (history.handlers/finalize "Create ellipse") + (tool.handlers/activate :transform))) (defmethod tool.hierarchy/on-pointer-up :ellipse [db e] (if (= (:state db) :create) - (-> db - (history.handlers/finalize "Create ellipse") - (tool.handlers/activate :transform)) + (finalize db) (create db (:ctrl-key e)))) (defmethod tool.hierarchy/on-pointer-move :ellipse @@ -78,6 +79,4 @@ (defmethod tool.hierarchy/on-drag-end :ellipse [db _e] - (-> db - (history.handlers/finalize "Create ellipse") - (tool.handlers/activate :transform))) + (finalize db)) diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index ed6c30b7..792dbf98 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -19,55 +19,50 @@ [] [:div "Hold " [:span.shortcut-key "Ctrl"] " to lock proportions."]) -(defn create +(defn attributes [db lock-ratio] (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - width (abs (- x offset-x)) - height (abs (- y offset-y)) - width (cond-> width lock-ratio (min height)) - height (cond-> height lock-ratio (min width)) - fill (document.handlers/attr db :fill) + width (.toFixed (abs (- x offset-x)) 3) + height (.toFixed (abs (- y offset-y)) 3)] + {:x (.toFixed (min x offset-x) 3) + :y (.toFixed (min y offset-y) 3) + :width (cond-> width lock-ratio (min height)) + :height (cond-> height lock-ratio (min width))})) + +(defn create + [db lock-ratio] + (let [fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) (element.handlers/add {:type :element :tag :rect - :attrs {:x (min x offset-x) - :y (min y offset-y) - :width width - :height height - :fill fill - :stroke stroke}})))) + :attrs (merge (attributes db lock-ratio) + {:fill fill + :stroke stroke})})))) (defn update-size [db lock-ratio] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) - (:adjusted-pointer-offset db)) - [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - width (.toFixed (abs (- x offset-x)) 3) - height (.toFixed (abs (- y offset-y)) 3) - width (cond-> width lock-ratio (min height)) - height (cond-> height lock-ratio (min width)) - x (.toFixed (min x offset-x) 3) - y (.toFixed (min y offset-y) 3) + (let [attrs (attributes db lock-ratio) + assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v))) {:keys [id parent]} (first (element.handlers/selected db)) [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent))] (-> db - (element.handlers/update-el id #(-> % - (assoc-in [:attrs :x] (str x)) - (assoc-in [:attrs :y] (str y)) - (assoc-in [:attrs :width] (str width)) - (assoc-in [:attrs :height] (str height)))) + (element.handlers/update-el id #(reduce assoc-attr % attrs)) (element.handlers/translate [(- min-x) (- min-y)])))) +(defn finalize + [db] + (-> db + (history.handlers/finalize "Create rectangle") + (tool.handlers/activate :transform))) + (defmethod tool.hierarchy/on-pointer-up :rect [db e] (if (= (:state db) :create) - (-> db - (history.handlers/finalize "Create rectangle") - (tool.handlers/activate :transform)) + (finalize db) (create db (:ctrl-key e)))) (defmethod tool.hierarchy/on-pointer-move :rect @@ -86,6 +81,4 @@ (defmethod tool.hierarchy/on-drag-end :rect [db _e] - (-> db - (history.handlers/finalize "Create rectangle") - (tool.handlers/activate :transform))) + (finalize db)) diff --git a/src/renderer/tool/impl/element/svg.cljs b/src/renderer/tool/impl/element/svg.cljs index ad3aad5a..75961cff 100644 --- a/src/renderer/tool/impl/element/svg.cljs +++ b/src/renderer/tool/impl/element/svg.cljs @@ -16,45 +16,43 @@ [] [:div "Hold " [:span.shortcut-key "Ctrl"] " to lock proportions."]) -(defn create +(defn attributes [db lock-ratio] (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - width (abs (- x offset-x)) - height (abs (- y offset-y)) - width (cond-> width lock-ratio (min height)) - height (cond-> height lock-ratio (min width))] - (-> (tool.handlers/set-state db :create) - (element.handlers/add {:tag :svg - :type :element - :attrs {:x (min x offset-x) - :y (min y offset-y) - :width width - :height height}})))) + width (.toFixed (abs (- x offset-x)) 3) + height (.toFixed (abs (- y offset-y)) 3)] + {:x (.toFixed (min x offset-x) 3) + :y (.toFixed (min y offset-y) 3) + :width (cond-> width lock-ratio (min height)) + :height (cond-> height lock-ratio (min width))})) + +(defn create + [db lock-ratio] + (-> db + (tool.handlers/set-state :create) + (element.handlers/add {:tag :svg + :type :element + :attrs (attributes db lock-ratio)}))) (defn update-size [db lock-ratio] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) - (:adjusted-pointer-offset db)) - [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - width (abs (- x offset-x)) - height (abs (- y offset-y)) - width (cond-> width lock-ratio (min height)) - height (cond-> height lock-ratio (min width)) - id (:id (first (element.handlers/selected db)))] - (element.handlers/update-el db id #(-> % - (assoc-in [:attrs :x] (str (min x offset-x))) - (assoc-in [:attrs :y] (str (min y offset-y))) - (assoc-in [:attrs :width] (str width)) - (assoc-in [:attrs :height] (str height)))))) + (let [id (:id (first (element.handlers/selected db))) + attrs (attributes db lock-ratio) + assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v)))] + (element.handlers/update-el db id #(reduce assoc-attr % attrs)))) + +(defn finalize + [db] + (-> db + (history.handlers/finalize "Create SVG") + (tool.handlers/activate :transform))) (defmethod tool.hierarchy/on-pointer-up :svg [db e] (if (= (:state db) :create) - (-> db - (history.handlers/finalize "Create SVG") - (tool.handlers/activate :transform)) + (finalize db) (create db (:ctrl-key e)))) (defmethod tool.hierarchy/on-pointer-move :svg @@ -73,6 +71,4 @@ (defmethod tool.hierarchy/on-drag-end :svg [db _e] - (-> db - (history.handlers/finalize "Create SVG") - (tool.handlers/activate :transform))) + (finalize db)) From 8bd4db8a600bba15aaa55430c9f5d5d99cd8a139 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 16:33:32 +0300 Subject: [PATCH 25/31] fix text create --- src/renderer/tool/impl/element/text.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/tool/impl/element/text.cljs b/src/renderer/tool/impl/element/text.cljs index 4a40758e..0d7dd64f 100644 --- a/src/renderer/tool/impl/element/text.cljs +++ b/src/renderer/tool/impl/element/text.cljs @@ -27,8 +27,8 @@ :y offset-y}}] (-> (element.handlers/deselect-all db) (element.handlers/add el) - (tool.handlers/activate :edit) - (tool.handlers/set-state :type)))) + (tool.handlers/set-state :type) + (tool.handlers/activate :edit)))) (defmethod tool.hierarchy/on-drag-end :text [db e] From 9a285e3fef9e4726d8a636bfb7686c2cf506061b Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 17:04:23 +0300 Subject: [PATCH 26/31] enhance disabled state --- src/renderer/attribute/impl/points.cljs | 7 ++++--- src/renderer/attribute/views.cljs | 8 +++++++- src/renderer/tool/db.cljs | 2 +- src/renderer/tool/impl/base/pan.cljs | 11 ++--------- src/renderer/tool/subs.cljs | 4 ++++ 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/renderer/attribute/impl/points.cljs b/src/renderer/attribute/impl/points.cljs index 37a3a5e8..eb518e57 100644 --- a/src/renderer/attribute/impl/points.cljs +++ b/src/renderer/attribute/impl/points.cljs @@ -38,11 +38,12 @@ [views/icon "times"]]]) (defn points-popover - [points] + [points disabled] [:> Popover/Root {:modal true} [:> Popover/Trigger {:title "Edit points" - :class "form-control-button"} + :class "form-control-button" + :disabled disabled} [views/icon "pencil"]] [:> Popover/Portal [:> Popover/Content @@ -64,4 +65,4 @@ [:div.flex.gap-px.w-full [attribute.views/form-input k (if state-idle v "waiting") {:disabled (or disabled (not v) (not state-idle))}] - (when v [points-popover (utils.utils.attribute/points->vec v)])])) + (when v [points-popover (utils.utils.attribute/points->vec v) disabled])])) diff --git a/src/renderer/attribute/views.cljs b/src/renderer/attribute/views.cljs index 21859674..19d5feb8 100644 --- a/src/renderer/attribute/views.cljs +++ b/src/renderer/attribute/views.cljs @@ -13,6 +13,7 @@ [renderer.event.impl.keyboard :as event.impl.keyboard] [renderer.events :as-alias events] [renderer.tool.hierarchy :as tool.hierarchy] + [renderer.tool.subs :as-alias tool.subs] [renderer.utils.attribute :as utils.attribute] [renderer.views :as views])) @@ -242,7 +243,12 @@ (let [selected-elements @(rf/subscribe [::element.subs/selected]) selected-tags @(rf/subscribe [::element.subs/selected-tags]) selected-attrs @(rf/subscribe [::element.subs/selected-attrs]) - locked? @(rf/subscribe [::element.subs/selected-locked?]) + selected-locked? @(rf/subscribe [::element.subs/selected-locked?]) + tool-state @(rf/subscribe [::tool.subs/state]) + tool-cached-state @(rf/subscribe [::tool.subs/cached-state]) + locked? (or selected-locked? + (not= tool-state :idle) + (and tool-cached-state (not= tool-cached-state :idle))) tag (first selected-tags) multitag? (next selected-tags)] (when-first [el selected-elements] diff --git a/src/renderer/tool/db.cljs b/src/renderer/tool/db.cljs index 357336dd..852e3902 100644 --- a/src/renderer/tool/db.cljs +++ b/src/renderer/tool/db.cljs @@ -9,7 +9,7 @@ [:fn {:error/fn (fn [{:keys [value]} _] (str value " is not a supported tool"))} tool?]) -(def State [:enum :idle :translate :clone :scale :select :create :edit :pan :type]) +(def State [:enum :idle :translate :clone :scale :select :create :edit :type]) (def Cursor [:enum diff --git a/src/renderer/tool/impl/base/pan.cljs b/src/renderer/tool/impl/base/pan.cljs index c564c243..9a07c442 100644 --- a/src/renderer/tool/impl/base/pan.cljs +++ b/src/renderer/tool/impl/base/pan.cljs @@ -21,19 +21,13 @@ [] "Click and drag to pan.") -(defmethod tool.hierarchy/help [:pan :pan] - [] - "Drag to pan.") - (defmethod tool.hierarchy/on-pointer-up :pan [db _e] - (-> (tool.handlers/set-cursor db "grab") - (tool.handlers/set-state :idle))) + (tool.handlers/set-cursor db "grab")) (defmethod tool.hierarchy/on-pointer-down :pan [db _e] - (-> (tool.handlers/set-cursor db "grabbing") - (tool.handlers/set-state :pan))) + (tool.handlers/set-cursor db "grabbing")) (defmethod tool.hierarchy/on-drag :pan [db e] @@ -42,6 +36,5 @@ (defmethod tool.hierarchy/on-drag-end :pan [db _e] (-> (tool.handlers/set-cursor db "grab") - (tool.handlers/set-state :idle) (snap.handlers/update-viewport-tree) (tool.handlers/add-fx [::app.effects/persist]))) diff --git a/src/renderer/tool/subs.cljs b/src/renderer/tool/subs.cljs index b4aba581..7377485c 100644 --- a/src/renderer/tool/subs.cljs +++ b/src/renderer/tool/subs.cljs @@ -27,6 +27,10 @@ ::state :-> :state) +(rf/reg-sub + ::cached-state + :-> :cached-state) + (rf/reg-sub ::help :<- [::active] From 1f4a57c1cc265e7d55bd12c0c1284f2450080be8 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 17:14:14 +0300 Subject: [PATCH 27/31] path fixes --- src/renderer/attribute/impl/d.cljs | 3 ++- src/renderer/element/impl/shape/path.cljs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/attribute/impl/d.cljs b/src/renderer/attribute/impl/d.cljs index 466a179e..b1d16827 100644 --- a/src/renderer/attribute/impl/d.cljs +++ b/src/renderer/attribute/impl/d.cljs @@ -140,7 +140,8 @@ [:> Popover/Root {:modal true} [:> Popover/Trigger {:title "Edit path" - :class "form-control-button"} + :class "form-control-button" + :disabled disabled} [views/icon "pencil"]] [:> Popover/Portal [:> Popover/Content {:sideOffset 5 diff --git a/src/renderer/element/impl/shape/path.cljs b/src/renderer/element/impl/shape/path.cljs index 5e487cab..b5f7b03b 100644 --- a/src/renderer/element/impl/shape/path.cljs +++ b/src/renderer/element/impl/shape/path.cljs @@ -22,6 +22,7 @@ :fill :stroke :stroke-linejoin + :stroke-linecap :opacity]}) (defmethod element.hierarchy/translate :path From 1f7d4a7ea86392d1a60ad0280efff3edb0ed7734 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 17:37:39 +0300 Subject: [PATCH 28/31] refactor --- src/renderer/element/impl/shape/polyshape.cljs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/renderer/element/impl/shape/polyshape.cljs b/src/renderer/element/impl/shape/polyshape.cljs index 3d34a8ae..89541efe 100644 --- a/src/renderer/element/impl/shape/polyshape.cljs +++ b/src/renderer/element/impl/shape/polyshape.cljs @@ -66,7 +66,8 @@ [:g (map-indexed (fn [index point] (let [id (keyword (str index)) is-active (and (= (:id clicked-element) id) - (= (:element clicked-element) (:id el))) + (= (:element clicked-element) + (:id el))) offset (utils.element/offset el) [x y] (->> point (mapv utils.length/unit->px) @@ -89,11 +90,12 @@ (defmethod element.hierarchy/edit ::element.hierarchy/polyshape [el [x y] handle] - (let [index (js/parseInt (name handle))] + (let [index (js/parseInt (name handle)) + transform-point (fn [[px py]] + (list (utils.length/transform px + x) + (utils.length/transform py + y)))] (update-in el [:attrs :points] #(-> (utils.attribute/points->vec %) - (update index (fn [[px py]] - (list (utils.length/transform px + x) - (utils.length/transform py + y)))) + (update index transform-point) (flatten) (->> (string/join " ") (string/trim)))))) From c0578f2756af8cebcbfce77ac8794bd93c1b7bbc Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 21:43:21 +0300 Subject: [PATCH 29/31] refactor --- .clj-kondo/config.edn | 2 +- src/electron/main.cljs | 4 +- src/renderer/app/effects.cljs | 4 +- src/renderer/app/views.cljs | 47 ++- src/renderer/attribute/impl/core.cljs | 4 +- src/renderer/attribute/impl/font_weight.cljs | 9 +- src/renderer/attribute/impl/href.cljs | 7 +- src/renderer/attribute/views.cljs | 4 +- src/renderer/dialog/views.cljs | 6 +- src/renderer/effects.cljs | 6 +- src/renderer/element/impl/box.cljs | 16 +- .../element/impl/container/canvas.cljs | 3 +- src/renderer/element/impl/custom/brush.cljs | 3 +- src/renderer/element/impl/shape/path.cljs | 8 +- src/renderer/element/impl/text.cljs | 21 +- src/renderer/event/handlers.cljs | 10 +- src/renderer/frame/handlers.cljs | 7 +- src/renderer/frame/views.cljs | 3 +- src/renderer/notification/views.cljs | 5 +- src/renderer/reepl/replumb.cljs | 6 +- src/renderer/reepl/views.cljs | 31 +- src/renderer/tool/impl/base/transform.cljs | 10 +- src/renderer/tool/impl/element/text.cljs | 3 +- src/renderer/tool/impl/extension/blob.cljs | 48 +-- src/renderer/tool/impl/misc/measure.cljs | 3 +- src/renderer/tree/views.cljs | 19 +- src/renderer/utils/element.cljs | 20 +- src/renderer/window/views.cljs | 4 +- src/renderer/worker/effects.cljs | 4 +- test/document_test.cljs | 283 +++++++++--------- 30 files changed, 331 insertions(+), 269 deletions(-) diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index b8fa2ab1..7563b3c5 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -19,7 +19,7 @@ :unused-alias {:level :warning} :redundant-call {:level :warning} :redundant-str-call {:level :warning} - :line-length {:max-line-length 100 + :line-length {:max-line-length 90 :exclude-urls true} :clojure-lsp/unused-public-var {:exclude-regex #{"pages.*"}} :consistent-alias {:level :warning diff --git a/src/electron/main.cljs b/src/electron/main.cljs index 511a0db8..5bf9f9d3 100644 --- a/src/electron/main.cljs +++ b/src/electron/main.cljs @@ -162,7 +162,9 @@ :frame false})) (.once ^js @loading-window "show" init-main-window!) (.loadURL ^js @loading-window (resource-path "/public/loading.html")) - (.once ^js (.-webContents @loading-window) "did-finish-load" #(.show ^js @loading-window))) + (.once ^js (.-webContents @loading-window) + "did-finish-load" + #(.show ^js @loading-window))) (defn ^:export init! [] (.initialize log) diff --git a/src/renderer/app/effects.cljs b/src/renderer/app/effects.cljs index 729998b4..74317e29 100644 --- a/src/renderer/app/effects.cljs +++ b/src/renderer/app/effects.cljs @@ -45,7 +45,9 @@ (fn [{:keys [on-success on-error formatter]}] (when-not (undefined? js/window.queryLocalFonts) (-> (.queryLocalFonts js/window) - (.then #(when on-success (rf/dispatch (conj on-success (cond-> % formatter formatter))))) + (.then #(when on-success (rf/dispatch (conj on-success + (cond-> % + formatter formatter))))) (.catch #(when on-error (rf/dispatch (conj on-error %)))))))) (rf/reg-fx diff --git a/src/renderer/app/views.cljs b/src/renderer/app/views.cljs index 77d0fc9f..1722e9f0 100644 --- a/src/renderer/app/views.cljs +++ b/src/renderer/app/views.cljs @@ -49,20 +49,34 @@ (defn debug-rows [] - [["Dom rect" (map->str @(rf/subscribe [::app.subs/dom-rect]))] - ["Viewbox" (coll->str @(rf/subscribe [::frame.subs/viewbox]))] - ["Pointer position" (coll->str @(rf/subscribe [::app.subs/pointer-pos]))] - ["Adjusted pointer position" (coll->str @(rf/subscribe [::app.subs/adjusted-pointer-pos]))] - ["Pointer offset" (coll->str @(rf/subscribe [::app.subs/pointer-offset]))] - ["Adjusted pointer offset" (coll->str @(rf/subscribe [::app.subs/adjusted-pointer-offset]))] - ["Pointer drag?" (str @(rf/subscribe [::tool.subs/drag?]))] - ["Pan" (coll->str @(rf/subscribe [::document.subs/pan]))] - ["Active tool" @(rf/subscribe [::tool.subs/active])] - ["Cached tool" @(rf/subscribe [::tool.subs/cached])] - ["State" @(rf/subscribe [::tool.subs/state])] - ["Clicked element" (:id @(rf/subscribe [::app.subs/clicked-element]))] - ["Ignored elements" @(rf/subscribe [::document.subs/ignored-ids])] - ["Snap" (map->str @(rf/subscribe [::snap.subs/nearest-neighbor]))]]) + (let [dom-rect (rf/subscribe [::app.subs/dom-rect]) + viewbox (rf/subscribe [::frame.subs/viewbox]) + pointer-pos (rf/subscribe [::app.subs/pointer-pos]) + adjusted-pointer-pos (rf/subscribe [::app.subs/adjusted-pointer-pos]) + pointer-offset (rf/subscribe [::app.subs/pointer-offset]) + adjusted-pointer-offset (rf/subscribe [::app.subs/adjusted-pointer-offset]) + drag? (rf/subscribe [::tool.subs/drag?]) + pan (rf/subscribe [::document.subs/pan]) + active-tool (rf/subscribe [::tool.subs/active]) + cached-tool (rf/subscribe [::tool.subs/cached]) + tool-state (rf/subscribe [::tool.subs/state]) + clicked-element (rf/subscribe [::app.subs/clicked-element]) + ignored-ids (rf/subscribe [::document.subs/ignored-ids]) + nearest-neighbor (rf/subscribe [::snap.subs/nearest-neighbor])] + [["Dom rect" (map->str @dom-rect)] + ["Viewbox" (coll->str @viewbox)] + ["Pointer position" (coll->str @pointer-pos)] + ["Adjusted pointer position" (coll->str @adjusted-pointer-pos)] + ["Pointer offset" (coll->str @pointer-offset)] + ["Adjusted pointer offset" (coll->str @adjusted-pointer-offset)] + ["Pointer drag?" (str @drag?)] + ["Pan" (coll->str @pan)] + ["Active tool" @active-tool] + ["Cached tool" @cached-tool] + ["State" @tool-state] + ["Clicked element" (:id @clicked-element)] + ["Ignored elements" @ignored-ids] + ["Snap" (map->str @nearest-neighbor)]])) (defn debug-info [] @@ -112,8 +126,9 @@ (when (and help-bar (seq help-message)) [:div.flex.absolute.justify-center.w-full.p-4.pointer-events-none [:div.bg-primary.rounded-full.overflow-hidden.shadow-lg - [:div.overlay.text-color.text-xs.gap-1.flex.flex-wrap.truncate.py-2.px-4.justify-center - {:aria-live "polite"} + [:div.overlay.text-color.text-xs.gap-1.flex.flex-wrap.truncate.py-2 + {:class "px-4 justify-center" + :aria-live "polite"} help-message]]])]]])) (defn center-top-group diff --git a/src/renderer/attribute/impl/core.cljs b/src/renderer/attribute/impl/core.cljs index 0339427c..aff93bff 100644 --- a/src/renderer/attribute/impl/core.cljs +++ b/src/renderer/attribute/impl/core.cljs @@ -194,8 +194,8 @@ (defmethod attribute.hierarchy/description [:default :values] [] - "The values attribute has different meanings, depending upon the context where it's used, - either it defines a sequence of values used over the course of an animation, + "The values attribute has different meanings, depending upon the context where it's + used, either it defines a sequence of values used over the course of an animation, or it's a list of numbers for a color matrix, which is interpreted differently depending on the type of color change to be performed.") diff --git a/src/renderer/attribute/impl/font_weight.cljs b/src/renderer/attribute/impl/font_weight.cljs index 8bb68896..89c3f202 100644 --- a/src/renderer/attribute/impl/font_weight.cljs +++ b/src/renderer/attribute/impl/font_weight.cljs @@ -12,6 +12,11 @@ "The font-weight attribute refers to the boldness or lightness of the glyphs used to render the text, relative to other fonts in the same font family.") +(defn label + [weight] + (let [weight-name (first (get utils.attribute/weight-name-mapping weight))] + (str weight " - " weight-name))) + (defmethod attribute.hierarchy/form-element [:default :font-weight] [_ k v attrs] (let [available-weights @(rf/subscribe [::element.subs/font-weights]) @@ -22,7 +27,5 @@ (merge attrs {:default-value "400" :items (mapv #(do {:key % - :label (str % " - " (-> % - utils.attribute/weight-name-mapping - first)) + :label (label %) :value %}) weights)})])) diff --git a/src/renderer/attribute/impl/href.cljs b/src/renderer/attribute/impl/href.cljs index 5638d449..9bb17e29 100644 --- a/src/renderer/attribute/impl/href.cljs +++ b/src/renderer/attribute/impl/href.cljs @@ -45,7 +45,6 @@ ::success (fn [{:keys [db]} [_ file]] {:db (tool.handlers/activate db :transform) - ::effects/file-read-as [file - :data-url - {"load" {:on-fire [::element.events/set-attr :href]} - "error" {:on-fire [::notification.events/show-exception]}}]})) + ::effects/file-read-as + [file :data-url {"load" {:on-fire [::element.events/set-attr :href]} + "error" {:on-fire [::notification.events/show-exception]}}]})) diff --git a/src/renderer/attribute/views.cljs b/src/renderer/attribute/views.cljs index 19d5feb8..dc1faa64 100644 --- a/src/renderer/attribute/views.cljs +++ b/src/renderer/attribute/views.cljs @@ -96,8 +96,8 @@ % v on-change-handler! k v)})] (when-not (or (empty? (str v)) disabled) - [:button.button.bg-primary.text-muted.absolute.h-full.right-0.clear-input-button.invisible.p-1 - {:class "hover:bg-transparent" + [:button.button.bg-primary.text-muted.absolute.h-full.right-0.p-1.invisible + {:class "clear-input-button hover:bg-transparent" :on-pointer-down #(rf/dispatch [::element.events/remove-attr k])} [views/icon "times"]])]) diff --git a/src/renderer/dialog/views.cljs b/src/renderer/dialog/views.cljs index e83d3149..daf1b60b 100644 --- a/src/renderer/dialog/views.cljs +++ b/src/renderer/dialog/views.cljs @@ -47,14 +47,16 @@ " will be lost if you close the document without saving."] [:div.flex.gap-2.flex-wrap [:button.button.px-2.bg-primary.rounded.flex-1 - {:on-click #(rf/dispatch [::dialog.events/close [::document.events/close id false]])} + {:on-click #(rf/dispatch [::dialog.events/close + [::document.events/close id false]])} "Don't save"] [:button.button.px-2.bg-primary.rounded.flex-1 {:on-click #(rf/dispatch [::dialog.events/close])} "Cancel"] [:button.button.px-2.rounded.flex-1.accent {:auto-focus true - :on-click #(rf/dispatch [::dialog.events/close [::document.events/save-and-close id]])} + :on-click #(rf/dispatch [::dialog.events/close + [::document.events/save-and-close id]])} "Save"]]]) (defn cmdk-item diff --git a/src/renderer/effects.cljs b/src/renderer/effects.cljs index f757baa4..13c00c1c 100644 --- a/src/renderer/effects.cljs +++ b/src/renderer/effects.cljs @@ -150,7 +150,8 @@ (.addEventListener target channel #(rf/dispatch (conj listener - (cond-> % formatter formatter)))))) + (cond-> % + formatter formatter)))))) (rf/reg-fx ::ipc-send @@ -163,7 +164,8 @@ (fn [{:keys [channel data formatter on-success on-error]}] (when js/window.api (-> (js/window.api.invoke channel (clj->js data)) - (.then #(when on-success (rf/dispatch (conj on-success (cond-> % formatter formatter))))) + (.then #(when on-success (rf/dispatch (conj on-success (cond-> % + formatter formatter))))) (.catch #(when on-error (rf/dispatch (conj on-error %)))))))) (rf/reg-fx diff --git a/src/renderer/element/impl/box.cljs b/src/renderer/element/impl/box.cljs index 695cf034..9c587ae7 100644 --- a/src/renderer/element/impl/box.cljs +++ b/src/renderer/element/impl/box.cljs @@ -23,15 +23,17 @@ (defmethod element.hierarchy/edit ::element.hierarchy/box [el [x y] handle] - (case handle - :position - (-> (utils.element/update-attrs-with el (comp (partial max 0) -) [[:width x] [:height y]]) - (element.hierarchy/translate [x y])) + (let [clamp (partial max 0)] + (case handle + :position + (-> el + (utils.element/update-attrs-with (comp clamp -) [[:width x] [:height y]]) + (element.hierarchy/translate [x y])) - :size - (utils.element/update-attrs-with el (comp (partial max 0) +) [[:width x] [:height y]]) + :size + (utils.element/update-attrs-with el (comp clamp +) [[:width x] [:height y]]) - el)) + el))) (defmethod element.hierarchy/render-edit ::element.hierarchy/box [el] diff --git a/src/renderer/element/impl/container/canvas.cljs b/src/renderer/element/impl/container/canvas.cljs index 4e10ed06..2bb93acc 100644 --- a/src/renderer/element/impl/container/canvas.cljs +++ b/src/renderer/element/impl/container/canvas.cljs @@ -40,7 +40,8 @@ snap? @(rf/subscribe [::snap.subs/active?]) nearest-neighbor @(rf/subscribe [::snap.subs/nearest-neighbor]) snapped-el-id (-> nearest-neighbor meta :id) - snapped-el (when snapped-el-id @(rf/subscribe [::element.subs/entity snapped-el-id]))] + snapped-el (when snapped-el-id + @(rf/subscribe [::element.subs/entity snapped-el-id]))] [:svg#canvas {:on-pointer-up pointer-handler :on-pointer-down pointer-handler :on-pointer-move pointer-handler diff --git a/src/renderer/element/impl/custom/brush.cljs b/src/renderer/element/impl/custom/brush.cljs index 7736b252..db25e301 100644 --- a/src/renderer/element/impl/custom/brush.cljs +++ b/src/renderer/element/impl/custom/brush.cljs @@ -165,7 +165,8 @@ #(->> (into [] partition-to-px (utils.attribute/str->seq %)) (reduce (fn [points point] (let [rel-point (matrix/sub bbox-min (take 2 point)) - rel-offset (utils.element/scale-offset ratio rel-point) + rel-offset (utils.element/scale-offset ratio + rel-point) offset (matrix/add offset rel-offset)] (translate offset points point))) []) (string/join " "))))) diff --git a/src/renderer/element/impl/shape/path.cljs b/src/renderer/element/impl/shape/path.cljs index b5f7b03b..45f03b54 100644 --- a/src/renderer/element/impl/shape/path.cljs +++ b/src/renderer/element/impl/shape/path.cljs @@ -63,13 +63,13 @@ (map-indexed (fn [i segment] (case (-> segment first string/lower-case) "m" - (let [[x y] (mapv utils.length/unit->px [(second segment) (last segment)]) - [x y] (matrix/add offset [x y])] + (let [point (mapv utils.length/unit->px (rest segment)) + [x y] (matrix/add offset point)] (square-handle i [x y])) "l" - (let [[x y] (mapv utils.length/unit->px [(second segment) (last segment)]) - [x y] (matrix/add offset [x y])] + (let [point (mapv utils.length/unit->px (rest segment)) + [x y] (matrix/add offset point)] (square-handle i [x y])) nil)) diff --git a/src/renderer/element/impl/text.cljs b/src/renderer/element/impl/text.cljs index c2145d6f..ea94d525 100644 --- a/src/renderer/element/impl/text.cljs +++ b/src/renderer/element/impl/text.cljs @@ -139,8 +139,8 @@ (.then (fn [blob] (-> (.arrayBuffer blob) (.then (fn [buffer] - (let [opentype-font (opentype/parse buffer) - path (.getPath opentype-font content x y font-size)] + (let [font (opentype/parse buffer) + path (.getPath font content x y font-size)] (.toPathData path))))))))) (defn includes-prop? @@ -152,9 +152,9 @@ [weight fonts] (let [weight-num (js/parseInt weight) weight-names (get utils.attribute/weight-name-mapping weight) - matched-weight (->> fonts - (filter (fn [font] - (some #(includes-prop? % (.-style font)) weight-names))))] + includes-weight? (fn [font] + (some #(includes-prop? % (.-style font)) weight-names)) + matched-weight (filter includes-weight? fonts)] (if (or (seq matched-weight) (< weight-num 100)) matched-weight (recur (str (- weight-num 100)) fonts)))) @@ -171,6 +171,10 @@ (first matched-family) (first fonts)))) +(defn default-font-path + [font-style font-weight] + (str "./css/files/noto-sans-latin-" font-weight "-" font-style ".woff")) + (defmethod element.hierarchy/path :text [el] (let [{:keys [attrs content]} el @@ -180,8 +184,11 @@ (if font-family (-> (js/window.queryLocalFonts) (.then (fn [fonts] - (when-let [font (match-font fonts font-family font-style font-weight)] + (when-let [font (match-font fonts + font-family + font-style + font-weight)] (font-file->path-data font content x y font-size))))) - (-> (js/fetch (str "./css/files/noto-sans-latin-" font-weight "-" font-style ".woff")) + (-> (js/fetch (default-font-path font-style font-weight)) (.then (fn [response] (font-file->path-data response content x y font-size))))))) diff --git a/src/renderer/event/handlers.cljs b/src/renderer/event/handlers.cljs index 48b1f1bd..ad573800 100644 --- a/src/renderer/event/handlers.cljs +++ b/src/renderer/event/handlers.cljs @@ -36,9 +36,10 @@ (tool.handlers/pan-out-of-canvas dom-rect pointer-pos pointer-offset) (not drag) - (-> (tool.hierarchy/on-drag-start e) - (tool.handlers/add-fx [::event.effects/set-pointer-capture pointer-id]) - (assoc :drag true)) + (-> (assoc :drag true) + (tool.hierarchy/on-drag-start e) + (tool.handlers/add-fx [::event.effects/set-pointer-capture + pointer-id])) :always (tool.hierarchy/on-drag e)) @@ -66,7 +67,8 @@ "pointerup" (cond-> (if drag (-> (tool.hierarchy/on-drag-end db e) - (tool.handlers/add-fx [::event.effects/release-pointer-capture pointer-id])) + (tool.handlers/add-fx [::event.effects/release-pointer-capture + pointer-id])) (if (= button :right) db (if (< 0 (- timestamp (:event-timestamp db)) (:double-click-delta db)) diff --git a/src/renderer/frame/handlers.cljs b/src/renderer/frame/handlers.cljs index 851b62e1..6f8ee9e2 100644 --- a/src/renderer/frame/handlers.cljs +++ b/src/renderer/frame/handlers.cljs @@ -38,13 +38,12 @@ (m/=> recenter-to-dom-rect [:-> App DomRect App]) (defn recenter-to-dom-rect [db updated-dom-rect] - (let [offset (-> (merge-with - (:dom-rect db) updated-dom-rect) - (select-keys [:width :height]))] + (let [delta (merge-with - (:dom-rect db) updated-dom-rect) + offset (matrix/div [(:width delta) (:height delta)] 2)] (if-not (-> db :window :focused) db (->> (:document-tabs db) - (reduce (fn [db id] - (pan-by db (matrix/div [(:width offset) (:height offset)] 2) id)) db))))) + (reduce (fn [db id] (pan-by db offset id)) db))))) (m/=> zoom-at-position [:-> App number? Vec2 App]) (defn zoom-at-position diff --git a/src/renderer/frame/views.cljs b/src/renderer/frame/views.cljs index 3d0eb5b6..c0dc9a7e 100644 --- a/src/renderer/frame/views.cljs +++ b/src/renderer/frame/views.cljs @@ -23,7 +23,8 @@ (let [frame-window (.-window (useFrame))] (reagent/create-class {:component-did-mount - #(.addEventListener frame-window "wheel" event.impl.wheel/handler! #js {:passive false}) + #(.addEventListener frame-window "wheel" event.impl.wheel/handler! + #js {:passive false}) :component-will-unmount #(.removeEventListener frame-window "wheel" event.impl.wheel/handler!) diff --git a/src/renderer/notification/views.cljs b/src/renderer/notification/views.cljs index 02278c36..2d5fdd46 100644 --- a/src/renderer/notification/views.cljs +++ b/src/renderer/notification/views.cljs @@ -42,8 +42,9 @@ [:div.fixed.flex.flex-col.m-4.right-0.bottom-0.gap-2.items-end (map-indexed (fn [index notification] - [:div.relative.flex.bg-secondary.w-80.p-4.mb-2.rounded.shadow-md.border.border-default - {:key index} + [:div.relative.flex.bg-secondary.w-80.p-4.mb-2.rounded.shadow-md + {:key index + :class "border border-default"} (:content notification) [views/icon-button "times" diff --git a/src/renderer/reepl/replumb.cljs b/src/renderer/reepl/replumb.cljs index d02981c7..179b3172 100644 --- a/src/renderer/reepl/replumb.cljs +++ b/src/renderer/reepl/replumb.cljs @@ -238,8 +238,10 @@ cljs.js/*load-fn* [mode text] (let [parts (vec (.split text ".")) completion (or (last parts) "") - prefix #(str (when (= mode :cljs) "js/") (string/join "." (conj (vec (butlast parts)) %))) - possibles (js-attrs (reduce aget js/window (butlast parts)))] + possibles (js-attrs (reduce aget js/window (butlast parts))) + prefix #(->> (conj (vec (butlast parts)) %) + (string/join ".") + (str (when (= mode :cljs) "js/")))] (->> possibles (filter #(not= -1 (.indexOf % completion))) (sort (partial compare-completion text)) diff --git a/src/renderer/reepl/views.cljs b/src/renderer/reepl/views.cljs index e900fe30..a0d145d8 100644 --- a/src/renderer/reepl/views.cljs +++ b/src/renderer/reepl/views.cljs @@ -100,7 +100,8 @@ {:ref ref} (into [:div.p-1] - (map (fn [i] [:div.font-mono.p-1.flex.text-xs.min-h-4 (item i opts)]) items))]])}))) + (map (fn [i] + [:div.font-mono.p-1.flex.text-xs.min-h-4 (item i opts)]) items))]])}))) (defn repl-items-panel [items show-value-opts set-text] @@ -232,17 +233,17 @@ (defn root [] - [repl - :execute #(replumb/run-repl (if (= @(rf/subscribe [::app.subs/repl-mode]) :cljs) - %1 - (str "(js/eval \"" %1 "\")")) - {:verbose @(rf/subscribe [::app.subs/debug-info])} %2) - :complete-word (fn [text] (replumb/process-apropos @(rf/subscribe [::app.subs/repl-mode]) text)) - :get-docs replumb/process-doc - :state state - :show-value-opts - {:showers [show-devtools/show-devtools - (partial show-function/show-fn-with-docs maybe-fn-docs)]} - :js-cm-opts {:mode (if (= @(rf/subscribe [::app.subs/repl-mode]) :cljs) "clojure" "javascript") - :keyMap "default" - :showCursorWhenSelecting true}]) + (let [repl-mode (rf/subscribe [::app.subs/repl-mode]) + debug-info (rf/subscribe [::app.subs/debug-info])] + [repl + :execute #(replumb/run-repl (if (= @repl-mode :cljs) %1 (str "(js/eval \"" %1 "\")")) + {:verbose @debug-info} %2) + :complete-word (fn [text] (replumb/process-apropos @repl-mode text)) + :get-docs replumb/process-doc + :state state + :show-value-opts + {:showers [show-devtools/show-devtools + (partial show-function/show-fn-with-docs maybe-fn-docs)]} + :js-cm-opts {:mode (if (= @repl-mode :cljs) "clojure" "javascript") + :keyMap "default" + :showCursorWhenSelecting true}])) diff --git a/src/renderer/tool/impl/base/transform.cljs b/src/renderer/tool/impl/base/transform.cljs index 35ca57a4..9bc286da 100644 --- a/src/renderer/tool/impl/base/transform.cljs +++ b/src/renderer/tool/impl/base/transform.cljs @@ -279,7 +279,8 @@ offset)] (reduce (fn [db id] (let [container (element.handlers/parent-container db id) - hovered-svg (element.handlers/hovered-svg db)] + hovered-svg (element.handlers/hovered-svg db) + start-point (fn [el] (into [] (take 2) (:bbox el)))] (cond-> (element.handlers/translate db id offset) (and (seq (element.handlers/selected db)) (empty? (rest (element.handlers/selected db))) @@ -292,10 +293,10 @@ ;; FIXME: Handle nested containers. (:bbox container) - (element.handlers/translate id (vec (take 2 (:bbox container)))) + (element.handlers/translate id (start-point container)) (:bbox hovered-svg) - (element.handlers/translate id (matrix/mul (take 2 (:bbox hovered-svg)) + (element.handlers/translate id (matrix/mul (start-point hovered-svg) -1)))))) db (element.handlers/top-ancestor-ids db)))) @@ -402,7 +403,8 @@ (defmethod tool.hierarchy/snapping-elements :transform [db] (let [non-selected-ids (element.handlers/non-selected-ids db) - non-selected (select-keys (element.handlers/entities db) (vec non-selected-ids))] + els (element.handlers/entities db) + non-selected (select-keys els (vec non-selected-ids))] (filter :visible (vals non-selected)))) (m/=> size-label [:-> BBox any?]) diff --git a/src/renderer/tool/impl/element/text.cljs b/src/renderer/tool/impl/element/text.cljs index 0d7dd64f..7dc9422e 100644 --- a/src/renderer/tool/impl/element/text.cljs +++ b/src/renderer/tool/impl/element/text.cljs @@ -20,7 +20,8 @@ (defmethod tool.hierarchy/on-pointer-up :text [db _e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) el {:type :element :tag :text :attrs {:x offset-x diff --git a/src/renderer/tool/impl/extension/blob.cljs b/src/renderer/tool/impl/extension/blob.cljs index 6f3f9465..f14c8a47 100644 --- a/src/renderer/tool/impl/extension/blob.cljs +++ b/src/renderer/tool/impl/extension/blob.cljs @@ -6,6 +6,7 @@ [renderer.element.handlers :as element.handlers] [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] + [renderer.reepl.db :as db] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -17,39 +18,44 @@ (defn pointer-delta [db] - (matrix/distance (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) - (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)))) + (matrix/distance (or (:point (:nearest-neighbor db)) + (:adjusted-pointer-pos db)) + (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)))) -(defn create +(defn attributes [db] (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) - radius (pointer-delta db) - fill (document.handlers/attr db :fill) - stroke (document.handlers/attr db :stroke)] + radius (pointer-delta db)] + {:x (- offset-x radius) + :y (- offset-y radius) + :size (* radius 2)})) + +(defn create + [db] + (let [fill (document.handlers/attr db :fill) + stroke (document.handlers/attr db :stroke) + seed (rand-int 1000000)] (-> (tool.handlers/set-state db :create) (element.handlers/add {:type :element :tag :blob - :attrs {:x (- offset-x radius) - :y (- offset-y radius) - :seed (rand-int 1000000) - :extraPoints 8 - :randomness 4 - :size (* radius 2) - :fill fill - :stroke stroke}})))) + :attrs (merge (attributes db/initial-state) + {:seed seed + :extraPoints 8 + :randomness 4 + :fill fill + :stroke stroke})})))) (defn update-size [db] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) - radius (pointer-delta db) + (let [attrs (attributes db) + assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v))) {:keys [id parent]} (first (element.handlers/selected db)) - [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent))] + el (element.handlers/entity db parent) + [min-x min-y] (element.hierarchy/bbox el)] (-> db - (element.handlers/update-el id #(-> % - (assoc-in [:attrs :x] (str (- offset-x radius))) - (assoc-in [:attrs :y] (str (- offset-y radius))) - (assoc-in [:attrs :size] (str (* radius 2))))) + (element.handlers/update-el id #(reduce assoc-attr % attrs)) (element.handlers/translate [(- min-x) (- min-y)])))) (defmethod tool.hierarchy/on-pointer-up :blob diff --git a/src/renderer/tool/impl/misc/measure.cljs b/src/renderer/tool/impl/misc/measure.cljs index 33b48684..7e7a54db 100644 --- a/src/renderer/tool/impl/misc/measure.cljs +++ b/src/renderer/tool/impl/misc/measure.cljs @@ -38,7 +38,8 @@ (defmethod tool.hierarchy/on-drag :measure [db _e] - (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) + (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) + (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) [adjacent opposite] (matrix/sub [offset-x offset-y] [x y]) hypotenuse (Math/hypot adjacent opposite)] diff --git a/src/renderer/tree/views.cljs b/src/renderer/tree/views.cljs index 2e766689..ec818f0f 100644 --- a/src/renderer/tree/views.cljs +++ b/src/renderer/tree/views.cljs @@ -18,11 +18,12 @@ [renderer.utils.element :as utils.element] [renderer.views :as views])) -(defn toggle-item-prop-button +(defn item-prop-toggle [id state k active-icon inactive-icon active-title inactive-title] [views/icon-button (if state active-icon inactive-icon) - {:class ["hover:bg-transparent text-inherit hover:text-inherit focus:outline-hidden small" + {:class ["hover:bg-transparent text-inherit hover:text-inherit + focus:outline-hidden small" (when-not state "invisible")] :title (if state active-title inactive-title) :on-double-click #(.stopPropagation %) @@ -47,7 +48,8 @@ :default-value label :placeholder tag-label :auto-focus true - :on-key-down #(event.impl.keyboard/input-key-down-handler! % label set-item-label! id) + :on-key-down #(event.impl.keyboard/input-key-down-handler! % label + set-item-label! id) :on-blur (fn [e] (reset! edit-mode? false) (set-item-label! e id))}] @@ -103,7 +105,8 @@ [views/icon-button (if collapsed "chevron-right" "chevron-down") {:title (if collapsed "expand" "collapse") - :class "hover:bg-transparent text-inherit hover:text-inherit focus:outline-hidden small" + :class "hover:bg-transparent text-inherit hover:text-inherit + focus:outline-hidden small" :on-double-click #(.stopPropagation %) :on-click #(do (.stopPropagation %) (rf/dispatch (if collapsed @@ -115,8 +118,8 @@ (let [{:keys [id selected children locked visible]} el collapse-button-width 21 padding (* collapse-button-width (cond-> depth (seq children) dec))] - [:div.list-item-button.button.flex.pr-1.items-center.text-start.outline-default.hover:overlay - {:class ["[&.hovered]:overlay hover:[&_button]:visible" + [:div.list-item-button.button.flex.pr-1.items-center.text-start.outline-default + {:class ["hover:overlay [&.hovered]:overlay hover:[&_button]:visible" (when selected "accent") (when hovered "hovered")] :tab-index 0 @@ -150,8 +153,8 @@ (when-let [icon (:icon (utils.element/properties el))] [views/icon icon {:class (when-not visible "opacity-60")}]) [item-label el]] - [toggle-item-prop-button id locked :locked "lock" "unlock" "unlock" "lock"] - [toggle-item-prop-button id (not visible) :visible "eye-closed" "eye" "show" "hide"]]])) + [item-prop-toggle id locked :locked "lock" "unlock" "unlock" "lock"] + [item-prop-toggle id (not visible) :visible "eye-closed" "eye" "show" "hide"]]])) (defn item [el depth elements] (let [{:keys [selected children id]} el diff --git a/src/renderer/utils/element.cljs b/src/renderer/utils/element.cljs index afa42819..0132ea51 100644 --- a/src/renderer/utils/element.cljs +++ b/src/renderer/utils/element.cljs @@ -95,14 +95,15 @@ ([el] (->path el (element.hierarchy/path el))) ([el d] - (cond - (string? d) - (-> (assoc el :tag :path) - (update :attrs #(utils.map/merge-common-with str % (utils.attribute/defaults-memo :path))) - (assoc-in [:attrs :d] d)) + (let [default-attrs (utils.attribute/defaults-memo :path)] + (cond + (string? d) + (-> (assoc el :tag :path) + (update :attrs #(utils.map/merge-common-with str % default-attrs)) + (assoc-in [:attrs :d] d)) - (instance? js/Promise d) - (.then d (fn [d] (->path el d)))))) + (instance? js/Promise d) + (.then d (fn [d] (->path el d))))))) (m/=> stroke->path [:-> Element Element]) (defn stroke->path @@ -114,10 +115,11 @@ (/ el-offset 2) #js {:cap (or (:stroke-linecap attrs) "butt") :join (or (:stroke-linejoin attrs) "miter")}) - new-d (.getAttribute (.exportSVG stroke-path) "d")] + new-d (.getAttribute (.exportSVG stroke-path) "d") + default-attrs (utils.attribute/defaults-memo :path)] (-> (assoc el :tag :path) (update :attrs dissoc :stroke :stroke-width) - (update :attrs #(utils.map/merge-common-with str % (utils.attribute/defaults-memo :path))) + (update :attrs #(utils.map/merge-common-with str % default-attrs)) (assoc-in [:attrs :d] new-d) (assoc-in [:attrs :fill] (:stroke attrs))))) diff --git a/src/renderer/window/views.cljs b/src/renderer/window/views.cljs index 116e421c..5da150df 100644 --- a/src/renderer/window/views.cljs +++ b/src/renderer/window/views.cljs @@ -50,8 +50,8 @@ [:div.flex.relative.bg-secondary {:class (when (and mac? (not fullscreen?)) "ml-16")} [menubar.views/root]] - [:div.absolute.hidden.justify-center.drag.grow.h-full.items-center.pointer-events-none - {:class "md:flex left-1/2 -translate-x-1/2" + [:div.absolute.hidden.justify-center.drag.grow.h-full.items-center + {:class "pointer-events-none md:flex left-1/2 -translate-x-1/2" :style {:z-index -1}} @(rf/subscribe [::document.subs/title-bar])] [:div.flex.h-full.flex-1.drag] diff --git a/src/renderer/worker/effects.cljs b/src/renderer/worker/effects.cljs index cff8d640..06d65e67 100644 --- a/src/renderer/worker/effects.cljs +++ b/src/renderer/worker/effects.cljs @@ -14,6 +14,8 @@ #(let [response-data (js->clj (.. % -data) :keywordize-keys true)] (rf/dispatch [::worker.events/message id on-success response-data]))) - (.addEventListener worker "error" #(rf/dispatch [::worker.events/message id on-error %])) + (.addEventListener worker + "error" + #(rf/dispatch [::worker.events/message id on-error %])) (.postMessage worker (clj->js data))))) diff --git a/test/document_test.cljs b/test/document_test.cljs index b38706ed..bfe63697 100644 --- a/test/document_test.cljs +++ b/test/document_test.cljs @@ -12,147 +12,150 @@ (rf.test/run-test-sync (rf/dispatch [::app.events/initialize-db]) - (testing "defaults" - (is (not @(rf/subscribe [::document.subs/entities?]))) - (is (not @(rf/subscribe [::document.subs/active])))) - - (testing "initialization" - (rf/dispatch [::document.events/init]) - (is @(rf/subscribe [::document.subs/entities?])) - (is (document.db/valid? @(rf/subscribe [::document.subs/active]))) - (is (= "• Untitled-1 - Repath Studio" @(rf/subscribe [::document.subs/title-bar])))) - - (testing "close" - (rf/dispatch [::document.events/close @(rf/subscribe [::document.subs/active-id]) false]) - (is (not @(rf/subscribe [::document.subs/active])))) - - (testing "close active" - (rf/dispatch [::document.events/new]) - (rf/dispatch [::document.events/saved @(rf/subscribe [::document.subs/active])]) - (rf/dispatch [::document.events/close-active]) - (is (not @(rf/subscribe [::document.subs/active])))) - - (testing "close saved" - (rf/dispatch [::document.events/new]) - (rf/dispatch [::document.events/new]) - (rf/dispatch [::document.events/saved @(rf/subscribe [::document.subs/active])]) - (rf/dispatch [::document.events/close-saved]) - (is (= (count @(rf/subscribe [::document.subs/entities])) 1))) - - (testing "close all" - (rf/dispatch [::document.events/saved @(rf/subscribe [::document.subs/active])]) - (rf/dispatch [::document.events/close-all]) - (is (not @(rf/subscribe [::document.subs/active])))) - - (testing "create" - (rf/dispatch [::document.events/new]) - (is (= "• Untitled-1 - Repath Studio" @(rf/subscribe [::document.subs/title-bar]))) - - (rf/dispatch [::document.events/new-from-template [800 600]]) - (is (= "• Untitled-2 - Repath Studio" @(rf/subscribe [::document.subs/title-bar]))) - (is (= "800" (->> @(rf/subscribe [::document.subs/elements]) - (vals) - (filter #(= (:tag %) :svg)) - (first) - :attrs - :width)))) - - (testing "colors" - (let [fill (rf/subscribe [::document.subs/fill]) - stroke (rf/subscribe [::document.subs/stroke])] - (testing "default color values" - (is (= @fill "white")) - (is (= @stroke "black"))) - - (testing "swap colors" - (rf/dispatch [::document.events/swap-colors]) - (is (= @fill "black")) - (is (= @stroke "white"))) - - (testing "set fill" - (rf/dispatch [::document.events/set-attr :fill "red"]) - (is (= @fill "red"))) - - (testing "set stroke" - (rf/dispatch [::document.events/set-attr :stroke "yellow"]) - (is (= @stroke "yellow"))))) - - (testing "filters" - (let [active-filter (rf/subscribe [::document.subs/filter])] + (let [document-entities? (rf/subscribe [::document.subs/entities?]) + active-document (rf/subscribe [::document.subs/active]) + saved? (rf/subscribe [::document.subs/active-saved?]) + title-bar (rf/subscribe [::document.subs/title-bar]) + active-id (rf/subscribe [::document.subs/active-id])] + (testing "defaults" + (is (not @document-entities?)) + (is (not @active-document))) + + (testing "initialization" + (rf/dispatch [::document.events/init]) + (is @document-entities?) + (is (document.db/valid? @active-document)) + (is (= "• Untitled-1 - Repath Studio" @title-bar))) + + (testing "close" + (rf/dispatch [::document.events/close @active-id false]) + (is (not @active-document))) + + (testing "close active" + (rf/dispatch [::document.events/new]) + (rf/dispatch [::document.events/saved @active-document]) + (rf/dispatch [::document.events/close-active]) + (is (not @active-document))) + + (testing "close saved" + (rf/dispatch [::document.events/new]) + (rf/dispatch [::document.events/new]) + (rf/dispatch [::document.events/saved @active-document]) + (rf/dispatch [::document.events/close-saved]) + (is (= (count @(rf/subscribe [::document.subs/entities])) 1))) + + (testing "close all" + (rf/dispatch [::document.events/saved @active-document]) + (rf/dispatch [::document.events/close-all]) + (is (not @active-document))) + + (testing "create" + (rf/dispatch [::document.events/new]) + (is (= "• Untitled-1 - Repath Studio" @title-bar)) + + (rf/dispatch [::document.events/new-from-template [800 600]]) + (is (= "• Untitled-2 - Repath Studio" @title-bar)) + (is (= "800" (->> @(rf/subscribe [::document.subs/elements]) + (vals) + (filter #(= (:tag %) :svg)) + (first) + :attrs + :width)))) + + (testing "colors" + (let [fill (rf/subscribe [::document.subs/fill]) + stroke (rf/subscribe [::document.subs/stroke])] + (testing "default color values" + (is (= @fill "white")) + (is (= @stroke "black"))) + + (testing "swap colors" + (rf/dispatch [::document.events/swap-colors]) + (is (= @fill "black")) + (is (= @stroke "white"))) + + (testing "set fill" + (rf/dispatch [::document.events/set-attr :fill "red"]) + (is (= @fill "red"))) + + (testing "set stroke" + (rf/dispatch [::document.events/set-attr :stroke "yellow"]) + (is (= @stroke "yellow"))))) + + (testing "filters" + (let [active-filter (rf/subscribe [::document.subs/filter])] + (testing "default state" + (is (not @active-filter))) + + (testing "enable filter" + (rf/dispatch [::document.events/toggle-filter :blur]) + (is (= @active-filter :blur))) + + (testing "change active filter" + (rf/dispatch [::document.events/toggle-filter :deuteranopia]) + (is (= @active-filter :deuteranopia))) + + (testing "disable filter" + (rf/dispatch [::document.events/toggle-filter :deuteranopia]) + (is (not @active-filter))))) + + (testing "collapse/expand elements" + (let [collapsed-ids (rf/subscribe [::document.subs/collapsed-ids]) + id (random-uuid)] + (testing "default state" + (is (empty? @collapsed-ids))) + + (testing "collapse" + (rf/dispatch [::document.events/collapse-el id]) + (is (= #{id} @collapsed-ids))) + + (testing "expand" + (rf/dispatch [::document.events/expand-el id]) + (is (empty? @collapsed-ids))))) + + (testing "hover elements" + (let [hovered-ids (rf/subscribe [::document.subs/hovered-ids]) + id (random-uuid)] + (testing "default state" + (is (empty? @hovered-ids))) + + (testing "hover" + (rf/dispatch [::document.events/set-hovered-id id]) + (is (= #{id} @hovered-ids))) + + (testing "clear hovered" + (rf/dispatch [::document.events/clear-hovered]) + (is (empty? @hovered-ids))))) + + (testing "save" (testing "default state" - (is (not @active-filter))) - - (testing "enable filter" - (rf/dispatch [::document.events/toggle-filter :blur]) - (is (= @active-filter :blur))) - - (testing "change active filter" - (rf/dispatch [::document.events/toggle-filter :deuteranopia]) - (is (= @active-filter :deuteranopia))) - - (testing "disable filter" - (rf/dispatch [::document.events/toggle-filter :deuteranopia]) - (is (not @active-filter))))) - - (testing "collapse/expand elements" - (let [collapsed-ids (rf/subscribe [::document.subs/collapsed-ids]) - id (random-uuid)] - (testing "default state" - (is (empty? @collapsed-ids))) - - (testing "collapse" - (rf/dispatch [::document.events/collapse-el id]) - (is (= #{id} @collapsed-ids))) - - (testing "expand" - (rf/dispatch [::document.events/expand-el id]) - (is (empty? @collapsed-ids))))) - - (testing "hover elements" - (let [hovered-ids (rf/subscribe [::document.subs/hovered-ids]) - id (random-uuid)] - (testing "default state" - (is (empty? @hovered-ids))) - - (testing "hover" - (rf/dispatch [::document.events/set-hovered-id id]) - (is (= #{id} @hovered-ids))) - - (testing "clear hovered" - (rf/dispatch [::document.events/clear-hovered]) - (is (empty? @hovered-ids))))) - - (testing "save" - (let [saved (rf/subscribe [::document.subs/active-saved?]) - active-document (rf/subscribe [::document.subs/active]) - id (:id @active-document)] - (testing "default state" - (is (not @saved))) + (is (not @saved?))) (testing "save" (rf/dispatch [::document.events/saved @active-document]) - (is @saved) - (is @(rf/subscribe [::document.subs/saved? id]))))) - - (testing "load" - (rf/dispatch [::document.events/load {:version "100000.0.0" ; Skips migrations. - :path "foo/bar/document.rps" - :title "document.rps" - :elements {}}]) - - (is @(rf/subscribe [::document.subs/active-saved?])) - (is (= "foo/bar/document.rps - Repath Studio" @(rf/subscribe [::document.subs/title-bar])))) - - (testing "load multiple" - (rf/dispatch [::document.events/load-multiple [{:version "100000.0.0" - :path "foo/bar/document-1.rps" - :title "document-1.rps" - :elements {}} - {:version "100000.0.0" - :path "foo/bar/document-2.rps" - :title "document-2.rps" - :elements {}}]]) - - (is (= (:title @(rf/subscribe [::document.subs/active])) "document-2.rps")) - (is (= (take 2 @(rf/subscribe [::document.subs/recent])) ["foo/bar/document-2.rps" - "foo/bar/document-1.rps"]))))) + (is @saved?) + (is @(rf/subscribe [::document.subs/saved? (:id @active-document)])))) + + (testing "load" + (rf/dispatch [::document.events/load {:version "100000.0.0" ; Skips migrations. + :path "foo/bar/document.rps" + :title "document.rps" + :elements {}}]) + + (is @(rf/subscribe [::document.subs/active-saved?])) + (is (= "foo/bar/document.rps - Repath Studio" @title-bar))) + + (testing "load multiple" + (let [recent-documents (rf/subscribe [::document.subs/recent])] + (rf/dispatch [::document.events/load-multiple [{:version "100000.0.0" + :path "foo/bar/document-1.rps" + :title "document-1.rps" + :elements {}} + {:version "100000.0.0" + :path "foo/bar/document-2.rps" + :title "document-2.rps" + :elements {}}]]) + + (is (= (:title @active-document) "document-2.rps")) + (is (= (take 2 @recent-documents) ["foo/bar/document-2.rps" + "foo/bar/document-1.rps"]))))))) From e451f9d73cd150e7002347dd9e9b96b2f4b192cc Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 22:12:23 +0300 Subject: [PATCH 30/31] simplify tools --- src/renderer/tool/impl/element/circle.cljs | 36 ++++--------------- src/renderer/tool/impl/element/ellipse.cljs | 40 +++++---------------- src/renderer/tool/impl/element/line.cljs | 30 +++------------- src/renderer/tool/impl/element/rect.cljs | 40 +++++---------------- src/renderer/tool/impl/extension/blob.cljs | 33 +++-------------- 5 files changed, 31 insertions(+), 148 deletions(-) diff --git a/src/renderer/tool/impl/element/circle.cljs b/src/renderer/tool/impl/element/circle.cljs index 37ec8de3..86f1c683 100644 --- a/src/renderer/tool/impl/element/circle.cljs +++ b/src/renderer/tool/impl/element/circle.cljs @@ -14,8 +14,8 @@ [] {:icon "circle-tool"}) -(defn create - [db] +(defmethod tool.hierarchy/on-drag-start :circle + [db _e] (let [offset (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) radius (matrix/distance position offset) @@ -31,44 +31,20 @@ :stroke stroke :r radius}})))) -(defn update-radius - [db] +(defmethod tool.hierarchy/on-drag :circle + [db _e] (let [offset (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) radius (.toFixed (matrix/distance position offset) 3) id (:id (first (element.handlers/selected db)))] (element.handlers/update-el db id #(assoc-in % [:attrs :r] (str radius))))) -(defn finalize - [db] +(defmethod tool.hierarchy/on-drag-end :circle + [db _e] (-> db (history.handlers/finalize "Create circle") (tool.handlers/activate :transform))) -(defmethod tool.hierarchy/on-pointer-up :circle - [db _e] - (if (= (:state db) :create) - (finalize db) - (create db))) - -(defmethod tool.hierarchy/on-pointer-move :circle - [db _e] - (cond-> db - (= (:state db) :create) - (update-radius))) - -(defmethod tool.hierarchy/on-drag-start :circle - [db _e] - (create db)) - -(defmethod tool.hierarchy/on-drag :circle - [db _e] - (update-radius db)) - -(defmethod tool.hierarchy/on-drag-end :circle - [db _e] - (finalize db)) - (defmethod tool.hierarchy/snapping-points :circle [db] [(with-meta diff --git a/src/renderer/tool/impl/element/ellipse.cljs b/src/renderer/tool/impl/element/ellipse.cljs index 22e6acba..f226e701 100644 --- a/src/renderer/tool/impl/element/ellipse.cljs +++ b/src/renderer/tool/impl/element/ellipse.cljs @@ -28,8 +28,8 @@ {:rx (cond-> rx lock-ratio (min ry)) :ry (cond-> ry lock-ratio (min rx))})) -(defn create - [db lock-ratio] +(defmethod tool.hierarchy/on-drag-start :ellipse + [db e] (let [[x y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) fill (document.handlers/attr db :fill) @@ -38,45 +38,21 @@ (tool.handlers/set-state :create) (element.handlers/add {:type :element :tag :ellipse - :attrs (merge (attributes db lock-ratio) + :attrs (merge (attributes db (:ctrl-key e)) {:cx x :cy y :fill fill :stroke stroke})})))) -(defn update-radius - [db lock-ratio] - (let [attrs (attributes db lock-ratio) +(defmethod tool.hierarchy/on-drag :ellipse + [db e] + (let [attrs (attributes db (:ctrl-key e)) assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v))) id (:id (first (element.handlers/selected db)))] (element.handlers/update-el db id #(reduce assoc-attr % attrs)))) -(defn finalize - [db] +(defmethod tool.hierarchy/on-drag-end :ellipse + [db _e] (-> db (history.handlers/finalize "Create ellipse") (tool.handlers/activate :transform))) - -(defmethod tool.hierarchy/on-pointer-up :ellipse - [db e] - (if (= (:state db) :create) - (finalize db) - (create db (:ctrl-key e)))) - -(defmethod tool.hierarchy/on-pointer-move :ellipse - [db e] - (cond-> db - (= (:state db) :create) - (update-radius (:ctrl-key e)))) - -(defmethod tool.hierarchy/on-drag-start :ellipse - [db e] - (create db (:ctrl-key e))) - -(defmethod tool.hierarchy/on-drag :ellipse - [db e] - (update-radius db (:ctrl-key e))) - -(defmethod tool.hierarchy/on-drag-end :ellipse - [db _e] - (finalize db)) diff --git a/src/renderer/tool/impl/element/line.cljs b/src/renderer/tool/impl/element/line.cljs index 3d6a9fd7..1a17a35d 100644 --- a/src/renderer/tool/impl/element/line.cljs +++ b/src/renderer/tool/impl/element/line.cljs @@ -15,8 +15,8 @@ [] {:icon "line-tool"}) -(defn create - [db] +(defmethod tool.hierarchy/on-drag-start :line + [db _e] (let [[offset-x offset-y] (or (:nearest-neighbor-offset db) (:adjusted-pointer-offset db)) [x y] (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) @@ -31,8 +31,8 @@ :y2 y :stroke stroke}})))) -(defn update-end - [db] +(defmethod tool.hierarchy/on-drag :line + [db _e] (let [position (or (:point (:nearest-neighbor db)) (:adjusted-pointer-pos db)) {:keys [id parent]} (first (element.handlers/selected db)) [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent)) @@ -43,28 +43,6 @@ (assoc-in [:attrs :x2] (str x)) (assoc-in [:attrs :y2] (str y)))))) -(defmethod tool.hierarchy/on-pointer-move :line - [db _e] - (cond-> db - (= (:state db) :create) - (update-end))) - -(defmethod tool.hierarchy/on-pointer-up :line - [db _e] - (if (= (:state db) :create) - (-> db - (history.handlers/finalize "Create line") - (tool.handlers/activate :transform)) - (create db))) - -(defmethod tool.hierarchy/on-drag-start :line - [db _e] - (create db)) - -(defmethod tool.hierarchy/on-drag :line - [db _e] - (update-end db)) - (defmethod tool.hierarchy/on-drag-end :line [db _e] (-> db diff --git a/src/renderer/tool/impl/element/rect.cljs b/src/renderer/tool/impl/element/rect.cljs index 792dbf98..05b171ad 100644 --- a/src/renderer/tool/impl/element/rect.cljs +++ b/src/renderer/tool/impl/element/rect.cljs @@ -31,21 +31,21 @@ :width (cond-> width lock-ratio (min height)) :height (cond-> height lock-ratio (min width))})) -(defn create - [db lock-ratio] +(defmethod tool.hierarchy/on-drag-start :rect + [db e] (let [fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke)] (-> db (tool.handlers/set-state :create) (element.handlers/add {:type :element :tag :rect - :attrs (merge (attributes db lock-ratio) + :attrs (merge (attributes db (:ctrl-key e)) {:fill fill :stroke stroke})})))) -(defn update-size - [db lock-ratio] - (let [attrs (attributes db lock-ratio) +(defmethod tool.hierarchy/on-drag :rect + [db e] + (let [attrs (attributes db (:ctrl-key e)) assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v))) {:keys [id parent]} (first (element.handlers/selected db)) [min-x min-y] (element.hierarchy/bbox (element.handlers/entity db parent))] @@ -53,32 +53,8 @@ (element.handlers/update-el id #(reduce assoc-attr % attrs)) (element.handlers/translate [(- min-x) (- min-y)])))) -(defn finalize - [db] +(defmethod tool.hierarchy/on-drag-end :rect + [db _e] (-> db (history.handlers/finalize "Create rectangle") (tool.handlers/activate :transform))) - -(defmethod tool.hierarchy/on-pointer-up :rect - [db e] - (if (= (:state db) :create) - (finalize db) - (create db (:ctrl-key e)))) - -(defmethod tool.hierarchy/on-pointer-move :rect - [db e] - (cond-> db - (= (:state db) :create) - (update-size (:ctrl-key e)))) - -(defmethod tool.hierarchy/on-drag-start :rect - [db e] - (create db (:ctrl-key e))) - -(defmethod tool.hierarchy/on-drag :rect - [db e] - (update-size db (:ctrl-key e))) - -(defmethod tool.hierarchy/on-drag-end :rect - [db _e] - (finalize db)) diff --git a/src/renderer/tool/impl/extension/blob.cljs b/src/renderer/tool/impl/extension/blob.cljs index f14c8a47..5ae2ec08 100644 --- a/src/renderer/tool/impl/extension/blob.cljs +++ b/src/renderer/tool/impl/extension/blob.cljs @@ -6,7 +6,6 @@ [renderer.element.handlers :as element.handlers] [renderer.element.hierarchy :as element.hierarchy] [renderer.history.handlers :as history.handlers] - [renderer.reepl.db :as db] [renderer.tool.handlers :as tool.handlers] [renderer.tool.hierarchy :as tool.hierarchy])) @@ -32,23 +31,23 @@ :y (- offset-y radius) :size (* radius 2)})) -(defn create - [db] +(defmethod tool.hierarchy/on-drag-start :blob + [db _e] (let [fill (document.handlers/attr db :fill) stroke (document.handlers/attr db :stroke) seed (rand-int 1000000)] (-> (tool.handlers/set-state db :create) (element.handlers/add {:type :element :tag :blob - :attrs (merge (attributes db/initial-state) + :attrs (merge (attributes db) {:seed seed :extraPoints 8 :randomness 4 :fill fill :stroke stroke})})))) -(defn update-size - [db] +(defmethod tool.hierarchy/on-drag :blob + [db _e] (let [attrs (attributes db) assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v))) {:keys [id parent]} (first (element.handlers/selected db)) @@ -58,28 +57,6 @@ (element.handlers/update-el id #(reduce assoc-attr % attrs)) (element.handlers/translate [(- min-x) (- min-y)])))) -(defmethod tool.hierarchy/on-pointer-up :blob - [db _e] - (if (= (:state db) :create) - (-> db - (history.handlers/finalize "Create blob") - (tool.handlers/activate :transform)) - (create db))) - -(defmethod tool.hierarchy/on-pointer-move :blob - [db _e] - (cond-> db - (= (:state db) :create) - (update-size))) - -(defmethod tool.hierarchy/on-drag-start :blob - [db _e] - (create db)) - -(defmethod tool.hierarchy/on-drag :blob - [db _e] - (update-size db)) - (defmethod tool.hierarchy/on-drag-end :blob [db _e] (-> db From d6d9a404b80b63ad78cd53e58adc9aff2f0f6f8e Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 12 Jun 2025 22:14:38 +0300 Subject: [PATCH 31/31] simplify svg tool --- src/renderer/tool/impl/element/svg.cljs | 40 +++++-------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/src/renderer/tool/impl/element/svg.cljs b/src/renderer/tool/impl/element/svg.cljs index 75961cff..0e68385b 100644 --- a/src/renderer/tool/impl/element/svg.cljs +++ b/src/renderer/tool/impl/element/svg.cljs @@ -28,47 +28,23 @@ :width (cond-> width lock-ratio (min height)) :height (cond-> height lock-ratio (min width))})) -(defn create - [db lock-ratio] +(defmethod tool.hierarchy/on-drag-start :svg + [db e] (-> db (tool.handlers/set-state :create) (element.handlers/add {:tag :svg :type :element - :attrs (attributes db lock-ratio)}))) + :attrs (attributes db (:ctrl-key e))}))) -(defn update-size - [db lock-ratio] +(defmethod tool.hierarchy/on-drag :svg + [db e] (let [id (:id (first (element.handlers/selected db))) - attrs (attributes db lock-ratio) + attrs (attributes db (:ctrl-key e)) assoc-attr (fn [el [k v]] (assoc-in el [:attrs k] (str v)))] (element.handlers/update-el db id #(reduce assoc-attr % attrs)))) -(defn finalize - [db] +(defmethod tool.hierarchy/on-drag-end :svg + [db _e] (-> db (history.handlers/finalize "Create SVG") (tool.handlers/activate :transform))) - -(defmethod tool.hierarchy/on-pointer-up :svg - [db e] - (if (= (:state db) :create) - (finalize db) - (create db (:ctrl-key e)))) - -(defmethod tool.hierarchy/on-pointer-move :svg - [db e] - (cond-> db - (= (:state db) :create) - (update-size (:ctrl-key e)))) - -(defmethod tool.hierarchy/on-drag-start :svg - [db e] - (create db (:ctrl-key e))) - -(defmethod tool.hierarchy/on-drag :svg - [db e] - (update-size db (:ctrl-key e))) - -(defmethod tool.hierarchy/on-drag-end :svg - [db _e] - (finalize db))