1. /*
  2. * @(#)MotifPopupMenuUI.java 1.17 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.motif;
  8. import javax.swing.*;
  9. import javax.swing.event.*;
  10. import javax.swing.border.*;
  11. import java.awt.Color;
  12. import java.awt.Component;
  13. import java.awt.Container;
  14. import java.awt.Dimension;
  15. import java.awt.Font;
  16. import java.awt.FontMetrics;
  17. import java.awt.Frame;
  18. import java.awt.Graphics;
  19. import java.awt.Insets;
  20. import java.awt.LayoutManager;
  21. import java.awt.Point;
  22. import java.awt.Rectangle;
  23. import java.awt.event.*;
  24. import javax.swing.plaf.*;
  25. import javax.swing.plaf.basic.BasicPopupMenuUI;
  26. /**
  27. * A Motif L&F implementation of PopupMenuUI.
  28. * <p>
  29. * <strong>Warning:</strong>
  30. * Serialized objects of this class will not be compatible with
  31. * future Swing releases. The current serialization support is appropriate
  32. * for short term storage or RMI between applications running the same
  33. * version of Swing. A future release of Swing will provide support for
  34. * long term persistence.
  35. *
  36. * @version 1.17 11/29/01
  37. * @author Georges Saab
  38. * @author Rich Schiavi
  39. */
  40. public class MotifPopupMenuUI extends BasicPopupMenuUI {
  41. private static Border border = null;
  42. private Font titleFont = null;
  43. public static ComponentUI createUI(JComponent x) {
  44. return new MotifPopupMenuUI();
  45. }
  46. /* This has to deal with the fact that the title may be wider than
  47. the widest child component.
  48. */
  49. public Dimension getPreferredSize(JComponent c) {
  50. LayoutManager layout = c.getLayout();
  51. Dimension d = layout.preferredLayoutSize(c);
  52. String title = ((JPopupMenu)c).getLabel();
  53. if (titleFont == null) {
  54. UIDefaults table = UIManager.getLookAndFeelDefaults();
  55. titleFont = table.getFont("PopupMenu.font");
  56. }
  57. FontMetrics fm = c.getFontMetrics(titleFont);
  58. int stringWidth = 0;
  59. if (title!=null) {
  60. stringWidth +=fm.stringWidth(title);
  61. }
  62. if (d.width < stringWidth) {
  63. d.width = stringWidth + 8;
  64. Insets i = c.getInsets();
  65. if (i!=null) {
  66. d.width += i.left + i.right;
  67. }
  68. if (border != null) {
  69. i = border.getBorderInsets(c);
  70. d.width += i.left + i.right;
  71. }
  72. return d;
  73. }
  74. return null;
  75. }
  76. public void installDefaults() {
  77. // This should all go in the table, but can't until we can
  78. // have API Change to add the borders to the factory...
  79. UIDefaults table = UIManager.getLookAndFeelDefaults();
  80. if (border == null) {
  81. border = new CompoundUIResourceBorder(
  82. new MotifBorders.BevelBorder(true,
  83. table.getColor("controlShadow"),
  84. table.getColor("controlLtHighlight")),
  85. new MotifPopupMenuBorder(
  86. table.getFont("PopupMenu.font"),
  87. table.getColor("PopupMenu.background"),
  88. table.getColor("PopupMenu.foreground"),
  89. table.getColor("controlShadow"),
  90. table.getColor("controlLtHighlight")
  91. ));
  92. }
  93. table.put("PopupMenu.border", border);
  94. super.installDefaults();
  95. }
  96. protected ChangeListener createChangeListener(JPopupMenu m) {
  97. return new ChangeListener() {
  98. public void stateChanged(ChangeEvent e) {}
  99. };
  100. }
  101. private static class CompoundUIResourceBorder extends CompoundBorder implements UIResource {
  102. public CompoundUIResourceBorder(Border a, Border b) {
  103. super(a,b);
  104. }
  105. }
  106. /*
  107. * Fix to 4187004:
  108. * This class is currently private since API changes are not allowed.
  109. * When they are, it should be moved to MotifBorderFactory and made
  110. * public. At that time, the installDefaults method above can
  111. * be removed and the defaults table in MotifLookAndFeel updated.
  112. */
  113. private static class MotifPopupMenuBorder extends AbstractBorder implements UIResource {
  114. protected Font font;
  115. protected Color background;
  116. protected Color foreground;
  117. protected Color shadowColor;
  118. protected Color highlightColor;
  119. // Space between the border and text
  120. static protected final int TEXT_SPACING = 2;
  121. // Space for the separator under the title
  122. static protected final int GROOVE_HEIGHT = 2;
  123. /**
  124. * Creates a MotifPopupMenuBorder instance
  125. *
  126. */
  127. public MotifPopupMenuBorder(
  128. Font titleFont,
  129. Color bgColor,
  130. Color fgColor,
  131. Color shadow,
  132. Color highlight) {
  133. this.font = titleFont;
  134. this.background = bgColor;
  135. this.foreground = fgColor;
  136. this.shadowColor = shadow;
  137. this.highlightColor = highlight;
  138. }
  139. /**
  140. * Paints the border for the specified component with the
  141. * specified position and size.
  142. * @param c the component for which this border is being painted
  143. * @param g the paint graphics
  144. * @param x the x position of the painted border
  145. * @param y the y position of the painted border
  146. * @param width the width of the painted border
  147. * @param height the height of the painted border
  148. */
  149. public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
  150. Font origFont = g.getFont();
  151. Color origColor = g.getColor();
  152. String title = ((JPopupMenu)c).getLabel();
  153. if (title == null) {
  154. return;
  155. }
  156. g.setFont(font);
  157. FontMetrics fm = g.getFontMetrics();
  158. int fontHeight = fm.getHeight();
  159. int descent = fm.getDescent();
  160. int ascent = fm.getAscent();
  161. Point textLoc = new Point();
  162. int stringWidth = fm.stringWidth(title);
  163. textLoc.y = y + ascent + TEXT_SPACING;
  164. textLoc.x = x + ((width - stringWidth) / 2);
  165. g.setColor(background);
  166. g.fillRect(textLoc.x - TEXT_SPACING, textLoc.y - (fontHeight-descent),
  167. stringWidth + (2 * TEXT_SPACING), fontHeight - descent);
  168. g.setColor(foreground);
  169. g.drawString(title, textLoc.x, textLoc.y);
  170. MotifGraphicsUtils.drawGroove(g, x, textLoc.y + TEXT_SPACING,
  171. width, GROOVE_HEIGHT,
  172. shadowColor, highlightColor);
  173. g.setFont(origFont);
  174. g.setColor(origColor);
  175. }
  176. /**
  177. * Returns the insets of the border.
  178. * @param c the component for which this border insets value applies
  179. */
  180. public Insets getBorderInsets(Component c) {
  181. return getBorderInsets(c, new Insets(0, 0, 0, 0));
  182. }
  183. /**
  184. * Reinitialize the insets parameter with this Border's current Insets.
  185. * @param c the component for which this border insets value applies
  186. * @param insets the object to be reinitialized
  187. */
  188. public Insets getBorderInsets(Component c, Insets insets) {
  189. FontMetrics fm;
  190. int descent = 0;
  191. int ascent = 16;
  192. String title = ((JPopupMenu)c).getLabel();
  193. if (title == null) {
  194. insets.left = insets.top = insets.right = insets.bottom = 0;
  195. return insets;
  196. }
  197. fm = c.getFontMetrics(font);
  198. if(fm != null) {
  199. descent = fm.getDescent();
  200. ascent = fm.getAscent();
  201. }
  202. insets.top += ascent + descent + TEXT_SPACING + GROOVE_HEIGHT;
  203. return insets;
  204. }
  205. }
  206. }