/** * ColorPanel - a hexagon-shaped control panel allowing any color to be * mixed and chosen with a single mouse click-and-drag. * * public functions: * ColorPanel - create a new colorpanel * setColor - set the colorpanel's current color * start - allocate a buffered image * stop - kill the buffered image * public fields: * Color color - the chosen color * String colorhex - the hex for the chosen color * * Architecture: * UseColor - a way for colorpanel to notify someone a color is chosen * ColorPanel - a big hexagon * ColorBar - one of the three bars in the big hexagon * ColorHandle - the little hexagon at the intersection of the bars * * Explanation: * This is a 2-dimensional image of a color cube. The color cube has * three axes, Red, Green, and Blue. The colorbars are those axes. The * colorhandle sits at the intersection of those axes at the chosen color. * The cube is viewed corner-on. (That's why the bars never leave the * hexagon.) The colorbars show the colors along their axes. If you want * a color, move in the direction of the colorbar showing a color close to * what you want. * * The class names have no capital letters because CompuServe can't store * files whose names have capital letters. Sorry about that. * * @author Author: Bob Jenkins * @version version 2.0, May 20, 1999 */ import java.awt.*; import java.awt.event.*; import java.util.*; import java.lang.*; /** ColorPanel: a color panel, a hexagonal widget for choosing a color */ public final class ColorPanel extends Panel { public Color color; /* the chosen color */ public String colorhex; /* the chosen color, hex string */ private static final int RED = 0x1; /* adjust red */ private static final int GREEN = 0x2; /* adjust green */ private static final int BLUE = 0x4; /* adjust blue */ final int thickness; /* thickness of bars */ final float handlewidth; /* thickness*0.8664 */ final UseColor u; final Color outside; /* color of outside of hexagon */ final ColorBar bar[]; /* The red,green,blue bars */ final ColorHandle handle; /* the handle at the intersection */ Image buffered; /* the current image, for antiflicker */ Graphics bg; /* buffered.getGraphics() */ float newval[]; final int[] hexx; /* x coordinates of hexagon */ final int[] hexy; /* y coordinates of hexagon */ float coef[][][]; /* red|green|blue, {red,green,blue}, {x,y} */ int centerx; /* center of hexagon */ int centery; /* center of hexagon */ int currx; /* current x coordinate of bar intersection */ int curry; /* current y coordinate of bar intersection */ int lastx; /* last x from mouse */ int lasty; /* last y from mouse */ boolean changing; /* are we currently changing the color */ float dabs; /* sqrt((currx-x)^^2+(curry-y)^^2)*0.9 */ int cc; /* the current color, in hex */ /** ColorPanel(): create a new color panel * UseColor u: a class to notify whenever a color has been chosen * Color outside: the color outside of the hexagon * also the original inside color * int thickness: the thickness of the bars * int width: the width of the panel * int height: the height of the panel */ ColorPanel(UseColor u, Color outside, int thickness, int width, int height) { resize(width, height); this.u = u; this.outside = (outside==null) ? Color.black : outside; this.thickness = thickness; this.handlewidth = thickness*(float)0.8664; this.bar = new ColorBar[3]; this.handle = new ColorHandle(this); this.coef = new float[8][3][2]; this.newval = new float[3]; /* construct the background */ this.lastx = this.centerx = width/2; this.lasty = this.centery = height/2; this.currx = centerx; this.curry = centery; this.cc = 0x808080; this.color = new Color(this.cc); if (width > height) { /* have a horizontal line */ this.hexx = new int[] { 0, centerx/2, 3*centerx/2, width-1, 3*centerx/2, centerx/2 }; this.hexy = new int[] { centery, height-1, height-1, centery, 0, 0 }; int tx = (centerx-2*thickness)/2; int ty = (centery-2*thickness); this.bar[0] = new ColorBar(this, ColorBar.RED, (float)0.5, centerx-2*thickness, 0); this.bar[1] = new ColorBar(this, ColorBar.GREEN, (float)0.5, -tx, ty); this.bar[2] = new ColorBar(this, ColorBar.BLUE, (float)0.5, -tx, -ty); } else { /* have a vertical line */ this.hexx = new int[] { centerx, width-1, width-1, centerx, 0, 0 }; this.hexy = new int[] { 0, centery/2, 3*centery/2, height-1, 3*centery/2, centery/2 }; int tx = (centerx-2*thickness); int ty = (centery-2*thickness)/2; this.bar[0] = new ColorBar(this, ColorBar.RED, (float)0.5, 0, centery-2*thickness); this.bar[1] = new ColorBar(this, ColorBar.GREEN, (float)0.5, tx, -ty); this.bar[2] = new ColorBar(this, ColorBar.BLUE, (float)0.5, -tx, -ty); } initCoef(); } /** getColor: get the color that has been selected */ public int getColor() { return cc; } public void update(Graphics g) { paint(g); } /* clear the old bar and handle */ public void clear(Graphics g) { for (int i=0; i distance[max]) max=1; if (distance[2] > distance[max]) max=2; return (max==0 ? (GREEN|BLUE) : (max==1 ? (RED|BLUE) : (RED|GREEN))); } } /* move to these positions along the bars */ void setCurrent() { currx = centerx; curry = centery; for (int i=0; i<3; ++i) { currx += (int)(newval[i]*(float)bar[i].lenx); curry += (int)(newval[i]*(float)bar[i].leny); } for (int i=0; i<3; ++i) bar[i].move(newval[i]); } /* move the bar intersection */ void moveCurrent(int x, /* change in x coordinate */ int y) /* change in y coordinate */ { int mode = findMode(x,y); if (mode==0) return; /* nowhere to move */ int i; /* Find distance to move. From surface of handle. */ int dx=(currx-x), dy=(curry-y); dx = (int)(dx-(dx/dabs)*handlewidth); dy = (int)(dy-(dy/dabs)*handlewidth); for (i=0; i<3; ++i) newval[i] = bar[i].value+coef[mode][i][0]*dx+coef[mode][i][1]*dy; for (i=0; i<3; ++i) { if (newval[i] < bar[i].mindim) newval[i]=bar[i].mindim; if (newval[i] > bar[i].maxdim) newval[i]=bar[i].maxdim; } setCurrent(); } /* register that the mouse has moved */ public boolean mouseDrag(Event e, int x, int y) { if (changing) { lastx = x; lasty = y; repaint(); } return true; } /* choose a color */ public boolean mouseDown(Event e, int x, int y) { if (findMode(x,y) == 0) { /* inside the little hexagon */ changing = true; } return true; } /* choose a color */ public boolean mouseUp(Event e, int x, int y) { if (changing) { setColor(new Color(cc)); if (u != null) u.UseColor(colorhex); changing = false; } return true; } private final void setNewval() { int q = color.getRGB(); newval[0] = (float)((q&0xff0000)>>16); newval[1] = (float)((q&0xff00)>>8); newval[2] = (float) (q&0xff); for (int i=0; i<3; ++i) { newval[i] = (newval[i]/(float)254.9); if (newval[i] < bar[i].mindim) newval[i]=bar[i].mindim; if (newval[i] > bar[i].maxdim) newval[i]=bar[i].maxdim; } } public void setColor(Color c) { color = c; // c is the current color setNewval(); // figure out bar positions for current color setCurrent(); // move the little hexagon to those bar positions changing = false; // don't pay attention to the mouse right now lastx = currx; // pretend we were always here lasty = curry; refresh(); // draw it } void refresh() { bg.setColor(outside); bg.fillRect(0, 0, size().width, size().height); bg.setColor((outside.getRGB()&0x808080)==0 ? Color.white : Color.black); colorhex = Integer.toString(color.getRGB()&0xffffff,16); while (colorhex.length() < 6) colorhex = "0" + colorhex; bg.drawString(colorhex, 2, size().height-2); bg.setColor(color); bg.fillPolygon(hexx, hexy, hexx.length); bg.setColor(color.darker()); bg.drawLine(hexx[4],hexy[4], hexx[5],hexy[5]); bg.drawLine(hexx[5],hexy[5], hexx[0],hexy[0]); bg.drawLine(hexx[0],hexy[0], hexx[1],hexy[1]); bg.setColor(color.brighter()); bg.drawLine(hexx[1],hexy[1], hexx[2],hexy[2]); bg.drawLine(hexx[2],hexy[2], hexx[3],hexy[3]); bg.drawLine(hexx[3],hexy[3], hexx[4],hexy[4]); repaint(); } /** start: make a buffer and initialize it */ public void start() { buffered = createImage(size().width, size().height); bg = buffered.getGraphics(); refresh(); } /** stop: dispose of buffered graphics object */ public void stop() { if (bg != null) { bg.dispose(); bg = null; } buffered = null; } }