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: package org.netbeans.swing.plaf.gtk;
042:
043: import javax.swing.*;
044: import javax.swing.border.Border;
045: import java.awt.*;
046:
047: /**
048: * A matte border with a few twists - can do drop shadow; also, for toolbars,
049: * will check the position of the component and return taller insets for the
050: * top row, so it's offset from the menu, but not present a doubled border
051: * for lower rows; same thing for toolbars adjacent to each other.
052: *
053: * @author Tim Boudreau
054: */
055: public class AdaptiveMatteBorder implements Border {
056: private Insets insets;
057: private int shadowDepth;
058: private boolean topLeftInsets;
059:
060: /** Creates a new instance of AdaptiveMatteBorder */
061: public AdaptiveMatteBorder(boolean t, boolean l, boolean b,
062: boolean r, int shadowDepth, boolean topLeftInsets) {
063: insets = new Insets(
064: t ? topLeftInsets ? shadowDepth + 1 : 1 : 0,
065: l ? topLeftInsets ? shadowDepth + 1 : 1 : 0,
066: b ? 1 + shadowDepth : shadowDepth, r ? 1 + shadowDepth
067: : shadowDepth);
068: this .shadowDepth = shadowDepth;
069: this .topLeftInsets = topLeftInsets;
070: }
071:
072: public AdaptiveMatteBorder(boolean t, boolean l, boolean b,
073: boolean r, int shadowDepth) {
074: this (t, l, b, r, shadowDepth, false);
075: }
076:
077: private Insets maybeOmitInsets(Insets ins, Component c) {
078: if (shadowDepth <= 0 || !topLeftInsets) {
079: return ins;
080: }
081: Insets result = new Insets(ins.top, ins.left, ins.right,
082: ins.bottom);
083: if (topLeftInsets) {
084: Point p = c.getLocation();
085: if (p.x > 10) {
086: result.left = 1;
087: }
088: if (p.y > 10) {
089: result.top = 1;
090: }
091: }
092: return result;
093: }
094:
095: public Insets getBorderInsets(Component c) {
096: return maybeOmitInsets(insets, c);
097: }
098:
099: public boolean isBorderOpaque() {
100: return false;
101: }
102:
103: public void paintBorder(Component c, Graphics g, int x, int y,
104: int w, int h) {
105: Color color = g.getColor();
106: Insets ins = getBorderInsets(c);
107: Point p = c.getLocation();
108:
109: //This will always really come from the theme on GTK
110: g.setColor(UIManager.getColor("controlShadow")); //NOI18N
111: w -= shadowDepth;
112: h -= shadowDepth;
113: if (topLeftInsets) {
114: if (p.y <= 10) {
115: y += shadowDepth;
116: h -= shadowDepth;
117: }
118: if (p.x <= 10) {
119: x += shadowDepth;
120: w -= shadowDepth;
121: }
122: }
123: if (ins.top > 0) {
124: g.fillRect(x, y, w, 1);
125: }
126: if (ins.left > 0) {
127: g.fillRect(x, y, 1, h);
128: }
129: if (ins.right > 0) {
130: g.fillRect(x + w - 1, y, 1, h);
131: }
132: if (ins.bottom > 0) {
133: g.fillRect(x, y + h - 1, w, 1);
134: }
135:
136: boolean isViewTab = isViewTab(c);
137:
138: if (shadowDepth > 1) {
139: Rectangle clip = g.getClipBounds();
140: boolean clipTouchesRight = ((clip.x + clip.width) >= (x + w));
141: boolean clipTouchesBottom = ((clip.y + clip.height) >= (y + h));
142:
143: if (clipTouchesBottom || clipTouchesRight) {
144: Color ctrl = UIManager.getColor("control"); //NOI18N
145: Color base = UIManager.getColor("controlShadow");
146:
147: Color curr;
148: for (int i = 1; i < shadowDepth; i++) {
149: curr = colorTowards(base, ctrl, shadowDepth, i + 1);
150: g.setColor(curr);
151: if (clipTouchesRight && ins.right > 0) {
152: g.fillRect(x + w - 1 + i, y
153: + (isViewTab ? 0 : i), 1, h);
154: }
155: if (clipTouchesBottom && ins.bottom > 0) {
156: g.fillRect(x + i, y + h - 1 + i, w - 1, 1);
157: }
158: }
159: }
160: }
161: g.setColor(color);
162: }
163:
164: // private static int[] xpoints = new int[4];
165: // private static int[] ypoints = new int[4];
166:
167: static boolean isViewTab(Component c) {
168: if (c.getParent() instanceof JComponent) {
169: JComponent jc = (JComponent) c.getParent();
170: Object o = jc.getClientProperty("viewType");
171: if (o != null && o instanceof Integer) {
172: return ((Integer) o).intValue() == 0;
173: }
174: }
175: return false;
176: }
177:
178: private static final float[] comps = new float[4];
179: private static final float[] targs = new float[4];
180:
181: static final Color colorTowards(Color base, Color target,
182: float steps, float step) {
183: base.getColorComponents(comps);
184: target.getColorComponents(targs);
185:
186: comps[3] = 1.0f; //No transparency, performance problems
187:
188: float factor = (step / steps);
189:
190: for (int i = 0; i < 3; i++) {
191: comps[i] = saturate(comps[i]
192: - (factor * (comps[i] - targs[i])));
193: }
194:
195: // comps[3] = 1f - (step / steps);
196: Color result = new Color(comps[0], comps[1], comps[2], comps[3]);
197: return result;
198: }
199:
200: private static final float saturate(float f) {
201: float orig = f;
202: if (f > 1) {
203: f = 1;
204: }
205: if (f < 0) {
206: f = 0;
207: }
208: return f;
209: }
210:
211: }
|