1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
package com.explodingpixels.macwidgets.plaf;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.UIManager;
import com.explodingpixels.macwidgets.MacFontUtils;
import com.explodingpixels.macwidgets.WidgetBaseColors;
/**
* A collection of utilty method for painting Heads Up Style widgets. See the following for examples
* of HUD widgets:
* <ul>
* <li>{@link HudButtonUI}</li>
* <li>{@link HudCheckBoxUI}</li>
* <li>{@link HudComboBoxUI}</li>
* <li>{@link HudLabelUI}</li>
* </ul>
*/
public class HudPaintingUtils {
public static final Color FONT_COLOR = Color.WHITE;
public static final Color FONT_DISABLED_COLOR = new Color(0xaaaaaa);
public static final Color PRESSED_MARK_COLOR = new Color(0, 0, 0, 225);
public static final Color BORDER_COLOR = new Color(0xc5c8cf);
private static final int BORDER_WIDTH = 1;
private static final Color LIGHT_SHADOW_COLOR = new Color(0, 0, 0, 145);
private static final Color DARK_SHADOW_COLOR = new Color(0, 0, 0, 50);
private HudPaintingUtils() {
// utility class - no constructor needed.
}
/**
* Initializes the given {@link JComponent} as a HUD style widget. This includes setting the
* font, foreground and opacity of the given component.
*
* @param component the component to initialize as a HUD component.
*/
public static void initHudComponent(JComponent component, boolean isDarkColorScheme) {
component.setFont(HudPaintingUtils.getHudFont());
if (isDarkColorScheme)
component.setForeground(WidgetBaseColors.DARK_FONT_COLOR);
else
component.setForeground(WidgetBaseColors.LIGHT_FONT_COLOR);
// component.setForeground(HudPaintingUtils.FONT_COLOR);
component.setOpaque(false);
}
/**
* Gets the font used by HUD style widgets.
*
* @return the font used by HUD style widgets.
*/
public static Font getHudFont() {
return MacFontUtils.HUD_BUTTON_FONT;
}
/**
* Gets the number of pixels that a HUD style widget's shadow takes up. HUD button's have a
* shadow directly below them, that is, there is no top, left or right component to the shadow.
*
* @param button the button that the shadow is drawn on.
* @return the number of pixels that a HUD style widget's shadow takes up.
*/
public static int getHudControlShadowSize(AbstractButton button) {
// TODO use the button's font size to figure this out.
return 2;
}
/**
* Paints a HUD style button background onto the given {@link Graphics2D} context using the
* given {@link Roundedness}. The background will be painted from 0,0 to width/height.
*
* @param graphics the graphics context to paint onto.
* @param button the button being painted.
* @param width the width of the area to paint.
* @param height the height of the area to paint.
* @param roundedness the roundedness to use when painting the background.
* @param isDarkColorScheme whether to use the light or dark color scheme for this button
*/
public static void paintHudControlBackground(Graphics2D graphics, AbstractButton button,
int width, int height, Roundedness roundedness, boolean isDarkColorScheme) {
Paint paint = HudPaintingUtils.createButtonPaint(button, BORDER_WIDTH, isDarkColorScheme);
paintHudControlBackground(graphics, new Rectangle(0, 0, width, height),
roundedness.getShapeProvider(), paint);
}
/**
* Paints a HUD style background in the given shape. This includes a drop shadow which will be
* drawn under the shape to be painted. The shadow will be draw outside the given bounds.
*
* @param graphics the {@code Graphics2D} context to draw in.
* @param bounds the bounds to paint in.
* @param shapeProvider the delegate to request the {@link Shape} from.
* @param paint the {@link Paint} to use to fill the {@code Shape}.
*/
public static void paintHudControlBackground(Graphics2D graphics, Rectangle bounds,
ShapeProvider shapeProvider, Paint paint) {
graphics.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// TODO replace with real drop shadow painting.
int x = bounds.x;
int y = bounds.y;
int width = bounds.width;
int height = bounds.height;
graphics.setColor(LIGHT_SHADOW_COLOR);
graphics.draw(shapeProvider.createShape(x, y, width - 1, height));
graphics.setColor(DARK_SHADOW_COLOR);
graphics.draw(shapeProvider.createShape(x, y, width - 1, height + 1));
graphics.setPaint(paint);
graphics.fill(shapeProvider.createShape(x, y + 1, width, height - 1));
graphics.setColor(BORDER_COLOR);
graphics.draw(shapeProvider.createShape(x, y, width - 1, height - 1));
}
private static Paint createButtonPaint(AbstractButton button, int lineBorderWidth, boolean isDarkColorScheme) {
boolean isPressed = button.getModel().isPressed();
Color topPressedColor = isDarkColorScheme ? WidgetBaseColors.DARK_ACTIVE_SELECTED_TOP_COLOR : WidgetBaseColors.LIGHT_ACTIVE_SELECTED_TOP_COLOR;
Color topUnpressedColor = isDarkColorScheme ? WidgetBaseColors.DARK_ACTIVE_TOP_COLOR : WidgetBaseColors.LIGHT_ACTIVE_TOP_COLOR;
Color bottomPressedColor = isDarkColorScheme ? WidgetBaseColors.DARK_ACTIVE_SELECTED_BOTTOM_COLOR : WidgetBaseColors.LIGHT_ACTIVE_SELECTED_BOTTOM_COLOR;
Color bottomUnpressedColor = isDarkColorScheme ? WidgetBaseColors.DARK_ACTIVE_BOTTOM_COLOR : WidgetBaseColors.LIGHT_ACTIVE_BOTTOM_COLOR;
Color topColor = isPressed ? topPressedColor : topUnpressedColor;
Color bottomColor = isPressed ? bottomPressedColor : bottomUnpressedColor;
int bottomY = button.getHeight() - lineBorderWidth * 2;
return new GradientPaint(0, lineBorderWidth, topColor, 0, bottomY, bottomColor);
}
/**
* Installs an {@link AlphaComposite} on the given {@link Graphics2D) if the given
* {@link Component} is disabled.
*
* @param graphics the {@code Graphics2D} to adjust.
* @param component the {@code Component} whos enablement state should be queried.
*/
public static void updateGraphicsToPaintDisabledControlIfNecessary(Graphics2D graphics,
Component component) {
if (!component.isEnabled()) {
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
}
}
/**
* An enumeration representing the roundness styles of HUD buttons.
*/
public enum Roundedness {
ROUNDED_BUTTON(.95), COMBO_BUTTON(0.45), CHECK_BOX(0.4), RADIO(1.0), SLIDER_KNOB(1.0);
private final double fRoundedPercentage;
private final ShapeProvider fShapeProvider;
private Roundedness(double roundedPercentage) {
fRoundedPercentage = roundedPercentage;
fShapeProvider = createShapeProvider();
}
private int getRoundedDiameter(int controlHeight) {
// TODO make roudedness based on font size rather than component height.
int roundedDiameter = (int) (controlHeight * fRoundedPercentage);
int makeItEven = roundedDiameter % 2;
return roundedDiameter - makeItEven;
}
private ShapeProvider getShapeProvider() {
return fShapeProvider;
}
private ShapeProvider createShapeProvider() {
return new ShapeProvider() {
public Shape createShape(double x, double y, double width, double height) {
double arcDiameter = getRoundedDiameter((int) height);
return new RoundRectangle2D.Double(x, y, width, height, arcDiameter,
arcDiameter);
}
};
}
}
public interface ShapeProvider {
Shape createShape(double x, double y, double width, double height);
}
}
|