package net.xoetrope.swing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.ImageObserver;
import javax.swing.ButtonModel;
import javax.swing.DefaultButtonModel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.text.View;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JToggleButton;
import net.xoetrope.xui.XAttributedComponent;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.XProjectManager;
import net.xoetrope.xui.XTextRenderer;
import net.xoetrope.xui.helper.XuiUtilities;
import org.jdesktop.swingx.painter.Painter;
/**
* <p>Uses a set of images to create a button</p>
* <p>Copyright (c) Xoetrope Ltd., 1998-2003</p>
* License: see license.txt
* $Revision: 1.17 $
*/
public class XImageButton extends JToggleButton implements XAttributedComponent, MouseListener
{
private Image image = null;
private Image pressedImage = null;
private Image rolloverImage = null;
private Image disabledImage = null;
private ImageIcon iconImage = null;
private String imageName;
private String rolloverImageName;
private String pressedImageName;
private String disabledImageName;
private String iconName;
/* boolean to indicate whether to antialias the text. */
protected boolean antiAlias;
private boolean vertical;
/**
* The renderer that will paint the component
*/
protected XTextRenderer textRenderer = null;
private Painter painter;
/**
* The current project
*/
protected XProject currentProject;
/**
* Creates a new instance of XImageButton
*/
public XImageButton()
{
super();
currentProject = XProjectManager.getCurrentProject();
setUI( new BasicButtonUI() );
// setModel( new DefaultButtonModel());
addMouseListener( this );
setBorderPainted( false );
setContentAreaFilled( false );
setRolloverEnabled( true );
setDoubleBuffered( true );
}
/**
* Paints the component
* @param g The graphics context
*/
public void paintComponent( Graphics g )
{
Graphics2D g2d = (Graphics2D)g;
Object oldHint = g2d.getRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING );
g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, antiAlias ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF );
Color bkColor = getBackground();
g.setColor( bkColor );
Dimension sz = getSize();
int width = getSize().width;
int height = getSize().height;
if ( painter != null )
painter.paint( (Graphics2D)g, this, width, height );
else {
if ( isOpaque())
g.fillRect( 0, 0, width, height );
ButtonModel model = getModel();
if ( !model.isEnabled()) {
if ( disabledImage == null ) {
Paint paint = g2d.getPaint();
g2d.setPaint( new Color( bkColor.getRed(), bkColor.getGreen(), bkColor.getBlue(), 128 ));
g.drawImage( image, 0, 0, (int)sz.width, (int)sz.height, null );
g.fillRect( 0, 0, (int)sz.width, (int)sz.height );
g2d.setPaint( paint );
}
else
g.drawImage( disabledImage, 0, 0, (int)sz.width, (int)sz.height, null );
}
else if ( model.isRollover()) {
if ( model.isPressed() && ( pressedImage != null ))
g.drawImage( pressedImage, 0, 0, (int)sz.width, (int)sz.height, null );
else if ( rolloverImage != null )
g.drawImage( rolloverImage, 0, 0, (int)sz.width, (int)sz.height, null );
}
else if ( image != null )
g.drawImage( image, 0, 0, (int)sz.width, (int)sz.height, null );
if ( iconImage != null ) {
int iwidth = (int)iconImage.getImage().getWidth( null );
int iheight = iconImage.getImage().getHeight( null );
g.drawImage( iconImage.getImage(), 10, ( height - iheight ) / 2, iwidth, iheight, null );
}
}
String text = getText();
if (( text != null ) && ( text.length() > 0 )) {
FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics( g.getFont());
if ( isEnabled())
g.setColor( getForeground());
else
g.setColor( getBackground().brighter());
View v = (View)getClientProperty( "html" );
Rectangle textRect = new Rectangle( 0, 0, sz.width, sz.height );
Rectangle iconRect = new Rectangle( 0, 0, sz.width, sz.height );
Rectangle viewRect = new Rectangle( 0, 0, sz.width, sz.height );
Insets insets = super.getInsets();
viewRect.x = insets.left;
viewRect.y = insets.top;
viewRect.width = getWidth() - (insets.right + viewRect.x);
viewRect.height = getHeight() - (insets.bottom + viewRect.y);
textRect.x = textRect.y = textRect.width = textRect.height = 0;
iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
/*String textPos = */SwingUtilities.layoutCompoundLabel(
this, fm, text, null,
getVerticalAlignment(), getHorizontalAlignment(),
getVerticalTextPosition(), getHorizontalTextPosition(),
viewRect, iconRect, textRect,
text == null ? 0 : getIconTextGap());
if ( v != null )
v.paint( g, textRect );
else {
if (( textRenderer != null ) && ( text != null ) && ( text.length() > 0 ))
textRenderer.paintText( this, g, insets, text );
else {
if ( !vertical ) {
int x = ( sz.width - fm.stringWidth( text )) / 2;
// The FontMetrics round-up indiscriminately so 11.2 becomes 12 and so on, so we subtract 2 to conterbalance this offset
int y = ( sz.height + fm.getAscent() - 2 ) / 2;
drawStringUnderlineCharAt( this, fm, g,
text,
getDisplayedMnemonicIndex(),
x,
y/* + fm.getAscent()*/ );
}
else {
int w = fm.stringWidth( text );
Dimension preferredSize = new Dimension( width, w + 16 );
int x = 0;
AffineTransform at = g2d.getTransform();
g2d.translate( 0, preferredSize.width -1 );
g2d.rotate( -1.57 );
int verticalOffset = 33;
Object vo = getClientProperty( "verticalOffset" );
if ( vo != null )
verticalOffset = Integer.parseInt( vo.toString());
g2d.drawString( text, x + ( preferredSize.width - 8.0F ) - w - verticalOffset, fm.getHeight() + 2.0F );
g2d.setTransform( at );
}
}
}
}
g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, oldHint );
}
/**
* Gets the preferred size of this component.
*
* @return a dimension object indicating this component's preferred size
* @see #getMinimumSize
* @see LayoutManager
*/
public Dimension getPreferredSize()
{
Dimension dim = super.getPreferredSize();
if ( getBorder() != null ) {
Insets insets = getBorder().getBorderInsets( this );
dim.setSize(dim.getWidth() + insets.left + insets.right,
dim.getHeight() + insets.top + insets.bottom);
}
if ( vertical )
return new Dimension( dim.height, dim.width );
return dim;
}
/**
* Update the image as it is loaded.
* @param img the image
* @param infoflags the flags
* @param x the left/x coordinate
* @param y the y/top coordinate
* @param width width dimension
* @param height the height dimension
* @return super.imageUpdate(...)
*/
public boolean imageUpdate( Image img, int infoflags, int x, int y, int width, int height )
{
repaint( 100, x, y, width, height );
if ( infoflags == ImageObserver.ALLBITS )
return false;
return true;
}
/**
* Set one or more attributes of the component. Attributes include <br>
* align (left|right|center ) or<br>
* alignment (left|right|center )<br>
* buffered (true|false) double buffering<br>
*
* @param align
* 1 to right align the text, 0 for left alignment and 2 for
* centered text
*/
public void setAlignment( int align )
{
super.setHorizontalAlignment( align );
textRenderer.setHorizontalAlignment( align );
}
/**
* Sets the image to display.
* @param img the image
*/
public void setImage( Image img )
{
image = img;
repaint();
prepareImage( img, this );
}
/**
* Sets the pressed image to display.
* @param img the image
*/
public void setPressedImage( Image img )
{
pressedImage = img;
repaint();
prepareImage( img, this );
}
/**
* Sets the pressed image to display.
* @param img the image
*/
public void setDisabledImage( Image img )
{
disabledImage = img;
repaint();
prepareImage( img, this );
}
/**
* Sets the pressed image to display.
* @param img the image
*/
public void setRolloverImage( Image img )
{
rolloverImage = img;
repaint();
prepareImage( img, this );
}
/**
* Sets the image to display based on the image name.
* @param imgName the image
*/
public void setImageName( String imgName )
{
imageName = imgName;
setImage( currentProject.getImage( imgName ) );
}
/**
* Sets the pressed image to display based on the image name.
* @param imgName the image
*/
public void setPressedImageName( String imgName )
{
pressedImageName = imgName;
setPressedImage( currentProject.getImage( imgName ) );
}
/**
* Sets the rollover image to display based on the image name.
* @param imgName the image
*/
public void setRolloverImageName( String imgName )
{
rolloverImageName = imgName;
setRolloverImage( currentProject.getImage( imgName ) );
}
/**
* Sets the disabled image to display based on the image name.
* @param imgName the image
*/
public void setDisabledImageName( String imgName )
{
disabledImageName = imgName;
setDisabledImage( currentProject.getImage( imgName ) );
}
/**
* Get the name of the main image
* @return the image file name
*/
public String getImageName()
{
return imageName;
}
/**
* Get the name of the rollover image
* @return the image file name
*/
public String getRolloverImageName()
{
return rolloverImageName;
}
/**
* Get the name of the pressed image
* @return the image file name
*/
public String getPressedImageName()
{
return pressedImageName;
}
/**
* Get the name of the disabled image
* @return the image file name
*/
public String getDisabledImageName()
{
return disabledImageName;
}
/**
* Set one or more attributes of the component.
* <OL>
* <LI>content, value=the image file name</LI>
* <LI>imagename, value=the image file name</LI>
* <LI>pressed, value=the pressed image file name</LI>
* <LI>rollover, value=the rollover image file name</LI>
* <LI>disabled, value=the dsabled image file name</LI>
* <LI>border, value=true to paint the border. Defaults to false</LI>
* <LI>tooltip, value=the tooltip text</LI>
* <LI>antialias, value=(true|false) antialias the text</LI>
* <LI>painter value=the class name of an Painter class for painting the panel backgrounds</LI>
* </OL>
* @param attribName the attribute name
* @param attribValue the attribute value
* @return 0 for success, non zero for failure or to require some further action
*/
public int setAttribute( String attribName, Object attribValue )
{
String attribNameLwr = attribName.toLowerCase();
String attribValueStr = (String)attribValue;
String attribValueLwr = null;
if ( attribValue != null ){
attribValueLwr = attribValueStr.toLowerCase();
if ( attribNameLwr.equals( "content" ) || attribNameLwr.equals( "imagename" )) {
Image img = currentProject.getImage( attribValueStr );
if ( img != null ) {
imageName = attribValueStr;
setImageName( imageName );
}
else
setText( XuiUtilities.translate( currentProject, attribValueStr ));
}
else if ( attribNameLwr.equals( "icon" ) ) {
Image img = currentProject.getImage( attribValueStr );
if ( img != null ) {
iconName = attribValueStr;
iconImage = new ImageIcon( img );
}
}
else if ( attribNameLwr.equals( "pressed" )) {
pressedImageName = attribValueStr;
setPressedImageName( pressedImageName );
}
else if ( attribNameLwr.equals( "rollover" )) {
rolloverImageName = attribValueStr;
setRolloverImageName( rolloverImageName );
}
else if ( attribNameLwr.equals( "disabled" )) {
disabledImageName = attribValueStr;
setDisabledImageName( disabledImageName );
}
else if ( attribNameLwr.equals( "border" ))
setBorderPainted( attribValue.equals( "true" ));
else if ( attribNameLwr.compareTo( "tooltip" ) == 0 )
setToolTipText( XuiUtilities.translate( currentProject, attribValueStr ) );
else if ( attribNameLwr.compareTo( "text" ) == 0 )
setText( XuiUtilities.translate( currentProject, attribValueStr ));
else if ( attribNameLwr.equals( "antialias" ))
antiAlias = attribValue.equals( "true" );
else if ( attribNameLwr.equals( "userenderer" ))
textRenderer = new XTextRenderer();
else if ( attribNameLwr.equals( "painter" )) {
try {
Painter xp = (Painter)Class.forName( attribValueStr.trim()).newInstance();
setPainter( xp );
}
catch ( Exception e )
{}
}
else
return -1;
}
return 0;
}
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
* @param e the event
*/
public void mouseClicked (MouseEvent e)
{
}
/**
* Invoked when a mouse button has been pressed on a component.
* @param e the event
*/
public void mousePressed (MouseEvent e)
{
model.setPressed( true );
repaint ();
}
/**
* Invoked when a mouse button has been released on a component.
* @param e the event
*/
public void mouseReleased (MouseEvent e)
{
model.setPressed( false );
repaint ();
}
/**
* Invoked when the mouse enters a component.
* @param e the event
*/
public void mouseEntered (MouseEvent e)
{
model.setRollover( true );
repaint ();
}
/**
* Invoked when the mouse exits a component.
* @param e the event
*/
public void mouseExited (MouseEvent e)
{
model.setRollover( false );
repaint ();
}
/**
* Draws the string at the specified location underlining the specified
* character.
*
* @param c JComponent that will display the string, may be null
* @param g Graphics to draw the text to
* @param text String to display
* @param underlinedIndex Index of a character in the string to underline
* @param x X coordinate to draw the text at
* @param y Y coordinate to draw the text at
*/
public static void drawStringUnderlineCharAt(JComponent c, FontMetrics fm, Graphics g,
String text, int underlinedIndex, int x,int y)
{
g.drawString( text, x, y );
if (underlinedIndex >= 0 && underlinedIndex < text.length() ) {
int underlineRectX = x + fm.stringWidth( text.substring(0,underlinedIndex));
int underlineRectY = y;
int underlineRectWidth = fm.charWidth( text.charAt(underlinedIndex));
int underlineRectHeight = 1;
g.fillRect( underlineRectX, underlineRectY + 1,
underlineRectWidth, underlineRectHeight );
}
}
/**
* Set the horizontal text alignment
*/
public void setHorizontalAlignment( int alignment )
{
if ( textRenderer != null )
textRenderer.setHorizontalAlignment( alignment );
super.setHorizontalAlignment( alignment );
}
/**
* Set the vertical text alignment
*/
public void setVerticalAlignment( int verticalAlignment )
{
if ( textRenderer != null )
textRenderer.setVerticalAlignment( verticalAlignment );
super.setVerticalAlignment( verticalAlignment );
}
/**
* Set the background painter object
* @param xp the painter object
*/
public void setPainter( Painter xp )
{
painter = xp;
}
/**
* Get the background painter object
* @return the painter object
*/
public Painter getPainter()
{
return painter;
}
/**
* Is the button drawn vertically?
* @return
*/
public boolean isVertical()
{
return vertical;
}
/**
* Set the button to draw vertically?
* @return
*/
public void setVertical( boolean isVertical )
{
vertical = isVertical;
}
}