Mercurial > hg > indyvon
changeset 30:a8821f4b5ade
Event dispatcher creates new context.
author | Mikhail Kryshen <mikhail@kryshen.net> |
---|---|
date | Wed, 07 Jul 2010 03:10:22 +0400 |
parents | 4cb70c5a6e0d |
children | 8ac3a21955db |
files | src/indyvon/core.clj |
diffstat | 1 files changed, 49 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/src/indyvon/core.clj Tue Jul 06 06:05:28 2010 +0400 +++ b/src/indyvon/core.clj Wed Jul 07 03:10:22 2010 +0400 @@ -20,9 +20,14 @@ (defrecord MouseEvent [id when x y x-on-screen y-on-screen button]) (defprotocol EventDispatcher - (listen! [this component]) - (register [this context handlers]) - (commit [this])) + (listen! [this component] + "Listen for events on the specified AWT Component.") + (register [this context handle handlers] + "Returns new context associated with the specified event + handlers (an event-id -> handler-fn map). Handle is used + to match the contexts between commits.") + (commit [this] + "Apply the registered handlers for event processing.")) (defprotocol Anchored "Provide anchor point for Layers. Used by viewport." @@ -53,11 +58,11 @@ (defn default-theme [] (Theme. Color/BLACK Color/WHITE Color/BLUE (Font. "Sans" Font/PLAIN 12))) -(defrecord LayerContext [layer parent x y width height update-fn - dispatcher font-context theme target]) +(defrecord LayerContext [x y width height update-fn font-context + theme target dispatcher node]) (defn default-context [] - (LayerContext. nil nil 0 0 0 0 nil nil nil (default-theme) nil)) + (LayerContext. 0 0 0 0 nil nil (default-theme) nil nil nil)) (defn update [context] ((:update-fn context))) @@ -102,18 +107,22 @@ (finally (.dispose graphics)))))) -(defn listen* [context & handlers] - (register (:dispatcher context) context (apply array-map handlers))) +(defmacro handlers [handle bindings & specs] + "bindings => binding-form context + specs => (:event-id name & handler-body)* form -;; (listen context -;; (:mouse-entered e (println e)) -;; (:mouse-exited e (println e))) -(defmacro listen [context & specs] - `(register (:dispatcher ~context) ~context - ~(reduce #(assoc %1 - (first %2) - `(fn [~(second %2)] ~@(nnext %2))) - {} specs))) + Execute form with the specified event handlers." + (let [[binding context] bindings + context (or context binding)] + `(let [context# ~context + ~binding + (register (:dispatcher context#) context# handle + ~(reduce (fn [m spec] + (assoc m (first spec) + `(fn [~(second spec)] + ~@(nnext spec)))) {} + (butlast specs)))] + ~(last specs)))) ;; ;; EventDispatcher implementation @@ -128,33 +137,17 @@ java.awt.event.MouseEvent/MOUSE_PRESSED :mouse-pressed java.awt.event.MouseEvent/MOUSE_RELEASED :mouse-released}) -(defrecord DispatcherNode [layer x y width height handlers children]) - -(defrecord DispatcherRootNode [children]) +(defrecord DispatcherNode [handle handlers parent x y width height]) -(defn- make-node [c handlers] - (DispatcherNode. (:layer c) (:x c) (:y c) (:width c) (:height c) - handlers nil)) - -(defn- add-child [node child] - (assoc node :children (cons child (:children node)))) +(defn- make-node [c handle handlers] + (DispatcherNode. handle handlers (:node c) + (:x c) (:y c) (:width c) (:height c))) -(defn- registered-parent - "Returns first context parent registered for event processing." - [tree context] - (let [parent (:parent context)] - (cond - (nil? parent) nil - (contains? tree parent) parent - :default (recur tree parent)))) +(defn- assoc-cons [m key val] + (assoc m key (cons val (get m key)))) -(defn- add-context - [tree context handlers] - (let [parent (registered-parent tree context) - node (make-node context handlers)] - (assoc tree - parent (add-child (tree parent) node) - context node))) +(defn- add-node [tree node] + (assoc-cons tree (:parent node) node)) (defn- inside? ([x y node] @@ -168,10 +161,12 @@ (defn- under-cursor "Returns a sequence of child nodes under cursor." - [x y node] - (some #(if (inside? x y %) - (conj (under-cursor x y %) %)) - (:children node))) + ([x y tree] + (under-cursor x y tree nil)) + ([x y tree node] + (some #(if (inside? x y %) + (conj (under-cursor x y %) %)) + (get tree node)))) (defn- remove-all [coll1 coll2 pred] (filter #(not (some (partial pred %) coll2)) coll1)) @@ -199,8 +194,8 @@ [hovered tree event] (let [x (.getX event) y (.getY event) - hovered2 (under-cursor x y (get tree nil)) - pred #(= (:layer %1) (:layer %2)) + hovered2 (under-cursor x y tree) + pred #(= (:handle %1) (:handle %2)) exited (remove-all hovered hovered2 pred) entered (remove-all hovered2 hovered pred) moved (remove-all hovered2 entered pred)] @@ -228,9 +223,8 @@ (alter picked-ref dispatch-mouse-button* @hovered-ref event))) (defn make-event-dispatcher [] - (let [tree-i {nil (DispatcherRootNode. nil)} ; initial - tree-r (ref tree-i) ; register - tree (ref tree-i) ; dispatch + (let [tree-r (ref {}) ; register + tree (ref {}) ; dispatch hovered (ref '()) picked (ref '())] (reify @@ -239,11 +233,13 @@ (doto component (.addMouseListener this) (.addMouseMotionListener this))) - (register [this context handlers] - (dosync (alter tree-r add-context context handlers))) + (register [this context handle handlers] + (let [node (make-node context handle handlers)] + (dosync (alter tree-r add-node node)) + (assoc context :node node))) (commit [this] (dosync (ref-set tree @tree-r) - (ref-set tree-r tree-i))) + (ref-set tree-r {}))) MouseListener (mouseEntered [this event] (dispatch-mouse-motion hovered @tree event))