001 /*
002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.swing.plaf.basic;
027
028 import javax.swing.*;
029 import javax.swing.border.*;
030 import javax.swing.plaf.*;
031 import javax.swing.text.JTextComponent;
032
033 import java.awt.Component;
034 import java.awt.Insets;
035 import java.awt.Dimension;
036 import java.awt.Rectangle;
037 import java.awt.Color;
038 import java.awt.Graphics;
039 import java.io.Serializable;
040
041 /**
042 * Factory object that can vend Borders appropriate for the basic L & F.
043 * @version 1.42 05/05/07
044 * @author Georges Saab
045 * @author Amy Fowler
046 */
047
048 public class BasicBorders {
049
050 public static Border getButtonBorder() {
051 UIDefaults table = UIManager.getLookAndFeelDefaults();
052 Border buttonBorder = new BorderUIResource.CompoundBorderUIResource(
053 new BasicBorders.ButtonBorder(table
054 .getColor("Button.shadow"), table
055 .getColor("Button.darkShadow"), table
056 .getColor("Button.light"), table
057 .getColor("Button.highlight")),
058 new MarginBorder());
059 return buttonBorder;
060 }
061
062 public static Border getRadioButtonBorder() {
063 UIDefaults table = UIManager.getLookAndFeelDefaults();
064 Border radioButtonBorder = new BorderUIResource.CompoundBorderUIResource(
065 new BasicBorders.RadioButtonBorder(table
066 .getColor("RadioButton.shadow"), table
067 .getColor("RadioButton.darkShadow"), table
068 .getColor("RadioButton.light"), table
069 .getColor("RadioButton.highlight")),
070 new MarginBorder());
071 return radioButtonBorder;
072 }
073
074 public static Border getToggleButtonBorder() {
075 UIDefaults table = UIManager.getLookAndFeelDefaults();
076 Border toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
077 new BasicBorders.ToggleButtonBorder(table
078 .getColor("ToggleButton.shadow"), table
079 .getColor("ToggleButton.darkShadow"), table
080 .getColor("ToggleButton.light"), table
081 .getColor("ToggleButton.highlight")),
082 new MarginBorder());
083 return toggleButtonBorder;
084 }
085
086 public static Border getMenuBarBorder() {
087 UIDefaults table = UIManager.getLookAndFeelDefaults();
088 Border menuBarBorder = new BasicBorders.MenuBarBorder(table
089 .getColor("MenuBar.shadow"), table
090 .getColor("MenuBar.highlight"));
091 return menuBarBorder;
092 }
093
094 public static Border getSplitPaneBorder() {
095 UIDefaults table = UIManager.getLookAndFeelDefaults();
096 Border splitPaneBorder = new BasicBorders.SplitPaneBorder(table
097 .getColor("SplitPane.highlight"), table
098 .getColor("SplitPane.darkShadow"));
099 return splitPaneBorder;
100 }
101
102 /**
103 * Returns a border instance for a JSplitPane divider
104 * @since 1.3
105 */
106 public static Border getSplitPaneDividerBorder() {
107 UIDefaults table = UIManager.getLookAndFeelDefaults();
108 Border splitPaneBorder = new BasicBorders.SplitPaneDividerBorder(
109 table.getColor("SplitPane.highlight"), table
110 .getColor("SplitPane.darkShadow"));
111 return splitPaneBorder;
112 }
113
114 public static Border getTextFieldBorder() {
115 UIDefaults table = UIManager.getLookAndFeelDefaults();
116 Border textFieldBorder = new BasicBorders.FieldBorder(table
117 .getColor("TextField.shadow"), table
118 .getColor("TextField.darkShadow"), table
119 .getColor("TextField.light"), table
120 .getColor("TextField.highlight"));
121 return textFieldBorder;
122 }
123
124 public static Border getProgressBarBorder() {
125 UIDefaults table = UIManager.getLookAndFeelDefaults();
126 Border progressBarBorder = new BorderUIResource.LineBorderUIResource(
127 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(
135 BevelBorder.RAISED,
136 table.getColor("InternalFrame.borderLight"),
137 table.getColor("InternalFrame.borderHighlight"),
138 table
139 .getColor("InternalFrame.borderDarkShadow"),
140 table.getColor("InternalFrame.borderShadow")),
141 BorderFactory.createLineBorder(table
142 .getColor("InternalFrame.borderColor"), 1));
143
144 return internalFrameBorder;
145 }
146
147 /**
148 * Special thin border for rollover toolbar buttons.
149 * @since 1.4
150 */
151 public static class RolloverButtonBorder extends ButtonBorder {
152
153 public RolloverButtonBorder(Color shadow, Color darkShadow,
154 Color highlight, Color lightHighlight) {
155 super (shadow, darkShadow, highlight, lightHighlight);
156 }
157
158 public void paintBorder(Component c, Graphics g, int x, int y,
159 int w, int h) {
160 AbstractButton b = (AbstractButton) c;
161 ButtonModel model = b.getModel();
162
163 Color shade = shadow;
164 Component p = b.getParent();
165 if (p != null && p.getBackground().equals(shadow)) {
166 shade = darkShadow;
167 }
168
169 if ((model.isRollover() && !(model.isPressed() && !model
170 .isArmed()))
171 || model.isSelected()) {
172
173 Color oldColor = g.getColor();
174 g.translate(x, y);
175
176 if (model.isPressed() && model.isArmed()
177 || model.isSelected()) {
178 // Draw the pressd button
179 g.setColor(shade);
180 g.drawRect(0, 0, w - 1, h - 1);
181 g.setColor(lightHighlight);
182 g.drawLine(w - 1, 0, w - 1, h - 1);
183 g.drawLine(0, h - 1, w - 1, h - 1);
184 } else {
185 // Draw a rollover button
186 g.setColor(lightHighlight);
187 g.drawRect(0, 0, w - 1, h - 1);
188 g.setColor(shade);
189 g.drawLine(w - 1, 0, w - 1, h - 1);
190 g.drawLine(0, h - 1, w - 1, h - 1);
191 }
192 g.translate(-x, -y);
193 g.setColor(oldColor);
194 }
195 }
196 }
197
198 /**
199 * A border which is like a Margin border but it will only honor the margin
200 * if the margin has been explicitly set by the developer.
201 *
202 * Note: This is identical to the package private class
203 * MetalBorders.RolloverMarginBorder and should probably be consolidated.
204 */
205 static class RolloverMarginBorder extends EmptyBorder {
206
207 public RolloverMarginBorder() {
208 super (3, 3, 3, 3); // hardcoded margin for JLF requirements.
209 }
210
211 public Insets getBorderInsets(Component c) {
212 return getBorderInsets(c, new Insets(0, 0, 0, 0));
213 }
214
215 public Insets getBorderInsets(Component c, Insets insets) {
216 Insets margin = null;
217
218 if (c instanceof AbstractButton) {
219 margin = ((AbstractButton) c).getMargin();
220 }
221 if (margin == null || margin instanceof UIResource) {
222 // default margin so replace
223 insets.left = left;
224 insets.top = top;
225 insets.right = right;
226 insets.bottom = bottom;
227 } else {
228 // Margin which has been explicitly set by the user.
229 insets.left = margin.left;
230 insets.top = margin.top;
231 insets.right = margin.right;
232 insets.bottom = margin.bottom;
233 }
234 return insets;
235 }
236 }
237
238 public static class ButtonBorder extends AbstractBorder implements
239 UIResource {
240 protected Color shadow;
241 protected Color darkShadow;
242 protected Color highlight;
243 protected Color lightHighlight;
244
245 public ButtonBorder(Color shadow, Color darkShadow,
246 Color highlight, Color lightHighlight) {
247 this .shadow = shadow;
248 this .darkShadow = darkShadow;
249 this .highlight = highlight;
250 this .lightHighlight = lightHighlight;
251 }
252
253 public void paintBorder(Component c, Graphics g, int x, int y,
254 int width, int height) {
255 boolean isPressed = false;
256 boolean isDefault = false;
257
258 if (c instanceof AbstractButton) {
259 AbstractButton b = (AbstractButton) c;
260 ButtonModel model = b.getModel();
261
262 isPressed = model.isPressed() && model.isArmed();
263
264 if (c instanceof JButton) {
265 isDefault = ((JButton) c).isDefaultButton();
266 }
267 }
268 BasicGraphicsUtils.drawBezel(g, x, y, width, height,
269 isPressed, isDefault, shadow, darkShadow,
270 highlight, lightHighlight);
271 }
272
273 public Insets getBorderInsets(Component c) {
274 return getBorderInsets(c, new Insets(0, 0, 0, 0));
275 }
276
277 public Insets getBorderInsets(Component c, Insets insets) {
278 // leave room for default visual
279 insets.top = 2;
280 insets.left = insets.bottom = insets.right = 3;
281 return insets;
282 }
283
284 }
285
286 public static class ToggleButtonBorder extends ButtonBorder {
287
288 public ToggleButtonBorder(Color shadow, Color darkShadow,
289 Color highlight, Color lightHighlight) {
290 super (shadow, darkShadow, highlight, lightHighlight);
291 }
292
293 public void paintBorder(Component c, Graphics g, int x, int y,
294 int width, int height) {
295 BasicGraphicsUtils.drawBezel(g, x, y, width, height, false,
296 false, shadow, darkShadow, highlight,
297 lightHighlight);
298 }
299
300 public Insets getBorderInsets(Component c) {
301 return new Insets(2, 2, 2, 2);
302 }
303
304 public Insets getBorderInsets(Component c, Insets insets) {
305 insets.top = insets.left = insets.bottom = insets.right = 2;
306 return insets;
307 }
308 }
309
310 public static class RadioButtonBorder extends ButtonBorder {
311
312 public RadioButtonBorder(Color shadow, Color darkShadow,
313 Color highlight, Color lightHighlight) {
314 super (shadow, darkShadow, highlight, lightHighlight);
315 }
316
317 public void paintBorder(Component c, Graphics g, int x, int y,
318 int width, int height) {
319
320 if (c instanceof AbstractButton) {
321 AbstractButton b = (AbstractButton) c;
322 ButtonModel model = b.getModel();
323
324 if (model.isArmed() && model.isPressed()
325 || model.isSelected()) {
326 BasicGraphicsUtils.drawLoweredBezel(g, x, y, width,
327 height, shadow, darkShadow, highlight,
328 lightHighlight);
329 } else {
330 BasicGraphicsUtils.drawBezel(g, x, y, width,
331 height, false, b.isFocusPainted()
332 && b.hasFocus(), shadow,
333 darkShadow, highlight, lightHighlight);
334 }
335 } else {
336 BasicGraphicsUtils.drawBezel(g, x, y, width, height,
337 false, false, shadow, darkShadow, highlight,
338 lightHighlight);
339 }
340 }
341
342 public Insets getBorderInsets(Component c) {
343 return getBorderInsets(c, new Insets(0, 0, 0, 0));
344 }
345
346 public Insets getBorderInsets(Component c, Insets insets) {
347 insets.top = insets.left = insets.bottom = insets.right = 2;
348 return insets;
349 }
350 }
351
352 public static class MenuBarBorder extends AbstractBorder implements
353 UIResource {
354 private Color shadow;
355 private Color highlight;
356
357 public MenuBarBorder(Color shadow, Color highlight) {
358 this .shadow = shadow;
359 this .highlight = highlight;
360 }
361
362 public void paintBorder(Component c, Graphics g, int x, int y,
363 int width, int height) {
364 Color oldColor = g.getColor();
365 g.translate(x, y);
366 g.setColor(shadow);
367 g.drawLine(0, height - 2, width, height - 2);
368 g.setColor(highlight);
369 g.drawLine(0, height - 1, width, height - 1);
370 g.translate(-x, -y);
371 g.setColor(oldColor);
372 }
373
374 public Insets getBorderInsets(Component c) {
375 return getBorderInsets(c, new Insets(0, 0, 0, 0));
376 }
377
378 public Insets getBorderInsets(Component c, Insets insets) {
379 insets.top = 0;
380 insets.left = 0;
381 insets.bottom = 2;
382 insets.right = 0;
383 return insets;
384 }
385 }
386
387 public static class MarginBorder extends AbstractBorder implements
388 UIResource {
389
390 public Insets getBorderInsets(Component c) {
391 return getBorderInsets(c, new Insets(0, 0, 0, 0));
392 }
393
394 public Insets getBorderInsets(Component c, Insets insets) {
395 Insets margin = null;
396 //
397 // Ideally we'd have an interface defined for classes which
398 // support margins (to avoid this hackery), but we've
399 // decided against it for simplicity
400 //
401 if (c instanceof AbstractButton) {
402 AbstractButton b = (AbstractButton) c;
403 margin = b.getMargin();
404 } else if (c instanceof JToolBar) {
405 JToolBar t = (JToolBar) c;
406 margin = t.getMargin();
407 } else if (c instanceof JTextComponent) {
408 JTextComponent t = (JTextComponent) c;
409 margin = t.getMargin();
410 }
411 insets.top = margin != null ? margin.top : 0;
412 insets.left = margin != null ? margin.left : 0;
413 insets.bottom = margin != null ? margin.bottom : 0;
414 insets.right = margin != null ? margin.right : 0;
415
416 return insets;
417 }
418 }
419
420 public static class FieldBorder extends AbstractBorder implements
421 UIResource {
422 protected Color shadow;
423 protected Color darkShadow;
424 protected Color highlight;
425 protected Color lightHighlight;
426
427 public FieldBorder(Color shadow, Color darkShadow,
428 Color highlight, Color lightHighlight) {
429 this .shadow = shadow;
430 this .highlight = highlight;
431 this .darkShadow = darkShadow;
432 this .lightHighlight = lightHighlight;
433 }
434
435 public void paintBorder(Component c, Graphics g, int x, int y,
436 int width, int height) {
437 BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height,
438 shadow, darkShadow, highlight, lightHighlight);
439 }
440
441 public Insets getBorderInsets(Component c) {
442 return getBorderInsets(c, new Insets(0, 0, 0, 0));
443 }
444
445 public Insets getBorderInsets(Component c, Insets insets) {
446 Insets margin = null;
447 if (c instanceof JTextComponent) {
448 margin = ((JTextComponent) c).getMargin();
449 }
450 insets.top = margin != null ? 2 + margin.top : 2;
451 insets.left = margin != null ? 2 + margin.left : 2;
452 insets.bottom = margin != null ? 2 + margin.bottom : 2;
453 insets.right = margin != null ? 2 + margin.right : 2;
454
455 return insets;
456 }
457 }
458
459 /**
460 * Draws the border around the divider in a splitpane
461 * (when BasicSplitPaneUI is used). To get the appropriate effect, this
462 * needs to be used with a SplitPaneBorder.
463 */
464 static class SplitPaneDividerBorder implements Border, UIResource {
465 Color highlight;
466 Color shadow;
467
468 SplitPaneDividerBorder(Color highlight, Color shadow) {
469 this .highlight = highlight;
470 this .shadow = shadow;
471 }
472
473 public void paintBorder(Component c, Graphics g, int x, int y,
474 int width, int height) {
475 Component child;
476 Rectangle cBounds;
477 JSplitPane splitPane = ((BasicSplitPaneDivider) c)
478 .getBasicSplitPaneUI().getSplitPane();
479 Dimension size = c.getSize();
480
481 child = splitPane.getLeftComponent();
482 // This is needed for the space between the divider and end of
483 // splitpane.
484 g.setColor(c.getBackground());
485 g.drawRect(x, y, width - 1, height - 1);
486 if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
487 if (child != null) {
488 g.setColor(highlight);
489 g.drawLine(0, 0, 0, size.height);
490 }
491 child = splitPane.getRightComponent();
492 if (child != null) {
493 g.setColor(shadow);
494 g.drawLine(size.width - 1, 0, size.width - 1,
495 size.height);
496 }
497 } else {
498 if (child != null) {
499 g.setColor(highlight);
500 g.drawLine(0, 0, size.width, 0);
501 }
502 child = splitPane.getRightComponent();
503 if (child != null) {
504 g.setColor(shadow);
505 g.drawLine(0, size.height - 1, size.width,
506 size.height - 1);
507 }
508 }
509 }
510
511 public Insets getBorderInsets(Component c) {
512 Insets insets = new Insets(0, 0, 0, 0);
513 if (c instanceof BasicSplitPaneDivider) {
514 BasicSplitPaneUI bspui = ((BasicSplitPaneDivider) c)
515 .getBasicSplitPaneUI();
516
517 if (bspui != null) {
518 JSplitPane splitPane = bspui.getSplitPane();
519
520 if (splitPane != null) {
521 if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
522 insets.top = insets.bottom = 0;
523 insets.left = insets.right = 1;
524 return insets;
525 }
526 // VERTICAL_SPLIT
527 insets.top = insets.bottom = 1;
528 insets.left = insets.right = 0;
529 return insets;
530 }
531 }
532 }
533 insets.top = insets.bottom = insets.left = insets.right = 1;
534 return insets;
535 }
536
537 public boolean isBorderOpaque() {
538 return true;
539 }
540 }
541
542 /**
543 * Draws the border around the splitpane. To work correctly you shoudl
544 * also install a border on the divider (property SplitPaneDivider.border).
545 */
546 public static class SplitPaneBorder implements Border, UIResource {
547 protected Color highlight;
548 protected Color shadow;
549
550 public SplitPaneBorder(Color highlight, Color shadow) {
551 this .highlight = highlight;
552 this .shadow = shadow;
553 }
554
555 public void paintBorder(Component c, Graphics g, int x, int y,
556 int width, int height) {
557 // The only tricky part with this border is that the divider is
558 // not positioned at the top (for horizontal) or left (for vert),
559 // so this border draws to where the divider is:
560 // -----------------
561 // |xxxxxxx xxxxxxx|
562 // |x --- x|
563 // |x | | x|
564 // |x |D| x|
565 // |x | | x|
566 // |x --- x|
567 // |xxxxxxx xxxxxxx|
568 // -----------------
569 // The above shows (rather excessively) what this looks like for
570 // a horizontal orientation. This border then draws the x's, with
571 // the SplitPaneDividerBorder drawing its own border.
572
573 Component child;
574 Rectangle cBounds;
575
576 JSplitPane splitPane = (JSplitPane) c;
577
578 child = splitPane.getLeftComponent();
579 // This is needed for the space between the divider and end of
580 // splitpane.
581 g.setColor(c.getBackground());
582 g.drawRect(x, y, width - 1, height - 1);
583 if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
584 if (child != null) {
585 cBounds = child.getBounds();
586 g.setColor(shadow);
587 g.drawLine(0, 0, cBounds.width + 1, 0);
588 g.drawLine(0, 1, 0, cBounds.height + 1);
589
590 g.setColor(highlight);
591 g.drawLine(0, cBounds.height + 1,
592 cBounds.width + 1, cBounds.height + 1);
593 }
594 child = splitPane.getRightComponent();
595 if (child != null) {
596 cBounds = child.getBounds();
597
598 int maxX = cBounds.x + cBounds.width;
599 int maxY = cBounds.y + cBounds.height;
600
601 g.setColor(shadow);
602 g.drawLine(cBounds.x - 1, 0, maxX, 0);
603 g.setColor(highlight);
604 g.drawLine(cBounds.x - 1, maxY, maxX, maxY);
605 g.drawLine(maxX, 0, maxX, maxY + 1);
606 }
607 } else {
608 if (child != null) {
609 cBounds = child.getBounds();
610 g.setColor(shadow);
611 g.drawLine(0, 0, cBounds.width + 1, 0);
612 g.drawLine(0, 1, 0, cBounds.height);
613 g.setColor(highlight);
614 g.drawLine(1 + cBounds.width, 0, 1 + cBounds.width,
615 cBounds.height + 1);
616 g.drawLine(0, cBounds.height + 1, 0,
617 cBounds.height + 1);
618 }
619 child = splitPane.getRightComponent();
620 if (child != null) {
621 cBounds = child.getBounds();
622
623 int maxX = cBounds.x + cBounds.width;
624 int maxY = cBounds.y + cBounds.height;
625
626 g.setColor(shadow);
627 g.drawLine(0, cBounds.y - 1, 0, maxY);
628 g
629 .drawLine(maxX, cBounds.y - 1, maxX,
630 cBounds.y - 1);
631 g.setColor(highlight);
632 g.drawLine(0, maxY, cBounds.width + 1, maxY);
633 g.drawLine(maxX, cBounds.y, maxX, maxY);
634 }
635 }
636 }
637
638 public Insets getBorderInsets(Component c) {
639 return new Insets(1, 1, 1, 1);
640 }
641
642 public boolean isBorderOpaque() {
643 return true;
644 }
645 }
646
647 }
|