1. /*
  2. * @(#)WindowsButtonUI.java 1.35 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.windows;
  8. import javax.swing.plaf.basic.*;
  9. import javax.swing.border.*;
  10. import javax.swing.plaf.*;
  11. import javax.swing.*;
  12. import java.awt.*;
  13. /**
  14. * Windows button.
  15. * <p>
  16. * <strong>Warning:</strong>
  17. * Serialized objects of this class will not be compatible with
  18. * future Swing releases. The current serialization support is appropriate
  19. * for short term storage or RMI between applications running the same
  20. * version of Swing. A future release of Swing will provide support for
  21. * long term persistence.
  22. *
  23. * @version 1.35 12/19/03
  24. * @author Jeff Dinkins
  25. *
  26. */
  27. public class WindowsButtonUI extends BasicButtonUI
  28. {
  29. private final static WindowsButtonUI windowsButtonUI = new WindowsButtonUI();
  30. protected int dashedRectGapX;
  31. protected int dashedRectGapY;
  32. protected int dashedRectGapWidth;
  33. protected int dashedRectGapHeight;
  34. protected Color focusColor;
  35. private boolean defaults_initialized = false;
  36. // ********************************
  37. // Create PLAF
  38. // ********************************
  39. public static ComponentUI createUI(JComponent c){
  40. return windowsButtonUI;
  41. }
  42. // ********************************
  43. // Create Listeners
  44. // ********************************
  45. protected BasicButtonListener createButtonListener(AbstractButton b) {
  46. return super.createButtonListener(b);
  47. }
  48. // ********************************
  49. // Defaults
  50. // ********************************
  51. protected void installDefaults(AbstractButton b) {
  52. super.installDefaults(b);
  53. if(!defaults_initialized) {
  54. String pp = getPropertyPrefix();
  55. dashedRectGapX = UIManager.getInt(pp + "dashedRectGapX");
  56. dashedRectGapY = UIManager.getInt(pp + "dashedRectGapY");
  57. dashedRectGapWidth = UIManager.getInt(pp + "dashedRectGapWidth");
  58. dashedRectGapHeight = UIManager.getInt(pp + "dashedRectGapHeight");
  59. focusColor = UIManager.getColor(pp + "focus");
  60. defaults_initialized = true;
  61. }
  62. XPStyle xp = XPStyle.getXP();
  63. if (xp != null) {
  64. b.setBorder(xp.getBorder("button.pushbutton"));
  65. LookAndFeel.installProperty(b, "rolloverEnabled", Boolean.TRUE);
  66. }
  67. }
  68. protected void uninstallDefaults(AbstractButton b) {
  69. super.uninstallDefaults(b);
  70. defaults_initialized = false;
  71. }
  72. protected Color getFocusColor() {
  73. return focusColor;
  74. }
  75. // ********************************
  76. // Paint Methods
  77. // ********************************
  78. /**
  79. * Overridden method to render the text without the mnemonic
  80. */
  81. protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {
  82. WindowsGraphicsUtils.paintText(g, b, textRect, text, getTextShiftOffset());
  83. }
  84. protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect){
  85. if (b.getParent() instanceof JToolBar) {
  86. // Windows doesn't draw the focus rect for buttons in a toolbar.
  87. return;
  88. }
  89. if (XPStyle.getXP() != null) {
  90. return;
  91. }
  92. // focus painted same color as text on Basic??
  93. int width = b.getWidth();
  94. int height = b.getHeight();
  95. g.setColor(getFocusColor());
  96. BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY,
  97. width - dashedRectGapWidth, height - dashedRectGapHeight);
  98. }
  99. protected void paintButtonPressed(Graphics g, AbstractButton b){
  100. setTextShiftOffset();
  101. }
  102. // ********************************
  103. // Layout Methods
  104. // ********************************
  105. public Dimension getPreferredSize(JComponent c) {
  106. Dimension d = super.getPreferredSize(c);
  107. /* Ensure that the width and height of the button is odd,
  108. * to allow for the focus line if focus is painted
  109. */
  110. AbstractButton b = (AbstractButton)c;
  111. if (d != null && b.isFocusPainted()) {
  112. if(d.width % 2 == 0) { d.width += 1; }
  113. if(d.height % 2 == 0) { d.height += 1; }
  114. }
  115. return d;
  116. }
  117. /* These rectangles/insets are allocated once for all
  118. * ButtonUI.paint() calls. Re-using rectangles rather than
  119. * allocating them in each paint call substantially reduced the time
  120. * it took paint to run. Obviously, this method can't be re-entered.
  121. */
  122. private static Rectangle viewRect = new Rectangle();
  123. public void paint(Graphics g, JComponent c) {
  124. if (XPStyle.getXP() != null) {
  125. WindowsButtonUI.paintXPButtonBackground(g, c);
  126. }
  127. super.paint(g, c);
  128. }
  129. static void paintXPButtonBackground(Graphics g, JComponent c) {
  130. AbstractButton b = (AbstractButton)c;
  131. XPStyle xp = XPStyle.getXP();
  132. if (b.isContentAreaFilled() && xp != null &&
  133. "imagefile".equalsIgnoreCase(xp.getString("button.pushbutton", null, "bgtype"))) {
  134. ButtonModel model = b.getModel();
  135. boolean toolbar = (c.getParent() instanceof JToolBar);
  136. XPStyle.Skin skin = xp.getSkin(toolbar ? "toolbar.button" : "button.pushbutton");
  137. // normal, rollover/activated/focus, pressed, disabled, default
  138. int index = 0;
  139. if (toolbar) {
  140. if (model.isArmed() && model.isPressed()) {
  141. index = 2;
  142. } else if (model.isSelected() && model.isRollover()) {
  143. index = 5;
  144. } else if (model.isSelected()) {
  145. index = 4;
  146. } else if (model.isRollover()) {
  147. index = 1;
  148. }
  149. } else {
  150. if (model.isArmed() && model.isPressed() || model.isSelected()) {
  151. index = 2;
  152. } else if (!model.isEnabled()) {
  153. index = 3;
  154. } else if (model.isRollover() || model.isPressed()) {
  155. index = 1;
  156. } else if (b instanceof JButton && ((JButton)b).isDefaultButton()) {
  157. index = 4;
  158. } else if (c.hasFocus()) {
  159. index = 1;
  160. }
  161. }
  162. Dimension d = c.getSize();
  163. int dx = 0;
  164. int dy = 0;
  165. int dw = d.width;
  166. int dh = d.height;
  167. Border border = c.getBorder();
  168. Insets insets;
  169. if (border != null) {
  170. // Note: The border may be compound, containing an outer
  171. // opaque border (supplied by the application), plus an
  172. // inner transparent margin border. We want to size the
  173. // background to fill the transparent part, but stay
  174. // inside the opaque part.
  175. insets = WindowsButtonUI.getOpaqueInsets(border, c);
  176. } else {
  177. insets = c.getInsets();
  178. }
  179. if (insets != null) {
  180. dx += insets.left;
  181. dy += insets.top;
  182. dw -= (insets.left + insets.right);
  183. dh -= (insets.top + insets.bottom);
  184. }
  185. skin.paintSkin(g, dx, dy, dw, dh, index);
  186. }
  187. }
  188. /**
  189. * returns - b.getBorderInsets(c) if border is opaque
  190. * - null if border is completely non-opaque
  191. * - somewhere inbetween if border is compound and
  192. * outside border is opaque and inside isn't
  193. */
  194. private static Insets getOpaqueInsets(Border b, Component c) {
  195. if (b == null) {
  196. return null;
  197. }
  198. if (b.isBorderOpaque()) {
  199. return b.getBorderInsets(c);
  200. } else if (b instanceof CompoundBorder) {
  201. CompoundBorder cb = (CompoundBorder)b;
  202. Insets iOut = getOpaqueInsets(cb.getOutsideBorder(), c);
  203. if (iOut != null && iOut.equals(cb.getOutsideBorder().getBorderInsets(c))) {
  204. // Outside border is opaque, keep looking
  205. Insets iIn = getOpaqueInsets(cb.getInsideBorder(), c);
  206. if (iIn == null) {
  207. // Inside is non-opaque, use outside insets
  208. return iOut;
  209. } else {
  210. // Found non-opaque somewhere in the inside (which is
  211. // also compound).
  212. return new Insets(iOut.top + iIn.top, iOut.left + iIn.left,
  213. iOut.bottom + iIn.bottom, iOut.right + iIn.right);
  214. }
  215. } else {
  216. // Outside is either all non-opaque or has non-opaque
  217. // border inside another compound border
  218. return iOut;
  219. }
  220. } else {
  221. return null;
  222. }
  223. }
  224. }