39 |
package javax.swing.plaf.basic; |
package javax.swing.plaf.basic; |
40 |
|
|
41 |
import java.awt.Color; |
import java.awt.Color; |
|
import java.awt.Component; |
|
42 |
import java.awt.Dimension; |
import java.awt.Dimension; |
43 |
import java.awt.Graphics; |
import java.awt.Graphics; |
|
import java.awt.Insets; |
|
44 |
import java.awt.Polygon; |
import java.awt.Polygon; |
45 |
import java.awt.Rectangle; |
import java.awt.Rectangle; |
46 |
|
|
47 |
import javax.swing.AbstractButton; |
import javax.swing.ButtonModel; |
48 |
import javax.swing.JButton; |
import javax.swing.JButton; |
49 |
import javax.swing.SwingConstants; |
import javax.swing.SwingConstants; |
|
import javax.swing.border.Border; |
|
50 |
|
|
51 |
/** |
/** |
52 |
* This class draws simple arrow buttons for the Basic Look and Feel. |
* A button that displays an arrow (triangle) that points {@link #NORTH}, |
53 |
|
* {@link #SOUTH}, {@link #EAST} or {@link #WEST}. This button is used by |
54 |
|
* the {@link BasicComboBoxUI} class. |
55 |
|
* |
56 |
|
* @see BasicComboBoxUI#createArrowButton |
57 |
*/ |
*/ |
58 |
public class BasicArrowButton extends JButton implements SwingConstants |
public class BasicArrowButton extends JButton implements SwingConstants |
59 |
{ |
{ |
|
/** The default size of the Arrow buttons. */ |
|
|
private static int defaultSize = 12; |
|
60 |
|
|
61 |
/** The Polygon that points up. */ |
/** |
62 |
private static Polygon upIcon = new Polygon(new int[] { 0, 5, 9 }, |
* The direction that the arrow points. |
63 |
new int[] { 7, 2, 7 }, 3); |
* |
64 |
|
* @see #getDirection() |
65 |
/** The Polygon that points down. */ |
*/ |
|
private static Polygon downIcon = new Polygon(new int[] { 1, 5, 9 }, |
|
|
new int[] { 3, 7, 3 }, 3); |
|
|
|
|
|
/** The Polygon that points left. */ |
|
|
private static Polygon leftIcon = new Polygon(new int[] { 7, 3, 7 }, |
|
|
new int[] { 1, 5, 9 }, 3); |
|
|
|
|
|
/** The Polygon that points right. */ |
|
|
private static Polygon rightIcon = new Polygon(new int[] { 3, 7, 3 }, |
|
|
new int[] { 1, 5, 9 }, 3); |
|
|
|
|
|
/** The direction to point in. */ |
|
66 |
protected int direction; |
protected int direction; |
67 |
|
|
68 |
/** |
/** |
77 |
* edges of the button. |
* edges of the button. |
78 |
* This is package-private to avoid an accessor method. |
* This is package-private to avoid an accessor method. |
79 |
*/ |
*/ |
80 |
transient Color darkShadow = Color.DARK_GRAY; |
transient Color darkShadow = new Color(102, 102, 102); |
81 |
|
|
82 |
/** |
/** |
83 |
* The top and left edges of the button. |
* The top and left edges of the button. |
85 |
*/ |
*/ |
86 |
transient Color highlight = Color.WHITE; |
transient Color highlight = Color.WHITE; |
87 |
|
|
|
/** The border around the ArrowButton. */ |
|
|
private transient Border buttonBorder = new Border() |
|
|
{ |
|
|
public Insets getBorderInsets(Component c) |
|
|
{ |
|
|
return new Insets(2, 2, 2, 2); |
|
|
} |
|
|
|
|
|
public boolean isBorderOpaque() |
|
|
{ |
|
|
return true; |
|
|
} |
|
|
|
|
|
public void paintBorder(Component c, Graphics g, int x, int y, int w, |
|
|
int h) |
|
|
{ |
|
|
Color saved = g.getColor(); |
|
|
AbstractButton b = (AbstractButton) c; |
|
|
if (b.getModel().isPressed()) |
|
|
{ |
|
|
g.setColor(darkShadow); |
|
|
g.drawRect(x, y, x + w - 1, y + h - 1); |
|
|
} |
|
|
else |
|
|
{ |
|
|
g.setColor(highlight); |
|
|
g.drawLine(x + 1, y + 1, x + w - 3, y + 1); |
|
|
g.drawLine(x + 1, y + 1, x + 1, y + h - 2); |
|
|
|
|
|
g.setColor(shadow); |
|
|
g.drawLine(x + 1, y + h - 2, x + w - 1, y + h - 2); |
|
|
g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2); |
|
|
|
|
|
g.setColor(darkShadow); |
|
|
g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); |
|
|
g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); |
|
|
|
|
|
g.setColor(saved); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
88 |
/** |
/** |
89 |
* Creates a new BasicArrowButton object. |
* Creates a new <code>BasicArrowButton</code> object. |
90 |
* |
* |
91 |
* @param direction The direction the arrow points in. |
* @param direction The direction the arrow points in (one of: |
92 |
|
* {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}). |
93 |
*/ |
*/ |
94 |
public BasicArrowButton(int direction) |
public BasicArrowButton(int direction) |
95 |
{ |
{ |
96 |
super(); |
super(); |
|
setBorder(buttonBorder); |
|
97 |
setDirection(direction); |
setDirection(direction); |
98 |
} |
} |
99 |
|
|
101 |
* Creates a new BasicArrowButton object with the given colors and |
* Creates a new BasicArrowButton object with the given colors and |
102 |
* direction. |
* direction. |
103 |
* |
* |
104 |
* @param direction The direction to point in. |
* @param direction The direction to point in (one of: |
105 |
|
* {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}). |
106 |
* @param background The background color. |
* @param background The background color. |
107 |
* @param shadow The shadow color. |
* @param shadow The shadow color. |
108 |
* @param darkShadow The dark shadow color. |
* @param darkShadow The dark shadow color. |
119 |
} |
} |
120 |
|
|
121 |
/** |
/** |
122 |
* This method returns whether the focus can traverse to this component. |
* Returns whether the focus can traverse to this component. This method |
123 |
|
* always returns <code>false</code>. |
124 |
* |
* |
125 |
* @return Whether the focus can traverse to this component. |
* @return <code>false</code>. |
126 |
*/ |
*/ |
127 |
public boolean isFocusTraversable() |
public boolean isFocusTraversable() |
128 |
{ |
{ |
130 |
} |
} |
131 |
|
|
132 |
/** |
/** |
133 |
* This method returns the direction of the arrow. |
* Returns the direction of the arrow (one of: {@link #NORTH}, |
134 |
|
* {@link #SOUTH}, {@link #EAST} and {@link #WEST}). |
135 |
* |
* |
136 |
* @return The direction of the arrow. |
* @return The direction of the arrow. |
137 |
*/ |
*/ |
141 |
} |
} |
142 |
|
|
143 |
/** |
/** |
144 |
* This method changes the direction of the arrow. |
* Sets the direction of the arrow. |
145 |
* |
* |
146 |
* @param dir The new direction of the arrow. |
* @param dir The new direction of the arrow (one of: {@link #NORTH}, |
147 |
|
* {@link #SOUTH}, {@link #EAST} and {@link #WEST}). |
148 |
*/ |
*/ |
149 |
public void setDirection(int dir) |
public void setDirection(int dir) |
150 |
{ |
{ |
152 |
} |
} |
153 |
|
|
154 |
/** |
/** |
155 |
* This method paints the arrow button. The painting is delegated to the |
* Paints the arrow button. The painting is delegated to the |
156 |
* paintTriangle method. |
* paintTriangle method. |
157 |
* |
* |
158 |
* @param g The Graphics object to paint with. |
* @param g The Graphics object to paint with. |
160 |
public void paint(Graphics g) |
public void paint(Graphics g) |
161 |
{ |
{ |
162 |
super.paint(g); |
super.paint(g); |
|
Insets insets = getInsets(); |
|
163 |
Rectangle bounds = getBounds(); |
Rectangle bounds = getBounds(); |
164 |
int x = insets.left |
int size = bounds.height / 4; |
165 |
+ (bounds.width - insets.left - insets.right - defaultSize) / 2; |
int x = (bounds.width - size) / 2; |
166 |
int y = insets.top |
int y = (bounds.height - size) / 2; |
167 |
+ (bounds.height - insets.left - insets.right - defaultSize) / 2; |
ButtonModel m = getModel(); |
168 |
paintTriangle(g, x, y, defaultSize, direction, isEnabled()); |
if (m.isArmed()) |
169 |
|
{ |
170 |
|
x++; |
171 |
|
y++; |
172 |
|
} |
173 |
|
paintTriangle(g, x, y, size, direction, isEnabled()); |
174 |
} |
} |
175 |
|
|
176 |
/** The preferred size for the button. */ |
/** The preferred size for the button. */ |
184 |
= new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); |
= new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); |
185 |
|
|
186 |
/** |
/** |
187 |
* This method returns the preferred size of the arrow button. |
* Returns the preferred size of the arrow button. |
188 |
* |
* |
189 |
* @return The preferred size. |
* @return The preferred size (always 16 x 16). |
190 |
*/ |
*/ |
191 |
public Dimension getPreferredSize() |
public Dimension getPreferredSize() |
192 |
{ |
{ |
194 |
} |
} |
195 |
|
|
196 |
/** |
/** |
197 |
* This method returns the minimum size of the arrow button. |
* Returns the minimum size of the arrow button. |
198 |
* |
* |
199 |
* @return The minimum size. |
* @return The minimum size (always 5 x 5). |
200 |
*/ |
*/ |
201 |
public Dimension getMinimumSize() |
public Dimension getMinimumSize() |
202 |
{ |
{ |
204 |
} |
} |
205 |
|
|
206 |
/** |
/** |
207 |
* This method returns the maximum size of the arrow button. |
* Returns the maximum size of the arrow button. |
208 |
* |
* |
209 |
* @return The maximum size. |
* @return The maximum size. |
210 |
*/ |
*/ |
214 |
} |
} |
215 |
|
|
216 |
/** |
/** |
217 |
* The method paints a triangle with the given size and direction at the |
* Paints a triangle with the given size, location and direction. It is |
218 |
* given x and y coordinates. |
* difficult to explain the rationale behind the positioning of the triangle |
219 |
|
* relative to the given (x, y) position - by trial and error we seem to |
220 |
|
* match the behaviour of the reference implementation (which is missing a |
221 |
|
* specification for this method). |
222 |
* |
* |
223 |
* @param g The Graphics object to paint with. |
* @param g the graphics device. |
224 |
* @param x The x coordinate to paint at. |
* @param x the x-coordinate for the triangle's location. |
225 |
* @param y The y coordinate to paint at. |
* @param y the y-coordinate for the triangle's location. |
226 |
* @param size The size of the icon. |
* @param size the arrow size (depth). |
227 |
* @param direction The direction of the icon. |
* @param direction the direction of the arrow (one of: {@link #NORTH}, |
228 |
* @param isEnabled Whether it is enabled. |
* {@link #SOUTH}, {@link #EAST} and {@link #WEST}). |
229 |
|
* @param isEnabled if <code>true</code> the arrow is drawn in the enabled |
230 |
|
* state, otherwise it is drawn in the disabled state. |
231 |
*/ |
*/ |
232 |
public void paintTriangle(Graphics g, int x, int y, int size, int direction, |
public void paintTriangle(Graphics g, int x, int y, int size, int direction, |
233 |
boolean isEnabled) |
boolean isEnabled) |
234 |
{ |
{ |
235 |
Polygon arrow = null; |
Color savedColor = g.getColor(); |
236 |
switch (direction) |
switch (direction) |
237 |
{ |
{ |
238 |
case NORTH: |
case NORTH: |
239 |
arrow = upIcon; |
paintTriangleNorth(g, x, y, size, isEnabled); |
240 |
break; |
break; |
241 |
case SOUTH: |
case SOUTH: |
242 |
arrow = downIcon; |
paintTriangleSouth(g, x, y, size, isEnabled); |
243 |
break; |
break; |
|
case EAST: |
|
|
case RIGHT: |
|
|
arrow = rightIcon; |
|
|
break; |
|
|
case WEST: |
|
|
case LEFT: |
|
|
arrow = leftIcon; |
|
|
break; |
|
|
} |
|
|
|
|
|
int[] xPoints = arrow.xpoints; |
|
|
int[] yPoints = arrow.ypoints; |
|
|
int x1; |
|
|
int y1; |
|
|
int x2; |
|
|
int y2; |
|
|
x1 = y1 = x2 = y2 = 0; |
|
|
|
|
|
if (size != defaultSize) |
|
|
{ |
|
|
float scale = size * 1f / defaultSize; |
|
|
for (int i = 0; i < 3; i++) |
|
|
{ |
|
|
xPoints[i] *= scale; |
|
|
yPoints[i] *= scale; |
|
|
} |
|
|
} |
|
|
g.translate(x, y); |
|
|
|
|
|
switch (direction) |
|
|
{ |
|
|
case NORTH: |
|
|
x1 = xPoints[0] + 2; |
|
|
y1 = yPoints[0]; |
|
|
y2 = y1; |
|
|
x2 = xPoints[2] - 1; |
|
|
break; |
|
|
case SOUTH: |
|
|
x1 = xPoints[1]; |
|
|
y1 = yPoints[1]; |
|
|
x2 = xPoints[2]; |
|
|
y2 = yPoints[2]; |
|
|
break; |
|
244 |
case LEFT: |
case LEFT: |
245 |
case WEST: |
case WEST: |
246 |
x1 = xPoints[0] + 1; |
paintTriangleWest(g, x, y, size, isEnabled); |
247 |
y1 = yPoints[0] + 1; |
break; |
|
x2 = x1; |
|
|
y2 = yPoints[2] + 1; |
|
|
break; |
|
248 |
case RIGHT: |
case RIGHT: |
249 |
case EAST: |
case EAST: |
250 |
x1 = xPoints[2]; |
paintTriangleEast(g, x, y, size, isEnabled); |
251 |
y1 = yPoints[2] + 1; |
break; |
|
x2 = xPoints[1] - 1; |
|
|
y2 = yPoints[1] + 1; |
|
|
break; |
|
252 |
} |
} |
253 |
Color saved = g.getColor(); |
g.setColor(savedColor); |
254 |
|
} |
255 |
|
|
256 |
|
/** |
257 |
|
* Paints an upward-pointing triangle. This method is called by the |
258 |
|
* {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. |
259 |
|
* |
260 |
|
* @param g the graphics device. |
261 |
|
* @param x the x-coordinate for the anchor point. |
262 |
|
* @param y the y-coordinate for the anchor point. |
263 |
|
* @param size the arrow size (depth). |
264 |
|
* @param isEnabled if <code>true</code> the arrow is drawn in the enabled |
265 |
|
* state, otherwise it is drawn in the disabled state. |
266 |
|
*/ |
267 |
|
private void paintTriangleNorth(Graphics g, int x, int y, int size, |
268 |
|
boolean isEnabled) |
269 |
|
{ |
270 |
|
int tipX = x + (size - 2) / 2; |
271 |
|
int tipY = y; |
272 |
|
int baseX1 = tipX - (size - 1); |
273 |
|
int baseX2 = tipX + (size - 1); |
274 |
|
int baseY = y + (size - 1); |
275 |
|
Polygon triangle = new Polygon(); |
276 |
|
triangle.addPoint(tipX, tipY); |
277 |
|
triangle.addPoint(baseX1, baseY); |
278 |
|
triangle.addPoint(baseX2, baseY); |
279 |
if (isEnabled) |
if (isEnabled) |
280 |
{ |
{ |
281 |
g.setColor(Color.DARK_GRAY); |
g.setColor(Color.DARK_GRAY); |
282 |
|
g.fillPolygon(triangle); |
283 |
if (arrow != null) |
g.drawPolygon(triangle); |
284 |
g.fillPolygon(xPoints, yPoints, 3); |
} |
|
} |
|
285 |
else |
else |
286 |
{ |
{ |
287 |
g.setColor(Color.GRAY); |
g.setColor(Color.GRAY); |
288 |
g.fillPolygon(xPoints, yPoints, 3); |
g.fillPolygon(triangle); |
289 |
g.setColor(Color.WHITE); |
g.drawPolygon(triangle); |
290 |
g.drawLine(x1, y1, x2, y2); |
g.setColor(Color.WHITE); |
291 |
} |
g.drawLine(baseX1 + 1, baseY + 1, baseX2 + 1, baseY + 1); |
292 |
g.setColor(saved); |
} |
293 |
g.translate(-x, -y); |
} |
294 |
|
|
295 |
|
/** |
296 |
|
* Paints an downward-pointing triangle. This method is called by the |
297 |
|
* {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. |
298 |
|
* |
299 |
|
* @param g the graphics device. |
300 |
|
* @param x the x-coordinate for the anchor point. |
301 |
|
* @param y the y-coordinate for the anchor point. |
302 |
|
* @param size the arrow size (depth). |
303 |
|
* @param isEnabled if <code>true</code> the arrow is drawn in the enabled |
304 |
|
* state, otherwise it is drawn in the disabled state. |
305 |
|
*/ |
306 |
|
private void paintTriangleSouth(Graphics g, int x, int y, int size, |
307 |
|
boolean isEnabled) |
308 |
|
{ |
309 |
|
int tipX = x + (size - 2) / 2; |
310 |
|
int tipY = y + (size - 1); |
311 |
|
int baseX1 = tipX - (size - 1); |
312 |
|
int baseX2 = tipX + (size - 1); |
313 |
|
int baseY = y; |
314 |
|
Polygon triangle = new Polygon(); |
315 |
|
triangle.addPoint(tipX, tipY); |
316 |
|
triangle.addPoint(baseX1, baseY); |
317 |
|
triangle.addPoint(baseX2, baseY); |
318 |
|
if (isEnabled) |
319 |
|
{ |
320 |
|
g.setColor(Color.DARK_GRAY); |
321 |
|
g.fillPolygon(triangle); |
322 |
|
g.drawPolygon(triangle); |
323 |
|
} |
324 |
|
else |
325 |
|
{ |
326 |
|
g.setColor(Color.GRAY); |
327 |
|
g.fillPolygon(triangle); |
328 |
|
g.drawPolygon(triangle); |
329 |
|
g.setColor(Color.WHITE); |
330 |
|
g.drawLine(tipX + 1, tipY, baseX2, baseY + 1); |
331 |
|
g.drawLine(tipX + 1, tipY + 1, baseX2 + 1, baseY + 1); |
332 |
|
} |
333 |
} |
} |
334 |
|
|
335 |
|
/** |
336 |
|
* Paints a right-pointing triangle. This method is called by the |
337 |
|
* {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. |
338 |
|
* |
339 |
|
* @param g the graphics device. |
340 |
|
* @param x the x-coordinate for the anchor point. |
341 |
|
* @param y the y-coordinate for the anchor point. |
342 |
|
* @param size the arrow size (depth). |
343 |
|
* @param isEnabled if <code>true</code> the arrow is drawn in the enabled |
344 |
|
* state, otherwise it is drawn in the disabled state. |
345 |
|
*/ |
346 |
|
private void paintTriangleEast(Graphics g, int x, int y, int size, |
347 |
|
boolean isEnabled) |
348 |
|
{ |
349 |
|
int tipX = x + (size - 1); |
350 |
|
int tipY = y + (size - 2) / 2; |
351 |
|
int baseX = x; |
352 |
|
int baseY1 = tipY - (size - 1); |
353 |
|
int baseY2 = tipY + (size - 1); |
354 |
|
|
355 |
|
Polygon triangle = new Polygon(); |
356 |
|
triangle.addPoint(tipX, tipY); |
357 |
|
triangle.addPoint(baseX, baseY1); |
358 |
|
triangle.addPoint(baseX, baseY2); |
359 |
|
if (isEnabled) |
360 |
|
{ |
361 |
|
g.setColor(Color.DARK_GRAY); |
362 |
|
g.fillPolygon(triangle); |
363 |
|
g.drawPolygon(triangle); |
364 |
|
} |
365 |
|
else |
366 |
|
{ |
367 |
|
g.setColor(Color.GRAY); |
368 |
|
g.fillPolygon(triangle); |
369 |
|
g.drawPolygon(triangle); |
370 |
|
g.setColor(Color.WHITE); |
371 |
|
g.drawLine(baseX + 1, baseY2, tipX, tipY + 1); |
372 |
|
g.drawLine(baseX + 1, baseY2 + 1, tipX + 1, tipY + 1); |
373 |
|
} |
374 |
|
} |
375 |
|
|
376 |
|
/** |
377 |
|
* Paints a left-pointing triangle. This method is called by the |
378 |
|
* {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. |
379 |
|
* |
380 |
|
* @param g the graphics device. |
381 |
|
* @param x the x-coordinate for the anchor point. |
382 |
|
* @param y the y-coordinate for the anchor point. |
383 |
|
* @param size the arrow size (depth). |
384 |
|
* @param isEnabled if <code>true</code> the arrow is drawn in the enabled |
385 |
|
* state, otherwise it is drawn in the disabled state. |
386 |
|
*/ |
387 |
|
private void paintTriangleWest(Graphics g, int x, int y, int size, |
388 |
|
boolean isEnabled) |
389 |
|
{ |
390 |
|
int tipX = x; |
391 |
|
int tipY = y + (size - 2) / 2; |
392 |
|
int baseX = x + (size - 1); |
393 |
|
int baseY1 = tipY - (size - 1); |
394 |
|
int baseY2 = tipY + (size - 1); |
395 |
|
|
396 |
|
Polygon triangle = new Polygon(); |
397 |
|
triangle.addPoint(tipX, tipY); |
398 |
|
triangle.addPoint(baseX, baseY1); |
399 |
|
triangle.addPoint(baseX, baseY2); |
400 |
|
if (isEnabled) |
401 |
|
{ |
402 |
|
g.setColor(Color.DARK_GRAY); |
403 |
|
g.fillPolygon(triangle); |
404 |
|
g.drawPolygon(triangle); |
405 |
|
} |
406 |
|
else |
407 |
|
{ |
408 |
|
g.setColor(Color.GRAY); |
409 |
|
g.fillPolygon(triangle); |
410 |
|
g.drawPolygon(triangle); |
411 |
|
g.setColor(Color.WHITE); |
412 |
|
g.drawLine(baseX + 1, baseY1 + 1, baseX + 1, baseY2 + 1); |
413 |
|
} |
414 |
|
} |
415 |
|
|
416 |
} |
} |