001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: // $Id: TitleBarUI.java,v 1.12 2007/01/28 21:25:10 jesper Exp $
023: package net.infonode.docking.theme.internal.laftheme;
024:
025: import net.infonode.docking.View;
026: import net.infonode.docking.internal.ViewTitleBar;
027: import net.infonode.gui.DimensionProvider;
028: import net.infonode.gui.DynamicUIManager;
029: import net.infonode.gui.DynamicUIManagerListener;
030: import net.infonode.gui.componentpainter.ComponentPainter;
031: import net.infonode.gui.componentpainter.GradientComponentPainter;
032: import net.infonode.tabbedpanel.theme.internal.laftheme.SizeIcon;
033: import net.infonode.util.ColorUtil;
034: import net.infonode.util.Direction;
035:
036: import javax.swing.*;
037: import java.awt.*;
038: import java.awt.image.BufferedImage;
039: import java.awt.image.FilteredImageSource;
040: import java.awt.image.RGBImageFilter;
041: import java.beans.PropertyVetoException;
042:
043: public class TitleBarUI {
044: private static final int NUM_FADE_COLORS = 25;
045:
046: private static final int BUTTON_OFFSET = 2;
047:
048: private static final int RIGHT_INSET = 4;
049:
050: private boolean showing = true;
051:
052: private boolean enabled;
053:
054: private DynamicUIManagerListener uiListener = new DynamicUIManagerListener() {
055:
056: public void lookAndFeelChanged() {
057: doUpdate();
058: }
059:
060: public void propertiesChanging() {
061: listener.updating();
062: }
063:
064: public void propertiesChanged() {
065: doUpdate();
066: }
067:
068: public void lookAndFeelChanging() {
069: listener.updating();
070: }
071:
072: };
073:
074: private class IFrame extends JInternalFrame {
075: public IFrame() {
076: }
077:
078: public void updateUI() {
079: super .updateUI();
080:
081: setClosable(false);
082: setIconifiable(false);
083: setMaximizable(false);
084: setFocusable(false);
085: }
086:
087: public void setSelectedActivated(boolean selected) {
088: try {
089: setSelected(selected);
090: } catch (PropertyVetoException e) {
091: e.printStackTrace();
092: }
093: }
094:
095: public boolean isShowing() {
096: return showing;
097: }
098: }
099:
100: ;
101:
102: private Color[] fadeSelectedColors = new Color[NUM_FADE_COLORS];
103:
104: private Color[] fadeNormalColors = new Color[NUM_FADE_COLORS];
105:
106: private IFrame iFrame = new IFrame();
107:
108: private JFrame frame;
109:
110: private Dimension reportedMinimumSize;
111:
112: private Dimension minimumSize;
113:
114: private Insets iFrameInsets;
115:
116: private Color inactiveBackgroundColor;
117:
118: private Color activeBackgroundColor;
119:
120: private Color foundBackgroundColor;
121:
122: private boolean skipIFrame = false;
123:
124: private ComponentPainter activeComponentPainter = new ComponentPainter() {
125: public void paint(Component component, Graphics g, int x,
126: int y, int width, int height) {
127: }
128:
129: public void paint(Component component, Graphics g, int x,
130: int y, int width, int height, Direction direction,
131: boolean horizontalFlip, boolean verticalFlip) {
132: g.translate(-x, -y);
133: paintTitleBar(component, g, true, width, height,
134: Direction.UP);
135: g.translate(x, y);
136: }
137:
138: public boolean isOpaque(Component component) {
139: return false;
140: }
141:
142: public Color getColor(Component component) {
143: return getActiveBackgroundColor();
144: }
145: };
146:
147: private ComponentPainter inactiveComponentPainter = new ComponentPainter() {
148: public void paint(Component component, Graphics g, int x,
149: int y, int width, int height) {
150: }
151:
152: public void paint(Component component, Graphics g, int x,
153: int y, int width, int height, Direction direction,
154: boolean horizontalFlip, boolean verticalFlip) {
155: g.translate(-x, -y);
156: paintTitleBar(component, g, false, width, height,
157: Direction.UP);
158: g.translate(x, y);
159: }
160:
161: public boolean isOpaque(Component component) {
162: return false;
163: }
164:
165: public Color getColor(Component component) {
166: return getInactiveBackgroundColor();
167: }
168: };
169:
170: private TitleBarUIListener listener;
171:
172: public TitleBarUI(TitleBarUIListener listener, boolean enabled) {
173: this .enabled = enabled;
174: this .listener = listener;
175: }
176:
177: public void setEnabled(boolean enabled) {
178: this .enabled = enabled;
179: }
180:
181: public void dispose() {
182: DynamicUIManager.getInstance().removePrioritizedListener(
183: uiListener);
184: frame.removeAll();
185: frame.dispose();
186: }
187:
188: public void init() {
189: DynamicUIManager.getInstance().addPrioritizedListener(
190: uiListener);
191:
192: frame = new JFrame();
193:
194: frame.getContentPane().setLayout(null);
195: frame.getContentPane().add(iFrame);
196: frame.pack();
197:
198: listener.updating();
199: update();
200: }
201:
202: private void doUpdate() {
203: setEnabled(false);
204: SwingUtilities.updateComponentTreeUI(frame);
205:
206: update();
207: }
208:
209: private void update() {
210: SwingUtilities.invokeLater(new Runnable() {
211:
212: public void run() {
213: iFrame.setClosable(false);
214: iFrame.setMaximizable(false);
215: iFrame.setIconifiable(false);
216: iFrame.setBounds(0, 0, 50, 50);
217: iFrame.setResizable(false);
218:
219: iFrame.setVisible(true);
220: iFrame.setTitle(" ");
221:
222: iFrame.setFrameIcon(SizeIcon.EMPTY);
223:
224: {
225: // Insets
226: iFrameInsets = (Insets) iFrame.getInsets().clone();
227: if (UIManager.getLookAndFeel().getClass().getName()
228: .indexOf(".MotifLookAndFeel") != -1) {
229: iFrameInsets.left += 19;
230: }
231: }
232:
233: {
234: // Size
235: reportedMinimumSize = iFrame.getPreferredSize();
236: minimumSize = new Dimension(Math.max(0,
237: reportedMinimumSize.width
238: - iFrameInsets.left
239: - iFrameInsets.right),
240: reportedMinimumSize.height
241: - iFrameInsets.top
242: - iFrameInsets.bottom);
243: }
244:
245: String lafName = UIManager.getLookAndFeel().getClass()
246: .getName();
247: skipIFrame = lafName.indexOf("GTKLookAndFeel") != -1
248: || (lafName.indexOf(".WindowsLookAndFeel") != -1 || UIManager
249: .getLookAndFeel().getClass().getName()
250: .indexOf(".Office2003LookAndFeel") != -1)
251: && Toolkit.getDefaultToolkit()
252: .getDesktopProperty(
253: "win.xpstyle.themeActive") != null;
254:
255: estimateBackgroundColors();
256:
257: setEnabled(true);
258: listener.updated();
259: }
260:
261: });
262: }
263:
264: private void estimateBackgroundColors() {
265: activeBackgroundColor = estimateBackgroundColor(true);
266:
267: inactiveBackgroundColor = estimateBackgroundColor(false);
268:
269: double factor = 255 / fadeSelectedColors.length;
270:
271: for (int i = 0; i < fadeSelectedColors.length; i++) {
272: if (activeBackgroundColor != null)
273: fadeSelectedColors[i] = new Color(activeBackgroundColor
274: .getRed(), activeBackgroundColor.getGreen(),
275: activeBackgroundColor.getBlue(),
276: (int) ((i + 1) * factor));
277: if (inactiveBackgroundColor != null)
278: fadeNormalColors[i] = new Color(inactiveBackgroundColor
279: .getRed(), inactiveBackgroundColor.getGreen(),
280: inactiveBackgroundColor.getBlue(),
281: (int) ((i + 1) * factor));
282: }
283: }
284:
285: private Color estimateBackgroundColor(boolean selected) {
286: setSize(400);
287:
288: iFrame.setSelectedActivated(selected);
289:
290: BufferedImage img = new BufferedImage(iFrame.getWidth(), iFrame
291: .getHeight(), BufferedImage.TYPE_INT_ARGB);
292:
293: int x = iFrame.getWidth() - iFrameInsets.right - 3;
294: int y = iFrameInsets.top + 3;
295:
296: final int px = x;
297: final int py = y;
298:
299: RGBImageFilter colorFilter = new RGBImageFilter() {
300: public int filterRGB(int x, int y, int rgb) {
301: if (px == x && py == y) {
302: int r = (rgb >> 16) & 0xff;
303: int g = (rgb >> 8) & 0xff;
304: int b = (rgb) & 0xff;
305: int a = (rgb >> 24) & 0xff;
306:
307: foundBackgroundColor = new Color(r, g, b, a);
308: }
309:
310: return rgb;
311: }
312: };
313:
314: FilteredImageSource source = new FilteredImageSource(img
315: .getSource(), colorFilter);
316: iFrame.paint(img.getGraphics());
317:
318: BufferedImage img2 = new BufferedImage(img.getWidth(), img
319: .getHeight(), BufferedImage.TYPE_INT_ARGB);
320: img2.getGraphics().drawImage(
321: Toolkit.getDefaultToolkit().createImage(source), 0, 0,
322: null);
323:
324: return foundBackgroundColor;
325: }
326:
327: public DimensionProvider getSizeDimensionProvider() {
328: return skipIFrame ? null : new DimensionProvider() {
329: public Dimension getDimension(Component c) {
330: return minimumSize;
331: }
332: };
333: }
334:
335: public void paintTitleBar(Component c, Graphics g,
336: boolean selected, int width, int height, Direction d) {
337: if (enabled) {
338: View view = findView(c);
339: if (view == null)
340: return;
341:
342: setTitleAndIcon(view.getViewProperties()
343: .getViewTitleBarProperties().getNormalProperties()
344: .getTitle(), view.getViewProperties()
345: .getViewTitleBarProperties().getNormalProperties()
346: .getIcon());
347:
348: iFrame.setSelectedActivated(selected);
349:
350: setSize(width);
351:
352: Shape clip = g.getClip();
353:
354: g.clipRect(0, 0, width, reportedMinimumSize.height
355: - iFrameInsets.top - iFrameInsets.bottom);
356: g.translate(-iFrameInsets.left, -iFrameInsets.top);
357: iFrame.paint(g);
358: g.translate(iFrameInsets.left, iFrameInsets.top);
359: g.setClip(clip);
360:
361: paintSolidButtonBackground(c, g, selected);
362: }
363: }
364:
365: private void paintSolidButtonBackground(Component c, Graphics g,
366: boolean selected) {
367: ViewTitleBar bar = (ViewTitleBar) c;
368:
369: JComponent[] comps = bar.getRightTitleComponents();
370: if (comps.length > 0) {
371: int width = 0;
372:
373: for (int i = 0; i < comps.length; i++) {
374: if (comps[i].isVisible())
375: width += comps[i].getWidth();
376: }
377:
378: Color background = selected ? activeBackgroundColor
379: : inactiveBackgroundColor;
380: Color[] fadeColors = selected ? fadeSelectedColors
381: : fadeNormalColors;
382:
383: for (int i = 0; i < fadeColors.length; i++) {
384: g.setColor(fadeColors[i]);
385: int xPos = c.getWidth() - width
386: - (fadeColors.length - i) - RIGHT_INSET;
387: g.drawLine(xPos, BUTTON_OFFSET, xPos, c.getHeight() - 2
388: * BUTTON_OFFSET);
389: }
390:
391: g.setColor(background);
392: g.fillRect(c.getWidth() - width - RIGHT_INSET,
393: BUTTON_OFFSET, width + RIGHT_INSET, c.getHeight()
394: - 2 * BUTTON_OFFSET);
395: }
396: }
397:
398: private void setTitleAndIcon(String title, Icon icon) {
399: iFrame.setTitle(title);
400: iFrame.setFrameIcon(icon == null ? SizeIcon.EMPTY : icon);
401: }
402:
403: private View findView(Component c) {
404: if (c == null || c instanceof View)
405: return (View) c;
406:
407: return findView(c.getParent());
408: }
409:
410: private void setSize(int width) {
411: iFrame.setSize(width + iFrameInsets.left + iFrameInsets.right,
412: reportedMinimumSize.height);
413: iFrame.invalidate();
414: iFrame.validate();
415: }
416:
417: public boolean isRenderingIcon() {
418: return !skipIFrame;
419: }
420:
421: public boolean isRenderingTitle() {
422: return !skipIFrame;
423: }
424:
425: public Direction getRenderingDirection() {
426: return Direction.RIGHT;
427: }
428:
429: public ComponentPainter getInactiveComponentPainter() {
430: if (!skipIFrame)
431: return inactiveComponentPainter;
432:
433: Color bkg = UIManager
434: .getColor("InternalFrame.inactiveTitleBackground");
435: if (bkg == null)
436: bkg = inactiveBackgroundColor;
437:
438: return createComponentPainter(bkg, UIManager
439: .getColor("InternalFrame.inactiveTitleGradient"));
440: }
441:
442: public ComponentPainter getActiveComponentPainter() {
443: if (!skipIFrame)
444: return activeComponentPainter;
445:
446: Color bkg = UIManager
447: .getColor("InternalFrame.activeTitleBackground");
448: if (bkg == null)
449: bkg = activeBackgroundColor;
450:
451: return createComponentPainter(bkg, UIManager
452: .getColor("InternalFrame.activeTitleGradient"));
453: }
454:
455: public Insets getInsets() {
456: return skipIFrame ? new Insets(2, 2, 2, 2) : new Insets(0, 0,
457: 0, RIGHT_INSET);
458: }
459:
460: public Color getInactiveBackgroundColor() {
461: return inactiveBackgroundColor;
462: }
463:
464: public Color getActiveBackgroundColor() {
465: return activeBackgroundColor;
466: }
467:
468: private ComponentPainter createComponentPainter(
469: final Color background, final Color gradient) {
470: final Color avgColor = ColorUtil.blend(background, gradient,
471: 0.5);
472: final ComponentPainter painter = createGradientSegmentPainter(
473: background, gradient, true);
474:
475: return new ComponentPainter() {
476: public void paint(Component component, Graphics g, int x,
477: int y, int width, int height) {
478: }
479:
480: public void paint(Component component, Graphics g, int x,
481: int y, int width, int height, Direction direction,
482: boolean horizontalFlip, boolean verticalFlip) {
483: g.setColor(gradient);
484: g.drawLine(x, y, x + width - 1, y);
485: g.drawLine(x, y, x, y + height - 1);
486:
487: g.setColor(avgColor);
488: g.drawRect(x + 1, y + 1, width - 3, height - 3);
489:
490: painter.paint(component, g, x + 2, y + 2, width - 4,
491: height - 4, direction, horizontalFlip,
492: verticalFlip);
493:
494: g.setColor(background);
495: g.drawLine(x + 1, height - 1 + y, x + width - 1, height
496: - 1 + y);
497: g.drawLine(x + width - 1, y, x + width - 1, y + height
498: - 1);
499: }
500:
501: public boolean isOpaque(Component component) {
502: return painter.isOpaque(component);
503: }
504:
505: public Color getColor(Component component) {
506: return painter.getColor(component);
507: }
508: };
509: }
510:
511: private ComponentPainter createGradientSegmentPainter(
512: Color background, Color gradient, boolean flip) {
513: if (background != null) {
514: gradient = gradient == null ? background : gradient;
515: background = ColorUtil.mult(background, flip ? 1.05 : 0.90);
516: gradient = ColorUtil.mult(gradient, flip ? 0.90 : 1.05);
517:
518: return new GradientComponentPainter(background, background,
519: gradient, gradient);
520: }
521:
522: return null;
523: }
524: }
|