All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.juife.swing.Dial Maven / Gradle / Ivy

There is a newer version: 0.7
Show newest version
/*
 *   juife - Java User Interface Framework Extensions
 *
 *   Copyright (C) 2005-2011 Grigor Iliev 
 *
 *   This file is part of juife.
 *
 *   juife is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License version 2.1 as published by the Free Software Foundation.
 *
 *   juife 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
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with juife; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *   MA  02110-1301, USA
 */

package net.sf.juife.swing;

import javax.swing.BoundedRangeModel;
import javax.swing.DefaultBoundedRangeModel;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.UIManager;

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

import net.sf.juife.swing.plaf.DialUI;


/**
 * This class implements a dial knob, which is mainly used in audio applications.
 * @author Grigor Iliev
 */
public class Dial extends JComponent {
	static {
		// TODO: In future this must be done the right way
		UIManager.put("DialUI", "net.sf.juife.swing.plaf.basic.BasicDialUI");
	}
	
	private static final String uiClassID = "DialUI";
	
	/** Represents how the mouse dragging affects the dial's value. */
	public enum MouseHandlerMode {
		/**
		 * Indicates that the dial's value will be increased
		 * when dragging from left to right and will be decreased
		 * when dragging from right to left.
		 */
		LEFT_TO_RIGHT,
				
		/**
		 * Indicates that the dial's value will be increased
		 * when dragging from right to left and will be decreased
		 * when dragging from left to right.
		 */
		RIGHT_TO_LEFT,
		
		/**
		 * Indicates that the dial's value will be increased
		 * when dragging from down to up and will be decreased
		 * when dragging from up to down.
		 */
		DOWN_TO_UP,
		
		/**
		 * Indicates that the dial's value will be increased
		 * when dragging from up to down and will be decreased
		 * when dragging from down to up.
		 */
		UP_TO_DOWN,
		
		/**
		 * Indicates that both LEFT_TO_RIGHT and
		 * DOWN_TO_UP modes will be handled.
		 */
		LEFT_TO_RIGHT_AND_DOWN_TO_UP,
		
		/**
		 * Indicates that both LEFT_TO_RIGHT and
		 * UP_TO_DOWN modes will be handled.
		 */
		LEFT_TO_RIGHT_AND_UP_TO_DOWN,
		
		/**
		 * Indicates that both RIGHT_TO_LEFT and
		 * DOWN_TO_UP modes will be handled.
		 */
		RIGHT_TO_LEFT_AND_DOWN_TO_UP,
		
		/**
		 * Indicates that both RIGHT_TO_LEFT and
		 * UP_TO_DOWN modes will be handled.
		 */
		RIGHT_TO_LEFT_AND_UP_TO_DOWN,
		
		/**
		 * Indicates that, when dragging occurs, the dial's position will
		 * be set to the radial position of the mouse relative to dial's center.
		 */
		RADIAL
	}
	
	/**
	 * The data model that handles the numeric maximum value,
	 * minimum value, and current-position value for the dial.
	 */
	protected BoundedRangeModel dialModel;
	
	private final ChangeListener changeListener;
	private ImageIcon pixmap = null;
	private ImageIcon disabledPixmap = null;
	private ImageIcon rolloverPixmap = null;
	private ImageIcon pressedPixmap = null;
	private int minAngle = 45;
	private int maxAngle = 315;
	
	private MouseHandlerMode mouseHandlerMode = MouseHandlerMode.RADIAL;
	
	/**
	 * Creates a new instance of Dial with a range of 0 to 100
	 * and initial value of 50.
	 */
	public
	Dial() { this(0, 100); }
	
	/**
	 * Creates a new instance of Dial using the specified
	 * min and max with an initial value equal to
	 * the average of the min plus max.
	 * @param min Specifies the minimum value of the dial.
	 * @param max Specifies the maximum value of the dial.
	 * @throws IllegalArgumentException if min is greater then max.
	 */
	public
	Dial(int min, int max) { this(min, max, (min + max) / 2); }
	
	/**
	 * Creates a new instance of Dial using the specified
	 * min, max and value.
	 * @param min Specifies the minimum value of the dial.
	 * @param max Specifies the maximum value of the dial.
	 * @param value Specifies the current value of the dial.
	 * @throws IllegalArgumentException if the following constraints aren't satisfied:
	 * min <= value <= max
	 */
	public
	Dial(int min, int max, int value) {
		this(new DefaultBoundedRangeModel(value, 0, min, max));
	}
	
	/**
	 * Creates a new instance of Dial using the specified data model.
	 * @param model Specifies the data model to be used.
	 */
	public
	Dial(BoundedRangeModel model) { 
		changeListener = new ChangeListener() {
			public void
			stateChanged(ChangeEvent e) { fireStateChanged(); }
		};
		
		setModel(model);
		updateUI();
	}
	
	/**
	 * Gets a string that specifies the name
	 * of the L&F class that renders this component.
	 * @return the string "DialUI"
	 */
	public String
	getUIClassID() { return uiClassID; }
	
	/**
	 * Gets the L&F object that renders this component.
	 * @return The L&F object that renders this component.
	 */
	public DialUI
	getUI() { return (DialUI)ui; }
	
	/**
	 * Sets the L&F object that renders this component.
	 * @param ui The new UI delegate.
	 */
	public void
	setUI(DialUI ui) { super.setUI(ui); }
	
	/**
	 * Resets the UI property to a value from the current look and feel.
	 */
	public void
	updateUI() { setUI((DialUI)UIManager.getUI(this)); }
	
	/**
	 * Registers the specified listener to be notified about chages of the data model.
	 * @param listener The ChangeListener to register.
	 */
	public void
	addChangeListener(ChangeListener listener) {
		listenerList.add(ChangeListener.class, listener);
	}
	
	/**
	 * Removes the specified listener.
	 * @param listener The ChangeListener to remove.
	 */
	public void
	removeChangeListener(ChangeListener listener) {
		listenerList.remove(ChangeListener.class, listener);
	}
	/**
	 * Gets the data model that handles the dials' minimum, maximum and value properties.
	 * @return The data model that handles the dials' minimum, maximum and value properties.
	 */
	public BoundedRangeModel
	getModel() { return dialModel; }
	
	/**
	 * Sets the model that handles the dials' minimum, maximum and value properties.
	 * @param model The new non-null model to be set.
	 * @throws IllegalArgumentException if model is null.
	 * @see #getModel
	 */
	public void
	setModel(BoundedRangeModel model) {
		if(model == null) throw new IllegalArgumentException("model must be non-null");
		
		BoundedRangeModel oldModel = getModel();
		if(oldModel != null) oldModel.removeChangeListener(changeListener);
		
		dialModel = model;
		model.addChangeListener(changeListener);
		
		firePropertyChange("model", oldModel, dialModel);
	}
	
	
	/**
	 * Gets the pixmap used for drawing the dial knob.
	 * @return The pixmap used for drawing the dial knob.
	 */
	public ImageIcon
	getDialPixmap() { return pixmap; }
	
	/**
	 * Sets the pixmap to be used for drawing the dial knob
	 * with minimum angle of 45 and maximum angle of 315 degrees.
	 * If pixmap is null the builtin L&F is used.
	 * @param pixmap Specifies the pixmap to be used for drawing the dial knob.
	 * @see #getMinimumAngle
	 * @see #getMaximumAngle
	 */
	public void
	setDialPixmap(ImageIcon pixmap) { setDialPixmap(pixmap, 45, 315); }
	
	/**
	 * Sets the pixmap to be used for drawing the dial knob with the specified
	 * minimum and maximum angle.
	 * @throws IllegalArgumentException if the following constraints aren't satisfied:
	 * 0 <= minAngle <= maxAngle <= 360
	 * @see #getMinimumAngle
	 * @see #getMaximumAngle
	 */
	public void
	setDialPixmap(ImageIcon pixmap, int minAngle, int maxAngle) {
		if(pixmap == getDialPixmap()) return;
		this.pixmap = pixmap;
		
		if(minAngle < 0 || minAngle > maxAngle || maxAngle > 360)
			throw new IllegalArgumentException("Invalid angle range");
		
		this.minAngle = minAngle;
		this.maxAngle = maxAngle;
	}
	
	/**
	 * Gets the thumb angle (in degrees) of the minimum position of the dial knob.
	 * @return The thumb angle (in degrees) of the minimum position of the dial knob.
	 * @see #setDialPixmap(ImageIcon pixmap, int minAngle, int maxAngle)
	 */
	public int
	getMinimumAngle() { return minAngle; }
	
	/**
	 * Gets the thumb angle (in degrees) of the maximum position of the dial knob.
	 * @return The thumb angle (in degrees) of the maximum position of the dial knob.
	 * @see #setDialPixmap(ImageIcon pixmap, int minAngle, int maxAngle)
	 */
	public int
	getMaximumAngle() { return maxAngle; }
	
	/**
	 * Gets the pixmap used for drawing the dial knob when is disabled.
	 * If null, the pixmap returned by
	 * {@link #getDialPixmap()} is used for drawing the dial knob.
	 * @return The pixmap used for drawing the dial knob when is disabled.
	 */
	public ImageIcon
	getDisabledDialPixmap() { return disabledPixmap; }
	
	/**
	 * Sets the pixmap to be used for drawing the dial knob when is disabled.
	 * If pixmap is null the pixmap returned by
	 * {@link #getDialPixmap()} is used for drawing the dial knob.
	 * @param pixmap Specifies the pixmap to be used for drawing the dial knob when is disabled.
	 */
	public void
	setDisabledDialPixmap(ImageIcon pixmap) { disabledPixmap = pixmap; }
	
	/**
	 * Gets the pixmap used for drawing the dial knob
	 * when dragging is performed or the mouse is over the knob.
	 * If null, the pixmap returned by
	 * {@link #getDialPixmap()} is used for drawing the dial knob.
	 * @return The pixmap used for drawing the dial knob
	 * when dragging is performed or the mouse is over the knob.
	 */
	public ImageIcon
	getRolloverDialPixmap() { return rolloverPixmap; }
	
	/**
	 * Sets the pixmap to be used for drawing the dial knob
	 * when dragging is performed or the mouse is over the knob.
	 * If pixmap is null the pixmap returned by
	 * {@link #getDialPixmap()} is used for drawing the dial knob.
	 * @param pixmap The pixmap to be used for drawing the dial knob
	 * when dragging is performed or the mouse is over the knob.
	 */
	public void
	setRolloverDialPixmap(ImageIcon pixmap) { rolloverPixmap = pixmap; }
	
	/**
	 * Gets the pixmap used for drawing
	 * the dial knob when a mouse button is pressed.
	 * If null, the pixmap returned by
	 * {@link #getDialPixmap()} is used for drawing the dial knob.
	 * @return The pixmap used for drawing
	 * the dial knob when a mouse button is pressed.
	 */
	public ImageIcon
	getPressedDialPixmap() { return pressedPixmap; }
	
	/**
	 * Sets the pixmap to be used for drawing
	 * the dial knob when a mouse button is pressed.
	 * If pixmap is null the pixmap returned by
	 * {@link #getDialPixmap()} is used for drawing the dial knob.
	 * @param pixmap The pixmap to be used for drawing
	 * the dial knob when a mouse button is pressed.
	 */
	public void
	setPressedDialPixmap(ImageIcon pixmap) { pressedPixmap = pixmap; }
	
	/**
	 * Gets the model's maximum acceptable value.
	 * @return The model's maximum acceptable value.
	 */
	public int
	getMaximum() { return getModel().getMaximum(); }
	
	/**
	 * Sets the maximum allowed value of this Dial.
	 * @param max the new maximum value of this Dial.
	 */
	public void
	setMaximum(int max) { getModel().setMaximum(max); }
	
	/**
	 * Gets the model's minimum acceptable value.
	 * @return The model's minimum acceptable value.
	 */
	public int
	getMinimum() { return getModel().getMinimum(); }
	
	/**
	 * Sets the minimum allowed value of this Dial.
	 * @param min the new minimum value of this Dial.
	 */
	public void
	setMinimum(int min) { getModel().setMinimum(min); }
	
	/**
	 * Gets the current value of the Dial.
	 * @return The current value of the Dial.
	 * @see #setValue
	 */
	public int
	getValue() { return getModel().getValue(); }
	
	/**
	 * Sets the current value of the Dial.
	 * @param value Specifies the new value of the Dial.
	 * @see #getValue
	 */
	public void
	setValue(int value) { getModel().setValue(value); }
	
	/**
	 * Determines whether the dial knob is being dragged.
	 * @return true if the dial knob is
	 * being dragged, false otherwise.
	 */
	public boolean
	getValueIsAdjusting() { return getModel().getValueIsAdjusting(); }
	
	/**
	 * Sets whether the dial knob is being dragged.
	 * Dial look and feel implementations should set this property to true
	 * when drag begins, and to false when the drag ends.
	 * @param b true to specify that the dial knob is
	 * being dragged, false otherwise.
	 */
	public void
	setValueIsAdjusting(boolean b) { getModel().setValueIsAdjusting(b); }
	
	/**
	 * Gets the mouse handler mode, which determines
	 * how the mouse dragging affects the dial's value.
	 * @return The current mouse handler mode.
	 */
	public MouseHandlerMode
	getMouseHandlerMode() { return mouseHandlerMode; }
	
	/**
	 * Sets the mouse handler mode, which determines
	 * how the mouse dragging affects the dial's value.
	 * @param mouseHandlerMode The new mouse handler mode.
	 */
	public void
	setMouseHandlerMode(MouseHandlerMode mouseHandlerMode) {
		this.mouseHandlerMode = mouseHandlerMode;
	}
	
	/**
	 * Gets the value that the dial knob will have if
	 * dragging to point p is made in radial mode.
	 * @param p The point for which the respective dial's value should be obtained.
	 * @return The value that the dial knob will have if
	 * dragging to point p is made in radial mode.
	 * @throws IllegalArgumentException if p is null.
	 */
	public int
	getValueByPoint(java.awt.Point p) { return getUI().getValueByPoint(p); }
	
	private final ChangeEvent changeEvent = new ChangeEvent(this);
	
	/**
	 * Sends a ChangeEvent whose source is this Dial.
	 * This method method is called each time a ChangeEvent
	 * is received from the model.
	 */
	protected void
	fireStateChanged() {
		Object[] listeners = listenerList.getListenerList();
		
		for(int i = listeners.length - 2; i >= 0; i -= 2) {
			if(listeners[i] == ChangeListener.class) {
				((ChangeListener)listeners[i + 1]).stateChanged(changeEvent);
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy