1 | |
package com.liquidatom.derbyscore.ui; |
2 | |
|
3 | |
import com.liquidatom.derbyscore.domain.Bout; |
4 | |
import com.liquidatom.derbyscore.domain.BoutListener; |
5 | |
import com.liquidatom.derbyscore.theme.ImageElement; |
6 | |
import com.liquidatom.derbyscore.theme.TextElement; |
7 | |
import com.liquidatom.derbyscore.theme.Theme; |
8 | |
import com.liquidatom.derbyscore.theme.ThemeElement; |
9 | |
import com.liquidatom.derbyscore.theme.ThemeFactory; |
10 | |
import java.awt.Color; |
11 | |
import java.awt.Font; |
12 | |
import java.awt.FontMetrics; |
13 | |
import java.awt.Graphics; |
14 | |
import java.awt.Graphics2D; |
15 | |
import java.awt.GraphicsConfiguration; |
16 | |
import java.awt.GraphicsEnvironment; |
17 | |
import java.awt.Point; |
18 | |
import java.awt.Rectangle; |
19 | |
import java.awt.RenderingHints; |
20 | |
import java.awt.Transparency; |
21 | |
import java.awt.event.ComponentEvent; |
22 | |
import java.awt.event.ComponentListener; |
23 | |
import java.awt.geom.AffineTransform; |
24 | |
import java.awt.geom.Rectangle2D; |
25 | |
import java.awt.image.BufferStrategy; |
26 | |
import java.awt.image.BufferedImage; |
27 | |
import java.io.IOException; |
28 | |
import java.net.URL; |
29 | |
import java.util.Collection; |
30 | |
import java.util.LinkedHashMap; |
31 | |
import java.util.Map; |
32 | |
import javax.imageio.ImageIO; |
33 | |
import javax.swing.JFrame; |
34 | |
import org.slf4j.Logger; |
35 | |
import org.slf4j.LoggerFactory; |
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
|
41 | |
public class ScoreboardWindow extends JFrame implements BoutListener, ComponentListener { |
42 | |
|
43 | 0 | static private final Logger log = LoggerFactory.getLogger(ScoreboardWindow.class); |
44 | |
static private final int DEFAULT_WINDOW_WIDTH = 800; |
45 | |
static private final int DEFAULT_WINDOW_HEIGHT = 600; |
46 | |
|
47 | |
|
48 | 0 | private GraphicsConfiguration graphicsConfiguration = |
49 | |
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); |
50 | |
|
51 | 0 | private AffineTransform xform = AffineTransform.getTranslateInstance(0.0, 0.0); |
52 | |
private Bout bout; |
53 | 0 | private Map<String, Object> scriptScope = new LinkedHashMap<String, Object>(); |
54 | |
|
55 | |
public ScoreboardWindow(Bout bout) { |
56 | 0 | super(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration()); |
57 | 0 | setDefaultCloseOperation(DISPOSE_ON_CLOSE); |
58 | 0 | setSize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT); |
59 | 0 | setLocationByPlatform(true); |
60 | 0 | setFocusTraversalKeysEnabled(false); |
61 | |
|
62 | |
|
63 | 0 | addComponentListener(this); |
64 | 0 | this.getRootPane().setDoubleBuffered(true); |
65 | |
|
66 | |
try { |
67 | 0 | URL appLogo = getClass().getResource("/gfx/brrg.png"); |
68 | 0 | setIconImage(ImageIO.read(appLogo)); |
69 | |
} |
70 | 0 | catch (IOException e) { |
71 | 0 | if (log.isWarnEnabled()) { |
72 | 0 | log.warn("Unable to set window icon for scoreboard."); |
73 | |
} |
74 | 0 | } |
75 | |
|
76 | 0 | setBout(bout); |
77 | 0 | } |
78 | |
|
79 | |
@Override |
80 | |
public void paint(Graphics parentGraphics) { |
81 | 0 | BufferStrategy strategy = getBufferStrategy(); |
82 | 0 | if (strategy != null) { |
83 | 0 | Graphics2D g = (Graphics2D) strategy.getDrawGraphics(); |
84 | |
try { |
85 | |
|
86 | |
|
87 | 0 | Rectangle r = parentGraphics.getClipBounds(); |
88 | 0 | if (r != null) { |
89 | 0 | g.setClip((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight()); |
90 | |
} |
91 | 0 | g.transform(xform); |
92 | 0 | render(g); |
93 | 0 | strategy.show(); |
94 | |
} |
95 | |
finally { |
96 | 0 | g.dispose(); |
97 | 0 | } |
98 | |
} |
99 | 0 | } |
100 | |
|
101 | |
protected void render(Graphics2D g) { |
102 | 0 | getBout().getPeriodClock().readLock().lock(); |
103 | |
try { |
104 | 0 | getBout().getJamClock().readLock().lock(); |
105 | |
try { |
106 | 0 | g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); |
107 | 0 | Collection<ThemeElement> elements = getTheme().getThemeElements(); |
108 | 0 | for (ThemeElement element : elements) { |
109 | 0 | drawThemeElement(g, element); |
110 | |
} |
111 | |
} |
112 | |
finally { |
113 | 0 | getBout().getJamClock().readLock().unlock(); |
114 | 0 | } |
115 | |
} |
116 | |
finally { |
117 | 0 | getBout().getPeriodClock().readLock().unlock(); |
118 | 0 | } |
119 | 0 | } |
120 | |
|
121 | |
protected void drawThemeElement(Graphics2D g, ThemeElement element) { |
122 | 0 | if (element.isVisible(getScriptScope())) { |
123 | 0 | if (element instanceof TextElement) { |
124 | 0 | drawTextElement(g, (TextElement)element); |
125 | |
} |
126 | 0 | else if (element instanceof ImageElement) { |
127 | 0 | drawImageElement(g, (ImageElement)element); |
128 | |
} |
129 | |
} |
130 | 0 | } |
131 | |
|
132 | |
protected void drawTextElement(Graphics2D g, TextElement element) { |
133 | 0 | String text = element.getText(getScriptScope()); |
134 | 0 | Font font = element.getFont(); |
135 | 0 | Color color = element.getColor(); |
136 | |
|
137 | 0 | g.setFont(font); |
138 | 0 | g.setColor(color); |
139 | 0 | FontMetrics fontMetrics = g.getFontMetrics(); |
140 | 0 | Rectangle2D bounds = fontMetrics.getStringBounds(text, g); |
141 | 0 | int width = (int) bounds.getWidth(); |
142 | 0 | int height = (int) bounds.getHeight(); |
143 | 0 | if (width > 0 && height > 0) { |
144 | 0 | BufferedImage textImage = getDefaultConfiguration().createCompatibleImage(width, height, Transparency.BITMASK); |
145 | 0 | Graphics2D textG = textImage.createGraphics(); |
146 | |
try { |
147 | 0 | textG.setFont(font); |
148 | 0 | textG.setColor(color); |
149 | 0 | textG.drawString(text, 0, fontMetrics.getAscent()); |
150 | |
|
151 | 0 | Rectangle position = element.getPosition(); |
152 | 0 | g.drawImage(textImage, |
153 | |
(int)position.getX(), |
154 | |
(int)position.getY(), |
155 | |
(int)position.getWidth(), |
156 | |
(int)position.getHeight(), |
157 | |
null); |
158 | |
} |
159 | |
finally { |
160 | 0 | textG.dispose(); |
161 | 0 | } |
162 | |
} |
163 | 0 | } |
164 | |
|
165 | |
protected void drawImageElement(Graphics2D g, ImageElement element) { |
166 | 0 | BufferedImage image = getTheme().getImage(element.getImgRef()); |
167 | 0 | if (image != null) { |
168 | 0 | Rectangle position = element.getPosition(); |
169 | 0 | int x = (int) position.getX(); |
170 | 0 | int y = (int) position.getY(); |
171 | 0 | int width = (int) position.getWidth(); |
172 | 0 | int height = (int) position.getHeight(); |
173 | 0 | g.drawImage(image, x, y, width, height, null); |
174 | |
} |
175 | 0 | } |
176 | |
|
177 | |
protected GraphicsConfiguration getDefaultConfiguration() { |
178 | 0 | return graphicsConfiguration; |
179 | |
} |
180 | |
|
181 | |
protected void setScriptScope(Map<String, Object> scriptScope) { |
182 | 0 | if (scriptScope == null) { |
183 | 0 | throw new IllegalArgumentException("The parameter scriptScope must be non-null."); |
184 | |
} |
185 | 0 | this.scriptScope = scriptScope; |
186 | 0 | } |
187 | |
|
188 | |
protected Map<String, Object> getScriptScope() { |
189 | 0 | return scriptScope; |
190 | |
} |
191 | |
|
192 | |
protected Theme getTheme() { |
193 | 0 | return ThemeFactory.getInstance().getCurrent(); |
194 | |
} |
195 | |
|
196 | |
protected void setBout(Bout bout) { |
197 | 0 | this.bout = bout; |
198 | 0 | if (bout == null) { |
199 | 0 | scriptScope.remove("bout"); |
200 | |
} |
201 | |
else { |
202 | 0 | scriptScope.put("bout", bout); |
203 | |
} |
204 | 0 | } |
205 | |
|
206 | |
protected Bout getBout() { |
207 | 0 | return bout; |
208 | |
} |
209 | |
|
210 | |
public void onChanged() { |
211 | 0 | repaint(); |
212 | 0 | } |
213 | |
|
214 | |
public void componentResized(ComponentEvent e) { |
215 | |
|
216 | 0 | Point parentPoint = getLocationOnScreen(); |
217 | 0 | Point childPoint = getContentPane().getLocationOnScreen(); |
218 | 0 | double tx = childPoint.getX() - parentPoint.getX(); |
219 | 0 | double ty = childPoint.getY() - parentPoint.getY(); |
220 | 0 | AffineTransform transform = AffineTransform.getTranslateInstance(tx, ty); |
221 | |
|
222 | |
|
223 | 0 | BufferedImage original = getTheme().getBackdrop(); |
224 | 0 | int width = getContentPane().getWidth(); |
225 | 0 | int height = getContentPane().getHeight(); |
226 | 0 | double sx = (double)width / (double)original.getWidth(); |
227 | 0 | double sy = (double)height / (double)original.getHeight(); |
228 | 0 | transform.concatenate(AffineTransform.getScaleInstance(sx, sy)); |
229 | |
|
230 | |
|
231 | 0 | this.xform = transform; |
232 | |
|
233 | |
|
234 | 0 | repaint(); |
235 | 0 | } |
236 | |
|
237 | |
public void componentMoved(ComponentEvent e) { |
238 | 0 | } |
239 | |
|
240 | |
public void componentShown(ComponentEvent e) { |
241 | 0 | createBufferStrategy(2); |
242 | 0 | } |
243 | |
|
244 | |
public void componentHidden(ComponentEvent e) { |
245 | 0 | } |
246 | |
} |