1 /*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package javax.swing.plaf.basic;
26
27 import java.awt.Dimension;
28 import java.awt.Graphics;
29 import java.awt.Color;
30
31 import javax.swing;
32 import javax.swing.plaf.UIResource;
33
34 /**
35 * JButton object that draws a scaled Arrow in one of the cardinal directions.
36 * <p>
37 * <strong>Warning:</strong>
38 * Serialized objects of this class will not be compatible with
39 * future Swing releases. The current serialization support is
40 * appropriate for short term storage or RMI between applications running
41 * the same version of Swing. As of 1.4, support for long term storage
42 * of all JavaBeans<sup><font size="-2">TM</font></sup>
43 * has been added to the <code>java.beans</code> package.
44 * Please see {@link java.beans.XMLEncoder}.
45 *
46 * @author David Kloba
47 */
48 public class BasicArrowButton extends JButton implements SwingConstants
49 {
50 /**
51 * The direction of the arrow. One of
52 * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH},
53 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST}.
54 */
55 protected int direction;
56
57 private Color shadow;
58 private Color darkShadow;
59 private Color highlight;
60
61 /**
62 * Creates a {@code BasicArrowButton} whose arrow
63 * is drawn in the specified direction and with the specified
64 * colors.
65 *
66 * @param direction the direction of the arrow; one of
67 * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH},
68 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST}
69 * @param background the background color of the button
70 * @param shadow the color of the shadow
71 * @param darkShadow the color of the dark shadow
72 * @param highlight the color of the highlight
73 * @since 1.4
74 */
75 public BasicArrowButton(int direction, Color background, Color shadow,
76 Color darkShadow, Color highlight) {
77 super();
78 setRequestFocusEnabled(false);
79 setDirection(direction);
80 setBackground(background);
81 this.shadow = shadow;
82 this.darkShadow = darkShadow;
83 this.highlight = highlight;
84 }
85
86 /**
87 * Creates a {@code BasicArrowButton} whose arrow
88 * is drawn in the specified direction.
89 *
90 * @param direction the direction of the arrow; one of
91 * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH},
92 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST}
93 */
94 public BasicArrowButton(int direction) {
95 this(direction, UIManager.getColor("control"), UIManager.getColor("controlShadow"),
96 UIManager.getColor("controlDkShadow"), UIManager.getColor("controlLtHighlight"));
97 }
98
99 /**
100 * Returns the direction of the arrow.
101 */
102 public int getDirection() {
103 return direction;
104 }
105
106 /**
107 * Sets the direction of the arrow.
108 *
109 * @param direction the direction of the arrow; one of
110 * of {@code SwingConstants.NORTH},
111 * {@code SwingConstants.SOUTH},
112 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST}
113 */
114 public void setDirection(int direction) {
115 this.direction = direction;
116 }
117
118 public void paint(Graphics g) {
119 Color origColor;
120 boolean isPressed, isEnabled;
121 int w, h, size;
122
123 w = getSize().width;
124 h = getSize().height;
125 origColor = g.getColor();
126 isPressed = getModel().isPressed();
127 isEnabled = isEnabled();
128
129 g.setColor(getBackground());
130 g.fillRect(1, 1, w-2, h-2);
131
132 /// Draw the proper Border
133 if (getBorder() != null && !(getBorder() instanceof UIResource)) {
134 paintBorder(g);
135 } else if (isPressed) {
136 g.setColor(shadow);
137 g.drawRect(0, 0, w-1, h-1);
138 } else {
139 // Using the background color set above
140 g.drawLine(0, 0, 0, h-1);
141 g.drawLine(1, 0, w-2, 0);
142
143 g.setColor(highlight); // inner 3D border
144 g.drawLine(1, 1, 1, h-3);
145 g.drawLine(2, 1, w-3, 1);
146
147 g.setColor(shadow); // inner 3D border
148 g.drawLine(1, h-2, w-2, h-2);
149 g.drawLine(w-2, 1, w-2, h-3);
150
151 g.setColor(darkShadow); // black drop shadow __|
152 g.drawLine(0, h-1, w-1, h-1);
153 g.drawLine(w-1, h-1, w-1, 0);
154 }
155
156 // If there's no room to draw arrow, bail
157 if(h < 5 || w < 5) {
158 g.setColor(origColor);
159 return;
160 }
161
162 if (isPressed) {
163 g.translate(1, 1);
164 }
165
166 // Draw the arrow
167 size = Math.min((h - 4) / 3, (w - 4) / 3);
168 size = Math.max(size, 2);
169 paintTriangle(g, (w - size) / 2, (h - size) / 2,
170 size, direction, isEnabled);
171
172 // Reset the Graphics back to it's original settings
173 if (isPressed) {
174 g.translate(-1, -1);
175 }
176 g.setColor(origColor);
177
178 }
179
180 /**
181 * Returns the preferred size of the {@code BasicArrowButton}.
182 *
183 * @return the preferred size
184 */
185 public Dimension getPreferredSize() {
186 return new Dimension(16, 16);
187 }
188
189 /**
190 * Returns the minimum size of the {@code BasicArrowButton}.
191 *
192 * @return the minimum size
193 */
194 public Dimension getMinimumSize() {
195 return new Dimension(5, 5);
196 }
197
198 /**
199 * Returns the maximum size of the {@code BasicArrowButton}.
200 *
201 * @return the maximum size
202 */
203 public Dimension getMaximumSize() {
204 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
205 }
206
207 /**
208 * Returns whether the arrow button should get the focus.
209 * {@code BasicArrowButton}s are used as a child component of
210 * composite components such as {@code JScrollBar} and
211 * {@code JComboBox}. Since the composite component typically gets the
212 * focus, this method is overriden to return {@code false}.
213 *
214 * @return {@code false}
215 */
216 public boolean isFocusTraversable() {
217 return false;
218 }
219
220 /**
221 * Paints a triangle.
222 *
223 * @param g the {@code Graphics} to draw to
224 * @param x the x coordinate
225 * @param y the y coordinate
226 * @param size the size of the triangle to draw
227 * @param direction the direction in which to draw the arrow;
228 * one of {@code SwingConstants.NORTH},
229 * {@code SwingConstants.SOUTH}, {@code SwingConstants.EAST} or
230 * {@code SwingConstants.WEST}
231 * @param isEnabled whether or not the arrow is drawn enabled
232 */
233 public void paintTriangle(Graphics g, int x, int y, int size,
234 int direction, boolean isEnabled) {
235 Color oldColor = g.getColor();
236 int mid, i, j;
237
238 j = 0;
239 size = Math.max(size, 2);
240 mid = (size / 2) - 1;
241
242 g.translate(x, y);
243 if(isEnabled)
244 g.setColor(darkShadow);
245 else
246 g.setColor(shadow);
247
248 switch(direction) {
249 case NORTH:
250 for(i = 0; i < size; i++) {
251 g.drawLine(mid-i, i, mid+i, i);
252 }
253 if(!isEnabled) {
254 g.setColor(highlight);
255 g.drawLine(mid-i+2, i, mid+i, i);
256 }
257 break;
258 case SOUTH:
259 if(!isEnabled) {
260 g.translate(1, 1);
261 g.setColor(highlight);
262 for(i = size-1; i >= 0; i--) {
263 g.drawLine(mid-i, j, mid+i, j);
264 j++;
265 }
266 g.translate(-1, -1);
267 g.setColor(shadow);
268 }
269
270 j = 0;
271 for(i = size-1; i >= 0; i--) {
272 g.drawLine(mid-i, j, mid+i, j);
273 j++;
274 }
275 break;
276 case WEST:
277 for(i = 0; i < size; i++) {
278 g.drawLine(i, mid-i, i, mid+i);
279 }
280 if(!isEnabled) {
281 g.setColor(highlight);
282 g.drawLine(i, mid-i+2, i, mid+i);
283 }
284 break;
285 case EAST:
286 if(!isEnabled) {
287 g.translate(1, 1);
288 g.setColor(highlight);
289 for(i = size-1; i >= 0; i--) {
290 g.drawLine(j, mid-i, j, mid+i);
291 j++;
292 }
293 g.translate(-1, -1);
294 g.setColor(shadow);
295 }
296
297 j = 0;
298 for(i = size-1; i >= 0; i--) {
299 g.drawLine(j, mid-i, j, mid+i);
300 j++;
301 }
302 break;
303 }
304 g.translate(-x, -y);
305 g.setColor(oldColor);
306 }
307
308 }