/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*	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.*;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalButtonUI;

import de.muntjak.tinylookandfeel.controlpanel.*;

/**
 * TinyButtonUI. The UI delegate for JButton, JToggleButton and ArrowButtons for JSpinner.
 *
 * @version 1.3.04
 * @author Hans Bickel
 */
public class TinyButtonUI extends MetalButtonUI {

	// if a button has not the defined background, it will
	// be darkened resp. lightened by BG_CHANGE amount if
	// pressed or rollover
	public static final int BG_CHANGE_AMOUNT = 10;

	/**
	 * The Cached UI delegate.
	 */
	private static final TinyButtonUI buttonUI = new TinyButtonUI();

	/* the only instance of the stroke for the focus */
	private static final BasicStroke focusStroke =
		new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f, new float[] { 1.0f, 1.0f }, 0.0f);

	private boolean graphicsTranslated;
	private boolean isToolBarButton, isFileChooserButton;
	private boolean isDefault;

	public TinyButtonUI() {}
	
	public void installUI(JComponent c) {
		super.installUI(c);
        
        if(!Theme.buttonEnter[Theme.style]) return;
        if(!c.isFocusable()) return;

        InputMap km = (InputMap)UIManager.get(getPropertyPrefix() + "focusInputMap");

        if(km != null) {
        	// replace SPACE with ENTER (but SPACE will still work, don't know why)
        	km.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "pressed");
        	km.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), "released");
        }
    }

	public void installDefaults(AbstractButton button) {
		super.installDefaults(button);
		button.setRolloverEnabled(true);
	}

	protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
		if(isFileChooserButton ||
			(isToolBarButton && !Theme.toolFocus[Theme.style]) ||
			!Theme.buttonFocus[Theme.style])
		{
			return;
		}

		Graphics2D g2d = (Graphics2D)g;
		Rectangle focusRect = b.getBounds();

		g.setColor(Color.black);
		g2d.setStroke(focusStroke);

		int x1 = 2;
		int y1 = 2;
		int x2 = x1 + focusRect.width - 5;
		int y2 = y1 + focusRect.height - 5;

		if(!isToolBarButton) {
			x1++;
			y1++;
			x2--;
			y2--;
		}

		if(graphicsTranslated) {
			g.translate(-1, -1);
		}

		g2d.drawLine(x1, y1, x2, y1);
		g2d.drawLine(x1, y1, x1, y2);
		g2d.drawLine(x1, y2, x2, y2);
		g2d.drawLine(x2, y1, x2, y2);
	}

	/**
	 * Creates the UI delegate for the given component.
	 *
	 * @param mainColor The component to create its UI delegate.
	 * @return The UI delegate for the given component.
	 */
	public static ComponentUI createUI(final JComponent c) {
		return buttonUI;
	}

	protected void paintButtonPressed(Graphics g, AbstractButton button) {
		if(isToolBarButton || isFileChooserButton) return;

		Color col = null;
		if(!button.getBackground().equals(Theme.buttonNormalColor[Theme.style].getColor())) {
			col = ColorRoutines.darken(button.getBackground(), BG_CHANGE_AMOUNT);
		}
		else {
			col = Theme.buttonPressedColor[Theme.style].getColor();
		}

		g.setColor(col);

		switch (Theme.derivedStyle[Theme.style]) {
			case Theme.TINY_STYLE :
				drawTinyButton(g, button, col);
				break;
			case Theme.W99_STYLE :
				drawWinButton(g, button, col);
				break;
			case Theme.YQ_STYLE :
				drawXpButton(g, button, col, false);
				break;
		}

		if(!(button instanceof JToggleButton)) {
			// Changed in 1.3.04: If button is icon-only
			// then don't shift
			if(Theme.shiftButtonText[Theme.style] &&
				button.getText() != null &&
				!"".equals(button.getText()))
			{
				g.translate(1, 1);
				graphicsTranslated = true;
			}
		}
	}

	public void paintToolBarButton(Graphics g, AbstractButton b) {
		Color col = null;
		
		// New in 1.3.7
		boolean isRollover = b.getModel().isRollover() || b.getModel().isArmed();
		Color toolButtColor = null;
		
		if(isFileChooserButton) {
			toolButtColor = b.getParent().getBackground();
		}
		else {
			toolButtColor = Theme.toolButtColor[Theme.style].getColor();
		}

		if(b.getModel().isPressed()) {
			if(isRollover) {
				col = Theme.toolButtPressedColor[Theme.style].getColor();
			}
			else {
				if(b.isSelected()) {
					col = Theme.toolButtSelectedColor[Theme.style].getColor();
				}
				else {
					col = toolButtColor;
				}
			}
		}
		else if(isRollover && Theme.derivedStyle[Theme.style] == Theme.YQ_STYLE) {
			if(b.isSelected()) {
				col = Theme.toolButtSelectedColor[Theme.style].getColor();
			}
			else {
				col = Theme.toolButtRolloverColor[Theme.style].getColor();
			}
		}
		else if(b.isSelected()) {
			col = Theme.toolButtSelectedColor[Theme.style].getColor();
		}
		else {
			col = toolButtColor;
		}

		g.setColor(col);

		switch (Theme.derivedStyle[Theme.style]) {
			case Theme.TINY_STYLE :
				drawTinyToolBarButton(g, b, col, false);
				break;
			case Theme.W99_STYLE :
				drawWinToolBarButton(g, b, col, false);
				break;
			case Theme.YQ_STYLE :
				drawXpToolBarButton(g, b, col, false);
				break;
		}
	}

	public void paint(Graphics g, JComponent c) {
		AbstractButton button = (AbstractButton)c;

		if(isToolBarButton || isFileChooserButton) {
			paintToolBarButton(g, button);
			
			// the base class may paint text and/or icons
			super.paint(g, c);

			return;
		}

		if((button instanceof JToggleButton) && button.isSelected()) {
			paintButtonPressed(g, button);

			// the base class may paint text and/or icons
			super.paint(g, c);
			return;
		}

		isDefault = (c instanceof JButton) && (((JButton)c).isDefaultButton());
		boolean isRollover = button.getModel().isRollover() &&
			Theme.buttonRollover[Theme.derivedStyle[Theme.style]];
		boolean isDefinedBackground = c.getBackground().equals(
			Theme.buttonNormalColor[Theme.style].getColor());
		Color col = null;

		if(!button.isEnabled()) {		
			col = Theme.buttonDisabledColor[Theme.style].getColor();
		}
		else if(button.getModel().isPressed()) {
			if(isRollover) {
				if(isDefinedBackground) {
					col = Theme.buttonPressedColor[Theme.style].getColor();
				}
				else {
					col = ColorRoutines.darken(c.getBackground(), BG_CHANGE_AMOUNT);
				}
			}
			else {
				// button pressed but mouse exited
				col = c.getBackground();
			}
		}
		else if(isRollover) {
			if(isDefinedBackground) {
				col = Theme.buttonRolloverBgColor[Theme.style].getColor();
			}
			else {
				col = ColorRoutines.lighten(c.getBackground(), BG_CHANGE_AMOUNT);
			}
		}
		else {
			col = c.getBackground();
		}

		g.setColor(col);

		switch(Theme.derivedStyle[Theme.style]) {
			case Theme.TINY_STYLE :
				drawTinyButton(g, button, col);
				break;
			case Theme.W99_STYLE :
				drawWinButton(g, button, col);
				break;
			case Theme.YQ_STYLE :
				drawXpButton(g, button, col, isRollover);
				break;
		}

		// the base class may paint text and/or icons
		super.paint(g, c);
	}

	// this overrides BasicButtonUI.paintIcon(...)
	protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) {
		if(c instanceof JToggleButton) {
			paintToggleButtonIcon(g, c, iconRect);
		}
		else {
			super.paintIcon(g, c, iconRect);
		}
	}

	protected void paintToggleButtonIcon(Graphics g, JComponent c, Rectangle iconRect) {
		AbstractButton b = (AbstractButton)c;
		ButtonModel model = b.getModel();
		Icon icon = null;

		if(!model.isEnabled()) {
			if(model.isSelected()) {
				icon = (Icon)b.getDisabledSelectedIcon();
			}
			else {
				icon = (Icon)b.getDisabledIcon();
			}
		}
		else if(model.isPressed() && model.isArmed()) {
			icon = (Icon)b.getPressedIcon();
			if(icon == null) {
				// Use selected icon
				icon = (Icon)b.getSelectedIcon();
			}
		}
		else if(model.isSelected()) {
			if(b.isRolloverEnabled() && model.isRollover()) {
				icon = (Icon)b.getRolloverSelectedIcon();
				if(icon == null) {
					icon = (Icon)b.getSelectedIcon();
				}
			}
			else {
				icon = (Icon)b.getSelectedIcon();
			}
		}
		else if(model.isRollover() && Theme.derivedStyle[Theme.style] == Theme.YQ_STYLE) {
			icon = (Icon)b.getRolloverIcon();
		}

		if(icon == null) {
			icon = (Icon)b.getIcon();
		}

		icon.paintIcon(b, g, iconRect.x, iconRect.y);
	}

	public void update(Graphics g, JComponent c) {
		isToolBarButton = Boolean.TRUE.equals(
			c.getClientProperty(TinyToolBarUI.IS_TOOL_BAR_BUTTON_KEY));
		isFileChooserButton = Boolean.TRUE.equals(
			c.getClientProperty(TinyFileChooserUI.IS_FILE_CHOOSER_BUTTON_KEY));
		paint(g, c);
		graphicsTranslated = false;
	}

	private void drawTinyButton(Graphics g, AbstractButton b, Color c) {
	}

	private void drawWinButton(Graphics g, AbstractButton b, Color c) {
		int w = b.getWidth();
		int h = b.getHeight();

		if(b.isContentAreaFilled() && b.isOpaque()) {
			g.fillRect(1, 1, w - 2, h - 2);
		}
	}

	private void drawXpButton(Graphics g, AbstractButton b, Color c, boolean isRollover) {
		if(!b.isContentAreaFilled()) return;
		if(!b.isOpaque()) return;

		int w = b.getWidth();
		int h = b.getHeight();
		
		// paint border background
		Color bg = b.getParent().getBackground();
		g.setColor(bg);
		g.drawRect(0, 0, w - 1, h - 1);

		int spread1 = Theme.buttonSpreadLight[Theme.style];
		int spread2 = Theme.buttonSpreadDark[Theme.style];
		if(!b.isEnabled()) {
			spread1 = Theme.buttonSpreadLightDisabled[Theme.style];
			spread2 = Theme.buttonSpreadDarkDisabled[Theme.style];
		}

		float spreadStep1 = 10.0f * spread1 / (h - 3);
		float spreadStep2 = 10.0f * spread2 / (h - 3);
		int halfY = h / 2;
		int yd;

		for (int y = 1; y < h - 1; y++) {
			if(y < halfY) {
				yd = halfY - y;
				g.setColor(ColorRoutines.lighten(c, (int)(yd * spreadStep1)));
			}
			else if(y == halfY) {
				g.setColor(c);
			}
			else {
				yd = y - halfY;
				g.setColor(ColorRoutines.darken(c, (int)(yd * spreadStep2)));
			}

			g.drawLine(2, y, w - 3, y);

			if(y == 1) {
				// left vertical line
				g.drawLine(1, 1, 1, h - 2);
				
				if(isRollover || isDefault) {
					// right vertical line
					g.drawLine(w - 2, 1, w - 2, h - 2);
				}
			}
			else if(y == h - 2 && !isRollover && !isDefault) {
				// right vertical line
				g.drawLine(w - 2, 1, w - 2, h - 2);
			}
		}
		
		// 1 pixel away from each corner
		if(isRollover) {
			g.setColor(Theme.buttonRolloverColor[Theme.style].getColor());
			g.drawLine(1, h - 2, 1, h - 2);
			g.drawLine(w - 2, h - 2, w - 2, h - 2);
		}
		else if(isDefault) {
			g.setColor(Theme.buttonDefaultColor[Theme.style].getColor());
			g.drawLine(1, h - 2, 1, h - 2);
			g.drawLine(w - 2, h - 2, w - 2, h - 2);
		}
	}

	private void drawTinyToolBarButton(Graphics g, AbstractButton b, Color c, boolean isPressed) {
	}

	private void drawWinToolBarButton(Graphics g, AbstractButton b, Color c, boolean isPressed) {
		int w = b.getWidth();
		int h = b.getHeight();

		if(b.isContentAreaFilled()) {
			g.fillRect(1, 1, w - 2, h - 2);
		}
	}

	private void drawXpToolBarButton(Graphics g, AbstractButton b, Color c, boolean isPressed) {
		int w = b.getWidth();
		int h = b.getHeight();

		if(b.isContentAreaFilled()) {
			g.fillRect(1, 1, w - 2, h - 2);
		}
		
		// paint border background
		Color bg = b.getParent().getBackground();
		g.setColor(bg);
		g.drawRect(0, 0, w - 1, h - 1);
	}
}