2
* Copyright (c) 2001-2009 JGoodies Karsten Lentzsch. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of JGoodies Karsten Lentzsch nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
package com.jgoodies.looks.plastic;
33
import java.awt.Component;
34
import java.awt.Graphics;
35
import java.awt.Insets;
38
import javax.swing.border.AbstractBorder;
39
import javax.swing.border.Border;
40
import javax.swing.border.CompoundBorder;
41
import javax.swing.border.EmptyBorder;
42
import javax.swing.plaf.BorderUIResource;
43
import javax.swing.plaf.UIResource;
44
import javax.swing.plaf.basic.BasicBorders;
45
import javax.swing.plaf.metal.MetalBorders;
46
import javax.swing.text.JTextComponent;
50
* This class consists of a set of <code>Border</code>s used
51
* by the JGoodies Plastic Look and Feel UI delegates.
53
* @author Karsten Lentzsch
54
* @version $Revision: 1.2 $
57
final class PlasticBorders {
59
private PlasticBorders() {
60
// Overrides default constructor; prevents instantiation.
64
// Accessing and Creating Borders ***************************************
66
private static Border comboBoxEditorBorder;
67
private static Border comboBoxArrowButtonBorder;
68
private static Border etchedBorder;
69
private static Border flush3DBorder;
70
private static Border menuBarHeaderBorder;
71
private static Border menuBorder;
72
private static Border menuItemBorder;
73
private static Border popupMenuBorder;
74
private static Border noMarginPopupMenuBorder;
75
private static Border rolloverButtonBorder;
76
private static Border scrollPaneBorder;
77
private static Border separatorBorder;
78
private static Border textFieldBorder;
79
private static Border thinLoweredBorder;
80
private static Border thinRaisedBorder;
81
private static Border toolBarHeaderBorder;
85
* Returns a border instance for a <code>JButton</code>.
87
* @return the lazily created button border
89
static Border getButtonBorder(Insets buttonMargin) {
90
return new BorderUIResource.CompoundBorderUIResource(
91
new ButtonBorder(buttonMargin),
92
new BasicBorders.MarginBorder());
96
* Returns a border for a <code>JComboBox</code>'s button.
98
* @return the lazily created combo box arrow button border
100
static Border getComboBoxArrowButtonBorder() {
101
if (comboBoxArrowButtonBorder == null) {
102
comboBoxArrowButtonBorder = new CompoundBorder( // No UIResource
103
new ComboBoxArrowButtonBorder(),
104
new BasicBorders.MarginBorder());
106
return comboBoxArrowButtonBorder;
110
* Returns a border for a <code>JComboBox</code>'s editor.
112
* @return the lazily created combo box editor border
114
static Border getComboBoxEditorBorder() {
115
if (comboBoxEditorBorder == null) {
116
comboBoxEditorBorder = new CompoundBorder( // No UIResource
117
new ComboBoxEditorBorder(),
118
new BasicBorders.MarginBorder());
120
return comboBoxEditorBorder;
124
* Returns an etched border instance for <code>JMenuBar</code> or
125
* <code>JToolBar</code>.
127
* @return the lazily created etched border
129
static Border getEtchedBorder() {
130
if (etchedBorder == null) {
131
etchedBorder = new BorderUIResource.CompoundBorderUIResource(
133
new BasicBorders.MarginBorder());
139
* Returns a flushed 3D border.
141
* @return the lazily created flushed 3D border
143
static Border getFlush3DBorder() {
144
if (flush3DBorder == null) {
145
flush3DBorder = new Flush3DBorder();
147
return flush3DBorder;
151
* Returns a border for a <code>JInternalFrame</code>.
153
* @return an internal frame border
155
static Border getInternalFrameBorder() {
156
return new InternalFrameBorder();
160
* Returns a special border for a <code>JMenuBar</code> that
161
* is used in a header just above a <code>JToolBar</code>.
163
* @return the lazily created menu bar header border
165
static Border getMenuBarHeaderBorder() {
166
if (menuBarHeaderBorder == null) {
167
menuBarHeaderBorder = new BorderUIResource.CompoundBorderUIResource(
168
new MenuBarHeaderBorder(),
169
new BasicBorders.MarginBorder());
171
return menuBarHeaderBorder;
175
* Returns a border instance for a <code>JMenu</code>.
177
* @return the lazily created menu border
179
static Border getMenuBorder() {
180
if (menuBorder == null) {
181
menuBorder = new BorderUIResource.CompoundBorderUIResource(
183
new BasicBorders.MarginBorder());
189
* Returns a border instance for a <code>JMenuItem</code>.
191
* @return the lazily created menu item border
193
static Border getMenuItemBorder() {
194
if (menuItemBorder == null) {
196
new BorderUIResource(new BasicBorders.MarginBorder());
198
return menuItemBorder;
202
* Returns a border instance for a <code>JPopupMenu</code>.
204
* @return the lazily created popup menu border
206
static Border getPopupMenuBorder() {
207
if (popupMenuBorder == null) {
208
popupMenuBorder = new PopupMenuBorder();
210
return popupMenuBorder;
214
* Returns a border instance for a <code>JPopupMenu</code> that
215
* has no (extra) margin.
217
* @return the lazily created no-margin popup menu border
219
static Border getNoMarginPopupMenuBorder() {
220
if (noMarginPopupMenuBorder == null) {
221
noMarginPopupMenuBorder = new NoMarginPopupMenuBorder();
223
return noMarginPopupMenuBorder;
227
* Returns a border for a <code>JInternalFrame</code>'s palette.
229
* @return a border for an internal frame in palette mode
231
static Border getPaletteBorder() {
232
return new PaletteBorder();
236
* Returns a rollover border for buttons in a <code>JToolBar</code>.
238
* @return the lazily created rollover button border
240
static Border getRolloverButtonBorder() {
241
if (rolloverButtonBorder == null) {
242
rolloverButtonBorder = new CompoundBorder( // No UIResource
243
new RolloverButtonBorder(),
244
new RolloverMarginBorder());
246
return rolloverButtonBorder;
250
* Returns a separator border instance for <code>JScrollPane</code>.
252
* @return the lazily created scroll pane border
254
static Border getScrollPaneBorder() {
255
if (scrollPaneBorder == null) {
256
scrollPaneBorder = new ScrollPaneBorder();
258
return scrollPaneBorder;
262
* Returns a separator border instance for <code>JMenuBar</code> or
263
* <code>JToolBar</code>.
265
* @return the lazily created separator border
267
static Border getSeparatorBorder() {
268
if (separatorBorder == null) {
269
separatorBorder = new BorderUIResource.CompoundBorderUIResource(
270
new SeparatorBorder(),
271
new BasicBorders.MarginBorder());
273
return separatorBorder;
277
* Returns a border instance for a JTextField.
279
* @return the lazily created text field border
281
static Border getTextFieldBorder() {
282
if (textFieldBorder == null) {
283
textFieldBorder = new BorderUIResource.CompoundBorderUIResource(
284
new TextFieldBorder(),
285
new BasicBorders.MarginBorder());
287
return textFieldBorder;
291
* Returns a thin lowered border.
293
* @return the lazily created thin lowered border
295
static Border getThinLoweredBorder() {
296
if (thinLoweredBorder == null) {
297
thinLoweredBorder = new ThinLoweredBorder();
299
return thinLoweredBorder;
303
* Returns a thin raised border.
305
* @return the lazily created thin raised border
307
static Border getThinRaisedBorder() {
308
if (thinRaisedBorder == null) {
309
thinRaisedBorder = new ThinRaisedBorder();
311
return thinRaisedBorder;
315
* Returns a border instance for a JToggleButton.
317
* @return the lazily created toggle button border
319
static Border getToggleButtonBorder(Insets buttonMargin) {
320
return new BorderUIResource.CompoundBorderUIResource(
321
new ToggleButtonBorder(buttonMargin),
322
new BasicBorders.MarginBorder());
326
* Returns a special border for a <code>JToolBar</code> that
327
* is used in a header just below a <code>JMenuBar</code>.
329
* @return the lazily created toolbar header border
331
static Border getToolBarHeaderBorder() {
332
if (toolBarHeaderBorder == null) {
333
toolBarHeaderBorder = new BorderUIResource.CompoundBorderUIResource(
334
new ToolBarHeaderBorder(),
335
new BasicBorders.MarginBorder());
337
return toolBarHeaderBorder;
340
private static class Flush3DBorder extends AbstractBorder implements UIResource {
342
private static final Insets INSETS = new Insets(2, 2, 2, 2);
344
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
346
PlasticUtils.drawFlush3DBorder(g, x, y, w, h);
348
PlasticUtils.drawDisabledBorder(g, x, y, w, h);
351
public Insets getBorderInsets(Component c) { return INSETS; }
353
public Insets getBorderInsets(Component c, Insets newInsets) {
354
newInsets.top = INSETS.top;
355
newInsets.left = INSETS.left;
356
newInsets.bottom = INSETS.bottom;
357
newInsets.right = INSETS.right;
363
private static class ButtonBorder extends AbstractBorder implements UIResource {
365
protected final Insets insets;
367
protected ButtonBorder(Insets insets) {
368
this.insets = insets;
371
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
372
AbstractButton button = (AbstractButton) c;
373
ButtonModel model = button.getModel();
375
if (model.isEnabled()) {
376
boolean isPressed = model.isPressed() && model.isArmed();
377
boolean isDefault = button instanceof JButton
378
&& ((JButton) button).isDefaultButton();
380
if (isPressed && isDefault)
381
PlasticUtils.drawDefaultButtonPressedBorder(g, x, y, w, h);
383
PlasticUtils.drawPressed3DBorder(g, x, y, w, h);
385
PlasticUtils.drawDefaultButtonBorder(g, x, y, w, h, false);
387
PlasticUtils.drawButtonBorder(g, x, y, w, h, false);
388
} else { // disabled state
389
PlasticUtils.drawDisabledBorder(g, x, y, w - 1, h - 1);
393
public Insets getBorderInsets(Component c) { return insets; }
395
public Insets getBorderInsets(Component c, Insets newInsets) {
396
newInsets.top = insets.top;
397
newInsets.left = insets.left;
398
newInsets.bottom = insets.bottom;
399
newInsets.right = insets.right;
405
private static final class ComboBoxArrowButtonBorder extends AbstractBorder implements UIResource {
407
protected static final Insets INSETS = new Insets(1, 1, 1, 1);
409
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
410
AbstractButton button = (AbstractButton) c;
411
ButtonModel model = button.getModel();
413
if (model.isEnabled()) {
414
boolean isPressed = model.isPressed() && model.isArmed();
417
PlasticUtils.drawPressed3DBorder(g, x, y, w, h);
419
PlasticUtils.drawButtonBorder(g, x, y, w, h, false);
421
PlasticUtils.drawDisabledBorder(g, x, y, w - 1, h - 1);
425
public Insets getBorderInsets(Component c) { return INSETS; }
429
private static final class ComboBoxEditorBorder extends AbstractBorder {
431
private static final Insets INSETS = new Insets(2, 2, 2, 0);
433
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
435
PlasticUtils.drawFlush3DBorder(g, x, y, w + 2, h);
437
PlasticUtils.drawDisabledBorder(g, x, y, w + 2, h-1);
438
g.setColor(UIManager.getColor("control"));
439
g.drawLine(x, y + h-1, x + w, y + h-1);
443
public Insets getBorderInsets(Component c) { return INSETS; }
448
* A border used for <code>JInternalFrame</code>s.
450
private static final class InternalFrameBorder extends AbstractBorder implements UIResource {
452
private static final Insets NORMAL_INSETS = new Insets(1, 1, 1, 1);
453
private static final Insets MAXIMIZED_INSETS = new Insets(1, 1, 0, 0);
456
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
457
JInternalFrame frame = (JInternalFrame) c;
458
if (frame.isMaximum())
459
paintMaximizedBorder(g, x, y, w, h);
461
PlasticUtils.drawThinFlush3DBorder(g, x, y, w, h);
464
private void paintMaximizedBorder(Graphics g, int x, int y, int w, int h) {
466
g.setColor(PlasticLookAndFeel.getControlHighlight());
467
g.drawLine(0, 0, w - 2, 0);
468
g.drawLine(0, 0, 0, h - 2);
472
public Insets getBorderInsets(Component c) {
473
return ((JInternalFrame) c).isMaximum() ? MAXIMIZED_INSETS : NORMAL_INSETS;
479
* A border used for the palette of <code>JInternalFrame</code>s.
481
private static final class PaletteBorder extends AbstractBorder implements UIResource {
483
private static final Insets INSETS = new Insets(1, 1, 1, 1);
485
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h ) {
487
g.setColor(PlasticLookAndFeel.getControlDarkShadow());
488
g.drawRect(0, 0, w-1, h-1);
492
public Insets getBorderInsets(Component c) { return INSETS; }
497
* A border that looks like a separator line; used for menu bars
500
private static final class SeparatorBorder extends AbstractBorder implements UIResource {
502
private static final Insets INSETS = new Insets(0, 0, 2, 1);
504
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
506
g.setColor( UIManager.getColor("Separator.foreground"));
507
g.drawLine( 0, h - 2, w - 1, h - 2 );
509
g.setColor( UIManager.getColor("Separator.background"));
510
g.drawLine( 0, h - 1, w - 1, h - 1 );
513
public Insets getBorderInsets(Component c) { return INSETS; }
517
private static final class ThinRaisedBorder extends AbstractBorder implements UIResource {
518
private static final Insets INSETS = new Insets(2, 2, 2, 2);
520
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
521
PlasticUtils.drawThinFlush3DBorder(g, x, y, w, h);
524
public Insets getBorderInsets(Component c) { return INSETS; }
528
private static final class ThinLoweredBorder extends AbstractBorder implements UIResource {
529
private static final Insets INSETS = new Insets(2, 2, 2, 2);
531
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
532
PlasticUtils.drawThinPressed3DBorder(g, x, y, w, h);
535
public Insets getBorderInsets(Component c) { return INSETS; }
540
* A border used for menu bars and tool bars in
541
* <code>HeaderStyle.SINGLE</code>. The bar is wrapped by an inner thin
542
* raised border, which in turn is wrapped by an outer thin lowered
545
private static final class EtchedBorder extends AbstractBorder implements UIResource {
547
private static final Insets INSETS = new Insets(2, 2, 2, 2);
549
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
550
PlasticUtils.drawThinPressed3DBorder(g, x, y, w, h);
551
PlasticUtils.drawThinFlush3DBorder (g, x + 1, y + 1, w - 2, h - 2);
554
public Insets getBorderInsets(Component c) { return INSETS; }
559
* A border used for menu bars in <code>HeaderStyle.BOTH</code>.
560
* The menu bar and tool bar are wrapped by a thin raised border,
561
* both together are wrapped by a thin lowered border.
563
private static final class MenuBarHeaderBorder extends AbstractBorder implements UIResource {
565
private static final Insets INSETS = new Insets(2, 2, 1, 2);
567
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
568
PlasticUtils.drawThinPressed3DBorder(g, x, y, w, h + 1);
569
PlasticUtils.drawThinFlush3DBorder (g, x + 1, y + 1, w - 2, h - 1);
572
public Insets getBorderInsets(Component c) { return INSETS; }
577
* A border used for tool bars in <code>HeaderStyle.BOTH</code>.
578
* The menu bar and tool bar are wrapped by a thin raised border,
579
* both together are wrapped by a thin lowered border.
581
private static final class ToolBarHeaderBorder extends AbstractBorder implements UIResource {
583
private static final Insets INSETS = new Insets(1, 2, 2, 2);
585
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
586
PlasticUtils.drawThinPressed3DBorder(g, x, y - 1, w, h + 1);
587
PlasticUtils.drawThinFlush3DBorder (g, x + 1, y, w - 2, h - 1);
590
public Insets getBorderInsets(Component c) { return INSETS; }
594
private static final class MenuBorder extends AbstractBorder implements UIResource {
595
private static final Insets INSETS = new Insets( 2, 2, 2, 2 );
597
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
598
JMenuItem b = (JMenuItem) c;
599
ButtonModel model = b.getModel();
601
if (model.isArmed() || model.isSelected()) {
602
g.setColor(PlasticLookAndFeel.getControlDarkShadow());
603
g.drawLine(0, 0, w - 2, 0 );
604
g.drawLine(0, 0, 0, h - 1 );
605
//g.drawLine(w - 2, 2, w - 2, h - 1 );
607
g.setColor(PlasticLookAndFeel.getPrimaryControlHighlight());
608
g.drawLine(w - 1, 0, w - 1, h - 1 );
609
} else if (model.isRollover()) {
611
PlasticUtils.drawFlush3DBorder(g, x, y, w, h);
616
public Insets getBorderInsets(Component c) { return INSETS; }
618
public Insets getBorderInsets(Component c, Insets newInsets) {
619
newInsets.top = INSETS.top;
620
newInsets.left = INSETS.left;
621
newInsets.bottom = INSETS.bottom;
622
newInsets.right = INSETS.right;
628
private static final class PopupMenuBorder extends AbstractBorder implements UIResource {
629
private static final Insets INSETS = new Insets(3, 3, 3, 3);
631
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
633
g.setColor(PlasticLookAndFeel.getControlDarkShadow());
634
g.drawRect(0, 0, w-1, h-1);
635
g.setColor(PlasticLookAndFeel.getMenuItemBackground());
636
g.drawRect(1, 1, w-3, h-3);
637
g.drawRect(2, 2, w-5, h-5);
641
public Insets getBorderInsets(Component c) { return INSETS; }
645
private static final class NoMarginPopupMenuBorder extends AbstractBorder implements UIResource {
646
private static final Insets INSETS = new Insets(1, 1, 1, 1);
648
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
650
g.setColor(PlasticLookAndFeel.getControlDarkShadow());
651
g.drawRect(0, 0, w-1, h-1);
655
public Insets getBorderInsets(Component c) { return INSETS; }
659
private static class RolloverButtonBorder extends ButtonBorder {
661
private RolloverButtonBorder() {
662
super(new Insets(3, 3, 3, 3));
665
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
666
AbstractButton b = (AbstractButton) c;
667
ButtonModel model = b.getModel();
669
if (!model.isEnabled())
672
if (!(c instanceof JToggleButton)) {
673
if ( model.isRollover() && !( model.isPressed() && !model.isArmed() ) ) {
674
super.paintBorder( c, g, x, y, w, h );
679
//if ( model.isRollover() && !( model.isPressed() && !model.isArmed() ) ) {
680
//super.paintBorder( c, g, x, y, w, h );
683
if (model.isRollover()) {
684
if (model.isPressed() && model.isArmed()) {
685
PlasticUtils.drawPressed3DBorder(g, x, y, w, h);
687
PlasticUtils.drawFlush3DBorder(g, x, y, w, h);
689
} else if (model.isSelected())
690
PlasticUtils.drawDark3DBorder(g, x, y, w, h);
696
* A border which is like a Margin border but it will only honor the margin
697
* if the margin has been explicitly set by the developer.
699
static final class RolloverMarginBorder extends EmptyBorder {
701
RolloverMarginBorder() {
706
public Insets getBorderInsets(Component c) {
707
return getBorderInsets(c, new Insets(0, 0, 0, 0));
711
public Insets getBorderInsets(Component c, Insets insets) {
712
Insets margin = null;
714
if (c instanceof AbstractButton) {
715
margin = ((AbstractButton) c).getMargin();
717
if (margin == null || margin instanceof UIResource) {
718
// default margin so replace
721
insets.right = right;
722
insets.bottom = bottom;
724
// Margin which has been explicitly set by the user.
725
insets.left = margin.left;
726
insets.top = margin.top;
727
insets.right = margin.right;
728
insets.bottom = margin.bottom;
735
* Unlike Metal we don't paint the (misplaced) control color edges.
736
* Being a subclass of MetalBorders.ScrollPaneBorders ensures that
737
* the ScrollPaneUI will update the ScrollbarsFreeStanding property.
739
private static final class ScrollPaneBorder extends MetalBorders.ScrollPaneBorder {
741
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
744
g.setColor(PlasticLookAndFeel.getControlDarkShadow());
745
g.drawRect(0, 0, w - 2, h - 2);
746
g.setColor(PlasticLookAndFeel.getControlHighlight());
747
g.drawLine(w - 1, 0, w - 1, h - 1);
748
g.drawLine(0, h - 1, w - 1, h - 1);
755
private static final class TextFieldBorder extends Flush3DBorder {
756
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
758
if (!(c instanceof JTextComponent)) {
759
// special case for non-text components (bug ID 4144840)
761
PlasticUtils.drawFlush3DBorder(g, x, y, w, h);
763
PlasticUtils.drawDisabledBorder(g, x, y, w, h);
768
if (c.isEnabled() && ((JTextComponent) c).isEditable())
769
PlasticUtils.drawFlush3DBorder(g, x, y, w, h);
771
PlasticUtils.drawDisabledBorder(g, x, y, w, h);
776
private static final class ToggleButtonBorder extends ButtonBorder {
778
private ToggleButtonBorder(Insets insets) {
782
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
783
if (!c.isEnabled()) {
784
PlasticUtils.drawDisabledBorder(g, x, y, w - 1, h - 1);
786
AbstractButton button = (AbstractButton) c;
787
ButtonModel model = button.getModel();
788
if (model.isPressed() && model.isArmed())
789
PlasticUtils.drawPressed3DBorder(g, x, y, w, h);
790
else if (model.isSelected())
791
PlasticUtils.drawDark3DBorder(g, x, y, w, h);
793
PlasticUtils.drawFlush3DBorder(g, x, y, w, h);