mirror of
https://github.com/sojamo/controlp5
synced 2024-11-16 03:07:56 +01:00
484 lines
13 KiB
Java
484 lines
13 KiB
Java
package main.java.src2.main.java.controlP5.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 static main.java.src2.main.java.controlP5.controlP5.ControlP5.b;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import processing.core.PApplet;
|
|
import processing.core.PGraphics;
|
|
import processing.event.KeyEvent;
|
|
|
|
/**
|
|
* A ScrollableList is a list of vertically aligned items
|
|
* which can be scrolled if required.
|
|
*
|
|
* @example controllers/ControlP5scrollableList
|
|
*/
|
|
public class ScrollableList extends Controller< ScrollableList > implements ControlListener {
|
|
|
|
private int _myType = DROPDOWN;
|
|
protected int _myBackgroundColor = 0x00ffffff;
|
|
protected int itemHeight = 13;
|
|
protected int barHeight = 10;
|
|
private float scrollSensitivity = 1;
|
|
private boolean isOpen = true;
|
|
protected List< Map< String , Object > > items;
|
|
protected int itemRange = 5;
|
|
protected int itemHover = -1;
|
|
private int itemIndexOffset = 0;
|
|
private final int itemSpacing = 1;
|
|
private int _myDirection = PApplet.DOWN;
|
|
private boolean isBarVisible = true;
|
|
static public final int LIST = ControlP5.LIST;
|
|
static public final int DROPDOWN = ControlP5.DROPDOWN;
|
|
static public final int CHECKBOX = ControlP5.CHECKBOX; /* TODO */
|
|
static public final int TREE = ControlP5.TREE; /* TODO */
|
|
|
|
public ScrollableList( ControlP5 theControlP5 , String theName ) {
|
|
this( theControlP5 , theControlP5.getDefaultTab( ) , theName , 0 , 0 , 99 , 199 );
|
|
theControlP5.register( theControlP5.papplet , theName , this );
|
|
}
|
|
|
|
protected ScrollableList( ControlP5 theControlP5 , ControllerGroup< ? > theGroup , String theName , int theX , int theY , int theW , int theH ) {
|
|
super( theControlP5 , theGroup , theName , theX , theY , theW , theH );
|
|
items = new ArrayList< Map< String , Object > >( );
|
|
updateHeight( );
|
|
getValueLabel( ).align( PApplet.LEFT , PApplet.CENTER );
|
|
}
|
|
|
|
public boolean isOpen( ) {
|
|
return isOpen;
|
|
}
|
|
|
|
public ScrollableList open( ) {
|
|
return setOpen( true );
|
|
}
|
|
|
|
public ScrollableList close( ) {
|
|
return setOpen( false );
|
|
}
|
|
|
|
public ScrollableList setOpen( boolean b ) {
|
|
isOpen = b;
|
|
return this;
|
|
}
|
|
|
|
@Override public int getHeight( ) {
|
|
return isOpen ? super.getHeight( ) : barHeight;
|
|
}
|
|
|
|
public ScrollableList setType( int theType ) {
|
|
_myType = theType;
|
|
return this;
|
|
}
|
|
|
|
public void setDirection( int theDirection ) {
|
|
_myDirection = ( theDirection == PApplet.UP ) ? PApplet.UP : PApplet.DOWN;
|
|
}
|
|
|
|
@Override protected boolean inside( ) {
|
|
/* constrain the bounds of the controller to the
|
|
* dimensions of the cp5 area, required since
|
|
* PGraphics as render area has been introduced. */
|
|
float x0 = PApplet.max( 0 , x( position ) + x( _myParent.getAbsolutePosition( ) ) );
|
|
float x1 = PApplet.min( cp5.pgw , x( position ) + x( _myParent.getAbsolutePosition( ) ) + getWidth( ) );
|
|
float y0 = PApplet.max( 0 , y( position ) + y( _myParent.getAbsolutePosition( ) ) );
|
|
float y1 = PApplet.min( cp5.pgh , y( position ) + y( _myParent.getAbsolutePosition( ) ) + getHeight( ) );
|
|
if ( y1 < y0 ) {
|
|
float ty = y0;
|
|
y0 = y1;
|
|
y1 = ty;
|
|
}
|
|
return ( _myControlWindow.mouseX > x0 && _myControlWindow.mouseX < x1 && _myControlWindow.mouseY > ( y1 < y0 ? y1 : y0 ) && _myControlWindow.mouseY < ( y0 < y1 ? y1 : y0 ) );
|
|
}
|
|
|
|
@Override protected void onRelease( ) {
|
|
if ( !isDragged ) {
|
|
if ( getPointer( ).y( ) >= 0 && getPointer( ).y( ) <= barHeight ) {
|
|
setOpen( !isOpen( ) );
|
|
} else if ( isOpen ) {
|
|
|
|
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
|
|
|
|
// n += itemRange; /* UP */
|
|
int index = ( int ) n + itemIndexOffset;
|
|
updateIndex( index );
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateIndex( int theIndex ) {
|
|
if ( theIndex >= items.size( ) ) {
|
|
return;
|
|
}
|
|
|
|
Map m = items.get( theIndex );
|
|
|
|
switch ( _myType ) {
|
|
case ( LIST ):
|
|
super.setValue( theIndex );
|
|
for ( Object o : items ) {
|
|
( ( Map ) o ).put( "state" , false );
|
|
}
|
|
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
|
|
break;
|
|
case ( DROPDOWN ):
|
|
super.setValue( theIndex );
|
|
setOpen( false );
|
|
getCaptionLabel( ).setText( ( m.get( "text" ).toString( ) ) );
|
|
break;
|
|
case ( CHECKBOX ):
|
|
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
public ScrollableList setValue( float theValue ) {
|
|
updateIndex( ( int ) ( theValue ) );
|
|
return this;
|
|
}
|
|
|
|
@Override protected void onDrag( ) {
|
|
scroll( getPointer( ).dy( ) );
|
|
}
|
|
|
|
@Override protected void onScroll( int theValue ) {
|
|
scroll( theValue );
|
|
}
|
|
|
|
private void scroll( int theValue ) {
|
|
if ( isOpen ) {
|
|
itemIndexOffset += theValue;
|
|
itemIndexOffset = ( int ) ( Math.floor( Math.max( 0 , Math.min( itemIndexOffset , items.size( ) - itemRange ) ) ) );
|
|
itemHover = -2;
|
|
}
|
|
}
|
|
|
|
@Override protected void onLeave( ) {
|
|
itemHover = -1;
|
|
}
|
|
|
|
private void updateHover( ) {
|
|
if ( getPointer( ).y( ) > barHeight ) {
|
|
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
|
|
itemHover = ( int ) ( itemIndexOffset + n );
|
|
} else {
|
|
itemHover = -1;
|
|
}
|
|
}
|
|
|
|
@Override protected void onEnter( ) {
|
|
updateHover( );
|
|
}
|
|
|
|
@Override protected void onMove( ) {
|
|
updateHover( );
|
|
}
|
|
|
|
@Override protected void onEndDrag( ) {
|
|
updateHover( );
|
|
}
|
|
|
|
private int updateHeight( ) {
|
|
itemRange = ( PApplet.abs( getHeight( ) ) - ( isBarVisible( ) ? barHeight : 0 ) ) / itemHeight;
|
|
return itemHeight * ( items.size( ) < itemRange ? items.size( ) : itemRange );
|
|
}
|
|
|
|
public ScrollableList setItemHeight( int theHeight ) {
|
|
itemHeight = theHeight;
|
|
updateHeight( );
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList setBarHeight( int theHeight ) {
|
|
barHeight = theHeight;
|
|
updateHeight( );
|
|
return this;
|
|
}
|
|
|
|
public int getBarHeight( ) {
|
|
return barHeight;
|
|
}
|
|
|
|
public ScrollableList setScrollSensitivity( float theSensitivity ) {
|
|
scrollSensitivity = theSensitivity;
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList setBarVisible( boolean b ) {
|
|
isBarVisible = b;
|
|
updateHeight( );
|
|
return this;
|
|
}
|
|
|
|
public boolean isBarVisible( ) {
|
|
return isBarVisible;
|
|
}
|
|
|
|
private Map< String , Object > getDefaultItemMap( String theName , Object theValue ) {
|
|
Map< String , Object > item = new HashMap< String , Object >( );
|
|
item.put( "name" , theName );
|
|
item.put( "text" , theName );
|
|
item.put( "value" , theValue );
|
|
item.put( "color" , getColor( ) );
|
|
item.put( "view" , new CDrawable( ) {
|
|
@Override public void draw( PGraphics theGraphics ) {
|
|
}
|
|
|
|
} );
|
|
item.put( "state" , false );
|
|
return item;
|
|
}
|
|
|
|
public ScrollableList addItem( String theName , Object theValue ) {
|
|
Map< String , Object > item = getDefaultItemMap( theName , theValue );
|
|
items.add( item );
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList addItems( String[] theItems ) {
|
|
addItems( Arrays.asList( theItems ) );
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList addItems( List< String > theItems ) {
|
|
for ( int i = 0 ; i < theItems.size( ) ; i++ ) {
|
|
addItem(theItems.get( i ), i );
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList addItems( Map< String , Object > theItems ) {
|
|
for ( Map.Entry< String , Object > item : theItems.entrySet( ) ) {
|
|
addItem( item.getKey( ) , item.getValue( ) );
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList setItems( String[] theItems ) {
|
|
setItems( Arrays.asList( theItems ) );
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList setItems( List< String > theItems ) {
|
|
items.clear( );
|
|
return addItems( theItems );
|
|
}
|
|
|
|
public ScrollableList setItems( Map< String , Object > theItems ) {
|
|
items.clear( );
|
|
return addItems( theItems );
|
|
}
|
|
|
|
public ScrollableList removeItems( List< String > theItems ) {
|
|
for ( String s : theItems ) {
|
|
removeItem( s );
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public ScrollableList removeItem( String theName ) {
|
|
if ( theName != null ) {
|
|
|
|
List l = new ArrayList( );
|
|
for ( Map m : items ) {
|
|
if ( theName.equals( m.get( "name" ) ) ) {
|
|
l.add( m );
|
|
}
|
|
}
|
|
items.removeAll( l );
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public void updateItemIndexOffset( ) {
|
|
int m1 = items.size( ) > itemRange ? ( itemIndexOffset + itemRange ) : items.size( );
|
|
int n = ( m1 - items.size( ) );
|
|
if ( n >= 0 ) {
|
|
itemIndexOffset -= n;
|
|
}
|
|
}
|
|
|
|
public Map< String , Object > getItem( int theIndex ) {
|
|
return items.get( theIndex );
|
|
}
|
|
|
|
public Map< String , Object > getItem( String theName ) {
|
|
if ( theName != null ) {
|
|
for ( Map< String , Object > o : items ) {
|
|
if ( theName.equals( o.get( "name" ) ) ) {
|
|
return o;
|
|
}
|
|
}
|
|
}
|
|
return Collections.EMPTY_MAP;
|
|
}
|
|
|
|
public List getItems( ) {
|
|
return Collections.unmodifiableList( items );
|
|
}
|
|
|
|
public ScrollableList clear( ) {
|
|
for ( int i = items.size( ) - 1 ; i >= 0 ; i-- ) {
|
|
items.remove( i );
|
|
}
|
|
items.clear( );
|
|
itemIndexOffset = 0;
|
|
return this;
|
|
}
|
|
|
|
@Override public void controlEvent( ControlEvent theEvent ) {
|
|
// TODO Auto-generated method stub
|
|
}
|
|
|
|
public ScrollableList setBackgroundColor( int theColor ) {
|
|
_myBackgroundColor = theColor;
|
|
return this;
|
|
}
|
|
|
|
public int getBackgroundColor( ) {
|
|
return _myBackgroundColor;
|
|
}
|
|
|
|
@Override @ControlP5.Invisible public ScrollableList updateDisplayMode( int theMode ) {
|
|
_myDisplayMode = theMode;
|
|
switch ( theMode ) {
|
|
case ( DEFAULT ):
|
|
_myControllerView = new ScrollableListView( );
|
|
break;
|
|
case ( IMAGE ):
|
|
case ( SPRITE ):
|
|
case ( CUSTOM ):
|
|
default:
|
|
break;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
static public class ScrollableListView implements ControllerView< ScrollableList > {
|
|
|
|
public void display( PGraphics g , ScrollableList c ) {
|
|
|
|
// setHeight( -200 ); /* UP */
|
|
|
|
g.noStroke( );
|
|
|
|
if ( c.isBarVisible( ) ) {
|
|
boolean b = c.itemHover == -1 && c.isInside && !c.isDragged;
|
|
g.fill( b ? c.getColor( ).getForeground( ) : c.getColor( ).getBackground( ) );
|
|
g.rect( 0 , 0 , c.getWidth( ) , c.barHeight );
|
|
g.pushMatrix( );
|
|
g.translate( c.getWidth( ) - 8 , c.barHeight / 2 - 2 );
|
|
g.fill( c.getColor( ).getCaptionLabel( ) );
|
|
if ( c.isOpen( ) ) {
|
|
g.triangle( -3 , 0 , 3 , 0 , 0 , 3 );
|
|
} else {
|
|
g.triangle( -3 , 3 , 3 , 3 , 0 , 0 );
|
|
}
|
|
g.popMatrix( );
|
|
|
|
c.getCaptionLabel( ).draw( g , 4 , c.barHeight / 2 );
|
|
|
|
}
|
|
|
|
if ( c.isOpen( ) ) {
|
|
int bar = ( c.isBarVisible( ) ? c.barHeight : 0 );
|
|
int h = ( ( c.updateHeight( ) ) );
|
|
g.pushMatrix( );
|
|
// g.translate( 0 , - ( h + bar +
|
|
// c.itemSpacing ) ); /* UP */
|
|
g.fill( c.getBackgroundColor( ) );
|
|
g.rect( 0 , bar , c.getWidth( ) , h );
|
|
g.pushMatrix( );
|
|
g.translate( 0 , ( bar == 0 ? 0 : ( c.barHeight + c.itemSpacing ) ) );
|
|
/* draw visible items */
|
|
c.updateItemIndexOffset( );
|
|
int m0 = c.itemIndexOffset;
|
|
int m1 = c.items.size( ) > c.itemRange ? ( c.itemIndexOffset + c.itemRange ) : c.items.size( );
|
|
for ( int i = m0 ; i < m1 ; i++ ) {
|
|
Map< String , Object > item = c.items.get( i );
|
|
CColor color = ( CColor ) item.get( "color" );
|
|
g.fill( ( ControlP5.b( item.get( "state" ) ) ) ? color.getActive( ) : ( i == c.itemHover ) ? ( c.isMousePressed ? color.getActive( ) : color.getForeground( ) ) : color.getBackground( ) );
|
|
g.rect( 0 , 0 , c.getWidth( ) , c.itemHeight - 1 );
|
|
c.getValueLabel( ).set( item.get( "text" ).toString( ) ).draw( g , 4 , c.itemHeight / 2 );
|
|
g.translate( 0 , c.itemHeight );
|
|
}
|
|
g.popMatrix( );
|
|
|
|
if ( c.isInside ) {
|
|
int m = c.items.size( ) - c.itemRange;
|
|
if ( m > 0 ) {
|
|
g.fill( c.getColor( ).getCaptionLabel( ) );
|
|
g.pushMatrix( );
|
|
int s = 4; /* spacing */
|
|
int s2 = s / 2;
|
|
g.translate( c.getWidth( ) - s , c.barHeight );
|
|
int len = ( int ) PApplet.map( ( float ) Math.log( m * 10 ) , 0 , 10 , h , 0 );
|
|
int pos = ( int ) ( PApplet.map( c.itemIndexOffset , 0 , m , s2 , h - len - s2 ) );
|
|
g.rect( 0 , pos , s2 , len );
|
|
g.popMatrix( );
|
|
}
|
|
}
|
|
g.popMatrix( );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public void keyEvent( KeyEvent theKeyEvent ) {
|
|
if ( isInside && theKeyEvent.getAction( ) == KeyEvent.PRESS ) {
|
|
switch ( theKeyEvent.getKeyCode( ) ) {
|
|
case (UP):
|
|
scroll( theKeyEvent.isAltDown( ) ? -itemIndexOffset : theKeyEvent.isShiftDown( ) ? -10 : -1 );
|
|
updateHover( );
|
|
break;
|
|
case (DOWN):
|
|
scroll( theKeyEvent.isAltDown( ) ? items.size( ) - itemRange : theKeyEvent.isShiftDown( ) ? 10 : 1 );
|
|
updateHover( );
|
|
break;
|
|
case (LEFT):
|
|
break;
|
|
case (RIGHT):
|
|
break;
|
|
case (ENTER):
|
|
onRelease( );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* TODO keycontrol: arrows, return dragging moving items
|
|
* sorting custom view custom event types */
|
|
}
|