package com.explodingpixels.macwidgets.plaf; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.swing.AbstractButton; import javax.swing.ButtonModel; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.plaf.basic.BasicCheckBoxUI; import javax.swing.plaf.basic.BasicGraphicsUtils; import com.explodingpixels.macwidgets.MacFontUtils; import com.explodingpixels.macwidgets.WidgetBaseColors; /** * Creates a Heads Up Display (HUD) style check box button, similar to that seen in various iApps * (e.g. iPhoto). * <br> * <img src="../../../../../graphics/HUDCheckBoxUI.png"> */ public class HudCheckBoxUI extends BasicCheckBoxUI { private boolean isDarkColorScheme = true; /** * Creates a HUD style {@link javax.swing.plaf.CheckBoxUI}. */ public HudCheckBoxUI() { super(); } /** * Creates a HUD style {@link javax.swing.plaf.CheckBoxUI}. */ public HudCheckBoxUI(boolean isDarkColorScheme) { super(); this.isDarkColorScheme = isDarkColorScheme; } @Override protected void installDefaults(final AbstractButton b) { super.installDefaults(b); HudPaintingUtils.initHudComponent(b, isDarkColorScheme); b.setIconTextGap((int) (MacFontUtils.HUD_FONT_SIZE / 2)); icon = new CheckIcon(isDarkColorScheme); } @Override public void paint(Graphics g, JComponent c) { HudPaintingUtils.updateGraphicsToPaintDisabledControlIfNecessary((Graphics2D) g, c); super.paint(g, c); } @Override protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) { MacFontUtils.enableAntialiasing((Graphics2D) g); AbstractButton button = (AbstractButton) c; FontMetrics fontMetrics = g.getFontMetrics(button.getFont()); int mnemonicIndex = button.getDisplayedMnemonicIndex(); g.setColor(button.getForeground()); BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemonicIndex, textRect.x + getTextShiftOffset(), textRect.y + fontMetrics.getAscent() + getTextShiftOffset()); } // Check icon implementation. ///////////////////////////////////////////////////////////////// private class CheckIcon implements Icon { private final int CHECK_BOX_SIZE = 12; private boolean isDarkColorScheme = true; private Color fontColor = WidgetBaseColors.DARK_FONT_COLOR; public CheckIcon(boolean isDarkColorScheme) { this.isDarkColorScheme = isDarkColorScheme; if (isDarkColorScheme) fontColor = WidgetBaseColors.DARK_FONT_COLOR; else fontColor = WidgetBaseColors.LIGHT_FONT_COLOR; } public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton button = (AbstractButton) c; Graphics2D graphics = (Graphics2D) g.create(); // translate the graphics context so that 0,0 is the top/left of the check box. this // allows us to then delegate the painting to the HudPaintingUtils method, which assumes // 0,0. graphics.translate(x, y); HudPaintingUtils.paintHudControlBackground(graphics, button, CHECK_BOX_SIZE, CHECK_BOX_SIZE, HudPaintingUtils.Roundedness.CHECK_BOX, isDarkColorScheme); drawCheckMarkIfNecessary(graphics, button.getModel()); graphics.dispose(); } /** * Draws the check mark if {@link javax.swing.ButtonModel#isSelected} returns true. */ private void drawCheckMarkIfNecessary(Graphics2D graphics, ButtonModel model) { if (model.isSelected()) { drawCheckMark(graphics, model); } } /** * Draws the check in the check box using the appropriate color based on the * {@link javax.swing.ButtonModel#isPressed} state. Note that part of the check will be drawn outside * it's bounds. Because this icon is actually being drawn inside a larger component (a * {@link javax.swing.JCheckBox}), this shouldn't be an issue. */ private void drawCheckMark(Graphics2D graphics, ButtonModel model) { int x1 = CHECK_BOX_SIZE / 4; int y1 = CHECK_BOX_SIZE / 3; int x2 = x1 + CHECK_BOX_SIZE / 6; int y2 = y1 + CHECK_BOX_SIZE / 4; int x3 = CHECK_BOX_SIZE - 2; int y3 = -1; Color color = model.isPressed() ? HudPaintingUtils.PRESSED_MARK_COLOR : fontColor; graphics.setStroke(new BasicStroke(1.65f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); graphics.setColor(color); graphics.drawLine(x1, y1, x2, y2); graphics.drawLine(x2, y2, x3, y3); } public int getIconWidth() { return CHECK_BOX_SIZE; } public int getIconHeight() { return CHECK_BOX_SIZE; } } }