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;
21
22 import java.awt.AlphaComposite;
23 import java.awt.Color;
24 import java.awt.Dimension;
25 import java.awt.Font;
26 import java.awt.GradientPaint;
27 import java.awt.Graphics;
28 import java.awt.Graphics2D;
29 import java.awt.GridLayout;
30 import java.awt.Rectangle;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ComponentAdapter;
33 import java.awt.event.ComponentEvent;
34 import java.awt.event.WindowAdapter;
35 import java.awt.event.WindowEvent;
36 import java.awt.image.BufferedImage;
37 import java.beans.Beans;
38 import java.util.Timer;
39 import java.util.TimerTask;
40 import javax.swing.AbstractAction;
41 import javax.swing.JComponent;
42 import javax.swing.JPanel;
43 import com.cosylab.application.state.State;
44 import com.cosylab.application.state.StateFactory;
45 import com.cosylab.application.state.StateOriginator;
46 import com.cosylab.gui.components.customizer.AbstractCustomizerPanel;
47 import com.cosylab.gui.components.range2.RangedValueController;
48 import com.cosylab.gui.components.range2.LinearRange;
49 import com.cosylab.gui.components.range2.LogarithmicRange;
50 import com.cosylab.gui.components.range2.RangedValueEvent;
51 import com.cosylab.gui.components.range2.RangedValueListener;
52 import com.cosylab.gui.components.range2.RangedValuePolicy;
53 import com.cosylab.gui.components.range2.Tick;
54 import com.cosylab.gui.components.range2.TickParameters;
55 import com.cosylab.gui.components.range2.TrimValuePolicy;
56 import com.cosylab.gui.components.util.ActionList;
57 import com.cosylab.gui.components.util.ColorHelper;
58 import com.cosylab.gui.components.util.FontHelper;
59 import com.cosylab.gui.components.util.PaintHelper;
60 import com.cosylab.gui.components.util.PopupManageable;
61 import com.cosylab.gui.components.util.PopupManager;
62 import com.cosylab.gui.components.util.ScreenCapturer;
63 import com.cosylab.util.PrintfFormat;
64
65
66
67
68
69
70
71
72
73
74 public class Piper extends JComponent implements PopupManageable,
75 StateOriginator
76 {
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public enum LayoutOrientation {
91 BOTTOM_UP, LEFT_RIGHT, TOP_DOWN, RIGHT_LEFT
92 }
93
94 private static final long serialVersionUID = 1L;
95
96
97
98
99
100
101
102 protected class TiltHandler extends Timer
103 {
104 private class TiltTask extends TimerTask
105 {
106
107
108
109 public void run()
110 {
111 if (numberOfTilts >= MAX_NUMBER_OF_TILTS) {
112 cancel();
113 tilting = false;
114 } else {
115 numberOfTilts++;
116 tilting = !tilting;
117 }
118
119 renderer.clearBuffer();
120 repaint();
121 }
122 }
123
124 private final int MAX_NUMBER_OF_TILTS = 3;
125 private final long TILT_RATE = 200;
126 private int numberOfTilts = MAX_NUMBER_OF_TILTS;
127
128
129
130
131
132 public void tilt()
133 {
134 if (numberOfTilts >= MAX_NUMBER_OF_TILTS) {
135 numberOfTilts = 0;
136 schedule(new TiltTask(), 0, TILT_RATE);
137 } else {
138 numberOfTilts = 0;
139 }
140 }
141 }
142
143 private class PiperRenderer implements TickParameters
144 {
145 private Graphics2D g;
146 private Rectangle pipeRect;
147 private Rectangle pipeRectOrg;
148 private int arcRadius;
149 private BufferedImage pipeImage;
150 private BufferedImage scaleImage;
151 private BufferedImage tickImage;
152 private final Color DARK_COLOR = new Color(0, 0, 10);
153 private final Color LIGHT_COLOR = new Color(50, 150, 250);
154 private final Color OUT_OF_BOUNDS_DARK_COLOR = new Color(250, 120, 10);
155 private final Color OUT_OF_BOUNDS_LIGHT_COLOR = new Color(250, 250, 50);
156 private Color darkColor;
157 private Color ligtColor;
158 private Color outOfBoundsDarkColor;
159 private Color outOfBoundsLightColor;
160 private Tick[] ticks;
161
162 public PiperRenderer() {
163 darkColor = DARK_COLOR;
164 ligtColor = LIGHT_COLOR;
165 outOfBoundsDarkColor = OUT_OF_BOUNDS_DARK_COLOR;
166 outOfBoundsLightColor = OUT_OF_BOUNDS_LIGHT_COLOR;
167 }
168
169 private int getPiperWidth() {
170 if (orientation == LayoutOrientation.BOTTOM_UP || orientation == LayoutOrientation.TOP_DOWN) {
171 return getWidth();
172 } else if (orientation == LayoutOrientation.LEFT_RIGHT || orientation == LayoutOrientation.RIGHT_LEFT) {
173 return getHeight();
174 }
175 return 0;
176 }
177
178 private int getPiperHeight() {
179 if (orientation == LayoutOrientation.BOTTOM_UP || orientation == LayoutOrientation.TOP_DOWN) {
180 return getHeight();
181 } else if (orientation == LayoutOrientation.LEFT_RIGHT || orientation == LayoutOrientation.RIGHT_LEFT) {
182 return getWidth();
183 }
184 return 0;
185 }
186
187 private int transformXToOrientation(int x, int piperWidth) {
188 if (orientation == LayoutOrientation.TOP_DOWN) {
189 return getWidth() - x - piperWidth;
190 } else if (orientation == LayoutOrientation.RIGHT_LEFT) {
191 return getHeight() - x - piperWidth;
192 } else {
193 return x;
194 }
195 }
196
197
198
199
200 public void clearBuffer() {
201 synchronized (renderer) {
202 pipeImage = null;
203 scaleImage = null;
204 tickImage = null;
205 pipeRect = null;
206 pipeRectOrg = null;
207 ticks = null;
208 arcRadius = 0;
209 }
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223 public int measureTick(double position, String text)
224 {
225 if (orientation == LayoutOrientation.BOTTOM_UP || orientation == LayoutOrientation.TOP_DOWN) {
226 return g.getFontMetrics().getHeight();
227 } else {
228 return g.getFontMetrics().stringWidth(text);
229 }
230 }
231
232
233
234
235
236
237
238 public void paintFill(Graphics2D g)
239 {
240
241
242
243
244 int fillHeight = Math.max(1,
245 (int)Math.round(
246 rangedValue.getRelativeValue() * (pipeRect.height
247 - 2 * arcRadius)));
248 int fillWidth = pipeRect.width;
249
250 BufferedImage fillImage = new BufferedImage(fillWidth,
251 fillHeight + arcRadius, BufferedImage.TYPE_4BYTE_ABGR);
252 Graphics2D g2D = (Graphics2D)fillImage.getGraphics();
253 prepareGraphics(g2D);
254
255 boolean checkValue = (getValue() >= getMinimum()
256 && getValue() <= getMaximum());
257
258 Color lightColor = (checkValue ? this.ligtColor
259 : outOfBoundsLightColor);
260 Color darkColor = (checkValue ? this.darkColor : outOfBoundsDarkColor);
261
262 if (enhanced) {
263 g2D.setPaint(new GradientPaint(0.f, 0.f, lightColor,
264 fillWidth, fillHeight, darkColor));
265 } else {
266 g2D.setColor(lightColor);
267 }
268
269 g2D.fillRect(0, 0, fillWidth, fillHeight);
270 g2D.fillArc(0, fillHeight - arcRadius, 2 * arcRadius,
271 2 * arcRadius, 180, 270);
272 g2D.fillArc(fillWidth - 2 * arcRadius, fillHeight - arcRadius,
273 2 * arcRadius, 2 * arcRadius, 270, 360);
274
275 if (arcRadius < fillWidth) {
276 g2D.fillRect(arcRadius, fillHeight, fillWidth - 2 * arcRadius,
277 arcRadius);
278 }
279
280 if (enhanced) {
281 g.setComposite(AlphaComposite.getInstance(
282 AlphaComposite.SRC_OVER, 0.5f));
283 }
284
285 g.drawImage(fillImage, null, pipeRect.x,
286 pipeRect.y + pipeRect.height - arcRadius - fillHeight);
287
288
289 if (enhanced) {
290 g.setComposite(AlphaComposite.getInstance(
291 AlphaComposite.SRC_OVER, 1.f));
292 }
293 }
294
295
296
297
298
299
300
301 public void paintLabel(Graphics2D g)
302 {
303
304
305 String unitText = units;
306
307 if (units == null && Beans.isDesignTime()) {
308 unitText = "<u>";
309 }
310
311 if (unitText == null || !unitsVisible) {
312 unitText = "";
313 }
314
315 String text;
316
317 try {
318
319 text = this.formatNumber(labelValue);
320 } catch (Exception e) {
321 text = Double.toString(labelValue);
322 }
323
324 text += (units == null ? "" : " " + unitText);
325
326 int textWidth = g.getFontMetrics().stringWidth(text);
327 int textHeight = g.getFontMetrics().getAscent();
328
329
330 textHeight = (int)(textHeight * 0.7) + 1;
331 int botLeftX;
332 int botLeftY;
333
334 if (orientation == LayoutOrientation.LEFT_RIGHT || orientation == LayoutOrientation.RIGHT_LEFT) {
335 botLeftX = pipeRectOrg.y + (pipeRectOrg.height - textWidth) / 2;
336 botLeftY = getHeight() - (getHeight() - (pipeRectOrg.x + pipeRectOrg.width))/2 + textHeight;
337 } else {
338 botLeftX = pipeRectOrg.x + (pipeRectOrg.width - textWidth) / 2;
339 botLeftY = pipeRectOrg.y + pipeRectOrg.height + (textHeight + pipeRectOrg.y) / 2;
340 if (orientation == LayoutOrientation.BOTTOM_UP) {
341 if (!titleVisible) {
342 botLeftY += g.getFontMetrics().getHeight()/2;
343 }
344 } else {
345 if (!titleVisible) {
346 botLeftY -= g.getFontMetrics().getHeight();
347 }
348 }
349 }
350
351
352
353 g.setColor((isEnabled() ? Color.BLACK : Color.GRAY));
354 g.drawString(text, botLeftX, botLeftY);
355 }
356
357
358
359
360
361
362
363 public void paintPipe(Graphics2D g)
364 {
365
366
367 if (pipeImage == null) {
368
369 pipeImage = new BufferedImage(pipeRect.width, pipeRect.height,
370 BufferedImage.TYPE_4BYTE_ABGR);
371
372 Graphics2D g2D = (Graphics2D)pipeImage.getGraphics();
373 prepareGraphics(g2D);
374 g2D.setColor((tilting ? ColorHelper.getAlarm() : Color.WHITE));
375 g2D.fillRoundRect(0, 0, pipeRect.width, pipeRect.height,
376 2 * arcRadius, 2 * arcRadius);
377 }
378
379 g.drawImage(pipeImage, null, pipeRect.x, pipeRect.y);
380 }
381
382 private Dimension getTickDim(Graphics g, int pipeHeigth)
383 {
384 Tick[] tcks = getTicks(pipeHeigth);
385 int tckW = 0;
386 int maxLen = 0;
387
388 for (int i = 0; i < tcks.length; i++) {
389 if (tcks[i] != null && tcks[i].text != null
390 && tcks[i].text.length() > maxLen) {
391 int newW = g.getFontMetrics().stringWidth(tcks[i].text);
392 tckW = Math.max(tckW, newW);
393 }
394 }
395
396 return new Dimension(tckW, g.getFontMetrics().getHeight());
397 }
398
399 private void setPipeRect(Graphics2D g)
400 {
401 if (pipeRect == null) {
402
403 this.g=g;
404
405 int compW = getPiperWidth();
406 int compH = getPiperHeight();
407 int x;
408 int y;
409 int w;
410 int h;
411
412 y = Math.max(1, (int)(6 * Math.atan(compH / 100)));
413 if (orientation == LayoutOrientation.TOP_DOWN) {
414 if (titleVisible) {
415 y += g.getFontMetrics().getHeight();
416 h = Math.max(1, compH - 2 * y);
417 } else {
418 y += g.getFontMetrics().getHeight();
419 h = Math.max(1, compH - 2 * y + g.getFontMetrics().getHeight());
420 }
421 } else if (orientation == LayoutOrientation.BOTTOM_UP) {
422 if (titleVisible) {
423 y += g.getFontMetrics().getHeight();
424 h = Math.max(1, compH - 2 * y);
425 } else {
426 h = Math.max(1, compH - 2 * y - g.getFontMetrics().getHeight());
427 }
428
429 } else {
430 h = Math.max(1, compH - 2 * y);
431 }
432
433 Dimension tickDim = getTickDim(g, h);
434
435 if (stretch) {
436 x = 10;
437 w = Math.max(1, compW - tickDim.width * 3 / 2 - 2 * x);
438 } else {
439 x = compW * 1 / 5;
440
441 if (10 + tickDim.width > x) {
442 x = (2 * x - 10 - tickDim.width) / 2 + 5;
443 w = Math.max(1, compW - x - 10 - tickDim.width);
444 } else {
445 w = Math.max(1, compW - 2 * x);
446 }
447 }
448
449 pipeRect = new Rectangle(transformXToOrientation(x,w), y, w, h);
450 pipeRectOrg = new Rectangle(x, y, w, h);
451 g=null;
452
453 setArcRadius(pipeRect);
454 }
455 }
456
457 private void setArcRadius(Rectangle pipeRect)
458 {
459 double ratio = pipeRect.height / (double)pipeRect.width;
460
461 if (ratio > 5) {
462 arcRadius = pipeRect.width / 2;
463 } else {
464 arcRadius = (int)Math.max(ratio / 5 * pipeRect.width / 2, 2);
465 }
466 }
467
468
469
470
471
472
473
474 public void paintScale(Graphics2D g)
475 {
476 g.drawImage(getScaleImage(), null, 0, 0);
477 }
478
479 public void paintTickLabels(Graphics2D g) {
480
481 g.drawImage(getTickImage(), null, 0, 0);
482 }
483
484
485
486
487
488
489 public void paintTitle(Graphics2D g)
490 {
491
492
493 String text = title;
494
495 if (title == null && Beans.isDesignTime()) {
496 text = "<title>";
497 }
498
499 if (text == null || text.length() == 0) {
500 return;
501 }
502
503 int textWidth = g.getFontMetrics().stringWidth(text);
504 int textHeight = g.getFontMetrics().getAscent();
505
506
507 textHeight = (int)(textHeight * 0.7) + 1;
508 int botLeftX;
509 int botLeftY;
510
511 if (orientation == LayoutOrientation.LEFT_RIGHT || orientation == LayoutOrientation.RIGHT_LEFT) {
512 botLeftX = pipeRect.y + (pipeRect.height - textWidth) / 2;
513 botLeftY = (textHeight + pipeRectOrg.x) / 2;
514 } else {
515 botLeftX = pipeRectOrg.x + (pipeRectOrg.width - textWidth) / 2;
516 botLeftY = (textHeight + pipeRectOrg.y) / 2;
517 }
518
519
520 g.setColor((isEnabled() ? Color.BLACK : Color.GRAY));
521
522
523 g.drawString(text, botLeftX, botLeftY);
524 }
525
526 protected void prepareGraphics(Graphics2D g)
527 {
528 Font f = FontHelper.getDefaultFont();
529
530 if (resizable) {
531 int fontHeight = 5 + Math.min(getWidth(), getHeight() / 2) / 15;
532 if (orientation == LayoutOrientation.LEFT_RIGHT || orientation == LayoutOrientation.RIGHT_LEFT) {
533 f = FontHelper.getFontWithSize((int)(fontHeight*1.5), f);
534 } else {
535 f = FontHelper.getFontWithSize((int)(fontHeight*1.2), f);
536 }
537
538 }
539
540 g.setFont(f);
541
542 if (enhanced) {
543 g.addRenderingHints(PaintHelper.getAntialiasingHints());
544 }
545 }
546
547 private BufferedImage getScaleImage()
548 {
549 if (scaleImage == null) {
550
551 int width = getPiperWidth();
552 int height = getPiperHeight();
553
554 scaleImage = new BufferedImage(width, height,
555 BufferedImage.TYPE_4BYTE_ABGR);
556
557 Graphics2D g2D = (Graphics2D)scaleImage.getGraphics();
558 prepareGraphics(g2D);
559 g2D.setColor((isEnabled() ? Color.BLACK : Color.GRAY));
560
561 Font oldFont = g2D.getFont();
562 g2D.setFont(oldFont.deriveFont(Font.PLAIN,
563 oldFont.getSize2D() * 0.8f));
564
565
566
567
568
569
570 int spaceWidth = width - pipeRect.x - pipeRect.width;
571
572 int scaleHeight = pipeRect.height - 2 * arcRadius;
573
574 int tickLength = Math.max(pipeRect.width * 3 / 4, 5);
575 int minorTickLength = tickLength / 2;
576
577 if (pipeRect.width > 200) {
578 tickLength = 150 + (pipeRect.width - 200) * 1 / 3;
579 minorTickLength = 75;
580 }
581
582
583 Dimension tickDim = getTickDim(g2D, pipeRect.height);
584 int offsetX = tickDim.height / 2;
585
586 if (2 * offsetX + tickDim.width > spaceWidth) {
587 offsetX = Math.max(1, (spaceWidth - tickDim.width) / 2);
588 }
589
590 Tick[] ticks = getTicks(scaleHeight);
591
592 if (ticks == null) {
593 return scaleImage;
594 }
595
596 for (int i = 0; i < ticks.length; i++) {
597 if (ticks[i].major) {
598 g2D.drawLine(pipeRect.x
599 + (pipeRect.width - tickLength) / 2,
600 pipeRect.y + arcRadius
601 + (int)(scaleHeight * (1. - ticks[i].proportional)),
602 pipeRect.x + (pipeRect.width + tickLength) / 2 - 1,
603 pipeRect.y + arcRadius
604 + (int)(scaleHeight * (1. - ticks[i].proportional)));
605 } else {
606 g2D.drawLine(pipeRect.x
607 + (pipeRect.width - minorTickLength) / 2,
608 pipeRect.y + arcRadius
609 + (int)(scaleHeight * (1. - ticks[i].proportional)),
610 pipeRect.x + (pipeRect.width + minorTickLength) / 2
611 - 1,
612 pipeRect.y + arcRadius
613 + (int)(scaleHeight * (1. - ticks[i].proportional)));
614 }
615 }
616 }
617
618 return scaleImage;
619 }
620
621 private BufferedImage getTickImage()
622 {
623 if (tickImage == null) {
624 int width;
625 int height;
626 if (orientation == LayoutOrientation.BOTTOM_UP || orientation == LayoutOrientation.TOP_DOWN) {
627 width = getPiperWidth();
628 height = getPiperHeight();
629 } else {
630 width = getPiperHeight();
631 height = getPiperWidth();
632 }
633
634 tickImage = new BufferedImage(width, height,
635 BufferedImage.TYPE_4BYTE_ABGR);
636
637 Graphics2D g2D = (Graphics2D)tickImage.getGraphics();
638 prepareGraphics(g2D);
639 g2D.setColor((isEnabled() ? Color.BLACK : Color.GRAY));
640
641 Font oldFont = g2D.getFont();
642 g2D.setFont(oldFont.deriveFont(Font.PLAIN,
643 oldFont.getSize2D() * 0.8f));
644
645 int spaceWidth = width - pipeRectOrg.x - pipeRectOrg.width;
646 int scaleHeight = pipeRect.height - 2 * arcRadius;
647
648 Dimension tickDim = getTickDim(g2D, pipeRectOrg.height);
649 int offsetX = tickDim.height / 2;
650
651 if (orientation == LayoutOrientation.TOP_DOWN || orientation == LayoutOrientation.BOTTOM_UP) {
652 if (2 * offsetX + tickDim.width > spaceWidth) {
653 offsetX = Math.max(1, (spaceWidth - tickDim.width) / 2);
654 }
655 }
656
657 Tick[] ticks = getTicks(scaleHeight);
658
659 if (ticks == null) {
660 return tickImage;
661 }
662
663 int textPosX = pipeRectOrg.x + pipeRectOrg.width + offsetX;
664
665 if (orientation == LayoutOrientation.TOP_DOWN) {
666 int y0 = pipeRectOrg.y;
667 if (!titleVisible) {
668 y0 -= g.getFontMetrics().getHeight();
669 }
670 for (int i = 0; i < ticks.length; i++) {
671 if (ticks[i].major) {
672 g2D.drawString(ticks[i].text,
673 textPosX,
674 pipeRectOrg.y + arcRadius
675 + (int)(scaleHeight * (ticks[i].proportional))
676 + 5);
677 }
678 }
679 } else if(orientation == LayoutOrientation.BOTTOM_UP) {
680 for (int i = 0; i < ticks.length; i++) {
681 if (ticks[i].major) {
682 g2D.drawString(ticks[i].text,
683 textPosX,
684 pipeRectOrg.y + arcRadius
685 + (int)(scaleHeight * (1-ticks[i].proportional))
686 + 5);
687 }
688 }
689 } else if (orientation == LayoutOrientation.LEFT_RIGHT){
690 for (int i = 0; i < ticks.length; i++) {
691 if (ticks[i].major && ticks[i].text != null && ticks[i].text.length() != 0) {
692 g2D.drawString(ticks[i].text,
693 pipeRectOrg.y + arcRadius
694 + (int)(scaleHeight * (ticks[i].proportional))
695 - tickDim.width/2, textPosX + 5);
696 }
697 }
698 } else if (orientation == LayoutOrientation.RIGHT_LEFT) {
699 for (int i = 0; i < ticks.length; i++) {
700 if (ticks[i].major) {
701 g2D.drawString(ticks[i].text,
702 pipeRectOrg.y + arcRadius
703 + (int)(scaleHeight * (1-ticks[i].proportional))
704 - tickDim.width/2, textPosX + 5);
705 }
706 }
707 }
708
709 }
710
711 return tickImage;
712 }
713
714 private Tick[] getTicks(int height)
715 {
716 if (ticks == null) {
717
718 ticks = rangedValue.calculateTicks(height,this);
719 }
720
721 return ticks;
722 }
723
724 public String formatNumber(double x) {
725 return formatter.sprintf(x);
726 }
727 }
728
729 private class ResizeListener extends ComponentAdapter
730 {
731
732
733
734
735
736
737
738 public void componentResized(ComponentEvent e)
739 {
740 Piper.this.setSize(getBounds().width, getBounds().height);
741 renderer.clearBuffer();
742 repaint();
743 }
744 }
745
746 private class ValueListener implements RangedValueListener
747 {
748
749
750
751
752
753
754
755 public void valueChanged(RangedValueEvent event)
756 {
757 if (event.isMinimumChanged() || event.isMaximumChanged()) {
758 renderer.clearBuffer();
759
760 if (!isEnabled()) {
761 return;
762 }
763 repaint();
764 }
765
766 if (event.isValueChanged()) {
767 if (!isEnabled()) {
768 return;
769 }
770 repaint();
771 }
772 }
773 }
774
775 private RangedValuePolicy policy;
776 private AbstractCustomizerPanel customizer;
777 private PiperRenderer renderer;
778 private PopupManager popupManager;
779 private PrintfFormat formatter;
780
781 private RangedValueController rangedValue;
782 private String format;
783 private String title;
784 private boolean titleVisible;
785 private int titleMinimumFontSize;
786 private int titleMaximumFontSize;
787 private String units;
788 private TiltHandler tiltHandler;
789 private boolean enhanced = true;
790 private boolean logarithmic;
791 private boolean popupEnabled;
792 private boolean resizable = true;
793 private boolean stretch = false;
794 private boolean tilting;
795 private boolean tiltingEnabled;
796 private double labelValue;
797 private boolean unitsVisible = true;
798
799 private LayoutOrientation orientation = LayoutOrientation.BOTTOM_UP;
800
801
802
803
804
805
806 public Piper(double newValue)
807 {
808 super();
809
810 renderer = new PiperRenderer();
811
812 format = "%3.2f";
813 formatter = new PrintfFormat(format);
814
815 policy = new TrimValuePolicy();
816
817 labelValue = newValue;
818
819 rangedValue = new RangedValueController();
820 rangedValue.setValue(0, 1, newValue);
821 rangedValue.setRange(new LinearRange());
822 rangedValue.addPolicy(policy);
823 rangedValue.addRangedValueListener(new ValueListener());
824
825 addComponentListener(new ResizeListener());
826
827 setBackground(ColorHelper.getCosyControl());
828 setPreferredSize(new Dimension(150, 300));
829 setMinimumSize(new Dimension(60, 100));
830 setVisible(true);
831 setOpaque(true);
832 setPopupEnabled(true);
833 }
834
835
836
837
838 public Piper()
839 {
840 this(0);
841 }
842
843
844
845
846
847
848 public AbstractCustomizerPanel getCustomizer()
849 {
850 if (customizer == null) {
851 customizer = AbstractCustomizerPanel.findCustomizer(this);
852 }
853
854 return customizer;
855 }
856
857
858
859
860
861
862
863
864 public void setEnhanced(boolean enhanced)
865 {
866 if (this.enhanced == enhanced) {
867 return;
868 }
869
870 boolean oldEnhanced = this.enhanced;
871 this.enhanced = enhanced;
872 renderer.clearBuffer();
873 repaint();
874 firePropertyChange("enhanced", oldEnhanced, enhanced);
875 }
876
877
878
879
880
881
882 public boolean isEnhanced()
883 {
884 return enhanced;
885 }
886
887
888
889
890
891
892 public void setFormat(String format)
893 {
894 String oldFormat = this.format;
895
896 if (format == null && oldFormat == null
897 || format != null && format.equals(oldFormat)) {
898 return;
899 }
900
901 this.format = format;
902 formatter = new PrintfFormat(format);
903 firePropertyChange("format", oldFormat, format);
904 renderer.clearBuffer();
905 if (!isEnabled()) {
906 return;
907 }
908
909 repaint();
910 }
911
912
913
914
915
916
917 public String getFormat()
918 {
919 return format;
920 }
921
922
923
924
925
926
927
928
929 public void setMaximum(double newMaximum)
930 {
931 double oldMaximum = rangedValue.getMaximum();
932
933
934
935
936 rangedValue.setValue(rangedValue.getMinimum(), newMaximum,
937 rangedValue.getValue());
938 firePropertyChange("maximum", oldMaximum, newMaximum);
939 }
940
941
942
943
944
945
946
947 public double getMaximum()
948 {
949 return rangedValue.getMaximum();
950 }
951
952
953
954
955
956
957
958
959 public void setMinimum(double newMinimum)
960 {
961 double oldMinimum = rangedValue.getMinimum();
962
963
964
965
966 rangedValue.setValue(newMinimum, rangedValue.getMaximum(),
967 rangedValue.getValue());
968 firePropertyChange("minimum", oldMinimum, newMinimum);
969 }
970
971
972
973
974
975
976
977 public double getMinimum()
978 {
979 return rangedValue.getMinimum();
980 }
981
982
983
984
985
986
987
988 public void setLogarithmic(boolean logScale)
989 {
990 if (logScale == logarithmic) {
991 return;
992 }
993
994 logarithmic = logScale;
995
996 if (logScale) {
997 rangedValue.setRange(new LogarithmicRange());
998 } else {
999 rangedValue.setRange(new LinearRange());
1000 }
1001
1002 firePropertyChange("logarithmic", !logScale, logScale);
1003 }
1004
1005
1006
1007
1008
1009
1010 public boolean isLogarithmic()
1011 {
1012 return logarithmic;
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023 public void setMaxMin(double newMax, double newMin)
1024 {
1025 double oldMaximum = rangedValue.getMaximum();
1026 double oldMinimum = rangedValue.getMinimum();
1027
1028 if (oldMaximum == newMax && oldMinimum == newMin) {
1029 return;
1030 }
1031
1032 rangedValue.setValue(newMin, newMax, rangedValue.getValue());
1033 firePropertyChange("maximum", oldMaximum, newMax);
1034 firePropertyChange("minimum", oldMinimum, newMin);
1035 }
1036
1037
1038
1039
1040
1041
1042 public void setPopupEnabled(boolean b)
1043 {
1044 if (popupEnabled == b) return;
1045 popupEnabled = b;
1046 if (b) {
1047 addMouseListener(getPopupManager().getMouseHook());
1048 } else {
1049 removeMouseListener(getPopupManager().getMouseHook());
1050 }
1051 firePropertyChange("popupEnabled", !b, b);
1052 }
1053
1054
1055
1056
1057
1058
1059
1060 public boolean isPopupEnabled()
1061 {
1062 return popupEnabled;
1063 }
1064
1065
1066
1067
1068
1069
1070
1071 public void setValue(double newValue)
1072 {
1073 double oldValue = rangedValue.getValue();
1074
1075 labelValue = newValue;
1076
1077
1078
1079
1080 rangedValue.setValue(newValue);
1081
1082 if ((newValue > rangedValue.getMaximum()
1083 || newValue < rangedValue.getMinimum()) && tiltingEnabled) {
1084 getTiltHandler().tilt();
1085 }
1086
1087 firePropertyChange("value", oldValue, newValue);
1088 }
1089
1090
1091
1092
1093
1094
1095 public double getValue()
1096 {
1097 return labelValue;
1098 }
1099
1100
1101
1102
1103
1104
1105 public static void main(String[] args)
1106 {
1107 Thread t = new Thread() {
1108 public void run()
1109 {
1110 javax.swing.JFrame frame = new javax.swing.JFrame();
1111 frame.addWindowListener(new WindowAdapter() {
1112 public void windowClosing(WindowEvent e)
1113 {
1114 System.exit(0);
1115 }
1116 });
1117
1118 JPanel panel = new JPanel();
1119 frame.setContentPane(panel);
1120 frame.setSize(new java.awt.Dimension(100, 220));
1121
1122 Piper sp = new Piper();
1123 sp.setEnhanced(true);
1124 sp.setPopupEnabled(true);
1125
1126 sp.setMinimum(-10.0);
1127 sp.setMaximum(20.0);
1128 sp.setValue(10.0);
1129 sp.setTitle("NASLOV");
1130 sp.setTitleVisible(false);
1131 sp.setLayoutOrientation(LayoutOrientation.LEFT_RIGHT);
1132 panel.setLayout(new GridLayout());
1133 panel.add(sp);
1134
1135 frame.setVisible(true);
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162 }
1163 };
1164
1165 t.run();
1166 }
1167
1168
1169
1170
1171
1172
1173 public void setEnabled(boolean enabled)
1174 {
1175 super.setEnabled(enabled);
1176
1177 renderer.clearBuffer();
1178 repaint();
1179 }
1180
1181
1182
1183
1184
1185
1186 public PopupManager getPopupManager()
1187 {
1188 if (popupManager == null) {
1189 popupManager = new PopupManager(this, false);
1190 popupManager.addAction(new AbstractAction("Preferences...") {
1191 private static final long serialVersionUID = 1L;
1192
1193 public void actionPerformed(ActionEvent e)
1194 {
1195 getCustomizer().showDialog();
1196 }
1197 });
1198
1199
1200
1201 ActionList al=new ActionList("Capture screen");
1202
1203 al.addAction(new AbstractAction("To file...") {
1204 private static final long serialVersionUID = 1L;
1205
1206 public void actionPerformed(ActionEvent e)
1207 {
1208 ScreenCapturer sc = new ScreenCapturer(Piper.this);
1209 sc.showScreenDialog();
1210 }
1211 });
1212
1213
1214
1215
1216
1217
1218
1219 popupManager.addAction(al);
1220
1221 }
1222
1223 return popupManager;
1224 }
1225
1226
1227
1228
1229
1230
1231
1232
1233 public void setResizable(boolean b)
1234 {
1235 if (b == resizable) {
1236 return;
1237 }
1238 boolean oldResizable = resizable;
1239
1240 resizable = b;
1241
1242 firePropertyChange("resizable", oldResizable, resizable);
1243 renderer.clearBuffer();
1244
1245 if (!isEnabled()) {
1246 return;
1247 }
1248
1249 repaint();
1250 }
1251
1252
1253
1254
1255
1256
1257 public boolean isResizable()
1258 {
1259 return resizable;
1260 }
1261
1262
1263
1264
1265
1266
1267
1268
1269 public void setState(State state)
1270 {
1271 setFormat(state.getString("format", getFormat()));
1272 setMaximum(state.getDouble("maximum", getMaximum()));
1273 setMinimum(state.getDouble("minimum", getMinimum()));
1274 setTitle(state.getString("title", getTitle()));
1275 setUnits(state.getString("units", getUnits()));
1276 setLogarithmic(state.getBoolean("logarithmic", isLogarithmic()));
1277 setStretch(state.getBoolean("stretch", isStretch()));
1278 setEnhanced(state.getBoolean("enhanced", isEnhanced()));
1279 setResizable(state.getBoolean("resizable", isResizable()));
1280 setPopupEnabled(state.getBoolean("popupEnabled", isPopupEnabled()));
1281 setTiltingEnabled(state.getBoolean("tiltingEnabled", isTiltingEnabled()));
1282 }
1283
1284
1285
1286
1287
1288
1289
1290
1291 public State getState()
1292 {
1293 State state = StateFactory.createState();
1294
1295 state.putString("format", getFormat());
1296 state.putDouble("graphMax", getMaximum());
1297 state.putDouble("graphMin", getMinimum());
1298 state.putString("title", getTitle());
1299 state.putString("units", getUnits());
1300 state.putBoolean("logarithmic", isLogarithmic());
1301 state.putBoolean("stretch", isStretch());
1302 state.putBoolean("enhanced", isEnhanced());
1303 state.putBoolean("resizable", isResizable());
1304 state.putBoolean("popupEnabled", isPopupEnabled());
1305 state.putBoolean("tiltingEnabled", isTiltingEnabled());
1306
1307 return state;
1308 }
1309
1310
1311
1312
1313
1314
1315
1316 public void setStretch(boolean b)
1317 {
1318 if (b == stretch) {
1319 return;
1320 }
1321
1322 boolean oldStretch = stretch;
1323 stretch = b;
1324 renderer.clearBuffer();
1325 firePropertyChange("stretch", oldStretch, stretch);
1326
1327 if (!isEnabled()) {
1328 return;
1329 }
1330 repaint();
1331 }
1332
1333
1334
1335
1336
1337
1338
1339 public boolean isStretch()
1340 {
1341 return stretch;
1342 }
1343
1344
1345
1346
1347
1348
1349 public void setTiltingEnabled(boolean b)
1350 {
1351 if (tiltingEnabled == b) {
1352 return;
1353 }
1354
1355 tiltingEnabled = b;
1356 firePropertyChange("tiltingEnabled", !b, b);
1357 }
1358
1359
1360
1361
1362
1363
1364
1365 public boolean isTiltingEnabled()
1366 {
1367 return tiltingEnabled;
1368 }
1369
1370
1371
1372
1373
1374
1375
1376 public void setTitle(String string)
1377 {
1378 if (string == null && title == null
1379 || string != null && string.equals(title)) {
1380 return;
1381 }
1382
1383 String oldTitle = title;
1384
1385 title = string;
1386 firePropertyChange("title", oldTitle, title);
1387
1388 if (!isEnabled()) {
1389 return;
1390 }
1391
1392 repaint();
1393 }
1394
1395
1396
1397
1398
1399
1400 public String getTitle()
1401 {
1402 return title;
1403 }
1404
1405
1406
1407
1408
1409
1410
1411 public void setUnits(String units)
1412 {
1413 if (this.units == null && units == null
1414 || units != null && units.equals(this.units)) {
1415 return;
1416 }
1417
1418 String oldUnits = this.units;
1419 this.units = units;
1420 firePropertyChange("units", oldUnits, units);
1421
1422 if (!isEnabled()) {
1423 return;
1424 }
1425 repaint();
1426 }
1427
1428
1429
1430
1431
1432
1433
1434 public String getUnits()
1435 {
1436 return units;
1437 }
1438
1439
1440
1441
1442
1443
1444 protected RangedValueController getRangedValue()
1445 {
1446 return rangedValue;
1447 }
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457 public void setLayoutOrientation(LayoutOrientation orientation) {
1458 if (this.orientation == orientation) return;
1459 LayoutOrientation oldValue = this.orientation;
1460 this.orientation = orientation;
1461 firePropertyChange("layoutOrientation", oldValue, orientation);
1462 repaint();
1463 }
1464
1465
1466
1467
1468
1469
1470 public LayoutOrientation getLayoutOrientation() {
1471 return orientation;
1472 }
1473
1474 private double getAngle() {
1475 if (orientation == LayoutOrientation.BOTTOM_UP) {
1476 return 0;
1477 } else if (orientation == LayoutOrientation.LEFT_RIGHT) {
1478 return Math.PI/2;
1479 } else if (orientation == LayoutOrientation.TOP_DOWN) {
1480 return Math.PI;
1481 } else if (orientation == LayoutOrientation.RIGHT_LEFT) {
1482 return 3*Math.PI/2;
1483 }
1484 return 0;
1485 }
1486
1487 private double getHorizontalShift() {
1488 if (orientation == LayoutOrientation.BOTTOM_UP || orientation == LayoutOrientation.RIGHT_LEFT) {
1489 return 0;
1490 } else {
1491 return getWidth();
1492 }
1493 }
1494
1495 private double getVerticalShift() {
1496 if (orientation == LayoutOrientation.BOTTOM_UP || orientation == LayoutOrientation.LEFT_RIGHT) {
1497 return 0;
1498 } else {
1499 return getHeight();
1500 }
1501 }
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 protected void paintComponent(Graphics g)
1512 {
1513 if (isOpaque()) {
1514 g.setColor(getBackground());
1515 g.fillRect(0, 0, getWidth(), getHeight());
1516 }
1517
1518 ((Graphics2D)g).translate(getHorizontalShift(),getVerticalShift());
1519 ((Graphics2D)g).rotate(getAngle());
1520
1521 Graphics2D g2D = (Graphics2D)g;
1522 g2D.setBackground(getBackground());
1523 synchronized (renderer) {
1524
1525
1526 renderer.prepareGraphics(g2D);
1527 renderer.setPipeRect(g2D);
1528 renderer.paintPipe(g2D);
1529 renderer.paintFill(g2D);
1530 renderer.paintScale(g2D);
1531
1532 ((Graphics2D)g).rotate(-getAngle());
1533 ((Graphics2D)g).translate(-getHorizontalShift(),-getVerticalShift());
1534 renderer.paintTickLabels(g2D);
1535 renderer.paintLabel(g2D);
1536 if (titleVisible)
1537 renderer.paintTitle(g2D);
1538 }
1539
1540
1541
1542 }
1543
1544
1545
1546
1547
1548
1549 private TiltHandler getTiltHandler()
1550 {
1551 if (tiltHandler == null) {
1552 tiltHandler = new TiltHandler();
1553 }
1554
1555 return tiltHandler;
1556 }
1557
1558
1559
1560
1561
1562
1563 public void setValuePolicy(RangedValuePolicy p)
1564 {
1565 rangedValue.removePolicy(policy);
1566 this.policy = p;
1567 rangedValue.addPolicy(p);
1568 }
1569
1570
1571
1572
1573
1574
1575 public RangedValuePolicy getValuePolicy()
1576 {
1577 return policy;
1578 }
1579
1580
1581
1582
1583
1584
1585 public boolean isUnitsVisible()
1586 {
1587 return unitsVisible;
1588 }
1589
1590
1591
1592
1593
1594
1595 public void setUnitsVisible(boolean b)
1596 {
1597 if (unitsVisible == b) {
1598 return;
1599 }
1600
1601 boolean oldB = unitsVisible;
1602 unitsVisible = b;
1603 firePropertyChange("unitsVisible", oldB, b);
1604 renderer.clearBuffer();
1605 repaint();
1606 }
1607
1608 public boolean isTitleVisible() {
1609 return titleVisible;
1610 }
1611
1612 public void setTitleVisible(boolean titleVisible) {
1613 if (this.titleVisible == titleVisible) {
1614 return;
1615 }
1616
1617 this.titleVisible = titleVisible;
1618 firePropertyChange("titleVisible", !titleVisible, titleVisible);
1619 repaint();
1620 }
1621
1622 public int getTitleMaximumFontSize() {
1623 return titleMaximumFontSize;
1624 }
1625
1626 public void setTitleMaximumFontSize(int titleMaximumFontSize) {
1627
1628 if (this.titleMaximumFontSize == titleMaximumFontSize) return;
1629 int i = this.titleMaximumFontSize;
1630 this.titleMaximumFontSize = titleMaximumFontSize;
1631 firePropertyChange("titleMaximumFontSize", i, titleMaximumFontSize);
1632 }
1633
1634 public int getTitleMinimumFontSize() {
1635 return titleMinimumFontSize;
1636 }
1637
1638 public void setTitleMinimumFontSize(int titleMinimumFontSize) {
1639 if (this.titleMinimumFontSize == titleMinimumFontSize) return;
1640 int i = this.titleMinimumFontSize;
1641 this.titleMinimumFontSize = titleMinimumFontSize;
1642 firePropertyChange("titleMinimumFontSize", i, titleMinimumFontSize);
1643 }
1644
1645
1646
1647
1648
1649
1650 public void setLightWaterColor(Color color) {
1651 Color old = renderer.ligtColor;
1652 renderer.ligtColor = color;
1653 firePropertyChange("lightWaterColor", old, color);
1654 }
1655
1656
1657
1658
1659
1660
1661 public void setDarkWaterColor(Color color) {
1662 Color old = renderer.darkColor;
1663 renderer.darkColor = color;
1664 firePropertyChange("darkWaterColor", old, color);
1665 }
1666
1667
1668
1669
1670
1671
1672 public void setOutOfBoundsLightWaterColor(Color color) {
1673 Color old = renderer.outOfBoundsLightColor;
1674 renderer.outOfBoundsLightColor = color;
1675 firePropertyChange("outOfBoundsLightWaterColor", old, color);
1676 }
1677
1678
1679
1680
1681
1682
1683 public void setOutOfBoundsDarkWaterColor(Color color) {
1684 Color old = renderer.outOfBoundsDarkColor;
1685 renderer.outOfBoundsDarkColor = color;
1686 firePropertyChange("outOfBoundsDarkWaterColor", old, color);
1687 }
1688
1689
1690
1691
1692 public Color getLightWaterColor() {
1693 return renderer.ligtColor;
1694 }
1695
1696
1697
1698
1699 public Color getDarkWaterColor() {
1700 return renderer.darkColor;
1701 }
1702
1703
1704
1705
1706 public Color getOutOfBoundsLightWaterColor() {
1707 return renderer.outOfBoundsLightColor;
1708 }
1709
1710
1711
1712
1713 public Color getOutOfBoundsDarkWaterColor() {
1714 return renderer.outOfBoundsDarkColor;
1715 }
1716 }
1717
1718