001 /*
002 * Copyright (c) Holger Pfaff - http://pfaff.ws
003 *
004 * This software maybe used for any purpose provided the
005 * above copyright notice is retained. It is supplied as is.
006 * No warranty expressed or implied - Use at your own risk.
007 */
008
009 import java.awt.*;
010 import java.awt.event.*;
011 import java.util.*;
012 import java.io.*;
013 import java.net.*;
014 import java.applet.*;
015
016 /**
017 * (#)Awt.java
018 * @author Holger Pfaff
019 * @version 3.2 19-Mar-2004<br><br>
020 *
021 * Implements some useful (static) AWT routines and acts as baseclass
022 * for several gui items
023 * <br>
024 * Overview of mode bits used in this class:
025 * <pre>
026 * misc effect position
027 * 0 0 0 0 0 0 0 0 0 0 0 0
028 * - - H F U B S R W S E N
029 * r i l u u a e o a o
030 * e l i l n i s u s r
031 * f l n k k s t t t t
032 * e e e h h
033 * n d
034 * </pre>
035 * This class also implements a simple text formating mechanism. Unicode
036 * escape sequences can be used to change fonts alignment, color etc. The
037 * syntax is pretty easy. A formatting directive is always constructed
038 * from <unicode esc> + <unicode format info>. The prefix for setting the
039 * font to serif and the color to white woud be Esc + Serif + Esc + White.<br>
040 * A summary of all attributes:<br>
041 * <pre>
042 * Font Family FFnn
043 * Serif FF00
044 * SansSerif FF01
045 * Monospaced FF02
046 * <br>
047 * Font style FBnn
048 * Plain FB00
049 * Bold FB01
050 * Italic FB02
051 * Bolditalic FB03
052 *
053 * Font Size rel. F0nn
054 * Smaller F000 two pixel smaller
055 * Larger F001 two pixel larger
056 *
057 * Font Size Absolut F5nn nn = size in pixel (hex)
058 *
059 * Text Alignment A00n
060 * North A001
061 * East A002
062 * South A004
063 * West A008
064 * NorthWest A009
065 * SouthWest A00C
066 * NorthEast A003
067 * SouthEast A00A
068 * Center A00F
069 *
070 * Text Tabs Dnnn Left tabs only nnn = no of char to tab
071 * Tab0 D000
072 *
073 * Effects Ennn
074 * Flat E000 default effect
075 * Raised E001 makes objects looking raised
076 * Sunken E002 makes objects looking sunken
077 * Bulk E003 actually a drawing mode @see setBorderType()
078 * Uline E004 underline
079 * Href E0D1 start of a href
080 * Hrefend E0D0 end of a href
081 * Darker E0C1 make foreground color darker
082 * Brighter E0C2 make foreground color brighter
083 * Background E0C3 make foreground equal to current backgroundcolor
084 *
085 * Colors Cnnn nnn = rgb - eight bits per color
086 * White C000
087 * Black CFFF
088 * </pre>
089 *
090 */
091
092 public class Awt extends Panel implements MouseListener, MouseMotionListener, KeyListener, AdjustmentListener, FocusListener, ItemSelectable {
093
094 /**
095 * One special mode
096 */
097 public final static int NONE = 0;
098
099 /**
100 * positions / directions mask - the lowest 4 bits 0-3
101 */
102 public final static int POSITION_MASK = 0xF;
103
104 /**
105 * North position
106 */
107 public final static int N = 0x1 << 0;
108
109 /**
110 * East position
111 */
112 public final static int E = 0x1 << 1;
113
114 /**
115 * South position
116 */
117 public final static int S = 0x1 << 2;
118
119 /**
120 * West position
121 */
122 public final static int W = 0x1 << 3;
123
124 /**
125 * NorthWest position
126 */
127 public final static int NW = N|W;
128
129 /**
130 * SouthWest position
131 */
132 public final static int SW = S|W;
133
134 /**
135 * NorthEast position
136 */
137 public final static int NE = N|E;
138
139 /**
140 * SouthEast position
141 */
142 public final static int SE = S|E;
143
144 /**
145 * Center position
146 */
147 public final static int C = N|E|S|W;
148
149 /**
150 * Center position
151 */
152 public final static int CENTER = C;
153
154 /**
155 * Top position
156 */
157 public final static int TOP = N;
158
159 /**
160 * Right position
161 */
162 public final static int RIGHT = E;
163
164 /**
165 * Bottom position
166 */
167 public final static int BOTTOM = S;
168
169 /**
170 * Left position
171 */
172 public final static int LEFT = W;
173
174 /**
175 * effect mask - bits 4-7
176 */
177 public final static int EFFECT_MASK = 0xF << 4;
178
179 /**
180 * a raised border
181 */
182 public final static int RAISED = 0x1 << 4;
183
184 /**
185 * a sunken border
186 */
187 public final static int SUNKEN = 0x1 << 5;
188
189 /**
190 * a highlighted border/text
191 */
192 public final static int BULK = 0x1 << 6;
193
194 /**
195 * underline effect
196 */
197 public final static int ULINE = 0x1 << 7;
198
199 /**
200 * mode mask - bits 8-11
201 */
202 public final static int MISC_MASK = 0xF << 8;
203
204 /**
205 * fill object (rectangle/triangle) - Outline is default
206 */
207 public final static int FILL = 0x1 << 8;
208
209 /**
210 * the following text is a href
211 */
212 public final static int HREF = 0x1 << 9;
213
214 /**
215 * Unicode replacement char. Used as indicator that the
216 * following char is interpreted as formatting information
217 */
218 public final static char Esc = '\uFFFD';
219
220 /**
221 * Unicode null char. Not a char at all. Used as placeholder
222 */
223 public final static char Null = '\uFFFF';
224
225 /**
226 * reset all styles to default
227 */
228 public final static char None = '\u0000';
229
230 /**
231 * font family Serif
232 */
233 public final static char Serif = '\uFF00';
234
235 /**
236 * font family SansSerif
237 */
238 public final static char SansSerif = '\uFF01';
239
240 /**
241 * font family Monospaced
242 */
243 public final static char Monospaced = '\uFF02';
244
245 /**
246 * font style plain
247 */
248 public final static char Plain = '\uFB00';
249
250 /**
251 * font style bold
252 */
253 public final static char Bold = '\uFB01';
254
255 /**
256 * font style italic
257 */
258 public final static char Italic = '\uFB02';
259
260 /**
261 * font style bolditalic
262 */
263 public final static char Bolditalic = '\uFB03';
264
265 /**
266 * font size relative smaller
267 */
268 public final static char Smaller = '\uF000';
269
270 /**
271 * font size relative larger
272 */
273 public final static char Larger = '\uF001';
274
275 /**
276 * font sizes absolute
277 */
278 public final static char FontSize0 = '\uF500';
279
280 /**
281 * Mask for computing fontsizes
282 */
283 public final static char FontMask = '\uFF00';
284
285 /**
286 * Mask for computing fontsizes
287 */
288 public final static char FontSizeMask = '\u00FF';
289
290 /**
291 * North alignment
292 */
293 public final static char North = '\uA001';
294
295 /**
296 * East alignment
297 */
298 public final static char East = '\uA002';
299
300 /**
301 * South alignment
302 */
303 public final static char South = '\uA004';
304
305 /**
306 * West alignment
307 */
308 public final static char West = '\uA008';
309
310 /**
311 * NorthWest alignment
312 */
313 public final static char NorthWest = '\uA009';
314
315 /**
316 * SouthWest alignment
317 */
318 public final static char SouthWest = '\uA00C';
319
320 /**
321 * NorthEast alignment
322 */
323 public final static char NorthEast = '\uA003';
324
325 /**
326 * SouthEast alignment
327 */
328 public final static char SouthEast = '\uA00A';
329
330 /**
331 * Center alignment
332 */
333 public final static char Center = '\uA00F';
334
335 /**
336 * Tab positions absolute; Format: Dnnn nnn is the pos in hex ranging from 0 - 7FF
337 */
338 public final static char Tab0 = '\uD000';
339
340 /**
341 * Tab mask to determine tabs
342 */
343 public final static char TabMask = '\uF000';
344
345 /**
346 * Tab mask to determine tab positions
347 */
348 public final static char TabSizeMask = '\u07FF';
349
350 /**
351 * the default 'effect'
352 */
353 public final static char Flat = '\uE000';
354
355 /**
356 * shadow effect to emphasize text
357 */
358 public final static char Raised = '\uE001';
359
360 /**
361 * shadow effect to make text look inaktive
362 */
363 public final static char Sunken = '\uE002';
364
365 /**
366 * Used to specify a border mode in property files. not used for text
367 */
368 public final static char Bulk = '\uE003';
369
370 /**
371 * Underline text
372 */
373 public final static char Uline = '\uE004';
374
375 /**
376 * start of a href
377 */
378 public final static char Href = '\uE0D1';
379
380 /**
381 * end of a href (or use flat/default)
382 */
383 public final static char Hrefend = '\uE0D0';
384
385 /**
386 * make fg color darker
387 */
388 public final static char Darker = '\uE0C1';
389
390 /**
391 * make fg color brighter
392 */
393 public final static char Brighter = '\uE0C2';
394
395 /**
396 * make fg color equal to fg color (same as setting it to default)
397 */
398 public final static char Foreground = '\uE0C3';
399
400 /**
401 * make fg color equal to bg color
402 */
403 public final static char Background = '\uE0C4';
404
405 /**
406 * colors use the format C<r><g><b>, where each color value can range from 0 to F. See examples below
407 */
408 public final static char ColorMask = '\uF000';
409
410 /**
411 * used to determine the red portion of this color spec
412 */
413 public final static char RedMask = '\u0F00';
414
415 /**
416 * used to determine the green portion of this color spec
417 */
418 public final static char GreenMask = '\u00F0';
419
420 /**
421 * used to determine the blue portion of this color spec
422 */
423 public final static char BlueMask = '\u000F';
424
425 /**
426 * the color white
427 */
428 public final static char White = '\uC000';
429
430 /**
431 * the color black
432 */
433 public final static char Black = '\uCFFF';
434
435 /**
436 * java version
437 */
438 protected final static String jversion = System.getProperty("java.version");
439
440 /**
441 * java vendor
442 */
443 protected final static String jvendor = System.getProperty("java.vendor");
444
445 /**
446 * font cache
447 */
448 protected final static Hashtable fonts = new Hashtable();
449
450 /**
451 * insets around this comp
452 */
453 protected Insets insets = new Insets(0,0,0,0); // borders around the component
454
455 /**
456 * insets within this comp
457 */
458 protected Insets innerInsets = new Insets(0,0,0,0); // borders within the component
459
460 /**
461 * borderdepth - thickness of border
462 */
463 protected int borderDepth = 0;
464
465 /**
466 * bordertype - one of NONE, RAISED, SUNKEN, BULK, TOP
467 */
468 protected int borderType = NONE;
469
470 /**
471 * the dimension for comp
472 */
473 protected Dimension minimumDimension = new Dimension();
474
475 /**
476 * ActionListener to notify clients
477 */
478 protected ActionListener actionListener = null;
479
480 /**
481 * ItemListener to notify clients
482 */
483 protected ItemListener itemListener = null;
484
485 /**
486 * save components states if this panel is set to disable
487 */
488 protected Hashtable componentStates = new Hashtable();
489
490 /**
491 * our Background
492 */
493 protected Object bg = null;
494
495 /**
496 * backing image for flickerfree drawing
497 */
498 protected Image bim = null;
499
500 /**
501 * Grphics for bim
502 */
503 protected Graphics big = null;
504
505 /**
506 * Creates a nicely formatted error popup.
507 *
508 * @param m the message; usually string or exception
509 * @param c comp used as parent for popup or null
510 */
511 public static void error(Object m, Component c) {
512 String s[] = Debug.stackline(1);
513 String e = "" + Esc + Bold + Debug.msg(m);
514 if(s.length > 2) {
515 e += "\n" + Esc + Plain + "[" + s[1] + " at " + s[2] + "]";
516 }
517 if(m instanceof Exception) {
518 e += "\n\n" + Esc + Italic + Debug.stack((Exception) m).replace('\t',' ');
519 }
520 DialogBox.errorDialog(e).show(c);
521 }
522
523 /**
524 * Creates an image from an InputStream
525 *
526 * @param n the name of the image.
527 */
528 public static Image loadImageFromStream(InputStream i) {
529 try {
530 ByteArrayOutputStream b = new ByteArrayOutputStream();
531 for(int c = i.read(); c >= 0; c = i.read()) {
532 b.write(c);
533 }
534 return Toolkit.getDefaultToolkit().createImage(b.toByteArray());
535 } catch(Exception x) {
536 Debug.debug(Awt.class, x);
537 return null;
538 }
539 }
540
541 /**
542 * Creates an image from a Archive
543 * At least this is what Netscape 4.x does.
544 * @link <a href="http://developer.netscape.com/docs/technote/java/getresource/getresource.html">Technote getresource</a>
545 * Returns <code>null</code> on failure.
546 *
547 * @param n the name of the image.
548 */
549 public static Image loadImageFromArchive(String n) {
550 return loadImageFromStream(Awt.class.getResourceAsStream(n));
551 }
552
553 /**
554 * Creates an image from an url.
555 * Returns <code>null</code> on failure.
556 *
557 * @param n the name/url of the image.
558 */
559 public static Image loadImageFromURL(String n) {
560 try {
561 return loadImageFromStream(new URL(n).openStream());
562 } catch(Exception x) {
563 Debug.debug(Awt.class, x);
564 return null;
565 }
566 }
567
568 /**
569 * Creates an image either form URL or Archive
570 * Returns <code>null</code> on failure.
571 *
572 * @param n the name/url of the image.
573 */
574 public Image loadImage(String n) {
575 Image i = loadImageFromURL(n);
576 if(i == null) {
577 i = loadImageFromArchive(n);
578 }
579 return i;
580 }
581
582 /**
583 * Check if this is a Netscape 4 JVM
584 *
585 * @return true if this is a Netscape 4 JVM
586 */
587 public static boolean isNS4JVM() {
588 return jversion.equals("1.1.5") && jvendor.startsWith("Net");
589 }
590
591 /**
592 * Check if this is a MS JVM
593 *
594 * @return true if this is a MS JVM
595 */
596 public static boolean isMSJVM() {
597 return jversion.equals("1.1.4") && jvendor.startsWith("Mic");
598 }
599
600 /**
601 * Center a window on screen. Reduces window size if larger
602 * than screen.
603 *
604 * @param w the window to center.
605 */
606 public static void centerWindow(Window w) {
607 Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
608 // not larger than screen ...
609 w.setSize(Math.min(d.width, w.getSize().width), Math.min(d.height, w.getSize().height));
610 // Center Frame, Dialog or Window on screen
611 w.setLocation((d.width - w.getSize().width) / 2, (d.height - w.getSize().height) / 2);
612 }
613
614 /**
615 * Set BG color of a (AWT) component
616 *
617 * @param c Component
618 */
619 public static void setBackground(Component c) {
620 if(c.getParent().getBackground() != null) {
621 c.setBackground(c instanceof TextComponent && (isNS4JVM() || isMSJVM()) ? c.getParent().getBackground().darker() : c.getParent().getBackground());
622 }
623 }
624
625 /**
626 * Set FG color of a (AWT) component
627 *
628 * @param c Component
629 */
630 public static void setForeground(Component c) {
631 if(c.getParent().getForeground() != null) {
632 c.setForeground(c.getParent().getForeground());
633 }
634 }
635
636 /**
637 * Set font of a (AWT) textcomponent
638 *
639 * @param tc TextComponent
640 */
641 public static void setFont(TextComponent tc) {
642 if(tc.getParent().getFont() != null) {
643 tc.setFont(tc.getParent().getFont());
644 }
645 }
646
647 /**
648 * Refresh (force new layout) starting from component up the tree
649 *
650 * @param c the component to refresh.
651 */
652 public static void refresh(Component c) {
653 c.invalidate();
654 c.validate();
655 if(isMSJVM()) c.repaint();
656 if(c instanceof Container) {
657 Component[] cs = ((Container) c).getComponents();
658 for(int i = 0; i < cs.length; ++i) {
659 if(cs[i] instanceof TextComponent) {
660 setFont((TextComponent) cs[i]);
661 }
662 if(cs[i] instanceof TextComponent || cs[i] instanceof Scrollbar) {
663 setForeground(cs[i]);
664 setBackground(cs[i]);
665 }
666 refresh(cs[i]);
667 }
668 }
669 if(c instanceof Window) {
670 ((Window) c).pack(); return;
671 }
672 }
673
674 /**
675 * Refresh (force new layout) starting from this component down the tree
676 */
677 public void refresh() {
678 refresh(this);
679 }
680
681 /**
682 * Refresh (force new layout) starting from root component up the tree
683 */
684 public void refreshAll() {
685 refresh(getTopComponent(this));
686 refresh(getTopComponent(this));
687 }
688
689 /**
690 * Gets the toplevel component (usually a frame)
691 *
692 * @param c the component to find the toplevel component for.
693 */
694 public static Component getTopComponent(Component c) {
695 return (Component) c.getParent() == null || (c instanceof Main && ((Main)c).isApplet()) ? c : getTopComponent(c.getParent());
696 }
697
698 /**
699 * Gets the current applet context if any
700 *
701 * @param c the component to find the applet context for.
702 */
703 public static AppletContext getAppletContext(Component c) {
704 return getApplet(getTopComponent(c)).getAppletContext();
705 }
706
707 /**
708 * Gets the current applet if any. Used internaly
709 *
710 * @param c the toplevel component to start with
711 */
712 private static Applet getApplet(Component c) {
713 if(c instanceof Applet) {
714 return (Applet) c;
715 }
716 if(c instanceof Container) {
717 Container C = (Container) c;
718 for(int i = 0; i < C.getComponentCount(); ++i) {
719 Applet a = getApplet(C.getComponent(i));
720 if(a != null) {
721 return a;
722 }
723 }
724 }
725 return null;
726 }
727
728 /**
729 * Try to get a font. <code>obj</code> can be a
730 * standard font name or already a font object.
731 *
732 * @return <code>null</code> on failure.
733 *
734 * @param obj color specification.
735 */
736 public static Font getFont(Object o) {
737 if(o == null) {
738 return null;
739 }
740 if(o instanceof Font) {
741 return (Font) o;
742 }
743 return Font.decode(o.toString());
744 }
745
746 /**
747 * Try to get a font from our cache. Create a new one if none was found.
748 *
749 * @param name Font name/family
750 * @param style Font.PAIN Font.BOLD Font.ITALIC
751 * @param size Font size in points
752 */
753 public static Font getFont(String name, int style, int size) {
754 String idx = name + style + size;
755 if(fonts.containsKey(idx)) {
756 return (Font) fonts.get(idx);
757 } else {
758 Font font = new Font(name, style, size);
759 fonts.put(idx, font); getMetrics(font);
760 return font;
761 }
762 }
763
764 /**
765 * Returns Metrics for font
766 * @param f font to use.
767 */
768 public static FontMetrics getMetrics(Font f) {
769 if(f != null) {
770 if(fonts.containsKey(f) == false) {
771 fonts.put(f, Toolkit.getDefaultToolkit().getFontMetrics(f));
772 }
773 return (FontMetrics) fonts.get(f);
774 }
775 return null;
776 }
777
778 /**
779 * Returns a larger font with same family and style
780 * @param f use this as base font.
781 */
782 public static Font larger(Font f) {
783 return getFont(f.getName(), f.getStyle(), f.getSize() + 2);
784 }
785
786 /**
787 * Returns a smaller font with same family and style
788 * @param f use this as base font.
789 */
790 public static Font smaller(Font f) {
791 return getFont(f.getName(), f.getStyle(), f.getSize() > 1 ? f.getSize() - 2 : f.getSize());
792 }
793
794 /**
795 * Returns a serif font with same size and style
796 * @param f use this as base font.
797 */
798 public static Font serif(Font f) {
799 return getFont("Serif", f.getStyle(), f.getSize());
800 }
801
802 /**
803 * Returns a sansserif font with same size and style
804 * @param f use this as base font.
805 */
806 public static Font sansserif(Font f) {
807 return getFont("SansSerif", f.getStyle(), f.getSize());
808 }
809
810 /**
811 * Returns a monospaced font with same size and style
812 * @param f use this as base font.
813 */
814 public static Font monospaced(Font f) {
815 return getFont("Monospaced", f.getStyle(), f.getSize());
816 }
817
818 /**
819 * Returns a bold font with same size and family
820 * @param f use this as base font.
821 */
822 public static Font bold(Font f) {
823 return getFont(f.getName(), Font.BOLD, f.getSize());
824 }
825
826 /**
827 * Returns a italic font with same size and family
828 * @param f use this as base font.
829 */
830 public static Font italic(Font f) {
831 return getFont(f.getName(), Font.ITALIC, f.getSize());
832 }
833
834 /**
835 * Returns a bolditalic font with same size and family
836 * @param f use this as base font.
837 */
838 public static Font bolditalic(Font f) {
839 return getFont(f.getName(), Font.BOLD | Font.ITALIC, f.getSize());
840 }
841
842 /**
843 * Returns a plain font with same size and family
844 * @param f use this as base font.
845 */
846 public static Font plain(Font f) {
847 return getFont(f.getName(), Font.PLAIN, f.getSize());
848 }
849
850 /**
851 * Returns the escape sequence for Color c
852 * @param c the color
853 */
854 public static String Color2Esc(Color c) {
855 if(c == null) {
856 return "";
857 }
858 int v = White + ((c.getRed() / 16) << 8) + ((c.getGreen() / 16) << 4) + ((c.getBlue() / 16) << 0);
859 char[] buf = {Esc, (char) v};
860 return String.valueOf(buf);
861 }
862
863 /**
864 * Try to get color. <code>obj</code> can be color name
865 * or a numeric value or already a color object.
866 *
867 * @return <code>null</code> on failure.
868 *
869 * @param o color specification.
870 */
871 public static Color getColor(Object o) {
872 if(o == null) {
873 return null;
874 }
875 if(o instanceof Color) {
876 return (Color) o;
877 }
878 try {
879 return Color.decode(o.toString());
880 } catch(Exception x) {
881 return null;
882 }
883 }
884
885 /**
886 * Return a dimmed version of color <code>c</code>
887 *
888 * @param c original color
889 * @param v value to dim
890 */
891 public static Color dim(Color c, int v) {
892 return c == null ? Color.white :
893 new Color(Math.max(Math.min(c.getRed() + v, 255),0),
894 Math.max(Math.min(c.getGreen() + v, 255),0),
895 Math.max(Math.min(c.getBlue() + v, 255),0));
896 }
897
898 /**
899 * Return a brighter version of color <code>c</code>
900 *
901 * @param c original color
902 */
903 public static Color brighter(Color c) {
904 return dim(c, 63);
905 }
906
907 /**
908 * Return a darker version of color <code>c</code>
909 *
910 * @param c original color
911 */
912 public static Color darker(Color c) {
913 return dim(c, -63);
914 }
915
916 /**
917 * Return Insets from an int array (used to set Insets from property file)
918 *
919 * @param i insets values (as in Insets constructor)
920 */
921 public static Insets Array2Insets(int[] i) {
922 return i != null && i.length == 4 ? new Insets(i[0], i[1], i[2], i[3]) : null;
923 }
924
925 /**
926 * Draws a line between the given points
927 *
928 * @param g Graphics object to use
929 * @param c color to use as base for shadow, or null
930 * @param x,y x,y coords of first point
931 * @param X,Y x,y coords of second point
932 * @param d thickness of line in pixel
933 * @param m RAISED or SUNKEN
934 */
935 public static void drawLine(Graphics g, Color c,
936 int x, int y, int X, int Y,
937 int d, int m) {
938 Color C = g.getColor();
939 g.setColor(c == null ? C : c);
940
941 if(isBulk(m)) {
942 d = d/2;
943 drawLine(g, isSunken(m) ? brighter(c) : darker(c), x, y, X, Y, d, m & ~EFFECT_MASK);
944 drawLine(g, isSunken(m) ? darker(c) : brighter(c), x + d, y + d, X + d, Y + d, d, m & ~EFFECT_MASK);
945 return;
946 }
947
948 g.drawLine(x, y, X, Y);
949 if(--d > 0) {
950 drawLine(g, c, x + 1, y + 1, X + 1, Y + 1, d, 0);
951 }
952 g.setColor(C);
953 }
954
955 /**
956 * Draws a rectangle within the given box
957 *
958 * @param g Graphics object to use
959 * @param c color to use as base for shadow, or null
960 * @param x x-position of describing rect
961 * @param y y-position of describing rect
962 * @param w width of describing rect
963 * @param h height of describing rect
964 * @param d thickness of the line in pixel
965 * @param m combination of FILL RAISED SUNKEN
966 */
967 public static void drawRectangle(Graphics g, Color c,
968 int x, int y, int w, int h,
969 int d, int m) {
970 if(w < 1 || h < 1 || d < 1) {
971 return;
972 }
973
974 g = g.create(x, y, w + 1, h + 1);
975
976 if(c != null) {
977 g.setColor(c);
978 }
979
980 if(isFill(m)) {
981 g.fillRect(0, 0, w, h);
982 }
983
984 if(isBulk(m)) {
985 d = d/2;
986 drawRectangle(g, isSunken(m) ? brighter(c) : darker(c), 0, 0, w, h, d, m & ~EFFECT_MASK);
987 drawRectangle(g, isSunken(m) ? darker(c) : brighter(c), d, d, w - d - d, h - d - d, d, m & ~EFFECT_MASK);
988 g.dispose();
989 return;
990 }
991
992 if(isEffect(m)) {
993 g.setColor(isRaised(m) ? brighter(c) : darker(c));
994 }
995 g.drawLine(0, 0, w, 0);
996 g.drawLine(0, 0, 0, h);
997
998 if(isEffect(m)) {
999 g.setColor(isRaised(m) ? darker(c) : brighter(c));
1000 }
1001 g.drawLine(w, h, w, 0);
1002 g.drawLine(w, h, 0, h);
1003
1004 if(--d > 0) {
1005 drawRectangle(g, c, 1, 1, w - 2, h - 2, d, m & ~FILL);
1006 }
1007 g.dispose();
1008 }
1009
1010 /**
1011 * Draws a triangle within the given box
1012 *
1013 * @param g Graphics object to use
1014 * @param c color to use as base for shadow, or null
1015 * @param x x-position of describing rect
1016 * @param y y-position of describing rect
1017 * @param w width of describing rect
1018 * @param h height of describing rect
1019 * @param d thickness of the line in pixel
1020 * @param m combination of LINE FILL RAISED SUNKEN and Direction (N E S W etc)
1021 */
1022 public static void drawTriangle(Graphics g, Color c,
1023 int x, int y, int w, int h,
1024 int d, int m) {
1025 if(w < 1 || h < 1 || d < 1) {
1026 return;
1027 }
1028
1029 int X[] = new int[3];
1030 int Y[] = new int[3];
1031 boolean drk = ((m & W) > 0 || getPosition(m) == N) == isSunken(m);
1032
1033 g = g.create(x, y, w + 1, h + 1);
1034
1035 if(c != null) {
1036 g.setColor(c);
1037 }
1038
1039 w--; h--;
1040
1041 switch(getPosition(m)) {
1042 case N:
1043 X[0]=w/2; X[1]=w; Y[1]=h; Y[2]=h; break;
1044 case W:
1045 X[1]=w; X[2]=w; Y[0]=h/2; Y[1]=h; break;
1046 case SW:
1047 X[1]=w; Y[1]=h; break;
1048 case NW:
1049 X[1]=w; Y[2]=h; break;
1050 case S:
1051 X[0]=w/2; X[2]=w; Y[0]=h; break;
1052 case E:
1053 X[0]=w; Y[0]=h/2; Y[2]=h; break;
1054 case SE:
1055 X[0]=w; X[2]=w; Y[0]=h; Y[1]=h; break;
1056 case NE:
1057 X[0]=w; X[2]=w; Y[2]=h; break;
1058 default:
1059 g.dispose();
1060 return;
1061 }
1062
1063 if(isEffect(m)) {
1064 g.setColor(c);
1065 }
1066
1067 if(isFill(m)) {
1068 g.fillPolygon(X, Y, 3);
1069 }
1070
1071 if(isEffect(m)) {
1072 g.setColor(drk ? brighter(c) : darker(c));
1073 }
1074 g.drawPolyline(X, Y, 3);
1075
1076 if(isEffect(m)) {
1077 g.setColor(drk ? darker(c) : brighter(c));
1078 }
1079 g.drawLine(X[0], Y[0], X[2], Y[2]);
1080
1081 if(isFill(m)) {
1082 g.dispose();
1083 return;
1084 }
1085
1086 if(--d > 0) {
1087 drawTriangle(g, c, 1, 1, w - 1, h - 1, d, m & ~FILL);
1088 }
1089 g.dispose();
1090 }
1091
1092 /**
1093 *
1094 * Draws a string within the given box.
1095 *
1096 * @param g Graphics object to use
1097 * @param c color to use or null
1098 * @param f font to use or null
1099 * @param s the string
1100 * @param x x-position of describing rect
1101 * @param y y-position of describing rect
1102 * @param w width of describing rect
1103 * @param h height of describing rect
1104 * @param m mode including position & effect & misc
1105 */
1106 public static Dimension drawString(Graphics g, Color c, Font f, String s,
1107 int x, int y, int w, int h, int m) {
1108 return drawString(g, c, f, s, x, y, w, h, m, null);
1109 }
1110
1111 /**
1112 *
1113 * Draws a string within the given box.
1114 *
1115 * @param g Graphics object to use
1116 * @param c color to use or null
1117 * @param f font to use or null
1118 * @param s the string
1119 * @param x x-position of describing rect
1120 * @param y y-position of describing rect
1121 * @param w width of describing rect
1122 * @param h height of describing rect
1123 * @param m mode including position & effect & misc
1124 * @param awt comp used as callback for hrefs
1125 */
1126 public static Dimension drawString(Graphics g, Color c, Font f, String s,
1127 int x, int y, int w, int h, int m, Awt awt) {
1128
1129 Dimension d = new Dimension();
1130
1131 if(s == null) {
1132 return d;
1133 }
1134
1135 if(f == null) {
1136 f = g.getFont();
1137 }
1138
1139 if(c == null) {
1140 c = g.getColor();
1141 }
1142
1143 g = g.create(x, y, w, h);
1144 d = measureString(s, f);
1145
1146 g.setFont(f);
1147 g.setColor(c);
1148
1149 if(d.width > w) {
1150 d.width = w;
1151 }
1152
1153 if(d.height > h) {
1154 d.height = h;
1155 }
1156
1157 if(awt != null && isHref(m)) {
1158 awt.doHref(s, x, y, d.width, h);
1159 g.setColor(Color.blue);
1160 m |= ULINE;
1161 }
1162
1163 if(isRaised(m) || isSunken(m)) {
1164 d = drawString(g, isRaised(m) ? brighter(c) : darker(c), f, s, 0, 0, w, h, m & ~EFFECT_MASK);
1165 d = drawString(g, isRaised(m) ? darker(c) : brighter(c), f, s, 1, 1, w, h, m & ~EFFECT_MASK);
1166 g.dispose();
1167 return d;
1168 }
1169
1170 switch(getPosition(m)) {
1171 case N:
1172 case S:
1173 case C: x =(w - d.width) / 2; break;
1174 case NE:
1175 case E:
1176 case SE: x = w - d.width; break;
1177 default: x = 0;
1178 }
1179
1180 switch(getPosition(m)) {
1181 case E:
1182 case W:
1183 case C: y =(h - d.height) / 2; break;
1184 case SW:
1185 case S:
1186 case SE: y = h - d.height; break;
1187 default: y = 0;
1188 }
1189
1190 g.drawString(exString(s), x, y + g.getFontMetrics().getAscent());
1191
1192 if(isUline(m)) {
1193 g.drawLine(x, y + g.getFontMetrics().getAscent() + 1, d.width, y + g.getFontMetrics().getAscent() + 1);
1194 }
1195
1196 g.dispose();
1197 return d;
1198 }
1199
1200 /**
1201 * Calculates the box needed to draw the string
1202 *
1203 * @param s the string
1204 * @param f the base font to use
1205 */
1206 public static Dimension measureString(String s, Font f) {
1207 if(f == null) {
1208 return new Dimension();
1209 }
1210 FontMetrics m = getMetrics(f);
1211 return new Dimension(m.stringWidth(exString(s)), m.getHeight());
1212 }
1213
1214 /**
1215 *
1216 * Draws a caption within the given box. drawCaption recognizes the
1217 * escape sequences above for changing text characteristics and supports
1218 * multiple lines
1219 *
1220 * @param g Graphics object to use
1221 * @param c color to use or null
1222 * @param f font to use or null
1223 * @param s the string
1224 * @param x x-position of describing rect
1225 * @param y y-position of describing rect
1226 * @param w width of describing rect
1227 * @param h height of describing rect
1228 * @param m mode including position & effect
1229 * @param dl the line delimiter usually "\n" specify "" for a single line
1230 */
1231 public static void drawCaption(Graphics g, Color c, Font f, String s,
1232 int x, int y, int w, int h, int m, String dl) {
1233 drawCaption(g, c, f, s, x, y, w, h, m, dl, null);
1234 }
1235
1236 /**
1237 *
1238 * Draws a caption within the given box. drawCaption recognizes the
1239 * escape sequences above for changing text characteristics and supports
1240 * multiple lines
1241 *
1242 * @param g Graphics object to use
1243 * @param c color to use or null
1244 * @param f font to use or null
1245 * @param s the string
1246 * @param x x-position of describing rect
1247 * @param y y-position of describing rect
1248 * @param w width of describing rect
1249 * @param h height of describing rect
1250 * @param m mode including position & effect
1251 * @param dl the line delimiter usually "\n" specify "" for a single line
1252 * @param awt comp used as callback for hrefs
1253 */
1254 public static void drawCaption(Graphics g, Color c, Font f, String s,
1255 int x, int y, int w, int h, int m, String dl, Awt awt) {
1256
1257 if(s == null) {
1258 return;
1259 }
1260
1261 if(c == null) {
1262 c = g.getColor();
1263 }
1264
1265 if(f == null) {
1266 f = g.getFont();
1267 }
1268
1269 Color dc = c; // default color
1270 Font df = f; // default font
1271 int dm = m; // default mode
1272 int X = 0; // current X
1273 Dimension D = measureCaption(s, f, df, dl); // total dims
1274
1275 if(D.width > w) {
1276 D.width = w;
1277 }
1278
1279 if(D.height > h) {
1280 D.height = h;
1281 }
1282
1283 switch(getPosition(m)) {
1284 case E:
1285 case W:
1286 case C: y += (h - D.height) / 2; break;
1287 case SW:
1288 case S:
1289 case SE: y += h - D.height; break;
1290 }
1291
1292 for(StringSplitter L = new StringSplitter(s, dl); L.hasMoreTokens();) {
1293 String l = L.nextToken(); // one line
1294 Dimension d = measureCaption(l, f, df, dl); // lines dimensions
1295 boolean p = false; // already started to paint ?
1296 if(d.width > w) {
1297 d.width = w;
1298 }
1299 if(d.height > h) {
1300 d.height = h;
1301 }
1302 for(StringSplitter T = new StringSplitter("" + Null + l, "" + Esc); T.hasMoreTokens();) {
1303 String t = T.nextToken(); // one token
1304 c = getColor(t.charAt(0), c, dc, awt == null ? dc : awt.getBackground());
1305 f = getFont(t.charAt(0), f, df);
1306 m = getMode(t.charAt(0), m, dm);
1307 X = getTab(t.charAt(0), f, X);
1308 if(t.length() > 1) {
1309 if(p == false) {
1310 switch(getPosition(m)) {
1311 case N:
1312 case S:
1313 case C: X = x + (w - d.width) / 2; break;
1314 case NE:
1315 case E:
1316 case SE: X = x + w - d.width; break;
1317 default: X = x; break;
1318 }
1319 p = true;
1320 }
1321 X += drawString(g, c, f, t.substring(1), X, y, w, d.height, (m & POSITION_MASK) == C ? m & ~POSITION_MASK | W : m & ~E | W, awt).width;
1322 }
1323 }
1324 y += d.height;
1325 }
1326 }
1327
1328 /**
1329 * Calculates the box needed to draw the caption
1330 *
1331 * @param s the string
1332 * @param f the base font to use
1333 * @param df the default font to use
1334 * @param dl the line delimiter usually "\n" specify "" for a single line
1335 */
1336 public static Dimension measureCaption(String s, Font f, Font df, String dl) {
1337 Dimension D = s.length() == 0 ? measureString("", f) : new Dimension();
1338 for(StringSplitter L = new StringSplitter(s, dl); L.hasMoreTokens();) {
1339 int w = 0, h = 0;
1340 for(StringSplitter T = new StringSplitter("" + Null + L.nextToken(), "" + Esc); T.hasMoreTokens();) {
1341 String t = T.nextToken();
1342 f = getFont(t.charAt(0), f, df);
1343 w = Math.max(w, getTab(t.charAt(0), f, w));
1344 Dimension d = measureString(t.substring(1), f);
1345 w += d.width;
1346 if(w > 0 || T.hasMoreTokens() == false) {
1347 h = Math.max(d.height, h);
1348 }
1349 }
1350 D.height += h;
1351 D.width = Math.max(w, D.width);;
1352 }
1353 return D;
1354 }
1355
1356 /**
1357 * Returns the visible (right) part of a string resp. href.
1358 * Parts are separated using the unicode null char
1359 *
1360 * @param s the orig. string
1361 */
1362 public static String exString(String s) {
1363 int i = s.indexOf(Null);
1364 return s.substring(i == -1 ? 0 : i + 1);
1365 }
1366
1367 /**
1368 * Returns the invisible (left or href) part of a string resp. href.
1369 * Parts are separated using the unicode null char
1370 *
1371 * @param s the orig. string
1372 */
1373 public static String exHref(String s) {
1374 int i = s.indexOf(Null);
1375 return s.substring(0, i == -1 ? s.length() : i);
1376 }
1377
1378 /**
1379 * Returns the modified font for escape char u
1380 * leaves font unchanged if u does not descibe any font characteristics
1381 *
1382 * @param u the escape char
1383 * @param f the base font to use
1384 * @param df the default font to use
1385 */
1386 public static Font getFont(char u, Font f, Font df) {
1387 if(f == null) {
1388 return null;
1389 }
1390 switch(u) {
1391 case Bold: return bold(f);
1392 case Plain: return plain(f);
1393 case Italic: return italic(f);
1394 case Bolditalic: return bolditalic(f);
1395 case Larger: return larger(f);
1396 case Smaller: return smaller(f);
1397 case Serif: return serif(f);
1398 case SansSerif: return sansserif(f);
1399 case Monospaced: return monospaced(f);
1400 case None: return df;
1401 }
1402 if((u & FontMask) == FontSize0) {
1403 return getFont(f.getName(), f.getStyle(), u & FontSizeMask);
1404 }
1405 return f;
1406 }
1407
1408 /**
1409 * Returns the modified color for escape char u
1410 * leaves color unchanged if u does not descibe any color characteristics
1411 *
1412 * @param u the escape char
1413 * @param c the base color to use
1414 * @param dc the default color to use
1415 * @param dc the background color to use
1416 */
1417 public static Color getColor(char u, Color c, Color dc, Color bg) {
1418 switch(u) {
1419 case Darker: return darker(c);
1420 case Brighter: return brighter(c);
1421 case Background: return bg;
1422 case Foreground: return dc;
1423 case None: return dc;
1424 }
1425 if((u & ColorMask) == White) {
1426 return new Color(((u & RedMask) >> 8) * 17, ((u & GreenMask) >> 4) * 17, ((u & BlueMask) >> 0) * 17);
1427 }
1428 return c;
1429 }
1430
1431 /**
1432 * Returns the tab position for escape char u
1433 * return default tab if u does not descibe any tab position
1434 *
1435 * @param u the escape char
1436 * @param f the base font to use
1437 * @param dt the default tab to use
1438 */
1439 public static int getTab(char u, Font f, int dt) {
1440 if((u & TabMask) == Tab0) {
1441 return (u & TabSizeMask) * getMetrics(f).charWidth('8');
1442 } else {
1443 return dt;
1444 }
1445 }
1446
1447 /**
1448 * Returns the modified mode for escape char u
1449 * leaves mode unchanged if u does not descibe any mode characteristics
1450 *
1451 * @param u the escape char
1452 * @param m the base mode to use
1453 * @param dm the default mode to use
1454 */
1455 public static int getMode(char u, int m, int dm) {
1456 switch(u) {
1457 case North: return m & ~POSITION_MASK | N;
1458 case East: return m & ~POSITION_MASK | E;
1459 case South: return m & ~POSITION_MASK | S;
1460 case West: return m & ~POSITION_MASK | W;
1461 case NorthWest: return m & ~POSITION_MASK | NW;
1462 case SouthWest: return m & ~POSITION_MASK | SW;
1463 case NorthEast: return m & ~POSITION_MASK | NE;
1464 case SouthEast: return m & ~POSITION_MASK | SE;
1465 case Center: return m & ~POSITION_MASK | C;
1466
1467 case Flat: return m & ~EFFECT_MASK;
1468 case Raised: return m & ~(RAISED|SUNKEN) | RAISED;
1469 case Sunken: return m & ~(RAISED|SUNKEN) | SUNKEN;
1470 case Uline: return m | ULINE;
1471
1472 case Hrefend: return m & ~MISC_MASK;
1473 case Href: return m & ~MISC_MASK | HREF;
1474
1475 case None: return dm;
1476 }
1477 return m;
1478 }
1479
1480 /**
1481 * Exctract position bits from m.
1482 *
1483 * @param m mode
1484 */
1485 public static int getPosition(int m) {
1486 return (m & POSITION_MASK) == 0 ? NW : m & POSITION_MASK;
1487 }
1488
1489 /**
1490 * True if m describes an effect (see above).
1491 *
1492 * @param m mode
1493 */
1494 public static boolean isEffect(int m) {
1495 return (m & EFFECT_MASK) > 0;
1496 }
1497
1498 /**
1499 * True if m describes effect Raised.
1500 *
1501 * @param m mode
1502 */
1503 public static boolean isRaised(int m) {
1504 return (m & RAISED) == RAISED;
1505 }
1506
1507 /**
1508 * True if m describes effect Sunken.
1509 *
1510 * @param m mode
1511 */
1512 public static boolean isSunken(int m) {
1513 return (m & SUNKEN) == SUNKEN;
1514 }
1515
1516 /**
1517 * True if m describes effect Bulk.
1518 *
1519 * @param m mode
1520 */
1521 public static boolean isBulk(int m) {
1522 return (m & BULK) == BULK;
1523 }
1524
1525 /**
1526 * True if m describes effect Underline.
1527 *
1528 * @param m mode
1529 */
1530 public static boolean isUline(int m) {
1531 return (m & ULINE) == ULINE;
1532 }
1533
1534 /**
1535 * True if we are in Href mode.
1536 *
1537 * @param m mode
1538 */
1539 public static boolean isHref(int m) {
1540 return (m & HREF) == HREF;
1541 }
1542
1543 /**
1544 * True if m describes effect Fill.
1545 *
1546 * @param m mode
1547 */
1548 public static boolean isFill(int m) {
1549 return (m & FILL) == FILL;
1550 }
1551
1552 /**
1553 * Contructor for an Awt component
1554 */
1555 public Awt() {
1556 if(this instanceof BorderPanel == false && this instanceof TabbedPanel == false) super.setLayout(null);
1557
1558 }
1559
1560 /**
1561 * callback routine for dynamic caption content
1562 * should be overwritten by implementing classes
1563 *
1564 * @param s the href string (including href & text)
1565 * @param x x pos of describing rect
1566 * @param y y pos of describing rect
1567 * @param w width of describing rect
1568 * @param h height of describing rect
1569 */
1570 public void doHref(String s, int x, int y, int w, int h) {
1571 }
1572
1573 /**
1574 * Overwrite Component.setBounds() to recognize resizing
1575 */
1576 public void setBounds(int x, int y, int w, int h) {
1577 super.setBounds(x, y, w, h);
1578 bim = null;
1579 big = null;
1580 }
1581
1582 /**
1583 * Return currently needed Dimension
1584 * Should be overridden by Awt Components
1585 */
1586 public Dimension measure() {
1587 return new Dimension(insets.left + borderDepth + innerInsets.left + innerInsets.right + borderDepth + insets.right,
1588 insets.top + borderDepth + innerInsets.top + innerInsets.bottom + borderDepth + insets.bottom);
1589 }
1590
1591 /**
1592 * Utility function for Awt Components
1593 * re-measures an invalidates if dims changed
1594 */
1595 public void doMeasure() {
1596 Dimension nd = measure();
1597 if(minimumDimension.equals(nd) == false) {
1598 minimumDimension = nd;
1599 invalidate();
1600 }
1601 }
1602
1603 /**
1604 * Get this comps rectangle
1605 * totalsize - insets
1606 */
1607 public Rectangle getRectangle() {
1608 return new Rectangle(insets.left,
1609 insets.top,
1610 getBounds().width - insets.left - insets.right,
1611 getBounds().height - insets.top - insets.bottom);
1612 }
1613
1614 /**
1615 * Get this comps rectangle within border
1616 * totalsize - insets - borderDepth
1617 */
1618 public Rectangle getBorderRectangle() {
1619 Rectangle r = getRectangle();
1620 return new Rectangle(r.x + borderDepth,
1621 r.y + borderDepth,
1622 r.width - borderDepth - borderDepth,
1623 r.height - borderDepth - borderDepth);
1624 }
1625
1626 /**
1627 * Get this comps inner rectangle
1628 * totalsize - insets - borderDepth - innerInsets
1629 */
1630 public Rectangle getInnerRectangle() {
1631 Rectangle r = getBorderRectangle();
1632 return new Rectangle(r.x + innerInsets.left,
1633 r.y + innerInsets.top,
1634 r.width - innerInsets.left - innerInsets.right,
1635 r.height - innerInsets.top - innerInsets.bottom);
1636 }
1637
1638 /**
1639 * Overwrite java.awt.component.invalidate() to do
1640 * measuring
1641 * .
1642 */
1643 public void invalidate() {
1644 doMeasure();
1645 super.invalidate();
1646 }
1647
1648 /**
1649 * override java.awt.Panel.addNotify()
1650 * called shortly after instantiation
1651 * first chance to call measure()
1652 */
1653 public void addNotify() {
1654 super.addNotify();
1655 minimumDimension = measure();
1656 }
1657
1658 /**
1659 * override java.awt.Panel.getPreferredSize() and return
1660 * our minimum size
1661 */
1662 public Dimension getPreferredSize() {
1663 return minimumDimension;
1664 }
1665
1666 /**
1667 * override java.awt.Panel.getMinimumSize()
1668 * @see Awt#getPreferredSize()
1669 */
1670 public Dimension getMinimumSize() {
1671 return minimumDimension;
1672 }
1673
1674 /**
1675 * Overwrite java.awt.component.update() to avoid flickering
1676 * .
1677 */
1678 public void update(Graphics g) {
1679 if(g == null) return;
1680 paint(g);
1681 }
1682
1683 /**
1684 * Actually do the work ... this basic paint() routine just draws the
1685 * border. Should be overwritten.
1686 *
1687 * @param g Graphics object to use
1688 */
1689 public void paint(Graphics g) {
1690 if(borderDepth > 0) {
1691 Rectangle r = getRectangle();
1692 paintBorder(g, r.x, r.y, r.width - 1, r.height - 1);
1693 }
1694 }
1695
1696 /**
1697 * Paint the border
1698 *
1699 * @param g Graphics object to use
1700 * @param x x-position of describing rect
1701 * @param y y-position of describing rect
1702 * @param w width of describing rect
1703 * @param h height of describing rect
1704 */
1705 public void paintBorder(Graphics g, int x, int y, int w, int h) {
1706 if(g == null) return;
1707 switch(borderType) {
1708 case TOP:
1709 drawLine(g, getBackground(), x, y, x + w, y, borderDepth, BULK);
1710 break;
1711 case BULK:
1712 case NONE:
1713 case RAISED:
1714 case SUNKEN:
1715 drawRectangle(g, getBackground(), x, y, w, h, borderDepth, borderType);
1716 break;
1717 }
1718 }
1719
1720 /**
1721 * Paint the Background
1722 *
1723 * @param g Graphics object to use
1724 */
1725 public void paintBackground(Graphics g) {
1726 paintBackground(g, 0, 0, getBounds().width, getBounds().height);
1727 }
1728
1729 /**
1730 * Paint the Background
1731 *
1732 * @param g Graphics object to use
1733 * @param x x-position of describing rect
1734 * @param y y-position of describing rect
1735 * @param w width of describing rect
1736 * @param h height of describing rect
1737 */
1738 public void paintBackground(Graphics g, int x, int y, int w, int h) {
1739 if(g == null) return;
1740 Awt a = getBGParent();
1741 if(a == null || a.isShowing() == false || isShowing() == false || a.getBGImage() == null) {
1742 drawRectangle(g, getBackground(), x, y, w, h, 1, FILL);
1743 } else {
1744 int xo = getLocationOnScreen().x - a.getLocationOnScreen().x;
1745 int yo = getLocationOnScreen().y - a.getLocationOnScreen().y;
1746 g.drawImage(a.getBGImage(),
1747 x, y, x + w, y + h,
1748 x + xo, y + yo, x + xo + w, y + yo + h, this);
1749 }
1750 }
1751
1752 public void paintBim(Graphics g) {
1753 if(g == null || bim == null) return;
1754 g.drawImage(bim, 0, 0, this);
1755 }
1756
1757 public void makeBim() {
1758 if(bim == null) {
1759 bim = createImage(getBounds().width, getBounds().height);
1760 big = bim.getGraphics();
1761 }
1762 }
1763
1764 /**
1765 * set the BG for this comp. BG can be one of
1766 * null - use parent BG (or none)
1767 * Image - use this Image
1768 * String - use this filename/URL to load an Image
1769 * Awt - inherit BG from this Awt component
1770 */
1771 public void setBG(Object b) {
1772 bg = b;
1773 }
1774
1775 /**
1776 * set the BG for this comp only if none is currently present
1777 * (even from parent)
1778 */
1779 public void setBGIfNull(Object b) {
1780 if(getBGParentImage() == null) bg = b;
1781 }
1782
1783 /**
1784 * return the object currently used as BG for this comp
1785 * Attn: all BG's are converted to Image the first time used
1786 * So this routine usually returns Object type Image
1787 */
1788 public Object getBG() {
1789 return bg;
1790 }
1791
1792 /**
1793 * get the BG Image if any
1794 */
1795 public Image getBGImage() {
1796 if(bg == null) { // no image ? -> ok
1797 return null;
1798 }
1799 if(bg instanceof Image) { // already an Image ? -> make sure it fits
1800 bg = tile((Image) bg, getSize());
1801 return (Image) bg;
1802 }
1803 if(bg instanceof String) { // a String ? -> try to load image
1804 bg = waitForImage(loadImage((String) bg));
1805 return getBGImage();
1806 }
1807 if(bg instanceof Awt && bg != this) { // an Awt Component ? -> try to get image form there
1808 bg = ((Awt) bg).getBGParentImage();
1809 return getBGImage();
1810 }
1811 return null;
1812 }
1813
1814 /**
1815 * walk up the component tree to find a parent with a BG != null
1816 *
1817 * @param i the image
1818 */
1819 public Awt getBGParent() {
1820 if(getBG() == null) {
1821 Container p = getParent();
1822 if(p != null && p instanceof Awt) {
1823 return ((Awt) p).getBGParent();
1824 }
1825 return null;
1826 }
1827 return this;
1828 }
1829
1830 /**
1831 * walk up the component tree to find a BG != null
1832 *
1833 * @param i the image
1834 */
1835 public Image getBGParentImage() {
1836 Awt a = getBGParent();
1837 return a == null ? null : a.getBGImage();
1838 }
1839
1840 /**
1841 * wait for an Image to load completely
1842 *
1843 * @param i the image
1844 */
1845 public Image waitForImage(Image i) {
1846 if(i == null) {
1847 return null;
1848 }
1849 try {
1850 MediaTracker t = new MediaTracker(this);
1851 t.addImage(i, 0);
1852 t.waitForID(0);
1853 } catch(InterruptedException x){
1854 Debug.debug(this, x);
1855 return null;
1856 }
1857 return i;
1858 }
1859
1860 /**
1861 * scale (grow only) an Image to specified size by just
1862 * filling it with the original from left to right, top down
1863 * w, h will be rounded to the next multiple of original size
1864 *
1865 * @param i orinigal image
1866 * @param d new dims
1867 */
1868 public Image tile(Image i, Dimension d) {
1869 return tile(i, d.width, d.height);
1870 }
1871
1872 /**
1873 * scale (grow only) an Image to specified size by just
1874 * filling it with the original from left to right, top down
1875 * w, h will be rounded to the next multiple of original size
1876 *
1877 * @param i orinigal image
1878 * @param w new width
1879 * @param h new height
1880 */
1881 public Image tile(Image i, int w, int h) {
1882 if(i == null) {
1883 return null;
1884 }
1885
1886 int iw = i.getWidth(this);
1887 int ih = i.getHeight(this);
1888
1889 if(w > iw || h > ih) {
1890
1891 w = w / iw + 1;
1892 h = h / ih + 1;
1893 w *= iw;
1894 h *= ih;
1895
1896 Image I = createImage(w, h);
1897 for(int H = 0; H < h; H += i.getHeight(this)) {
1898 for(int W = 0; W < w; W += i.getWidth(this)) {
1899 I.getGraphics().drawImage(i, W, H, this);
1900 }
1901 }
1902 return waitForImage(I);
1903 } else {
1904 return i;
1905 }
1906 }
1907
1908 /**
1909 * override java.awt.Panel.setEnabled()
1910 * just to recocnize state change
1911 *
1912 * @param enabled enabled?
1913 */
1914 public void setEnabled(boolean enabled) {
1915 if(enabled == super.isEnabled()) {
1916 return;
1917 }
1918
1919 super.setEnabled(enabled);
1920
1921 if(enabled) {
1922 for(Enumeration e = componentStates.keys(); e.hasMoreElements(); ) {
1923 ((Component) e.nextElement()).setEnabled(true);
1924 }
1925 componentStates.clear();
1926 } else {
1927 for(int i = 0; i < getComponents().length; ++i) {
1928 Component c = getComponents()[i];
1929 if(c.isEnabled()) {
1930 componentStates.put(c, this);
1931 c.setEnabled(false);
1932 }
1933 }
1934 }
1935 repaint();
1936 }
1937
1938 /**
1939 * override java.awt.Panel.setVisible()
1940 * just to recocnize state change
1941 *
1942 * @param v visible?
1943 */
1944 public void setVisible(boolean v) {
1945 super.setVisible(v);
1946 repaint();
1947 }
1948
1949 /**
1950 * sets a new border
1951 *
1952 * @param i the border around the component
1953 */
1954 public void setInsets(Insets i) {
1955 if(i != null && insets.equals(i) == false) {
1956 insets = i;
1957 doMeasure();
1958 repaint();
1959 }
1960 }
1961
1962 /**
1963 * get current border
1964 */
1965 public Insets getInsets() {
1966 return insets;
1967 }
1968
1969 /**
1970 * sets a new border
1971 *
1972 * @param insets the border within the component
1973 */
1974 public void setInnerInsets(Insets i) {
1975 if(i != null && innerInsets.equals(i) == false) {
1976 innerInsets = i;
1977 doMeasure();
1978 repaint();
1979 }
1980 }
1981
1982 /**
1983 * get current inner border
1984 */
1985 public Insets getInnerInsets() {
1986 return innerInsets;
1987 }
1988
1989 /**
1990 * set borderdepth
1991 * @param d depth in pixel
1992 */
1993 public void setBorderDepth(int d) {
1994 if(d >= 0 && borderDepth != d) {
1995 borderDepth = d;
1996 doMeasure();
1997 repaint();
1998 }
1999 }
2000
2001 /**
2002 * get borderdepth
2003 */
2004 public int getBorderDepth() {
2005 return borderDepth;
2006 }
2007
2008 /**
2009 * set bodertype
2010 * @param t bordertype [TOP NONE BULK RAISED SUNKEN
2011 */
2012 public void setBorderType(int t) {
2013 if(borderType != t) {
2014 borderType = t;
2015 doMeasure();
2016 repaint();
2017 }
2018 }
2019
2020 /**
2021 * set bodertype - String version (attributes from property file)
2022 * @param t bordertype [North(Top) None Bulk Raised Sundekn]
2023 */
2024 public void setBorderType(String t) {
2025 if(t != null && t.length() == 2 && t.charAt(0) == Esc) {
2026 switch(t.charAt(1)) {
2027 case North: setBorderType(TOP); break;
2028 case None: setBorderType(NONE); break;
2029 case Bulk: setBorderType(BULK); break;
2030 case Raised: setBorderType(RAISED); break;
2031 case Sunken: setBorderType(SUNKEN); break;
2032 }
2033 }
2034 }
2035
2036 /**
2037 * get bodertype
2038 */
2039 public int getBorderType() {
2040 return borderType;
2041 }
2042
2043 /**
2044 * override java.awt.Panel.setFont(Font font)
2045 * just to recognize the change
2046 */
2047 public void setFont(Font f) {
2048 if(f != null) {
2049 super.setFont(f);
2050 doMeasure();
2051 repaint();
2052 }
2053 }
2054
2055 /**
2056 * implement java.awt.event.MouseListener
2057 */
2058 public void mousePressed(MouseEvent e) {
2059 }
2060
2061 /**
2062 * implement java.awt.event.MouseListener
2063 */
2064 public void mouseReleased(MouseEvent e) {
2065 }
2066
2067 /**
2068 * implement java.awt.event.MouseListener
2069 */
2070 public void mouseExited(MouseEvent e) {
2071 }
2072
2073 /**
2074 * implement java.awt.event.MouseListener
2075 */
2076 public void mouseEntered(MouseEvent e) {
2077 }
2078
2079 /**
2080 * implement java.awt.event.MouseListener
2081 */
2082 public void mouseClicked(MouseEvent e) {
2083 }
2084
2085 /**
2086 * implement java.awt.event.MouseListener
2087 */
2088 public void mouseMoved(MouseEvent e) {
2089 }
2090
2091 /**
2092 * implement java.awt.event.MouseListener
2093 */
2094 public void mouseDragged(MouseEvent e) {
2095 }
2096
2097 /**
2098 * implement java.awt.event.KeyListener
2099 */
2100 public void keyTyped(KeyEvent e) {
2101 }
2102
2103 /**
2104 * implement java.awt.event.KeyListener
2105 */
2106 public void keyPressed(KeyEvent e) {
2107 }
2108
2109 /**
2110 * implement java.awt.event.KeyListener
2111 */
2112 public void keyReleased(KeyEvent e) {
2113 }
2114
2115 /**
2116 * implement java.awt.event.AdjustmentListener
2117 */
2118 public void adjustmentValueChanged(AdjustmentEvent e) {
2119 }
2120
2121 /**
2122 * implement java.awt.event.FocusListener
2123 */
2124 public void focusGained(FocusEvent e) {
2125 }
2126
2127 /**
2128 * implement java.awt.event.FocusListener
2129 */
2130 public void focusLost(FocusEvent e) {
2131 }
2132
2133 /**
2134 * implement java.awt.ItemSelectable
2135 */
2136 public Object[] getSelectedObjects() {
2137 return null;
2138 }
2139
2140 /**
2141 * adds an actionListener
2142 * @param l the actionListener to add
2143 */
2144 public void addActionListener(ActionListener l) {
2145 actionListener = AWTEventMulticaster.add(actionListener, l);
2146 }
2147
2148 /**
2149 * removes an actionListener
2150 * @param l the actionListener to remove
2151 */
2152 public void removeActionListener(ActionListener l) {
2153 actionListener = AWTEventMulticaster.remove(actionListener, l);
2154 }
2155
2156 /**
2157 * notifies all actionListeners
2158 * @param e the event to post
2159 */
2160 protected synchronized void notifyActionListeners(ActionEvent e) {
2161 if(actionListener != null) actionListener.actionPerformed(e);
2162 }
2163
2164 /**
2165 * adds an itemListener
2166 * @param l the itemListener to add
2167 */
2168 public void addItemListener(ItemListener l) {
2169 itemListener = AWTEventMulticaster.add(itemListener, l);
2170 }
2171
2172 /**
2173 * removes an itemListener
2174 * @param l the itemListener to remove
2175 */
2176 public void removeItemListener(ItemListener l) {
2177 itemListener = AWTEventMulticaster.remove(itemListener, l);
2178 }
2179
2180 /**
2181 * notifies all itemListeners
2182 * @param e the event to post
2183 */
2184 protected synchronized void notifyItemListeners(ItemEvent e) {
2185 if(itemListener != null) itemListener.itemStateChanged(e);
2186 }
2187 }