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: * MetalEditorTabCellRenderer.java
043: *
044: * Created on December 2, 2003, 9:30 PM
045: */
046:
047: package org.netbeans.swing.tabcontrol.plaf;
048:
049: import javax.swing.*;
050: import java.awt.*;
051:
052: /**
053: * Renderer for editor tabs in metal l&f
054: *
055: * @author Tim Boudreau
056: */
057: class MetalEditorTabCellRenderer extends AbstractTabCellRenderer {
058: private static final MetalTabPainter metalborder = new MetalTabPainter();
059: private static final MetalRightClippedTabPainter rightBorder = new MetalRightClippedTabPainter();
060: private static final MetalLeftClippedTabPainter leftBorder = new MetalLeftClippedTabPainter();
061:
062: static final Color ATTENTION_COLOR = new Color(255, 238, 120);
063:
064: /**
065: * Creates a new instance of MetalEditorTabCellRenderer
066: */
067: public MetalEditorTabCellRenderer() {
068: super (leftBorder, metalborder, rightBorder, new Dimension(34,
069: 29));
070: setBorder(metalborder);
071: }
072:
073: protected int getCaptionYAdjustment() {
074: return 0;
075: }
076:
077: public Dimension getPadding() {
078: Dimension d = super .getPadding();
079: d.width = isShowCloseButton()
080: && !Boolean.getBoolean("nb.tabs.suppressCloseButton") ? 34
081: : 24;
082: return d;
083: }
084:
085: private static class MetalTabPainter implements TabPainter {
086: public Insets getBorderInsets(Component c) {
087: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
088: return new Insets(mtr.isSelected() ? 3 : 5, mtr
089: .isSelected() ? 10 : 9, 1, 0); //XXX
090: }
091:
092: public boolean supportsCloseButton(JComponent renderer) {
093: return ((AbstractTabCellRenderer) renderer)
094: .isShowCloseButton();
095: }
096:
097: public boolean isBorderOpaque() {
098: return true;
099: }
100:
101: public void paintBorder(Component c, Graphics g, int x, int y,
102: int width, int height) {
103: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
104: Polygon p = getInteriorPolygon(c);
105:
106: //Draw the highlight first, one pixel over, to get the left side and
107: //diagonal highlight (the right edge will get cut off, as we want)
108: g.setColor(UIManager.getColor("controlHighlight")); //NOI18N
109: g.drawPolygon(p);
110: p.translate(-1, 0);
111: Insets ins = getBorderInsets(c);
112: g.drawLine(x + 6, y + ins.top + 1, x + width - 1, y
113: + ins.top + 1);
114:
115: if (mtr.isSelected()) {
116: //draw the dark portion of the drag texture dots
117: g.drawLine(4, ins.top + 6, 4, ins.top + 6);
118: g.drawLine(2, ins.top + 8, 2, ins.top + 8);
119:
120: g.drawLine(4, ins.top + 10, 4, ins.top + 10);
121: g.drawLine(2, ins.top + 12, 2, ins.top + 12);
122:
123: g.drawLine(4, ins.top + 14, 4, ins.top + 14);
124: g.drawLine(2, ins.top + 16, 2, ins.top + 16);
125: }
126:
127: //Draw the dark polygon
128: g.setColor(UIManager.getColor("controlDkShadow")); //NOI18N
129: g.drawPolygon(p);
130:
131: if (mtr.isSelected()) {
132: //draw the dark portion of the drag texture dots
133: g.drawLine(5, ins.top + 7, 5, ins.top + 7);
134: g.drawLine(3, ins.top + 9, 3, ins.top + 9);
135:
136: g.drawLine(5, ins.top + 11, 5, ins.top + 11);
137: g.drawLine(3, ins.top + 13, 3, ins.top + 13);
138:
139: g.drawLine(5, ins.top + 15, 5, ins.top + 15);
140: g.drawLine(3, ins.top + 17, 3, ins.top + 17);
141: }
142:
143: if (!mtr.isSelected()) {
144: g.setColor(UIManager.getColor("controlDkShadow")); //NOI18N
145: g.drawLine(x, mtr.getHeight() - 1, mtr.getWidth() - 1,
146: mtr.getHeight() - 1);
147: }
148: }
149:
150: public Polygon getInteriorPolygon(Component c) {
151: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
152:
153: Insets ins = getBorderInsets(c);
154: Polygon p = new Polygon();
155: int x = mtr.isLeftmost() ? 1 : 0;
156: int y = 0;
157:
158: int width = mtr.isLeftmost() ? c.getWidth() - 1 : c
159: .getWidth();
160: int height = mtr.isSelected() ? c.getHeight() + 3 : c
161: .getHeight();
162:
163: p.addPoint(x, y + ins.top + 6);
164: p.addPoint(x + 6, y + ins.top);
165: p.addPoint(x + width, y + ins.top);
166: p.addPoint(x + width, y + height);
167: p.addPoint(x, y + height);
168: return p;
169: }
170:
171: public void paintInterior(Graphics g, Component c) {
172: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
173:
174: if (mtr.isAttention()) {
175: g.setColor(ATTENTION_COLOR);
176: }
177:
178: Polygon p = getInteriorPolygon(c);
179: g.fillPolygon(p);
180:
181: //Get the close button bounds, more or less
182: Rectangle r = new Rectangle();
183: getCloseButtonRectangle(mtr, r, new Rectangle(0, 0, mtr
184: .getWidth(), mtr.getHeight()));
185:
186: if (!g.hitClip(r.x, r.y, r.width, r.height)) {
187: return;
188: }
189: paintCloseButton(g, (JComponent) c);
190: }
191:
192: public void getCloseButtonRectangle(JComponent jc,
193: final Rectangle rect, Rectangle bounds) {
194: if (!((AbstractTabCellRenderer) jc).isShowCloseButton()) {
195: rect.x = -100;
196: rect.y = -100;
197: rect.width = 0;
198: rect.height = 0;
199: return;
200: }
201: String iconPath = findIconPath((MetalEditorTabCellRenderer) jc);
202: Icon icon = TabControlButtonFactory.getIcon(iconPath);
203: int iconWidth = icon.getIconWidth();
204: int iconHeight = icon.getIconHeight();
205: rect.x = bounds.x + bounds.width - iconWidth - 2;
206: rect.y = bounds.y
207: + (Math.max(0, bounds.height / 2 - iconHeight / 2))
208: + 2;
209: rect.width = iconWidth;
210: rect.height = iconHeight;
211: }
212:
213: private void paintCloseButton(Graphics g, JComponent c) {
214: if (((AbstractTabCellRenderer) c).isShowCloseButton()) {
215:
216: Rectangle r = new Rectangle(0, 0, c.getWidth(), c
217: .getHeight());
218: Rectangle cbRect = new Rectangle();
219: getCloseButtonRectangle((JComponent) c, cbRect, r);
220:
221: //paint close button
222: String iconPath = findIconPath((MetalEditorTabCellRenderer) c);
223: Icon icon = TabControlButtonFactory.getIcon(iconPath);
224: icon.paintIcon(c, g, cbRect.x, cbRect.y);
225: }
226: }
227:
228: /**
229: * Returns path of icon which is correct for currect state of tab at given
230: * index
231: */
232: private String findIconPath(MetalEditorTabCellRenderer renderer) {
233: if (renderer.inCloseButton() && renderer.isPressed()) {
234: return "org/netbeans/swing/tabcontrol/resources/metal_close_pressed.png"; // NOI18N
235: }
236: if (renderer.inCloseButton()) {
237: return "org/netbeans/swing/tabcontrol/resources/metal_close_rollover.png"; // NOI18N
238: }
239: return "org/netbeans/swing/tabcontrol/resources/metal_close_enabled.png"; // NOI18N
240: }
241: }
242:
243: private static class MetalLeftClippedTabPainter implements
244: TabPainter {
245:
246: public Insets getBorderInsets(Component c) {
247: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
248: return new Insets(mtr.isSelected() ? 3 : 5, mtr
249: .isSelected() ? 10 : 9, 1, 0); //XXX
250: }
251:
252: public boolean isBorderOpaque() {
253: return true;
254: }
255:
256: public Polygon getInteriorPolygon(Component c) {
257: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
258:
259: Insets ins = getBorderInsets(c);
260: Polygon p = new Polygon();
261: //Ensure the left edge is out of bounds
262: int x = -1;
263: int y = ins.top;
264:
265: int width = c.getWidth();
266: int height = mtr.isSelected() ? c.getHeight() + 3 : c
267: .getHeight();
268:
269: p.addPoint(x, y);
270: p.addPoint(x + width, y);
271: p.addPoint(x + width, y + height);
272: p.addPoint(x, y + height);
273:
274: return p;
275: }
276:
277: public void paintBorder(Component c, Graphics g, int x, int y,
278: int width, int height) {
279: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
280: g.setColor(UIManager.getColor("controlHighlight")); //NOI18N
281: Polygon p = getInteriorPolygon(c);
282:
283: p.translate(0, 1);
284: g.drawPolygon(p);
285: p.translate(0, -1);
286: g.setColor(UIManager.getColor("controlDkShadow")); //NOI18N
287: g.drawPolygon(p);
288: if (!mtr.isSelected()) {
289: g
290: .drawLine(x, y + height - 1, x + width, y
291: + height - 1);
292: }
293: }
294:
295: public void paintInterior(Graphics g, Component c) {
296: Polygon p = getInteriorPolygon(c);
297: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
298: if (mtr.isAttention()) {
299: g.setColor(ATTENTION_COLOR);
300: }
301:
302: g.fillPolygon(p);
303: }
304:
305: public void getCloseButtonRectangle(JComponent jc,
306: Rectangle rect, Rectangle bounds) {
307: bounds.setBounds(-20, -20, 0, 0);
308: }
309:
310: public boolean supportsCloseButton(JComponent renderer) {
311: return false;
312: }
313: }
314:
315: private static class MetalRightClippedTabPainter implements
316: TabPainter {
317: public Insets getBorderInsets(Component c) {
318: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
319: return new Insets(mtr.isSelected() ? 3 : 5, mtr
320: .isSelected() ? 10 : 9, 1, 0); //XXX
321: }
322:
323: public boolean isBorderOpaque() {
324: return true;
325: }
326:
327: public Polygon getInteriorPolygon(Component c) {
328: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
329:
330: Insets ins = getBorderInsets(c);
331: Polygon p = new Polygon();
332: int x = mtr.isLeftmost() ? 1 : 0;
333: int y = 0;
334:
335: int width = c.getWidth() + 2;
336: int height = mtr.isSelected() ? c.getHeight() + 3 : c
337: .getHeight();
338:
339: p.addPoint(x, y + ins.top + 6);
340: p.addPoint(x + 6, y + ins.top);
341: p.addPoint(x + width, y + ins.top);
342: p.addPoint(x + width, y + height);
343: p.addPoint(x, y + height);
344: return p;
345: }
346:
347: public void paintBorder(Component c, Graphics g, int x, int y,
348: int width, int height) {
349: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
350: Polygon p = getInteriorPolygon(c);
351:
352: //Draw the highlight first, one pixel over, to get the left side and
353: //diagonal highlight (the right edge will get cut off, as we want)
354: g.setColor(UIManager.getColor("controlHighlight")); //NOI18N
355: g.drawPolygon(p);
356: p.translate(-1, 0);
357: Insets ins = getBorderInsets(c);
358: g.drawLine(x + 6, y + ins.top + 1, x + width - 1, y
359: + ins.top + 1);
360:
361: if (mtr.isSelected()) {
362: //draw the light portion of the drag texture dots
363: g.drawLine(4, ins.top + 6, 4, ins.top + 6);
364: g.drawLine(2, ins.top + 8, 2, ins.top + 8);
365:
366: g.drawLine(4, ins.top + 10, 4, ins.top + 10);
367: g.drawLine(2, ins.top + 12, 2, ins.top + 12);
368:
369: g.drawLine(4, ins.top + 14, 4, ins.top + 14);
370: g.drawLine(2, ins.top + 16, 2, ins.top + 16);
371: }
372:
373: //Draw the dark polygon
374: g.setColor(UIManager.getColor("controlDkShadow")); //NOI18N
375: g.drawPolygon(p);
376:
377: if (mtr.isSelected()) {
378: //draw the dark portion of the drag texture dots
379: g.drawLine(5, ins.top + 7, 5, ins.top + 7);
380: g.drawLine(3, ins.top + 9, 3, ins.top + 9);
381:
382: g.drawLine(5, ins.top + 11, 5, ins.top + 11);
383: g.drawLine(3, ins.top + 13, 3, ins.top + 13);
384:
385: g.drawLine(5, ins.top + 15, 5, ins.top + 15);
386: g.drawLine(3, ins.top + 17, 3, ins.top + 17);
387: }
388:
389: if (!mtr.isSelected()) {
390: g.setColor(UIManager.getColor("controlDkShadow")); //NOI18N
391: g.drawLine(x, c.getHeight() - 1, c.getWidth() - 1, c
392: .getHeight() - 1);
393: }
394: }
395:
396: public void paintInterior(Graphics g, Component c) {
397: Polygon p = getInteriorPolygon(c);
398: MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c;
399: if (mtr.isAttention()) {
400: g.setColor(ATTENTION_COLOR);
401: }
402: g.fillPolygon(p);
403: }
404:
405: public void getCloseButtonRectangle(JComponent jc,
406: Rectangle rect, Rectangle bounds) {
407: bounds.setBounds(-20, -20, 0, 0);
408: }
409:
410: public boolean supportsCloseButton(JComponent renderer) {
411: return false;
412: }
413: }
414: }
|