controlp5/src/controlP5/Range.java
2016-04-14 18:39:16 +08:00

520 lines
16 KiB
Java
Executable File

package controlP5;
/**
* controlP5 is a processing gui library.
*
* 2006-2015 by Andreas Schlegel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* This library 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 this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
* @author Andreas Schlegel (http://www.sojamo.de)
* @modified ##date##
* @version ##version##
*
*/
import java.util.ArrayList;
import java.util.logging.Level;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PGraphics;
import controlP5.ControlP5.Invisible;
/**
* A range slider works just like a slider but can be adjusted on both ends.
*
* @see Slider
* @example controllers/ControlP5range
* @nosuperclasses Controller Controller
*/
public class Range extends Controller< Range > {
/* TODO if range value is int, value labels do initialize as floats. first click makes them
* display as ints without decimal point */
protected static final int HORIZONTAL = 0;
protected static final int VERTICAL = 1;
protected int _myDirection;
protected float _myValuePosition;
protected boolean isDragging;
protected boolean isDraggable = true;
protected boolean isFirstClick;
protected Label _myHighValueLabel;
protected float _myValueRange;
protected boolean isMinHandle;
protected boolean isMaxHandle;
protected boolean isMoveHandle;
protected float distanceHandle;
protected int handleSize = 10;
protected int minHandle = 0;
protected int maxHandle = 0;
protected int mr = 0;
protected final ArrayList< TickMark > _myTickMarks = new ArrayList< TickMark >( );
protected boolean isShowTickMarks;
protected boolean isSnapToTickMarks;
public static int autoWidth = 99;
public static int autoHeight = 9;
public static float[] autoSpacing = new float[]{ 0 , 5 , 0 };
public int alignValueLabel = CENTER;
protected int _myColorTickMark = 0xffffffff;
private int mode = -1;
/**
* Convenience constructor to extend Range.
*
* @example use/ControlP5extendController
* @param theControlP5
* @param theName
*/
public Range( ControlP5 theControlP5 , String theName ) {
this( theControlP5 , theControlP5.getDefaultTab( ) , theName , 0 , 100 , 0 , 100 , 0 , 0 , 99 , 9 );
theControlP5.register( theControlP5.papplet , theName , this );
}
/**
*
* @param theControlP5 ControlP5
* @param theParent ControllerGroup
* @param theName String
* @param theMin float
* @param theMax float
* @param theDefaultValue float
* @param theX int
* @param theY int
* @param theWidth int
* @param theHeight int
*/
@ControlP5.Invisible public Range( ControlP5 theControlP5 , ControllerGroup< ? > theParent , String theName , float theMin , float theMax , float theDefaultMinValue , float theDefaultMaxValue , int theX , int theY , int theWidth , int theHeight ) {
super( theControlP5 , theParent , theName , theX , theY , theWidth , theHeight );
_myArrayValue = new float[] { theDefaultMinValue , theDefaultMaxValue };
_myMin = theMin;
_myMax = theMax;
_myValueRange = _myMax - _myMin;
minHandle = ( int ) PApplet.map( theDefaultMinValue , _myMin , _myMax , handleSize , getWidth( ) - handleSize );
maxHandle = ( int ) PApplet.map( theDefaultMaxValue , _myMin , _myMax , handleSize , getWidth( ) - handleSize );
mr = maxHandle - minHandle;
_myCaptionLabel = new Label( cp5 , theName ).setColor( color.getCaptionLabel( ) ).align( RIGHT_OUTSIDE , CENTER );
_myValueLabel = new Label( cp5 , "" + adjustValue( _myMin ) ).setColor( color.getValueLabel( ) ).set( "" + adjustValue( theDefaultMinValue ) ).align( LEFT , CENTER );
_myHighValueLabel = new Label( cp5 , adjustValue( _myMax ) ).setColor( color.getValueLabel( ) ).set( "" + adjustValue( theDefaultMaxValue ) ).align( RIGHT , CENTER );
_myValue = theDefaultMinValue;
_myDirection = HORIZONTAL;
update( );
}
@Override public Range setColorValueLabel( int theColor ) {
_myValueLabel.setColor( theColor );
_myHighValueLabel.setColor( theColor );
return this;
}
@Override public Range setColorCaptionLabel( int theColor ) {
_myCaptionLabel.setColor( theColor );
return this;
}
public Range setHighValueLabel( final String theLabel ) {
_myHighValueLabel.set( theLabel );
return this;
}
public Range setLowValueLabel( final String theLabel ) {
_myValueLabel.set( theLabel );
return this;
}
@ControlP5.Invisible public Range setSliderMode( int theMode ) {
return this;
}
public Range setHandleSize( int theSize ) {
handleSize = theSize;
setLowValue( _myArrayValue[ 0 ] , false );
setHighValue( _myArrayValue[ 1 ] , false );
mr = maxHandle - minHandle;
return this;
}
@ControlP5.Invisible public Range updateInternalEvents( PApplet theApplet ) {
if ( isVisible ) {
int c = _myControlWindow.mouseX - _myControlWindow.pmouseX;
if ( c == 0 ) {
return this;
}
if ( isMousePressed && !cp5.isAltDown( ) ) {
switch ( mode ) {
case ( LEFT ):
minHandle = PApplet.max( handleSize , PApplet.min( maxHandle , minHandle + c ) );
break;
case ( RIGHT ):
maxHandle = PApplet.max( minHandle , PApplet.min( getWidth( ) - handleSize , maxHandle + c ) );
break;
case ( CENTER ):
minHandle = PApplet.max( handleSize , PApplet.min( getWidth( ) - mr - handleSize , minHandle + c ) );
maxHandle = PApplet.max( minHandle , PApplet.min( getWidth( ) - handleSize , minHandle + mr ) );
break;
}
update( );
}
}
return this;
}
@Override @Invisible public void mousePressed( ) {
final float posX = x( _myParent.getAbsolutePosition( ) ) + x( position );
final float posY = y( _myParent.getAbsolutePosition( ) ) + y( position );
if ( _myControlWindow.mouseY < posY || _myControlWindow.mouseY > posY + getHeight( ) ) {
mode = -1;
isMinHandle = isMaxHandle = false;
return;
}
int x0 = ( int ) ( posX + minHandle );
int x1 = ( int ) ( posX + maxHandle );
if ( _myControlWindow.mouseX >= x0 - handleSize && _myControlWindow.mouseX < x0 ) {
mode = LEFT;
isMinHandle = true;
} else if ( _myControlWindow.mouseX >= x1 && _myControlWindow.mouseX < x1 + handleSize ) {
mode = RIGHT;
isMaxHandle = true;
} else if ( _myControlWindow.mouseX > x0 && _myControlWindow.mouseX < x1 && isDraggable ) {
mode = CENTER;
}
}
/**
* set the value of the range-slider. to set the low and high value, use setLowValue and
* setHighValue or setRangeValues
*
* @see #setLowValue(float)
* @see #setHighValue(float)
* @see #setRangeValues(float, float)
*
* @param theValue float
* @return Range
*/
@Override @ControlP5.Invisible public Range setValue( float theValue ) {
_myValue = theValue;
broadcast( ARRAY );
return this;
}
/**
* @exclude
*/
@Override @ControlP5.Invisible public Range update( ) {
_myArrayValue[ 0 ] = PApplet.map( minHandle , handleSize , getWidth( ) - handleSize , _myMin , _myMax );
_myArrayValue[ 1 ] = PApplet.map( maxHandle , handleSize , getWidth( ) - handleSize , _myMin , _myMax );
mr = maxHandle - minHandle;
_myHighValueLabel.set( adjustValue( _myArrayValue[ 1 ] ) );
_myValueLabel.set( adjustValue( _myArrayValue[ 0 ] ) );
return setValue( _myValue );
}
@ControlP5.Invisible public Range setDraggable( boolean theFlag ) {
isDraggable = theFlag;
isDragging = ( theFlag == false ) ? false : isDragging;
return this;
}
public float[] getArrayValue( ) {
return _myArrayValue;
}
@Override public Range setArrayValue( float[] theArray ) {
setLowValue( theArray[ 0 ] , false );
setHighValue( theArray[ 1 ] , false );
return update( );
}
@Override public Range setMin( float theValue ) {
_myMin = theValue;
_myValueRange = _myMax - _myMin;
return setLowValue( _myArrayValue[ 0 ] );
}
@Override public Range setMax( float theValue ) {
_myMax = theValue;
_myValueRange = _myMax - _myMin;
return setHighValue( _myArrayValue[ 1 ] );
}
public float getLowValue( ) {
return _myArrayValue[ 0 ];
}
public float getHighValue( ) {
return _myArrayValue[ 1 ];
}
@Override public Range setWidth( int theValue ) {
super.setWidth( theValue );
return this;
}
@Override public Range setHeight( int theValue ) {
super.setHeight( theValue );
return this;
}
@Override @ControlP5.Invisible public void mouseReleased( ) {
isDragging = isMinHandle = isMaxHandle = isMoveHandle = false;
mode = -1;
}
@Override @ControlP5.Invisible public void mouseReleasedOutside( ) {
mouseReleased( );
}
@Override @ControlP5.Invisible public void onLeave( ) {
isMinHandle = false;
isMaxHandle = false;
}
protected void setTickMarks( ) {
System.out.println( "Range Tickmarks not yet supported" );
}
public Range setColorTickMark( int theColor ) {
_myColorTickMark = theColor;
return this;
}
public Range showTickMarks( boolean theFlag ) {
isShowTickMarks = theFlag;
return this;
}
public Range snapToTickMarks( boolean theFlag ) {
isSnapToTickMarks = theFlag;
System.out.println( "Range Tickmarks not yet supported" );
return this;
}
@ControlP5.Invisible public TickMark getTickMark( ) {
System.out.println( "Range Tickmarks not yet supported" );
return null;
}
public ArrayList< TickMark > getTickMarks( ) {
return _myTickMarks;
}
public Range setNumberOfTickMarks( int theNumber ) {
System.out.println( "Range Tickmarks not yet supported" );
_myTickMarks.clear( );
if ( theNumber > 0 ) {
for ( int i = 0 ; i < theNumber ; i++ ) {
_myTickMarks.add( new TickMark( this ) );
}
showTickMarks( true );
snapToTickMarks( true );
} else {
showTickMarks( false );
snapToTickMarks( false );
}
_myUnit = ( _myMax - _myMin ) / ( ( getWidth( ) > getHeight( ) ) ? getWidth( ) - 1 : getHeight( ) - 1 );
setLowValue( _myArrayValue[ 0 ] , false );
setHighValue( _myArrayValue[ 1 ] , false );
return update( );
}
public Range setRange( float theMinValue , float theMaxValue ) {
setMin( theMinValue );
setMax( theMaxValue );
return this;
}
public Range setRangeValues( float theLowValue , float theHighValue ) {
return setArrayValue( new float[] { theLowValue , theHighValue } );
}
private Range setLowValue( float theValue , boolean isUpdate ) {
_myArrayValue[ 0 ] = PApplet.max( _myMin , snapValue( theValue ) );
minHandle = ( int ) PApplet.map( _myArrayValue[ 0 ] , _myMin , _myMax , handleSize , getWidth( ) - handleSize );
return ( isUpdate ) ? update( ) : this;
}
public Range setLowValue( float theValue ) {
return setLowValue( theValue , true );
}
private Range setHighValue( float theValue , boolean isUpdate ) {
_myArrayValue[ 1 ] = PApplet.min( _myMax , snapValue( theValue ) );
maxHandle = ( int ) PApplet.map( _myArrayValue[ 1 ] , _myMin , _myMax , handleSize , getWidth( ) - handleSize );
return ( isUpdate ) ? update( ) : this;
}
public Range setHighValue( float theValue ) {
return setHighValue( theValue , true );
}
protected float snapValue( float theValue ) {
if ( isMousePressed ) {
return theValue;
}
if ( isSnapToTickMarks ) {
_myValuePosition = ( ( theValue - _myMin ) / _myUnit );
float n = PApplet.round( PApplet.map( _myValuePosition , 0 , ( _myDirection == HORIZONTAL ) ? getWidth( ) : getHeight( ) , 0 , _myTickMarks.size( ) - 1 ) );
theValue = PApplet.map( n , 0 , _myTickMarks.size( ) - 1 , _myMin , _myMax );
}
return theValue;
}
@Override @ControlP5.Invisible public Range updateDisplayMode( int theMode ) {
_myDisplayMode = theMode;
switch ( theMode ) {
case ( DEFAULT ):
_myControllerView = new RangeView( );
break;
case ( SPRITE ):
_myControllerView = new RangeSpriteView( );
break;
case ( IMAGE ):
_myControllerView = new RangeImageView( );
break;
case ( CUSTOM ):
default:
break;
}
return this;
}
class RangeSpriteView implements ControllerView< Range > {
public void display( PGraphics theGraphics , Range theController ) {
ControlP5.logger( ).log( Level.INFO , "RangeSpriteDisplay not available." );
}
}
class RangeView implements ControllerView< Range > {
public void display( PGraphics theGraphics , Range theController ) {
int high = mode;
final float posX = x( _myParent.getAbsolutePosition( ) ) + x( position );
int x0 = ( int ) ( posX + minHandle );
int x1 = ( int ) ( posX + maxHandle );
if ( isInside( ) && high < 0 ) {
if ( _myControlWindow.mouseX >= x0 - handleSize && _myControlWindow.mouseX < x0 ) {
high = LEFT;
} else if ( _myControlWindow.mouseX >= x1 && _myControlWindow.mouseX < x1 + handleSize ) {
high = RIGHT;
} else if ( _myControlWindow.mouseX > x0 && _myControlWindow.mouseX < x1 && isDraggable ) {
high = CENTER;
}
}
theGraphics.pushMatrix( );
theGraphics.fill( color.getBackground( ) );
theGraphics.noStroke( );
theGraphics.rect( 0 , 0 , getWidth( ) , getHeight( ) );
theGraphics.fill( high == CENTER ? color.getActive( ) : color.getForeground( ) );
if ( isShowTickMarks ) {
int n = handleSize / 2;
theGraphics.rect( minHandle - n , 0 , mr + handleSize , getHeight( ) );
theGraphics.fill( ( isMinHandle || high == LEFT ) ? color.getActive( ) : color.getForeground( ) );
theGraphics.triangle( minHandle - handleSize , 0 , minHandle , 0 , minHandle - n , getHeight( ) );
theGraphics.fill( ( isMaxHandle || high == RIGHT ) ? color.getActive( ) : color.getForeground( ) );
theGraphics.triangle( maxHandle , 0 , maxHandle + handleSize , 0 , maxHandle + n , getHeight( ) );
} else {
theGraphics.rect( minHandle , 0 , mr , getHeight( ) );
theGraphics.fill( ( isMinHandle || high == LEFT ) ? color.getActive( ) : color.getForeground( ) );
theGraphics.rect( ( minHandle - handleSize ) , 0 , handleSize , getHeight( ) );
theGraphics.fill( ( isMaxHandle || high == RIGHT ) ? color.getActive( ) : color.getForeground( ) );
theGraphics.rect( maxHandle , 0 , handleSize , getHeight( ) );
}
if ( isLabelVisible ) {
_myCaptionLabel.draw( theGraphics , 0 , 0 , theController );
_myValueLabel.draw( theGraphics , 0 , 0 , theController );
_myHighValueLabel.draw( theGraphics , 0 , 0 , theController );
}
theGraphics.popMatrix( );
if ( isShowTickMarks ) {
theGraphics.pushMatrix( );
float x = ( getWidth( ) - handleSize ) / ( getTickMarks( ).size( ) - 1 );
theGraphics.translate( handleSize / 2 , getHeight( ) );
theGraphics.fill( _myColorTickMark );
for ( TickMark tm : getTickMarks( ) ) {
tm.draw( theGraphics );
theGraphics.translate( x , 0 );
}
theGraphics.popMatrix( );
}
}
}
class RangeImageView implements ControllerView< Range > {
public void display( PGraphics theGraphics , Range theController ) {
ControlP5.logger( ).log( Level.INFO , "RangeImageDisplay not implemented." );
}
}
@Override public Range setFont( PFont thePFont ) {
_myHighValueLabel.setFont( thePFont );
return super.setFont( thePFont );
}
@Override public Range setFont( ControlFont theFont ) {
_myHighValueLabel.setFont( theFont );
return super.setFont( theFont );
}
@Override @ControlP5.Invisible public String toString( ) {
return "type:\tRange\n" + super.toString( );
}
@Deprecated public float lowValue( ) {
return getLowValue( );
}
@Deprecated public float highValue( ) {
return getHighValue( );
}
@Deprecated public float[] arrayValue( ) {
return _myArrayValue;
}
}