001: package Schmortopf.Utility.gui;
002:
003: import javax.swing.*;
004: import javax.swing.event.*;
005: import javax.swing.border.*;
006: import java.awt.*;
007: import java.io.*;
008: import java.util.*;
009: import java.awt.event.*;
010: import java.awt.geom.*;
011: import java.beans.*;
012:
013: /**
014: * Another panel with gradients.
015: *
016: * @author jpl
017: */
018: public class JToolGradientPanel extends JPanel {
019: // The gradient types :
020: public static int ApplyUpperLeftCornerHighLight = 0;
021: public static int ApplyVerticalHighLight = 1;
022:
023: // Some predefined color keystrings :
024: public static String ActiveTitleBackground = "InternalFrame.activeTitleBackground";
025: public static String PanelBackground = "Panel.background";
026:
027: // The gradient strength :
028: public static int LightGradientStrength = 0;
029: public static int MediumGradientStrength = 1;
030: public static int StrongGradientStrength = 2;
031:
032: private Color lightColor = new Color(190, 190, 250);
033: private Color mediumColor = new Color(120, 120, 180);
034: private Color darkColor = new Color(80, 80, 120);
035: float xGradient;
036:
037: private Color lightBorderColor = new Color(210, 210, 250);
038: private Color darkBorderColor = new Color(60, 60, 100);
039:
040: private Color basisColor; // around this the gradient will be
041:
042: // gradient look : (defaults)
043: private int gradientType = ApplyUpperLeftCornerHighLight;
044: private int gradientStrength = MediumGradientStrength;
045: private String colorKey = ActiveTitleBackground;
046:
047: float gradientLength;
048:
049: private int finalColorOffset;
050: private int colorOffset;
051:
052: private boolean displayBackGroundPicture = true;
053: // this can be turned off/on
054:
055: private boolean useParentBackGround = false; // when a background color has been assigned
056:
057: // This is set according to the current theme, and changes,
058: // when the theme changes. It isnt used, if
059: // displayBackGroundPicture is false.
060: private ImageIcon backgroundImage = null;
061:
062: // This can be set by using one of the constructors.
063: // If this is set, this backgroundimage is used always,
064: // and not the one associated to the current theme.
065: private ImageIcon customBackgroundImage = null;
066:
067: // Needed, as some updateUI() calls are too early
068: // for the special UI updates, cause some components
069: // could not be existing yet.
070: private boolean readyForSpecialUpdates = false;
071:
072: // draws a small 1 line raised bevel border
073: private boolean drawRaisedBevelBorder = true;
074:
075: /**
076: * Creates a panel where you can pass
077: * theGradientType = ApplyUpperLeftCornerHighLight
078: * or ApplyVerticalHighLight
079: *
080: * and
081: * theGradientStrength = LightGradientStrength
082: * or MediumGradientStrength
083: * or StrongGradientStrength
084: *
085: * and
086: * theColorKey = null
087: * or ActiveTitleBackground
088: * or PanelBackground
089: * or any valid theme colorkey.
090: *
091: */
092: public JToolGradientPanel(final int theGradientType,
093: final int theGradientStrength, final String theColorKey,
094: final boolean _drawRaisedBevelBorder) {
095: this (new BorderLayout(), true, theGradientType,
096: theGradientStrength, theColorKey,
097: _drawRaisedBevelBorder);
098: }
099:
100: /**
101: * Creates a panel where you can pass
102: * theGradientType = ApplyUpperLeftCornerHighLight
103: * or ApplyVerticalHighLight
104: *
105: * and
106: * theGradientStrength = LightGradientStrength
107: * or MediumGradientStrength
108: * or StrongGradientStrength
109: *
110: * and
111: * theColorKey = null
112: * or ActiveTitleBackground
113: * or PanelBackground
114: * or any valid theme colorkey.
115: *
116: */
117: public JToolGradientPanel(LayoutManager layout,
118: int theGradientType, int theGradientStrength,
119: String theColorKey, final boolean _drawRaisedBevelBorder) {
120: this (layout, true, theGradientType, theGradientStrength,
121: theColorKey, _drawRaisedBevelBorder);
122: }
123:
124: /**
125: * This constructor additionally defines a custom background
126: * picture. If this constructor is used, the passed backround
127: * picture will be used for ever, instead of getting or changing
128: * the background picture with the theme.
129: */
130: public JToolGradientPanel(LayoutManager layout,
131: int theGradientType, int theGradientStrength,
132: String theColorKey, ImageIcon customBackgroundImage,
133: final boolean _drawRaisedBevelBorder) {
134: this (layout, theGradientType, theGradientStrength, theColorKey,
135: _drawRaisedBevelBorder);
136: this .customBackgroundImage = customBackgroundImage;
137: }
138:
139: /**
140: * Creates a panel where you can pass
141: * theGradientType = ApplyUpperLeftCornerHighLight
142: * or ApplyVerticalHighLight
143: *
144: * and
145: * theGradientStrength = LightGradientStrength
146: * or MediumGradientStrength
147: * or StrongGradientStrength
148: *
149: * and
150: * theColorKey = null
151: * or ActiveTitleBackground
152: * or PanelBackground
153: * or any valid theme colorkey.
154: *
155: */
156: public JToolGradientPanel(LayoutManager layout,
157: boolean isDoubleBuffered, int theGradientType,
158: int theGradientStrength, String theColorKey,
159: final boolean _drawRaisedBevelBorder) {
160: super (layout, isDoubleBuffered);
161: this .drawRaisedBevelBorder = _drawRaisedBevelBorder;
162: this .gradientType = theGradientType;
163: this .gradientStrength = theGradientStrength;
164: if (colorKey != null) {
165: this .colorKey = theColorKey;
166: } // else use the default
167: // scale the gradient along with the current font size :
168: float unitSize = UIManager.getFont("TextField.font")
169: .getSize2D();
170: this .xGradient = (2 * unitSize) / 3;
171:
172: this .updateSpecialUI(); // sets basisColor, startColor and endColor
173:
174: this .colorOffset = 0; // This will increased to the value of
175: // finalColorOffset in a few steps by the
176: // startupThread.
177:
178: this .finalColorOffset = 70; // medium gradient strength
179: if (this .gradientStrength == LightGradientStrength) {
180: this .finalColorOffset = 40;
181: }
182: if (this .gradientStrength == StrongGradientStrength) {
183: this .finalColorOffset = 90;
184: }
185:
186: // Launch the startupthread, which will increase the coloroffset :
187: final StartupThread startupThread = new StartupThread(this );
188: // but launch him after all swing work has been done -
189: // so set it into the swing queue :
190: EventQueue.invokeLater(new Runnable() {
191: public void run() {
192: startupThread.start();
193: }
194: });
195: EventQueue.invokeLater(new Runnable() {
196: public void run() {
197: readyForSpecialUpdates = true;
198: }
199: });
200: } // Constructor
201:
202: /**
203: * Just calls <code>paint(g)</code>. This method was overridden to
204: * prevent an unnecessary call to clear the background.
205: *
206: * @param g the Graphics context in which to paint
207: */
208: public void update(Graphics g) {
209: this .paint(g);
210: }
211:
212: /**
213: * Overwritten method. Additionally updates special components.
214: */
215: public void updateUI() {
216: super .updateUI();
217: if (this .readyForSpecialUpdates) {
218: if (!useParentBackGround) // only if setBackground was never called
219: {
220: updateSpecialUI();
221: // rescale the gradient along with the current font size :
222: float unitSize = UIManager.getFont("TextField.font")
223: .getSize2D();
224: xGradient = unitSize;
225: }
226: }
227: }
228:
229: /**
230: * Set a a fixed background color, and with that : turns out the
231: * UIManager update mechanism.
232: */
233: public void setConstantBackground(Color bgColor) {
234: super .setBackground(bgColor);
235: this .useParentBackGround = true; // turns off UIManager special update
236: this .basisColor = super .getBackground();
237: this .calculateColors();
238: }
239:
240: /**
241: * Calculate the start and endcolor of the gradient
242: * taking the basisColor as center color :
243: */
244: private void calculateColors() {
245: int rBase = this .basisColor.getRed();
246: int gBase = this .basisColor.getGreen();
247: int bBase = this .basisColor.getBlue();
248: // start color is lighter :
249: int rStart = rBase + colorOffset;
250: int gStart = gBase + colorOffset;
251: int bStart = bBase + colorOffset;
252: if ((rStart <= 255) && (gStart <= 255) && (bStart <= 255)) {
253: this .lightColor = new Color(rStart, gStart, bStart);
254: } else {
255: if (rStart > 255)
256: rStart = 255;
257: if (gStart > 255)
258: gStart = 255;
259: if (bStart > 255)
260: bStart = 255;
261: this .lightColor = new Color(rStart, gStart, bStart);
262: }
263:
264: this .mediumColor = this .basisColor;
265:
266: rStart = rBase - colorOffset;
267: gStart = gBase - colorOffset;
268: bStart = bBase - colorOffset;
269: if ((rStart >= 0) && (gStart >= 0) && (bStart >= 0)) {
270: this .darkColor = new Color(rStart, gStart, bStart);
271: } else {
272: if (rStart < 0)
273: rStart = 0;
274: if (gStart < 0)
275: gStart = 0;
276: if (bStart < 0)
277: bStart = 0;
278: this .darkColor = new Color(rStart, gStart, bStart);
279: }
280:
281: this .lightBorderColor = this .changeBrightnessBy(lightColor, 16);
282: this .darkBorderColor = this .changeBrightnessBy(darkColor, -16);
283:
284: // If the current panel has a background image, we use this one and
285: // set the medium color slightly transparent :
286: // The background image is valid, when there is a theme with background
287: // image OR when a custom backgroundimage was set :
288:
289: // Intro scaling : During the startup thread loops,
290: // the colorOffset goes from a fraction of finalColorOffset
291: // in some steps upto this.finalColorOffset. We use this to
292: // zoom in the transparency :
293: double introShift = 50.0
294: * (this .finalColorOffset - this .colorOffset)
295: / (1.0 * this .finalColorOffset);
296: int alphaColor = 170 + (int) introShift;
297: if (alphaColor > 255)
298: alphaColor = 255;
299: if (alphaColor < 0)
300: alphaColor = 0;
301: if (this .displayBackGroundPicture) {
302: if (this .customBackgroundImage != null) {
303: // A custom image was set, so set the color a bit transparent :
304: this .mediumColor = new Color(mediumColor.getRed(),
305: mediumColor.getGreen(), mediumColor.getBlue(),
306: alphaColor);
307: // and use this one :
308: this .backgroundImage = this .customBackgroundImage;
309: }
310:
311: /* ------- not supported so far, LAF can be anyone
312: else
313: {
314: // Check if we have a background image from the current theme:
315: sun.awt.AppContext context = sun.awt.AppContext.getAppContext();
316: if( context != null)
317: {
318: MetalTheme currentTheme = (MetalTheme)context.get( "currentMetalTheme" );
319: if( currentTheme != null )
320: {
321: if( currentTheme instanceof EFCNThemesBasis )
322: {
323: EFCNThemesBasis efcnTheme = (EFCNThemesBasis)currentTheme;
324: this.backgroundImage = efcnTheme.getBackgroundImage();
325: if( this.backgroundImage != null )
326: {
327: this.mediumColor = new Color( mediumColor.getRed(),
328: mediumColor.getGreen(),
329: mediumColor.getBlue(),
330: alphaColor );
331: }
332: }
333: }
334: }
335: }
336: -------- */
337: }
338: } // calculateColors
339:
340: private Color changeBrightnessBy(final Color basisColor,
341: int colorOffset) {
342: int r = basisColor.getRed();
343: int g = basisColor.getGreen();
344: int b = basisColor.getBlue();
345: r += colorOffset;
346: if (r > 255)
347: r = 255;
348: if (r < 0)
349: r = 0;
350: g += colorOffset;
351: if (g > 255)
352: g = 255;
353: if (g < 0)
354: g = 0;
355: b += colorOffset;
356: if (b > 255)
357: b = 255;
358: if (b < 0)
359: b = 0;
360: return new Color(r, g, b);
361: }
362:
363: /**
364: * Must be called, when the lf theme changes.
365: * Called by the propertychange listener above.
366: */
367: public void updateSpecialUI() {
368: // Derive the basisColor :
369: Color color = UIManager.getColor(this .colorKey);
370: // give more green and blue
371: int r = color.getRed() - 5;
372: int g = color.getGreen() - 5;
373: int b = color.getBlue() + 10;
374: // level out grayscale value a bit :
375: if (r + g + b > 384) {
376: r -= 10;
377: g -= 10;
378: b -= 10;
379: } else {
380: r += 10;
381: g += 10;
382: b += 10;
383: }
384: // keep in range :
385: if (r < 0)
386: r = 0;
387: if (r > 255)
388: r = 255;
389: if (g < 0)
390: g = 0;
391: if (g > 255)
392: g = 255;
393: if (b < 0)
394: b = 0;
395: if (b > 255)
396: b = 255;
397: // and set it as basis :
398: this .basisColor = new Color(r, g, b);
399: // Calculate the start and endColors from that :
400: this .calculateColors();
401: }
402:
403: /**
404: * Overwritten paint method to have a slight color gradient.
405: */
406: public void paintComponent(Graphics g) {
407: Graphics2D graphics2D = (Graphics2D) g;
408: final Paint savePaint = graphics2D.getPaint();
409: final Color saveColor = graphics2D.getColor();
410:
411: // Draw the background image, if we have one.
412: // In this panel, we zoom the pic to fit horizontally,
413: // and tile vertically :
414: if ((this .backgroundImage != null)
415: && (this .displayBackGroundPicture)) {
416: int xMax = this .getWidth();
417: int yMax = this .getHeight();
418: int imageWidth = this .backgroundImage.getIconWidth();
419: int imageHeight = this .backgroundImage.getIconHeight();
420: // Security [prevents endless loop, case an attribute is zero]
421: if ((xMax > 1) && (yMax > 1) && (imageWidth > 1)
422: && (imageHeight > 1)) {
423: AffineTransform backupTransform = graphics2D
424: .getTransform();
425: // zoom the background picture to fit the width, keep aspect ratio :
426: AffineTransform xform = new AffineTransform();
427: double scaleFactor = (1.0 * xMax) / (1.0 * imageWidth);
428: xform.scale(scaleFactor, scaleFactor);
429: // Tile vertically :
430: int currentHeight = 0;
431: int verticalOffset = (int) (scaleFactor * imageHeight);
432: while (currentHeight < yMax) {
433: graphics2D.drawImage(backgroundImage.getImage(),
434: xform, this );
435: currentHeight += verticalOffset;
436: xform.translate(0.0, imageHeight);
437: }
438: // Restore the previous graphics2D transformation :
439: graphics2D.setTransform(backupTransform);
440: } // if pic is ok
441: } // if
442:
443: if (this .gradientType == ApplyUpperLeftCornerHighLight) {
444: GradientPaint upperLeftGradientPaint = new GradientPaint(
445: 0f, 0f, lightColor, xGradient, xGradient * 5.0f,
446: mediumColor);
447:
448: graphics2D.setPaint(upperLeftGradientPaint);
449: graphics2D.fill(graphics2D.getClip());
450: } else if (this .gradientType == ApplyVerticalHighLight) {
451:
452: this .gradientLength = xGradient;
453: if (gradientLength > this .getHeight() / 2.5f) {
454: gradientLength = this .getHeight() / 2.5f;
455: }
456: GradientPaint upperVerticalGradientPaint = new GradientPaint(
457: 0f, 0f, this .lightColor, 0f, gradientLength,
458: this .mediumColor);
459:
460: GradientPaint lowerVerticalGradientPaint = new GradientPaint(
461: 0f, getHeight(), this .darkColor, 0f, getHeight()
462: - gradientLength, this .mediumColor);
463:
464: Shape saveClip = graphics2D.getClip();
465:
466: Rectangle rLower = new Rectangle(0, getHeight() / 2,
467: getWidth(), 1 + getHeight() / 2);
468: graphics2D.setPaint(lowerVerticalGradientPaint);
469: graphics2D.fill(rLower);
470:
471: Rectangle rUpper = new Rectangle(0, 0, getWidth(),
472: 1 + getHeight() / 2);
473: graphics2D.setPaint(upperVerticalGradientPaint);
474: graphics2D.fill(rUpper);
475:
476: graphics2D.setClip(saveClip);
477: } // if
478: // Finally, if drawRaisedBevelBorder is set, draw that:
479: if (this .drawRaisedBevelBorder) {
480: int xMin = 0;
481: int yMin = 0;
482: int xMax = this .getWidth() - 1;
483: int yMax = this .getHeight() - 1;
484: // light topleft:
485: graphics2D.setColor(this .lightBorderColor);
486: graphics2D.drawLine(xMin, yMin, xMax, yMin);
487: graphics2D.drawLine(xMin, yMin, xMin, yMax);
488: // dark botright:
489: graphics2D.setColor(this .darkBorderColor);
490: graphics2D.drawLine(xMin, yMax, xMax, yMax);
491: graphics2D.drawLine(xMax, yMin, xMax, yMax);
492: } // if
493: graphics2D.setPaint(savePaint);
494: graphics2D.setColor(saveColor);
495: super .paintChildren(graphics2D);
496: } // paint
497:
498: public boolean imageUpdate(Image img, int infoflags, int x, int y,
499: int width, int height) {
500: return true;
501: }
502:
503: public float getGradientLength() {
504: return this .gradientLength;
505: }
506:
507: /**
508: * Changes the color offset. Must be called inside
509: * the event dispatch thread.
510: */
511: public void setColorOffset(int newValue) {
512: this .colorOffset = newValue;
513: this .calculateColors();
514: if (this .isShowing()) {
515: this .updateUI();
516: }
517: }
518:
519: public void setDisplayBackgroundPicture(boolean use) {
520: this .displayBackGroundPicture = use;
521: }
522:
523: public int getFinalColorOffset() {
524: return this .finalColorOffset;
525: }
526:
527: /**
528: * The startup thread, which makes this panel shape itself
529: * in the first 3 seconds of its lifetime
530: */
531: private class StartupThread extends Thread {
532: private JToolGradientPanel bgPanel;
533:
534: public StartupThread(JToolGradientPanel bgPanel) {
535: this .bgPanel = bgPanel;
536: this .setDaemon(true);
537: }
538:
539: public void run() {
540: int loops = 16;
541: double offsetStep = (1.0 * bgPanel.getFinalColorOffset())
542: / (1.0 * loops);
543: for (int i = 1; i <= loops; i++) {
544: final int colorOffset = (int) (i * offsetStep);
545: SwingUtilities.invokeLater(new Runnable() {
546: public void run() {
547: bgPanel.setColorOffset(colorOffset);
548: }
549: });
550: if (i == 1) {
551: // Wait half a second initially - increases the effect :
552: try {
553: Thread.sleep(660);
554: } catch (Exception sdfkjh) {
555: }
556: } else {
557: try {
558: Thread.sleep(90);
559: } catch (Exception wurscht) {
560: }
561: }
562: }
563: }
564:
565: } // class StartupThread
566:
567: } // JToolGradientPanel
|