Package com.dreamfabric

Source Code of com.dreamfabric.DKnob

/* For License see bottom */
/*
* 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.Color;
import java.awt.Dimension;
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.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import jonkoshare.util.VersionInformation;

/**
* Round Slider interface.
* Basic source code derived from Joakim Eriksson. Improved by
* Alexander Methke (font size adjustment, tick adjustment,
* rendering of boolean properties like enabled/disabled or
* resizing)
* <a href="http://www.dreamfabric.com/java/knob/knob.html">
* http://www.dreamfabric.com/java/knob/knob.html
* </a>
*
* @author Joakim Eriksson
* @author Alexander Methke
*/
@VersionInformation (
  lastChanged="$LastChangedDate: 2009-07-25 04:59:33 -0500 (Sat, 25 Jul 2009) $",
  authors={"Joakim Eriksson", "Alexander Methke"},
  revision="$LastChangedRevision: 11 $",
  lastEditor="$LastChangedBy: onkobu $",
  id="$Id"
)
public class DKnob extends JComponent {
  /**
   * Default starting angle.
   */
    private final static double DEFAULT_START = 225;
  /**
   * Default length in degree.
   */
    private final static double DEFAULT_LENGTH = 270;
  /**
   * Angle in radians.
   */
    private final static double DEFAULT_START_ANGLE = (DEFAULT_START/360)*Math.PI*2;
  /**
   * Length in radians.
   */
    private final static double DEFAULT_LENGTH_ANGLE = (DEFAULT_LENGTH/360)*Math.PI*2;
  /**
   * Multiplier for radian conversion.
   */
    private final static double MULTIP = 180 / Math.PI;
  /**
   * Focus color.
   */
    private final static Color DEFAULT_FOCUS_COLOR = new Color(0x8080ff);
  /**
   * Drag increment.
   */
  private final static double DEFAULT_DRAG_INCREMENT=0.01;
  /**
   * Click increment.
   */
  private final static double DEFAULT_CLICK_INCREMENT=0.01;
  /**
   * Default minimum value.
   */
  private final static int DEFAULT_MIN_VALUE=0;
  /**
   * Default maximum value.
   */
  private final static int DEFAULT_MAX_VALUE=100;
  /**
   * Default starting value.
   */
  private final static int DEFAULT_INT_VALUE=50;

    private int SHADOWX = 1;
    private int SHADOWY = 1;
    private double dragIncrement;
    private double clickIncrement;
    private int size;
    private int middle;

  /**
   * Describes possible DragTypes.
   */
    public enum DragType {
    /**
     * Simple Drag-Pattern with mainly
     * vertical movement.
     */
    SIMPLE,
    /**
     * Round Drag-Pattern where user
     * needs to go round in circles.
     * This is the default value.
     */
    ROUND
  }

    private DragType dragType = DragType.ROUND;


    private final static Dimension DEFAULT_MIN_SIZE = new Dimension(40, 40);
    private final static Dimension DEFAULT_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 ArrayList<ChangeListener> listenerList = new ArrayList<ChangeListener>();

    private Arc2D hitArc = new Arc2D.Float(Arc2D.PIE);

    private double angle = (double) DEFAULT_START_ANGLE;
    private double value;
    private int dragpos = -1;
    private double startVal;
    private Color focusColor;
    private double lastAng;

    public DKnob() {
    setMinimumSize(DEFAULT_MIN_SIZE);
    setPreferredSize(DEFAULT_PREF_SIZE);
    setMinimumValue(DEFAULT_MIN_VALUE);
    setMaximumValue(DEFAULT_MAX_VALUE);
    setIntValue(DEFAULT_INT_VALUE);

    dragIncrement=DEFAULT_DRAG_INCREMENT;
    clickIncrement=DEFAULT_CLICK_INCREMENT;
    SHADOWX = 1;
    SHADOWY = 1;

    focusColor = DEFAULT_FOCUS_COLOR;

    hitArc.setAngleStart(235); // Degrees ??? Radians???
    addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent me) {
        if (!isEnabled()) {
          return;
        }
        dragpos = me.getX() + me.getY();
        startVal = value;

        // Fix last angle
        int xpos = middle - me.getX();
        int ypos = middle - me.getY();
        lastAng = Math.atan2(xpos, ypos);

        requestFocus();
      }

      @Override
      public void mouseClicked(MouseEvent me) {
        if (!isEnabled()) {
          return;
        }
        hitArc.setAngleExtent(-(DEFAULT_LENGTH + 20));
        if  (hitArc.contains(me.getX(), me.getY())) {
        hitArc.setAngleExtent(MULTIP * (angle-DEFAULT_START_ANGLE)-10);
        if  (hitArc.contains(me.getX(), me.getY())) {
          decValue();
        } else incValue();
        }
      }
    });

    // Let the user control the knob with the mouse
    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseDragged(MouseEvent me) {
        if (!isEnabled()) {
          return;
        }
        if ( dragType == DragType.SIMPLE) {
          double f = dragIncrement * (double)
          ((me.getX() + me.getY()) - dragpos);
          setValue(startVal + f);
          fireChangeEvent();
        } else if ( dragType == DragType.ROUND) {
          // Measure relative the middle of the button!
          int xpos = middle - me.getX();
          int ypos = middle - me.getY();
          double angle = Math.atan2(xpos, ypos);
          double diff = lastAng - angle;
          setValue((double) (getValue() + (diff / DEFAULT_LENGTH_ANGLE)));
          lastAng = angle;
          fireChangeEvent();
        }
      }

      @Override
      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) {
        if (!isEnabled()) {
          return;
        }
        int k = e.getKeyCode();
        if (k == KeyEvent.VK_RIGHT) {
          incValue();
          fireChangeEvent();
        } else if (k == KeyEvent.VK_LEFT) {
          decValue();
          fireChangeEvent();
        }
      }
    });

    // Handle focus so that the knob gets the correct focus highlighting.
    addFocusListener(new FocusListener() {
      public void focusGained(FocusEvent e) {
        if (!isEnabled()) {
          return;
        }
        repaint();
      }
      public void focusLost(FocusEvent e) {
        if (!isEnabled()) {
          return;
        }
        repaint();
      }
    });
    }

  /**
   * Sets the component's drag type.
   *
   * @param type
   */
    public void setDragType(DragType type) {
    dragType = type;
    }
 
  /**
   * Returns component's drag type.
   *
   * @return
   */
    public DragType getDragType() {
    return dragType;
    }

  /**
   * Increments by one tick.
   *
   * @see #getClickIncrement
   */
    public void incValue() {
    setValue(value + clickIncrement);
    }

  /**
   * Decrements by one tick.
   *
   * @see #getClickIncrement
   */
    public void decValue() {
    setValue(value - clickIncrement);
    }

  /**
   * Returns set value. Values are
   * between 0 and 1.
   *
   * @return
   */
    public double getValue() {
    return value;
    }

  /**
   * Sets value. Beware, this causes
   * a change event. Values must be
   * between 0 and 1. Greater values
   * will be set to 1, smaller values
   * to 0.
   *
   * @param value
   */
    public void setValue(double value) {
    if (value < 0) {
      value = 0;
    }
    if (value > 1) {
      value = 1;
    }
    this.value = value;
    angle = DEFAULT_START_ANGLE - (double) DEFAULT_LENGTH_ANGLE * value;
    repaint();
    fireChangeEvent();
    }

  /**
   * Returns value as rounded int.
   *
   * @return
   */
    public int getIntValue() {
    return (int)(Math.round(getValue()*maximumValue))+minimumValue;
  }

  /**
   * Sets value as int.
   *
   * @param val
   */
  public void setIntValue(int val) {
    if (val<minimumValue ||
      val>maximumValue) {
      throw new IllegalArgumentException("value must be between "+minimumValue+" and "+maximumValue+" therefore "+val+" is invalid");
    }
    if (val<=minimumValue) {
      setValue(0);
    } else if (val>=maximumValue) {
      setValue(1.0);
    } else {
      setValue((double)val/(double)maximumValue);
    }
  }

  /**
   * Adds a {@link ChangeListener} to notify it
   * of changes to value. Multiple registration
   * is not possible.
   *
   * @param cl
   */
    public void addChangeListener(ChangeListener cl) {
    if (listenerList.contains(cl)) {
      return;
    }
    listenerList.add(cl);
    }

  /**
   * Removes given Listener.
   *
   * @param cl
   */
    public void removeChangeListener(ChangeListener cl) {
    listenerList.remove(cl);
    }

  /**
   * Call this method if you need to notify
   * about changes.
   *
   */
    protected void fireChangeEvent() {
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (ChangeListener cl:listenerList) {
      // Lazily create the event:
      if (changeEvent == null) {
        changeEvent = new ChangeEvent(this);
      }
      cl.stateChanged(changeEvent);
    }
    }

  /**
   * Determines if markes (ticks 'round
   * circle) will be painted.
   *
   * @param f
   */
  public void setPaintMarkers(boolean f) {
    paintMarkers=f;
  }

  /**
   * Checks if markers should be painted.
   *
   * @return
   */
  public boolean isPaintMarkers() {
    return paintMarkers;
  }

    // Paint the DKnob
  @Override
    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);
    }

    int msCorr=0;
    if (size<20) {
      g.setFont(g.getFont().deriveFont(8.0F));
      msCorr=2;
    } else if (size<30) {
      g.setFont(g.getFont().deriveFont(9.0F));
      msCorr=1;
    }

    // Paint the "markers"
    if (isPaintMarkers()) {
      int ms=(size>>1);
      for (double a2 = DEFAULT_START_ANGLE;
         a2 >= DEFAULT_START_ANGLE - DEFAULT_LENGTH_ANGLE;
         a2=a2 -(double) (DEFAULT_LENGTH_ANGLE/10.01))  {
        int x = 10 + ms + (int)((6+ms-msCorr) * Math.cos(a2));
        int y = 10 + ms - (int)((6+ms-msCorr) * Math.sin(a2));
        g.drawLine(10 + ms, 10 + ms, x, y);

      }
    }

    // Set the position of the Zero
    g.drawString("0", 1, size + 10+msCorr);

    // 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);

    if (isEnabled()) {
      g.setColor(getCenterColor());
    } else {
      g.setColor(Color.gray);
    }
    g.drawArc(10, 10, size, size, 315, 270);
    g.fillOval(14, 14, size-8, size-8);

    if (isEnabled()) {
      g.setColor(Color.white);
    } else {
      g.setColor(Color.lightGray);
    }

    int x = 10 + size/2 + (int)(size/2 * Math.cos(angle));
    int y = 10 + size/2 - (int)(size/2 * Math.sin(angle));
    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(angle));
    int dy = (int)(2 * Math.cos(angle));
    g.drawLine(10 + dx + size/2, 10 + dy + size/2, x, y);
    g.drawLine(10-dx + size/2, 10-dy + size/2, x, y);
    }

  /**
   * Sets Minimum value. This is the value
   * in leftmost position.
   *
   * @param val
   */
  public void setMinimumValue(int val) {
    minimumValue=val;
  }

  /**
   * Sets Maximum value. This is the value
   * in rightmost position.
   *
   * @param val
   */
  public void setMaximumValue(int val) {
    maximumValue=val;
  }

  /**
   * Returns minimum value.
   *
   * @see #setMinimumValue
   * @return
   */
  public int getMinimumValue() {
    return minimumValue;
  }

  /**
   * Returns maximum value.
   *
   * @see #setMaximumValue
   * @return
   */
  public int getMaximumValue() {
    return maximumValue;
  }

  /**
   * Getter for property centerColor.
   * @return Value of property centerColor.
   */
  public Color getCenterColor() {
    return this.centerColor==null?getForeground():this.centerColor;
  }

  /**
   * Setter for property centerColor.
   * @param centerColor New value of property centerColor.
   */
  public void setCenterColor(Color centerColor) {
    this.centerColor = centerColor;
  }

  private int minimumValue;
  private int maximumValue;

  private boolean paintMarkers;

  /**
   * Holds value of property centerColor.
   */
  private Color centerColor;
}
/*
    Copyright (C) 2008  Alexander Methke

    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 3 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.

    You should have received a copy of the GNU General Public License
    along with this program (gplv3.txt).
*/
TOP

Related Classes of com.dreamfabric.DKnob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.