/* * DKnob.java * (c) 2000 by Joakim Eriksson * * DKnob is a component similar to JSlider but with * round "user interface", a knob. */ package com.dreamfabric; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*; import javax.swing.event.*; public class DKnob extends JComponent { private final static float START = 225; private final static float LENGTH = 270; private final static float PI = (float) 3.1415; private final static float START_ANG = (START/360)*PI*2; private final static float LENGTH_ANG = (LENGTH/360)*PI*2; private final static float DRAG_RES = (float) 0.01; private final static float MULTIP = 180 / PI; private final static Color DEFAULT_FOCUS_COLOR = new Color(0x8080ff); private int SHADOWX = 1; private int SHADOWY = 1; private float DRAG_SPEED; private float CLICK_SPEED; private int size; private int middle; public final static int SIMPLE = 1; public final static int ROUND = 2; private int dragType = ROUND; private final static Dimension MIN_SIZE = new Dimension(40, 40); private final static Dimension PREF_SIZE = new Dimension(80, 80); // Set the antialiasing to get the right look! private final static RenderingHints AALIAS = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); private ChangeEvent changeEvent = null; private EventListenerList listenerList = new EventListenerList(); private Arc2D hitArc = new Arc2D.Float(Arc2D.PIE); private float ang = (float) START_ANG; private float val; private int dragpos = -1; private float startVal; private Color focusColor; private double lastAng; public DKnob() { DRAG_SPEED = 0.01F; CLICK_SPEED = 0.01F; SHADOWX = 1; SHADOWY = 1; focusColor = DEFAULT_FOCUS_COLOR; setPreferredSize(PREF_SIZE); hitArc.setAngleStart(235); // Degrees ??? Radians??? addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent me) { dragpos = me.getX() + me.getY(); startVal = val; // Fix last angle int xpos = middle - me.getX(); int ypos = middle - me.getY(); lastAng = Math.atan2(xpos, ypos); requestFocus(); } public void mouseClicked(MouseEvent me) { hitArc.setAngleExtent(-(LENGTH + 20)); if (hitArc.contains(me.getX(), me.getY())) { hitArc.setAngleExtent(MULTIP * (ang-START_ANG)-10); if (hitArc.contains(me.getX(), me.getY())) { decValue(); } else incValue(); } } }); // Let the user control the knob with the mouse addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent me) { if ( dragType == SIMPLE) { float f = DRAG_SPEED * (float) ((me.getX() + me.getY()) - dragpos); setValue(startVal + f); } else if ( dragType == ROUND) { // Measure relative the middle of the button! int xpos = middle - me.getX(); int ypos = middle - me.getY(); double ang = Math.atan2(xpos, ypos); double diff = lastAng - ang; setValue((float) (getValue() + (diff / LENGTH_ANG))); lastAng = ang; } } public void mouseMoved(MouseEvent me) { } }); // Let the user control the knob with the keyboard addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e) {} public void keyPressed(KeyEvent e) { int k = e.getKeyCode(); if (k == e.VK_RIGHT) incValue(); else if (k == e.VK_LEFT) decValue(); } }); // Handle focus so that the knob gets the correct focus highlighting. addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { repaint(); } public void focusLost(FocusEvent e) { repaint(); } }); } public void setDragType(int type) { dragType = type; } public int getDragType() { return dragType; } public boolean isManagingFocus() { return true; } public boolean isFocusTraversable() { return true; } private void incValue() { setValue(val + CLICK_SPEED); } private void decValue() { setValue(val - CLICK_SPEED); } public float getValue() { return val; } public void setValue(float val) { if (val < 0) val = 0; if (val > 1) val = 1; this.val = val; ang = START_ANG - (float) LENGTH_ANG * val; repaint(); fireChangeEvent(); } public void addChangeListener(ChangeListener cl) { listenerList.add(ChangeListener.class, cl); } public void removeChangeListener(ChangeListener cl) { listenerList.remove(ChangeListener.class, cl); } public Dimension getMinimumSize() { return MIN_SIZE; } protected void fireChangeEvent() { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) changeEvent = new ChangeEvent(this); ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); } } } // Paint the DKnob public void paint(Graphics g) { int width = getWidth(); int height = getHeight(); size = Math.min(width, height) - 22; middle = 10 + size/2; if (g instanceof Graphics2D) { Graphics2D g2d = (Graphics2D) g; g2d.setBackground(getParent().getBackground()); g2d.addRenderingHints(AALIAS); // For the size of the "mouse click" area hitArc.setFrame(4, 4, size+12, size+12); } // Paint the "markers" for (float a2 = START_ANG; a2 >= START_ANG - LENGTH_ANG; a2=a2 -(float) (LENGTH_ANG/10.01)) { int x = 10 + size/2 + (int)((6+size/2) * Math.cos(a2)); int y = 10 + size/2 - (int)((6+size/2) * Math.sin(a2)); g.drawLine(10 + size/2, 10 + size/2, x, y); } // Set the position of the Zero g.drawString("0", 2, size + 10); // Paint focus if in focus if (hasFocus()) { g.setColor(focusColor); } else { g.setColor(Color.white); } g.fillOval(10, 10, size, size); g.setColor(Color.gray); g.fillOval(14 + SHADOWX, 14 + SHADOWY, size-8, size-8); g.setColor(Color.black); g.drawArc(10, 10, size, size, 315, 270); g.fillOval(14, 14, size-8, size-8); g.setColor(Color.white); int x = 10 + size/2 + (int)(size/2 * Math.cos(ang)); int y = 10 + size/2 - (int)(size/2 * Math.sin(ang)); g.drawLine(10 + size/2, 10 + size/2, x, y); g.setColor(Color.gray); int s2 = (int) Math.max(size / 6, 6); g.drawOval(10 + s2, 10 + s2, size - s2*2, size - s2*2); int dx = (int)(2 * Math.sin(ang)); int dy = (int)(2 * Math.cos(ang)); g.drawLine(10 + dx + size/2, 10 + dy + size/2, x, y); g.drawLine(10-dx + size/2, 10-dy + size/2, x, y); } }