Skip to content
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

Annotate scenes with custom notes. #166

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 src/main/ogres/app/component/scene.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
(comp (filter :mask/enabled?) (map :mask/vecs)))

(def ^:private draw-modes
#{:grid :ruler :circle :rect :cone :line :poly :mask})
#{:grid :ruler :circle :rect :cone :line :poly :mask :note})

(def ^:private condition->icon
{:blinded "eye-slash-fill"
Expand Down
3 changes: 2 additions & 1 deletion src/main/ogres/app/component/scene_context_menu.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,5 @@
(if (= (count types) 1)
(case (first types)
:shape ($ context-menu-shape props)
:token ($ context-menu-token props)))))
:token ($ context-menu-token props)
nil))))
15 changes: 15 additions & 0 deletions src/main/ogres/app/component/scene_draw.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,20 @@
($ :button {:type "submit" :data-name "submit"}
($ icon {:name "check"})))))))))))

(defui draw-note []
(let [dispatch (hooks/use-dispatch)]
($ :rect
{:x 0
:y 0
:width "100%"
:height "100%"
:fill "transparent"
:on-click
(fn [event]
(let [x (.-clientX event)
y (.-clientY event)]
(dispatch :note/create x y)))})))

(defui draw [{:keys [mode] :as props}]
($ dnd-context
(case mode
Expand All @@ -317,6 +331,7 @@
:grid ($ draw-grid props)
:line ($ draw-line props)
:mask ($ draw-mask props)
:note ($ draw-note props)
:poly ($ draw-poly props)
:rect ($ draw-rect props)
:ruler ($ draw-ruler props)
Expand Down
116 changes: 104 additions & 12 deletions src/main/ogres/app/component/scene_objects.cljs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(ns ogres.app.component.scene-objects
(:require [clojure.string :refer [join]]
[goog.object :refer [getValueByKeys]]
[ogres.app.component :refer [icon]]
[ogres.app.component.scene-context-menu :refer [context-menu]]
[ogres.app.component.scene-pattern :refer [pattern]]
[ogres.app.geom :as geom]
Expand All @@ -13,19 +14,22 @@
:rename {useDndMonitor use-dnd-monitor
useDraggable use-draggable}]))

(def ^:private note-icons
["journal-bookmark-fill" "dice-5" "door-open" "geo-alt" "fire" "skull" "question-circle"])

(defn ^:private stop-propagation
"Defines an event handler that ceases event propagation."
[event]
(.stopPropagation event))

(defn ^:private shapes-comparator
(defn ^:private compare-objects
"Defines a comparator function for shapes."
[a b]
(let [{[ax ay] :object/point} a
{[bx by] :object/point} b]
(compare [ax ay] [bx by])))

(defn ^:private tokens-comparator
(defn ^:private compare-tokens
"Defines a comparator function for tokens."
[a b]
(let [{size-a :token/size [ax ay] :object/point} a
Expand Down Expand Up @@ -54,6 +58,9 @@
(or (= user :host)
(not (contains? (:token/flags token) :hidden))))))

(defn ^:private objects-xf [user]
(filter (fn [entity] (or (= user :host) (not (:object/hidden entity))))))

(defn ^:private use-cursor-point
"Defines a React state hook which returns a point [Ax Ay] of the
given user's current cursor position, if available."
Expand Down Expand Up @@ -165,10 +172,79 @@
:width (- bx ax 1)
:height (- by ay 1)})) portal))))))

(defui ^:private object-note [{note :entity}]
(let [dispatch (hooks/use-dispatch)
selected (contains? note :camera/_selected)
{id :db/id hidden :object/hidden} note]
($ :foreignObject.scene-object-note
{:x -8 :y -8 :width 362 :height (if selected 334 58)}
($ :.scene-note {:data-hidden hidden}
($ :.scene-note-header
($ :.scene-note-anchor
($ icon {:name (:note/icon note) :size 26}))
($ :.scene-note-nav
($ :.scene-note-navinner
($ :.scene-note-label (:note/label note))
($ :.scene-note-control
{:on-pointer-down stop-propagation
:on-click (fn [] (dispatch :objects/toggle-hidden id))}
($ icon {:name (if hidden "eye-slash-fill" "eye-fill") :size 22}))
($ :.scene-note-control
{:on-pointer-down stop-propagation
:on-click (fn [] (dispatch :objects/remove [id]))}
($ icon {:name "trash3-fill" :size 22})))))
(if selected
($ :.scene-note-body {:on-pointer-down stop-propagation}
($ :ul.scene-note-icons
(for [icon-name note-icons]
($ :li {:key icon-name}
($ :label
($ :input
{:type "radio"
:name "note-icon"
:value icon-name
:checked (= (:note/icon note) icon-name)
:on-change
(fn [event]
(dispatch :note/change-icon (:db/id note) (.. event -target -value)))})
($ icon {:name icon-name})))))
($ :form.scene-note-form
{:on-blur
(fn [event]
(let [name (.. event -target -name)
value (.. event -target -value)]
(cond (and (= name "label") (not= (:note/label note) value))
(dispatch :note/change-label id value)
(and (= name "description") (not= (:note/description note) value))
(dispatch :note/change-description id value))))
:on-submit
(fn [event]
(.preventDefault event)
(let [input (.. event -target -elements)
label (.. input -label -value)
descr (.. input -description -value)]
(dispatch :note/change-details id label descr)))}
($ :fieldset.fieldset
($ :legend "Label")
($ :input.text.text-ghost
{:type "text"
:name "label"
:auto-complete "off"
:default-value (:note/label note)
:placeholder "Spider's Ballroom"}))
($ :fieldset.fieldset
($ :legend "Description")
($ :textarea
{:name "description"
:auto-complete "off"
:default-value (:note/description note)}))
($ :input {:type "submit" :hidden true}))))))))

(defui ^:private object [props]
(case (keyword (namespace (:object/type (:entity props))))
:shape ($ object-shape props)
:token ($ object-token props)))
:token ($ object-token props)
:note ($ object-note props)))

(defn ^:private use-drag-listener []
(let [dispatch (hooks/use-dispatch)]
Expand Down Expand Up @@ -231,7 +307,20 @@
[:shape/points :default [0 0]]
[:shape/color :default "#f44336"]
[:shape/opacity :default 0.25]
[:shape/pattern :default :solid]]}]}]}]
[:shape/pattern :default :solid]]}
{:scene/notes
[:db/id
[:object/type :default :note/note]
[:object/point :default [0 0]]
[:object/hidden :default true]
[:object/locked :default true]
[:note/icon :default "journal-bookmark-fill"]
[:note/label :default ""]
[:note/description :default ""]
{:camera/_selected
[{:user/_camera
[{:root/_user
[[:user/type :default :host]]}]}]}]}]}]}]
:root/session
[{:session/conns
[:db/ident :user/uuid :user/color :user/dragging]}]}])
Expand All @@ -245,16 +334,18 @@
selected :camera/selected
{[ox oy] :scene/grid-origin
align? :scene/grid-align
tokens :scene/tokens
shapes :scene/shapes}
notes :scene/notes
shapes :scene/shapes
tokens :scene/tokens}
:camera/scene}
:user/camera} :root/user
{conns :session/conns} :root/session} result
portal (uix/use-ref)
bounds [cx cy (+ (/ bw scale) cx) (+ (/ bh scale) cy)]
shapes (sort shapes-comparator shapes)
tokens (sort tokens-comparator (sequence (tokens-xf type) tokens))
entities (concat shapes tokens)
notes (sort compare-objects notes)
shapes (sort compare-objects shapes)
tokens (sort compare-tokens (sequence (tokens-xf type) tokens))
entities (into [] (objects-xf type) (into tokens (into shapes notes)))
selected (into #{} (map :db/id) selected)
dragging (into {} user-drag-xf conns)
boundsxf (comp (filter (comp selected :db/id)) (mapcat geom/object-bounding-rect))]
Expand All @@ -264,7 +355,8 @@
{:ref portal :tab-index -1})
($ TransitionGroup {:component nil}
(for [entity entities
:let [{id :db/id [ax ay] :object/point type :object/type} entity
:let [{id :db/id [ax ay] :object/point} entity
lock (and (= type :conn) (:object/locked entity))
node (uix/create-ref)
user (dragging id)
rect (geom/object-bounding-rect entity)
Expand All @@ -274,7 +366,7 @@
(if (not (selected id))
($ drag-remote-fn {:user (:user/uuid user) :x ax :y ay}
(fn [[rx ry]]
($ drag-local-fn {:id id :disabled (some? user)}
($ drag-local-fn {:id id :disabled (or user lock)}
(fn [drag]
(let [handler (getValueByKeys drag "listeners" "onPointerDown")
dx (or (getValueByKeys drag "transform" "x") 0)
Expand All @@ -291,7 +383,7 @@
:data-drag-remote (some? user)
:data-drag-local (.-isDragging drag)
:data-color (:user/color user)
:data-type (namespace type)
:data-type (namespace (:object/type entity))
:data-id id}
($ object
{:entity entity
Expand Down
Loading