Mercurial > hg > indyvon
changeset 151:cb108c6fa079
Layers are now called Views.
author | Mikhail Kryshen <mikhail@kryshen.net> |
---|---|
date | Mon, 07 Apr 2014 15:23:58 +0400 |
parents | 86d0358d38c7 |
children | 9997ac717c3c |
files | src/net/kryshen/indyvon/async.clj src/net/kryshen/indyvon/component.clj src/net/kryshen/indyvon/core.clj src/net/kryshen/indyvon/demo.clj src/net/kryshen/indyvon/layers.clj src/net/kryshen/indyvon/viewport.clj src/net/kryshen/indyvon/views.clj |
diffstat | 7 files changed, 542 insertions(+), 541 deletions(-) [+] |
line diff
1.1 --- a/src/net/kryshen/indyvon/async.clj Mon Apr 07 14:24:16 2014 +0400 1.2 +++ b/src/net/kryshen/indyvon/async.clj Mon Apr 07 15:23:58 2014 +0400 1.3 @@ -1,5 +1,5 @@ 1.4 ;; 1.5 -;; Copyright 2010, 2011 Mikhail Kryshen <mikhail@kryshen.net> 1.6 +;; Copyright 2010-2014 Mikhail Kryshen <mikhail@kryshen.net> 1.7 ;; 1.8 ;; This file is part of Indyvon. 1.9 ;; 1.10 @@ -40,15 +40,15 @@ 1.11 ;; :free 1.12 ;; not in use 1.13 1.14 -(defn- create-image [async-layer ^GraphicsConfiguration device-conf] 1.15 +(defn- create-image [async-view ^GraphicsConfiguration device-conf] 1.16 ;; TODO: support different image types. 1.17 (.createCompatibleImage device-conf 1.18 - (:width async-layer) 1.19 - (:height async-layer) 1.20 + (:width async-view) 1.21 + (:height async-view) 1.22 Transparency/TRANSLUCENT)) 1.23 1.24 -(defn- create-buffer [async-layer device-conf] 1.25 - (Buffer. (Object.) (create-image async-layer device-conf) 0 :free)) 1.26 +(defn- create-buffer [async-view device-conf] 1.27 + (Buffer. (Object.) (create-image async-view device-conf) 0 :free)) 1.28 1.29 (defn- find-buffer 1.30 "Find a buffer with the one of the specified states given 1.31 @@ -110,40 +110,40 @@ 1.32 (finally 1.33 (release-buffer al# ~name))))) 1.34 1.35 -(defn- draw-offscreen [async-layer] 1.36 +(defn- draw-offscreen [async-view] 1.37 ;;(Thread/sleep 1000) 1.38 - (with-buffer async-layer :back [b] 1.39 + (with-buffer async-view :back [b] 1.40 (let [g (.createGraphics ^BufferedImage (:image b))] 1.41 ;; Clear the buffer. 1.42 (.setComposite g AlphaComposite/Clear) 1.43 - (.fillRect g 0 0 (:width async-layer) (:height async-layer)) 1.44 + (.fillRect g 0 0 (:width async-view) (:height async-view)) 1.45 (.setComposite g AlphaComposite/Src) 1.46 - (draw-scene! (:scene async-layer) 1.47 + (draw-scene! (:scene async-view) 1.48 g 1.49 - (:width async-layer) 1.50 - (:height async-layer))) 1.51 - (update async-layer))) 1.52 + (:width async-view) 1.53 + (:height async-view))) 1.54 + (update async-view))) 1.55 1.56 -(defn- draw-offscreen-async [async-layer] 1.57 - (.execute ^ThreadPoolExecutor (:executor async-layer) 1.58 - #(draw-offscreen async-layer))) 1.59 +(defn- draw-offscreen-async [async-view] 1.60 + (.execute ^ThreadPoolExecutor (:executor async-view) 1.61 + #(draw-offscreen async-view))) 1.62 1.63 -(defrecord AsyncLayer [scene width height executor buffers] 1.64 - Layer 1.65 - (render! [layer] 1.66 - (repaint-on-update layer) 1.67 - (add-context-observer scene (fn [_ _] (draw-offscreen-async layer))) 1.68 +(defrecord AsyncView [scene width height executor buffers] 1.69 + View 1.70 + (render! [view] 1.71 + (repaint-on-update view) 1.72 + (add-context-observer scene (fn [_ _] (draw-offscreen-async view))) 1.73 (when-not @buffers 1.74 ;; TODO: dynamic size, recreate buffers when size increases. 1.75 (let [device-conf (.getDeviceConfiguration *graphics*) 1.76 new-buffers (repeatedly 2 1.77 - (partial create-buffer layer device-conf))] 1.78 + (partial create-buffer view device-conf))] 1.79 (dosync 1.80 (ref-set buffers new-buffers))) 1.81 - (draw-offscreen-async layer)) 1.82 - (with-buffer layer :front [b] 1.83 + (draw-offscreen-async view)) 1.84 + (with-buffer view :front [b] 1.85 (.drawImage *graphics* ^Image (:image b) 0 0 nil))) 1.86 - (geometry [layer] 1.87 + (geometry [view] 1.88 (->Size width height))) 1.89 1.90 (defn- create-thread-factory [priority] 1.91 @@ -164,15 +164,15 @@ 1.92 (ThreadPoolExecutor$DiscardOldestPolicy.)) 1.93 (.setThreadFactory (create-thread-factory priority)))) 1.94 1.95 -(defn async-layer 1.96 - "Creates layer that draws the content asynchronously using 1.97 +(defn async-view 1.98 + "Creates a View that draws the content asynchronously using an 1.99 offscreen buffer." 1.100 ([content width height] 1.101 - (async-layer content width height nil)) 1.102 + (async-view content width height nil)) 1.103 ([content width height priority] 1.104 ;; TODO: use operational event dispatcher. 1.105 - (->AsyncLayer (make-scene content) 1.106 - width 1.107 - height 1.108 - (create-executor priority) 1.109 - (ref nil)))) 1.110 + (->AsyncView (make-scene content) 1.111 + width 1.112 + height 1.113 + (create-executor priority) 1.114 + (ref nil))))
2.1 --- a/src/net/kryshen/indyvon/component.clj Mon Apr 07 14:24:16 2014 +0400 2.2 +++ b/src/net/kryshen/indyvon/component.clj Mon Apr 07 15:23:58 2014 +0400 2.3 @@ -1,5 +1,5 @@ 2.4 ;; 2.5 -;; Copyright 2010, 2011, 2012 Mikhail Kryshen <mikhail@kryshen.net> 2.6 +;; Copyright 2010-2014 Mikhail Kryshen <mikhail@kryshen.net> 2.7 ;; 2.8 ;; This file is part of Indyvon. 2.9 ;; 2.10 @@ -38,12 +38,12 @@ 2.11 (Dimension. (width geom) (height geom)))) 2.12 2.13 (defn ^JPanel make-jpanel 2.14 - ([layer] 2.15 - (make-jpanel layer (root-event-dispatcher))) 2.16 - ([layer event-dispatcher] 2.17 + ([view] 2.18 + (make-jpanel view (root-event-dispatcher))) 2.19 + ([view event-dispatcher] 2.20 (let [panel (proxy [JPanel] []) 2.21 scene (make-scene 2.22 - layer event-dispatcher panel 2.23 + view event-dispatcher panel 2.24 (.getDesktopProperty (java.awt.Toolkit/getDefaultToolkit) 2.25 "awt.font.desktophints"))] 2.26 (update-proxy 2.27 @@ -60,9 +60,9 @@ 2.28 (listen! event-dispatcher panel) 2.29 panel))) 2.30 2.31 -(defn ^JFrame make-jframe [^String title layer] 2.32 +(defn ^JFrame make-jframe [^String title view] 2.33 (doto (JFrame. title) 2.34 - (.. (getContentPane) (add (make-jpanel layer))) 2.35 + (.. (getContentPane) (add (make-jpanel view))) 2.36 (.pack))) 2.37 2.38 (defn message [m]
3.1 --- a/src/net/kryshen/indyvon/core.clj Mon Apr 07 14:24:16 2014 +0400 3.2 +++ b/src/net/kryshen/indyvon/core.clj Mon Apr 07 15:23:58 2014 +0400 3.3 @@ -1,5 +1,5 @@ 3.4 ;; 3.5 -;; Copyright 2010, 2011, 2012, 2013 Mikhail Kryshen <mikhail@kryshen.net> 3.6 +;; Copyright 2010-2014 Mikhail Kryshen <mikhail@kryshen.net> 3.7 ;; 3.8 ;; This file is part of Indyvon. 3.9 ;; 3.10 @@ -29,7 +29,7 @@ 3.11 com.google.common.collect.MapMaker)) 3.12 3.13 ;; 3.14 -;; Layer context 3.15 +;; View context 3.16 ;; 3.17 3.18 (def ^:dynamic ^Graphics2D *graphics*) 3.19 @@ -89,15 +89,15 @@ 3.20 ;; Core protocols and types 3.21 ;; 3.22 3.23 -(defprotocol Layer 3.24 +(defprotocol View 3.25 "Basic UI element." 3.26 - (render! [layer] 3.27 - "Draws layer in the current *graphics* context.") 3.28 - (geometry [layer] 3.29 - "Returns the preferred layer Geometry.")) 3.30 + (render! [view] 3.31 + "Draws the view in the current *graphics* context.") 3.32 + (geometry [view] 3.33 + "Returns the preferred Geometry for the view.")) 3.34 3.35 (defprotocol Geometry 3.36 - "Describes geometry of a Layer. Prefer using the available 3.37 + "Describes geometry of a View. Prefer using the available 3.38 implementations (Size, FixedGeometry and NestedGeometry) over 3.39 extending this protocol directly as it is likely to be changed in 3.40 the future versions." 3.41 @@ -234,7 +234,7 @@ 3.42 3.43 ;; 3.44 ;; Observers 3.45 -;; The mechanism used by layers to request repaints 3.46 +;; The mechanism used by views to request repaints 3.47 ;; 3.48 3.49 (def ^ConcurrentMap observers 3.50 @@ -318,24 +318,24 @@ 3.51 ;; 3.52 3.53 (defn ^FontRenderContext font-context 3.54 - "Returns FontRenderContext for the current Layer context." 3.55 + "Returns FontRenderContext for the current view context." 3.56 [] 3.57 (if (bound? (var *graphics*)) 3.58 (.getFontRenderContext *graphics*) 3.59 *font-context*)) 3.60 3.61 (defn ^AffineTransform relative-transform 3.62 - "Returns AffineTransform: layer context -> AWT component." 3.63 + "Returns AffineTransform: view context -> AWT component." 3.64 [] 3.65 (let [tr (.getTransform *graphics*)] 3.66 (.preConcatenate tr *inverse-initial-transform*) 3.67 tr)) 3.68 3.69 (defn ^AffineTransform inverse-relative-transform 3.70 - "Returns AffineTransform: AWT component -> layer context." 3.71 + "Returns AffineTransform: AWT component -> view context." 3.72 [] 3.73 (let [tr (.getTransform *graphics*)] 3.74 - (.invert tr) ; absolute -> layer 3.75 + (.invert tr) ; absolute -> view 3.76 (.concatenate tr *initial-transform*) ; component -> absolute 3.77 tr)) 3.78 3.79 @@ -502,40 +502,40 @@ 3.80 (.translate g# (- x#) (- y#)))))) 3.81 3.82 (defn draw! 3.83 - "Draws layer." 3.84 - ([layer] 3.85 + "Draws the View." 3.86 + ([view] 3.87 (let [graphics (create-graphics)] 3.88 (try 3.89 (binding [*graphics* graphics] 3.90 - (render! layer)) 3.91 + (render! view)) 3.92 (finally 3.93 (.dispose graphics))))) 3.94 - ([layer x y] 3.95 - (draw! layer x y true)) 3.96 - ([layer x y clip?] 3.97 - (let [geom (geometry layer)] 3.98 - (draw! layer x y (width geom) (height geom) clip?))) 3.99 - ([layer x y width height] 3.100 - (draw! layer x y width height true)) 3.101 - ([layer x y width height clip?] 3.102 + ([view x y] 3.103 + (draw! view x y true)) 3.104 + ([view x y clip?] 3.105 + (let [geom (geometry view)] 3.106 + (draw! view x y (width geom) (height geom) clip?))) 3.107 + ([view x y width height] 3.108 + (draw! view x y width height true)) 3.109 + ([view x y width height clip?] 3.110 (if clip? 3.111 - (with-bounds* x y width height render! layer) 3.112 - (with-bounds-noclip* x y width height render! layer)))) 3.113 + (with-bounds* x y width height render! view) 3.114 + (with-bounds-noclip* x y width height render! view)))) 3.115 3.116 (defn draw-aligned! 3.117 - "Draws layer. Location is relative to the layer's anchor point for 3.118 - the specified alignment." 3.119 - ([layer h-align v-align x y] 3.120 - (let [geom (geometry layer) 3.121 + "Draws the View. Location is relative to the view's anchor point 3.122 + for the specified alignment." 3.123 + ([view h-align v-align x y] 3.124 + (let [geom (geometry view) 3.125 w (width geom) 3.126 h (height geom)] 3.127 - (draw! layer 3.128 + (draw! view 3.129 (- x (anchor-x geom h-align w)) 3.130 (- y (anchor-y geom v-align h)) 3.131 w h))) 3.132 - ([layer h-align v-align x y w h] 3.133 - (let [geom (geometry layer)] 3.134 - (draw! layer 3.135 + ([view h-align v-align x y w h] 3.136 + (let [geom (geometry view)] 3.137 + (draw! view 3.138 (- x (anchor-x geom h-align w)) 3.139 (- y (anchor-y geom v-align h)) 3.140 w h)))) 3.141 @@ -792,7 +792,7 @@ 3.142 ;; Scene 3.143 ;; 3.144 3.145 -(defrecord Scene [layer 3.146 +(defrecord Scene [view 3.147 event-dispatcher 3.148 component 3.149 rendering-hints 3.150 @@ -807,15 +807,15 @@ 3.151 RenderingHints/VALUE_FRACTIONALMETRICS_DEFAULT}) 3.152 3.153 (defn make-scene 3.154 - ([layer] 3.155 - (make-scene layer dummy-event-dispatcher nil)) 3.156 - ([layer event-dispatcher] 3.157 - (make-scene layer event-dispatcher nil)) 3.158 - ([layer event-dispatcher ^Component component] 3.159 - (make-scene layer event-dispatcher component nil)) 3.160 - ([layer event-dispatcher ^Component component hints] 3.161 + ([view] 3.162 + (make-scene view dummy-event-dispatcher nil)) 3.163 + ([view event-dispatcher] 3.164 + (make-scene view event-dispatcher nil)) 3.165 + ([view event-dispatcher ^Component component] 3.166 + (make-scene view event-dispatcher component nil)) 3.167 + ([view event-dispatcher ^Component component hints] 3.168 (let [hints (merge default-rendering-hints hints)] 3.169 - (->Scene layer 3.170 + (->Scene view 3.171 event-dispatcher 3.172 component 3.173 hints 3.174 @@ -853,7 +853,7 @@ 3.175 ;; appear in both groups until tmp-watcher is removed. 3.176 (replace-observers-watcher scene tmp-watcher) 3.177 (try 3.178 - (render! (:layer scene)) 3.179 + (render! (:view scene)) 3.180 (finally 3.181 (remove-observers tmp-watcher) 3.182 (commit (:event-dispatcher scene))))))) 3.183 @@ -874,7 +874,7 @@ 3.184 (defn scene-geometry [scene] 3.185 (binding [*scene* scene 3.186 *font-context* (scene-font-context scene)] 3.187 - (geometry (:layer scene)))) 3.188 + (geometry (:view scene)))) 3.189 3.190 (defn set-cursor! [^Cursor cursor] 3.191 (when-let [^Component component (:component *scene*)]
4.1 --- a/src/net/kryshen/indyvon/demo.clj Mon Apr 07 14:24:16 2014 +0400 4.2 +++ b/src/net/kryshen/indyvon/demo.clj Mon Apr 07 15:23:58 2014 +0400 4.3 @@ -21,14 +21,14 @@ 4.4 "Indyvon demo and experiments." 4.5 (:gen-class) 4.6 (:use 4.7 - (net.kryshen.indyvon core layers viewport component)) 4.8 + (net.kryshen.indyvon core views viewport component)) 4.9 (:import 4.10 (java.awt Color) 4.11 (javax.swing JFrame))) 4.12 4.13 (defn draw-button! 4.14 - "Draws button immediately (but uses callback for button action 4.15 - unlike IMGUI)." 4.16 + "Draws a button immediately (but uses callback for the action unlike 4.17 + IMGUI)." 4.18 [id content callback & args] 4.19 (with-handlers id 4.20 (let [shadow-offset 2 4.21 @@ -65,8 +65,8 @@ 4.22 (Color. (aget rgb 0) (aget rgb 1) (aget rgb 2) (aget rgb 3))))) 4.23 4.24 (defn animate 4.25 - "Changes atom value according to specified range, speed, and current 4.26 - frame interval. Invokes repaint if change happens." 4.27 + "Changes the value of atom according to the specified range, speed, 4.28 + and current frame interval. Invokes repaint if change happens." 4.29 [atom from to speed] 4.30 (let [prev @atom 4.31 state (cond 4.32 @@ -83,7 +83,7 @@ 4.33 val)))) 4.34 4.35 (defn animated-button 4.36 - "Create animated button layer." 4.37 + "Creates an animated button." 4.38 [content callback & args] 4.39 (let [padding 4 4.40 border-width 1 4.41 @@ -91,9 +91,9 @@ 4.42 face (border content padding border-width) 4.43 highlight (atom 0) 4.44 animation-speed (atom 0)] 4.45 - (interval-layer 4.46 + (interval-view 4.47 (reify 4.48 - Layer 4.49 + View 4.50 (render! [button] 4.51 (with-handlers button 4.52 (let [hovered (hovered? button) 4.53 @@ -132,12 +132,12 @@ 4.54 (def button2 (animated-button (label "Animated button 2") 4.55 println "Animated button 2 clicked")) 4.56 4.57 -(def test-layer1 4.58 +(def test-view1 4.59 (reify 4.60 - Layer 4.61 - (render! [layer] 4.62 - (with-handlers layer 4.63 - (with-color (if (hovered? layer) Color/ORANGE Color/RED) 4.64 + View 4.65 + (render! [view] 4.66 + (with-handlers view 4.67 + (with-color (if (hovered? view) Color/ORANGE Color/RED) 4.68 (.fillRect *graphics* 0 0 *width* *height*)) 4.69 (:mouse-entered e 4.70 (repaint) 4.71 @@ -147,32 +147,32 @@ 4.72 (println e)) 4.73 (:mouse-moved e 4.74 (println e)))) 4.75 - (geometry [layer] 4.76 + (geometry [view] 4.77 (->Size 30 20)))) 4.78 4.79 -(def test-layer1b (border test-layer1 2 3)) 4.80 +(def test-view1b (border test-view1 2 3)) 4.81 4.82 -(def test-layer2 4.83 +(def test-view2 4.84 (reify 4.85 - Layer 4.86 - (render! [layer] 4.87 + View 4.88 + (render! [view] 4.89 (doto *graphics* 4.90 (.setColor Color/YELLOW) 4.91 (.fillRect 0 0 *width* *height*)) 4.92 (with-rotate 0.5 0 0 4.93 - (draw! test-layer1b 30 25)) 4.94 - (draw! test-layer1 55 5)) 4.95 - (geometry [layer] 4.96 + (draw! test-view1b 30 25)) 4.97 + (draw! test-view1 55 5)) 4.98 + (geometry [view] 4.99 (->Size 70 65)))) 4.100 4.101 -(def test-layer2m (miniature test-layer2 30 30)) 4.102 +(def test-view2m (miniature test-view2 30 30)) 4.103 4.104 -(def test-layer3 (border (label "Sample\ntext" :right :bottom))) 4.105 +(def test-view3 (border (label "Sample\ntext" :right :bottom))) 4.106 4.107 (def root 4.108 (reify 4.109 - Layer 4.110 - (render! [layer] 4.111 + View 4.112 + (render! [view] 4.113 ;;(repaint) 4.114 (doto *graphics* 4.115 (.drawLine 0 0 *width* *height*) 4.116 @@ -180,9 +180,9 @@ 4.117 ;; Random color to see when repaint happens. 4.118 (.setColor (rand-nth [Color/BLACK Color/BLUE Color/RED])) 4.119 (.fillOval 5 5 20 20)) 4.120 - (draw! test-layer2 30 20) 4.121 - (draw! test-layer2m 120 50) 4.122 - (draw! test-layer3 100 100 80 50) 4.123 + (draw! test-view2 30 20) 4.124 + (draw! test-view2m 120 50) 4.125 + (draw! test-view3 100 100 80 50) 4.126 (draw! button1 50 160) 4.127 (with-rotate (/ Math/PI 6) 250 200 4.128 (draw! button1 210 140)) 4.129 @@ -191,7 +191,7 @@ 4.130 (draw-button! :button 4.131 (label "Immediate button" :center :center) 4.132 #(println "Button clicked!")))) 4.133 - (geometry [layer] 4.134 + (geometry [view] 4.135 (->Size 400 300)))) 4.136 4.137 ;; Main viewport 4.138 @@ -202,8 +202,8 @@ 4.139 4.140 ;; Main scene 4.141 (def scene 4.142 - (fps-layer 4.143 - (decorate-layer vp [_] 4.144 + (fps-view 4.145 + (decorate-view vp [_] 4.146 (draw! vp) 4.147 (draw-aligned! 4.148 (label (str "Drag mouse to pan," \newline 4.149 @@ -211,8 +211,8 @@ 4.150 :left :bottom 5 (- *height* 5)) 4.151 (draw! vp-miniature (- *width* 105) 5)))) 4.152 4.153 -(defn show-frame [layer] 4.154 - (doto (make-jframe "Test" layer) 4.155 +(defn show-frame [view] 4.156 + (doto (make-jframe "Test" view) 4.157 (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE) 4.158 (.setVisible true))) 4.159
5.1 --- a/src/net/kryshen/indyvon/layers.clj Mon Apr 07 14:24:16 2014 +0400 5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 5.3 @@ -1,408 +0,0 @@ 5.4 -;; 5.5 -;; Copyright 2010, 2011, 2012, 2013 Mikhail Kryshen <mikhail@kryshen.net> 5.6 -;; 5.7 -;; This file is part of Indyvon. 5.8 -;; 5.9 -;; Indyvon is free software: you can redistribute it and/or modify it 5.10 -;; under the terms of the GNU Lesser General Public License version 3 5.11 -;; only, as published by the Free Software Foundation. 5.12 -;; 5.13 -;; Indyvon is distributed in the hope that it will be useful, but 5.14 -;; WITHOUT ANY WARRANTY; without even the implied warranty of 5.15 -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 5.16 -;; Lesser General Public License for more details. 5.17 -;; 5.18 -;; You should have received a copy of the GNU Lesser General Public 5.19 -;; License along with Indyvon. If not, see 5.20 -;; <http://www.gnu.org/licenses/>. 5.21 -;; 5.22 - 5.23 -(ns net.kryshen.indyvon.layers 5.24 - "Implementations of Layer protocol." 5.25 - (:use 5.26 - (net.kryshen.indyvon core async)) 5.27 - (:import 5.28 - (java.awt Font Image Toolkit) 5.29 - java.awt.image.ImageObserver 5.30 - (java.awt.geom Area AffineTransform Rectangle2D$Double Point2D 5.31 - Point2D$Double) 5.32 - (java.awt.font FontRenderContext TextLayout) 5.33 - java.util.concurrent.TimeUnit 5.34 - (com.google.common.cache Cache CacheBuilder CacheLoader))) 5.35 - 5.36 -(defmacro decorate-layer 5.37 - "Decorate Layer replacing render! implementation." 5.38 - [layer & render-tail] 5.39 - `(let [layer# ~layer] 5.40 - (reify 5.41 - Layer 5.42 - (render! ~@render-tail) 5.43 - (geometry [t#] (geometry layer#))))) 5.44 - 5.45 -(defrecord Empty [] 5.46 - Layer 5.47 - (render! [_]) 5.48 - (geometry [_] 5.49 - (->Size 0 0))) 5.50 - 5.51 -(def empty-layer (->Empty)) 5.52 - 5.53 -;; TODO: change argument order for decorators, content should be the 5.54 -;; last. 5.55 - 5.56 -(defn padding 5.57 - "Decorates layer adding padding." 5.58 - ([content pad] 5.59 - (padding content pad pad pad pad)) 5.60 - ([content top left bottom right] 5.61 - (if (== 0 top left bottom right) 5.62 - content 5.63 - (reify 5.64 - Layer 5.65 - (render! [l] 5.66 - (draw! content 5.67 - left top 5.68 - (- *width* left right) 5.69 - (- *height* top bottom) 5.70 - false)) 5.71 - (geometry [l] 5.72 - (->NestedGeometry (geometry content) top left bottom right)))))) 5.73 - 5.74 -(defn border 5.75 - "Decorate layer with a border." 5.76 - ([content] 5.77 - (border content 1)) 5.78 - ([content thikness] 5.79 - (border content thikness 0)) 5.80 - ([content thikness gap] 5.81 - (let [layer (padding content (+ thikness gap)) 5.82 - t (double thikness)] 5.83 - (decorate-layer layer [_] 5.84 - (render! layer) 5.85 - (with-color :border-color 5.86 - (let [w (double *width*) 5.87 - h (double *height*) 5.88 - outer (Area. (Rectangle2D$Double. 0.0 0.0 w h)) 5.89 - inner (Area. (Rectangle2D$Double. t t (- w t t) (- h t t)))] 5.90 - (.subtract outer inner) 5.91 - (.fill *graphics* outer))))))) 5.92 - 5.93 -;; TODO: opacity and blur. 5.94 -(defn shadow 5.95 - "Add shadow to content layer." 5.96 - ([content] 5.97 - (shadow content 1 1)) 5.98 - ([content x-offset y-offset] 5.99 - (let [x (if (neg? x-offset) (- x-offset) 0) 5.100 - y (if (neg? y-offset) (- y-offset) 0) 5.101 - abs-x (if (neg? x-offset) (- x-offset) x-offset) 5.102 - abs-y (if (neg? y-offset) (- y-offset) y-offset) 5.103 - shadow-x (+ x-offset x) 5.104 - shadow-y (+ y-offset y)] 5.105 - (reify 5.106 - Layer 5.107 - (render! [_] 5.108 - (let [w (- *width* abs-x) 5.109 - h (- *height* abs-y)] 5.110 - (with-color :shadow-color 5.111 - (.fillRect *graphics* shadow-x shadow-y w h)) 5.112 - (draw! content x y w h))) 5.113 - (geometry [_] 5.114 - (->NestedGeometry (geometry content) 5.115 - y x shadow-y shadow-x)))))) 5.116 - 5.117 -(defn panel 5.118 - "Opaque layer using theme's alt-back-color or a custom background color." 5.119 - ([content] 5.120 - (panel :alt-back-color content)) 5.121 - ([back-color content] 5.122 - (decorate-layer content [_] 5.123 - (with-color back-color 5.124 - (.fill *graphics* (Rectangle2D$Double. 0.0 0.0 *width* *height*))) 5.125 - (render! content)))) 5.126 - 5.127 -(defn hbox 5.128 - "Creates layer that draws the specified content layers placing them 5.129 - horizontally." 5.130 - [& contents] 5.131 - (reify 5.132 - Layer 5.133 - (render! [_] 5.134 - (let [widths (map #(width (geometry %)) contents) 5.135 - xs (cons 0 (reductions + widths)) 5.136 - widths-sum (last xs) 5.137 - scale (/ *width* widths-sum)] 5.138 - (doseq [[c w x] (map vector contents widths xs)] 5.139 - (draw! c x 0 w *height*)))) 5.140 - (geometry [_] 5.141 - (reduce #(->Size (+ (width %1) (width %2)) 5.142 - (max (height %1) (height %2))) 5.143 - (->Size 0 0) 5.144 - (map geometry contents))))) 5.145 - 5.146 -(defn vbox 5.147 - "Creates layer that draws the specified content layers placing them 5.148 - vertically." 5.149 - [& contents] 5.150 - (reify 5.151 - Layer 5.152 - (render! [_] 5.153 - (let [heights (map #(height (geometry %)) contents) 5.154 - ys (cons 0 (reductions + heights)) 5.155 - heights-sum (last ys) 5.156 - scale (/ *height* heights-sum)] 5.157 - (doseq [[c h y] (map vector contents heights ys)] 5.158 - (draw! c 0 y *width* h)))) 5.159 - (geometry [_] 5.160 - (reduce #(->Size (max (width %1) (width %2)) 5.161 - (+ (height %1) (height %2))) 5.162 - (->Size 0 0) 5.163 - (map geometry contents))))) 5.164 - 5.165 -(defn- re-split [^java.util.regex.Pattern re s] 5.166 - (seq (.split re s))) 5.167 - 5.168 -(def ^:private ^Cache text-layout-cache 5.169 - (-> (CacheBuilder/newBuilder) 5.170 - (.softValues) 5.171 - (.expireAfterAccess (long 1) TimeUnit/SECONDS) 5.172 - (.build))) 5.173 - 5.174 -(defn- get-text-layout 5.175 - [^String line ^Font font ^FontRenderContext font-context] 5.176 - (.get text-layout-cache [line font font-context] 5.177 - #(TextLayout. line font font-context))) 5.178 - 5.179 -(defn- layout-text 5.180 - [lines font font-context] 5.181 - (map #(get-text-layout % font font-context) lines)) 5.182 - 5.183 -(defn- text-width [layouts] 5.184 - (reduce (fn [w ^TextLayout tl] (max w (.getAdvance tl))) 0 layouts)) 5.185 - 5.186 -(defn- text-height [layouts] 5.187 - (reduce (fn [w ^TextLayout tl] 5.188 - (+ w (.getAscent tl) 5.189 - (.getDescent tl) 5.190 - (.getLeading tl))) 5.191 - 0 layouts)) 5.192 - 5.193 -(defn label 5.194 - "Creates a layer to display multiline text." 5.195 - ([text] 5.196 - (label text :left :top)) 5.197 - ([text h-align v-align] 5.198 - (let [lines (re-split #"\r\n|\n|\r|\u0085|\u2028|\u2029" (str text))] 5.199 - (reify Layer 5.200 - (render! [layer] 5.201 - (let [w *width* 5.202 - h *height* 5.203 - font (.getFont *graphics*) 5.204 - layouts (layout-text lines font (font-context)) 5.205 - y (align-y v-align (text-height layouts) h)] 5.206 - (loop [layouts layouts, y y] 5.207 - (when-first [^TextLayout layout layouts] 5.208 - (let [ascent (.getAscent layout) 5.209 - lh (+ ascent (.getDescent layout) (.getLeading layout)) 5.210 - x (align-x h-align (.getAdvance layout) w)] 5.211 - (.draw layout *graphics* x (+ y ascent)) 5.212 - (recur (next layouts) (+ y lh))))))) 5.213 - (geometry [layer] 5.214 - (let [layouts (layout-text lines (:font *theme*) (font-context)) 5.215 - w (text-width layouts) 5.216 - h (text-height layouts)] 5.217 - (->Size w h))))))) 5.218 - 5.219 -(defn- ^ImageObserver image-observer [layer] 5.220 - (reify 5.221 - ImageObserver 5.222 - (imageUpdate [this img infoflags x y width height] 5.223 - (update layer) 5.224 - (zero? (bit-and infoflags 5.225 - (bit-or ImageObserver/ALLBITS 5.226 - ImageObserver/ABORT)))))) 5.227 - 5.228 -(defn image-layer 5.229 - [image-or-uri] 5.230 - (let [^Image image (if (instance? Image image-or-uri) 5.231 - image-or-uri 5.232 - (.getImage (Toolkit/getDefaultToolkit) 5.233 - ^java.net.URL image-or-uri))] 5.234 - (.prepareImage (Toolkit/getDefaultToolkit) image -1 -1 nil) 5.235 - (reify 5.236 - Layer 5.237 - (render! [layer] 5.238 - (repaint-on-update layer) 5.239 - (.drawImage *graphics* image 0 0 (image-observer layer))) 5.240 - (geometry [layer] 5.241 - (let [observer (image-observer layer) 5.242 - width (.getWidth image observer) 5.243 - height (.getHeight image observer) 5.244 - width (if (pos? width) width 1) 5.245 - height (if (pos? height) height 1)] 5.246 - (->Size width height)))))) 5.247 - 5.248 -(def ^:dynamic *miniature-thread-priority* 2) 5.249 - 5.250 -(defn ref-layer 5.251 - [layer-ref] 5.252 - (let [l (reify 5.253 - Layer 5.254 - (render! [l] 5.255 - (repaint-on-update l) 5.256 - (if-let [layer @layer-ref] 5.257 - (render! layer))) 5.258 - (geometry [_] 5.259 - (if-let [layer @layer-ref] 5.260 - (geometry layer) 5.261 - (->Size 1 1))))] 5.262 - (add-watch layer-ref l (fn [_ _ _ _] (update l))) 5.263 - l)) 5.264 - 5.265 -;; 5.266 -;; Layer context decorators. 5.267 -;; 5.268 - 5.269 -(defmacro handler [layer & handlers] 5.270 - "Decorate layer to handle events." 5.271 - `(let [layer# ~layer] 5.272 - (decorate-layer layer# [t#] 5.273 - (with-handlers t# 5.274 - (render! layer#) 5.275 - ~@handlers)))) 5.276 - 5.277 -(defn themed [layer & map-or-keyvals] 5.278 - (let [theme (if (== (count map-or-keyvals) 1) 5.279 - (first map-or-keyvals) 5.280 - (apply array-map map-or-keyvals))] 5.281 - (reify 5.282 - Layer 5.283 - (render! [_] 5.284 - (with-theme theme 5.285 - (render! layer))) 5.286 - (geometry [_] 5.287 - (with-theme theme 5.288 - (geometry layer)))))) 5.289 - 5.290 -(defn hinted [layer & map-or-keyvals] 5.291 - (let [hints (if (== (count map-or-keyvals) 1) 5.292 - (first map-or-keyvals) 5.293 - (apply array-map map-or-keyvals))] 5.294 - (decorate-layer layer [_] 5.295 - (with-hints* hints render! layer)))) 5.296 - 5.297 -;; 5.298 -;; Measuring time 5.299 -;; 5.300 - 5.301 -(def ^:dynamic *interval*) 5.302 - 5.303 -(defn interval-layer 5.304 - "Creates layer that measures time between repaints ant draws it's 5.305 - content with the *interval* var bound to the measured time." 5.306 - [content] 5.307 - (let [last-time (atom nil)] 5.308 - (decorate-layer content [_] 5.309 - (compare-and-set! last-time nil *time*) 5.310 - (let [lt @last-time] 5.311 - (binding [*interval* (if (compare-and-set! last-time lt *time*) 5.312 - (- *time* lt) 5.313 - 0)] ; already measured on parallel thread 5.314 - (render! content)))))) 5.315 - 5.316 -(defn- fps-label [text] 5.317 - (padding (label text :right :bottom) 5)) 5.318 - 5.319 -(defn fps-layer 5.320 - "Creates layer that draws content and displays 5.321 - the frames per seconds rate." 5.322 - [content] 5.323 - (let [update-interval 2E8 ; 0.2 s in nanoseconds 5.324 - frames (ref 0) 5.325 - prev-time (ref nil) 5.326 - display (ref (fps-label "fps n/a"))] 5.327 - (decorate-layer content [_] 5.328 - (draw! content) 5.329 - (draw! 5.330 - (dosync 5.331 - (alter frames inc) 5.332 - (if @prev-time 5.333 - (let [elapsed (- *time* @prev-time)] 5.334 - (when (> elapsed update-interval) 5.335 - (let [fps (/ @frames (/ elapsed 1E9))] 5.336 - (ref-set display (fps-label (format "%.1f" fps))) 5.337 - (ref-set frames 0) 5.338 - (ref-set prev-time *time*)))) 5.339 - (ref-set prev-time *time*)) 5.340 - @display))))) 5.341 - 5.342 -;; 5.343 -;; Overlayer. 5.344 -;; 5.345 - 5.346 -(def ^:private ^:dynamic *above*) 5.347 - 5.348 -(defn- overlay* [f & args] 5.349 - (var-set #'*above* (conj *above* (apply partial f args)))) 5.350 - 5.351 -(defn- ^Point2D to-graphics-coords 5.352 - [^AffineTransform transform x y] 5.353 - (let [p (Point2D$Double. x y)] 5.354 - (.transform transform p p) 5.355 - (.transform (.createInverse (.getTransform *graphics*)) p p) 5.356 - p)) 5.357 - 5.358 -(defn- draw-relative! 5.359 - ([layer transform x y] 5.360 - (let [p (to-graphics-coords transform x y)] 5.361 - (draw! layer (.getX p) (.getY p)))) 5.362 - ([layer transform x y w h] 5.363 - (let [p (to-graphics-coords transform x y)] 5.364 - (draw! layer (.getX p) (.getY p) w h)))) 5.365 - 5.366 -(defn- draw-relative-aligned! 5.367 - [layer transform h-align v-align x y] 5.368 - (let [geom (geometry layer) 5.369 - w (width geom) 5.370 - h (height geom) 5.371 - p (to-graphics-coords transform x y) 5.372 - x (- (.getX p) (anchor-x geom h-align w)) 5.373 - y (- (.getY p) (anchor-y geom v-align h))] 5.374 - (draw! layer x y w h))) 5.375 - 5.376 -(defn overlay! 5.377 - "Draws layer in the overlayer context above the other layers." 5.378 - ([layer] 5.379 - (overlay* draw-relative! layer (.getTransform *graphics*) 0 0)) 5.380 - ([layer x y] 5.381 - (overlay* draw-relative! layer (.getTransform *graphics*) x y)) 5.382 - ([layer x y w h] 5.383 - (overlay* draw-relative! layer (.getTransform *graphics*) x y w h))) 5.384 - 5.385 -(defn overlay-aligned! [layer h-align v-align x y] 5.386 - (overlay* draw-relative-aligned! 5.387 - layer (.getTransform *graphics*) 5.388 - h-align v-align x y)) 5.389 - 5.390 -(defn with-overlays* [rec? f & args] 5.391 - (binding [*above* []] 5.392 - (apply f args) 5.393 - (if rec? 5.394 - (loop [above *above*] 5.395 - (when (seq above) 5.396 - (var-set #'*above* []) 5.397 - (doseq [f above] 5.398 - (f)) 5.399 - (recur *above*))) 5.400 - (doseq [of *above*] 5.401 - (of))))) 5.402 - 5.403 -(defmacro with-overlays [rec? & body] 5.404 - `(with-overlays* ~rec? (fn [] ~@body))) 5.405 - 5.406 -(defn overlayer 5.407 - ([content] 5.408 - (overlayer content true)) 5.409 - ([content rec?] 5.410 - (decorate-layer content [_] 5.411 - (with-overlays* rec? render! content))))
6.1 --- a/src/net/kryshen/indyvon/viewport.clj Mon Apr 07 14:24:16 2014 +0400 6.2 +++ b/src/net/kryshen/indyvon/viewport.clj Mon Apr 07 15:23:58 2014 +0400 6.3 @@ -1,5 +1,5 @@ 6.4 ;; 6.5 -;; Copyright 2010, 2011, 2012, 2013 Mikhail Kryshen <mikhail@kryshen.net> 6.6 +;; Copyright 2010-2014 Mikhail Kryshen <mikhail@kryshen.net> 6.7 ;; 6.8 ;; This file is part of Indyvon. 6.9 ;; 6.10 @@ -20,7 +20,7 @@ 6.11 (ns net.kryshen.indyvon.viewport 6.12 "Scrollable viewport and miniature." 6.13 (:use 6.14 - (net.kryshen.indyvon core async layers)) 6.15 + (net.kryshen.indyvon core async views)) 6.16 (:import 6.17 java.awt.Cursor 6.18 java.awt.geom.AffineTransform)) 6.19 @@ -80,15 +80,15 @@ 6.20 :transform transform))) 6.21 6.22 (defrecord Viewport [content h-align v-align state] 6.23 - Layer 6.24 - (render! [layer] 6.25 - (repaint-on-update layer) 6.26 - (with-handlers layer 6.27 + View 6.28 + (render! [view] 6.29 + (repaint-on-update view) 6.30 + (with-handlers view 6.31 (let [geom (geometry content) 6.32 new-state (swap! state update-viewport geom h-align v-align) 6.33 transform (:transform new-state)] 6.34 ;; TODO: notify observers when size changes. 6.35 - (binding [*viewport* layer 6.36 + (binding [*viewport* view 6.37 *viewport-transform* transform] 6.38 (with-transform transform 6.39 (draw! content 0 0 (width geom) (height geom) false)))) 6.40 @@ -109,10 +109,10 @@ 6.41 (- (:y-on-screen e) (:fix-y s))) 6.42 :fix-x (:x-on-screen e) 6.43 :fix-y (:y-on-screen e)))) 6.44 - (update layer)) 6.45 + (update view)) 6.46 (:mouse-wheel e 6.47 (scale-viewport! 6.48 - layer 6.49 + view 6.50 (Math/pow *viewport-scaling-step* (:wheel-rotation e)) 6.51 true (:x e) (:y e))))) 6.52 (geometry [_] 6.53 @@ -126,7 +126,7 @@ 6.54 0 0)) 6.55 6.56 (defn viewport 6.57 - "Creates scrollable viewport layer." 6.58 + "Creates scrollable viewport view." 6.59 ([content] 6.60 (viewport content :left :top)) 6.61 ([content h-align v-align] 6.62 @@ -175,12 +175,12 @@ 6.63 (/ max-height height))) 6.64 6.65 (defn miniature 6.66 - "Creates layer that asynchronously renders view of the content 6.67 - scaled to the specified size." 6.68 + "Creates a view that asynchronously renders the content view scaled to 6.69 + the specified size." 6.70 [content mw mh] 6.71 - (async-layer 6.72 + (async-view 6.73 (reify 6.74 - Layer 6.75 + View 6.76 (render! [this] 6.77 (let [geom (geometry content) 6.78 cw (width geom) 6.79 @@ -199,7 +199,7 @@ 6.80 "Creates miniature view of the viewport's contents." 6.81 [viewport m-width m-height] 6.82 (let [miniature (miniature (:content viewport) m-width m-height)] 6.83 - (decorate-layer miniature [l] 6.84 + (decorate-view miniature [l] 6.85 (repaint-on-update viewport) 6.86 (let [geom (geometry (:content viewport)) 6.87 s (scaling (width geom) (height geom) m-width m-height)
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/net/kryshen/indyvon/views.clj Mon Apr 07 15:23:58 2014 +0400 7.3 @@ -0,0 +1,409 @@ 7.4 +;; 7.5 +;; Copyright 2010-2014 Mikhail Kryshen <mikhail@kryshen.net> 7.6 +;; 7.7 +;; This file is part of Indyvon. 7.8 +;; 7.9 +;; Indyvon is free software: you can redistribute it and/or modify it 7.10 +;; under the terms of the GNU Lesser General Public License version 3 7.11 +;; only, as published by the Free Software Foundation. 7.12 +;; 7.13 +;; Indyvon is distributed in the hope that it will be useful, but 7.14 +;; WITHOUT ANY WARRANTY; without even the implied warranty of 7.15 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 7.16 +;; Lesser General Public License for more details. 7.17 +;; 7.18 +;; You should have received a copy of the GNU Lesser General Public 7.19 +;; License along with Indyvon. If not, see 7.20 +;; <http://www.gnu.org/licenses/>. 7.21 +;; 7.22 + 7.23 +(ns net.kryshen.indyvon.views 7.24 + "Implementations of the View protocol." 7.25 + (:use 7.26 + (net.kryshen.indyvon core async)) 7.27 + (:import 7.28 + (java.awt Font Image Toolkit) 7.29 + java.awt.image.ImageObserver 7.30 + (java.awt.geom Area AffineTransform Rectangle2D$Double Point2D 7.31 + Point2D$Double) 7.32 + (java.awt.font FontRenderContext TextLayout) 7.33 + java.util.concurrent.TimeUnit 7.34 + (com.google.common.cache Cache CacheBuilder CacheLoader))) 7.35 + 7.36 +(defmacro decorate-view 7.37 + "Decorate the view replacing render! implementation." 7.38 + [view & render-tail] 7.39 + `(let [view# ~view] 7.40 + (reify 7.41 + View 7.42 + (render! ~@render-tail) 7.43 + (geometry [t#] (geometry view#))))) 7.44 + 7.45 +(defrecord Empty [] 7.46 + View 7.47 + (render! [_]) 7.48 + (geometry [_] 7.49 + (->Size 0 0))) 7.50 + 7.51 +(def empty-view (->Empty)) 7.52 + 7.53 +;; TODO: change argument order for decorators, content should be the 7.54 +;; last. 7.55 + 7.56 +(defn padding 7.57 + "Adds padding to the content view." 7.58 + ([content pad] 7.59 + (padding content pad pad pad pad)) 7.60 + ([content top left bottom right] 7.61 + (if (== 0 top left bottom right) 7.62 + content 7.63 + (reify 7.64 + View 7.65 + (render! [l] 7.66 + (draw! content 7.67 + left top 7.68 + (- *width* left right) 7.69 + (- *height* top bottom) 7.70 + false)) 7.71 + (geometry [l] 7.72 + (->NestedGeometry (geometry content) top left bottom right)))))) 7.73 + 7.74 +(defn border 7.75 + "Adds a border to the content view." 7.76 + ([content] 7.77 + (border content 1)) 7.78 + ([content thikness] 7.79 + (border content thikness 0)) 7.80 + ([content thikness gap] 7.81 + (let [view (padding content (+ thikness gap)) 7.82 + t (double thikness)] 7.83 + (decorate-view view [_] 7.84 + (render! view) 7.85 + (with-color :border-color 7.86 + (let [w (double *width*) 7.87 + h (double *height*) 7.88 + outer (Area. (Rectangle2D$Double. 0.0 0.0 w h)) 7.89 + inner (Area. (Rectangle2D$Double. t t (- w t t) (- h t t)))] 7.90 + (.subtract outer inner) 7.91 + (.fill *graphics* outer))))))) 7.92 + 7.93 +;; TODO: opacity and blur. 7.94 +(defn shadow 7.95 + "Adds a shadow to the content view." 7.96 + ([content] 7.97 + (shadow content 1 1)) 7.98 + ([content x-offset y-offset] 7.99 + (let [x (if (neg? x-offset) (- x-offset) 0) 7.100 + y (if (neg? y-offset) (- y-offset) 0) 7.101 + abs-x (if (neg? x-offset) (- x-offset) x-offset) 7.102 + abs-y (if (neg? y-offset) (- y-offset) y-offset) 7.103 + shadow-x (+ x-offset x) 7.104 + shadow-y (+ y-offset y)] 7.105 + (reify 7.106 + View 7.107 + (render! [_] 7.108 + (let [w (- *width* abs-x) 7.109 + h (- *height* abs-y)] 7.110 + (with-color :shadow-color 7.111 + (.fillRect *graphics* shadow-x shadow-y w h)) 7.112 + (draw! content x y w h))) 7.113 + (geometry [_] 7.114 + (->NestedGeometry (geometry content) 7.115 + y x shadow-y shadow-x)))))) 7.116 + 7.117 +(defn panel 7.118 + "An opaque view using theme's alt-back-color or a custom background 7.119 + color." 7.120 + ([content] 7.121 + (panel :alt-back-color content)) 7.122 + ([back-color content] 7.123 + (decorate-view content [_] 7.124 + (with-color back-color 7.125 + (.fill *graphics* (Rectangle2D$Double. 0.0 0.0 *width* *height*))) 7.126 + (render! content)))) 7.127 + 7.128 +(defn hbox 7.129 + "Creates a view that draws the specified content views placing them 7.130 + horizontally." 7.131 + [& contents] 7.132 + (reify 7.133 + View 7.134 + (render! [_] 7.135 + (let [widths (map #(width (geometry %)) contents) 7.136 + xs (cons 0 (reductions + widths)) 7.137 + widths-sum (last xs) 7.138 + scale (/ *width* widths-sum)] 7.139 + (doseq [[c w x] (map vector contents widths xs)] 7.140 + (draw! c x 0 w *height*)))) 7.141 + (geometry [_] 7.142 + (reduce #(->Size (+ (width %1) (width %2)) 7.143 + (max (height %1) (height %2))) 7.144 + (->Size 0 0) 7.145 + (map geometry contents))))) 7.146 + 7.147 +(defn vbox 7.148 + "Creates a view that draws the specified content views placing them 7.149 + vertically." 7.150 + [& contents] 7.151 + (reify 7.152 + View 7.153 + (render! [_] 7.154 + (let [heights (map #(height (geometry %)) contents) 7.155 + ys (cons 0 (reductions + heights)) 7.156 + heights-sum (last ys) 7.157 + scale (/ *height* heights-sum)] 7.158 + (doseq [[c h y] (map vector contents heights ys)] 7.159 + (draw! c 0 y *width* h)))) 7.160 + (geometry [_] 7.161 + (reduce #(->Size (max (width %1) (width %2)) 7.162 + (+ (height %1) (height %2))) 7.163 + (->Size 0 0) 7.164 + (map geometry contents))))) 7.165 + 7.166 +(defn- re-split [^java.util.regex.Pattern re s] 7.167 + (seq (.split re s))) 7.168 + 7.169 +(def ^:private ^Cache text-layout-cache 7.170 + (-> (CacheBuilder/newBuilder) 7.171 + (.softValues) 7.172 + (.expireAfterAccess (long 1) TimeUnit/SECONDS) 7.173 + (.build))) 7.174 + 7.175 +(defn- get-text-layout 7.176 + [^String line ^Font font ^FontRenderContext font-context] 7.177 + (.get text-layout-cache [line font font-context] 7.178 + #(TextLayout. line font font-context))) 7.179 + 7.180 +(defn- layout-text 7.181 + [lines font font-context] 7.182 + (map #(get-text-layout % font font-context) lines)) 7.183 + 7.184 +(defn- text-width [layouts] 7.185 + (reduce (fn [w ^TextLayout tl] (max w (.getAdvance tl))) 0 layouts)) 7.186 + 7.187 +(defn- text-height [layouts] 7.188 + (reduce (fn [w ^TextLayout tl] 7.189 + (+ w (.getAscent tl) 7.190 + (.getDescent tl) 7.191 + (.getLeading tl))) 7.192 + 0 layouts)) 7.193 + 7.194 +(defn label 7.195 + "Creates a view to display multiline text." 7.196 + ([text] 7.197 + (label text :left :top)) 7.198 + ([text h-align v-align] 7.199 + (let [lines (re-split #"\r\n|\n|\r|\u0085|\u2028|\u2029" (str text))] 7.200 + (reify View 7.201 + (render! [view] 7.202 + (let [w *width* 7.203 + h *height* 7.204 + font (.getFont *graphics*) 7.205 + layouts (layout-text lines font (font-context)) 7.206 + y (align-y v-align (text-height layouts) h)] 7.207 + (loop [layouts layouts, y y] 7.208 + (when-first [^TextLayout layout layouts] 7.209 + (let [ascent (.getAscent layout) 7.210 + lh (+ ascent (.getDescent layout) (.getLeading layout)) 7.211 + x (align-x h-align (.getAdvance layout) w)] 7.212 + (.draw layout *graphics* x (+ y ascent)) 7.213 + (recur (next layouts) (+ y lh))))))) 7.214 + (geometry [view] 7.215 + (let [layouts (layout-text lines (:font *theme*) (font-context)) 7.216 + w (text-width layouts) 7.217 + h (text-height layouts)] 7.218 + (->Size w h))))))) 7.219 + 7.220 +(defn- ^ImageObserver image-observer [view] 7.221 + (reify 7.222 + ImageObserver 7.223 + (imageUpdate [this img infoflags x y width height] 7.224 + (update view) 7.225 + (zero? (bit-and infoflags 7.226 + (bit-or ImageObserver/ALLBITS 7.227 + ImageObserver/ABORT)))))) 7.228 + 7.229 +(defn image-view 7.230 + [image-or-uri] 7.231 + (let [^Image image (if (instance? Image image-or-uri) 7.232 + image-or-uri 7.233 + (.getImage (Toolkit/getDefaultToolkit) 7.234 + ^java.net.URL image-or-uri))] 7.235 + (.prepareImage (Toolkit/getDefaultToolkit) image -1 -1 nil) 7.236 + (reify 7.237 + View 7.238 + (render! [view] 7.239 + (repaint-on-update view) 7.240 + (.drawImage *graphics* image 0 0 (image-observer view))) 7.241 + (geometry [view] 7.242 + (let [observer (image-observer view) 7.243 + width (.getWidth image observer) 7.244 + height (.getHeight image observer) 7.245 + width (if (pos? width) width 1) 7.246 + height (if (pos? height) height 1)] 7.247 + (->Size width height)))))) 7.248 + 7.249 +(def ^:dynamic *miniature-thread-priority* 2) 7.250 + 7.251 +(defn ref-view 7.252 + [view-ref] 7.253 + (let [l (reify 7.254 + View 7.255 + (render! [l] 7.256 + (repaint-on-update l) 7.257 + (if-let [view @view-ref] 7.258 + (render! view))) 7.259 + (geometry [_] 7.260 + (if-let [view @view-ref] 7.261 + (geometry view) 7.262 + (->Size 1 1))))] 7.263 + (add-watch view-ref l (fn [_ _ _ _] (update l))) 7.264 + l)) 7.265 + 7.266 +;; 7.267 +;; View context decorators 7.268 +;; 7.269 + 7.270 +(defmacro handler [view & handlers] 7.271 + "Adds event handling to the view." 7.272 + `(let [view# ~view] 7.273 + (decorate-view view# [t#] 7.274 + (with-handlers t# 7.275 + (render! view#) 7.276 + ~@handlers)))) 7.277 + 7.278 +(defn themed [view & map-or-keyvals] 7.279 + (let [theme (if (== (count map-or-keyvals) 1) 7.280 + (first map-or-keyvals) 7.281 + (apply array-map map-or-keyvals))] 7.282 + (reify 7.283 + View 7.284 + (render! [_] 7.285 + (with-theme theme 7.286 + (render! view))) 7.287 + (geometry [_] 7.288 + (with-theme theme 7.289 + (geometry view)))))) 7.290 + 7.291 +(defn hinted [view & map-or-keyvals] 7.292 + (let [hints (if (== (count map-or-keyvals) 1) 7.293 + (first map-or-keyvals) 7.294 + (apply array-map map-or-keyvals))] 7.295 + (decorate-view view [_] 7.296 + (with-hints* hints render! view)))) 7.297 + 7.298 +;; 7.299 +;; Measuring time 7.300 +;; 7.301 + 7.302 +(def ^:dynamic *interval*) 7.303 + 7.304 +(defn interval-view 7.305 + "Creates a view that measures time between repaints ant draws it's 7.306 + content with the *interval* var bound to the measured time." 7.307 + [content] 7.308 + (let [last-time (atom nil)] 7.309 + (decorate-view content [_] 7.310 + (compare-and-set! last-time nil *time*) 7.311 + (let [lt @last-time] 7.312 + (binding [*interval* (if (compare-and-set! last-time lt *time*) 7.313 + (- *time* lt) 7.314 + 0)] ; already measured on parallel thread 7.315 + (render! content)))))) 7.316 + 7.317 +(defn- fps-label [text] 7.318 + (padding (label text :right :bottom) 5)) 7.319 + 7.320 +(defn fps-view 7.321 + "Creates a view that draws content and displays the 7.322 + frames per second rate." 7.323 + [content] 7.324 + (let [update-interval 2E8 ; 0.2 s in nanoseconds 7.325 + frames (ref 0) 7.326 + prev-time (ref nil) 7.327 + display (ref (fps-label "fps n/a"))] 7.328 + (decorate-view content [_] 7.329 + (draw! content) 7.330 + (draw! 7.331 + (dosync 7.332 + (alter frames inc) 7.333 + (if @prev-time 7.334 + (let [elapsed (- *time* @prev-time)] 7.335 + (when (> elapsed update-interval) 7.336 + (let [fps (/ @frames (/ elapsed 1E9))] 7.337 + (ref-set display (fps-label (format "%.1f" fps))) 7.338 + (ref-set frames 0) 7.339 + (ref-set prev-time *time*)))) 7.340 + (ref-set prev-time *time*)) 7.341 + @display))))) 7.342 + 7.343 +;; 7.344 +;; Overlays 7.345 +;; 7.346 + 7.347 +(def ^:private ^:dynamic *above*) 7.348 + 7.349 +(defn- overlay* [f & args] 7.350 + (var-set #'*above* (conj *above* (apply partial f args)))) 7.351 + 7.352 +(defn- ^Point2D to-graphics-coords 7.353 + [^AffineTransform transform x y] 7.354 + (let [p (Point2D$Double. x y)] 7.355 + (.transform transform p p) 7.356 + (.transform (.createInverse (.getTransform *graphics*)) p p) 7.357 + p)) 7.358 + 7.359 +(defn- draw-relative! 7.360 + ([view transform x y] 7.361 + (let [p (to-graphics-coords transform x y)] 7.362 + (draw! view (.getX p) (.getY p)))) 7.363 + ([view transform x y w h] 7.364 + (let [p (to-graphics-coords transform x y)] 7.365 + (draw! view (.getX p) (.getY p) w h)))) 7.366 + 7.367 +(defn- draw-relative-aligned! 7.368 + [view transform h-align v-align x y] 7.369 + (let [geom (geometry view) 7.370 + w (width geom) 7.371 + h (height geom) 7.372 + p (to-graphics-coords transform x y) 7.373 + x (- (.getX p) (anchor-x geom h-align w)) 7.374 + y (- (.getY p) (anchor-y geom v-align h))] 7.375 + (draw! view x y w h))) 7.376 + 7.377 +(defn overlay! 7.378 + "Draws view in the overlay context above the other views." 7.379 + ([view] 7.380 + (overlay* draw-relative! view (.getTransform *graphics*) 0 0)) 7.381 + ([view x y] 7.382 + (overlay* draw-relative! view (.getTransform *graphics*) x y)) 7.383 + ([view x y w h] 7.384 + (overlay* draw-relative! view (.getTransform *graphics*) x y w h))) 7.385 + 7.386 +(defn overlay-aligned! [view h-align v-align x y] 7.387 + (overlay* draw-relative-aligned! 7.388 + view (.getTransform *graphics*) 7.389 + h-align v-align x y)) 7.390 + 7.391 +(defn with-overlays* [rec? f & args] 7.392 + (binding [*above* []] 7.393 + (apply f args) 7.394 + (if rec? 7.395 + (loop [above *above*] 7.396 + (when (seq above) 7.397 + (var-set #'*above* []) 7.398 + (doseq [f above] 7.399 + (f)) 7.400 + (recur *above*))) 7.401 + (doseq [of *above*] 7.402 + (of))))) 7.403 + 7.404 +(defmacro with-overlays [rec? & body] 7.405 + `(with-overlays* ~rec? (fn [] ~@body))) 7.406 + 7.407 +(defn layered 7.408 + ([content] 7.409 + (layered content true)) 7.410 + ([content rec?] 7.411 + (decorate-view content [_] 7.412 + (with-overlays* rec? render! content))))