001: package snow.lookandfeel;
002:
003: import javax.swing.*;
004: import javax.swing.border.*;
005: import javax.swing.event.*;
006: import java.awt.*;
007: import java.io.*;
008: import java.util.*;
009: import java.awt.event.*;
010: import java.beans.*;
011: import javax.swing.plaf.metal.*;
012:
013: public class CustomOceanImagePanel extends JPanel {
014:
015: // The gradient types :
016: public static int ApplyUpperLeftCornerHighLight = 0;
017: public static int ApplyVerticalHighLight = 1;
018:
019: // Some predefined color keystrings :
020: public static String ActiveTitleBackground = "InternalFrame.activeTitleBackground";
021: public static String PanelBackground = "Panel.background";
022:
023: // The gradient strength :
024: public static int LightGradientStrength = 0;
025: public static int MediumGradientStrength = 1;
026: public static int StrongGradientStrength = 2;
027:
028: private static final int AlfaColorStrength = 224;
029: // The lower this value, the more the backgroundpicture comes visible.
030:
031: private Color lightColor = new Color(190, 190, 250);
032: private Color mediumColor = new Color(120, 120, 180);
033: private Color darkColor = new Color(80, 80, 120);
034: float xGradient;
035:
036: private Color basisColor; // around this the gradient will be
037:
038: // gradient look : (defaults)
039: private int gradientType = ApplyUpperLeftCornerHighLight;
040: private int gradientStrength = MediumGradientStrength;
041: private String colorKey = ActiveTitleBackground;
042:
043: float gradientLength;
044:
045: private int finalColorOffset;
046: private int colorOffset;
047:
048: private boolean useParentBackGround = false; // when a background color has been assigned
049:
050: private ImageIcon backgroundImage = null;
051: // This is set according to the current theme, and changes,
052: // when the theme changes.
053:
054: private ImageIcon customBackgroundImage = null;
055: // This can be set by using one of the constructors.
056: // If this is set, this backgroundimage is used always,
057: // and not the one associated to the current theme.
058:
059: private boolean introThreadHasBeenStarted = false;
060:
061: private boolean allIsReadyForSpecialUpdates = false;
062:
063: // This flag is needed, because the updateUI() method sometimes
064: // is initially called, when some referenced UIManager
065: // functionality is not available yet. DO NOT REMOVE THIS.
066:
067: /**
068: * Creates a panel where you can pass
069: * theGradientType = ApplyUpperLeftCornerHighLight
070: * or ApplyVerticalHighLight
071: *
072: * and
073: * theGradientStrength = LightGradientStrength
074: * or MediumGradientStrength
075: * or StrongGradientStrength
076: *
077: * and
078: * theColorKey = null
079: * or ActiveTitleBackground
080: * or PanelBackground
081: * or any valid theme colorkey.
082: *
083: */
084: public CustomOceanImagePanel(final int theGradientType,
085: final int theGradientStrength, final String theColorKey) {
086: this (new BorderLayout(), true, theGradientType,
087: theGradientStrength, theColorKey);
088: }
089:
090: public CustomOceanImagePanel() {
091: this (new BorderLayout(), true, ApplyUpperLeftCornerHighLight,
092: LightGradientStrength, PanelBackground);
093: }
094:
095: /**
096: * Creates a panel where you can pass
097: * theGradientType = ApplyUpperLeftCornerHighLight
098: * or ApplyVerticalHighLight
099: *
100: * and
101: * theGradientStrength = LightGradientStrength
102: * or MediumGradientStrength
103: * or StrongGradientStrength
104: *
105: * and
106: * theColorKey = null
107: * or ActiveTitleBackground
108: * or PanelBackground
109: * or any valid theme colorkey.
110: *
111: */
112: public CustomOceanImagePanel(LayoutManager layout,
113: int theGradientType, int theGradientStrength,
114: String theColorKey) {
115: this (layout, true, theGradientType, theGradientStrength,
116: theColorKey);
117: }
118:
119: /**
120: * Creates a panel where you can pass
121: * theGradientType = ApplyUpperLeftCornerHighLight
122: * or ApplyVerticalHighLight
123: *
124: * and
125: * theGradientStrength = LightGradientStrength
126: * or MediumGradientStrength
127: * or StrongGradientStrength
128: *
129: * and
130: * theColorKey = null
131: * or ActiveTitleBackground
132: * or PanelBackground
133: * or any valid theme colorkey.
134: *
135: */
136: public CustomOceanImagePanel(LayoutManager layout,
137: boolean isDoubleBuffered, int theGradientType,
138: int theGradientStrength, String theColorKey) {
139: super (layout, isDoubleBuffered);
140: this .gradientType = theGradientType;
141: this .gradientStrength = theGradientStrength;
142: this .updateSpecialUI(); // sets basisColor, startColor and endColor
143: if (colorKey != null) {
144: this .colorKey = theColorKey;
145: } // else use the default
146: // scale the gradient along with the current font size :
147: float unitSize1 = UIManager.getFont("TextField.font")
148: .getSize2D();
149: this .xGradient = unitSize1;
150:
151: this .colorOffset = this .getFinalColorOffset() / 16;
152: // This will increased to the value of
153: // finalColorOffset in a few steps by the
154: // startupThread.
155:
156: this .finalColorOffset = 70; // medium gradient strength
157: if (this .gradientStrength == LightGradientStrength) {
158: this .finalColorOffset = 40;
159: }
160: if (this .gradientStrength == StrongGradientStrength) {
161: this .finalColorOffset = 90;
162: }
163:
164: EventQueue.invokeLater(new Runnable() {
165: public void run() {
166: allIsReadyForSpecialUpdates = true;
167: }
168: });
169:
170: } // Constructor
171:
172: /**
173: * This last constructor additionally defines a custom background
174: * picture. If this constructor is used, the passed backround
175: * picture will be used for ever, instead of getting or changing
176: * the background picture with the theme.
177: */
178: public CustomOceanImagePanel(LayoutManager layout,
179: int theGradientType, int theGradientStrength,
180: String theColorKey, ImageIcon customBackgroundImage) {
181: this (layout, theGradientType, theGradientStrength, theColorKey);
182: this .customBackgroundImage = customBackgroundImage;
183: }
184:
185: /**
186: * Process additional update-work, after having called
187: * the parent method.
188: */
189: @Override
190: public void updateUI() {
191: super .updateUI();
192: if (this .allIsReadyForSpecialUpdates) {
193: // additional update work :
194: updateSpecialUI();
195: // rescale the gradient along with the current font size :
196: float unitSize2 = UIManager.getFont("TextField.font")
197: .getSize2D();
198: xGradient = unitSize2;
199: }
200: }
201:
202: /**
203: * Seta a fixed background color, and with that : turns out the
204: * UIManager update mechanism.
205: */
206: @Override
207: public void setBackground(Color bgColor) {
208: super .setBackground(bgColor);
209: this .useParentBackGround = true; // turns off UIManager special update
210: this .basisColor = super .getBackground();
211: this .calculateColors();
212: }
213:
214: /**
215: * Calculate the start and endcolor of the gradient
216: * taking the basisColor as center color :
217: */
218: private void calculateColors() {
219: int rBase = this .basisColor.getRed();
220: int gBase = this .basisColor.getGreen();
221: int bBase = this .basisColor.getBlue();
222: // start color is lighter :
223: int rStart = rBase + colorOffset;
224: int gStart = gBase + colorOffset;
225: int bStart = bBase + colorOffset;
226: if ((rStart <= 255) && (gStart <= 255) && (bStart <= 255)) {
227: this .lightColor = new Color(rStart, gStart, bStart);
228: } else {
229: if (rStart > 255)
230: rStart = 255;
231: if (gStart > 255)
232: gStart = 255;
233: if (bStart > 255)
234: bStart = 255;
235: this .lightColor = new Color(rStart, gStart, bStart);
236: }
237:
238: this .mediumColor = this .basisColor;
239:
240: rStart = rBase - colorOffset;
241: gStart = gBase - colorOffset;
242: bStart = bBase - colorOffset;
243: if ((rStart >= 0) && (gStart >= 0) && (bStart >= 0)) {
244: this .darkColor = new Color(rStart, gStart, bStart);
245: } else {
246: if (rStart < 0)
247: rStart = 0;
248: if (gStart < 0)
249: gStart = 0;
250: if (bStart < 0)
251: bStart = 0;
252: this .darkColor = new Color(rStart, gStart, bStart);
253: }
254:
255: // If the current panel has a background image, we use this one and
256: // set the medium color slightly transparent :
257: // The background image is valid, when there is a theme with background
258: // image OR when a custom backgroundimage was set :
259: if (this .customBackgroundImage != null) {
260: // A custom image was set, so set the color a bit transparent :
261: this .mediumColor = new Color(mediumColor.getRed(),
262: mediumColor.getGreen(), mediumColor.getBlue(),
263: AlfaColorStrength);
264: // and use this one :
265: this .backgroundImage = this .customBackgroundImage;
266: } else {
267: CustomOceanTheme cot = ThemesManager.getInstance()
268: .getSelectedTheme();
269: if (cot != null) {
270: this .backgroundImage = cot.getBackgroundImage();
271: if (this .backgroundImage != null) {
272: this .mediumColor = new Color(mediumColor.getRed(),
273: mediumColor.getGreen(), mediumColor
274: .getBlue(), AlfaColorStrength);
275: }
276:
277: }
278: }
279: } // calculateColors
280:
281: /**
282: * Must be called, when the lf theme changes.
283: * Called by the propertychange listener above.
284: */
285: public void updateSpecialUI() {
286: // set it as basis :
287: this .basisColor = UIManager.getColor(this .colorKey);
288: // Calculate the start and endColors from that :
289: this .calculateColors();
290: }
291:
292: /**
293: * Overwritten paint method to have a slight color gradient.
294: */
295: @Override
296: public void paint(Graphics g) {
297: Graphics2D graphics2D = (Graphics2D) g;
298: final Paint savePaint = graphics2D.getPaint();
299:
300: // draw the background image, if we have one :
301: if (this .backgroundImage != null) {
302: int xMax = this .getWidth();
303: int yMax = this .getHeight();
304: int imageWidth = this .backgroundImage.getIconWidth();
305: int imageHeight = this .backgroundImage.getIconHeight();
306:
307: // Security [prevents endless loop, case an attribute is zero]
308: if ((xMax > 0) && (yMax > 0) && (imageWidth > 0)
309: && (imageHeight > 0)) {
310: int x = 0;
311: int y = 0;
312: while (x < xMax) {
313: while (y < yMax) {
314: //Icon ic = this.backgroundImage;
315: //ic.paintIcon(this, graphics2D,x,y);
316: graphics2D.drawImage(
317: backgroundImage.getImage(), x, y,
318: imageWidth, imageHeight,
319: backgroundImage.getImageObserver());
320: // System.out.println("Paint at "+x+", "+y);
321: y += imageHeight;
322: } // while y
323: y = 0;
324: x += imageWidth;
325: } // while x
326: } // if
327: } // if
328:
329: if (this .gradientType == ApplyUpperLeftCornerHighLight) {
330: GradientPaint upperLeftGradientPaint = new GradientPaint(
331: 0f, 0f, lightColor, xGradient, xGradient * 5.0f,
332: mediumColor);
333:
334: graphics2D.setPaint(upperLeftGradientPaint);
335: graphics2D.fill(graphics2D.getClip());
336: } else if (this .gradientType == ApplyVerticalHighLight) {
337:
338: this .gradientLength = xGradient;
339: if (gradientLength > this .getHeight() / 2.5f) {
340: gradientLength = this .getHeight() / 2.5f;
341: }
342: GradientPaint upperVerticalGradientPaint = new GradientPaint(
343: 0f, 0f, this .lightColor, 0f, gradientLength,
344: this .mediumColor);
345:
346: GradientPaint lowerVerticalGradientPaint = new GradientPaint(
347: 0f, getHeight(), this .darkColor, 0f, getHeight()
348: - gradientLength, this .mediumColor);
349:
350: Shape saveClip = graphics2D.getClip();
351:
352: Rectangle rLower = new Rectangle(0, getHeight() / 2,
353: getWidth(), 1 + getHeight() / 2);
354: graphics2D.setPaint(lowerVerticalGradientPaint);
355: graphics2D.fill(rLower);
356:
357: Rectangle rUpper = new Rectangle(0, 0, getWidth(),
358: 1 + getHeight() / 2);
359: graphics2D.setPaint(upperVerticalGradientPaint);
360: graphics2D.fill(rUpper);
361:
362: graphics2D.setClip(saveClip);
363: }
364: graphics2D.setPaint(savePaint);
365: super .paintChildren(graphics2D);
366:
367: if (!introThreadHasBeenStarted) {
368: introThreadHasBeenStarted = true;
369: this .startIntroThread();
370: }
371: } // paint
372:
373: /**
374: * Overwitten, so it doesnt clear all, but
375: * one has to call super, so children are properly rendered.
376: */
377: @Override
378: public void update(Graphics g) {
379: //super.update(g);
380: paint(g);
381: }
382:
383: public float getGradientLength() {
384: return this .gradientLength;
385: }
386:
387: /**
388: * Changes the color offset. Must be called inside
389: * the event dispatch thread.
390: */
391: public void setColorOffset(int newValue) {
392: this .colorOffset = newValue;
393: this .calculateColors();
394: if (this .isShowing() && this .isVisible()) {
395: this .updateUI();
396: } else {
397: this .revalidate();
398: }
399: }
400:
401: private void startIntroThread() {
402: // Launch the startupthread, which will increase the coloroffset :
403: final StartupThread startupThread = new StartupThread(this );
404: // but launch him after all swing work has been done -
405: // so set it into the swing queue :
406: SwingUtilities.invokeLater(new Runnable() {
407: public void run() {
408: startupThread.start();
409: }
410: });
411: }
412:
413: public int getFinalColorOffset() {
414: return this .finalColorOffset;
415: }
416:
417: /**
418: * The startup thread, which makes this panel shape itself
419: * in the first 3 seconds of its lifetime
420: */
421: private class StartupThread extends Thread {
422: private CustomOceanImagePanel bgPanel;
423:
424: public StartupThread(CustomOceanImagePanel bgPanel) {
425: this .bgPanel = bgPanel;
426: this .setDaemon(true);
427: }
428:
429: @Override
430: public void run() {
431: // wait half a second initially - increses the effect :
432: try {
433: Thread.sleep(200);
434: } catch (Exception ignored) // NOPMD
435: {
436: }
437: int loops = 16;
438: int offsetStep = bgPanel.getFinalColorOffset() / loops;
439: for (int i = 1; i <= loops; i++) {
440: try {
441: Thread.sleep(90);
442: } catch (Exception wurscht) {
443: }
444: final int colorOffset = i * offsetStep;
445: SwingUtilities.invokeLater(new Runnable() {
446: public void run() {
447: bgPanel.setColorOffset(colorOffset);
448: }
449: });
450: try {
451: Thread.yield();
452: } catch (Exception ignored) {
453: } // NOPMD
454: }
455: }
456:
457: } // class StartupThread
458:
459: }
|