1 /*
2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.java.swing.plaf.motif;
27 
28 import sun.swing.SwingUtilities2;
29 import javax.swing.*;
30 import javax.swing.border.*;
31 import javax.swing.plaf.*;
32 
33 import java.awt.Color;
34 import java.awt.Component;
35 import java.awt.Dimension;
36 import java.awt.Font;
37 import java.awt.FontMetrics;
38 import java.awt.Graphics;
39 import java.awt.Insets;
40 import java.awt.Point;
41 import java.awt.Rectangle;
42 
43 /**
44  * Factory object that can vend Icons appropriate for the basic {@literal L & F}.
45  * <p>
46  * <strong>Warning:</strong>
47  * Serialized objects of this class will not be compatible with
48  * future Swing releases.  The current serialization support is appropriate
49  * for short term storage or RMI between applications running the same
50  * version of Swing.  A future release of Swing will provide support for
51  * long term persistence.
52  *
53  * @author Amy Fowler
54  */
55 public class MotifBorders {
56 
57     @SuppressWarnings("serial") // Superclass is not serializable across versions
58     public static class BevelBorder extends AbstractBorder implements UIResource {
59         private Color darkShadow = UIManager.getColor("controlShadow");
60         private Color lightShadow = UIManager.getColor("controlLtHighlight");
61         private boolean isRaised;
62 
BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow)63         public BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) {
64             this.isRaised = isRaised;
65             this.darkShadow = darkShadow;
66             this.lightShadow = lightShadow;
67         }
68 
paintBorder(Component c, Graphics g, int x, int y, int w, int h)69         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
70             g.setColor((isRaised) ? lightShadow : darkShadow);
71             g.drawLine(x, y, x+w-1, y);           // top
72             g.drawLine(x, y+h-1, x, y+1);         // left
73 
74             g.setColor((isRaised) ? darkShadow : lightShadow);
75             g.drawLine(x+1, y+h-1, x+w-1, y+h-1); // bottom
76             g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right
77         }
78 
getBorderInsets(Component c, Insets insets)79         public Insets getBorderInsets(Component c, Insets insets) {
80             insets.set(1, 1, 1, 1);
81             return insets;
82         }
83 
isOpaque(Component c)84         public boolean isOpaque(Component c) {
85             return true;
86         }
87 
88     }
89 
90 
91     @SuppressWarnings("serial") // Superclass is not serializable across versions
92     public static class FocusBorder extends AbstractBorder implements UIResource {
93         private Color focus;
94         private Color control;
95 
FocusBorder(Color control, Color focus)96         public FocusBorder(Color control, Color focus) {
97             this.control = control;
98             this.focus = focus;
99         }
100 
paintBorder(Component c, Graphics g, int x, int y, int w, int h)101         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
102             if (c.hasFocus()) {
103                 g.setColor(focus);
104                 g.drawRect(x, y, w-1, h-1);
105             } else {
106                 g.setColor(control);
107                 g.drawRect(x, y, w-1, h-1);
108             }
109         }
110 
getBorderInsets(Component c, Insets insets)111         public Insets getBorderInsets(Component c, Insets insets) {
112             insets.set(1, 1, 1, 1);
113             return insets;
114         }
115     }
116 
117 
118     @SuppressWarnings("serial") // Superclass is not serializable across versions
119     public static class ButtonBorder extends AbstractBorder implements UIResource {
120         protected Color focus = UIManager.getColor("activeCaptionBorder");
121         protected Color shadow = UIManager.getColor("Button.shadow");
122         protected Color highlight = UIManager.getColor("Button.light");
123         protected Color darkShadow;
124 
ButtonBorder(Color shadow, Color highlight, Color darkShadow, Color focus)125         public ButtonBorder(Color shadow, Color highlight, Color darkShadow, Color focus) {
126             this.shadow = shadow;
127             this.highlight = highlight;
128             this.darkShadow = darkShadow;
129             this.focus = focus;
130         }
131 
paintBorder(Component c, Graphics g, int x, int y, int w, int h)132         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
133             boolean isPressed = false;
134             boolean hasFocus = false;
135             boolean canBeDefault = false;
136             boolean isDefault = false;
137 
138             if (c instanceof AbstractButton) {
139                 AbstractButton b = (AbstractButton)c;
140                 ButtonModel model = b.getModel();
141 
142                 isPressed = (model.isArmed() && model.isPressed());
143                 hasFocus = (model.isArmed() && isPressed) ||
144                            (b.isFocusPainted() && b.hasFocus());
145                 if (b instanceof JButton) {
146                     canBeDefault = ((JButton)b).isDefaultCapable();
147                     isDefault = ((JButton)b).isDefaultButton();
148                 }
149             }
150             int bx1 = x+1;
151             int by1 = y+1;
152             int bx2 = x+w-2;
153             int by2 = y+h-2;
154 
155             if (canBeDefault) {
156                 if (isDefault) {
157                     g.setColor(shadow);
158                     g.drawLine(x+3, y+3, x+3, y+h-4);
159                     g.drawLine(x+3, y+3, x+w-4, y+3);
160 
161                     g.setColor(highlight);
162                     g.drawLine(x+4, y+h-4, x+w-4, y+h-4);
163                     g.drawLine(x+w-4, y+3, x+w-4, y+h-4);
164                 }
165                 bx1 +=6;
166                 by1 += 6;
167                 bx2 -= 6;
168                 by2 -= 6;
169             }
170 
171             if (hasFocus) {
172                 g.setColor(focus);
173                 if (isDefault) {
174                     g.drawRect(x, y, w-1, h-1);
175                 } else {
176                     g.drawRect(bx1-1, by1-1, bx2-bx1+2, by2-by1+2);
177                 }
178             }
179 
180             g.setColor(isPressed? shadow : highlight);
181             g.drawLine(bx1, by1, bx2, by1);
182             g.drawLine(bx1, by1, bx1, by2);
183 
184             g.setColor(isPressed? highlight : shadow);
185             g.drawLine(bx2, by1+1, bx2, by2);
186             g.drawLine(bx1+1, by2, bx2, by2);
187         }
188 
getBorderInsets(Component c, Insets insets)189         public Insets getBorderInsets(Component c, Insets insets) {
190             int thickness = (c instanceof JButton && ((JButton)c).isDefaultCapable())? 8 : 2;
191             insets.set(thickness, thickness, thickness, thickness);
192             return insets;
193         }
194 
195     }
196 
197     @SuppressWarnings("serial") // Superclass is not serializable across versions
198     public static class ToggleButtonBorder extends ButtonBorder {
199 
ToggleButtonBorder(Color shadow, Color highlight, Color darkShadow, Color focus)200         public ToggleButtonBorder(Color shadow, Color highlight, Color darkShadow, Color focus) {
201              super(shadow, highlight, darkShadow, focus);
202         }
203 
paintBorder(Component c, Graphics g, int x, int y, int width, int height)204         public void paintBorder(Component c, Graphics g, int x, int y,
205                             int width, int height) {
206             if (c instanceof AbstractButton) {
207                 AbstractButton b = (AbstractButton)c;
208                 ButtonModel model = b.getModel();
209 
210                 if (model.isArmed() && model.isPressed() || model.isSelected()) {
211                     drawBezel(g, x, y, width, height,
212                               (model.isPressed() || model.isSelected()),
213                               b.isFocusPainted() && b.hasFocus(), shadow, highlight, darkShadow, focus);
214                 } else {
215                     drawBezel(g, x, y, width, height,
216                               false, b.isFocusPainted() && b.hasFocus(),
217                               shadow, highlight, darkShadow, focus);
218                 }
219             } else {
220                 drawBezel(g, x, y, width, height, false, false,
221                           shadow, highlight, darkShadow, focus);
222             }
223         }
224 
getBorderInsets(Component c, Insets insets)225         public Insets getBorderInsets(Component c, Insets insets) {
226             insets.set(2, 2, 3, 3);
227             return insets;
228         }
229     }
230 
231     @SuppressWarnings("serial") // Superclass is not serializable across versions
232     public static class MenuBarBorder extends ButtonBorder {
233 
MenuBarBorder(Color shadow, Color highlight, Color darkShadow, Color focus)234         public MenuBarBorder(Color shadow, Color highlight, Color darkShadow, Color focus) {
235             super(shadow, highlight, darkShadow, focus);
236         }
237 
paintBorder(Component c, Graphics g, int x, int y, int width, int height)238         public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
239             if (!(c instanceof JMenuBar)) {
240                 return;
241             }
242             JMenuBar menuBar = (JMenuBar)c;
243             if (menuBar.isBorderPainted() == true) {
244                 // this draws the MenuBar border
245                 Dimension size = menuBar.getSize();
246                 drawBezel(g,x,y,size.width,size.height,false,false,
247                           shadow, highlight, darkShadow, focus);
248             }
249         }
250 
getBorderInsets(Component c, Insets insets)251         public Insets getBorderInsets(Component c, Insets insets) {
252             insets.set(6, 6, 6, 6);
253             return insets;
254         }
255     }
256 
257     @SuppressWarnings("serial") // Superclass is not serializable across versions
258     public static class FrameBorder extends AbstractBorder implements UIResource {
259 
260         JComponent jcomp;
261         Color frameHighlight;
262         Color frameColor;
263         Color frameShadow;
264 
265         // The width of the border
266         public static final int BORDER_SIZE = 5;
267 
268         /** Constructs an FrameBorder for the JComponent <b>comp</b>.
269         */
FrameBorder(JComponent comp)270         public FrameBorder(JComponent comp) {
271             jcomp = comp;
272         }
273 
274         /** Sets the FrameBorder's JComponent.
275       */
setComponent(JComponent comp)276         public void setComponent(JComponent comp) {
277             jcomp = comp;
278         }
279 
280         /** Returns the FrameBorder's JComponent.
281           * @see #setComponent
282           */
component()283         public JComponent component() {
284             return jcomp;
285         }
286 
getFrameHighlight()287         protected Color getFrameHighlight() {
288             return frameHighlight;
289         }
290 
getFrameColor()291         protected Color getFrameColor() {
292             return frameColor;
293         }
294 
getFrameShadow()295         protected Color getFrameShadow() {
296             return frameShadow;
297         }
298 
getBorderInsets(Component c, Insets newInsets)299         public Insets getBorderInsets(Component c, Insets newInsets) {
300             newInsets.set(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE);
301             return newInsets;
302         }
303 
304        /** Draws the FrameBorder's top border.
305          */
drawTopBorder(Component c, Graphics g, int x, int y, int width, int height)306         protected boolean drawTopBorder(Component c, Graphics g,
307                                     int x, int y, int width, int height) {
308             Rectangle titleBarRect = new Rectangle(x, y, width, BORDER_SIZE);
309             if (!g.getClipBounds().intersects(titleBarRect)) {
310                 return false;
311             }
312 
313             int maxX = width - 1;
314             int maxY = BORDER_SIZE - 1;
315 
316             // Draw frame
317             g.setColor(frameColor);
318             g.drawLine(x, y + 2, maxX - 2, y + 2);
319             g.drawLine(x, y + 3, maxX - 2, y + 3);
320             g.drawLine(x, y + 4, maxX - 2, y + 4);
321 
322             // Draw highlights
323             g.setColor(frameHighlight);
324             g.drawLine(x, y, maxX, y);
325             g.drawLine(x, y + 1, maxX, y + 1);
326             g.drawLine(x, y + 2, x, y + 4);
327             g.drawLine(x + 1, y + 2, x + 1, y + 4);
328 
329             // Draw shadows
330             g.setColor(frameShadow);
331             g.drawLine(x + 4, y + 4, maxX - 4, y + 4);
332             g.drawLine(maxX, y + 1, maxX, maxY);
333             g.drawLine(maxX - 1, y + 2, maxX - 1, maxY);
334 
335             return true;
336         }
337 
338         /** Draws the FrameBorder's left border.
339           */
drawLeftBorder(Component c, Graphics g, int x, int y, int width, int height)340         protected boolean drawLeftBorder(Component c, Graphics g, int x, int y,
341                                int width, int height) {
342             Rectangle borderRect =
343                 new Rectangle(0, 0, getBorderInsets(c).left, height);
344             if (!g.getClipBounds().intersects(borderRect)) {
345                 return false;
346             }
347 
348             int startY = BORDER_SIZE;
349 
350             g.setColor(frameHighlight);
351             g.drawLine(x, startY, x, height - 1);
352             g.drawLine(x + 1, startY, x + 1, height - 2);
353 
354             g.setColor(frameColor);
355             g.fillRect(x + 2, startY, x + 2, height - 3);
356 
357             g.setColor(frameShadow);
358             g.drawLine(x + 4, startY, x + 4, height - 5);
359 
360             return true;
361         }
362 
363         /** Draws the FrameBorder's right border.
364           */
drawRightBorder(Component c, Graphics g, int x, int y, int width, int height)365         protected boolean drawRightBorder(Component c, Graphics g, int x, int y,
366                                 int width, int height) {
367             Rectangle borderRect = new Rectangle(
368                 width - getBorderInsets(c).right, 0,
369                 getBorderInsets(c).right, height);
370             if (!g.getClipBounds().intersects(borderRect)) {
371                 return false;
372             }
373 
374             int startX = width - getBorderInsets(c).right;
375             int startY = BORDER_SIZE;
376 
377             g.setColor(frameColor);
378             g.fillRect(startX + 1, startY, 2, height - 1);
379 
380             g.setColor(frameShadow);
381             g.fillRect(startX + 3, startY, 2, height - 1);
382 
383             g.setColor(frameHighlight);
384             g.drawLine(startX, startY, startX, height - 1);
385 
386             return true;
387         }
388 
389         /** Draws the FrameBorder's bottom border.
390           */
drawBottomBorder(Component c, Graphics g, int x, int y, int width, int height)391         protected boolean drawBottomBorder(Component c, Graphics g, int x, int y,
392                                  int width, int height) {
393             Rectangle    borderRect;
394             int     marginHeight, startY;
395 
396             borderRect = new Rectangle(0, height - getBorderInsets(c).bottom,
397                                   width, getBorderInsets(c).bottom);
398             if (!g.getClipBounds().intersects(borderRect)) {
399                 return false;
400             }
401 
402             startY = height - getBorderInsets(c).bottom;
403 
404             g.setColor(frameShadow);
405             g.drawLine(x + 1, height - 1, width - 1, height - 1);
406             g.drawLine(x + 2, height - 2, width - 2, height - 2);
407 
408             g.setColor(frameColor);
409             g.fillRect(x + 2, startY + 1, width - 4, 2);
410 
411             g.setColor(frameHighlight);
412             g.drawLine(x + 5, startY, width - 5, startY);
413 
414             return true;
415         }
416 
417         // Returns true if the associated component has focus.
isActiveFrame()418         protected boolean isActiveFrame() {
419             return jcomp.hasFocus();
420         }
421 
422         /** Draws the FrameBorder in the given Rect.  Calls
423           * <b>drawTitleBar</b>, <b>drawLeftBorder</b>, <b>drawRightBorder</b> and
424           * <b>drawBottomBorder</b>.
425           */
paintBorder(Component c, Graphics g, int x, int y, int width, int height)426         public void paintBorder(Component c, Graphics g,
427                             int x, int y, int width, int height) {
428             if (isActiveFrame()) {
429                 frameColor = UIManager.getColor("activeCaptionBorder");
430             } else {
431                 frameColor = UIManager.getColor("inactiveCaptionBorder");
432             }
433             frameHighlight = frameColor.brighter();
434             frameShadow = frameColor.darker().darker();
435 
436             drawTopBorder(c, g, x, y, width, height);
437             drawLeftBorder(c, g, x, y, width, height);
438             drawRightBorder(c, g, x, y, width, height);
439             drawBottomBorder(c, g, x, y, width, height);
440         }
441     }
442 
443     @SuppressWarnings("serial") // Superclass is not serializable across versions
444     public static class InternalFrameBorder extends FrameBorder {
445 
446         JInternalFrame frame;
447 
448         // The size of the bounding box for Motif frame corners.
449         public static final int CORNER_SIZE = 24;
450 
451         /** Constructs an InternalFrameBorder for the InternalFrame
452           * <b>aFrame</b>.
453           */
InternalFrameBorder(JInternalFrame aFrame)454         public InternalFrameBorder(JInternalFrame aFrame) {
455             super(aFrame);
456             frame = aFrame;
457         }
458 
459         /** Sets the InternalFrameBorder's InternalFrame.
460           */
setFrame(JInternalFrame aFrame)461         public void setFrame(JInternalFrame aFrame) {
462             frame = aFrame;
463         }
464 
465         /** Returns the InternalFrameBorder's InternalFrame.
466           * @see #setFrame
467           */
frame()468         public JInternalFrame frame() {
469             return frame;
470         }
471 
472         /** Returns the width of the InternalFrameBorder's resize controls,
473           * appearing along the InternalFrameBorder's bottom border.  Clicking
474           * and dragging within these controls lets the user change both the
475           * InternalFrame's width and height, while dragging between the controls
476           * constrains resizing to just the vertical dimension.  Override this
477           * method if you implement your own bottom border painting and use a
478           * resize control with a different size.
479           */
resizePartWidth()480         public int resizePartWidth() {
481             if (!frame.isResizable()) {
482                 return 0;
483             }
484             return FrameBorder.BORDER_SIZE;
485         }
486 
487         /** Draws the InternalFrameBorder's top border.
488          */
drawTopBorder(Component c, Graphics g, int x, int y, int width, int height)489         protected boolean drawTopBorder(Component c, Graphics g,
490                                     int x, int y, int width, int height) {
491             if (super.drawTopBorder(c, g, x, y, width, height) &&
492                 frame.isResizable()) {
493                 g.setColor(getFrameShadow());
494                 g.drawLine(CORNER_SIZE - 1, y + 1, CORNER_SIZE - 1, y + 4);
495                 g.drawLine(width - CORNER_SIZE - 1, y + 1,
496                        width - CORNER_SIZE - 1, y + 4);
497 
498                 g.setColor(getFrameHighlight());
499                 g.drawLine(CORNER_SIZE, y, CORNER_SIZE, y + 4);
500                 g.drawLine(width - CORNER_SIZE, y, width - CORNER_SIZE, y + 4);
501                 return true;
502             }
503             return false;
504         }
505 
506         /** Draws the InternalFrameBorder's left border.
507           */
drawLeftBorder(Component c, Graphics g, int x, int y, int width, int height)508         protected boolean drawLeftBorder(Component c, Graphics g, int x, int y,
509                                      int width, int height) {
510             if (super.drawLeftBorder(c, g, x, y, width, height) &&
511                 frame.isResizable()) {
512                 g.setColor(getFrameHighlight());
513                 int topY = y + CORNER_SIZE;
514                 g.drawLine(x, topY, x + 4, topY);
515                 int bottomY = height - CORNER_SIZE;
516                 g.drawLine(x + 1, bottomY, x + 5, bottomY);
517                 g.setColor(getFrameShadow());
518                 g.drawLine(x + 1, topY - 1, x + 5, topY - 1);
519                 g.drawLine(x + 1, bottomY - 1, x + 5, bottomY - 1);
520                 return true;
521             }
522             return false;
523         }
524 
525         /** Draws the InternalFrameBorder's right border.
526           */
drawRightBorder(Component c, Graphics g, int x, int y, int width, int height)527         protected boolean drawRightBorder(Component c, Graphics g, int x, int y,
528                                       int width, int height) {
529             if (super.drawRightBorder(c, g, x, y, width, height) &&
530                 frame.isResizable()) {
531                 int startX = width - getBorderInsets(c).right;
532                 g.setColor(getFrameHighlight());
533                 int topY = y + CORNER_SIZE;
534                 g.drawLine(startX, topY, width - 2, topY);
535                 int bottomY = height - CORNER_SIZE;
536                 g.drawLine(startX + 1, bottomY, startX + 3, bottomY);
537                 g.setColor(getFrameShadow());
538                 g.drawLine(startX + 1, topY - 1, width - 2, topY - 1);
539                 g.drawLine(startX + 1, bottomY - 1, startX + 3, bottomY - 1);
540                 return true;
541             }
542             return false;
543         }
544 
545         /** Draws the InternalFrameBorder's bottom border.
546           */
drawBottomBorder(Component c, Graphics g, int x, int y, int width, int height)547         protected boolean drawBottomBorder(Component c, Graphics g, int x, int y,
548                                        int width, int height) {
549             if (super.drawBottomBorder(c, g, x, y, width, height) &&
550                 frame.isResizable()) {
551                 int startY = height - getBorderInsets(c).bottom;
552 
553                 g.setColor(getFrameShadow());
554                 g.drawLine(CORNER_SIZE - 1, startY + 1,
555                        CORNER_SIZE - 1, height - 1);
556                 g.drawLine(width - CORNER_SIZE, startY + 1,
557                        width - CORNER_SIZE, height - 1);
558 
559                 g.setColor(getFrameHighlight());
560                 g.drawLine(CORNER_SIZE, startY, CORNER_SIZE, height - 2);
561                 g.drawLine(width - CORNER_SIZE + 1, startY,
562                        width - CORNER_SIZE + 1, height - 2);
563                 return true;
564             }
565             return false;
566         }
567 
568         // Returns true if the associated internal frame has focus.
isActiveFrame()569         protected boolean isActiveFrame() {
570             return frame.isSelected();
571         }
572     }
573 
drawBezel(Graphics g, int x, int y, int w, int h, boolean isPressed, boolean hasFocus, Color shadow, Color highlight, Color darkShadow, Color focus)574     public static void drawBezel(Graphics g, int x, int y, int w, int h,
575                                boolean isPressed, boolean hasFocus,
576                                Color shadow, Color highlight,
577                                Color darkShadow, Color focus)  {
578 
579         Color oldColor = g.getColor();
580         g.translate(x, y);
581 
582         if (isPressed) {
583             if (hasFocus){
584                 g.setColor(focus);
585                 g.drawRect(0, 0, w-1, h-1);
586             }
587             g.setColor(shadow);         // inner border
588             g.drawRect(1, 1, w-3, h-3);
589 
590             g.setColor(highlight);    // inner 3D border
591             g.drawLine(2, h-3, w-3, h-3);
592             g.drawLine(w-3, 2, w-3, h-4);
593 
594         } else {
595             if (hasFocus) {
596                 g.setColor(focus);
597                 g.drawRect(0, 0, w-1, h-1);
598 
599                 g.setColor(highlight);   // inner 3D border
600                 g.drawLine(1, 1, 1, h-3);
601                 g.drawLine(2, 1, w-4, 1);
602 
603                 g.setColor(shadow);
604                 g.drawLine(2, h-3, w-3, h-3);
605                 g.drawLine(w-3, 1, w-3, h-4);
606 
607                 g.setColor(darkShadow);        // black drop shadow  __|
608                 g.drawLine(1, h-2, w-2, h-2);
609                 g.drawLine(w-2, h-2, w-2, 1);
610             } else {
611                 g.setColor(highlight);    // inner 3D border
612                 g.drawLine(1,1,1,h-3);
613                 g.drawLine(2,1,w-4,1);
614                 g.setColor(shadow);
615                 g.drawLine(2,h-3,w-3,h-3);
616                 g.drawLine(w-3,1,w-3,h-4);
617 
618                 g.setColor(darkShadow);         // black drop shadow  __|
619                 g.drawLine(1,h-2,w-2,h-2);
620                 g.drawLine(w-2,h-2,w-2,0);
621 
622             }
623             g.translate(-x, -y);
624         }
625         g.setColor(oldColor);
626     }
627 
628     @SuppressWarnings("serial") // Superclass is not serializable across versions
629     public static class MotifPopupMenuBorder extends AbstractBorder implements UIResource {
630         protected Font   font;
631         protected Color  background;
632         protected Color  foreground;
633         protected Color  shadowColor;
634         protected Color  highlightColor;
635 
636         // Space between the border and text
637         protected static final int TEXT_SPACING = 2;
638 
639         // Space for the separator under the title
640         protected static final int GROOVE_HEIGHT = 2;
641 
642         /**
643          * Creates a MotifPopupMenuBorder instance
644          *
645          */
MotifPopupMenuBorder( Font titleFont, Color bgColor, Color fgColor, Color shadow, Color highlight)646         public MotifPopupMenuBorder(
647                                     Font titleFont,
648                                     Color bgColor,
649                                     Color fgColor,
650                                     Color shadow,
651                                     Color highlight)       {
652             this.font = titleFont;
653             this.background = bgColor;
654             this.foreground = fgColor;
655             this.shadowColor = shadow;
656             this.highlightColor = highlight;
657         }
658 
659         /**
660          * Paints the border for the specified component with the
661          * specified position and size.
662          * @param c the component for which this border is being painted
663          * @param g the paint graphics
664          * @param x the x position of the painted border
665          * @param y the y position of the painted border
666          * @param width the width of the painted border
667          * @param height the height of the painted border
668          */
paintBorder(Component c, Graphics g, int x, int y, int width, int height)669         public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
670             if (!(c instanceof JPopupMenu)) {
671                 return;
672             }
673 
674             Font origFont = g.getFont();
675             Color origColor = g.getColor();
676             JPopupMenu popup = (JPopupMenu)c;
677 
678             String title = popup.getLabel();
679             if (title == null) {
680                 return;
681             }
682 
683             g.setFont(font);
684 
685             FontMetrics fm = SwingUtilities2.getFontMetrics(popup, g, font);
686             int         fontHeight = fm.getHeight();
687             int         descent = fm.getDescent();
688             int         ascent = fm.getAscent();
689             Point       textLoc = new Point();
690             int         stringWidth = SwingUtilities2.stringWidth(popup, fm,
691                                                                   title);
692 
693             textLoc.y = y + ascent + TEXT_SPACING;
694             textLoc.x = x + ((width - stringWidth) / 2);
695 
696             g.setColor(background);
697             g.fillRect(textLoc.x - TEXT_SPACING, textLoc.y - (fontHeight-descent),
698                        stringWidth + (2 * TEXT_SPACING), fontHeight - descent);
699             g.setColor(foreground);
700             SwingUtilities2.drawString(popup, g, title, textLoc.x, textLoc.y);
701 
702             MotifGraphicsUtils.drawGroove(g, x, textLoc.y + TEXT_SPACING,
703                                           width, GROOVE_HEIGHT,
704                                           shadowColor, highlightColor);
705 
706             g.setFont(origFont);
707             g.setColor(origColor);
708         }
709 
710         /**
711          * Reinitialize the insets parameter with this Border's current Insets.
712          * @param c the component for which this border insets value applies
713          * @param insets the object to be reinitialized
714          */
getBorderInsets(Component c, Insets insets)715         public Insets getBorderInsets(Component c, Insets insets) {
716             if (!(c instanceof JPopupMenu)) {
717                 return insets;
718             }
719             FontMetrics fm;
720             int         descent = 0;
721             int         ascent = 16;
722 
723             String title = ((JPopupMenu)c).getLabel();
724             if (title == null) {
725                 insets.left = insets.top = insets.right = insets.bottom = 0;
726                 return insets;
727             }
728 
729             fm = c.getFontMetrics(font);
730 
731             if(fm != null) {
732                 descent = fm.getDescent();
733                 ascent = fm.getAscent();
734             }
735 
736             insets.top += ascent + descent + TEXT_SPACING + GROOVE_HEIGHT;
737             return insets;
738         }
739 
740     }
741 
742 }
743