Mercurial > hg > indyvon
changeset 19:43f0d78057a9
New event dispatching code that uses weak references to allow listened layers to be garbage-collected.
author | Mikhail Kryshen <mikhail@kryshen.net> |
---|---|
date | Thu, 17 Jun 2010 20:59:22 +0400 |
parents | 740b9d2bbc45 |
children | 357bdd7d0550 |
files | src/indyvon/component.clj src/indyvon/event.clj |
diffstat | 2 files changed, 57 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/src/indyvon/component.clj Thu Jun 17 18:54:22 2010 +0400 +++ b/src/indyvon/component.clj Thu Jun 17 20:59:22 2010 +0400 @@ -83,26 +83,19 @@ (.pack) (.setVisible true)) - (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_ENTERED] - [layer context event] - (println "1 ENTERED")) - (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_EXITED] - [layer context event] - (println "1 EXITED")) - (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_MOVED] - [layer context event] - (println "1 MOVED")) - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_ENTERED] - [layer context event] - (println "2 ENTERED")) - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_EXITED] - [layer context event] - (println "2 EXITED")) - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_MOVED] - [layer context event] - (println "2 MOVED")) - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_DRAGGED] - [layer context event] - (println "2 DRAGGED")) + (add-listener layer1 MouseEvent/MOUSE_ENTERED + (fn [context event] (println "1 ENTERED"))) + (add-listener layer1 MouseEvent/MOUSE_EXITED + (fn [context event] (println "1 EXITED"))) + (add-listener layer1 MouseEvent/MOUSE_MOVED + (fn [context event] (println "1 MOVED"))) + (add-listener layer2 MouseEvent/MOUSE_ENTERED + (fn [context event] (println "2 ENTERED"))) + (add-listener layer2 MouseEvent/MOUSE_EXITED + (fn [context event] (println "2 EXITED"))) + (add-listener layer2 MouseEvent/MOUSE_MOVED + (fn [context event] (println "2 MOVED"))) + (add-listener layer2 MouseEvent/MOUSE_DRAGGED + (fn [context event] (println "2 DRAGGED"))) ) )
--- a/src/indyvon/event.clj Thu Jun 17 18:54:22 2010 +0400 +++ b/src/indyvon/event.clj Thu Jun 17 20:59:22 2010 +0400 @@ -6,13 +6,47 @@ (ns indyvon.event (:use indyvon.core) - (:import (java.awt.event MouseEvent MouseListener MouseMotionListener))) + (:import (java.awt.event MouseEvent MouseListener MouseMotionListener) + java.lang.ref.WeakReference)) + +;; map event-id -> [layer-weak-ref1 fn1, layer-weak-ref2 fn2...] +(def listeners-map (ref {})) + +(defn- assoc-conj [map key & vals] + (assoc map key (apply conj (vec (get map key)) vals))) + +(defn add-listener + "The supplied function will be invoked with context, event and + additional args when an event with the specified id occurs on the + specified layer." + [layer event-id f & args] + (let [f (if args #(apply f %1 %2 args) f)] + (dosync + (alter listeners-map assoc-conj event-id (WeakReference. layer) f)) + nil)) -(defmulti handle-layer-event - (fn [layer context event] - [layer (.getID event)])) +(defn- listeners + "Returns list of listener fns for event and target-layer. Listeners + for garbage-collected layers are removed." + [event-id target-layer] + (dosync + (loop [ref-vec (@listeners-map event-id) cleared-ref-vec [] listeners []] + (if-let [layer-ref (first ref-vec)] + (if-let [layer (.get layer-ref)] + (let [lfn (second ref-vec)] + (recur (nnext ref-vec) + (conj cleared-ref-vec layer-ref lfn) + (if (= layer target-layer) + (conj listeners lfn) + listeners))) + (recur (nnext ref-vec) cleared-ref-vec listeners)) + (do + (alter listeners-map assoc event-id cleared-ref-vec) + listeners))))) -(defmethod handle-layer-event :default [layer context event]) +(defn dispatch-event [context event] + (doseq [listener (listeners (.getID event) (:layer context))] + (listener context event))) (defprotocol EventDispatcher (listen! [this component]) @@ -78,11 +112,10 @@ ([contexts event] (translate-and-dispatch contexts event (.getID event))) ([contexts event id] - (doseq [c contexts] - (handle-layer-event - (:layer c) - c - (translate-mouse-event event (:x c) (:y c) id))))) + (doseq [context contexts] + (dispatch-event + context + (translate-mouse-event event (:x context) (:y context) id))))) (defn- dispatch-mouse-motion* "Dispatches mouse motion events. Returns a new set of contexts which