1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.cosylab.gui.components.slider;
21
22 import java.awt.AlphaComposite;
23 import java.awt.Color;
24 import java.awt.FontMetrics;
25 import java.awt.Graphics;
26 import java.awt.Graphics2D;
27 import java.awt.Rectangle;
28 import java.awt.image.BufferedImage;
29
30 import javax.swing.Icon;
31 import javax.swing.JComponent;
32 import javax.swing.JSlider;
33 import javax.swing.plaf.metal.MetalSliderUI;
34
35 import com.cosylab.gui.components.range2.RangedValueController;
36 import com.cosylab.gui.components.range2.Tick;
37 import com.cosylab.gui.components.range2.TickParameters;
38 import com.cosylab.util.PrintfFormat;
39
40
41
42
43
44
45
46
47 public class CosySliderUI extends MetalSliderUI
48 {
49 private boolean checkValue;
50 protected Icon vertTrailerIcon = null;
51 protected BufferedImage horizTrailerBuffer = null;
52 private AlphaComposite alphaComposite;
53 protected Rectangle trailerRect = new Rectangle(0, 0, 16, 16);
54 protected Rectangle trailerCache = new Rectangle();
55 protected double trailerPosition = 0;
56 private boolean showIntegerOnly = false;
57 private String format = "%f";
58 private double tolerance = 0.0001;
59 private boolean paintTrailer = true;
60
61 protected static final Color[] GREEN_LED = {
62 new Color(0, 160, 0), new Color(0, 220, 0), new Color(0, 250, 0)
63 };
64 protected static final Color[] RED_LED = {
65 new Color(160, 0, 0), new Color(220, 0, 0), new Color(250, 0, 0)
66 };
67 protected static final Color[] YELLOW_LED = {
68 new Color(150, 150, 0), new Color(200, 200, 0), new Color(250, 250, 0)
69 };
70 protected static final Color[] GREY_LED = {
71 new Color(64, 64, 64), new Color(128, 128, 128),
72 new Color(160, 160, 160)
73 };
74
75 private class TickMeasurer implements TickParameters
76 {
77 private FontMetrics fm;
78 private PrintfFormat formatter;
79
80
81
82
83
84
85 public TickMeasurer(Graphics g, String format)
86 {
87 fm = g.getFontMetrics();
88 if (format != null)
89 formatter = new PrintfFormat(format);
90 }
91
92
93
94
95 public int measureTick(double position, String text)
96 {
97
98 if(text==null) {
99 return 0;
100 }
101 return fm.stringWidth(text);
102 }
103
104
105
106
107
108 public String formatNumber(double value) {
109 if (formatter != null)
110 return formatter.sprintf(value);
111 else
112 return null;
113 }
114 }
115
116 private RangedValueController rangedValue;
117
118
119
120
121
122
123 public CosySliderUI(RangedValueController range)
124 {
125 super();
126 rangedValue = range;
127 alphaComposite = AlphaComposite.getInstance(AlphaComposite.DST_OVER,
128 (float)0.35);
129 }
130
131 private void renderHorizontalTrailer(Graphics g)
132 {
133 int[] xPoints = { 1, 14, 15, 15, 8, 0, 0 };
134 int[] yPoints = { 0, 0, 1, 9, 16, 9, 1 };
135
136 g.setColor((checkValue ? Color.black : YELLOW_LED[0]));
137 g.fillPolygon(xPoints, yPoints, xPoints.length);
138 }
139
140
141
142
143
144
145
146 protected BufferedImage getTrailer()
147 {
148 if(horizTrailerBuffer == null) {
149
150
151
152
153
154
155
156
157 trailerCache.width = trailerRect.width;
158 trailerCache.height = trailerRect.height;
159
160
161
162 horizTrailerBuffer = new BufferedImage(16, 16,
163 BufferedImage.TYPE_INT_ARGB);
164
165 Graphics2D gbi = horizTrailerBuffer.createGraphics();
166 gbi.setComposite(alphaComposite);
167
168 renderHorizontalTrailer(gbi);
169 }
170
171 return horizTrailerBuffer;
172 }
173
174 protected void calculateTrailerLocation()
175 {
176 int t = (int)(rangedValue.toRelative(getTrailerPosition()));
177
178 if(slider.getOrientation() == JSlider.HORIZONTAL) {
179 int valuePosition = xPositionForValue(t);
180
181 trailerRect.x = valuePosition - (trailerRect.width / 2);
182 trailerRect.y = thumbRect.y;
183 } else {
184 int valuePosition = yPositionForValue(t);
185
186 trailerRect.x = thumbRect.x;
187 trailerRect.y = valuePosition - (trailerRect.height / 2);
188 }
189 }
190
191
192
193
194
195
196 public double getTrailerPosition()
197 {
198 return trailerPosition;
199 }
200
201
202
203
204
205
206 public void setTrailerPosition(double value)
207 {
208 trailerCache.x = trailerRect.x;
209 trailerCache.y = trailerRect.y;
210
211 trailerPosition = value;
212 calculateTrailerLocation();
213
214
215
216
217 boolean oldCheck = checkValue;
218
219 checkValue = (trailerPosition<=rangedValue.getMaximum() && trailerPosition>=rangedValue.getMinimum());
220
221 if (checkValue!=oldCheck) horizTrailerBuffer = null;
222
223 slider.repaint(trailerCache);
224 slider.repaint(trailerRect);
225 slider.repaint(new Rectangle(0, 0, slider.getWidth(), slider.getHeight()));
226 }
227
228
229
230
231
232
233 public void paintTrailer(Graphics g)
234 {
235 if (!paintTrailer) return;
236 g.translate(trailerRect.x, thumbRect.y);
237
238 if(slider.getOrientation() == JSlider.HORIZONTAL) {
239 ((Graphics2D)g).drawImage(getTrailer(), null, 0, 0);
240 } else {
241 }
242
243 g.translate(-trailerRect.x, -thumbRect.y);
244
245 if(thumbRect.x == trailerRect.x) {
246 paintThumb(g);
247 }
248 }
249
250 protected Color[] getIndicatorColor()
251 {
252 if (slider.isEnabled()) {
253 if (paintTrailer) {
254 if (!checkValue) {
255 return RED_LED;
256 } else {
257
258 return (Math.abs(rangedValue.getValue() - trailerPosition) < tolerance) ? GREEN_LED : RED_LED;
259 }
260 } else {
261 return GREEN_LED;
262 }
263 } else {
264 return GREY_LED;
265 }
266 }
267
268
269
270
271
272 public void paintThumb(Graphics g)
273 {
274 super.paintThumb(g);
275
276 if (!paintTrailer) {
277 return;
278 }
279
280 Rectangle knobBounds = thumbRect;
281 g.translate(knobBounds.x, knobBounds.y);
282
283 if(slider.getOrientation() == JSlider.HORIZONTAL) {
284 Color[] colors = getIndicatorColor();
285
286 g.setColor(colors[0]);
287 g.drawLine(1, 3, 13, 3);
288 g.drawLine(13, 2, 13, 1);
289
290 g.setColor(colors[1]);
291 g.drawLine(1, 1, 13, 1);
292 g.drawLine(1, 1, 1, 3);
293 g.setColor(colors[2]);
294 g.drawLine(2, 2, 12, 2);
295 g.setColor(Color.black);
296 g.drawLine(1, 4, 13, 4);
297 } else {
298 }
299
300 g.translate(-knobBounds.x, -knobBounds.y);
301 }
302
303
304
305
306
307 public void paint(Graphics g, JComponent c)
308 {
309 super.paint(g, c);
310 calculateTrailerLocation();
311
312 Rectangle clip = g.getClipBounds();
313
314 if(clip.intersects(trailerRect)) {
315 paintTrailer(g);
316 }
317
318 if(trailerRect.intersects(thumbRect)) {
319 paintThumb(g);
320 }
321 }
322
323
324
325
326
327 public void paintTicks(Graphics g)
328 {
329 final Rectangle tr = tickRect;
330 final Rectangle lr = labelRect;
331 int w = tr.width - 1;
332
333 g.setColor(slider.getBackground());
334 g.fillRect(tr.x, tr.y, tr.width, tr.height);
335
336 final Tick[] ticks = rangedValue.calculateTicks(w,new TickMeasurer(g, format));
337
338 if(ticks == null) {
339 return;
340 }
341
342 g.translate(tr.x, tr.y-2);
343
344 final FontMetrics fm = g.getFontMetrics();
345 String text;
346 int left;
347 int x;
348 double tickValue;
349 for(int i = 0; i < ticks.length; i++) {
350 x = (int)(ticks[i].proportional * w);
351 if (showIntegerOnly) {
352 tickValue = ticks[i].absolute;
353 if(((long)(tickValue*1000L+0.5))/1000. != (long)(tickValue+0.5))
354 continue;
355
356
357
358
359 }
360
361 if(ticks[i].major) {
362 paintMajorTickForHorizSlider(g, tr, x);
363
364 text = ticks[i].text;
365 if(text==null) {
366 left = x;
367 } else {
368 left = x - (fm.stringWidth(text) / 2);
369 }
370
371
372 g.setColor(slider.getForeground());
373 if(text!=null) {
374 g.drawString(text, left, lr.y - 8);
375 }
376 } else {
377 paintMinorTickForHorizSlider(g, tr, x);
378 }
379 }
380
381 g.translate(-tr.x, -tr.y+2);
382 }
383
384
385
386
387
388 public void paintLabels(Graphics g)
389 {
390 paintTicks(g);
391 }
392
393
394
395
396
397 protected void scrollDueToClickInTrack(int dir)
398 {
399
400
401 }
402
403
404
405
406
407
408 public void setFormat(String format) {
409 this.format = format;
410 if (format.contains("%d")) {
411 showIntegerOnly = true;
412 } else {
413 showIntegerOnly = false;
414 }
415 }
416
417
418
419
420
421
422
423 public void setTolerance(double tol) {
424 this.tolerance=tol;
425 }
426
427
428
429
430
431
432 public double getTolerance() {
433 return this.tolerance;
434 }
435
436
437
438
439
440 public void setPaintTrailer(boolean paint) {
441 this.paintTrailer = paint;
442 slider.repaint();
443 }
444
445
446
447
448
449 public boolean isPaintTrailer() {
450 return this.paintTrailer;
451 }
452
453
454
455
456
457 public String getFormat() {
458 return format;
459 }
460 }
461