blob: 183ce6f45b56ac700165d5dc9dc06b3080b5d846 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
26package javax.swing.plaf.basic;
27
28import javax.swing.*;
29import javax.swing.border.*;
30import javax.swing.plaf.*;
31import javax.swing.text.JTextComponent;
32
33import java.awt.Component;
34import java.awt.Insets;
35import java.awt.Dimension;
36import java.awt.Rectangle;
37import java.awt.Color;
38import java.awt.Graphics;
39import java.io.Serializable;
40
41
42/**
43 * Factory object that can vend Borders appropriate for the basic L & F.
44 * @author Georges Saab
45 * @author Amy Fowler
46 */
47
48public class BasicBorders {
49
50 public static Border getButtonBorder() {
51 UIDefaults table = UIManager.getLookAndFeelDefaults();
52 Border buttonBorder = new BorderUIResource.CompoundBorderUIResource(
53 new BasicBorders.ButtonBorder(
54 table.getColor("Button.shadow"),
55 table.getColor("Button.darkShadow"),
56 table.getColor("Button.light"),
57 table.getColor("Button.highlight")),
58 new MarginBorder());
59 return buttonBorder;
60 }
61
62 public static Border getRadioButtonBorder() {
63 UIDefaults table = UIManager.getLookAndFeelDefaults();
64 Border radioButtonBorder = new BorderUIResource.CompoundBorderUIResource(
65 new BasicBorders.RadioButtonBorder(
66 table.getColor("RadioButton.shadow"),
67 table.getColor("RadioButton.darkShadow"),
68 table.getColor("RadioButton.light"),
69 table.getColor("RadioButton.highlight")),
70 new MarginBorder());
71 return radioButtonBorder;
72 }
73
74 public static Border getToggleButtonBorder() {
75 UIDefaults table = UIManager.getLookAndFeelDefaults();
76 Border toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
77 new BasicBorders.ToggleButtonBorder(
78 table.getColor("ToggleButton.shadow"),
79 table.getColor("ToggleButton.darkShadow"),
80 table.getColor("ToggleButton.light"),
81 table.getColor("ToggleButton.highlight")),
82 new MarginBorder());
83 return toggleButtonBorder;
84 }
85
86 public static Border getMenuBarBorder() {
87 UIDefaults table = UIManager.getLookAndFeelDefaults();
88 Border menuBarBorder = new BasicBorders.MenuBarBorder(
89 table.getColor("MenuBar.shadow"),
90 table.getColor("MenuBar.highlight")
91 );
92 return menuBarBorder;
93 }
94
95 public static Border getSplitPaneBorder() {
96 UIDefaults table = UIManager.getLookAndFeelDefaults();
97 Border splitPaneBorder = new BasicBorders.SplitPaneBorder(
98 table.getColor("SplitPane.highlight"),
99 table.getColor("SplitPane.darkShadow"));
100 return splitPaneBorder;
101 }
102
103 /**
104 * Returns a border instance for a JSplitPane divider
105 * @since 1.3
106 */
107 public static Border getSplitPaneDividerBorder() {
108 UIDefaults table = UIManager.getLookAndFeelDefaults();
109 Border splitPaneBorder = new BasicBorders.SplitPaneDividerBorder(
110 table.getColor("SplitPane.highlight"),
111 table.getColor("SplitPane.darkShadow"));
112 return splitPaneBorder;
113 }
114
115 public static Border getTextFieldBorder() {
116 UIDefaults table = UIManager.getLookAndFeelDefaults();
117 Border textFieldBorder = new BasicBorders.FieldBorder(
118 table.getColor("TextField.shadow"),
119 table.getColor("TextField.darkShadow"),
120 table.getColor("TextField.light"),
121 table.getColor("TextField.highlight"));
122 return textFieldBorder;
123 }
124
125 public static Border getProgressBarBorder() {
126 UIDefaults table = UIManager.getLookAndFeelDefaults();
127 Border progressBarBorder = new BorderUIResource.LineBorderUIResource(Color.green, 2);
128 return progressBarBorder;
129 }
130
131 public static Border getInternalFrameBorder() {
132 UIDefaults table = UIManager.getLookAndFeelDefaults();
133 Border internalFrameBorder = new BorderUIResource.CompoundBorderUIResource(
134 new BevelBorder(BevelBorder.RAISED,
135 table.getColor("InternalFrame.borderLight"),
136 table.getColor("InternalFrame.borderHighlight"),
137 table.getColor("InternalFrame.borderDarkShadow"),
138 table.getColor("InternalFrame.borderShadow")),
139 BorderFactory.createLineBorder(
140 table.getColor("InternalFrame.borderColor"), 1));
141
142 return internalFrameBorder;
143 }
144
145 /**
146 * Special thin border for rollover toolbar buttons.
147 * @since 1.4
148 */
149 public static class RolloverButtonBorder extends ButtonBorder {
150
151 public RolloverButtonBorder(Color shadow, Color darkShadow,
152 Color highlight, Color lightHighlight) {
153 super(shadow, darkShadow, highlight, lightHighlight);
154 }
155
156 public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
157 AbstractButton b = (AbstractButton) c;
158 ButtonModel model = b.getModel();
159
160 Color shade = shadow;
161 Component p = b.getParent();
162 if (p != null && p.getBackground().equals(shadow)) {
163 shade = darkShadow;
164 }
165
166 if ((model.isRollover() && !(model.isPressed() && !model.isArmed())) ||
167 model.isSelected()) {
168
169 Color oldColor = g.getColor();
170 g.translate(x, y);
171
172 if (model.isPressed() && model.isArmed() || model.isSelected()) {
173 // Draw the pressd button
174 g.setColor(shade);
175 g.drawRect(0, 0, w-1, h-1);
176 g.setColor(lightHighlight);
177 g.drawLine(w-1, 0, w-1, h-1);
178 g.drawLine(0, h-1, w-1, h-1);
179 } else {
180 // Draw a rollover button
181 g.setColor(lightHighlight);
182 g.drawRect(0, 0, w-1, h-1);
183 g.setColor(shade);
184 g.drawLine(w-1, 0, w-1, h-1);
185 g.drawLine(0, h-1, w-1, h-1);
186 }
187 g.translate(-x, -y);
188 g.setColor(oldColor);
189 }
190 }
191 }
192
193
194 /**
195 * A border which is like a Margin border but it will only honor the margin
196 * if the margin has been explicitly set by the developer.
197 *
198 * Note: This is identical to the package private class
199 * MetalBorders.RolloverMarginBorder and should probably be consolidated.
200 */
201 static class RolloverMarginBorder extends EmptyBorder {
202
203 public RolloverMarginBorder() {
204 super(3,3,3,3); // hardcoded margin for JLF requirements.
205 }
206
207 public Insets getBorderInsets(Component c, Insets insets) {
208 Insets margin = null;
209
210 if (c instanceof AbstractButton) {
211 margin = ((AbstractButton)c).getMargin();
212 }
213 if (margin == null || margin instanceof UIResource) {
214 // default margin so replace
215 insets.left = left;
216 insets.top = top;
217 insets.right = right;
218 insets.bottom = bottom;
219 } else {
220 // Margin which has been explicitly set by the user.
221 insets.left = margin.left;
222 insets.top = margin.top;
223 insets.right = margin.right;
224 insets.bottom = margin.bottom;
225 }
226 return insets;
227 }
228 }
229
230 public static class ButtonBorder extends AbstractBorder implements UIResource {
231 protected Color shadow;
232 protected Color darkShadow;
233 protected Color highlight;
234 protected Color lightHighlight;
235
236 public ButtonBorder(Color shadow, Color darkShadow,
237 Color highlight, Color lightHighlight) {
238 this.shadow = shadow;
239 this.darkShadow = darkShadow;
240 this.highlight = highlight;
241 this.lightHighlight = lightHighlight;
242 }
243
244 public void paintBorder(Component c, Graphics g, int x, int y,
245 int width, int height) {
246 boolean isPressed = false;
247 boolean isDefault = false;
248
249 if (c instanceof AbstractButton) {
250 AbstractButton b = (AbstractButton)c;
251 ButtonModel model = b.getModel();
252
253 isPressed = model.isPressed() && model.isArmed();
254
255 if (c instanceof JButton) {
256 isDefault = ((JButton)c).isDefaultButton();
257 }
258 }
259 BasicGraphicsUtils.drawBezel(g, x, y, width, height,
260 isPressed, isDefault, shadow,
261 darkShadow, highlight, lightHighlight);
262 }
263
264 public Insets getBorderInsets(Component c, Insets insets) {
265 // leave room for default visual
266 insets.set(2, 3, 3, 3);
267 return insets;
268 }
269
270 }
271
272 public static class ToggleButtonBorder extends ButtonBorder {
273
274 public ToggleButtonBorder(Color shadow, Color darkShadow,
275 Color highlight, Color lightHighlight) {
276 super(shadow, darkShadow, highlight, lightHighlight);
277 }
278
279 public void paintBorder(Component c, Graphics g, int x, int y,
280 int width, int height) {
281 BasicGraphicsUtils.drawBezel(g, x, y, width, height,
282 false, false,
283 shadow, darkShadow,
284 highlight, lightHighlight);
285 }
286
287 public Insets getBorderInsets(Component c, Insets insets) {
288 insets.set(2, 2, 2, 2);
289 return insets;
290 }
291 }
292
293 public static class RadioButtonBorder extends ButtonBorder {
294
295 public RadioButtonBorder(Color shadow, Color darkShadow,
296 Color highlight, Color lightHighlight) {
297 super(shadow, darkShadow, highlight, lightHighlight);
298 }
299
300
301 public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
302
303 if (c instanceof AbstractButton) {
304 AbstractButton b = (AbstractButton)c;
305 ButtonModel model = b.getModel();
306
307 if (model.isArmed() && model.isPressed() || model.isSelected()) {
308 BasicGraphicsUtils.drawLoweredBezel(g, x, y, width, height,
309 shadow, darkShadow,
310 highlight, lightHighlight);
311 } else {
312 BasicGraphicsUtils.drawBezel(g, x, y, width, height,
313 false, b.isFocusPainted() && b.hasFocus(),
314 shadow, darkShadow,
315 highlight, lightHighlight);
316 }
317 } else {
318 BasicGraphicsUtils.drawBezel(g, x, y, width, height, false, false,
319 shadow, darkShadow, highlight, lightHighlight);
320 }
321 }
322
323 public Insets getBorderInsets(Component c, Insets insets) {
324 insets.set(2, 2, 2, 2);
325 return insets;
326 }
327 }
328
329 public static class MenuBarBorder extends AbstractBorder implements UIResource {
330 private Color shadow;
331 private Color highlight;
332
333 public MenuBarBorder(Color shadow, Color highlight) {
334 this.shadow = shadow;
335 this.highlight = highlight;
336 }
337
338 public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
339 Color oldColor = g.getColor();
340 g.translate(x, y);
341 g.setColor(shadow);
342 g.drawLine(0, height-2, width, height-2);
343 g.setColor(highlight);
344 g.drawLine(0, height-1, width, height-1);
345 g.translate(-x,-y);
346 g.setColor(oldColor);
347 }
348
349 public Insets getBorderInsets(Component c, Insets insets) {
350 insets.set(0, 0, 2, 0);
351 return insets;
352 }
353 }
354
355 public static class MarginBorder extends AbstractBorder implements UIResource {
356 public Insets getBorderInsets(Component c, Insets insets) {
357 Insets margin = null;
358 //
359 // Ideally we'd have an interface defined for classes which
360 // support margins (to avoid this hackery), but we've
361 // decided against it for simplicity
362 //
363 if (c instanceof AbstractButton) {
364 AbstractButton b = (AbstractButton)c;
365 margin = b.getMargin();
366 } else if (c instanceof JToolBar) {
367 JToolBar t = (JToolBar)c;
368 margin = t.getMargin();
369 } else if (c instanceof JTextComponent) {
370 JTextComponent t = (JTextComponent)c;
371 margin = t.getMargin();
372 }
373 insets.top = margin != null? margin.top : 0;
374 insets.left = margin != null? margin.left : 0;
375 insets.bottom = margin != null? margin.bottom : 0;
376 insets.right = margin != null? margin.right : 0;
377
378 return insets;
379 }
380 }
381
382 public static class FieldBorder extends AbstractBorder implements UIResource {
383 protected Color shadow;
384 protected Color darkShadow;
385 protected Color highlight;
386 protected Color lightHighlight;
387
388 public FieldBorder(Color shadow, Color darkShadow,
389 Color highlight, Color lightHighlight) {
390 this.shadow = shadow;
391 this.highlight = highlight;
392 this.darkShadow = darkShadow;
393 this.lightHighlight = lightHighlight;
394 }
395
396 public void paintBorder(Component c, Graphics g, int x, int y,
397 int width, int height) {
398 BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height,
399 shadow, darkShadow,
400 highlight, lightHighlight);
401 }
402
403 public Insets getBorderInsets(Component c, Insets insets) {
404 Insets margin = null;
405 if (c instanceof JTextComponent) {
406 margin = ((JTextComponent)c).getMargin();
407 }
408 insets.top = margin != null? 2+margin.top : 2;
409 insets.left = margin != null? 2+margin.left : 2;
410 insets.bottom = margin != null? 2+margin.bottom : 2;
411 insets.right = margin != null? 2+margin.right : 2;
412
413 return insets;
414 }
415 }
416
417
418 /**
419 * Draws the border around the divider in a splitpane
420 * (when BasicSplitPaneUI is used). To get the appropriate effect, this
421 * needs to be used with a SplitPaneBorder.
422 */
423 static class SplitPaneDividerBorder implements Border, UIResource {
424 Color highlight;
425 Color shadow;
426
427 SplitPaneDividerBorder(Color highlight, Color shadow) {
428 this.highlight = highlight;
429 this.shadow = shadow;
430 }
431
432 public void paintBorder(Component c, Graphics g, int x, int y,
433 int width, int height) {
434 Component child;
435 Rectangle cBounds;
436 JSplitPane splitPane = ((BasicSplitPaneDivider)c).
437 getBasicSplitPaneUI().getSplitPane();
438 Dimension size = c.getSize();
439
440 child = splitPane.getLeftComponent();
441 // This is needed for the space between the divider and end of
442 // splitpane.
443 g.setColor(c.getBackground());
444 g.drawRect(x, y, width - 1, height - 1);
445 if(splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
446 if(child != null) {
447 g.setColor(highlight);
448 g.drawLine(0, 0, 0, size.height);
449 }
450 child = splitPane.getRightComponent();
451 if(child != null) {
452 g.setColor(shadow);
453 g.drawLine(size.width - 1, 0, size.width - 1, size.height);
454 }
455 } else {
456 if(child != null) {
457 g.setColor(highlight);
458 g.drawLine(0, 0, size.width, 0);
459 }
460 child = splitPane.getRightComponent();
461 if(child != null) {
462 g.setColor(shadow);
463 g.drawLine(0, size.height - 1, size.width,
464 size.height - 1);
465 }
466 }
467 }
468 public Insets getBorderInsets(Component c) {
469 Insets insets = new Insets(0,0,0,0);
470 if (c instanceof BasicSplitPaneDivider) {
471 BasicSplitPaneUI bspui = ((BasicSplitPaneDivider)c).
472 getBasicSplitPaneUI();
473
474 if (bspui != null) {
475 JSplitPane splitPane = bspui.getSplitPane();
476
477 if (splitPane != null) {
478 if (splitPane.getOrientation() ==
479 JSplitPane.HORIZONTAL_SPLIT) {
480 insets.top = insets.bottom = 0;
481 insets.left = insets.right = 1;
482 return insets;
483 }
484 // VERTICAL_SPLIT
485 insets.top = insets.bottom = 1;
486 insets.left = insets.right = 0;
487 return insets;
488 }
489 }
490 }
491 insets.top = insets.bottom = insets.left = insets.right = 1;
492 return insets;
493 }
494 public boolean isBorderOpaque() { return true; }
495 }
496
497
498 /**
499 * Draws the border around the splitpane. To work correctly you shoudl
500 * also install a border on the divider (property SplitPaneDivider.border).
501 */
502 public static class SplitPaneBorder implements Border, UIResource {
503 protected Color highlight;
504 protected Color shadow;
505
506 public SplitPaneBorder(Color highlight, Color shadow) {
507 this.highlight = highlight;
508 this.shadow = shadow;
509 }
510
511 public void paintBorder(Component c, Graphics g, int x, int y,
512 int width, int height) {
513 // The only tricky part with this border is that the divider is
514 // not positioned at the top (for horizontal) or left (for vert),
515 // so this border draws to where the divider is:
516 // -----------------
517 // |xxxxxxx xxxxxxx|
518 // |x --- x|
519 // |x | | x|
520 // |x |D| x|
521 // |x | | x|
522 // |x --- x|
523 // |xxxxxxx xxxxxxx|
524 // -----------------
525 // The above shows (rather excessively) what this looks like for
526 // a horizontal orientation. This border then draws the x's, with
527 // the SplitPaneDividerBorder drawing its own border.
528
529 Component child;
530 Rectangle cBounds;
531
532 JSplitPane splitPane = (JSplitPane)c;
533
534 child = splitPane.getLeftComponent();
535 // This is needed for the space between the divider and end of
536 // splitpane.
537 g.setColor(c.getBackground());
538 g.drawRect(x, y, width - 1, height - 1);
539 if(splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
540 if(child != null) {
541 cBounds = child.getBounds();
542 g.setColor(shadow);
543 g.drawLine(0, 0, cBounds.width + 1, 0);
544 g.drawLine(0, 1, 0, cBounds.height + 1);
545
546 g.setColor(highlight);
547 g.drawLine(0, cBounds.height + 1, cBounds.width + 1,
548 cBounds.height + 1);
549 }
550 child = splitPane.getRightComponent();
551 if(child != null) {
552 cBounds = child.getBounds();
553
554 int maxX = cBounds.x + cBounds.width;
555 int maxY = cBounds.y + cBounds.height;
556
557 g.setColor(shadow);
558 g.drawLine(cBounds.x - 1, 0, maxX, 0);
559 g.setColor(highlight);
560 g.drawLine(cBounds.x - 1, maxY, maxX, maxY);
561 g.drawLine(maxX, 0, maxX, maxY + 1);
562 }
563 } else {
564 if(child != null) {
565 cBounds = child.getBounds();
566 g.setColor(shadow);
567 g.drawLine(0, 0, cBounds.width + 1, 0);
568 g.drawLine(0, 1, 0, cBounds.height);
569 g.setColor(highlight);
570 g.drawLine(1 + cBounds.width, 0, 1 + cBounds.width,
571 cBounds.height + 1);
572 g.drawLine(0, cBounds.height + 1, 0, cBounds.height + 1);
573 }
574 child = splitPane.getRightComponent();
575 if(child != null) {
576 cBounds = child.getBounds();
577
578 int maxX = cBounds.x + cBounds.width;
579 int maxY = cBounds.y + cBounds.height;
580
581 g.setColor(shadow);
582 g.drawLine(0, cBounds.y - 1, 0, maxY);
583 g.drawLine(maxX, cBounds.y - 1, maxX, cBounds.y - 1);
584 g.setColor(highlight);
585 g.drawLine(0, maxY, cBounds.width + 1, maxY);
586 g.drawLine(maxX, cBounds.y, maxX, maxY);
587 }
588 }
589 }
590 public Insets getBorderInsets(Component c) {
591 return new Insets(1, 1, 1, 1);
592 }
593 public boolean isBorderOpaque() { return true; }
594 }
595
596}