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 
  63         public BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) {
  64             this.isRaised = isRaised;
  65             this.darkShadow = darkShadow;
  66             this.lightShadow = lightShadow;
  67         }
  68 
  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 
  79         public Insets getBorderInsets(Component c, Insets insets) {
  80             insets.set(1, 1, 1, 1);
  81             return insets;
  82         }
  83 
  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 
  96         public FocusBorder(Color control, Color focus) {
  97             this.control = control;
  98             this.focus = focus;
  99         }
 100 
 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 
 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 
 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 
 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 
 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 
 200         public ToggleButtonBorder(Color shadow, Color highlight, Color darkShadow, Color focus) {
 201              super(shadow, highlight, darkShadow, focus);
 202         }
 203 
 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 
 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 
 234         public MenuBarBorder(Color shadow, Color highlight, Color darkShadow, Color focus) {
 235             super(shadow, highlight, darkShadow, focus);
 236         }
 237 
 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 
 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         */
 270         public FrameBorder(JComponent comp) {
 271             jcomp = comp;
 272         }
 273 
 274         /** Sets the FrameBorder's JComponent.
 275       */
 276         public void setComponent(JComponent comp) {
 277             jcomp = comp;
 278         }
 279 
 280         /** Returns the FrameBorder's JComponent.
 281           * @see #setComponent
 282           */
 283         public JComponent component() {
 284             return jcomp;
 285         }
 286 
 287         protected Color getFrameHighlight() {
 288             return frameHighlight;
 289         }
 290 
 291         protected Color getFrameColor() {
 292             return frameColor;
 293         }
 294 
 295         protected Color getFrameShadow() {
 296             return frameShadow;
 297         }
 298 
 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          */
 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           */
 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           */
 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           */
 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.
 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           */
 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           */
 454         public InternalFrameBorder(JInternalFrame aFrame) {
 455             super(aFrame);
 456             frame = aFrame;
 457         }
 458 
 459         /** Sets the InternalFrameBorder's InternalFrame.
 460           */
 461         public void setFrame(JInternalFrame aFrame) {
 462             frame = aFrame;
 463         }
 464 
 465         /** Returns the InternalFrameBorder's InternalFrame.
 466           * @see #setFrame
 467           */
 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           */
 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          */
 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           */
 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           */
 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           */
 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.
 569         protected boolean isActiveFrame() {
 570             return frame.isSelected();
 571         }
 572     }
 573 
 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          */
 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          */
 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.getTextUIDrawing(popup)
 691                     .getStringWidth(popup, fm, 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.getTextUIDrawing(popup)
 701                     .drawString(popup, g, title, textLoc.x, textLoc.y);
 702 
 703             MotifGraphicsUtils.drawGroove(g, x, textLoc.y + TEXT_SPACING,
 704                                           width, GROOVE_HEIGHT,
 705                                           shadowColor, highlightColor);
 706 
 707             g.setFont(origFont);
 708             g.setColor(origColor);
 709         }
 710 
 711         /**
 712          * Reinitialize the insets parameter with this Border's current Insets.
 713          * @param c the component for which this border insets value applies
 714          * @param insets the object to be reinitialized
 715          */
 716         public Insets getBorderInsets(Component c, Insets insets) {
 717             if (!(c instanceof JPopupMenu)) {
 718                 return insets;
 719             }
 720             FontMetrics fm;
 721             int         descent = 0;
 722             int         ascent = 16;
 723 
 724             String title = ((JPopupMenu)c).getLabel();
 725             if (title == null) {
 726                 insets.left = insets.top = insets.right = insets.bottom = 0;
 727                 return insets;
 728             }
 729 
 730             fm = c.getFontMetrics(font);
 731 
 732             if(fm != null) {
 733                 descent = fm.getDescent();
 734                 ascent = fm.getAscent();
 735             }
 736 
 737             insets.top += ascent + descent + TEXT_SPACING + GROOVE_HEIGHT;
 738             return insets;
 739         }
 740 
 741     }
 742 
 743 }