Mercurial > hg > indyvon
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 wrap: on
line diff
--- a/src/indyvon/component.clj Wed Jul 07 05:57:49 2010 +0400 +++ b/src/indyvon/component.clj Wed Jul 07 07:17:08 2010 +0400 @@ -19,11 +19,17 @@ width (.width size) height (.height size) context (assoc context + :x 0 + :y 0 + :width width + :height height + :clip (indyvon.core.Bounds. 0 0 width height) :target component + :graphics graphics :font-context (.getFontRenderContext graphics) :update-fn #(.repaint component))] (.clearRect graphics 0 0 width height) - (draw! layer context graphics 0 0 width height false)) + (draw! layer context)) (commit (:event-dispatcher context))) (defn preferred-size [component layer context] @@ -56,9 +62,14 @@ (def layer1 (reify Layer - (render! [this context g] - (.setColor g Color/RED) - (.fillRect g 0 0 (:width context) (:height context))) + (render! [this context] + (let-handlers this [context] + (doto (graphics context) + (.setColor Color/RED) + (.fillRect 0 0 (:width context) (:height context))) + (:mouse-entered e (println e)) + (:mouse-exited e (println e)) + (:mouse-moved e (println e)))) (size [this context] (Size. 30 20)))) (def layer1b (border-layer layer1 2 3)) @@ -66,11 +77,12 @@ (def layer2 (reify Layer - (render! [this context g] - (.setColor g Color/YELLOW) - (.fillRect g 0 0 (:width context) (:height context)) - (draw! layer1b context g 10 5) - (draw! layer1 context g 55 5)) + (render! [this context] + (doto (graphics context) + (.setColor Color/YELLOW) + (.fillRect 0 0 (:width context) (:height context))) + (draw! layer1b context 10 5) + (draw! layer1 context 55 5)) (size [this context] (Size. 70 65)))) (def layer3 @@ -86,8 +98,8 @@ fl (ref (fps-layer 0.0))] (reify Layer - (render! [this c g] - (draw! @fl c g) + (render! [this c] + (draw! @fl c) (dosync (alter frames + 1) (let [time (System/currentTimeMillis) @@ -100,13 +112,14 @@ (def layer (reify Layer - (render! [this context g] + (render! [this context] (update context) - (.setColor g (rand-nth [Color/BLACK Color/BLUE Color/RED])) - (.drawLine g 0 0 (:width context) (:height context)) - (draw! layer2 context g 15 20) - (draw! layer3 context g 100 100 80 50) - (draw! fps context g)) + (doto (graphics context) + (.setColor (rand-nth [Color/BLACK Color/BLUE Color/RED])) + (.drawLine 0 0 (:width context) (:height context))) + (draw! layer2 context 15 20) + (draw! layer3 context 100 100 80 50) + (draw! fps context)) (size [this context] (Size. 400 300)))) (doto frame
--- a/src/indyvon/core.clj Wed Jul 07 05:57:49 2010 +0400 +++ b/src/indyvon/core.clj Wed Jul 07 07:17:08 2010 +0400 @@ -5,16 +5,17 @@ ;; (ns indyvon.core - (:import (java.awt Graphics Component Color Font) + (:import (java.awt Graphics2D Component Color Font) (java.awt.event MouseListener MouseMotionListener))) (defprotocol Layer "Basic UI element." - (render! [this context graphics]) + (render! [this context]) (size [this context])) (defrecord Location [x y]) (defrecord Size [width height]) +(defrecord Bounds [x y width height]) ;; TODO: modifiers (defrecord MouseEvent [id when x y x-on-screen y-on-screen button]) @@ -58,53 +59,68 @@ (defn default-theme [] (Theme. Color/BLACK Color/WHITE Color/BLUE (Font. "Sans" Font/PLAIN 12))) -(defrecord LayerContext [x y width height update-fn font-context - theme target event-dispatcher]) +(defrecord LayerContext [x y width height clip + update-fn font-context theme + target event-dispatcher]) (defn default-context [] - (LayerContext. 0 0 0 0 nil nil (default-theme) nil nil)) + (LayerContext. 0 0 0 0 nil nil nil (default-theme) nil nil)) (defn update [context] ((:update-fn context))) -(defn- ^Graphics make-graphics [^Graphics graphics x y w h clip] - (if clip - (.create graphics x y w h) - (doto (.create graphics) - (.translate x y)))) +(defn ^Graphics2D graphics + "Get AWT Graphics2D from context." + [context] + (:graphics context)) -(defn- ^Graphics apply-theme [^Graphics graphics theme] +(defn- ^Graphics2D make-graphics [^Graphics2D graphics x y w h] + (.create graphics x y w h)) + +(defn- ^Graphics2D apply-theme [^Graphics2D graphics theme] (doto graphics (.setColor (:fore-color theme)) (.setFont (:font theme)))) +(defn intersect [bounds x y w h] + (let [x12 (+ x w) + y12 (+ y h) + x21 (:x bounds) + y21 (:y bounds) + x22 (+ x21 (:width bounds)) + y22 (+ y21 (:height bounds)) + x1 (max x x21) + y1 (max y y21) + x2 (min x12 x22) + y2 (min y12 y22)] + (Bounds. x1 y1 (- x2 x1) (- y2 y1)))) + +(defn translate [context x y w h] + (let [ax (+ (:x context) x) + ay (+ (:y context) y)] + (assoc context + :x (+ (:x context) x) + :y (+ (:y context) y) + :width w + :height h + :clip (intersect (:clip context) ax ay w h) + :graphics (apply-theme + (make-graphics (:graphics context) x y w h) + (:theme context))))) + (defn draw! "Render layer in a new graphics context." - ([layer context graphics] - (render! layer context graphics)) - ([layer context graphics x y] - (draw! layer context graphics x y true)) - ([layer context graphics x y clip] + ([layer context] + (render! layer context)) + ([layer context x y] (let [s (size layer context)] - (draw! layer context graphics - x y (:width s) (:height s) clip))) - ([layer context graphics x y w h] - (draw! layer context graphics - x y w h true)) - ([layer context 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))] + (draw! layer context x y (:width s) (:height s)))) + ([layer context x y w h] + (let [context (translate context x y w h)] (try - (render! layer context graphics) + (render! layer context) (finally - (.dispose graphics)))))) + (.dispose (:graphics context))))))) (defn add-handlers [context handle handlers] "Returns new context with the specified event handlers." @@ -113,9 +129,9 @@ (create-dispatcher (:event-dispatcher context) context handle handlers))) -(defmacro let-handlers [handle bindings & specs] +(defmacro let-handlers [handle bindings form & specs] "bindings => [binding-form context] or [context-symbol] - specs => (:event-id name & handler-body)* form + specs => (:event-id name & handler-body)* Execute form with the specified event handlers." (let [[binding context] bindings @@ -127,8 +143,8 @@ (assoc m (first spec) `(fn [~(second spec)] ~@(nnext spec)))) {} - (butlast specs)))] - ~(last specs)))) + specs))] + ~form))) ;; ;; EventDispatcher implementation @@ -143,7 +159,7 @@ java.awt.event.MouseEvent/MOUSE_PRESSED :mouse-pressed java.awt.event.MouseEvent/MOUSE_RELEASED :mouse-released}) -(defrecord DispatcherNode [handle handlers parent x y width height] +(defrecord DispatcherNode [handle handlers parent bounds] EventDispatcher (listen! [this component] (listen! parent component)) @@ -153,8 +169,7 @@ (commit parent))) (defn- make-node [c handle handlers] - (DispatcherNode. handle handlers (:event-dispatcher c) - (:x c) (:y c) (:width c) (:height c))) + (DispatcherNode. handle handlers (:event-dispatcher c) (:clip c))) (defn- assoc-cons [m key val] (assoc m key (cons val (get m key)))) @@ -163,9 +178,9 @@ (assoc-cons tree (:parent node) node)) (defn- inside? - ([x y node] - (inside? x y (:x node) (:y node) - (:width node) (:height node))) + ([x y bounds] + (inside? x y (:x bounds) (:y bounds) + (:width bounds) (:height bounds))) ([px py x y w h] (and (>= px x) (>= py y) @@ -175,7 +190,7 @@ (defn- under-cursor "Returns a sequence of child nodes under cursor." [x y tree node] - (some #(if (inside? x y %) + (some #(if (inside? x y (:bounds %)) (conj (under-cursor x y tree %) %)) (get tree node))) @@ -195,7 +210,8 @@ (doseq [node nodes] (when-let [handler (get (:handlers node) id)] (handler - (translate-mouse-event event (:x node) (:y node) id)))) + (translate-mouse-event event + (-> node :bounds :x) (-> node :bounds :y) id)))) id)) (defn- dispatch-mouse-motion*
--- a/src/indyvon/layers.clj Wed Jul 07 05:57:49 2010 +0400 +++ b/src/indyvon/layers.clj Wed Jul 07 07:17:08 2010 +0400 @@ -33,13 +33,13 @@ ([content width gap] (let [offset (+ width gap)] (reify Layer - (render! [l c g] + (render! [l c] (let [w (:width c) h (:height c)] - (.setColor g (-> c :theme :border-color)) + (.setColor (graphics c) (-> c :theme :border-color)) (doseq [i (range 0 width)] - (.drawRect g i i (- w 1 i i) (- h 1 i i))) - (draw! content c g offset offset (- w offset offset) + (.drawRect (graphics c) i i (- w 1 i i) (- h 1 i i))) + (draw! content c offset offset (- w offset offset) (- h offset offset)))) (size [l c] (let [s (size content c)] @@ -66,10 +66,10 @@ ([text h-align v-align] (let [lines (re-split #"\r\n|\n|\r|\u0085|\u2028|\u2029" text)] (reify Layer - (render! [l c g] + (render! [l c] (let [w (:width c) h (:height c) - font (.getFont g) + font (.getFont (graphics c)) font-context (:font-context c) layouts (layout-text lines font font-context) y (align-y (text-height layouts) h v-align)] @@ -78,7 +78,7 @@ (let [ascent (.getAscent layout) lh (+ ascent (.getDescent layout) (.getLeading layout)) x (align-x (.getAdvance layout) w h-align)] - (.draw layout g x (+ y ascent)) + (.draw layout (graphics c) x (+ y ascent)) (recur (next layouts) (+ y lh))))))) (size [l c] (let [layouts (layout-text lines @@ -100,8 +100,19 @@ last-height (ref 0)] (reify Layer - (render! [layer c g] + (render! [layer c] (let-handlers layer [c] + (let [anchor (anchor content c h-align v-align) + width (:width c) + height (:height c)] + (dosync + (alter x + (align-x width @last-width h-align)) + (alter y + (align-y height @last-height v-align)) + (ref-set last-width width) + (ref-set last-height height)) + (draw! content c + (- 0 @x (:x anchor)) + (- 0 @y (:y anchor)))) (:mouse-pressed e (dosync (ref-set fix-x (:x-on-screen e)) @@ -115,16 +126,5 @@ (alter y + (- @fix-y (:y-on-screen e))) (ref-set fix-x (:x-on-screen e)) (ref-set fix-y (:y-on-screen e))) - (update c)) - (let [anchor (anchor content c h-align v-align) - width (:width c) - height (:height c)] - (dosync - (alter x + (align-x width @last-width h-align)) - (alter y + (align-y height @last-height v-align)) - (ref-set last-width width) - (ref-set last-height height)) - (draw! content c g - (- 0 @x (:x anchor)) - (- 0 @y (:y anchor)))))) + (update c)))) (size [layer c] (size content c))))))