// // Nenya library - tools for developing networked games // Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved // https://github.com/threerings/nenya // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package com.threerings.media.sprite; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import com.samskivert.swing.Label; import com.samskivert.swing.util.SwingUtil; import com.threerings.media.sprite.action.ArmingSprite; import com.threerings.media.sprite.action.CommandSprite; import com.threerings.media.sprite.action.DisableableSprite; /** * A sprite that acts as a button. */ public class ButtonSprite extends Sprite implements CommandSprite, ArmingSprite, DisableableSprite { /** The normal, square button style. */ public static final int NORMAL = 0; /** The rounded button style. */ public static final int ROUNDED = 1; /** * Constructs a button sprite. * * @param label the label to render on the button * @param style the style of button to render (NORMAL or ROUNDED) * @param backgroundColor the background color of the button * @param alternateColor the alternate (outline) color * @param actionCommand the button's command * @param commandArgument the button's command argument */ public ButtonSprite (Label label, int style, Color backgroundColor, Color alternateColor, String actionCommand, Object commandArgument) { _label = label; _style = style; _backgroundColor = backgroundColor; _alternateColor = alternateColor; _actionCommand = actionCommand; _commandArgument = commandArgument; } /** * Constructs a button sprite. * * @param label the label to render on the button * @param style the style of button to render (NORMAL or ROUNDED) * @param arcWidth the width of the corner arcs for rounded buttons * @param arcHeight the height of the corner arcs for rounded buttons * @param backgroundColor the background color of the button * @param alternateColor the alternate (outline) color * @param actionCommand the button's command * @param commandArgument the button's command argument */ public ButtonSprite (Label label, int style, int arcWidth, int arcHeight, Color backgroundColor, Color alternateColor, String actionCommand, Object commandArgument) { _label = label; _style = style; _arcWidth = arcWidth; _arcHeight = arcHeight; _backgroundColor = backgroundColor; _alternateColor = alternateColor; _actionCommand = actionCommand; _commandArgument = commandArgument; } /** * Returns a reference to the label displayed by this sprite. */ public Label getLabel () { return _label; } /** * Updates this sprite's bounds after a change to the label. */ public void updateBounds () { // invalidate the old... invalidate(); // size the bounds to fit our label Dimension size = _label.getSize(); _bounds.width = size.width + PADDING*2 + (_style == ROUNDED ? _arcWidth : 0); _bounds.height = size.height + PADDING*2; // ...and the new invalidate(); } /** * Sets the style of this button. */ public void setStyle (int style) { _style = style; updateBounds(); } /** * Returns the style of this button. */ public int getStyle () { return _style; } /** * Sets the arc width for rounded buttons. */ public void setArcWidth (int arcWidth) { _arcWidth = arcWidth; updateBounds(); } /** * Returns the arc width for rounded buttons. */ public int getArcWidth () { return _arcWidth; } /** * Sets the arc height for rounded buttons. */ public void setArcHeight (int arcHeight) { _arcHeight = arcHeight; updateBounds(); } /** * Returns the arc height for rounded buttons. */ public int getArcHeight () { return _arcHeight; } /** * Sets the background color of this button. */ public void setBackgroundColor (Color backgroundColor) { _backgroundColor = backgroundColor; } /** * Returns the background color of this button. */ public Color getBackgroundColor () { return _backgroundColor; } /** * Sets the action command generated by this button. */ public void setActionCommand (String actionCommand) { _actionCommand = actionCommand; } // documentation inherited from interface CommandSprite public String getActionCommand () { return _actionCommand; } /** * Sets the command argument generated by this button. */ public void setCommandArgument (Object commandArgument) { _commandArgument = commandArgument; } // documentation inherited from interface CommandSprite public Object getCommandArgument () { return _commandArgument; } /** * Sets whether or not this button is enabled. */ public void setEnabled (boolean enabled) { if (_enabled != enabled) { _enabled = enabled; invalidate(); } } // documentation inherited from interface DisableableSprite public boolean isEnabled () { return _enabled; } // documentation inherited from interface ArmingSprite public void setArmed (boolean pressed) { if (_pressed != pressed) { _pressed = pressed; invalidate(); } } /** * Checks whether or not this button appears pressed. */ public boolean isArmed () { return _pressed; } @Override protected void init () { super.init(); // lay out the label if not already if (!_label.isLaidOut()) { Graphics2D gfx = _mgr.createGraphics(); if (gfx != null) { try { _label.layout(gfx); } finally { gfx.dispose(); } } } updateBounds(); } @Override public void paint (Graphics2D gfx) { Color baseTextColor = _label.getTextColor(), baseAlternateColor = _label.getAlternateColor(); if (!_enabled) { _label.setTextColor(baseTextColor.darker()); _label.setAlternateColor(baseAlternateColor.darker()); } switch (_style) { case NORMAL: gfx.setColor(_enabled ? _backgroundColor : _backgroundColor.darker()); gfx.fill3DRect(_bounds.x, _bounds.y, _bounds.width, _bounds.height, !_pressed); _label.render(gfx, _bounds.x + (_pressed ? PADDING : PADDING - 1), _bounds.y + (_pressed ? PADDING : PADDING - 1)); break; case ROUNDED: Object aaState = SwingUtil.activateAntiAliasing(gfx); // draw outline gfx.setColor(_alternateColor); gfx.fillRoundRect(_bounds.x, _bounds.y, _bounds.width, _bounds.height, _arcWidth, _arcHeight); // draw foreground gfx.setColor(_enabled ? _backgroundColor : _backgroundColor.darker()); int innerBoundsX = _bounds.x+1, innerBoundsY = _bounds.y+1, innerBoundsWidth = _bounds.width-2, innerBoundsHeight = _bounds.height-2, innerBoundsArcWidth = _arcWidth-2, innerBoundsArcHeight = _arcHeight-2; gfx.fillRoundRect(innerBoundsX, innerBoundsY, innerBoundsWidth, innerBoundsHeight, innerBoundsArcWidth, innerBoundsArcHeight); Color brighter = _enabled ? _backgroundColor.brighter() : _backgroundColor, darker = _enabled ? _backgroundColor.darker() : _backgroundColor.darker().darker(); // draw the upper left/lower right corners (always dark) gfx.setColor(darker); gfx.drawArc(innerBoundsX, innerBoundsY, innerBoundsArcWidth, innerBoundsArcHeight, 90, 90); gfx.drawArc(innerBoundsX + innerBoundsWidth - innerBoundsArcWidth - 1, innerBoundsY + innerBoundsHeight - innerBoundsArcHeight - 1, innerBoundsArcWidth, innerBoundsArcHeight, 270, 90); // draw the upper right (dark when pressed) gfx.setColor(_pressed ? darker : brighter); gfx.drawLine(innerBoundsX + innerBoundsArcWidth/2, innerBoundsY, innerBoundsX + innerBoundsWidth - innerBoundsArcWidth/2, innerBoundsY); gfx.drawArc(innerBoundsX + innerBoundsWidth - innerBoundsArcWidth - 1, innerBoundsY, innerBoundsArcWidth, innerBoundsArcHeight, 0, 90); gfx.drawLine(innerBoundsX + innerBoundsWidth - 1, innerBoundsY + innerBoundsArcHeight/2, innerBoundsX + innerBoundsWidth - 1, innerBoundsY + innerBoundsHeight - innerBoundsArcHeight/2); // draw the lower left (light when pressed) gfx.setColor(_pressed ? brighter : darker); gfx.drawLine(innerBoundsX, innerBoundsY + innerBoundsArcHeight/2, innerBoundsX, innerBoundsY + innerBoundsHeight - innerBoundsArcHeight/2); gfx.drawArc(innerBoundsX, innerBoundsY + innerBoundsHeight - innerBoundsArcHeight - 1, innerBoundsArcWidth, innerBoundsArcHeight, 180, 90); gfx.drawLine(innerBoundsX + innerBoundsArcWidth/2, innerBoundsY + innerBoundsHeight - 1, innerBoundsX + innerBoundsWidth - innerBoundsArcWidth/2, innerBoundsY + innerBoundsHeight - 1); SwingUtil.restoreAntiAliasing(gfx, aaState); _label.render(gfx, _bounds.x + PADDING + _arcWidth/2 - (_pressed ? 2 : 1), _bounds.y + PADDING + (_pressed ? 1 : 0)); break; } if (!_enabled) { _label.setTextColor(baseTextColor); _label.setAlternateColor(baseAlternateColor); } } /** The number of pixels to add between the text and the border. */ protected static final int PADDING = 2; /** The label associated with this sprite. */ protected Label _label; /** The button style. */ protected int _style; /** The width of the corner arcs for rounded rectangle buttons. */ protected int _arcWidth; /** The height of the corner arcs for rounded rectangle buttons. */ protected int _arcHeight; /** The action command generated by this button. */ protected String _actionCommand; /** The command argument generated by this button. */ protected Object _commandArgument; /** The background color of this sprite. */ protected Color _backgroundColor; /** The alternate (outline) color of this sprite. */ protected Color _alternateColor; /** Whether or not the button is currently enabled. */ protected boolean _enabled = true; /** Whether or not the button is currently pressed. */ protected boolean _pressed; }