changeset 22:dc81033d4122

Layers should satisfy MouseHandler protocol to recieve mouse events.
author Mikhail Kryshen <mikhail@kryshen.net>
date Sat, 19 Jun 2010 06:50:24 +0400
parents a70609bad3a4
children bbe95838fe77
files src/indyvon/component.clj src/indyvon/core.clj src/indyvon/event.clj
diffstat 3 files changed, 98 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/src/indyvon/component.clj	Sat Jun 19 04:27:29 2010 +0400
+++ b/src/indyvon/component.clj	Sat Jun 19 06:50:24 2010 +0400
@@ -5,8 +5,8 @@
 ;;
 
 (ns indyvon.component
-  (:use indyvon.core
-        indyvon.event)
+  (:use indyvon.core)
+  (:require (indyvon [event :as event]))
   (:import (java.awt Component Dimension Color)
            (java.awt.event MouseEvent)
            (javax.swing JFrame JPanel)))
@@ -21,6 +21,7 @@
         context (assoc context
                   :font-context (.getFontRenderContext graphics)
                   :update-fn #(.repaint component))]
+    (.clearRect graphics 0 0 width height)
     (draw! context layer graphics 0 0 width height false))
   (commit (:dispatcher context)))
 
@@ -32,7 +33,7 @@
 
 (defn make-jpanel
   ([layer]
-     (make-jpanel layer (make-event-dispatcher)))
+     (make-jpanel layer (event/make-event-dispatcher)))
   ([layer event-dispatcher]
      (let [context (default-context)
            context (assoc context :dispatcher event-dispatcher)
@@ -47,45 +48,73 @@
        panel)))
 
 (comment
-  (do 
+  (do
     (def frame (JFrame. "Test"))
     
-    (defn handler [context event]
+    (defn handler [event context]
       (println (:layer context) (.paramString event)))
       
     (def layer1
-         (reify Layer
+         (reify
+          Layer
           (render! [this context g]
-             (mouse-handler context handler)
              (.setColor g Color/RED)
              (.fillRect g 0 0 (:width context) (:height context)))
           (size [this context] [30 20])
-          (toString [this] "layer1")))
+          MouseHandler
+          (handle-mouse [this context event]
+             (println "layer1" (.paramString event)))))
     
     (def layer1b (border-layer layer1 2 3))
     
     (def layer2
-         (reify Layer
+         (reify
+          Layer
           (render! [this context g]
-             (mouse-handler context handler)
              (.setColor g Color/YELLOW)
              (.fillRect g 0 0 (:width context) (:height context))
              (draw! context layer1b g 10 5)
              (draw! context layer1 g 55 5))
           (size [this context] [70 65])
-          (toString [this] "layer2")))
+          MouseHandler
+          (handle-mouse [this context event]
+             (println "layer2" (.paramString event)))))
     
     (def layer3
-         (border-layer (text-layer "Sample\ntext" :right :bottom)))
+         (border-layer (text-layer "Sample\ntext" :right :center)))
+
+    (defn fps-layer [fps]
+      (border-layer (text-layer (format "%.1f" fps) :right :bottom) 0 5))
+    
+    (def fps
+         (let [update-interval 0.1
+               frames (ref 0)
+               last (ref 0)
+               fl (ref (fps-layer 0.0))]
+           (reify
+            Layer
+            (render! [this c g]
+               (draw! c @fl g)
+               (dosync
+                (alter frames + 1)
+                (let [time (System/currentTimeMillis)
+                      elapsed (/ (- time @last) 1000.0)]
+                  (when (> elapsed update-interval)
+                    (ref-set fl (fps-layer (/ @frames elapsed)))
+                    (ref-set frames 0)
+                    (ref-set last time)))))
+            (size [this c] (size @fl c)))))
     
     (def layer
          (reify Layer
-          (render! [this context g]
+           (render! [this context g]
+             ;;(update context)
+             (.setColor g (rand-nth [Color/BLACK Color/BLUE Color/RED]))       
              (.drawLine g 0 0 (:width context) (:height context))
              (draw! context layer2 g 15 20)
-             (draw! context layer3 g 100 100 80 50))
-          (size [this context] [400 300])
-          (toString [this] "layer")))
+             (draw! context layer3 g 100 100 80 50)
+             (draw! context fps g))
+           (size [this context] [400 300])))
     
     (doto frame
       (.addWindowListener
--- a/src/indyvon/core.clj	Sat Jun 19 04:27:29 2010 +0400
+++ b/src/indyvon/core.clj	Sat Jun 19 06:50:24 2010 +0400
@@ -9,9 +9,21 @@
            (java.awt.font FontRenderContext TextLayout)))
 
 (defprotocol Layer
+  "Basic UI element."
   (render! [this context graphics])
   (size [this context]))
 
+(defprotocol MouseHandler
+  "Layers that also satisfy this protocol will recieve mouse events."
+  (handle-mouse [this context event]))
+
+(defprotocol EventDispatcher
+  (listen! [this component])
+  (register [this context])
+  (commit [this])
+  (hovered? [this layer])
+  (picked? [this layer]))
+
 (defrecord Theme [fore-color back-color border-color font])
 
 (defn default-theme []
@@ -23,6 +35,9 @@
 (defn default-context []
   (LayerContext. nil nil 0 0 0 0 nil nil nil (default-theme)))
 
+(defn update [context]
+  ((:update-fn context)))
+
 (defn- make-graphics [graphics x y w h clip]
   (if clip
     (.create graphics x y w h)
@@ -49,18 +64,18 @@
      (draw! context layer graphics
             x y w h true))
   ([context layer graphics x y w h clip]
-     (let [graphics (make-graphics graphics x y w h clip)
+     (let [context (assoc context
+                     :layer layer
+                     :parent context
+                     :x (+ (:x context) x)
+                     :y (+ (:y context) y)
+                     :width w
+                     :height h)
+           graphics (make-graphics graphics x y w h clip)
            graphics (apply-theme graphics (:theme context))]
        (try
-         (render! layer
-                  (assoc context
-                    :layer layer
-                    :parent context
-                    :x (+ (:x context) x)
-                    :y (+ (:y context) y)
-                    :width w
-                    :height h)
-                  graphics)
+         (register (:dispatcher context) context)
+         (render! layer context graphics)
          (finally
           (.dispose graphics))))))
 
--- a/src/indyvon/event.clj	Sat Jun 19 04:27:29 2010 +0400
+++ b/src/indyvon/event.clj	Sat Jun 19 06:50:24 2010 +0400
@@ -9,19 +9,6 @@
   (:import (java.awt.event MouseEvent MouseListener MouseMotionListener)
            java.lang.ref.WeakReference))
 
-(defprotocol EventDispatcher
-  (listen! [this component])
-  (register-mouse-handler [this context handler])
-  (commit [this])
-  (hovered? [this layer])
-  (picked? [this layer]))
-
-(defn mouse-handler [context handler & args]
-  "The supplied handler function will be invoked with context, event
-   and additional args when mouse event occurs on the context."
-  (let [handler (if args #(apply handler %1 %2 args) handler)]
-    (register-mouse-handler (:dispatcher context) context handler)))
-
 (defn- registered-parent
   "Returns first context parent registered for event processing."
   [context-tree context]
@@ -72,23 +59,19 @@
     (getXOnScreen [] (.getXOnScreen event))
     (getYOnScreen [] (.getYOnScreen event))))
 
-(defn- dispatch-event [handlers context event]
-  ((handlers context) context event))
-
 (defn- translate-and-dispatch
-  ([contexts handlers event]
-     (translate-and-dispatch contexts handlers event (.getID event)))
-  ([contexts handlers event id]
-  (doseq [context contexts]
-    (dispatch-event
-     handlers
-     context
-     (translate-mouse-event event (:x context) (:y context) id)))))
+  ([contexts event]
+     (translate-and-dispatch contexts event (.getID event)))
+  ([contexts event id]
+     (doseq [context contexts]
+       (handle-mouse
+        (:layer context) 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
   currently are under cursor."
-  [hovered context-tree handlers event]
+  [hovered context-tree event]
   (let [x (.getX event)
         y (.getY event)
         hovered2 (under-cursor context-tree x y)
@@ -96,39 +79,33 @@
         exited (remove-all hovered hovered2 pred)
         entered (remove-all hovered2 hovered pred)
         moved (remove-all hovered2 entered pred)]
-    (translate-and-dispatch
-     exited handlers event MouseEvent/MOUSE_EXITED)
-    (translate-and-dispatch
-     entered handlers event MouseEvent/MOUSE_ENTERED)
-    (translate-and-dispatch
-     moved handlers event MouseEvent/MOUSE_MOVED)
+    (translate-and-dispatch exited event MouseEvent/MOUSE_EXITED)
+    (translate-and-dispatch entered event MouseEvent/MOUSE_ENTERED)
+    (translate-and-dispatch moved event MouseEvent/MOUSE_MOVED)
     hovered2))
 
 (defn- dispatch-mouse-motion
-  [hovered-ref context-tree handlers event]
+  [hovered-ref context-tree event]
   (dosync
-   (alter hovered-ref dispatch-mouse-motion* context-tree handlers event)))
+   (alter hovered-ref dispatch-mouse-motion* context-tree event)))
 
 (defn- dispatch-mouse-button*
   "Dispatches mouse button events. Returns a new set of contexts which
   currently are picked with a pressed button."
-  [picked hovered handlers event]
-  (translate-and-dispatch hovered handlers event)
+  [picked hovered event]
+  (translate-and-dispatch hovered event)
   (if (= (.getID event) MouseEvent/MOUSE_PRESSED)
     hovered
     nil))
 
 (defn- dispatch-mouse-button
-  [picked-ref hovered-ref handlers event]
+  [picked-ref hovered-ref event]
   (dosync
-   (alter picked-ref dispatch-mouse-button*
-          @hovered-ref handlers event)))
+   (alter picked-ref dispatch-mouse-button* @hovered-ref event)))
 
 (defn make-event-dispatcher []
   (let [context-tree-r (ref {}) ; register
-        handlers-r (ref {})     ;
         context-tree (ref {})   ; dispatch
-        handlers (ref {})       ;
         hovered (ref '())
         picked (ref '())]
     (reify
@@ -137,29 +114,27 @@
         (doto component
           (.addMouseListener this)
           (.addMouseMotionListener this)))
-     (register-mouse-handler [this context handler]
-        (dosync (alter context-tree-r add-context context)
-                (alter handlers-r assoc context handler)))
+     (register [this context]
+        (when (satisfies? MouseHandler (:layer context))
+          (dosync (alter context-tree-r add-context context))))
      (commit [this]
         (dosync (ref-set context-tree @context-tree-r)
-                (ref-set context-tree-r {})
-                (ref-set handlers @handlers-r)
-                (ref-set handlers-r {})))
+                (ref-set context-tree-r {})))
      (picked? [this layer] false)
      (hovered? [this layer] false)
      MouseListener
      (mouseEntered [this event]
-        (dispatch-mouse-motion hovered context-tree handlers event))
+        (dispatch-mouse-motion hovered @context-tree event))
      (mouseExited [this event]
-        (dispatch-mouse-motion hovered context-tree handlers event))
+        (dispatch-mouse-motion hovered @context-tree event))
      (mouseClicked [this event]
-        (dispatch-mouse-button picked hovered handlers event))
+        (dispatch-mouse-button picked hovered event))
      (mousePressed [this event]
-        (dispatch-mouse-button picked hovered handlers  event))
+        (dispatch-mouse-button picked hovered event))
      (mouseReleased [this event]
-        (dispatch-mouse-button picked hovered handlers event))
+        (dispatch-mouse-button picked hovered event))
      MouseMotionListener
      (mouseDragged [this event]
-        (translate-and-dispatch @picked handlers event))
+        (translate-and-dispatch @picked event))
      (mouseMoved [this event]
-        (dispatch-mouse-motion hovered context-tree handlers event)))))
+        (dispatch-mouse-motion hovered @context-tree event)))))