package org.roussev.hiena.gui;
/*
* Copyright 2009 Hiena Mp3 Player http://code.google.com/p/hiena-mp3-player/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Image;
import java.awt.Dimension;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.Rectangle;
import java.util.Vector;
import java.util.Enumeration;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.net.URL;
/**
* <pre>
* <b>AtaProgressSlider</b> is a custom progress Slider. Features:
* - showing the current progress
* - slider available with mouse, key and focus support.
* </pre>
*
* @author
*
*/
public final class XProgressSlider extends java.awt.Panel {
private Color progressColor = new Color(0xAEAEFF);
private boolean showProgress = true;
private Rectangle progressRectangle = new Rectangle(0, 2);
private int progressWidth = getMinProgressWidth() ;
private int DOT_WIDTH ;
private int DOT_HEIGHT ;
private int CANVAS_WIDTH ;
private int CANVAS_HEIGHT ;
private int eX, eY;
private int eXprevios;
private int dotX = getMinDotX(), dotY = progressRectangle.y;
private boolean mouseEnter = false;
private boolean mouseUp = true;
private boolean keyPressed = false;
private boolean draggable = false;
private boolean hasListeners = true;
private boolean focusable = true;
//----------
// Event Source Management
private final Vector actionListeners;
private String label;
//-----------
private Image imgOff;
private Image dot;
private Image dot_;
private Image bgSlider;
private Graphics gOff;
//-------------------------------------------------------
public XProgressSlider(String label, String[] url, boolean hasListeners) {
this.hasListeners = hasListeners;
this.label = label;
if(hasListeners)
initListeners();
// Initialize Event Source Management
actionListeners = new Vector();
if(url.length < 3) {
throw new ArrayIndexOutOfBoundsException(
"\n ------------------------------" +
"\n -- Error loading images. " +
"\n -- 3 images are needed for XProgressSlider." +
"\n -- Usage:" +
"\n -- \t String[] url = {" +
"\n -- \t\t \"/img_arrow.gif\"" +
"\n -- \t\t \"/img_arrow_OVER.gif\"" +
"\n -- \t\t \"/img_slider_BACKGROUND.gif\"" +
"\n -- \t }" +
"\n ------------------------------"
);
}
setImages( url[0], url[1], url[2]);
setSliderPercent(0);
}
//-------------------------------------------------------
public XProgressSlider(String label, String[] url, boolean hasListeners, Rectangle progressRectangle) {
this( label, url, hasListeners);
this.progressRectangle = progressRectangle;
final double medium = progressRectangle.y + (double)progressRectangle.height/2.0;
dotY = (int)(medium - (double)DOT_HEIGHT/2.0);
dotX = getMinDotX();
}
//-------------------------------------------------------
public XProgressSlider(String label, URL[] url, boolean hasListeners) {
this.hasListeners = hasListeners;
this.label = label;
if(hasListeners)
initListeners();
// Initialize Event Source Management
actionListeners = new Vector();
if(url.length < 3) {
throw new ArrayIndexOutOfBoundsException(
"\n ------------------------------" +
"\n -- Error loading images. " +
"\n -- 3 images are needed for XProgressSlider." +
"\n -- Usage:" +
"\n -- \t URL[] url = {" +
"\n -- \t\t url_img_arrow" +
"\n -- \t\t url_img_arrow_OVER" +
"\n -- \t\t url_img_slider_BACKGROUND" +
"\n -- \t }" +
"\n ------------------------------"
);
}
setImages( url[0], url[1], url[2]);
setSliderPercent(0);
}
//-------------------------------------------------------
public XProgressSlider(String label, URL[] url, boolean hasListeners, Rectangle progressRectangle) {
this( label, url, hasListeners);
this.progressRectangle = progressRectangle;
final double medium = progressRectangle.y + (double)progressRectangle.height/2.0;
dotY = (int)(medium - (double)DOT_HEIGHT/2.0);
dotX = getMinDotX();
}
//-----------------------------------------------
private final void setImages(URL urlDot, URL urlDot_, URL urlBg) {
final MediaTracker md = new MediaTracker(this);
final Toolkit toolkit = getToolkit();
dot = toolkit.createImage( urlDot );
dot_ = toolkit.createImage( urlDot_ );
bgSlider = toolkit.createImage( urlBg );
md.addImage(dot, 0);
md.addImage(dot_, 1);
md.addImage(bgSlider, 2);
try {
md.waitForAll();
if (md.isErrorAny()) { System.out.println("Error loading image "); }
} catch (Exception ex) { ex.printStackTrace(); }
CANVAS_WIDTH = bgSlider.getWidth(this);
CANVAS_HEIGHT = bgSlider.getHeight(this);
DOT_WIDTH = dot.getWidth(this);
DOT_HEIGHT = dot.getHeight(this);
setSize( getPreferredSize());
}
//-----------------------------------------------
private final void setImages(String urlDot, String urlDot_, String urlBg) {
setImages(
getClass().getResource(urlDot),
getClass().getResource(urlDot_),
getClass().getResource(urlBg)
);
}
//-------------------------------------------------------
private final void initListeners() {
this.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
doMouseEntered();
}
public void mouseExited(java.awt.event.MouseEvent evt) {
doMouseExited();
}
public void mousePressed(java.awt.event.MouseEvent evt) {
doMousePressed(evt);
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
doMouseReleased();
}
});
this.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(java.awt.event.MouseEvent evt) {
doMouseMoved(evt);
}
public void mouseDragged(java.awt.event.MouseEvent evt) {
doMouseDragged(evt);
}
});
this.addFocusListener( new java.awt.event.FocusAdapter(){
public void focusGained(java.awt.event.FocusEvent evt) {
doFocusGained();
}
public void focusLost(java.awt.event.FocusEvent evt) {
doFocusLost();
}
});
this.addKeyListener( new java.awt.event.KeyAdapter(){
public void keyPressed(java.awt.event.KeyEvent evt) {
doKeyPressed(evt);
}
public void keyReleased(java.awt.event.KeyEvent evt) {
doKeyReleased();
}
});
}
//-------------------------------------------------------
public final void updateSlider(){
if(mouseEnter){
update( getGraphics() );
}
}
//-------------------------------------------------------
public final void update(Graphics g) {
gOff = null;
imgOff = null;
// create the offscreen buffer and associated Graphics
imgOff = createImage( this.CANVAS_WIDTH, this.CANVAS_HEIGHT );
gOff = imgOff.getGraphics();
// clear the exposed area
gOff.setColor(getBackground());
gOff.fillRect(0,0, this.CANVAS_WIDTH, this.CANVAS_HEIGHT);
gOff.setColor(getForeground());
// do normal redraw
paint(gOff);
// transfer offscreen to window
g.drawImage(imgOff, 0, 0, this);
imgOff.flush();
}
//-------------------------------------------------------
public final void paint(Graphics g){
g.drawImage( bgSlider, 0, 0, this);
drawProgress(g);
drawDot(g);
// Focus Management
/*if (hasFocus && focusable) {
g.setColor(FOCUS_COLOR);
g.drawRect( 0, 0, CANVAS_WIDTH - 1, CANVAS_HEIGHT - 1 );
}*/
g.dispose();
}
//-------------------------------------------------------
private final void drawProgress(Graphics g ){
if(showProgress){
g.setColor( progressColor );
g.fillRect( progressRectangle.x, progressRectangle.y, progressWidth, progressRectangle.height );
}
}
//-------------------------------------------------------
private final void drawDot(Graphics g ){
if( insideDot(eX,eY) || draggable )
g.drawImage( dot_, dotX, dotY, this);
else
g.drawImage( dot, dotX, dotY, this);
if(!mouseEnter)
g.drawImage( dot, dotX, dotY, this);
if(keyPressed)
g.drawImage( dot_, dotX, dotY, this);
}
//-------------------------------------------------------
public final int getPercent(){
int dotCenter = dotX + (int)Math.round(DOT_WIDTH / 2);
int sliderSize = CANVAS_WIDTH - 2*progressRectangle.x;
int x = (int)Math.round( (dotCenter*100) / sliderSize );
x = ( dotX <= progressRectangle.x)? 0 : x;
x = ( dotX >= CANVAS_WIDTH - DOT_WIDTH - progressRectangle.x)? 100 : x;
return x;
}
//-------------------------------------------------------
private final int getMinDotX(){
return (progressRectangle.x - DOT_WIDTH/2);
}
private final int getMaxDotX(){
return (CANVAS_WIDTH - getMinDotX() - DOT_WIDTH);
}
//-------------------------------------------------------
private final int getMinProgressWidth(){
return (progressRectangle.x);
}
private final int getMaxProgressWidth(){
return (CANVAS_WIDTH - 2*progressRectangle.x);
}
//-------------------------------------------------------
public final void setSliderPercent(int percent){
dotX = getMinDotX() + (percent*(CANVAS_WIDTH - 2*progressRectangle.x))/100 ;
//if( dotX > getMaxDotX()) dotX = getMaxDotX();
//else if( dotX < getMinDotX()) dotX = getMinDotX();
repaint();
}
//-------------------------------------------------------
public final void setProgressPercent(int percent){//
progressWidth = (percent*(CANVAS_WIDTH - 2*progressRectangle.x ))/100;
if( progressWidth > getMaxProgressWidth())
progressWidth = getMaxProgressWidth();
repaint();
}
//-------------------------------------------------------
public final void setProgressColor(Color c) {
this.progressColor = c;
}
//-------------------------------------------------------
// Set the progress line to be visible
public final void setShowProgress( boolean showProgress) {
this.showProgress = showProgress;
}
//-------------------------------------------------------
final void doKeyPressed(java.awt.event.KeyEvent evt) {
keyPressed = true;
// Key Model Management
if (evt.getKeyCode() == KeyEvent.VK_RIGHT || evt.getKeyCode() == KeyEvent.VK_UP ) {
fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, label));
if( dotX < CANVAS_WIDTH - DOT_WIDTH - progressRectangle.x ){
eX ++;
dotX ++;
repaint();
}
}
else if (evt.getKeyCode() == KeyEvent.VK_LEFT || evt.getKeyCode() == KeyEvent.VK_DOWN ) {
fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, label));
if( dotX > progressRectangle.x ){
eX --;
dotX --;
repaint();
}
}
}
//-----------------------------------
final void doKeyReleased() {
keyPressed = false;
repaint();
}
//-------------------------------------------------------
final void doFocusGained() {
keyPressed = true;
repaint();
}
//-----------------------------------
final void doFocusLost() {
keyPressed = false;
repaint();
}
//-------------------------------------------------------
final void doMouseEntered() {
mouseEnter = true;
}
//-----------------------------------
final void doMouseExited() {
mouseEnter = false;
keyPressed = false;
repaint();
}
//-----------------------------------
final void doMouseReleased() {
mouseUp = true;
setDraggable( eX, eY );
}
//-----------------------------------
final void doMousePressed(java.awt.event.MouseEvent evt) {
mouseUp = false;
eX = evt.getX();
eY = evt.getY();
setDraggable( eX, eY );
if( insideDraggCanvas(eX) ){
dotX = eX - (int)Math.round(DOT_WIDTH/2);
//===if( dotX > CANVAS_WIDTH - DOT_WIDTH - progressRectangle.x)
//=== dotX = CANVAS_WIDTH - DOT_WIDTH - progressRectangle.x;
fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, label));
repaint();
}
}
//-----------------------------------
final void doMouseMoved(java.awt.event.MouseEvent evt) {
eX = evt.getX() ;
eY = evt.getY() ;
eXprevios = eX;
setDraggable( eX, eY );
repaint();
}
//-----------------------------------
final void doMouseDragged(java.awt.event.MouseEvent evt) {
eX = evt.getX();
eY = evt.getY();
int currentDotX = dotX + eX-eXprevios ;
if( currentDotX >= getMinDotX() && currentDotX <= getMaxDotX() ) {
dotX += eX-eXprevios ;
}
//else if ( currentDotX < progressRectangle.x ) {
// //===dotX = progressRectangle.x;
//}
//else {
// //===dotX = CANVAS_WIDTH - DOT_WIDTH - progressRectangle.x;
//}
eXprevios = eX;
fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, label));
repaint();
}
//-------------------------------------------------------
private final void setDraggable(int x, int y){
if( insideDot( x, y) && mouseEnter ){
draggable = true;
}
else {
draggable = false;
}
}
//-------------------------------------------------------
private final boolean insideDot(int x, int y){
return ( x >= dotX && x <= (dotX + DOT_WIDTH) &&
y > dotY && y <= (dotY + DOT_HEIGHT)
);
}
//-------------------------------------------------------
private final boolean insideDraggCanvas(int x){
return (
x >= progressRectangle.x && x <= CANVAS_WIDTH - progressRectangle.x
);
}
//-------------------------------------------------------
public final void addActionListener(ActionListener li) {
actionListeners.addElement(li);
}
//--------------------------------------
public final void removeActionListener(ActionListener li) {
actionListeners.removeElement(li);
}
//--------------------------------------
protected final void fireActionPerformed(ActionEvent ev) {
Enumeration en = actionListeners.elements();
while ( en.hasMoreElements() ) {
ActionListener li = (ActionListener)en.nextElement();
li.actionPerformed(ev);
}
}
//-------------------------------------------------------
public final void setLabel(String l) {
label = l;
repaint();
}
public final String getLabel() {
return label;
}
//--------------------------------------
public final boolean isFocusable() {
if(hasListeners) {
return focusable;
} else {
return false;
}
}
public final void setFocusable(boolean focusable) {
this.focusable = focusable;
super.setFocusable(focusable);
}
//-------------------------------------------------------
public final Dimension getPreferredSize() {
return getMinimumSize();
}
public final Dimension getMinimumSize() {
return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
}
public final Dimension getMaximumSize() {
return getMinimumSize();
}
//-------------------------------------------------------
}