Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FlashForeground |
|
| 4.75;4.75 |
1 | package us.daveread.basicquery.gui; | |
2 | ||
3 | import java.awt.Component; | |
4 | import java.awt.Color; | |
5 | ||
6 | import org.apache.log4j.Logger; | |
7 | ||
8 | /** | |
9 | * <p> | |
10 | * Title: Flash foreground | |
11 | * </p> | |
12 | * <p> | |
13 | * Description: Eye candy modifying the foreground color of a component | |
14 | * </p> | |
15 | * <p> | |
16 | * Copyright: Copyright (c) 2004-2014, David Read | |
17 | * </p> | |
18 | * <p> | |
19 | * This program is free software; you can redistribute it and/or modify it under | |
20 | * the terms of the GNU General Public License as published by the Free Software | |
21 | * Foundation; either version 2 of the License, or (at your option) any later | |
22 | * version. | |
23 | * </p> | |
24 | * <p> | |
25 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
26 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
27 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
28 | * details. | |
29 | * </p> | |
30 | * <p> | |
31 | * You should have received a copy of the GNU General Public License along with | |
32 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
33 | * Place, Suite 330, Boston, MA 02111-1307 USA | |
34 | * </p> | |
35 | * <p> | |
36 | * </p> | |
37 | * | |
38 | * @author David Read | |
39 | */ | |
40 | ||
41 | public class FlashForeground implements Runnable { | |
42 | /** | |
43 | * Logger | |
44 | */ | |
45 | 1 | private static final Logger LOGGER = Logger.getLogger(FlashForeground.class); |
46 | ||
47 | /** | |
48 | * The component backing this instance | |
49 | */ | |
50 | private Component component; | |
51 | ||
52 | /** | |
53 | * The color to display when the flash is "on" | |
54 | */ | |
55 | private Color onColor; | |
56 | ||
57 | /** | |
58 | * The color to display when the flash is "off" | |
59 | */ | |
60 | private Color offColor; | |
61 | ||
62 | /** | |
63 | * Delay time when cycling the steps between "on" and "off" colors | |
64 | */ | |
65 | private int msDelay; | |
66 | ||
67 | /** | |
68 | * Red color value for RGB coloring when the flash is "on" | |
69 | */ | |
70 | private int redOn; | |
71 | ||
72 | /** | |
73 | * Red color value for RGB coloring when the flash is "off" | |
74 | */ | |
75 | private int redOff; | |
76 | ||
77 | /** | |
78 | * Green color value for RGB coloring when the flash is "on" | |
79 | */ | |
80 | private int greenOn; | |
81 | ||
82 | /** | |
83 | * Green color value for RGB coloring when the flash is "off" | |
84 | */ | |
85 | private int greenOff; | |
86 | ||
87 | /** | |
88 | * Blue color value for RGB coloring when the flash is "on" | |
89 | */ | |
90 | private int blueOn; | |
91 | ||
92 | /** | |
93 | * Blue color value for RGB coloring when the flash is "off" | |
94 | */ | |
95 | private int blueOff; | |
96 | ||
97 | /** | |
98 | * Amount of change for the red component of the RGB color at each step in the | |
99 | * coloring cycle | |
100 | */ | |
101 | private int redChange; | |
102 | ||
103 | /** | |
104 | * Amount of change for the green component of the RGB color at each step in | |
105 | * the coloring cycle | |
106 | */ | |
107 | private int greenChange; | |
108 | ||
109 | /** | |
110 | * Amount of change for the blue component of the RGB color at each step in | |
111 | * the coloring cycle | |
112 | */ | |
113 | private int blueChange; | |
114 | ||
115 | /** | |
116 | * Current red value in the RGB color | |
117 | */ | |
118 | private int redValue; | |
119 | ||
120 | /** | |
121 | * Current green value in the RGB color | |
122 | */ | |
123 | private int greenValue; | |
124 | ||
125 | /** | |
126 | * Current blue value in the RGB color | |
127 | */ | |
128 | private int blueValue; | |
129 | ||
130 | /** | |
131 | * The modulus value of the iteration counter for changing the red component | |
132 | * of the RGB color | |
133 | */ | |
134 | private int redModulus; | |
135 | ||
136 | /** | |
137 | * The modulus value of the iteration counter for changing the green component | |
138 | * of the RGB color | |
139 | */ | |
140 | private int greenModulus; | |
141 | ||
142 | /** | |
143 | * The modulus value of the iteration counter for changing the blue component | |
144 | * of the RGB color | |
145 | */ | |
146 | private int blueModulus; | |
147 | ||
148 | /** | |
149 | * The maximum range of the iteration counter to cycle through the component | |
150 | * color ranges from "on" to "off" | |
151 | */ | |
152 | private int maxChange; | |
153 | ||
154 | /** | |
155 | * The current value of the iteration counter cycling through the component | |
156 | * color ranges from "on" to "off" | |
157 | */ | |
158 | private int currentValue; | |
159 | ||
160 | /** | |
161 | * The current iteration direction (1=up or -1=down). Up moves from the "off" | |
162 | * color to the "on" color. | |
163 | */ | |
164 | private int direction; | |
165 | ||
166 | /** | |
167 | * Create a FlashForeground instance, associated with a specific component. | |
168 | * Then the instance is notified that it should "flash" it will begin changing | |
169 | * the foreground color between the "On" and "Off" colors. When the instance | |
170 | * is notified that it should stop, the foreground color is changed to | |
171 | * the "Off" color | |
172 | * | |
173 | * @param aComp | |
174 | * The component whose foreground color is controlled by this | |
175 | * instance | |
176 | * @param aOnColor | |
177 | * The color used to indicate some activity is running. | |
178 | * @param aOffColor | |
179 | * The default foreground color of the component. | |
180 | * @param aMSDelay | |
181 | * The number of milliseconds between color changes. Note that | |
182 | * the colors change by gradation, so this number should be small. | |
183 | */ | |
184 | public FlashForeground(Component aComp, Color aOnColor, Color aOffColor, | |
185 | 6 | int aMSDelay) { |
186 | 6 | component = aComp; |
187 | 6 | onColor = aOnColor; |
188 | 6 | offColor = aOffColor; |
189 | 6 | msDelay = aMSDelay; |
190 | 6 | computeChange(); |
191 | 6 | direction = -1; |
192 | 6 | currentValue = 0; |
193 | 6 | } |
194 | ||
195 | /** | |
196 | * Calculate the next color to be used for the foreground. The algorithm | |
197 | * is pretty simple, just change the RGB values between the "On" and "Off" | |
198 | * colors, incrementing based on the widest color descrepency. | |
199 | * | |
200 | * @return The Color to be used for the foreground | |
201 | */ | |
202 | private Color nextColor() { | |
203 | 295 | if (currentValue <= 0 || currentValue >= maxChange) { |
204 | 5 | direction *= -1; |
205 | } | |
206 | ||
207 | 295 | currentValue += direction; |
208 | ||
209 | 295 | if (currentValue == maxChange) { |
210 | 2 | redValue = redOn; |
211 | 2 | greenValue = greenOn; |
212 | 2 | blueValue = blueOn; |
213 | 293 | } else if (currentValue == 0) { |
214 | 2 | redValue = redOff; |
215 | 2 | greenValue = greenOff; |
216 | 2 | blueValue = blueOff; |
217 | } else { | |
218 | 291 | if (currentValue % redModulus == 0) { |
219 | 291 | redValue += (redChange * direction) < 0 ? 1 : -1; |
220 | } | |
221 | ||
222 | 291 | if (currentValue % greenModulus == 0) { |
223 | 291 | greenValue += (greenChange * direction) < 0 ? 1 : -1; |
224 | } | |
225 | ||
226 | 291 | if (currentValue % blueModulus == 0) { |
227 | 291 | blueValue += (blueChange * direction) < 0 ? 1 : -1; |
228 | } | |
229 | } | |
230 | ||
231 | 295 | if (currentValue == 0 || currentValue == maxChange) { |
232 | 4 | LOGGER.debug("currentValue=" + currentValue); |
233 | } | |
234 | ||
235 | 295 | return new Color(redValue, greenValue, blueValue); |
236 | } | |
237 | ||
238 | /** | |
239 | * Compute the RGB values for the "On" and "Off" colors. Then determine | |
240 | * the distance (numerically) between them. | |
241 | */ | |
242 | private void computeChange() { | |
243 | 6 | redOn = onColor.getRed(); |
244 | 6 | redOff = offColor.getRed(); |
245 | 6 | greenOn = onColor.getGreen(); |
246 | 6 | greenOff = offColor.getGreen(); |
247 | 6 | blueOn = onColor.getBlue(); |
248 | 6 | blueOff = offColor.getBlue(); |
249 | 6 | redChange = redOff - redOn; |
250 | 6 | greenChange = greenOff - greenOn; |
251 | 6 | blueChange = blueOff - blueOn; |
252 | 6 | maxChange = Math.abs(redChange); |
253 | 6 | if (Math.abs(greenChange) > maxChange) { |
254 | 1 | maxChange = Math.abs(greenChange); |
255 | } | |
256 | 6 | if (Math.abs(blueChange) > maxChange) { |
257 | 1 | maxChange = Math.abs(blueChange); |
258 | } | |
259 | ||
260 | 6 | if (redChange != 0) { |
261 | 5 | redModulus = maxChange / Math.abs(redChange); |
262 | // if (redModulus < 1) { | |
263 | // redModulus = 1; | |
264 | // } | |
265 | } else { | |
266 | 1 | redModulus = maxChange + 1; |
267 | } | |
268 | ||
269 | 6 | if (greenChange != 0) { |
270 | 5 | greenModulus = maxChange / Math.abs(greenChange); |
271 | // if (greenModulus < 1) { | |
272 | // greenModulus = 1; | |
273 | // } | |
274 | } else { | |
275 | 1 | greenModulus = maxChange + 1; |
276 | } | |
277 | ||
278 | 6 | if (blueChange != 0) { |
279 | 5 | blueModulus = maxChange / Math.abs(blueChange); |
280 | // if (blueModulus < 1) { | |
281 | // blueModulus = 1; | |
282 | // } | |
283 | } else { | |
284 | 1 | blueModulus = maxChange + 1; |
285 | } | |
286 | ||
287 | 6 | redValue = redOff; |
288 | 6 | greenValue = greenOff; |
289 | 6 | blueValue = blueOff; |
290 | 6 | } |
291 | ||
292 | /** | |
293 | * Oscillate the component colors until an interrupt is | |
294 | * received. | |
295 | */ | |
296 | public void run() { | |
297 | boolean isOn; | |
298 | boolean keepGoing; | |
299 | ||
300 | 1 | isOn = false; |
301 | 1 | keepGoing = true; |
302 | ||
303 | try { | |
304 | 296 | while (keepGoing && !Thread.currentThread().isInterrupted()) { |
305 | 295 | isOn = !isOn; |
306 | // component.setForeground(isOn ? onColor : offColor); | |
307 | 295 | component.setForeground(nextColor()); |
308 | try { | |
309 | 295 | Thread.sleep(msDelay); |
310 | 1 | } catch (InterruptedException ie) { |
311 | 1 | keepGoing = false; |
312 | 295 | } |
313 | } | |
314 | 0 | } catch (Throwable any) { |
315 | 0 | LOGGER.warn("Error when iterating through colors in a compoenent", any); |
316 | } finally { | |
317 | 1 | component.setForeground(offColor); |
318 | 1 | } |
319 | 1 | } |
320 | } |