1 package swingjs.plaf;
\r
3 //import jsjava.awt.FontMetrics;
\r
4 import jsjava.awt.event.MouseMotionListener;
\r
5 import jsjavax.swing.AbstractButton;
\r
6 import jsjavax.swing.LookAndFeel;
\r
7 import jsjavax.swing.UIManager;
\r
8 import swingjs.api.DOMNode;
\r
9 import jsjavax.swing.plaf.UIResource;
\r
11 * SWingJS implementation of stateful user interface for buttons.
\r
12 * Modeled after javax.swing.plaf.basic.BasicButtonUI.java (commented out below).
\r
14 * @author Bob Hanson
\r
17 public class JSButtonUI extends JSComponentUI {
\r
21 * the radio or check-box or simple button
\r
24 protected DOMNode domBtn;
\r
27 public DOMNode getDOMObject() {
\r
28 if (domNode == null)
\r
29 domBtn = enableNode = valueNode = domNode = createDOMObject("input", id,
\r
31 setCssFont(DOMNode.setAttr(domNode, "value", ((AbstractButton) c).getText()),
\r
37 * validate a button press -- with a simple button, this is just TRUE.
\r
38 * This is needed because sometimes the area near the button is pressed
\r
39 * but not the actual button.
\r
40 * @param isRelease TODO
\r
42 * @return true if the HTML5 button was actually pressed
\r
44 boolean verifyButtonClick(boolean isRelease) {
\r
49 // from BasicButtonUI
\r
51 protected void installJSUI() {
\r
52 installDefaults((AbstractButton) c);
\r
53 installListeners((AbstractButton) c);
\r
54 installKeyboardActions((AbstractButton) c);
\r
57 protected void uninstallJSUI() {
\r
58 uninstallKeyboardActions((AbstractButton) c);
\r
59 uninstallListeners((AbstractButton) c);
\r
60 //uninstallDefaults((AbstractButton) c);
\r
63 protected void installListeners(AbstractButton b) {
\r
64 JSButtonListener listener = new JSButtonListener(b);
\r
65 if (listener != null) {
\r
66 b.addMouseListener(listener);
\r
67 b.addMouseMotionListener(listener);
\r
68 b.addFocusListener(listener);
\r
69 b.addPropertyChangeListener(listener);
\r
70 b.addChangeListener(listener);
\r
74 protected void uninstallListeners(AbstractButton b) {
\r
75 JSButtonListener listener = getButtonListener(b);
\r
76 if (listener != null) {
\r
77 b.removeMouseListener(listener);
\r
78 b.removeMouseMotionListener(listener);
\r
79 b.removeFocusListener(listener);
\r
80 b.removeChangeListener(listener);
\r
81 b.removePropertyChangeListener(listener);
\r
85 protected void installKeyboardActions(AbstractButton b) {
\r
86 JSButtonListener listener = getButtonListener(b);
\r
87 if (listener != null) {
\r
88 listener.installKeyboardActions(b);
\r
92 protected void uninstallKeyboardActions(AbstractButton b) {
\r
93 JSButtonListener listener = getButtonListener(b);
\r
94 if(listener != null) {
\r
95 listener.uninstallKeyboardActions(b);
\r
100 * Returns the ButtonListener for the passed in Button, or null if one
\r
101 * could not be found.
\r
103 protected JSButtonListener getButtonListener(AbstractButton b) {
\r
104 MouseMotionListener[] listeners = b.getMouseMotionListeners();
\r
106 if (listeners != null) {
\r
107 for (int counter = 0; counter < listeners.length; counter++) {
\r
108 if (listeners[counter] instanceof JSButtonListener) {
\r
109 return (JSButtonListener)listeners[counter];
\r
116 // SwingJS -- this is interesting, as it summarizes everything we will need
\r
117 // to implement, ultimately. SwingUtilities.layoutCompoundLabel
\r
118 // details what we are going to have to do somewhere.
\r
120 // private String layout(AbstractButton b, FontMetrics fm, int width, int height) {
\r
121 // Insets i = b.getInsets();
\r
122 // viewRect.x = i.left;
\r
123 // viewRect.y = i.top;
\r
124 // viewRect.width = width - (i.right + viewRect.x);
\r
125 // viewRect.height = height - (i.bottom + viewRect.y);
\r
127 // textRect.x = textRect.y = textRect.width = textRect.height = 0;
\r
128 // iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
\r
130 // // layout the text and icon
\r
131 // return SwingUtilities.layoutCompoundLabel(b, fm, b.getText(), b.getIcon(),
\r
132 // b.getVerticalAlignment(), b.getHorizontalAlignment(),
\r
133 // b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect,
\r
134 // iconRect, textRect, b.getText() == null ? 0 : b.getIconTextGap());
\r
139 // // Visual constants
\r
140 // // NOTE: This is not used or set any where. Were we allowed to remove
\r
141 // // fields, this would be removed.
\r
142 // protected int defaultTextIconGap;
\r
144 /** Amount to offset text, the value of this comes from
\r
145 defaultTextShiftOffset once setTextShiftOffset has been invoked.
\r
147 protected int shiftOffset = 0;
\r
149 /** Value that is set in shiftOffset once setTextShiftOffset has been
\r
150 invoked. The value of this comes from the defaults table.
\r
152 protected int defaultTextShiftOffset;
\r
154 //protected String propertyPrefix = "Button.";
\r
156 // private static final Object BASIC_BUTTON_UI_KEY = new Object();
\r
158 // // ********************************
\r
160 // // ********************************
\r
161 // public static ComponentUI createUI(JComponent c) {
\r
162 // AppContext appContext = AppContext.getAppContext();
\r
163 // BasicButtonUI buttonUI =
\r
164 // (BasicButtonUI) appContext.get(BASIC_BUTTON_UI_KEY);
\r
165 // if (buttonUI == null) {
\r
166 // buttonUI = new BasicButtonUI();
\r
167 // appContext.put(BASIC_BUTTON_UI_KEY, buttonUI);
\r
169 // return buttonUI;
\r
172 protected String getPropertyPrefix() {
\r
177 // // ********************************
\r
179 // // ********************************
\r
180 // public void installUI(JComponent c) {
\r
181 // installDefaults((AbstractButton) c);
\r
182 // installListeners((AbstractButton) c);
\r
183 // installKeyboardActions((AbstractButton) c);
\r
184 // BasicHTML.updateRenderer(c, ((AbstractButton) c).getText());
\r
187 protected void installDefaults(AbstractButton b) {
\r
188 // load shared instance defaults
\r
189 String pp = getPropertyPrefix();
\r
191 defaultTextShiftOffset = UIManager.getInt(pp + "textShiftOffset");
\r
193 // // set the following defaults on the button
\r
194 // if (b.isContentAreaFilled()) {
\r
195 // LookAndFeel.installProperty(b, "opaque", Boolean.TRUE);
\r
197 // LookAndFeel.installProperty(b, "opaque", Boolean.FALSE);
\r
200 if(b.getMargin() == null || (b.getMargin() instanceof UIResource)) {
\r
201 b.setMargin(UIManager.getInsets(pp + "margin"));
\r
204 LookAndFeel.installColorsAndFont(b, pp + "background",
\r
205 pp + "foreground", pp + "font");
\r
206 // LookAndFeel.installBorder(b, pp + "border");
\r
208 // Object rollover = UIManager.get(pp + "rollover");
\r
209 // if (rollover != null) {
\r
210 // LookAndFeel.installProperty(b, "rolloverEnabled", rollover);
\r
212 LookAndFeel.installProperty(b, "iconTextGap", new Integer(4));
\r
215 // protected void installListeners(AbstractButton b) {
\r
216 // JSButtonListener listener = createButtonListener(b);
\r
217 // if(listener != null) {
\r
218 // b.addMouseListener(listener);
\r
219 // b.addMouseMotionListener(listener);
\r
220 // b.addFocusListener(listener);
\r
221 // b.addPropertyChangeListener(listener);
\r
222 // b.addChangeListener(listener);
\r
226 // protected void installKeyboardActions(AbstractButton b){
\r
227 // JSButtonListener listener = getButtonListener(b);
\r
229 // if(listener != null) {
\r
230 // listener.installKeyboardActions(b);
\r
235 // // ********************************
\r
236 // // Uninstall PLAF
\r
237 // // ********************************
\r
238 // public void uninstallUI(JComponent c) {
\r
239 // uninstallKeyboardActions((AbstractButton) c);
\r
240 // uninstallListeners((AbstractButton) c);
\r
241 // uninstallDefaults((AbstractButton) c);
\r
242 // BasicHTML.updateRenderer(c, "");
\r
245 // protected void uninstallKeyboardActions(AbstractButton b) {
\r
246 // JSButtonListener listener = getButtonListener(b);
\r
247 // if(listener != null) {
\r
248 // listener.uninstallKeyboardActions(b);
\r
252 // protected void uninstallListeners(AbstractButton b) {
\r
253 // JSButtonListener listener = getButtonListener(b);
\r
254 // if(listener != null) {
\r
255 // b.removeMouseListener(listener);
\r
256 // b.removeMouseMotionListener(listener);
\r
257 // b.removeFocusListener(listener);
\r
258 // b.removeChangeListener(listener);
\r
259 // b.removePropertyChangeListener(listener);
\r
263 // protected void uninstallDefaults(AbstractButton b) {
\r
264 // LookAndFeel.uninstallBorder(b);
\r
267 // // ********************************
\r
268 // // Create Listeners
\r
269 // // ********************************
\r
270 // protected JSButtonListener createButtonListener(AbstractButton b) {
\r
271 // return new JSButtonListener(b);
\r
274 // public int getDefaultTextIconGap(AbstractButton b) {
\r
275 // return defaultTextIconGap;
\r
278 // /* These rectangles/insets are allocated once for all
\r
279 // * ButtonUI.paint() calls. Re-using rectangles rather than
\r
280 // * allocating them in each paint call substantially reduced the time
\r
281 // * it took paint to run. Obviously, this method can't be re-entered.
\r
283 // private static Rectangle viewRect = new Rectangle();
\r
284 // private static Rectangle textRect = new Rectangle();
\r
285 // private static Rectangle iconRect = new Rectangle();
\r
287 // // ********************************
\r
288 // // Paint Methods
\r
289 // // ********************************
\r
291 // public void paint(Graphics g, JComponent c)
\r
293 // AbstractButton b = (AbstractButton) c;
\r
294 // ButtonModel model = b.getModel();
\r
296 // String text = layout(b, SwingUtilities2.getFontMetrics(b, g),
\r
297 // b.getWidth(), b.getHeight());
\r
299 // clearTextShiftOffset();
\r
301 // // perform UI specific press action, e.g. Windows L&F shifts text
\r
302 // if (model.isArmed() && model.isPressed()) {
\r
303 // paintButtonPressed(g,b);
\r
306 // // Paint the Icon
\r
307 // if(b.getIcon() != null) {
\r
308 // paintIcon(g,c,iconRect);
\r
311 // if (text != null && !text.equals("")){
\r
312 // View v = (View) c.getClientProperty(BasicHTML.propertyKey);
\r
313 // if (v != null) {
\r
314 // v.paint(g, textRect);
\r
316 // paintText(g, b, textRect, text);
\r
320 // if (b.isFocusPainted() && b.hasFocus()) {
\r
321 // // paint UI specific focus
\r
322 // paintFocus(g,b,viewRect,textRect,iconRect);
\r
326 // protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect){
\r
327 // AbstractButton b = (AbstractButton) c;
\r
328 // ButtonModel model = b.getModel();
\r
329 // Icon icon = b.getIcon();
\r
330 // Icon tmpIcon = null;
\r
332 // if(icon == null) {
\r
336 // Icon selectedIcon = null;
\r
338 // /* the fallback icon should be based on the selected state */
\r
339 // if (model.isSelected()) {
\r
340 // selectedIcon = (Icon) b.getSelectedIcon();
\r
341 // if (selectedIcon != null) {
\r
342 // icon = selectedIcon;
\r
346 // if(!model.isEnabled()) {
\r
347 // if(model.isSelected()) {
\r
348 // tmpIcon = (Icon) b.getDisabledSelectedIcon();
\r
349 // if (tmpIcon == null) {
\r
350 // tmpIcon = selectedIcon;
\r
354 // if (tmpIcon == null) {
\r
355 // tmpIcon = (Icon) b.getDisabledIcon();
\r
357 // } else if(model.isPressed() && model.isArmed()) {
\r
358 // tmpIcon = (Icon) b.getPressedIcon();
\r
359 // if(tmpIcon != null) {
\r
360 // // revert back to 0 offset
\r
361 // clearTextShiftOffset();
\r
363 // } else if(b.isRolloverEnabled() && model.isRollover()) {
\r
364 // if(model.isSelected()) {
\r
365 // tmpIcon = (Icon) b.getRolloverSelectedIcon();
\r
366 // if (tmpIcon == null) {
\r
367 // tmpIcon = selectedIcon;
\r
371 // if (tmpIcon == null) {
\r
372 // tmpIcon = (Icon) b.getRolloverIcon();
\r
376 // if(tmpIcon != null) {
\r
380 // if(model.isPressed() && model.isArmed()) {
\r
381 // icon.paintIcon(c, g, iconRect.x + getTextShiftOffset(),
\r
382 // iconRect.y + getTextShiftOffset());
\r
384 // icon.paintIcon(c, g, iconRect.x, iconRect.y);
\r
390 // * As of Java 2 platform v 1.4 this method should not be used or overriden.
\r
391 // * Use the paintText method which takes the AbstractButton argument.
\r
393 // protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) {
\r
394 // AbstractButton b = (AbstractButton) c;
\r
395 // ButtonModel model = b.getModel();
\r
396 // FontMetrics fm = SwingUtilities2.getFontMetrics(c, g);
\r
397 // int mnemonicIndex = b.getDisplayedMnemonicIndex();
\r
399 // /* Draw the Text */
\r
400 // if(model.isEnabled()) {
\r
401 // /*** paint the text normally */
\r
402 // g.setColor(b.getForeground());
\r
403 // SwingUtilities2.drawStringUnderlineCharAt(c, g,text, mnemonicIndex,
\r
404 // textRect.x + getTextShiftOffset(),
\r
405 // textRect.y + fm.getAscent() + getTextShiftOffset());
\r
408 // /*** paint the text disabled ***/
\r
409 // g.setColor(b.getBackground().brighter());
\r
410 // SwingUtilities2.drawStringUnderlineCharAt(c, g,text, mnemonicIndex,
\r
411 // textRect.x, textRect.y + fm.getAscent());
\r
412 // g.setColor(b.getBackground().darker());
\r
413 // SwingUtilities2.drawStringUnderlineCharAt(c, g,text, mnemonicIndex,
\r
414 // textRect.x - 1, textRect.y + fm.getAscent() - 1);
\r
419 // * Method which renders the text of the current button.
\r
421 // * @param g Graphics context
\r
422 // * @param b Current button to render
\r
423 // * @param textRect Bounding rectangle to render the text.
\r
424 // * @param text String to render
\r
427 // protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {
\r
428 // paintText(g, (JComponent)b, textRect, text);
\r
431 // // Method signature defined here overriden in subclasses.
\r
432 // // Perhaps this class should be abstract?
\r
433 // protected void paintFocus(Graphics g, AbstractButton b,
\r
434 // Rectangle viewRect, Rectangle textRect, Rectangle iconRect){
\r
439 // protected void paintButtonPressed(Graphics g, AbstractButton b){
\r
442 // protected void clearTextShiftOffset(){
\r
443 // this.shiftOffset = 0;
\r
446 // protected void setTextShiftOffset(){
\r
447 // this.shiftOffset = defaultTextShiftOffset;
\r
450 // protected int getTextShiftOffset() {
\r
451 // return shiftOffset;
\r
454 // // ********************************
\r
455 // // Layout Methods
\r
456 // // ********************************
\r
457 // public Dimension getMinimumSize(JComponent c) {
\r
458 // Dimension d = getPreferredSize(c);
\r
459 // View v = (View) c.getClientProperty(BasicHTML.propertyKey);
\r
460 // if (v != null) {
\r
461 // d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS);
\r
466 // public Dimension getPreferredSize(JComponent c) {
\r
467 // AbstractButton b = (AbstractButton)c;
\r
468 // return BasicGraphicsUtils.getPreferredButtonSize(b, b.getIconTextGap());
\r
471 // public Dimension getMaximumSize(JComponent c) {
\r
472 // Dimension d = getPreferredSize(c);
\r
473 // View v = (View) c.getClientProperty(BasicHTML.propertyKey);
\r
474 // if (v != null) {
\r
475 // d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS);
\r
481 // * Returns the baseline.
\r
483 // * @throws NullPointerException {@inheritDoc}
\r
484 // * @throws IllegalArgumentException {@inheritDoc}
\r
485 // * @see javax.swing.JComponent#getBaseline(int, int)
\r
488 // public int getBaseline(JComponent c, int width, int height) {
\r
489 // super.getBaseline(c, width, height);
\r
490 // AbstractButton b = (AbstractButton)c;
\r
491 // String text = b.getText();
\r
492 // if (text == null || "".equals(text)) {
\r
495 // FontMetrics fm = b.getFontMetrics(b.getFont());
\r
496 // layout(b, fm, width, height);
\r
497 // return BasicHTML.getBaseline(b, textRect.y, fm.getAscent(),
\r
498 // textRect.width, textRect.height);
\r
502 // * Returns an enum indicating how the baseline of the component
\r
503 // * changes as the size changes.
\r
505 // * @throws NullPointerException {@inheritDoc}
\r
506 // * @see javax.swing.JComponent#getBaseline(int, int)
\r
509 // public Component.BaselineResizeBehavior getBaselineResizeBehavior(
\r
511 // super.getBaselineResizeBehavior(c);
\r
512 // if (c.getClientProperty(BasicHTML.propertyKey) != null) {
\r
513 // return Component.BaselineResizeBehavior.OTHER;
\r
515 // switch(((AbstractButton)c).getVerticalAlignment()) {
\r
516 // case AbstractButton.TOP:
\r
517 // return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
\r
518 // case AbstractButton.BOTTOM:
\r
519 // return Component.BaselineResizeBehavior.CONSTANT_DESCENT;
\r
520 // case AbstractButton.CENTER:
\r
521 // return Component.BaselineResizeBehavior.CENTER_OFFSET;
\r
523 // return Component.BaselineResizeBehavior.OTHER;
\r
526 // private String layout(AbstractButton b, FontMetrics fm,
\r
527 // int width, int height) {
\r
528 // Insets i = b.getInsets();
\r
529 // viewRect.x = i.left;
\r
530 // viewRect.y = i.top;
\r
531 // viewRect.width = width - (i.right + viewRect.x);
\r
532 // viewRect.height = height - (i.bottom + viewRect.y);
\r
534 // textRect.x = textRect.y = textRect.width = textRect.height = 0;
\r
535 // iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
\r
537 // // layout the text and icon
\r
538 // return SwingUtilities.layoutCompoundLabel(
\r
539 // b, fm, b.getText(), b.getIcon(),
\r
540 // b.getVerticalAlignment(), b.getHorizontalAlignment(),
\r
541 // b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
\r
542 // viewRect, iconRect, textRect,
\r
543 // b.getText() == null ? 0 : b.getIconTextGap());
\r
547 // * Returns the ButtonListener for the passed in Button, or null if one
\r
548 // * could not be found.
\r
550 // private JSButtonListener getButtonListener(AbstractButton b) {
\r
551 // MouseMotionListener[] listeners = b.getMouseMotionListeners();
\r
553 // if (listeners != null) {
\r
554 // for (int counter = 0; counter < listeners.length; counter++) {
\r
555 // if (listeners[counter] instanceof JSButtonListener) {
\r
556 // return (JSButtonListener)listeners[counter];
\r