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