mirror of
https://github.com/sojamo/controlp5
synced 2024-11-26 23:54:56 +01:00
520 lines
16 KiB
Java
Executable File
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;
|
|
}
|
|
|
|
}
|