changeset 33:439f6ecee119

Include graphics into context. Event dispatcher respects clipping.
author Mikhail Kryshen <mikhail@kryshen.net>
date Wed, 07 Jul 2010 07:17:08 +0400
parents 0b3757d263db
children 6975b9a71eec
files src/indyvon/component.clj src/indyvon/core.clj src/indyvon/layers.clj
diffstat 3 files changed, 111 insertions(+), 82 deletions(-) [+]
line diff
     1.1 --- a/src/indyvon/component.clj	Wed Jul 07 05:57:49 2010 +0400
     1.2 +++ b/src/indyvon/component.clj	Wed Jul 07 07:17:08 2010 +0400
     1.3 @@ -19,11 +19,17 @@
     1.4          width (.width size)
     1.5          height (.height size)
     1.6          context (assoc context
     1.7 +                  :x 0
     1.8 +                  :y 0
     1.9 +                  :width width
    1.10 +                  :height height
    1.11 +                  :clip (indyvon.core.Bounds. 0 0 width height)
    1.12                    :target component
    1.13 +                  :graphics graphics
    1.14                    :font-context (.getFontRenderContext graphics)
    1.15                    :update-fn #(.repaint component))]
    1.16      (.clearRect graphics 0 0 width height)
    1.17 -    (draw! layer context graphics 0 0 width height false))
    1.18 +    (draw! layer context))
    1.19    (commit (:event-dispatcher context)))
    1.20  
    1.21  (defn preferred-size [component layer context]
    1.22 @@ -56,9 +62,14 @@
    1.23      (def layer1
    1.24           (reify
    1.25            Layer
    1.26 -          (render! [this context g]
    1.27 -             (.setColor g Color/RED)
    1.28 -             (.fillRect g 0 0 (:width context) (:height context)))
    1.29 +          (render! [this context]
    1.30 +             (let-handlers this [context]
    1.31 +               (doto (graphics context)
    1.32 +                 (.setColor Color/RED)
    1.33 +                 (.fillRect 0 0 (:width context) (:height context)))
    1.34 +               (:mouse-entered e (println e))
    1.35 +               (:mouse-exited e (println e))
    1.36 +               (:mouse-moved e (println e))))
    1.37            (size [this context] (Size. 30 20))))
    1.38      
    1.39      (def layer1b (border-layer layer1 2 3))
    1.40 @@ -66,11 +77,12 @@
    1.41      (def layer2
    1.42           (reify
    1.43            Layer
    1.44 -          (render! [this context g]
    1.45 -             (.setColor g Color/YELLOW)
    1.46 -             (.fillRect g 0 0 (:width context) (:height context))
    1.47 -             (draw! layer1b context g 10 5)
    1.48 -             (draw! layer1 context g 55 5))
    1.49 +          (render! [this context]
    1.50 +             (doto (graphics context)
    1.51 +               (.setColor Color/YELLOW)
    1.52 +               (.fillRect 0 0 (:width context) (:height context)))
    1.53 +             (draw! layer1b context 10 5)
    1.54 +             (draw! layer1 context 55 5))
    1.55            (size [this context] (Size. 70 65))))
    1.56      
    1.57      (def layer3
    1.58 @@ -86,8 +98,8 @@
    1.59                 fl (ref (fps-layer 0.0))]
    1.60             (reify
    1.61              Layer
    1.62 -            (render! [this c g]
    1.63 -               (draw! @fl c g)
    1.64 +            (render! [this c]
    1.65 +               (draw! @fl c)
    1.66                 (dosync
    1.67                  (alter frames + 1)
    1.68                  (let [time (System/currentTimeMillis)
    1.69 @@ -100,13 +112,14 @@
    1.70      
    1.71      (def layer
    1.72           (reify Layer
    1.73 -           (render! [this context g]
    1.74 +           (render! [this context]
    1.75               (update context)
    1.76 -             (.setColor g (rand-nth [Color/BLACK Color/BLUE Color/RED]))       
    1.77 -             (.drawLine g 0 0 (:width context) (:height context))
    1.78 -             (draw! layer2 context g 15 20)
    1.79 -             (draw! layer3 context g 100 100 80 50)
    1.80 -             (draw! fps context g))
    1.81 +             (doto (graphics context)       
    1.82 +               (.setColor (rand-nth [Color/BLACK Color/BLUE Color/RED]))
    1.83 +               (.drawLine 0 0 (:width context) (:height context)))
    1.84 +             (draw! layer2 context 15 20)
    1.85 +             (draw! layer3 context 100 100 80 50)
    1.86 +             (draw! fps context))
    1.87             (size [this context] (Size. 400 300))))
    1.88      
    1.89      (doto frame
     2.1 --- a/src/indyvon/core.clj	Wed Jul 07 05:57:49 2010 +0400
     2.2 +++ b/src/indyvon/core.clj	Wed Jul 07 07:17:08 2010 +0400
     2.3 @@ -5,16 +5,17 @@
     2.4  ;;
     2.5  
     2.6  (ns indyvon.core
     2.7 -  (:import (java.awt Graphics Component Color Font)
     2.8 +  (:import (java.awt Graphics2D Component Color Font)
     2.9             (java.awt.event MouseListener MouseMotionListener)))
    2.10  
    2.11  (defprotocol Layer
    2.12    "Basic UI element."
    2.13 -  (render! [this context graphics])
    2.14 +  (render! [this context])
    2.15    (size [this context]))
    2.16  
    2.17  (defrecord Location [x y])
    2.18  (defrecord Size [width height])
    2.19 +(defrecord Bounds [x y width height])
    2.20  
    2.21  ;; TODO: modifiers
    2.22  (defrecord MouseEvent [id when x y x-on-screen y-on-screen button])
    2.23 @@ -58,53 +59,68 @@
    2.24  (defn default-theme []
    2.25    (Theme. Color/BLACK Color/WHITE Color/BLUE (Font. "Sans" Font/PLAIN 12)))
    2.26    
    2.27 -(defrecord LayerContext [x y width height update-fn font-context
    2.28 -                         theme target event-dispatcher])
    2.29 +(defrecord LayerContext [x y width height clip
    2.30 +                         update-fn font-context theme
    2.31 +                         target event-dispatcher])
    2.32  
    2.33  (defn default-context []
    2.34 -  (LayerContext. 0 0 0 0 nil nil (default-theme) nil nil))
    2.35 +  (LayerContext. 0 0 0 0 nil nil nil (default-theme) nil nil))
    2.36  
    2.37  (defn update [context]
    2.38    ((:update-fn context)))
    2.39  
    2.40 -(defn- ^Graphics make-graphics [^Graphics graphics x y w h clip]
    2.41 -  (if clip
    2.42 -    (.create graphics x y w h)
    2.43 -    (doto (.create graphics)
    2.44 -      (.translate x y))))
    2.45 +(defn ^Graphics2D graphics
    2.46 +  "Get AWT Graphics2D from context."
    2.47 +  [context]
    2.48 +  (:graphics context))
    2.49  
    2.50 -(defn- ^Graphics apply-theme [^Graphics graphics theme]
    2.51 +(defn- ^Graphics2D make-graphics [^Graphics2D graphics x y w h]
    2.52 +  (.create graphics x y w h))
    2.53 +
    2.54 +(defn- ^Graphics2D apply-theme [^Graphics2D graphics theme]
    2.55    (doto graphics
    2.56      (.setColor (:fore-color theme))
    2.57      (.setFont (:font theme))))
    2.58  
    2.59 +(defn intersect [bounds x y w h]
    2.60 +  (let [x12 (+ x w)
    2.61 +        y12 (+ y h)
    2.62 +        x21 (:x bounds)
    2.63 +        y21 (:y bounds)
    2.64 +        x22 (+ x21 (:width bounds))
    2.65 +        y22 (+ y21 (:height bounds))
    2.66 +        x1 (max x x21)
    2.67 +        y1 (max y y21)
    2.68 +        x2 (min x12 x22)
    2.69 +        y2 (min y12 y22)]
    2.70 +    (Bounds. x1 y1 (- x2 x1) (- y2 y1))))
    2.71 +
    2.72 +(defn translate [context x y w h]
    2.73 +  (let [ax (+ (:x context) x)
    2.74 +        ay (+ (:y context) y)]
    2.75 +    (assoc context
    2.76 +      :x (+ (:x context) x)
    2.77 +      :y (+ (:y context) y)
    2.78 +      :width w
    2.79 +      :height h
    2.80 +      :clip (intersect (:clip context) ax ay w h)
    2.81 +      :graphics (apply-theme
    2.82 +                 (make-graphics (:graphics context) x y w h)
    2.83 +                 (:theme context)))))
    2.84 +
    2.85  (defn draw!
    2.86    "Render layer in a new graphics context."
    2.87 -  ([layer context graphics]
    2.88 -     (render! layer context graphics))
    2.89 -  ([layer context graphics x y]
    2.90 -     (draw! layer context graphics x y true))
    2.91 -  ([layer context graphics x y clip]
    2.92 +  ([layer context]
    2.93 +     (render! layer context))
    2.94 +  ([layer context x y]
    2.95       (let [s (size layer context)]
    2.96 -       (draw! layer context graphics
    2.97 -              x y (:width s) (:height s) clip)))
    2.98 -  ([layer context graphics x y w h]
    2.99 -     (draw! layer context graphics
   2.100 -            x y w h true))
   2.101 -  ([layer context graphics x y w h clip]
   2.102 -     (let [context (assoc context
   2.103 -                     :layer layer
   2.104 -                     :parent context
   2.105 -                     :x (+ (:x context) x)
   2.106 -                     :y (+ (:y context) y)
   2.107 -                     :width w
   2.108 -                     :height h)
   2.109 -           graphics (make-graphics graphics x y w h clip)
   2.110 -           graphics (apply-theme graphics (:theme context))]
   2.111 +       (draw! layer context x y (:width s) (:height s))))
   2.112 +  ([layer context x y w h]
   2.113 +     (let [context (translate context x y w h)]
   2.114         (try
   2.115 -         (render! layer context graphics)
   2.116 +         (render! layer context)
   2.117           (finally
   2.118 -          (.dispose graphics))))))
   2.119 +          (.dispose (:graphics context)))))))
   2.120  
   2.121  (defn add-handlers [context handle handlers]
   2.122    "Returns new context with the specified event handlers."
   2.123 @@ -113,9 +129,9 @@
   2.124      (create-dispatcher (:event-dispatcher context) context
   2.125                         handle handlers)))
   2.126  
   2.127 -(defmacro let-handlers [handle bindings & specs]
   2.128 +(defmacro let-handlers [handle bindings form & specs]
   2.129    "bindings => [binding-form context] or [context-symbol]
   2.130 -   specs => (:event-id name & handler-body)* form
   2.131 +   specs => (:event-id name & handler-body)*
   2.132  
   2.133    Execute form with the specified event handlers."
   2.134    (let [[binding context] bindings
   2.135 @@ -127,8 +143,8 @@
   2.136                          (assoc m (first spec)
   2.137                                 `(fn [~(second spec)]
   2.138                                    ~@(nnext spec)))) {}
   2.139 -                                  (butlast specs)))]
   2.140 -           ~(last specs))))
   2.141 +                                  specs))]
   2.142 +           ~form)))
   2.143  
   2.144  ;;
   2.145  ;; EventDispatcher implementation
   2.146 @@ -143,7 +159,7 @@
   2.147        java.awt.event.MouseEvent/MOUSE_PRESSED  :mouse-pressed
   2.148        java.awt.event.MouseEvent/MOUSE_RELEASED :mouse-released})
   2.149  
   2.150 -(defrecord DispatcherNode [handle handlers parent x y width height]
   2.151 +(defrecord DispatcherNode [handle handlers parent bounds]
   2.152    EventDispatcher
   2.153    (listen! [this component]
   2.154       (listen! parent component))
   2.155 @@ -153,8 +169,7 @@
   2.156       (commit parent)))
   2.157  
   2.158  (defn- make-node [c handle handlers]
   2.159 -  (DispatcherNode. handle handlers (:event-dispatcher c)
   2.160 -                   (:x c) (:y c) (:width c) (:height c)))
   2.161 +  (DispatcherNode. handle handlers (:event-dispatcher c) (:clip c)))
   2.162  
   2.163  (defn- assoc-cons [m key val]
   2.164    (assoc m key (cons val (get m key))))
   2.165 @@ -163,9 +178,9 @@
   2.166    (assoc-cons tree (:parent node) node))
   2.167  
   2.168  (defn- inside?
   2.169 -  ([x y node]
   2.170 -     (inside? x y (:x node) (:y node)
   2.171 -              (:width node) (:height node)))
   2.172 +  ([x y bounds]
   2.173 +     (inside? x y (:x bounds) (:y bounds)
   2.174 +              (:width bounds) (:height bounds)))
   2.175    ([px py x y w h]
   2.176       (and (>= px x)
   2.177            (>= py y)
   2.178 @@ -175,7 +190,7 @@
   2.179  (defn- under-cursor
   2.180    "Returns a sequence of child nodes under cursor."
   2.181    [x y tree node]
   2.182 -  (some #(if (inside? x y %)
   2.183 +  (some #(if (inside? x y (:bounds %))
   2.184             (conj (under-cursor x y tree %) %))
   2.185          (get tree node)))
   2.186  
   2.187 @@ -195,7 +210,8 @@
   2.188       (doseq [node nodes]
   2.189         (when-let [handler (get (:handlers node) id)]
   2.190           (handler
   2.191 -          (translate-mouse-event event (:x node) (:y node) id))))
   2.192 +          (translate-mouse-event event
   2.193 +            (-> node :bounds :x) (-> node :bounds :y) id))))
   2.194       id))
   2.195  
   2.196  (defn- dispatch-mouse-motion*
     3.1 --- a/src/indyvon/layers.clj	Wed Jul 07 05:57:49 2010 +0400
     3.2 +++ b/src/indyvon/layers.clj	Wed Jul 07 07:17:08 2010 +0400
     3.3 @@ -33,13 +33,13 @@
     3.4    ([content width gap]
     3.5       (let [offset (+ width gap)]
     3.6         (reify Layer
     3.7 -        (render! [l c g]
     3.8 +        (render! [l c]
     3.9             (let [w (:width c)
    3.10                   h (:height c)]
    3.11 -             (.setColor g (-> c :theme :border-color))
    3.12 +             (.setColor (graphics c) (-> c :theme :border-color))
    3.13               (doseq [i (range 0 width)]
    3.14 -               (.drawRect g i i (- w 1 i i) (- h 1 i i)))
    3.15 -             (draw! content c g offset offset (- w offset offset)
    3.16 +               (.drawRect (graphics c) i i (- w 1 i i) (- h 1 i i)))
    3.17 +             (draw! content c offset offset (- w offset offset)
    3.18                      (- h offset offset))))
    3.19          (size [l c]
    3.20             (let [s (size content c)]
    3.21 @@ -66,10 +66,10 @@
    3.22    ([text h-align v-align]
    3.23       (let [lines (re-split #"\r\n|\n|\r|\u0085|\u2028|\u2029" text)]
    3.24         (reify Layer
    3.25 -        (render! [l c g]
    3.26 +        (render! [l c]
    3.27             (let [w (:width c)
    3.28                   h (:height c)
    3.29 -                 font (.getFont g)
    3.30 +                 font (.getFont (graphics c))
    3.31                   font-context (:font-context c)
    3.32                   layouts (layout-text lines font font-context)
    3.33                   y (align-y (text-height layouts) h v-align)]
    3.34 @@ -78,7 +78,7 @@
    3.35                   (let [ascent (.getAscent layout)
    3.36                         lh (+ ascent (.getDescent layout) (.getLeading layout))
    3.37                         x (align-x (.getAdvance layout) w h-align)]
    3.38 -                   (.draw layout g x (+ y ascent))
    3.39 +                   (.draw layout (graphics c) x (+ y ascent))
    3.40                     (recur (next layouts) (+ y lh)))))))
    3.41          (size [l c]
    3.42             (let [layouts (layout-text lines
    3.43 @@ -100,8 +100,19 @@
    3.44          last-height (ref 0)]
    3.45      (reify
    3.46       Layer
    3.47 -     (render! [layer c g]
    3.48 +     (render! [layer c]
    3.49          (let-handlers layer [c]
    3.50 +         (let [anchor (anchor content c h-align v-align)
    3.51 +               width (:width c)
    3.52 +               height (:height c)]
    3.53 +           (dosync
    3.54 +            (alter x + (align-x width @last-width h-align))
    3.55 +            (alter y + (align-y height @last-height v-align))
    3.56 +            (ref-set last-width width)
    3.57 +            (ref-set last-height height))
    3.58 +           (draw! content c
    3.59 +                  (- 0 @x (:x anchor))
    3.60 +                  (- 0 @y (:y anchor))))
    3.61           (:mouse-pressed e
    3.62            (dosync
    3.63             (ref-set fix-x (:x-on-screen e))
    3.64 @@ -115,16 +126,5 @@
    3.65             (alter y + (- @fix-y (:y-on-screen e)))
    3.66             (ref-set fix-x (:x-on-screen e))
    3.67             (ref-set fix-y (:y-on-screen e)))
    3.68 -          (update c))
    3.69 -         (let [anchor (anchor content c h-align v-align)
    3.70 -               width (:width c)
    3.71 -               height (:height c)]
    3.72 -           (dosync
    3.73 -            (alter x + (align-x width @last-width h-align))
    3.74 -            (alter y + (align-y height @last-height v-align))
    3.75 -            (ref-set last-width width)
    3.76 -            (ref-set last-height height))
    3.77 -           (draw! content c g
    3.78 -                  (- 0 @x (:x anchor))
    3.79 -                  (- 0 @y (:y anchor))))))
    3.80 +          (update c))))
    3.81       (size [layer c] (size content c))))))