1. /*
  2. * @(#)MotifGraphicsUtils.java 1.36 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 java.awt.Color;
  10. import java.awt.Dimension;
  11. import java.awt.Graphics;
  12. import java.awt.Font;
  13. import java.awt.FontMetrics;
  14. import java.awt.Rectangle;
  15. import java.awt.Component;
  16. import java.awt.Insets;
  17. import java.awt.event.KeyEvent;
  18. import javax.swing.plaf.basic.*;
  19. import javax.swing.text.View;
  20. /*
  21. * @version 1.36 11/29/01
  22. * @author Jeff Dinkins
  23. * @author Dave Kloba
  24. */
  25. public class MotifGraphicsUtils implements SwingConstants
  26. {
  27. /**
  28. * Draws the point (<b>x</b>, <b>y</b>) in the current color.
  29. */
  30. static void drawPoint(Graphics g, int x, int y) {
  31. g.drawLine(x, y, x, y);
  32. }
  33. /*
  34. * Convenience method for drawing a grooved line
  35. *
  36. */
  37. public static void drawGroove(Graphics g, int x, int y, int w, int h,
  38. Color shadow, Color highlight)
  39. {
  40. Color oldColor = g.getColor(); // Make no net change to g
  41. g.translate(x, y);
  42. g.setColor(shadow);
  43. g.drawRect(0, 0, w-2, h-2);
  44. g.setColor(highlight);
  45. g.drawLine(1, h-3, 1, 1);
  46. g.drawLine(1, 1, w-3, 1);
  47. g.drawLine(0, h-1, w-1, h-1);
  48. g.drawLine(w-1, h-1, w-1, 0);
  49. g.translate(-x, -y);
  50. g.setColor(oldColor);
  51. }
  52. /** Draws <b>aString</b> in the rectangle defined by
  53. * (<b>x</b>, <b>y</b>, <b>width</b>, <b>height</b>).
  54. * <b>justification</b> specifies the text's justification, one of
  55. * LEFT, CENTER, or RIGHT.
  56. * <b>drawStringInRect()</b> does not clip to the rectangle, but instead
  57. * uses this rectangle and the desired justification to compute the point
  58. * at which to begin drawing the text.
  59. * @see #drawString
  60. */
  61. public static void drawStringInRect(Graphics g, String aString, int x, int y,
  62. int width, int height, int justification) {
  63. FontMetrics fontMetrics;
  64. int drawWidth, startX, startY, delta;
  65. if (g.getFont() == null) {
  66. // throw new InconsistencyException("No font set");
  67. return;
  68. }
  69. fontMetrics = g.getFontMetrics();
  70. if (fontMetrics == null) {
  71. // throw new InconsistencyException("No metrics for Font " + font());
  72. return;
  73. }
  74. if (justification == CENTER) {
  75. drawWidth = fontMetrics.stringWidth(aString);
  76. if (drawWidth > width) {
  77. drawWidth = width;
  78. }
  79. startX = x + (width - drawWidth) / 2;
  80. } else if (justification == RIGHT) {
  81. drawWidth = fontMetrics.stringWidth(aString);
  82. if (drawWidth > width) {
  83. drawWidth = width;
  84. }
  85. startX = x + width - drawWidth;
  86. } else {
  87. startX = x;
  88. }
  89. delta = (height - fontMetrics.getAscent() - fontMetrics.getDescent()) / 2;
  90. if (delta < 0) {
  91. delta = 0;
  92. }
  93. startY = y + height - delta - fontMetrics.getDescent();
  94. g.drawString(aString, startX, startY);
  95. }
  96. public static void paintMenuItem(Graphics g, JComponent c,
  97. Icon checkIcon, Icon arrowIcon,
  98. Color background, Color foreground,
  99. int defaultTextIconGap)
  100. {
  101. JMenuItem b = (JMenuItem) c;
  102. ButtonModel model = b.getModel();
  103. Dimension size = b.getSize();
  104. Insets i = c.getInsets();
  105. Rectangle viewRect = new Rectangle(size);
  106. viewRect.x += i.left;
  107. viewRect.y += i.top;
  108. viewRect.width -= (i.right + viewRect.x);
  109. viewRect.height -= (i.bottom + viewRect.y);
  110. Rectangle iconRect = new Rectangle();
  111. Rectangle textRect = new Rectangle();
  112. Rectangle acceleratorRect = new Rectangle();
  113. Rectangle checkRect = new Rectangle();
  114. Rectangle arrowRect = new Rectangle();
  115. Font holdf = g.getFont();
  116. Font f = c.getFont();
  117. g.setFont(f);
  118. FontMetrics fm = g.getFontMetrics(f);
  119. FontMetrics fmAccel = g.getFontMetrics( UIManager.getFont("MenuItem.acceleratorFont") );
  120. if (c.isOpaque()) {
  121. if (model.isArmed()|| (c instanceof JMenu && model.isSelected())) {
  122. g.setColor(background);
  123. } else {
  124. g.setColor(c.getBackground());
  125. }
  126. g.fillRect(0,0, size.width, size.height);
  127. }
  128. // get Accelerator text
  129. KeyStroke accelerator = b.getAccelerator();
  130. String acceleratorText = "";
  131. if (accelerator != null) {
  132. int modifiers = accelerator.getModifiers();
  133. if (modifiers > 0) {
  134. acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
  135. acceleratorText += "+";
  136. }
  137. acceleratorText += KeyEvent.getKeyText(accelerator.getKeyCode());
  138. }
  139. // layout the text and icon
  140. String text = layoutMenuItem(c, fm, b.getText(), fmAccel,
  141. acceleratorText, b.getIcon(),
  142. checkIcon, arrowIcon,
  143. b.getVerticalAlignment(),
  144. b.getHorizontalAlignment(),
  145. b.getVerticalTextPosition(),
  146. b.getHorizontalTextPosition(),
  147. viewRect, iconRect,
  148. textRect, acceleratorRect,
  149. checkRect, arrowRect,
  150. b.getText() == null
  151. ? 0 : defaultTextIconGap,
  152. defaultTextIconGap
  153. );
  154. // Paint the Check
  155. Color holdc = g.getColor();
  156. if (checkIcon != null) {
  157. if(model.isArmed() || (c instanceof JMenu && model.isSelected()))
  158. g.setColor(foreground);
  159. checkIcon.paintIcon(c, g, checkRect.x, checkRect.y);
  160. g.setColor(holdc);
  161. }
  162. // Paint the Icon
  163. if(b.getIcon() != null) {
  164. Icon icon;
  165. if(!model.isEnabled()) {
  166. icon = (Icon) b.getDisabledIcon();
  167. } else if(model.isPressed() && model.isArmed()) {
  168. icon = (Icon) b.getPressedIcon();
  169. if(icon == null) {
  170. // Use default icon
  171. icon = (Icon) b.getIcon();
  172. }
  173. } else {
  174. icon = (Icon) b.getIcon();
  175. }
  176. if (icon!=null) {
  177. icon.paintIcon(c, g, iconRect.x, iconRect.y);
  178. }
  179. }
  180. // Draw the Text
  181. if(text != null && !text.equals("")) {
  182. // Once BasicHTML becomes public, use BasicHTML.propertyKey
  183. // instead of the hardcoded string below!
  184. View v = (View) c.getClientProperty("html");
  185. if (v != null) {
  186. v.paint(g, textRect);
  187. } else {
  188. if(!model.isEnabled()) {
  189. // *** paint the text disabled
  190. g.setColor(b.getBackground().brighter());
  191. BasicGraphicsUtils.drawString(g,text,model.getMnemonic(),
  192. textRect.x, textRect.y + fmAccel.getAscent());
  193. g.setColor(b.getBackground().darker());
  194. BasicGraphicsUtils.drawString(g,text,model.getMnemonic(),
  195. textRect.x - 1, textRect.y + fmAccel.getAscent() - 1);
  196. } else {
  197. // *** paint the text normally
  198. if (model.isArmed()|| (c instanceof JMenu && model.isSelected())) {
  199. g.setColor(foreground);
  200. } else {
  201. g.setColor(b.getForeground());
  202. }
  203. BasicGraphicsUtils.drawString(g,text,
  204. model.getMnemonic(),
  205. textRect.x,
  206. textRect.y + fm.getAscent());
  207. }
  208. }
  209. }
  210. // Draw the Accelerator Text
  211. if(acceleratorText != null && !acceleratorText.equals("")) {
  212. g.setFont( UIManager.getFont("MenuItem.acceleratorFont") );
  213. if(!model.isEnabled()) {
  214. // *** paint the acceleratorText disabled
  215. g.setColor(b.getBackground().brighter());
  216. BasicGraphicsUtils.drawString(g,acceleratorText,0,
  217. acceleratorRect.x, acceleratorRect.y + fm.getAscent());
  218. g.setColor(b.getBackground().darker());
  219. BasicGraphicsUtils.drawString(g,acceleratorText,0,
  220. acceleratorRect.x - 1, acceleratorRect.y + fm.getAscent() - 1);
  221. } else {
  222. // *** paint the acceleratorText normally
  223. if (model.isArmed()|| (c instanceof JMenu && model.isSelected()))
  224. {
  225. g.setColor(foreground);
  226. } else {
  227. g.setColor(b.getForeground());
  228. }
  229. BasicGraphicsUtils.drawString(g,acceleratorText, 0,
  230. acceleratorRect.x,
  231. acceleratorRect.y + fmAccel.getAscent());
  232. }
  233. }
  234. // Paint the Arrow
  235. if (arrowIcon != null) {
  236. if(model.isArmed() || (c instanceof JMenu && model.isSelected()))
  237. g.setColor(foreground);
  238. if( !(b.getParent() instanceof JMenuBar) )
  239. arrowIcon.paintIcon(c, g, arrowRect.x, arrowRect.y);
  240. }
  241. g.setColor(holdc);
  242. g.setFont(holdf);
  243. }
  244. /**
  245. * Compute and return the location of the icons origin, the
  246. * location of origin of the text baseline, and a possibly clipped
  247. * version of the compound labels string. Locations are computed
  248. * relative to the viewR rectangle.
  249. */
  250. private static String layoutMenuItem(
  251. JComponent c,
  252. FontMetrics fm,
  253. String text,
  254. FontMetrics fmAccel,
  255. String acceleratorText,
  256. Icon icon,
  257. Icon checkIcon,
  258. Icon arrowIcon,
  259. int verticalAlignment,
  260. int horizontalAlignment,
  261. int verticalTextPosition,
  262. int horizontalTextPosition,
  263. Rectangle viewR,
  264. Rectangle iconR,
  265. Rectangle textR,
  266. Rectangle acceleratorR,
  267. Rectangle checkIconR,
  268. Rectangle arrowIconR,
  269. int textIconGap,
  270. int menuItemGap
  271. )
  272. {
  273. SwingUtilities.layoutCompoundLabel(c,
  274. fm,
  275. text,
  276. icon,
  277. verticalAlignment,
  278. horizontalAlignment,
  279. verticalTextPosition,
  280. horizontalTextPosition,
  281. viewR,
  282. iconR,
  283. textR,
  284. textIconGap);
  285. /* Initialize the acceelratorText bounds rectangle textR. If a null
  286. * or and empty String was specified we substitute "" here
  287. * and use 0,0,0,0 for acceleratorTextR.
  288. */
  289. if( (acceleratorText == null) || acceleratorText.equals("") ) {
  290. acceleratorR.width = acceleratorR.height = 0;
  291. acceleratorText = "";
  292. }
  293. else {
  294. acceleratorR.width
  295. = SwingUtilities.computeStringWidth(fmAccel, acceleratorText);
  296. acceleratorR.height = fmAccel.getHeight();
  297. }
  298. /* Initialize the checkIcon bounds rectangle checkIconR.
  299. */
  300. if (checkIcon != null) {
  301. checkIconR.width = checkIcon.getIconWidth();
  302. checkIconR.height = checkIcon.getIconHeight();
  303. }
  304. else {
  305. checkIconR.width = checkIconR.height = 0;
  306. }
  307. /* Initialize the arrowIcon bounds rectangle arrowIconR.
  308. */
  309. if (arrowIcon != null) {
  310. arrowIconR.width = arrowIcon.getIconWidth();
  311. arrowIconR.height = arrowIcon.getIconHeight();
  312. }
  313. else {
  314. arrowIconR.width = arrowIconR.height = 0;
  315. }
  316. Rectangle labelR = iconR.union(textR);
  317. if( MotifGraphicsUtils.isLeftToRight(c) ) {
  318. textR.x += checkIconR.width + menuItemGap;
  319. iconR.x += checkIconR.width + menuItemGap;
  320. // Position the Accelerator text rect
  321. acceleratorR.x = viewR.x + viewR.width - arrowIconR.width
  322. - menuItemGap - acceleratorR.width;
  323. // Position the Check and Arrow Icons
  324. checkIconR.x = viewR.x;
  325. arrowIconR.x = viewR.x + viewR.width - menuItemGap
  326. - arrowIconR.width;
  327. } else {
  328. textR.x -= (checkIconR.width + menuItemGap);
  329. iconR.x -= (checkIconR.width + menuItemGap);
  330. // Position the Accelerator text rect
  331. acceleratorR.x = viewR.x + arrowIconR.width + menuItemGap;
  332. // Position the Check and Arrow Icons
  333. checkIconR.x = viewR.x + viewR.width - checkIconR.width;
  334. arrowIconR.x = viewR.x + menuItemGap;
  335. }
  336. // Align the accelertor text and the check and arrow icons vertically
  337. // with the center of the label rect.
  338. acceleratorR.y = labelR.y + (labelR.height2) - (acceleratorR.height2);
  339. arrowIconR.y = labelR.y + (labelR.height2) - (arrowIconR.height2);
  340. checkIconR.y = labelR.y + (labelR.height2) - (checkIconR.height2);
  341. /*
  342. System.out.println("Layout: v=" +viewR+" c="+checkIconR+" i="+
  343. iconR+" t="+textR+" acc="+acceleratorR+" a="+arrowIconR);
  344. */
  345. return text;
  346. }
  347. private static void drawMenuBezel(Graphics g, Color background,
  348. int x, int y,
  349. int width, int height)
  350. {
  351. // shadowed button region
  352. g.setColor(background);
  353. g.fillRect(x,y,width,height);
  354. g.setColor(background.brighter().brighter());
  355. g.drawLine(x+1, y+height-1, x+width-1, y+height-1);
  356. g.drawLine(x+width-1, y+height-2, x+width-1, y+1);
  357. g.setColor(background.darker().darker());
  358. g.drawLine(x, y, x+width-2, y);
  359. g.drawLine(x, y+1, x, y+height-2);
  360. }
  361. /*
  362. * Convenience function for determining ComponentOrientation. Helps us
  363. * avoid having Munge directives throughout the code.
  364. */
  365. static boolean isLeftToRight( Component c ) {
  366. /*if[JDK1.2]
  367. return c.getComponentOrientation().isLeftToRight();
  368. else[JDK1.2]*/
  369. return true;
  370. /*end[JDK1.2]*/
  371. }
  372. }