// DisplayColours: display the Java Colour Cube
// Copyright (C) Lemma 1 Ltd. 1997
// Author: Rob Arthan; rda@lemma-one.com

// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// The GNU General Public License can be obtained at URL:
// http://www.lemma-one.com/scrapbook/gpl.html
// or by writing to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA.


import java.awt.*;
import GUIUtils.NatField;

// interface for a class to display an RGB value
interface DisplayRGB {
	public void displayRGB(int red, int green, int blue);
}

// interface for a class to zoom in on a square of the display
interface Zoom {
	public void zoom(int incr, byte axis,
			int red, int green, int blue);
}

class DisplayColoursCanvas extends Canvas {
// base points in colour cube:
	private int red, green, blue;
// incremental value (typically 1 or 16)
	private int increment;
// manifest constants defining axis of section through the colour cube:
// z = R => x = G /\ y = B
// z = G => x = B /\ y = R
// z = B => x = R /\ y = G
	final static byte RED_Z = 0;
	final static byte GREEN_Z = 1;
	final static byte BLUE_Z = 2;
// axis value:
	private byte axis;
// grid parameters:
	final private int edge_size = 20;
// display class
	DisplayRGB display_rgb;
	Zoom zoom;
//
// paint method; display grid
//
	public void paint(Graphics gfx) {
		int r, g, b;
		switch (axis) {
			case RED_Z:
				for(int i = 0; i < 16; ++i)
				for(int j = 0; j < 16; ++j) {
					r = red;
					g = green + i * increment;
					b = blue + j * increment;
					gfx.setColor(new Color(r, g, b));
					gfx.fillRect(i*edge_size+1, j*edge_size+1,
						edge_size-1, edge_size-1);
				}
				break;
			case GREEN_Z:
				for(int i = 0; i < 16; ++i)
				for(int j = 0; j < 16; ++j) {
					r = red + j * increment;
					g = green;
					b = blue + i * increment;
					gfx.setColor(new Color(r, g, b));
					gfx.fillRect(i*edge_size+1, j*edge_size+1,
						edge_size-1, edge_size-1);
				}
				break;
			default:
				for(int i = 0; i < 16; ++i)
				for(int j = 0; j < 16; ++j) {
					r = red + i * increment;
					g = green + j * increment;
					b = blue;
					gfx.setColor(new Color(r, g, b));
					gfx.fillRect(i*edge_size+1, j*edge_size+1,
						edge_size-1, edge_size-1);
				}
				break;
		}
	}
//
// constructor function:
//
	DisplayColoursCanvas (int incr, byte ax,
		int r, int g, int b, DisplayRGB d, Zoom z) {

		increment = incr;
		axis = ax;
		
		red = r;
		green = g;
		blue = b;
		display_rgb = d;
		zoom = z;
	}
//
// preferredSize method for layout managers
//
	public Dimension preferredSize() {
		return new Dimension(16*edge_size, 16*edge_size);
	}
//
// minimumSize method for layout managers
//
	public Dimension minimumSize() {
		return preferredSize();
	}
//
// mouseMove method: if display_rgb isn't null display character under cursor
//
	public boolean mouseMove(Event evt, int x, int y) {
		if(display_rgb != null) {
			int x0 = (x / edge_size) * increment;
			int y0 = (y / edge_size) * increment;
			switch(axis) {
				case RED_Z:
					display_rgb.displayRGB
						(red, green+x0, blue+y0);
					break;
				case GREEN_Z:
					display_rgb.displayRGB
						(red+y0, green, blue+x0);
					break;
				case BLUE_Z:
					display_rgb.displayRGB
						(red+x0, green+y0, blue);
					break;
			}
		}
		return true;
	}
//
// mouseUp method: if the shift key's down then call the zoom method
//
	public boolean mouseUp(Event evt, int x, int y) {
		if(zoom != null && (evt.modifiers & Event.SHIFT_MASK) != 0) {
			int x0 = (x / edge_size) * increment;
			int y0 = (y / edge_size) * increment;
			switch(axis) {
				case RED_Z:
					zoom.zoom(1, axis, red, x0, y0);
					break;
				case GREEN_Z:
					zoom.zoom(1, axis, y0, green, x0);
					break;
				case BLUE_Z:
					zoom.zoom(1, axis, x0, y0, blue);
					break;
			}
		}
		return true;
	}
}

class DisplayColoursFrame extends Frame implements DisplayRGB, Zoom {
//
// label to display the RGB value of the colour under the mouse
//
	Label rgb_label;
//
// method to display an RGB value (in hex) in the label
//
	public void displayRGB(int red, int green, int blue) {
		if(rgb_label != null) {
			String msg = "R = 0x" +
					Integer.toString(red, 16) +
					"; G = 0x" +
					Integer.toString(green, 16) +
					"; B = 0x" +
					Integer.toString(blue, 16);
			rgb_label.setText(msg);
		}
	}
//
// build_frame: build a frame and populate it with a font display canvas
// and the label for the RGB value display
//
	DisplayColoursFrame (int incr, byte axis,
			int red, int green, int blue, boolean zoomable) {
		super();
		String title;
		switch (axis) {
			case DisplayColoursCanvas.RED_Z:
				title = "R = 0x" + Integer.toString(red, 16) +
					"; G = x; B = y";
				break;
			case DisplayColoursCanvas.GREEN_Z:
				title = "R = y; " +
					"G = 0x" + Integer.toString(green, 16) +
					"; B = x";
				break;
			default:
				title = "R = x; G = y; " +
					"B = 0x" + Integer.toString(blue, 16);
				break;
		}
		title = title + "; Resolution = " + incr;
		setTitle(title);

		GridBagLayout layout = new GridBagLayout();

		setLayout(layout);

		DisplayColoursCanvas c = new DisplayColoursCanvas
				(incr, axis, red, green, blue, this,
				zoomable ? this : null);

		GridBagConstraints c_con = new GridBagConstraints();
		c_con.gridx = 0; c_con.gridy = 0;
		layout.setConstraints(c, c_con);

		add(c);

		rgb_label = new Label("R= 0x00; G = 0x00; B = 0x00 ", Label.LEFT);

		GridBagConstraints rgbl_con = new GridBagConstraints();
		rgbl_con.gridx = 0; c_con.gridy = 1;
		layout.setConstraints(rgb_label, rgbl_con);

		add(rgb_label);

		if (zoomable) {
			Label info_label =
			new Label("Shift+Click to zoom in", Label.LEFT);
			GridBagConstraints il_con = new GridBagConstraints();
			il_con.gridx = 0; il_con.gridy = 2;
			layout.setConstraints(info_label, il_con);
			add(info_label);
		}

		pack();
		show();
	}

	public void zoom (int incr, byte axis,
			int red, int green, int blue) {
		new DisplayColoursFrame(incr, axis, red, green, blue, false);
	}
	public boolean handleEvent(Event evt) {
		if(evt.id == Event.WINDOW_DESTROY) {
			dispose();
			return true;
		}
		return false;
	}
}

class DisplayColoursControlPanel extends Panel {


	private NatField level_field;

	private Choice axis_choice;

	private Button display_button;

	private static String hexits[] =
	{"0", "1", "2", "3", "4", "5", "6", "7", "8",
	 "9", "a", "b", "c", "d", "e", "f"};

	private static String axes[] = {"Red", "Green", "Blue"};

	private byte parse_axis (String a) {
		if (a == axes[0]) {
			return DisplayColoursCanvas.RED_Z;
		} else if (a == axes[1]) {
			return DisplayColoursCanvas.GREEN_Z;
		} else {
			return DisplayColoursCanvas.BLUE_Z;
		}
	}

	private GridBagConstraints
		 place(GridBagLayout gbl, Component comp,
			int x, int y, int width, int anchor) {
		
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = x;
		gbc.gridy = y;
		gbc.gridwidth = width;
		gbc.anchor = anchor;
		gbc.fill = GridBagConstraints.BOTH;
		gbl.setConstraints(comp, gbc);
		return gbc;
	}
		
	DisplayColoursControlPanel() {

		GridBagLayout gbl = new GridBagLayout();
		setLayout(gbl);

		Label level_label = new Label("Level:", Label.LEFT);
		add(level_label);
		level_field = new NatField(0, 4, 255);
		add(level_field);

		Label axis_label = new Label("Z axis:", Label.LEFT);
		add(axis_label);
		axis_choice = new Choice();
		for(int i = 0; i < 3; ++i) {
			axis_choice.addItem(axes[i]);
		}
		add(axis_choice);

		display_button = new Button("Display");
		add(display_button);

		place(gbl, level_label,    0, 0, 1, GridBagConstraints.WEST);
		place(gbl, level_field,    1, 0, 1, GridBagConstraints.EAST);
		place(gbl, axis_label,     0, 1, 1, GridBagConstraints.WEST);
		place(gbl, axis_choice,    1, 1, 1, GridBagConstraints.EAST);
		place(gbl, display_button, 0, 2, 2, GridBagConstraints.WEST);

		show();
	}

	public boolean handleEvent(Event evt) {
		if(evt.target == display_button
		&& evt.id == Event.ACTION_EVENT) {
			int level = level_field.getNat();
			byte axis = parse_axis(axis_choice.getSelectedItem());
			switch (axis) {
				case DisplayColoursCanvas.RED_Z:
					new DisplayColoursFrame(
						16, axis, level, 0, 0, true);
					break;
				case DisplayColoursCanvas.GREEN_Z:
					new DisplayColoursFrame(
						16, axis, 0, level, 0, true);
					break;
				case DisplayColoursCanvas.BLUE_Z:
					new DisplayColoursFrame(
						16, axis, 0, 0, level, true);
					break;
			}
			return true;
		}
		return false;
	}
}

public class DisplayColours extends java.applet.Applet {
	public void init () {
		DisplayColoursControlPanel pan = new DisplayColoursControlPanel();
		add(pan);
		resize(pan.size());
	}
}
