package org.limewire.ui.swing.painter; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import javax.swing.Action; import javax.swing.Icon; import org.jdesktop.swingx.JXButton; import org.jdesktop.swingx.painter.AbstractPainter; import org.limewire.ui.swing.components.LimeComboBox; import org.limewire.ui.swing.util.FontUtils; /** * Painter to be used to extend general font and icon behaviour to all * custom drawn buttons. Should only be accessed through it's factory * to avoid resource duplication. * * NOTE: Will not respect icon alignment */ public class ButtonForegroundPainter extends AbstractPainter<JXButton> { private final Paint pressedForeground; private final Paint hoverForeground; private final Paint disabledForeground; private final FontTransform pressedTransform; private final FontTransform hoverTransform; private final FontTransform disabledTransform; private Font fontCache = null; private Font pressedFontCache = null; private Font hoverFontCache = null; private Font disabledFontCache = null; /** * Creates a button foreground painter that does not * change it's font colour based on mouse state. * * NOTE: This should not be used as a shortcut to creating * buttons since it will ignore the default app style * -- instead use the factory */ public ButtonForegroundPainter() { this(null, null, null); } /** * Can be used to create a foreground painter with unique overlaid pressed and hover font colours * and a right aligned icon. * * NOTE: Will ignore default app style. Use the factory if regular behaviour is desired. */ public ButtonForegroundPainter(Paint hoverForeground, Paint pressedForeground, Paint disabledForeground) { this(hoverForeground, pressedForeground, disabledForeground, FontTransform.NO_CHANGE, FontTransform.NO_CHANGE, FontTransform.NO_CHANGE); } /** * Can be used to create a foreground painter with unique overlaid pressed and hover font style and colours * with a right aligned icon. FontTransforms are used to apply font transform operations on the * components base font when the button is in a certain state. * * NOTE: Will ignore default app style. Use the factory if regular behaviour is desired. */ public ButtonForegroundPainter(Paint hoverForeground, Paint pressedForeground, Paint disabledForeground, FontTransform hoverTransform, FontTransform pressedTransform, FontTransform disabledTransform) { this.pressedForeground = pressedForeground; this.hoverForeground = hoverForeground; this.disabledForeground = disabledForeground; this.pressedTransform = pressedTransform; this.hoverTransform = hoverTransform; this.disabledTransform = disabledTransform; setCacheable(false); } private Font deriveTransform(Font font, FontTransform transform) { switch (transform) { case NO_CHANGE : return font; case ADD_UNDERLINE : return FontUtils.deriveUnderline(font, true); case REMOVE_UNDERLINE : return FontUtils.deriveUnderline(font, false); } return font; } private void reloadFontCache(Font font) { fontCache = font; disabledFontCache = deriveTransform(font, disabledTransform); pressedFontCache = deriveTransform(font, pressedTransform); hoverFontCache = deriveTransform(font, hoverTransform); } @Override protected void doPaint(Graphics2D g, JXButton object, int width, int height) { int textBaseline = (object.getHeight()-3)/2 + g.getFontMetrics().getAscent()/2; Icon icon = null; Paint foreground = null; Font font = object.getFont(); if (font != fontCache) { reloadFontCache(font); } if (!object.isEnabled()) { foreground = disabledForeground; font = disabledFontCache; } else if (object.getModel().isPressed() || object.getModel().isSelected()) { icon = object.getPressedIcon(); foreground = pressedForeground; font = pressedFontCache; } else if (object.getModel().isRollover() || object.hasFocus()) { icon = object.getRolloverIcon(); foreground = hoverForeground; font = hoverFontCache; } else { icon = object.getIcon(); } if (foreground == null) { foreground = object.getForeground(); } g.setPaint(foreground); g.setFont(font); if (object.getText() != null) { g.drawString(object.getText(), object.getInsets().left, textBaseline); if (icon != null) { icon.paintIcon(object, g, object.getWidth() - icon.getIconWidth()/2 - 10, object.getHeight()/2 - icon.getIconHeight()/2); } } // TODO: should use a more OO solution in future else if (object instanceof LimeComboBox) { LimeComboBox box = (LimeComboBox) object; Action action = box.getSelectedAction(); if (action != null) { Icon actionIcon = (Icon)action.getValue(Action.SMALL_ICON); int leftGap = object.getInsets().left; if(actionIcon != null) { actionIcon.paintIcon(box, g, leftGap, (box.getHeight()- actionIcon.getIconHeight())/2); leftGap += actionIcon.getIconWidth() + 4; } g.drawString((String)action.getValue(Action.NAME), leftGap, textBaseline); } if (icon != null) { icon.paintIcon(box, g, box.getWidth() - object.getInsets().right + icon.getIconWidth(), box.getHeight()/2 - icon.getIconHeight()/2); } } } /** * Shortcuts to specify common font transform operations. * * NOTE: At this time only adding or removing an underline * from the base font is supported */ public enum FontTransform { NO_CHANGE, ADD_UNDERLINE, REMOVE_UNDERLINE; } }