import java.lang.*; import java.awt.*; import java.awt.event.*; import Bitmap; import Painter; final class PainterHSB extends Canvas implements KeyListener, MouseListener, MouseMotionListener, ComponentListener { Image _imageHS = null, _imageSB = null; int _iRadius, _iWidth = 0; int _xHS, _yHS, _xSB, _ySB; float _fHue, _fSaturation, _fBrightness; boolean _fHSDrag = false, _fSBDrag = false; Dimension _dimension; PainterHSB(int rgb) { float afHSB[] = Color.RGBtoHSB((rgb >>> 16) & 255, (rgb >>> 8) & 255, rgb & 255, null); _fHue = afHSB[0]; _fSaturation = afHSB[1]; _fBrightness = afHSB[2]; addKeyListener(this); addMouseListener(this); addMouseMotionListener(this); addComponentListener(this); } final void createImageHS() { _imageHS = null; Bitmap bitmap = new Bitmap(_iRadius * 2 + 1, _iRadius * 2 + 1); for (int y = -_iRadius; y <= _iRadius; y++) { for (int x = -_iRadius; x <= _iRadius; x++) { float fRadius = (float)Math.sqrt((double)(x * x + y * y) / (_iRadius * _iRadius)); int iColor; if (fRadius == 0) { iColor = 0xffffff; } else if (fRadius <= 1) { double dAngle = Math.atan2(y, x) / (2 * Math.PI); iColor = Color.HSBtoRGB((float)(dAngle - Math.floor(dAngle)), fRadius, 1); } else { iColor = 0xcccccc; } bitmap.put(x + _iRadius, y + _iRadius, iColor); } } _imageHS = createImage(bitmap); } final void createImageSB() { _imageSB = null; int iMaxWidth = _iWidth - 1; Bitmap bitmap = new Bitmap(_iWidth, _iWidth); float fHue = _fHue; for (int y = 0; y <= iMaxWidth ; y++) { for (int x = 0; x <= iMaxWidth; x++) { bitmap.put(x, y, Color.HSBtoRGB(fHue, (float)x / iMaxWidth, (float)y / iMaxWidth)); } } _imageSB = createImage(bitmap); } final void updateLineHS(int x, int y) { int iRadius = _iRadius; x -= iRadius; y -= iRadius; if (x != 0 || y != 0) { double dRadiusFactor = iRadius / Math.sqrt(x * x + y * y); x = iRadius + (int)(x * dRadiusFactor); y = iRadius + (int)(y * dRadiusFactor); int xMin = Math.min(Math.min(iRadius, _xHS), x), xMax = Math.max(Math.max(iRadius, _xHS), x), yMin = Math.min(Math.min(iRadius, _yHS), y), yMax = Math.max(Math.max(iRadius, _yHS), y); _xHS = x; _yHS = y; repaint(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1); } } final void updateLineSB(int x, int y) { int iWidth = _iWidth; _xSB = Math.min(Math.max(x, iWidth), iWidth * 2 - 1); _ySB = Math.min(Math.max(y, 0), iWidth - 1); repaint(iWidth, 0, iWidth, iWidth); } final void setupLines() { int iMaxWidth = _iWidth - 1; _xHS = _iRadius + (int)(_iRadius * Math.cos(_fHue * (2 * Math.PI))); _yHS = _iRadius - (int)(_iRadius * Math.sin(_fHue * (2 * Math.PI))); _xSB = _iWidth + (int)(iMaxWidth * _fSaturation + 0.5); _ySB = iMaxWidth - (int)(iMaxWidth * _fBrightness + 0.5); } final void setupRGB() { ((PainterPalette)getParent()).changeRGB(Color.HSBtoRGB(_fHue, _fSaturation, _fBrightness)); } final public void setupHSB(float fHue, float fSaturation, float fBrightness) { _fSaturation = fSaturation; _fBrightness = fBrightness; if (fHue != _fHue) { _fHue = fHue; createImageSB(); } setupLines(); setupRGB(); repaint(); } final public void paint(Graphics g) { g.setColor(Color.black); if (_imageHS != null) { g.drawImage(_imageHS, 0, 0, this); g.drawLine(_iRadius, _iRadius, _xHS, _yHS); } if (_imageSB != null) { g.drawImage(_imageSB, _iWidth, 0, this); g.drawLine(_xSB, 0, _xSB, _iWidth - 1); g.drawLine(_iWidth, _ySB, _iWidth * 2 - 1, _ySB); } } final public void update(Graphics g) { paint(g); } final public Dimension getPreferredSize() { return new Dimension(256, 128); } final public void keyPressed(KeyEvent ke) { if (ke.getKeyCode() == KeyEvent.VK_ESCAPE && (_fHSDrag || _fSBDrag)) { setupLines(); _fHSDrag = _fSBDrag = false; repaint(); } } final public void keyTyped(KeyEvent ke) { } final public void keyReleased(KeyEvent ke) { } final public void mouseClicked(MouseEvent me) { } final public void mouseEntered(MouseEvent me) { } final public void mouseExited(MouseEvent me) { } final public void mousePressed(MouseEvent me) { int x = me.getX(), y = me.getY(); if (x < _iWidth) { _fHSDrag = true; updateLineHS(x, y); } else if (x < _iWidth * 2) { _fSBDrag = true; updateLineSB(x, y); } } final public void mouseReleased(MouseEvent me) { if (_fHSDrag) { double dHue = Math.atan2(_iRadius - _yHS, _xHS - _iRadius) / (2 * Math.PI); dHue -= Math.floor(dHue); if ((float)dHue != _fHue) { _fHue = (float)dHue; createImageSB(); repaint(_iWidth, 0, _iWidth, _iWidth); setupRGB(); } _fHSDrag = false; } else if (_fSBDrag) { _fSaturation = (float)(_xSB - _iWidth) / (_iWidth - 1); _fBrightness = (float)(_iWidth - 1 - _ySB) / (_iWidth - 1); _fSBDrag = false; setupRGB(); } } final public void mouseMoved(MouseEvent me) { } final public void mouseDragged(MouseEvent me) { int x = me.getX(), y = me.getY(); if (_fHSDrag) { updateLineHS(x, y); } else if (_fSBDrag) { updateLineSB(x, y); } } final public void componentResized(ComponentEvent ce) { Dimension dimension = getSize(); int iWidth; if (dimension.width > 0 && dimension.height > 0 && (iWidth = Math.min(dimension.width / 2, dimension.height)) != _iWidth) { _dimension = dimension; _iWidth = iWidth; _iRadius = (iWidth - 1) / 2; setupLines(); createImageHS(); createImageSB(); } } final public void componentMoved(ComponentEvent ce) { } final public void componentShown(ComponentEvent ce) { } final public void componentHidden(ComponentEvent ce) { } } final class PainterPalette extends Frame implements ActionListener { PainterHSB _palette = null; TextField _tfRed, _tfGreen, _tfBlue; Choice _choiceTool, _choiceWidth; int _rgb; final static String strApply = "Apply"; final static String astrShapes[] = { "line", "box", "fill box", "circle", "fill circle", "free hand", "spray" }; PainterPalette() { super("Painter - Palette"); setBackground(new Color(0xcc, 0xcc, 0xcc)); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints gbc = Painter.standardConstraints(); setLayout(gridbag); gbc.gridheight = 1; _palette = new PainterHSB(0); gridbag.setConstraints(_palette, gbc); add(_palette); gbc.gridwidth = 1; gbc.weighty = 0; Painter.createLabel(this, gridbag, gbc, "Red:"); _tfRed = Painter.createTextField(this, gridbag, gbc); Painter.createLabel(this, gridbag, gbc, "Green:"); _tfGreen = Painter.createTextField(this, gridbag, gbc); Painter.createLabel(this, gridbag, gbc, "Blue:"); _tfBlue = Painter.createTextField(this, gridbag, gbc); changeRGB(0); gbc.gridwidth = GridBagConstraints.REMAINDER; Painter.createButton(this, gridbag, gbc, strApply).addActionListener(this); gbc.gridwidth = 1; Painter.createLabel(this, gridbag, gbc, "Type:"); _choiceTool = new Choice(); for (int iIndex = 0; iIndex < astrShapes.length; iIndex++) { _choiceTool.addItem(astrShapes[iIndex]); } gbc.gridwidth = 3; gridbag.setConstraints(_choiceTool, gbc); add(_choiceTool); gbc.gridwidth = 1; Painter.createLabel(this, gridbag, gbc, "Width:"); _choiceWidth = new Choice(); for (int iWidth = 1; iWidth <= 10; iWidth++) { _choiceWidth.addItem(String.valueOf(iWidth)); } gbc.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(_choiceWidth, gbc); add(_choiceWidth); pack(); validate(); show(); _palette.repaint(); } public void actionPerformed(ActionEvent ae) { try { float afHSB[] = Color.RGBtoHSB(Integer.parseInt(_tfRed.getText()), Integer.parseInt(_tfGreen.getText()), Integer.parseInt(_tfBlue.getText()), null); _palette.setupHSB(afHSB[0], afHSB[1], afHSB[2]); } catch (Exception e) { changeRGB(_rgb); } } final public void changeRGB(int rgb) { _rgb = rgb; _tfRed.setText(String.valueOf((rgb >>> 16) & 255)); _tfGreen.setText(String.valueOf((rgb >>> 8) & 255)); _tfBlue.setText(String.valueOf(rgb & 255)); } final public PainterShape getShape() { switch (_choiceTool.getSelectedIndex()) { case 0: return new PainterLine(); case 1: return new PainterBox(false); case 2: return new PainterBox(true); case 3: return new PainterCircle(false); case 4: return new PainterCircle(true); case 5: return new PainterPolygon(); default: return new PainterSpray(getWidth()); } } final public Color getColor() { return new Color(_rgb | 0xff000000); } final public int getWidth() { return _choiceWidth.getSelectedIndex() + 1; } } abstract class PainterShape extends Object { int _xStart, _yStart, _xEnd, _yEnd; public void mouseMove(int x, int y, Component comp) { int xMin = Math.min(Math.min(_xStart, _xEnd), x), xMax = Math.max(Math.max(_xStart, _xEnd), x), yMin = Math.min(Math.min(_yStart, _yEnd), y), yMax = Math.max(Math.max(_yStart, _yEnd), y); _xEnd = x; _yEnd = y; comp.repaint(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1); } public boolean mouseUp(int x, int y, Component comp) { mouseMove(x, y, comp); return true; // end drawing } public void mouseDown(int x, int y, Component comp) { _xStart = x; _yStart = y; } public abstract void draw(Graphics g, int xOffset, int yOffset); public void draw(Graphics g) { draw(g, 0, 0); } } final class PainterLine extends PainterShape { final public void draw(Graphics g, int xOffset, int yOffset) { g.drawLine(_xStart + xOffset, _yStart + yOffset, _xEnd + xOffset, _yEnd + yOffset); } } class PainterBox extends PainterShape { boolean _fFill; PainterBox(boolean fFill) { _fFill = fFill; } final public void draw(Graphics g) { int xMin = Math.min(_xStart, _xEnd), cx = _xStart + _xEnd - xMin - xMin, yMin = Math.min(_yStart, _yEnd), cy = _yStart + _yEnd - yMin - yMin; g.drawRect(xMin, yMin, cx, cy); } final public void draw(Graphics g, int xOffset, int yOffset) { int xMin = Math.min(_xStart, _xEnd), cx = _xStart + _xEnd - xMin - xMin, yMin = Math.min(_yStart, _yEnd), cy = _yStart + _yEnd - yMin - yMin; if (_fFill) { g.fillRect(xMin + xOffset, yMin + yOffset, cx + 1, cy + 1); } else { g.drawRect(xMin + xOffset, yMin + yOffset, cx, cy); } } } class PainterCircle extends PainterShape { boolean _fFill; int _iRadius; PainterCircle(boolean fFill) { _fFill = fFill; } final public void mouseDown(int x, int y, Component comp) { super.mouseDown(x, y, comp); _iRadius = 0; } final static int hypot(int x, int y) { return (int)Math.sqrt(x * x + y * y); } final public void mouseMove(int x, int y, Component comp) { _xEnd = x; _yEnd = y; int iNewRadius = hypot(x - _xStart, y - _yStart); int iMaxRadius = Math.max(_iRadius, iNewRadius); _iRadius = iNewRadius; comp.repaint(_xStart - iMaxRadius, _yStart - iMaxRadius, iMaxRadius * 2 + 1, iMaxRadius * 2 + 1); } final public void draw(Graphics g) { int iRadius = _iRadius; g.drawOval(_xStart - iRadius, _yStart - iRadius, iRadius * 2, iRadius * 2); } final public void draw(Graphics g, int xOffset, int yOffset) { int x = _xStart + xOffset, y = _yStart + yOffset, iRadius = _iRadius; if (_fFill) { g.fillOval(x - iRadius, y - iRadius, iRadius * 2 + 1, iRadius * 2 + 1); } else { g.drawOval(x - iRadius, y - iRadius, iRadius * 2, iRadius * 2); } } } class PainterPolygon extends PainterShape { Polygon _polygon; public void mouseDown(int x, int y, Component comp) { (_polygon = new Polygon()).addPoint(x, y); } public void mouseMove(int x, int y, Component comp) { int iLastPoint = _polygon.npoints - 1; int xPrev = _polygon.xpoints[iLastPoint], yPrev = _polygon.ypoints[iLastPoint]; _polygon.addPoint(x, y); int xMin = Math.min(x, xPrev), cx = x + xPrev - xMin - xMin, yMin = Math.min(y, yPrev), cy = y + yPrev - yMin - yMin; comp.repaint(xMin, yMin, cx + 1, cy + 1); } public boolean mouseUp(int x, int y, Component comp) { Rectangle rectUpdate = _polygon.getBounds(); comp.repaint(rectUpdate.x, rectUpdate.y, rectUpdate.width + 1, rectUpdate.height + 1); return true; } public void draw(Graphics g) { g.drawPolyline(_polygon.xpoints, _polygon.ypoints, _polygon.npoints); } public void draw(Graphics g, int xOffset, int yOffset) { int npoints = _polygon.npoints; int ax[] = new int[npoints], ay[] = new int[npoints]; for (int iIndex = 0; iIndex < npoints; iIndex++) { ax[iIndex] = _polygon.xpoints[iIndex] + xOffset; ay[iIndex] = _polygon.ypoints[iIndex] + yOffset; } g.drawPolyline(ax, ay, npoints); } } final class PainterSpray extends PainterPolygon { int _iWidth; PainterSpray(int iWidth) { _iWidth = iWidth; } final public void mouseDown(int x, int y, Component comp) { super.mouseDown(x, y, comp); int iWidth = _iWidth; comp.repaint(x - iWidth / 2, y - iWidth / 2, iWidth, iWidth); } final public void mouseMove(int x, int y, Component comp) { int iLastPoint = _polygon.npoints - 1; int xPrev = _polygon.xpoints[iLastPoint], yPrev = _polygon.ypoints[iLastPoint]; _polygon.addPoint(x, y); int xMin = Math.min(x, xPrev), cx = x + xPrev - xMin - xMin, yMin = Math.min(y, yPrev), cy = y + yPrev - yMin - yMin; int iWidth = _iWidth; comp.repaint(xMin - iWidth / 2, yMin - iWidth / 2, cx + 1 + iWidth, cy + 1 + iWidth); } final public boolean mouseUp(int x, int y, Component comp) { Rectangle rectUpdate = _polygon.getBounds(); int iWidth = _iWidth; comp.repaint(rectUpdate.x - iWidth / 2, rectUpdate.y - iWidth / 2, rectUpdate.width + 1 + iWidth, rectUpdate.height + 1 + iWidth); return true; } final public void draw(Graphics g) { draw(g, 0, 0); } final public void draw(Graphics g, int xOffset, int yOffset) { int npoints = _polygon.npoints; int ax[] = _polygon.xpoints, ay[] = _polygon.ypoints; int iWidth = _iWidth, iHalfWidth = iWidth / 2; Rectangle rect = g.getClipBounds(); if (rect != null) { rect.grow(iHalfWidth + 1, iHalfWidth + 1); } for (int iIndex = 0; iIndex < npoints; iIndex++) { int x = ax[iIndex] + xOffset, y = ay[iIndex] + yOffset; if (rect == null || rect.contains(x, y)) { g.fillOval(x - iHalfWidth, y - iHalfWidth, iWidth + 1, iWidth + 1); } } } }