/* Copyright (c) 2004 Andreas Ernst Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.flexdock.dockbar.util; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.Icon; /** * @author Andreas Ernst * @author Christopher Butler */ public class TextIcon implements Icon, PropertyChangeListener { // constants public static final int ROTATE_NONE = 0x01; public static final int ROTATE_LEFT = 0x02; public static final int ROTATE_RIGHT = 0x04; private static final double NINETY_DEGREES = Math.toRadians(90.0); // instance data private Component mComponent; private String mText; private Icon mIcon; private int mIconSpace; private int mInset; private int mWidth; private int mHeight; private int mCharHeight; private int mDescent; private int mRotation; // constructor /** * Creates a <code>TextIcon</code> for the specified <code>component</code> * with the specified <code>label</code>. * It sets the orientation to the provided value if it's legal for the string */ public TextIcon(Component cmp, int space, int inset) { mComponent = cmp; mText = ""; mIcon = null; mRotation = ROTATE_NONE; mIconSpace = space; mInset = inset; calcDimensions(); mComponent.addPropertyChangeListener(this); } // public public String getText() { return mText; } public void setText(String text) { if(text==null) { text = ""; } boolean changed = isChanged(mText, text); mText = text; if(changed) { recalcDimensions(); } } public void setIcon(Icon icon) { boolean changed = isChanged(mIcon, icon); mIcon = icon; if(changed) { recalcDimensions(); } } public void setRotation(int rotation) { rotation = getValidRotation(rotation); boolean changed = rotation!=mRotation; mRotation = rotation; if(changed) { recalcDimensions(); } } public static int getValidRotation(int rotation) { switch(rotation) { case ROTATE_LEFT: return ROTATE_LEFT; case ROTATE_RIGHT: return ROTATE_RIGHT; default: return ROTATE_NONE; } } private boolean isChanged(Object oldValue, Object newValue) { if(oldValue==newValue) { return false; } if(oldValue==null || newValue==null) { return true; } return !oldValue.equals(newValue); } // implement PropertyChangeListener @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (prop.equals("font")) { recalcDimensions(); } } // private private void recalcDimensions() { int w = getIconWidth(); int h = getIconHeight(); calcDimensions(); if (w != getIconWidth() || h != getIconHeight()) { mComponent.invalidate(); } } private void calcDimensions() { FontMetrics fm = mComponent.getFontMetrics(mComponent.getFont()); mCharHeight = fm.getAscent() + fm.getDescent(); mDescent = fm.getDescent(); if (mRotation == ROTATE_NONE) { mHeight = Math.max(mCharHeight, mIcon != null ? mIcon.getIconHeight() : 0); mWidth = fm.stringWidth(mText) + (mIcon != null ? (mIcon.getIconWidth() + mIconSpace) : 0); } else { mWidth = Math.max(mCharHeight, mIcon != null ? mIcon.getIconHeight() : 0); mHeight = fm.stringWidth(mText) + (mIcon != null ? (mIcon.getIconWidth() + mIconSpace) : 0); } // else mWidth += 2 * mInset; mHeight += 2 * mInset; } // Icon @Override public int getIconWidth() { return mWidth; } @Override public int getIconHeight() { return mHeight; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D)g; g2d.setColor(c.getForeground()); g2d.setFont(c.getFont()); if (mRotation == ROTATE_NONE) { if ( mIcon != null) { x += mInset; y += mInset; int iconHeight = mIcon.getIconHeight(); mIcon.paintIcon(mComponent, g, x, y + (mHeight - 2 * mInset - iconHeight) / 2); // center vertically x += mIconSpace + mIcon.getIconWidth(); } // if Object renderingHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.drawString(mText, x, mHeight- mDescent - mInset); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, renderingHint); } else if (mRotation == ROTATE_LEFT) { // Bottom up int translateX = x + mWidth - mInset; int translateY = y + mHeight - mInset; g2d.translate(translateX, translateY); g2d.rotate(-NINETY_DEGREES); if (mIcon != null) { int iconHeight = mIcon.getIconHeight(); int iconOffset = (mWidth - 2 * mInset - iconHeight) / 2; // center icon mIcon.paintIcon(mComponent, g2d, 0, -mIcon.getIconWidth() - iconOffset); } // if Object renderingHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.drawString(mText, mIcon != null ? mIcon.getIconHeight() + mIconSpace: 0, -mDescent); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, renderingHint); g2d.rotate(NINETY_DEGREES); g2d.translate(-translateX, -translateY); } else if (mRotation == ROTATE_RIGHT) { // top down int translateX = x + mInset; int translateY = y + mInset; g2d.translate(translateX, translateY); g2d.rotate(NINETY_DEGREES); if ( mIcon != null) { int iconHeight = mIcon.getIconHeight(); int iconOffset = (mWidth - 2 * mInset - iconHeight) / 2; // center icon mIcon.paintIcon(mComponent, g2d, 0, -mIcon.getIconWidth() - iconOffset); } // if Object renderingHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.drawString(mText, mIcon != null ? mIcon.getIconHeight() + mIconSpace: 0, -mDescent); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, renderingHint); g2d.rotate(-NINETY_DEGREES); g2d.translate(-translateX, -translateY); } // if } public void validate() { calcDimensions(); } }