001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.swing.tabcontrol.plaf;
043:
044: import java.awt.Color;
045: import java.awt.Dimension;
046: import java.awt.FontMetrics;
047: import java.awt.Graphics;
048: import java.awt.Graphics2D;
049: import java.awt.Insets;
050: import java.awt.geom.AffineTransform;
051: import javax.swing.AbstractButton;
052: import javax.swing.BorderFactory;
053: import javax.swing.Icon;
054: import javax.swing.JComponent;
055: import javax.swing.plaf.ComponentUI;
056: import javax.swing.plaf.basic.BasicToggleButtonUI;
057: import org.netbeans.swing.tabcontrol.TabDisplayer;
058: import org.openide.awt.HtmlRenderer;
059:
060: /**
061: * Button UI that can paint rotated text, which is used by {@link BasicSlidingTabDisplayerUI}.
062: * Uses the lightweight HTML renderer for good performance when rendering HTML strings. It is
063: * intended as a UI for {@link BasicSlidingTabDisplayerUI.IndexButton}. Provide a subclass
064: * of this class via UIDefaults to change the painting behavior or appearance of the tab buttons in
065: * "sliding" style tabbed controls. Typically the only method of interest when
066: * subclassing is {@link #paintBackground}.
067: * <p>
068: * As with its superclass {@link BasicToggleButtonUI}, instances of this class should be stateless,
069: * such that a single instance can manage any number of buttons.
070: *
071: * @see BasicSlidingTabDisplayerUI
072: * @see org.netbeans.swing.tabcontrol.TabbedContainer#TYPE_SLIDING
073: * @author Tim Boudreau
074: */
075: public class SlidingTabDisplayerButtonUI extends BasicToggleButtonUI {
076: private static final SlidingTabDisplayerButtonUI INSTANCE = new SlidingTabDisplayerButtonUI();
077:
078: /** Creates a new instance of SlidingTabDisplayerButtonUI */
079: private SlidingTabDisplayerButtonUI() {
080: }
081:
082: public static ComponentUI createUI(JComponent c) {
083: return INSTANCE;
084: }
085:
086: /** Overridden to not install keyboard actions (the buttons aren't focusable
087: * anyway) and not invoke the overhead of BasicHTML */
088: public void installUI(JComponent c) {
089: installDefaults((AbstractButton) c);
090: installListeners((AbstractButton) c);
091: installBorder((AbstractButton) c);
092: }
093:
094: /** Install a border on the button */
095: protected void installBorder(AbstractButton b) {
096: b.setBorder(BorderFactory.createEtchedBorder());
097: }
098:
099: /** Overridden to not uninstall keyboard actions (the buttons aren't focusable
100: * anyway) and not invoke the overhead of BasicHTML */
101: public void uninstallUI(JComponent c) {
102: uninstallListeners((AbstractButton) c);
103: uninstallDefaults((AbstractButton) c);
104: }
105:
106: /** Overridden to not call super.installDefaults() and only set the button
107: * to be non-focusable */
108: public void installDefaults(AbstractButton b) {
109: b.setFocusable(false);
110: }
111:
112: public Dimension getMinimumSize(JComponent c) {
113: return getPreferredSize(c);
114: }
115:
116: public Dimension getPreferredSize(JComponent c) {
117: return null; //Layout manager handles this anyway, nobody should ask for it
118: }
119:
120: public Dimension getMaximumSize(JComponent c) {
121: return getPreferredSize(c);
122: }
123:
124: /** Provides the painting logic. Note that this does not call any of the
125: * painting methods of BasicToggleButtonUI */
126: public final void paint(Graphics g, JComponent c) {
127:
128: BasicSlidingTabDisplayerUI.IndexButton b = (BasicSlidingTabDisplayerUI.IndexButton) c;
129:
130: Graphics2D g2d = (Graphics2D) g;
131:
132: paintBackground(g2d, b);
133:
134: Object orientation = b.getOrientation();
135:
136: AffineTransform tr = g2d.getTransform();
137: if (orientation == TabDisplayer.ORIENTATION_EAST) {
138: g2d.rotate(Math.PI / 2);
139: g2d.translate(0, -c.getWidth());
140: } else if (orientation == TabDisplayer.ORIENTATION_WEST) {
141: g2d.rotate(-Math.PI / 2);
142: g2d.translate(-c.getHeight(), 0);
143: }
144:
145: paintIconAndText(g2d, b, orientation);
146: g2d.setTransform(tr);
147: }
148:
149: /** Paints the tab background */
150: protected void paintBackground(Graphics2D g,
151: BasicSlidingTabDisplayerUI.IndexButton b) {
152: Color c = b.isSelected() ? Color.ORANGE : b.getBackground();
153: g.setColor(c);
154: g.fillRect(0, 0, b.getWidth(), b.getHeight());
155: }
156:
157: /** Paints the icon and text using the HTML mini renderer */
158: protected final void paintIconAndText(Graphics2D g,
159: BasicSlidingTabDisplayerUI.IndexButton b, Object orientation) {
160: FontMetrics fm = g.getFontMetrics(b.getFont());
161: Insets ins = b.getInsets();
162:
163: boolean flip = orientation == TabDisplayer.ORIENTATION_EAST
164: || orientation == TabDisplayer.ORIENTATION_WEST;
165:
166: int txtX = flip ? ins.top : ins.left;
167:
168: int txtY = orientation == TabDisplayer.ORIENTATION_EAST ? ins.right
169: : orientation == TabDisplayer.ORIENTATION_WEST ? ins.left
170: : ins.top;
171:
172: int txtW = flip ? b.getHeight() - (ins.top + ins.bottom) : b
173: .getWidth()
174: - (ins.left + ins.right);
175:
176: int iconX = txtX;
177: int iconY = txtY;
178:
179: int txtH = fm.getHeight();
180: txtY += fm.getMaxAscent();
181:
182: Icon icon = b.getIcon();
183:
184: int iconH = icon.getIconHeight();
185: int iconW = icon.getIconWidth();
186:
187: int workingHeight;
188: if (flip) {
189: workingHeight = b.getWidth() - (ins.left + ins.right);
190: } else {
191: workingHeight = b.getHeight() - (ins.top + ins.bottom);
192: }
193: txtY += (workingHeight / 2) - (txtH / 2);
194: iconY += (workingHeight / 2) - (iconH / 2);
195:
196: if (icon != null && iconW > 0 && iconH > 0) {
197: txtX += iconW + b.getIconTextGap();
198: icon.paintIcon(b, g, iconX, iconY);
199: txtW -= iconH + b.getIconTextGap();
200: }
201:
202: HtmlRenderer.renderString(b.getText(), g, txtX, txtY, txtW,
203: txtH, b.getFont(), b.getForeground(),
204: HtmlRenderer.STYLE_TRUNCATE, true);
205: }
206:
207: private static SlidingTabDisplayerButtonUI AQUA_INSTANCE = null;
208:
209: /** Aqua ui for sliding buttons. This class is public so it can be
210: * instantiated by UIManager, but is of no interest as API. */
211: public static final class Aqua extends SlidingTabDisplayerButtonUI {
212: public static ComponentUI createUI(JComponent c) {
213: if (AQUA_INSTANCE == null) {
214: AQUA_INSTANCE = new Aqua();
215: }
216: return AQUA_INSTANCE;
217: }
218:
219: protected void installBorder(AbstractButton b) {
220: b.setBorder(BorderFactory.createEmptyBorder(5, 2, 2, 2));
221: }
222:
223: protected void paintBackground(Graphics2D g,
224: BasicSlidingTabDisplayerUI.IndexButton b) {
225: GenericGlowingChiclet chic = GenericGlowingChiclet.INSTANCE;
226: int state = 0;
227: state |= b.isSelected() ? chic.STATE_SELECTED : 0;
228: state |= b.getModel().isPressed() ? chic.STATE_PRESSED : 0;
229: state |= b.isActive() ? chic.STATE_ACTIVE : 0;
230:
231: chic.setState(state);
232: chic.setArcs(0.2f, 0.2f, 0.2f, 0.2f);
233: chic.setBounds(0, 1, b.getWidth(), b.getHeight());
234: chic.setAllowVertical(true);
235: chic.draw(g);
236: chic.setAllowVertical(false);
237: }
238: }
239: }
|