Skip to content

Tool enhancements #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9d522bc
rename primary-tool to cached-tool
sprocketc Jun 12, 2025
00d3edd
enhance circle tool
sprocketc Jun 12, 2025
ee3fcb9
enhance ellipse tool
sprocketc Jun 12, 2025
48ee339
enhance line tool
sprocketc Jun 12, 2025
9168f16
enhance rect tool
sprocketc Jun 12, 2025
013ba32
enhance svg tool
sprocketc Jun 12, 2025
d6df665
enhance blob tool
sprocketc Jun 12, 2025
f57f6e8
reset history on tool activation
sprocketc Jun 12, 2025
63fd55d
fix reset state
sprocketc Jun 12, 2025
d63aee2
precision fixes
sprocketc Jun 12, 2025
e706181
enhance pen tool
sprocketc Jun 12, 2025
7bbfa5a
enhance measure tool
sprocketc Jun 12, 2025
28b301a
fix circle snap meta
sprocketc Jun 12, 2025
6a6de43
enhance zoom tool
sprocketc Jun 12, 2025
f9d6c60
remove side effects from events
sprocketc Jun 12, 2025
21943d9
enhance transform tool
sprocketc Jun 12, 2025
2c9354e
enhance brush tool
sprocketc Jun 12, 2025
1d84017
enhance polyshape tool
sprocketc Jun 12, 2025
7bea508
remove temp element leftovers
sprocketc Jun 12, 2025
ef4d589
introduce cached state
sprocketc Jun 12, 2025
582a828
remove unneeded deselect
sprocketc Jun 12, 2025
ba247a1
fix reset state
sprocketc Jun 12, 2025
a15c6f2
fix offset on create
sprocketc Jun 12, 2025
666edca
refactor
sprocketc Jun 12, 2025
8bd4db8
fix text create
sprocketc Jun 12, 2025
9a285e3
enhance disabled state
sprocketc Jun 12, 2025
1f4a57c
path fixes
sprocketc Jun 12, 2025
1f7d4a7
refactor
sprocketc Jun 12, 2025
c0578f2
refactor
sprocketc Jun 12, 2025
e451f9d
simplify tools
sprocketc Jun 12, 2025
d6d9a40
simplify svg tool
sprocketc Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clj-kondo/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/electron/main.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/app/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/app/effects.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 32 additions & 17 deletions src/renderer/app/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,39 @@
(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
[]
[["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])]
["Primary tool" @(rf/subscribe [::tool.subs/primary])]
["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
[]
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/attribute/impl/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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.")

Expand Down
3 changes: 2 additions & 1 deletion src/renderer/attribute/impl/d.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions src/renderer/attribute/impl/font_weight.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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)})]))
7 changes: 3 additions & 4 deletions src/renderer/attribute/impl/href.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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]}}]}))
7 changes: 4 additions & 3 deletions src/renderer/attribute/impl/points.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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])]))
12 changes: 9 additions & 3 deletions src/renderer/attribute/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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]))

Expand Down Expand Up @@ -95,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"]])])

Expand Down Expand Up @@ -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]
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/dialog/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/renderer/document/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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?]
Expand Down
5 changes: 0 additions & 5 deletions src/renderer/document/subs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,6 @@
:<- [::active]
:-> :elements)

(rf/reg-sub
::temp-element
:<- [::active]
:-> :temp-element)

(rf/reg-sub
::filter
:<- [::active]
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/effects.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@
(.addEventListener target
channel
#(rf/dispatch (conj listener
(cond-> % formatter formatter))))))
(cond-> %
formatter formatter))))))

(rf/reg-fx
::ipc-send
Expand All @@ -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
Expand Down
16 changes: 9 additions & 7 deletions src/renderer/element/impl/box.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
10 changes: 4 additions & 6 deletions src/renderer/element/impl/container/canvas.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@
(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])
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)
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
Expand All @@ -66,16 +66,14 @@

(when grid [ruler.views/grid])

(when-not read-only? [element.hierarchy/render temp-element])

(when snap?
[:<>
(when snapped-el
[utils.svg/bounding-box (:bbox snapped-el) true])
(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]
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/element/impl/custom/brush.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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 " ")))))
Expand Down
3 changes: 1 addition & 2 deletions src/renderer/element/impl/custom/core.cljs
Original file line number Diff line number Diff line change
@@ -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]))
Loading