/*
* Adapted DKnob.java by Joakim Eriksson
*/
// TODO -Combine with JModKnob.
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;
public class JModKnobGrafix extends JModParameterObject
{
private final static float START = 225;
private final static float LENGTH = 270;
private final static float PI = (float) Math.PI;
private final static float START_ANG = (START/360)*PI*2;
private final static float LENGTH_ANG = (LENGTH/360)*PI*2;
private final static float MULTIP = 180 / PI;
private final static Color DEFAULT_FOCUS_COLOR = new Color(0x8080ff);
private final static Color BOTTOM_COLOR = new Color(0xB0B0B0);
private final static Color MIDDLE_COLOR = new Color(0xD0D0D0);
private final static Color TOP_COLOR = new Color(0x707070);
private int SHADOWX = 1;
private int SHADOWY = 1;
private float DRAG_SPEED;
private float CLICK_SPEED;
private float DRAG_RES;
private int size;
private int middle;
public boolean indicator = false;
public boolean label = false;
public final static int HOR = 0;
public final static int VER = 1;
public final static int ROUND = 2;
public final static int DIA = 3;
private int dragType = DIA;
private final static Dimension MIN_SIZE = new Dimension(40, 40);
private final static Dimension PREF_SIZE = new Dimension(50, 50);
private final static RenderingHints AALIAS =
new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private Arc2D hitArc = new Arc2D.Float(Arc2D.PIE);
private float ang = (float) START_ANG;
private int dragpos = -1;
private float startVal = 0;
private Color focusColor = null;
private double lastAng = 0;
Font f = new Font("Dialog", Font.PLAIN, 10);
public JModKnobGrafix(int x, int y, int min_val, int max_val, Parameter newPar) {
super(min_val, max_val, newPar);
DRAG_SPEED = 1/getRange();
DRAG_RES = 1/getRange();
CLICK_SPEED = 1/getRange();
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 = getInternalValue();
// Fix last angle
int xpos = middle - me.getX();
int ypos = middle - me.getY();
lastAng = Math.atan2(xpos, ypos);
requestFocus();
}
public void mouseClicked(MouseEvent me) {
// TODO -Doesn't work well.
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 == HOR) {
float f = DRAG_SPEED * (float)(me.getX());
setInternalValue(startVal + f, true);
}
else
if (dragType == VER) {
float f = DRAG_SPEED * (float)(me.getY());
setInternalValue(startVal + f, true);
}
if (dragType == DIA) {
float f = DRAG_SPEED * (float)(me.getX() - me.getY());
setInternalValue(startVal + f, true);
}
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;
setInternalValue((float) (getValue() + (diff / LENGTH_ANG)), true);
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 == KeyEvent.VK_RIGHT)
incValue();
else if (k == KeyEvent.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;
}
private void incValue() {
setInternalValue(getInternalValue() + CLICK_SPEED, true);
}
private void decValue() {
setInternalValue(getInternalValue() - CLICK_SPEED, true);
}
public Dimension getMinimumSize() {
return MIN_SIZE;
}
public void calcMisc(boolean custom) {
// in this case we only want to calculate if there is going ot be repainted.
if (custom) ang = START_ANG - (float) LENGTH_ANG * getInternalValue();
}
public void updateKnob() {
repaint();
}
// Paint the DKnob
public void paint(Graphics g) {
calcMisc(true); // TODO ?It wil only calculate if it's in the paint method?
int x = 0;
int y = 0;
int width = getWidth();
int height = getHeight();
int offset = 2;
size = Math.min(width, height) - (offset*2);
middle = offset + 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);
// }
// // You use the modular to much
// g.setColor(BOTTOM_COLOR);
// g.fillOval(offset-2, offset-2, size+4, size+4);
// Outside circle
if (hasFocus())
if (indicator && isHalfway())
g.setColor(Color.GREEN);
else
g.setColor(focusColor);
else
if (indicator && isHalfway())
g.setColor(Color.GREEN.darker());
else
g.setColor(Color.gray);
g.drawArc(offset, offset, size, size, 315, 270);
// Circle top..?
g.setColor(BOTTOM_COLOR);
g.drawOval(offset+2, offset+2, size-6, size-6);
// Min / Max markers
g.setColor(Color.black);
x = offset + size/2 + (int)((6+size/3) * Math.cos(START_ANG));
y = offset + size/2 - (int)((6+size/3) * Math.sin(START_ANG));
g.drawLine(offset + size/2, offset + size/2, x, y);
x = offset + size/2 + (int)((6+size/3) * Math.cos(START_ANG - LENGTH_ANG));
y = offset + size/2 - (int)((6+size/3) * Math.sin(START_ANG - LENGTH_ANG));
g.drawLine(offset + size/2, offset + size/2, x, y);
// Top
g.setColor(MIDDLE_COLOR);
g.fillOval(offset+3, offset+3, size-6, size-6);
g.setColor(TOP_COLOR);
g.fillOval(offset+4, offset+4, size-8, size-8);
if (label && hasFocus()) {
drawCustomString(g);
}
// Inside needle
g.setColor(Color.white);
x = offset + size/2 + (int)(size/2 * Math.cos(ang));
y = offset + size/2 - (int)(size/2 * Math.sin(ang));
g.drawLine(offset + size/2, offset + size/2, x, y);
// Outside needle
g.setColor(Color.gray);
int dx = (int)(2 * Math.sin(ang));
int dy = (int)(2 * Math.cos(ang));
g.drawLine(offset + dx + size/2, offset + dy + size/2, x, y);
g.drawLine(offset-dx + size/2, offset-dy + size/2, x, y);
}
private void drawCustomString(Graphics g) {
g.setFont(f);
FontMetrics fontMetrics=getFontMetrics(g.getFont());
Rectangle2D r = fontMetrics.getStringBounds(String.valueOf(getValue()), g);
if (indicator && isHalfway())
g.setColor(Color.GREEN);
else
g.setColor(focusColor.brighter());
g.fillRect((int)((getWidth()/2)-r.getCenterX()) - 1, 0, (int)r.getWidth() + 2, 10);
if (indicator && isHalfway())
g.setColor(Color.GREEN.darker());
else
g.setColor(focusColor);
g.drawRect((int)((getWidth()/2)-r.getCenterX()) - 1, 0, (int)r.getWidth() + 2, 10);
g.setColor(Color.BLACK);
g.drawString(String.valueOf(getValue()), (int)((getWidth()/2)-r.getCenterX()) + 1, 9);
}
}
//public float getInternalValue() {
//return val;
//}
//
//public int getValue() {
//return (int)(val * MAX_VAL);
//}
//public void setInternalValue(float val, boolean fire) {
//if (val < 0) val = 0;
//if (val > 1) val = 1;
//this.val = val;
//ang = START_ANG - (float) LENGTH_ANG * val;
//repaint();
//fireChangeEvent();
//}
//public void setValue(float val) {
//setInternalValue(val / MAX_VAL, true);
//}
//public void setValueWithoutFireStarter(float val) {
//setInternalValue(val / MAX_VAL, false);
//}
//public void setMaxValue(float val) {
//MAX_VAL = val;
//}
//public void addChangeListener(ChangeListener cl) {
//listenerList.add(ChangeListener.class, cl);
//}
//
//public void removeChangeListener(ChangeListener cl) {
//listenerList.remove(ChangeListener.class, cl);
//}
//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);
// }
//}
//}