changeset 44:064b21604f74

Improved performance. Added image layer.
author Mikhail Kryshen <mikhail@kryshen.net>
date Mon, 19 Jul 2010 15:36:08 +0400
parents 7d67064f0880
children 33d836041cef
files src/kryshen/indyvon/core.clj src/kryshen/indyvon/graph.clj src/kryshen/indyvon/layers.clj
diffstat 3 files changed, 99 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/src/kryshen/indyvon/core.clj	Mon Jul 12 03:52:21 2010 +0400
+++ b/src/kryshen/indyvon/core.clj	Mon Jul 19 15:36:08 2010 +0400
@@ -95,33 +95,32 @@
            y2 (min y12 y22)]
        (Bounds. x1 y1 (- x2 x1) (- y2 y1)))))
 
-(defn- ^Graphics2D create-graphics
+(defn ^Graphics2D create-graphics
   ([]
      (create-graphics 0 0 (:width *bounds*) (:height *bounds*)))
   ([x y w h]
      (apply-theme (.create *graphics* x y w h) *theme*)))
 
-(defn with-bounds* [x y w h f & args]
-  (let [graphics (create-graphics x y w h)
-        bounds (Bounds. (+ x (:x *bounds*))
-                        (+ y (:y *bounds*))
-                        w h)]
-    (try
-      (apply with-bindings* {#'*bounds* bounds
-                             #'*clip* (intersect bounds *clip*)
-                             #'*graphics* graphics}
-             f args)
-      (finally
-       (.dispose graphics)))))
+(defmacro with-bounds [x y w h & body]
+  `(let [bounds# (Bounds. (+ ~x (:x *bounds*))
+                          (+ ~y (:y *bounds*))
+                          ~w ~h)
+         clip# (intersect bounds# *clip*)]
+     (when (and (pos? (:width clip#)) (pos? (:height clip#)))
+       (let [graphics# (create-graphics ~x ~y ~w ~h)]
+         (try
+           (binding [*bounds* bounds#
+                     *clip* clip#
+                     *graphics* graphics#]
+             ~@body)
+           (finally
+            (.dispose graphics#)))))))
 
-(defmacro with-bounds [x y w h & body]
-  `(with-bounds* ~x ~y ~w ~h (fn [] ~@body)))
-
-(defn with-handlers* [handle handlers f & args]
-  (apply with-bindings*
-         {#'*event-dispatcher*
-          (create-dispatcher *event-dispatcher* handle handlers)}
-         f args))
+(defmacro with-handlers* [handle handlers & body]
+  `(binding
+       [*event-dispatcher*
+        (create-dispatcher *event-dispatcher* ~handle ~handlers)]
+     ~@body))
 
 (defmacro with-handlers
   "specs => (:event-id name & handler-body)*
@@ -134,14 +133,15 @@
                        `(fn [~(second spec)]
                           ~@(nnext spec)))) {}
                           specs)
-     (fn [] ~form)))
+     ~form))
 
 (defn with-theme* [theme f & args]
   (apply with-bindings* {#'*theme* (merge *theme* theme)}
          f args))
 
 (defmacro with-theme [theme & body]
-  `(with-theme* ~theme (fn [] ~@body)))
+  `(binding [*theme* (merge *theme* ~theme)]
+     ~@body))
 
 (defmacro with-color [color & body]
   `(let [color# (.getColor *graphics*)]
@@ -160,14 +160,16 @@
   ([layer]
      (let [graphics (create-graphics)]
        (try
-         (with-bindings* {#'*graphics* graphics} render! layer)
+         (binding [*graphics* graphics]
+           (render! layer))
          (finally
           (.dispose graphics)))))
   ([layer x y]
      (let [size (layer-size layer)]
        (draw! layer x y (:width size) (:height size))))
   ([layer x y width height]
-     (with-bounds* x y width height render! layer)))
+     (with-bounds x y width height
+       (render! layer))))
 
 (defn draw-anchored!
   "Draw with location relative to the anchor point."
@@ -305,7 +307,8 @@
      (mousePressed [this event]
         (dispatch-mouse-button picked hovered event))
      (mouseReleased [this event]
-        (dispatch-mouse-button picked hovered event))
+        (translate-and-dispatch @picked true event))
+        ;;(dispatch-mouse-button picked hovered event))
      MouseMotionListener
      (mouseDragged [this event]
         (translate-and-dispatch @picked true event))
--- a/src/kryshen/indyvon/graph.clj	Mon Jul 12 03:52:21 2010 +0400
+++ b/src/kryshen/indyvon/graph.clj	Mon Jul 19 15:36:08 2010 +0400
@@ -76,29 +76,29 @@
     (.draw *graphics* path)))
   (.translate *graphics* (- x) (- y)))
 
-(defrecord GraphLayer [graph-layout movable dragged fix-x fix-y]
+(defrecord GraphLayer [layout movable dragged fix-x fix-y]
   Layer
   (render! [layer]
-     (let [bounds (.getBounds graph-layout)
+     (let [bounds (.getBounds layout)
            x (- (.getX bounds))
            y (- (.getY bounds))]
-       (draw-edges! graph-layout x y)
+       (draw-edges! layout x y)
        (if movable
-         (draw-movable-vertices! graph-layout x y dragged fix-x fix-y)
-         (draw-vertices! graph-layout x y))))
+         (draw-movable-vertices! layout x y dragged fix-x fix-y)
+         (draw-vertices! layout x y))))
   (layer-size [layer]
-     (let [bounds (.getBounds graph-layout)]
+     (let [bounds (.getBounds layout)]
        (Size. (.getWidth bounds) (.getHeight bounds))))
   Anchored
   (anchor [layer x-align y-align]
-          (let [bounds (.getBounds graph-layout)]
+          (let [bounds (.getBounds layout)]
             (Location. (- (.getX bounds))
                        (- (.getY bounds))))))
 
 (defn graph-layer
   ([graph-layout]
      (graph-layer graph-layout false))
-  ([^GraphGraph-Layout graph-layout movable]
+  ([^GraphLayout graph-layout movable]
      (GraphLayer. graph-layout movable (ref nil) (ref 0) (ref 0))))
 
 (defn build-graph
--- a/src/kryshen/indyvon/layers.clj	Mon Jul 12 03:52:21 2010 +0400
+++ b/src/kryshen/indyvon/layers.clj	Mon Jul 19 15:36:08 2010 +0400
@@ -7,7 +7,9 @@
 (ns kryshen.indyvon.layers
   (:use kryshen.indyvon.core)
   (:import (kryshen.indyvon.core Size Location)
-           (java.awt Font Cursor)
+           (java.lang.ref SoftReference)
+           (java.awt Font Cursor Image Toolkit)
+           (java.awt.image ImageObserver)
            (java.awt.font FontRenderContext TextLayout)))
 
 ;; Define as macro to avoid unnecessary calculation of inner and outer
@@ -25,12 +27,13 @@
   `(align-xy ~inner ~outer ~align :top :center :bottom))
 
 (defmacro decorate-layer [layer & render-tail]
-  `(reify
-    Layer
-    (render! ~@render-tail)
-    (layer-size [t#] (layer-size ~layer))
-    Anchored
-    (anchor [t# xa# ya#] (anchor ~layer xa# ya#))))
+  `(let [layer# ~layer]
+     (reify
+      Layer
+      (render! ~@render-tail)
+      (layer-size [t#] (layer-size layer#))
+      Anchored
+      (anchor [t# xa# ya#] (anchor layer# xa# ya#)))))
 
 (defn padding
   ([content pad]
@@ -81,8 +84,24 @@
 (defn- re-split [^java.util.regex.Pattern re s]
   (seq (.split re s)))
 
-(defn- layout-text [lines ^Font font ^FontRenderContext font-context]
-  (map #(TextLayout. ^String % font font-context) lines))
+(def text-layout-cache (atom {}))
+
+(defn- get-text-layout
+  [^String line ^Font font ^FontRenderContext font-context]
+  (let [key [line font font-context]]
+    (or (if-let [softref (@text-layout-cache key)]
+          (.get softref)
+          (do (swap! text-layout-cache dissoc key)
+              false))
+        (let [layout (TextLayout. line font font-context)]
+          (println "text-layout-cache miss" line)
+          (swap! text-layout-cache assoc key (SoftReference. layout))
+          layout))))
+
+(defn- layout-text
+  [lines ^Font font ^FontRenderContext font-context]
+  (map #(get-text-layout % font font-context) lines))
+  ;;(map #(TextLayout. ^String % font font-context) lines))
 
 (defn- text-width [layouts]
   (reduce (fn [w ^TextLayout tl] (max w (.getAdvance tl))) 0 layouts))
@@ -119,6 +138,34 @@
                  height (text-height layouts)]
              (Size. width height)))))))
 
+(defn- image-observer [update-fn]
+  (reify
+   ImageObserver
+   (imageUpdate [this img infoflags x y width height]
+      (update-fn)
+      (zero? (bit-and infoflags
+                      (bit-or ImageObserver/ALLBITS
+                              ImageObserver/ABORT))))))
+
+(defn image-layer
+  [image-or-uri]
+  (let [^Image image (if (isa? image-or-uri Image)
+                       image-or-uri
+                       (.createImage (Toolkit/getDefaultToolkit)
+                                     ^java.net.URL image-or-uri))]
+    (.prepareImage (Toolkit/getDefaultToolkit) image -1 -1 nil)
+    (reify
+     Layer
+     (render! [layer]
+        (.drawImage *graphics* image 0 0 (image-observer *update*)))
+     (layer-size [layer]
+        (let [observer (image-observer *update*)
+              width (.getWidth image observer)
+              height (.getHeight image observer)
+              width (if (pos? width) width 1)
+              height (if (pos? height) height 1)]
+          (Size. width height))))))
+
 (defn viewport
   "Creates scrollable viewport layer."
   ([content] (viewport content :left :top))
@@ -175,9 +222,12 @@
     (reify
      Layer
      (render! [t]
-        (with-theme* theme render! layer))
+        (with-theme theme
+          (render! layer)))
      (layer-size [t]
-        (with-theme* theme layer-size layer))
+        (with-theme theme
+          (layer-size layer)))
      Anchored
      (anchor [t xa ya]
-        (with-theme* theme anchor layer xa ya)))))
+        (with-theme theme
+          (anchor layer xa ya))))))