/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tiny Look and Feel * * * * (C) Copyright 2003 - 2007 Hans Bickel * * * * For licensing information and credits, please refer to the * * comment in file de.muntjak.tinylookandfeel.TinyLookAndFeel * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package de.muntjak.tinylookandfeel; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; import java.util.HashMap; import javax.swing.AbstractButton; import de.muntjak.tinylookandfeel.controlpanel.ColorRoutines; import de.muntjak.tinylookandfeel.controlpanel.DrawRoutines; /** * TinyRadioButtonIcon * * @version 1.0 * @author Hans Bickel */ class TinyRadioButtonIcon extends TinyCheckBoxIcon { // cache for already drawn icons - speeds up drawing by a factor // of 80 or more if there are several radio buttons or one radio button // is painted several times static HashMap cache = new HashMap(); static final int[][] a = { {255, 255, 255, 242, 228, 209, 187, 165, 142, 255, 255}, {255, 255, 242, 228, 209, 187, 165, 142, 120, 104, 255}, {255, 242, 228, 209, 187, 165, 142, 120, 104, 86, 72}, {242, 228, 209, 187, 165, 142, 120, 104, 86, 72, 56}, {228, 209, 187, 165, 142, 120, 104, 86, 72, 56, 42}, {209, 187, 165, 142, 120, 104, 86, 72, 56, 42, 28}, {187, 165, 142, 120, 104, 86, 72, 56, 42, 28, 17}, {165, 142, 120, 104, 86, 72, 56, 42, 28, 17, 9}, {142, 120, 104, 86, 72, 56, 42, 28, 17, 9, 0}, {255, 104, 86, 72, 56, 42, 28, 17, 9, 0, 255}, {255, 255, 72, 56, 42, 28, 17, 9, 0, 255, 255} }; /** * Draws the check box icon at the specified location. * * @param c The component to draw on. * @param g The graphics context. * @param x The x coordinate of the top left corner. * @param y The y coordinate of the top left corner. */ public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton button = (AbstractButton) c; // inner space Color col = null; if(!button.isEnabled()) { col = Theme.buttonDisabledColor[Theme.style].getColor(); } else if(button.getModel().isPressed()) { if(button.getModel().isRollover() || button.getModel().isArmed()) { col = Theme.buttonPressedColor[Theme.style].getColor(); } else { col = Theme.buttonNormalColor[Theme.style].getColor(); } } else if(button.getModel().isRollover() && Theme.buttonRollover[Theme.style]) { col = Theme.buttonRolloverBgColor[Theme.style].getColor(); } else { col = Theme.buttonNormalColor[Theme.style].getColor(); } g.setColor(col); switch(Theme.derivedStyle[Theme.style]) { case Theme.TINY_STYLE: drawTinyRadio(g, button, col, x, y, getIconWidth(), getIconHeight()); break; case Theme.W99_STYLE: drawWinRadio(g, button, col, x, y, getIconWidth(), getIconHeight()); break; case Theme.YQ_STYLE: if(TinyLookAndFeel.controlPanelInstantiated) { drawXpRadioNoCache(g, button, col, x, y, getIconWidth(), getIconHeight()); } else { drawXpRadio(g, button, col, x, y, getIconWidth(), getIconHeight()); } break; } // checkmark if(!button.isSelected()) return; if(!button.isEnabled()) { col = Theme.buttonCheckDisabledColor[Theme.style].getColor(); } else { col = Theme.buttonCheckColor[Theme.style].getColor(); } g.setColor(col); switch(Theme.derivedStyle[Theme.style]) { case Theme.TINY_STYLE: drawTinyCheckMark(g, col, x, y); break; case Theme.W99_STYLE: drawWinCheckMark(g, col, x, y); break; case Theme.YQ_STYLE: drawXpCheckMark(g, col, x, y); break; } } private void drawTinyRadio(Graphics g, AbstractButton b, Color c, int x, int y, int w, int h) { } private void drawWinRadio(Graphics g, AbstractButton b, Color c, int x, int y, int w, int h) { if(b.getModel().isPressed() && b.getModel().isRollover()) { g.setColor(Theme.backColor[Theme.style].getColor()); } else { if(!b.isEnabled()) { g.setColor(Theme.buttonLightDisabledColor[Theme.style].getColor()); } else { g.setColor(Theme.buttonLightColor[Theme.style].getColor()); } } g.fillRect(x + 2, y + 2, 8, 8); g.setColor(Theme.backColor[Theme.style].getColor()); g.drawLine(x + 9, y + 3, x + 9, y + 3); g.drawLine(x + 10, y + 4, x + 10, y + 7); g.drawLine(x + 9, y + 8, x + 9, y + 8); g.drawLine(x + 8, y + 9, x + 9, y + 9); g.drawLine(x + 2, y + 9, x + 3, y + 9); g.drawLine(x + 4, y + 10, x + 7, y + 10); if(!b.isEnabled()) { g.setColor(Theme.buttonLightDisabledColor[Theme.style].getColor()); } else { g.setColor(Theme.buttonLightColor[Theme.style].getColor()); } g.drawLine(x + 10, y + 2, x + 10, y + 3); g.drawLine(x + 11, y + 4, x + 11, y + 7); g.drawLine(x + 10, y + 8, x + 10, y + 9); g.drawLine(x + 8, y + 10, x + 9, y + 10); g.drawLine(x + 4, y + 11, x + 7, y + 11); g.drawLine(x + 2, y + 10, x + 3, y + 10); if(!b.isEnabled()) { g.setColor(Theme.buttonBorderDisabledColor[Theme.style].getColor()); } else { g.setColor(Theme.buttonBorderColor[Theme.style].getColor()); } g.drawLine(x + 4, y + 1, x + 7, y + 1); g.drawLine(x + 2, y + 2, x + 3, y + 2); g.drawLine(x + 8, y + 2, x + 9, y + 2); g.drawLine(x + 2, y + 3, x + 2, y + 3); g.drawLine(x + 1, y + 4, x + 1, y + 7); g.drawLine(x + 2, y + 8, x + 2, y + 8); if(!b.isEnabled()) { g.setColor(Theme.buttonDarkDisabledColor[Theme.style].getColor()); } else { g.setColor(Theme.buttonDarkColor[Theme.style].getColor()); } g.drawLine(x + 4, y + 0, x + 7, y + 0); g.drawLine(x + 2, y + 1, x + 3, y + 1); g.drawLine(x + 8, y + 1, x + 9, y + 1); g.drawLine(x + 1, y + 2, x + 1, y + 3); g.drawLine(x + 0, y + 4, x + 0, y + 7); g.drawLine(x + 1, y + 8, x + 1, y + 9); } private void drawXpRadio(Graphics g, AbstractButton b, Color c, int x, int y, int w, int h) { boolean pressed = b.getModel().isPressed(); boolean armed = b.getModel().isArmed(); boolean enabled = b.isEnabled(); boolean rollover = b.getModel().isRollover(); boolean focused = (Theme.buttonFocusBorder[Theme.style] && !rollover && b.isFocusOwner()); Color bg = b.getBackground(); if(!b.isOpaque()) { Container parent = b.getParent(); bg = parent.getBackground(); while(parent != null && !parent.isOpaque()) { parent = parent.getParent(); bg = parent.getBackground(); } } RadioKey key = new RadioKey(c, bg, pressed, enabled, (rollover || armed), focused); Object value = cache.get(key); if(value != null) { // image already cached - paint image and return g.drawImage((Image)value, x, y, b); return; } Image img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics imgGraphics = img.getGraphics(); imgGraphics.setColor(bg); imgGraphics.fillRect(0, 0, w, h); // spread light is between 0 and 20 int spread1 = Theme.buttonSpreadLight[Theme.style]; int spread2 = Theme.buttonSpreadDark[Theme.style]; if(!enabled) { spread1 = Theme.buttonSpreadLightDisabled[Theme.style]; spread2 = Theme.buttonSpreadDarkDisabled[Theme.style]; } int spreadStep1 = spread1 * 5; // 20 -> 100 // this means, we can never fully darken background, // but we also want it bright enough int spreadStep2 = spread2 * 4; // 20 -> 80 if(pressed && (rollover || armed)) { spreadStep2 *= 2; } c = ColorRoutines.lighten(c, spreadStep1); imgGraphics.setColor(ColorRoutines.darken(c, spreadStep2)); imgGraphics.fillRect(2, 2, w - 4, h - 4); imgGraphics.fillRect(1, 5, 1, 3); imgGraphics.fillRect(11, 5, 1, 3); imgGraphics.fillRect(5, 1, 3, 1); imgGraphics.fillRect(5, 11, 3, 1); Color color; for (int row = 0; row < 11; row++) { for (int col = 0; col < 11; col++) { color = new Color(c.getRed(), c.getGreen(), c.getBlue(), 255 - a[col][row]); imgGraphics.setColor(color); imgGraphics.drawLine(col + 1, row + 1, col + 1, row + 1); } } // border if(!enabled) { DrawRoutines.drawXpRadioBorder(imgGraphics, Theme.buttonBorderDisabledColor[Theme.style].getColor(), 0, 0, w, h); } else { if(rollover && Theme.buttonRollover[Theme.style] && !pressed) { DrawRoutines.drawXpRadioRolloverBorder(imgGraphics, Theme.buttonRolloverColor[Theme.style].getColor(), 0, 0, w, h); } else if(focused && !pressed) { DrawRoutines.drawXpRadioRolloverBorder(imgGraphics, Theme.buttonDefaultColor[Theme.style].getColor(), 0, 0, w, h); } DrawRoutines.drawXpRadioBorder(imgGraphics, Theme.buttonBorderColor[Theme.style].getColor(), 0, 0, w, h); } // dispose of image graphics imgGraphics.dispose(); // draw the image g.drawImage(img, x, y, b); // add the image to the cache cache.put(key, img); } // the old routine - execute this, if we are in the control panel // (else border colors not updated) private void drawXpRadioNoCache(Graphics g, AbstractButton b, Color c, int x, int y, int w, int h) { boolean pressed = b.getModel().isPressed(); boolean armed = b.getModel().isArmed(); boolean enabled = b.isEnabled(); boolean rollover = b.getModel().isRollover(); boolean focused = (Theme.buttonFocusBorder[Theme.style] && !rollover && b.isFocusOwner()); boolean useCachedImage = !pressed && !armed && !rollover && !focused; Image img = null; Object key = null; if(useCachedImage) { if(enabled) { key = new EnabledRadioKey(c, Theme.buttonBorderColor[Theme.style].getColor()); } else { key = new DisabledRadioKey(c, Theme.buttonBorderDisabledColor[Theme.style].getColor()); } Object value = cache.get(key); if(value != null) { // image already cached - paint image and return g.drawImage((Image)value, x, y, b); return; } img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); } // spread light is between 0 and 20 int spread1 = Theme.buttonSpreadLight[Theme.style]; int spread2 = Theme.buttonSpreadDark[Theme.style]; if(!enabled) { spread1 = Theme.buttonSpreadLightDisabled[Theme.style]; spread2 = Theme.buttonSpreadDarkDisabled[Theme.style]; } int spreadStep1 = spread1 * 5; // 20 -> 100 // this means, we can never fully darken background, // but we also want it bright enough int spreadStep2 = spread2 * 4; // 20 -> 80 if(pressed && (rollover || armed)) { spreadStep2 *= 2; } c = ColorRoutines.lighten(c, spreadStep1); Graphics graphics = null; int bx = x, by = y; if(img != null) { graphics = img.getGraphics(); Color bg = b.getBackground(); if(!b.isOpaque()) { Container parent = b.getParent(); bg = parent.getBackground(); while(parent != null && !parent.isOpaque()) { parent = parent.getParent(); bg = parent.getBackground(); } } graphics.setColor(bg); graphics.fillRect(0, 0, w - 1, h - 1); bx = 0; by = 0; } else { graphics = g; graphics.translate(x, y); } graphics.setColor(ColorRoutines.darken(c, spreadStep2)); graphics.fillRect(2, 2, w - 4, h - 4); graphics.fillRect(1, 5, 1, 3); graphics.fillRect(11, 5, 1, 3); graphics.fillRect(6, 1, 1, 1); graphics.fillRect(6, 11, 1, 1); Color color; for (int row = 0; row < 11; row++) { for (int col = 0; col < 11; col++) { color = new Color(c.getRed(), c.getGreen(), c.getBlue(), 255 - a[col][row]); graphics.setColor(color); graphics.drawLine(col + 1, row + 1, col + 1, row + 1); } } if(img == null) { graphics.translate(-x, -y); } // border if (!enabled) { DrawRoutines.drawXpRadioBorder( graphics, Theme.buttonBorderDisabledColor[Theme.style].getColor(), bx, by, w, h); } else { if(rollover && Theme.buttonRollover[Theme.style] && !pressed) { DrawRoutines.drawXpRadioRolloverBorder( graphics, Theme.buttonRolloverColor[Theme.style].getColor(), bx, by, w, h); } else if(focused && !pressed) { DrawRoutines.drawXpRadioRolloverBorder(graphics, Theme.buttonDefaultColor[Theme.style].getColor(), bx, by, w, h); } DrawRoutines.drawXpRadioBorder( graphics, Theme.buttonBorderColor[Theme.style].getColor(), bx, by, w, h); } if(img != null) { // dispose of image graphics graphics.dispose(); // draw the image g.drawImage(img, x, y, b); // cache image cache.put(key, img); } } private void drawTinyCheckMark(Graphics g, Color c, int x, int y) { } private void drawWinCheckMark(Graphics g, Color c, int x, int y) { g.fillRect(x + 4, y + 5, 4, 2); g.drawLine(x + 5, y + 4, x + 6, y + 4); g.drawLine(x + 5, y + 7, x + 6, y + 7); } private void drawXpCheckMark(Graphics g, Color c, int x, int y) { g.translate(x, y); g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 224)); g.fillRect(5, 5, 3, 3); g.setColor(c); g.drawLine(6, 6, 6, 6); g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 192)); g.drawLine(6, 4, 6, 4); g.drawLine(4, 6, 4, 6); g.drawLine(8, 6, 8, 6); g.drawLine(6, 8, 6, 8); g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 128)); g.drawLine(5, 4, 5, 4); g.drawLine(7, 4, 7, 4); g.drawLine(4, 5, 4, 5); g.drawLine(8, 5, 8, 5); g.drawLine(4, 7, 4, 7); g.drawLine(8, 7, 8, 7); g.drawLine(5, 8, 5, 8); g.drawLine(7, 8, 7, 8); g.translate(-x, -y); } /* * EnabledRadioKey is used as key in the cache HashMap. * Overrides equals() and hashCode(). * Used only if we are run from ControlPanel. */ static class EnabledRadioKey { int spread1; int spread2; Color c, back; EnabledRadioKey(Color c, Color back) { spread1 = Theme.buttonSpreadLight[Theme.style]; spread2 = Theme.buttonSpreadDark[Theme.style]; this.c = c; this.back = back; } public boolean equals(Object o) { if(o == null) return false; if(!(o instanceof EnabledCheckKey)) return false; EnabledCheckKey other = (EnabledCheckKey)o; return (c.equals(other.c) && back.equals(other.back) && spread1 == other.spread1 && spread2 == other.spread2); } public int hashCode() { return c.hashCode() * back.hashCode() * spread1 * spread2; } } /* * DisabledRadioKey is used as key in the cache HashMap. * Overrides equals() and hashCode(). * Used only if we are run from ControlPanel. */ static class DisabledRadioKey { int spread1; int spread2; Color c, back; DisabledRadioKey(Color c, Color back) { spread1 = Theme.buttonSpreadLightDisabled[Theme.style]; spread2 = Theme.buttonSpreadDarkDisabled[Theme.style]; this.c = c; this.back = back; } public boolean equals(Object o) { if(o == null) return false; if(!(o instanceof DisabledCheckKey)) return false; DisabledCheckKey other = (DisabledCheckKey)o; return (c.equals(other.c) && back.equals(other.back) && spread1 == other.spread1 && spread2 == other.spread2); } public int hashCode() { return c.hashCode() * back.hashCode() * spread1 * spread2; } } /* * RadioKey is used as key in the cache HashMap. * Overrides equals() and hashCode(). */ static class RadioKey { private Color c, background; private boolean pressed; private boolean enabled; private boolean rollover; private boolean focused; RadioKey(Color c, Color background, boolean pressed, boolean enabled, boolean rollover, boolean focused) { this.c = c; this.background = background; this.pressed = pressed; this.enabled = enabled; this.rollover = rollover; this.focused = focused; } public boolean equals(Object o) { if(o == null) return false; if(!(o instanceof RadioKey)) return false; RadioKey other = (RadioKey)o; return pressed == other.pressed && enabled == other.enabled && rollover == other.rollover && focused == other.focused && c.equals(other.c) && background.equals(other.background); } public int hashCode() { return c.hashCode() * background.hashCode() * (pressed ? 1 : 2) * (enabled ? 4 : 8) * (rollover ? 16 : 32); } } }