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 diff
1.1 --- a/src/indyvon/component.clj Thu Jun 17 18:54:22 2010 +0400 1.2 +++ b/src/indyvon/component.clj Thu Jun 17 20:59:22 2010 +0400 1.3 @@ -83,26 +83,19 @@ 1.4 (.pack) 1.5 (.setVisible true)) 1.6 1.7 - (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_ENTERED] 1.8 - [layer context event] 1.9 - (println "1 ENTERED")) 1.10 - (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_EXITED] 1.11 - [layer context event] 1.12 - (println "1 EXITED")) 1.13 - (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_MOVED] 1.14 - [layer context event] 1.15 - (println "1 MOVED")) 1.16 - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_ENTERED] 1.17 - [layer context event] 1.18 - (println "2 ENTERED")) 1.19 - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_EXITED] 1.20 - [layer context event] 1.21 - (println "2 EXITED")) 1.22 - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_MOVED] 1.23 - [layer context event] 1.24 - (println "2 MOVED")) 1.25 - (defmethod handle-layer-event [layer2 MouseEvent/MOUSE_DRAGGED] 1.26 - [layer context event] 1.27 - (println "2 DRAGGED")) 1.28 + (add-listener layer1 MouseEvent/MOUSE_ENTERED 1.29 + (fn [context event] (println "1 ENTERED"))) 1.30 + (add-listener layer1 MouseEvent/MOUSE_EXITED 1.31 + (fn [context event] (println "1 EXITED"))) 1.32 + (add-listener layer1 MouseEvent/MOUSE_MOVED 1.33 + (fn [context event] (println "1 MOVED"))) 1.34 + (add-listener layer2 MouseEvent/MOUSE_ENTERED 1.35 + (fn [context event] (println "2 ENTERED"))) 1.36 + (add-listener layer2 MouseEvent/MOUSE_EXITED 1.37 + (fn [context event] (println "2 EXITED"))) 1.38 + (add-listener layer2 MouseEvent/MOUSE_MOVED 1.39 + (fn [context event] (println "2 MOVED"))) 1.40 + (add-listener layer2 MouseEvent/MOUSE_DRAGGED 1.41 + (fn [context event] (println "2 DRAGGED"))) 1.42 ) 1.43 )
2.1 --- a/src/indyvon/event.clj Thu Jun 17 18:54:22 2010 +0400 2.2 +++ b/src/indyvon/event.clj Thu Jun 17 20:59:22 2010 +0400 2.3 @@ -6,13 +6,47 @@ 2.4 2.5 (ns indyvon.event 2.6 (:use indyvon.core) 2.7 - (:import (java.awt.event MouseEvent MouseListener MouseMotionListener))) 2.8 + (:import (java.awt.event MouseEvent MouseListener MouseMotionListener) 2.9 + java.lang.ref.WeakReference)) 2.10 2.11 -(defmulti handle-layer-event 2.12 - (fn [layer context event] 2.13 - [layer (.getID event)])) 2.14 +;; map event-id -> [layer-weak-ref1 fn1, layer-weak-ref2 fn2...] 2.15 +(def listeners-map (ref {})) 2.16 2.17 -(defmethod handle-layer-event :default [layer context event]) 2.18 +(defn- assoc-conj [map key & vals] 2.19 + (assoc map key (apply conj (vec (get map key)) vals))) 2.20 + 2.21 +(defn add-listener 2.22 + "The supplied function will be invoked with context, event and 2.23 + additional args when an event with the specified id occurs on the 2.24 + specified layer." 2.25 + [layer event-id f & args] 2.26 + (let [f (if args #(apply f %1 %2 args) f)] 2.27 + (dosync 2.28 + (alter listeners-map assoc-conj event-id (WeakReference. layer) f)) 2.29 + nil)) 2.30 + 2.31 +(defn- listeners 2.32 + "Returns list of listener fns for event and target-layer. Listeners 2.33 + for garbage-collected layers are removed." 2.34 + [event-id target-layer] 2.35 + (dosync 2.36 + (loop [ref-vec (@listeners-map event-id) cleared-ref-vec [] listeners []] 2.37 + (if-let [layer-ref (first ref-vec)] 2.38 + (if-let [layer (.get layer-ref)] 2.39 + (let [lfn (second ref-vec)] 2.40 + (recur (nnext ref-vec) 2.41 + (conj cleared-ref-vec layer-ref lfn) 2.42 + (if (= layer target-layer) 2.43 + (conj listeners lfn) 2.44 + listeners))) 2.45 + (recur (nnext ref-vec) cleared-ref-vec listeners)) 2.46 + (do 2.47 + (alter listeners-map assoc event-id cleared-ref-vec) 2.48 + listeners))))) 2.49 + 2.50 +(defn dispatch-event [context event] 2.51 + (doseq [listener (listeners (.getID event) (:layer context))] 2.52 + (listener context event))) 2.53 2.54 (defprotocol EventDispatcher 2.55 (listen! [this component]) 2.56 @@ -78,11 +112,10 @@ 2.57 ([contexts event] 2.58 (translate-and-dispatch contexts event (.getID event))) 2.59 ([contexts event id] 2.60 - (doseq [c contexts] 2.61 - (handle-layer-event 2.62 - (:layer c) 2.63 - c 2.64 - (translate-mouse-event event (:x c) (:y c) id))))) 2.65 + (doseq [context contexts] 2.66 + (dispatch-event 2.67 + context 2.68 + (translate-mouse-event event (:x context) (:y context) id))))) 2.69 2.70 (defn- dispatch-mouse-motion* 2.71 "Dispatches mouse motion events. Returns a new set of contexts which