Mercurial > hg > indyvon
changeset 8:c53ec3052ae7
Dispatching mouse motion events.
author | Mikhail Kryshen <mikhail@kryshen.net> |
---|---|
date | Sat, 12 Jun 2010 06:06:41 +0400 |
parents | f6d10a68b01d |
children | 160e9ec945a2 |
files | src/indyvon/core.clj |
diffstat | 1 files changed, 97 insertions(+), 22 deletions(-) [+] |
line diff
1.1 --- a/src/indyvon/core.clj Fri Jun 11 22:58:23 2010 +0400 1.2 +++ b/src/indyvon/core.clj Sat Jun 12 06:06:41 2010 +0400 1.3 @@ -1,6 +1,7 @@ 1.4 (ns indyvon.core 1.5 - (:import (java.awt Dimension Point Component Graphics2D AWTEvent) 1.6 - (java.awt.event MouseAdapter MouseMotionAdapter 1.7 + (:require (clojure [set :as s])) 1.8 + (:import (java.awt Dimension Point Component Graphics2D Color AWTEvent) 1.9 + (java.awt.event MouseEvent MouseAdapter MouseMotionAdapter 1.10 MouseListener MouseMotionListener))) 1.11 1.12 (defprotocol Layer 1.13 @@ -42,7 +43,7 @@ 1.14 ([context layer graphics x y clip] 1.15 (let [s (size layer context)] 1.16 (render-layer! context layer graphics 1.17 - x y (.width s) (.height s) clip))) 1.18 + x y (s 0) (s 1) clip))) 1.19 ([context layer graphics x y w h] 1.20 (render-layer! context layer graphics 1.21 x y w h true)) 1.22 @@ -90,6 +91,11 @@ 1.23 (contains? context-tree parent) parent 1.24 :default (recur context-tree parent)))) 1.25 1.26 +(defn- register-context 1.27 + [context-tree context] 1.28 + (assoc-conj 1.29 + context-tree (registered-parent context-tree context) context)) 1.30 + 1.31 (defn- inside? 1.32 ([x y context] 1.33 (inside? x y (:x context) (:y context) 1.34 @@ -109,17 +115,64 @@ 1.35 (conj (under-cursor context-tree x y %) %)) 1.36 (context-tree context)))) 1.37 1.38 +(defn- remove-all [coll1 coll2 pred] 1.39 + (filter #(not (some (partial pred %) coll2)) coll1)) 1.40 + 1.41 +(defn- translate-mouse-event 1.42 + [#^MouseEvent event x y id] 1.43 + (proxy [MouseEvent] [(.getComponent event) 1.44 + id 1.45 + (.getWhen event) 1.46 + (.getModifiers event) 1.47 + (- (.getX event) x) 1.48 + (- (.getY event) y) 1.49 + (.getClickCount event) 1.50 + (.isPopupTrigger event)] 1.51 + (getXOnScreen [] 1.52 + (.getXOnScreen event)) 1.53 + (getYOnScreen [] 1.54 + (.getYOnScreen event)))) 1.55 + 1.56 +(defn- translate-and-dispatch 1.57 + ([contexts event] 1.58 + (translate-and-dispatch contexts event (.getID event))) 1.59 + ([contexts event id] 1.60 + (doseq [c contexts] 1.61 + (handle-layer-event 1.62 + (:layer c) 1.63 + c 1.64 + (translate-mouse-event event (:x c) (:y c) id))))) 1.65 + 1.66 +(defn- dispatch-mouse-motion* 1.67 + "Dispatches mouse motion events. Returns a new set of contexts which 1.68 + currently are under cursor." 1.69 + [hovered context-tree #^MouseEvent event] 1.70 + (let [x (.getX event) 1.71 + y (.getY event) 1.72 + hovered2 (under-cursor context-tree x y) 1.73 + pred #(= (:layer %1) (:layer %2)) 1.74 + exited (remove-all hovered hovered2 pred) 1.75 + entered (remove-all hovered2 hovered pred) 1.76 + moved (remove-all hovered2 entered pred)] 1.77 + (translate-and-dispatch exited event MouseEvent/MOUSE_EXITED) 1.78 + (translate-and-dispatch entered event MouseEvent/MOUSE_ENTERED) 1.79 + (translate-and-dispatch moved event MouseEvent/MOUSE_MOVED) 1.80 + hovered2)) 1.81 + 1.82 +(defn- dispatch-mouse-motion 1.83 + [hovered-ref context-tree #^MouseEvent event] 1.84 + (dosync 1.85 + (alter hovered-ref dispatch-mouse-motion* context-tree event))) 1.86 + 1.87 (defn make-event-dispatcher [] 1.88 (let [context-tree-r (ref {}) ; register 1.89 context-tree (ref {}) ; dispatch 1.90 - hovered (ref []) 1.91 - picked (ref [])] 1.92 + hovered (ref '()) 1.93 + picked (ref '())] 1.94 (reify 1.95 EventDispatcher 1.96 (register [this context] 1.97 - (dosync 1.98 - (alter context-tree-r assoc-conj 1.99 - (registered-parent context) context))) 1.100 + (dosync (alter context-tree-r register-context context))) 1.101 (commit [this] 1.102 (dosync (ref-set context-tree @context-tree-r) 1.103 (ref-set context-tree-r {}))) 1.104 @@ -127,13 +180,17 @@ 1.105 (hovered? [this layer] false) 1.106 MouseListener 1.107 (mouseClicked [this event]) 1.108 - (mouseEntered [this event]) 1.109 - (mouseExited [this event]) 1.110 + (mouseEntered [this event] 1.111 + (dispatch-mouse-motion hovered context-tree event)) 1.112 + (mouseExited [this event] 1.113 + (dispatch-mouse-motion hovered context-tree event)) 1.114 (mousePressed [this event]) 1.115 (mouseReleased [this event]) 1.116 MouseMotionListener 1.117 - (mouseDragged [this event]) 1.118 - (mouseMoved [this event])))) 1.119 + (mouseDragged [this event] 1.120 + (translate-and-dispatch @picked event)) 1.121 + (mouseMoved [this event] 1.122 + (dispatch-mouse-motion hovered context-tree event))))) 1.123 1.124 ;; 1.125 ;; Connection to AWT. 1.126 @@ -154,25 +211,33 @@ 1.127 width (.width size) 1.128 height (.height size) 1.129 context (assoc (default-context) 1.130 + :dispatcher event-dispatcher 1.131 :update-fn (make-update-fn this))] 1.132 - (render-layer! context layer g 0 0 width height false))) 1.133 + (render-layer! context layer g 0 0 width height false)) 1.134 + (commit event-dispatcher)) 1.135 (getPreferredSize [] 1.136 (let [s (size layer nil)] ;; TODO: supply context 1.137 - (Dimension. (s 0) (s 1)))) 1.138 - (processEvent [event])) 1.139 - ;; No way to call protected final evenbleEvents even in gen-class, 1.140 - ;; have to use the following hack: 1.141 - (.addMouseListener (proxy [MouseAdapter] [])) 1.142 - (.addMouseMotionListener (proxy [MouseMotionAdapter] []))))) 1.143 + (Dimension. (s 0) (s 1))))) 1.144 + (.addMouseListener event-dispatcher) 1.145 + (.addMouseMotionListener event-dispatcher)))) 1.146 1.147 (comment 1.148 (do 1.149 (def frame (java.awt.Frame. "Test")) 1.150 + (def layer1 1.151 + (reify-layer 1.152 + (render! [this context g] 1.153 + (register (:dispatcher context) context) 1.154 + (.setColor g Color/BLUE) 1.155 + (.fillRect g 0 0 50 30)) 1.156 + (size [this context] [50 30]))) 1.157 (def layer 1.158 (reify-layer 1.159 - (render! [this] 1.160 - (.fillRect *graphics* 10 10 40 40)) 1.161 - (size [this] [100 100]))) 1.162 + (render! [this context g] 1.163 + (register (:dispatcher context) context) 1.164 + (.drawLine g 0 0 (:width context) (:height context)) 1.165 + (render-layer! context layer1 g 15 20)) 1.166 + (size [this context] [100 100]))) 1.167 (doto frame 1.168 (.addWindowListener 1.169 (proxy [java.awt.event.WindowAdapter] [] 1.170 @@ -180,5 +245,15 @@ 1.171 (.add (make-component layer)) 1.172 (.pack) 1.173 (.setVisible true)) 1.174 + 1.175 + (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_ENTERED] 1.176 + [layer context event] 1.177 + (println "ENTERED")) 1.178 + (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_EXITED] 1.179 + [layer context event] 1.180 + (println "EXITED")) 1.181 + (defmethod handle-layer-event [layer1 MouseEvent/MOUSE_MOVED] 1.182 + [layer context event] 1.183 + (println "MOVED")) 1.184 ) 1.185 ) 1.186 \ No newline at end of file