controlp5/distribution/library/controlP5.js

1159 lines
41 KiB
JavaScript

(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
if(!C) {
var C = (function() {
var cp5;
// this is taken from processing.js
// -------------------------------------
var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
var setStyleValues = function ( curElement ) {
if ( document.defaultView && document.defaultView.getComputedStyle ) {
var style = document.defaultView.getComputedStyle(curElement, null);
stylePaddingLeft = parseInt( style['paddingLeft'], 10 ) || 0;
stylePaddingTop = parseInt( style['paddingTop'], 10 ) || 0;
styleBorderLeft = parseInt( style['borderLeftWidth'], 10 ) || 0;
styleBorderTop = parseInt( style['borderTopWidth'], 10 ) || 0;
}
}
function calculateOffset(curElement, event) {
var element = curElement , offsetX = 0 , offsetY = 0;
// Find element offset
if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while (!!(element = element.offsetParent));
}
// Find Scroll offset
element = curElement;
do {
offsetX -= element.scrollLeft || 0;
offsetY -= element.scrollTop || 0;
} while (!!(element = element.parentNode));
// Add padding and border style widths to offset
offsetX += stylePaddingLeft;
offsetY += stylePaddingTop;
offsetX += styleBorderLeft;
offsetY += styleBorderTop;
// Take into account any scrolling done
offsetX += window.pageXOffset;
offsetY += window.pageYOffset;
return {X:offsetX, Y:offsetY};
}
// -------------------------------------
var addEventListenerImpl = function( target, event, callback ) {
if ( 'addEventListener' in target ) {
target.addEventListener( event, callback );
} else {
var originalEvent = target["on"+event];
target["on"+event] = function ( evt ) {
var bubble = callback.apply( evt.target, [evt] );
if ( originalEvent ) originalEvent.apply( target, [evt] );
return bubble;
};
}
};
var opts;
var C = function() {
opts = arguments[ 0 ];
this.target = opts.target;
setStyleValues( this.target );
this.pointer = { x: 0 , y: 0 , px: 0 , py: 0 , dx: 0 , dy: 0 };
this.controllers = []; /* all controllers including groups */
this.root = new Root();
this.fontsize = 10;
this.papplet = opts.papplet;
this.font = this.papplet.createFont( "" , this.fontsize );
this.target.addEventListener('mousewheel',function(event){
event.preventDefault();
return false;
}, false);
if ( this.papplet && 'draw' in this.papplet ) {
var drawStored = this.papplet.draw;
this.papplet.draw = (function( ia , pa , ds ){
return function(){
ia.preDraw( pa );
ds.apply( pa );
ia.postDraw( pa );
};
})( this , this.papplet , drawStored );
}
var events = [
"mousemove", "mousedown", "mouseup", "click", "dblclick",
"mouseover", "mouseout", "mouseenter", "mouseleave", "mousewheel",
"DOMMouseScroll", "keydown" , "keyup", "keypress"
];
var eventDests = {
"mousemove": "mouseMoved",
"mousedown": "mousePressed",
"dblclick": "mouseDoubleClicked",
"mouseup": "mouseReleased",
"mousewheel": "mouseScrolled",
"DOMMouseScroll": "mouseScrolled",
"keypress": "keyPressed",
"keydown": "keyDown",
"keyup": "keyReleased"
};
for ( var e in events ) {
(function( control , target , event , m ){
addEventListenerImpl( target , event , function( evt ) {
var offset = calculateOffset( target, evt );
control.pointer.px = control.pointer.x ; control.pointer.py = control.pointer.y ;
control.pointer.x = evt.pageX - offset.X ; control.pointer.y = evt.pageY - offset.Y ;
control.pointer.dx = control.pointer.x - control.pointer.px ; control.pointer.dy = control.pointer.y - control.pointer.py ;
var collection = [ ];
traverse( collection , control.root.children , 0 , 0 , control.pointer.x , control.pointer.y );
/* TODO
* when mouse is dragged outside of a controller and passes through another controller, this controller gets activated.
* to avoid this behavior, only register the dragged controller when traversing and ignore all others.
*/
if(evt instanceof KeyboardEvent) {
/* key events */
for(c in control.controllers) {
if ( m in control.controllers[ c ] ) {
control.controllers[ c ][ m ]( evt );
}
}
} else if (evt instanceof MouseEvent){
/* mouse events */
//for(item in collection) {
if(collection.length > 0) {
var item = collection.pop();
var c = item.controller.name;
if ( m in control.controllers[ c ] ) {
var pointer = { type: m,
ax: control.pointer.x ,
ay: control.pointer.y ,
apx: control.pointer.px ,
apy: control.pointer.py ,
rx: item.x ,
ry: item.y ,
dx: control.pointer.dx ,
dy: control.pointer.dy
}
control.controllers[ c ][ m ]( pointer );
control.controllers[ c ]['callback'].map( function( item ) { if(m==item.ev) { item.fn( pointer )} } );
collection = [];
}
if (evt instanceof WheelEvent) { /* Chrome */
/* http://phrogz.net/JS/wheeldelta.html */
console.log( "mouseWheel event detected (1) : " + evt +" / "+ c );
}
}
//}
} else {
if (evt instanceof WheelEvent) { /* Safari */
/* http://phrogz.net/JS/wheeldelta.html */
if(collection.length > 0 ) {
var item = collection.pop();
var c = item.controller.name;
console.log( "mouseWheel event detected (2) : " + evt +" / "+c);
}
}
}
// else if (evt instanceof TouchEvent){
// /* tbd, does cause a breakpoint in Safari */
// }
});
})( this , this.target , events[ e ] , eventDests[ events[ e ] ] );
}
var inside = function( mx , my , x0 , y0 , x1 , y1 ) { return ( mx > x0 && mx < x1 && my > y0 && my < y1 ); }
var traverse = function( col , a , x0 , y0 , mx , my ) {
for(c in a) {
var x = x0 + a[ c ].x;
var y = y0 + a[ c ].y;
var b = ( !a[ c ].state.visible ) ? false : inside( mx , my , x , y + a[ c ].yoff , x + a[ c ].getWidth() , y + a[ c ].getHeight() );
b = ( a[ c ].state.active ) ? true : b;
if( b ) { col.push( { controller: a[ c ], x: mx - x, y: my - y } ) };
if(a[ c ].state.open ) { traverse( col , a[ c ].children , x , y , mx , my ); }
}
}
this.add = function( c ) {
this.controllers[ c.name ] = c ;
c.parent = this.root;
this.root.children.push( c );
return c;
}
this.remove = function( c ) {
c.parent.remove( c );
this.controllers.splice( this.controllers.indexOf( c ) , 1 );
return this;
}
this.draw = function ( papplet ) { }
this.preDraw = function ( papplet ) { }
this.postDraw = function ( papplet ) { papplet.textFont( this.font ); this.root.draw( papplet ); }
}
C.papplet = function ( ) { return cp5.papplet; }
C.font = function ( ) { return cp5.font; }
C.pointer = function ( c ) { return cp5.pointer; }
C.add = function ( c ) { return cp5.add( c ); }
C.get = function ( c ) { return cp5.controllers[ c ]; }
C.remove = function ( c ) { return cp5.remove( c ); }
C.test = function ( m , v ) { var target = opts.papplet; C.invoke( target , m , v ); }
C.event = function ( ev ) { var target = opts.papplet; var method = 'controlEvent'; C.invoke( target , method , ev ) ; }
C.make = function ( t ) { cp5 = new C({ target: t.externals.canvas, papplet: t }); }
C.invoke = function ( target , method , event ) {
if( ! ( target == undefined ) ) {
if ( ! ( target[method] == undefined ) ) {
if(event==undefined) {
target[method]( );
} else {
target[method](event);
}
}
}
}
return C;
})();
var CENTER = 3
var LEFT = 37
var RIGHT = 39
var TOP = 101
var BOTTOM = 102
var BASELINE = 0
var UP = 38
var DOWN = 40
var LEFT_OUTSIDE = 10
var RIGHT_OUTSIDE = 11
var TOP_OUTSIDE = 12
var BOTTOM_OUTSIDE = 13
var clip = function ( theValue , theMin , theMax ) { return theValue < theMin ? theMin : ( theValue > theMax ? theMax : theValue ); }
var norm = function ( theValue , theStart , theStop ) { return ( theValue - theStart ) / ( theStop - theStart ); }
var map = function ( theValue ,theStart0 , theStop0 , theStart1 , theStop1 ) { return theStart1 + ( theStop1 - theStart1 ) * ( ( theValue - theStart0 ) / ( theStop0 - theStart0 ) ); }
var constrain = function ( theValue , theStart0 , theStop0 , theStart1 , theStop1 ) { return clip( map( theValue , theStart0 , theStop0 , theStart1 , theStop1 ) , theStart1 , theStop1 ); }
var remove = function ( theArray , theItem ) { if( theArray.indexOf( theItem ) > -1 ) { theArray.splice(theArray.indexOf( theItem ) , 1 ); } }
var add = function ( theArray , theItem ) { theArray.push( theItem ); }
/* Root */
var Root = Class.extend({
children: [ ]
, x: 0
, y: 0
, draw: function ( p ) { p.pushStyle(); for ( var c in this.children ) { this.children[ c ].draw( p ); }; p.popStyle(); }
, remove: function ( elem ) { this.children.splice( this.children.indexOf( elem ) , 1 ); }
});
/* ControlListener */
var ControlListener = Class.extend({
controlEvent: function( l ) { }
});
/* ControlView */
var ControllerView = Class.extend({
display: function( p , c ) { }
});
/* Label */
var Label = Class.extend({
alignX: LEFT
, alignY: CENTER
, text: ""
, x: 0
, y: 0
, init: function( theIndex ) { this.margin = {top:0, right:0, bottom:0, left:0 } }
, align: function( x , y ) { this.alignX = x; this.alignY = y; return this; }
, set: function( s ) { this.setText( s ); return this; }
, setText: function( s ) { this.text = s; return this; }
, getText: function( s ) { return this.text; }
, setMargin: function( which , value ) { this.margin[which] = value; console.log(this.margin); return this; }
, draw: function( p , c ) {
var x = 0
var ax = this.alignX
switch(this.alignX) {
case(CENTER) : x = c.getWidth() / 2; break;
case(RIGHT_OUTSIDE) : ax = LEFT; x = c.getWidth() + this.margin.left; break;
case(RIGHT) : x = c.getWidth() - this.margin.right; break;
case(LEFT_OUTSIDE) : ax = RIGHT; x = - this.margin.right; break;
case(LEFT) : x = this.margin.left; break;
}
var y = 0;
var ay = this.alignY;
switch(this.alignY) {
case(CENTER) : y = c.getHeight() / 2; break;
case(BOTTOM_OUTSIDE) : ay = TOP; y = c.getHeight() + this.margin.bottom; break;
case(BOTTOM) : y = c.getHeight() - this.margin.bottom; break;
case(TOP_OUTSIDE) : ay = BOTTOM; y = this.margin.top; break;
case(TOP) : y = this.margin.top; break;
}
txtalign( p , this.getText() , x , y , ax , ay );
}
});
/* Controller */
var Controller = Class.extend({
init: function( theIndex ) {
this.view = new ControllerView();
this.event = { };
this.x = 0;
this.y = 0;
this.yoff = 0; /* necessary for groups, the group's bar is in the negative for the y position */
this.value = 0;
this.name = theIndex;
this.label = theIndex;
this.decimalPrecision = 1
this.valueLabel = new Label().set( theIndex )
this.captionLabel = new Label().set( theIndex )
this.state = { broadcast: true
, inside: false
, visible: true
, active: false
, pressed: false
, dragged: false
, open: true
}
this.color = { colorBackground: 0xff003652
, colorForeground: 0xff009bd7
, colorActive: 0xff00c5ff
, colorCaptionLabel: 0xffffffff
, colorValueLabel: 0xffffffff
}
this.event = { onLeave: function( c , pointer ) { }
, onEnter: function( c , pointer ) { }
, onMove: function( c , pointer ) { }
, onStartDrag: function( c , pointer ) { }
, onDrag: function( c , pointer ) { }
, onEndDrag: function( c , pointer ) { }
, onPress: function( c , pointer ) { }
, onRelease: function( c , pointer ) { }
, onReleaseOutside: function( c , pointer ) { }
, onWheel: function( c , pointer ) { }
}
this.callback = [ ];
this.listeners = [ ];
this.children = [ ];
this.parent = undefined;
this.id = -1;
this.setup( );
}
, draw: function( p ) {
if(this.state.visible) {
p.pushMatrix( );
p.pushStyle();
p.translate( this.x , this.y );
this.view.display( p , this );
if(this.state.open) {
for( var c in this.children ) { this.children[ c ].draw( p ); }
}
p.popStyle();
p.popMatrix( );
}
}
, broadcast: function ( ) {
if( this.state.broadcast ) {
var ev = new ControlEvent( this );
C.event( ev );
C.test( this.getName() , this.getValue() );
this.listeners.map( function( item ) { C.invoke( item , 'controlEvent' , ev ) } );
}
}
, addCallback: function ( c , ev , fn ) { this.callback.push( {'c':c , 'ev':ev , 'fn':fn } ); return this; }
, addListener: function( l ) { add( this.listeners , l ); return this; }
, removeListener: function( l ) { remove( this.listeners , l ); return this; }
, setup: function ( ) { }
, setPosition: function ( theX , theY ) { this.x = theX; this.y = theY; return this; }
, setSize: function ( theW , theH ) { this.setWidth( theW ); this.setHeight( theH ); return this; }
, setWidth: function ( theW ) { this.width = theW; return this; }
, setHeight: function ( theH ) { this.height = theH; return this; }
, setCaptionLabel: function ( theString ) { this.label = theString; return this; }
, inside: function ( theX0 , theY0 ) { return (theX0 >= 0 && theX0 <= ( this.getWidth( ) ) && theY0 >= 0 + this.yoff && theY0 <= ( this.getHeight( ) ) ) ; }
, setColorActive: function ( theCol ) { this.color.colorActive = theCol; return this; }
, setColorBackground: function ( theCol ) { this.color.colorBackground = theCol; return this;}
, setColorForeground: function ( theCol ) { this.color.colorForeground = theCol; return this; }
, setColorCaptionLabel: function ( theCol ) { this.color.colorCaptionLabel = theCol; return this; }
, setColorValueLabel: function ( theCol ) { this.color.colorValueLabel = theCol; return this; }
, getColor: function ( ) { return this.color; }
, getId: function ( ) { return this.id; }
, getName: function ( ) { return this.name; }
, getValue: function ( ) { return this.value; }
, getWidth: function ( ) { return this.width; }
, getHeight: function ( ) { return this.height; }
, getDecimalPrecision: function ( ) { return this.decimalPrecision; }
, getView: function ( ) { return this.view; }
, setValue: function ( val ) { this.value = val; return this; }
, setVisible: function ( b ) { this.state.visible = ( b == true ) ? true : false ; return this; }
, setDecimalPrecision: function ( i ) { this.decimalPrecision = i; }
, setId: function ( theId ) { this.id = theId; return this; }
, moveTo: function ( theParent ) { this.parent.remove( this ); this.parent = theParent; theParent.children.push( this ) ; return this; }
, remove: function ( theElement ) { this.children.splice(this.children.indexOf( theElement ), 1); }
, hide: function ( ) { this.state.visible = false; return this; }
, show: function ( ) { this.state.visible = true; return this; }
, setCaptionLabel: function ( theLabel ) { this.captionLabel.set( theLabel ); return this; }
, setBroadcast: function ( b ) { this.state.broadcast = (b === true) ? true : false; return this; }
, setView: function ( theView ) { this.view = theView; return this; }
, remove: function ( ) { C.remove( this ); }
, isVisible: function ( ) { return this.state.visible; }
, mousePressed: function ( pointer ) { this.event.onPress( this , pointer ); this.state.pressed = true ; }
, mouseReleased: function ( pointer ) { if( this.state.dragged ) { this.onEndDrag( pointer ) } else { this.event.onRelease( this , pointer ); }; if(!this.state.inside) { this.event.onReleaseOutside( this , pointer ); this.state.active = false; } this.state.dragged = false ; this.state.pressed = false ; }
, onDrag: function ( pointer ) { if( !this.state.dragged ) { this.onStartDrag( pointer ) }; this.event.onDrag( this , pointer ); this.state.dragged = true ; }
, onMove: function ( pointer ) { this.event.onMove( this , pointer ); }
, onStartDrag: function ( pointer ) { this.event.onStartDrag( this , pointer ); }
, onEndDrag: function ( pointer ) { this.event.onEndDrag( this , pointer ); }
, onEnter: function ( pointer ) { this.event.onEnter( this , pointer ); }
, onLeave: function ( pointer ) { this.event.onLeave( this , pointer ); }
, mouseMoved: function ( pointer ) {
this.state.inside = this.inside( pointer.rx , pointer.ry );
this.onMove( pointer );
if ( this.state.active && this.state.pressed ) {
this.onDrag( pointer );
} else {
if ( this.state.active != this.state.inside ) { if ( this.state.active ) { this.onLeave( pointer ); } else { this.onEnter( pointer ); } }
this.state.active = this.state.inside;
}
}
, setImage: function( ) { console.log("setImage is not implemented for this controller."); }
, setView: function ( theView ) { return this; }
});
/* Slider */
var Slider = Controller.extend({
normalized: 0
, min: 0
, max: 100
, setup: function( ) {
this.captionLabel.align( RIGHT_OUTSIDE , CENTER ).setMargin('left' , 4 );
this.valueLabel.align( LEFT , CENTER ).setMargin( 'left' , 4 );
this.view.display = function( p , c ) {
p.noStroke();
p.fill( c.color.colorBackground );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.noStroke();
p.fill( c.state.inside | c.state.dragged ? c.color.colorActive : c.color.colorForeground );
p.rect( 0 , 0 , c.getWidth( ) * c.normalized , c.getHeight( ) );
p.fill( c.color.colorValueLabel );
c.valueLabel.set( c.getValue().toFixed( c.getDecimalPrecision( ) ) );
c.valueLabel.draw( p , c );
p.fill( c.color.colorCaptionLabel );
c.captionLabel.draw( p , c );
}
this.event['onPress'] = function( c , pointer ) {
c.normalized = constrain( pointer.rx, 0 , c.getWidth( ) , 0 , 1 ) ;
c.state.active = true ;
c.broadcast( );
}
this.event['onDrag'] = function( c , pointer ) {
c.normalized = constrain( pointer.rx , 0 , c.getWidth( ) , 0 , 1 ) ;
c.broadcast( ) ;
}
}
, getValue: function ( ) { return map( this.normalized , 0 , 1 , this.min , this.max ) ; }
, setRange: function ( theMin , theMax ) { this.min = theMin ; this.max = theMax ; return this ; }
});
/* Button */
var Button = Controller.extend({
setup: function( ) {
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( c.state.inside | c.state.dragged ? ( c.state.pressed | c.state.dragged ? c.color.colorActive : c.color.colorForeground ) : c.color.colorBackground );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.fill( c.color.colorCaptionLabel );
txtalign( p , c.label.toUpperCase() , c.getWidth() / 2 , c.getHeight() / 2 , p.CENTER , p.CENTER );
}
this.event['onPress'] = function( c , pointer ) { c.broadcast( ); }
}
, setImage: function ( img ) {
this.setSize( img.width , img.height );
this.view['image'] = function( p , c ) { if( c.getWidth( )==0 ) { c.setSize( img0.width , img0.height ); } p.image(img, 0 , 0); }
this.seq = [ 'image' ];
}
, setImages: function ( img0, img1, img2 ) {
this.setSize( img0.width , img0.height );
this.view.display = function( p , c ) {
if( c.getWidth( )==0 ) { c.setSize( img0.width , img0.height ); }
if( c.state.active ) { if(c.state.pressed) { p.image( img2 , 0 , 0 ); } else { p.image( img1 , 0 , 0 ); } } else { p.image( img0 , 0 , 0 ); }
}
}
});
/* Toggle */
var Toggle = Button.extend({
setup: function( ) {
this.value = 0;
this.captionLabel.align( CENTER , CENTER );
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( ( c.getValue() == 0 ) ? c.state.inside ? c.color.colorForeground : c.color.colorBackground : c.color.colorActive );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.fill( c.color.colorCaptionLabel );
c.captionLabel.draw( p , c );
}
this.event['onPress'] = function( c , pointer ) {
c.setValue( (c.getValue() == 0) ? 1 : 0 ) ;
c.broadcast( );
}
}
});
/* Bang */
var Bang = Button.extend({
setup: function( ) {
this.value = undefined;
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( ( c.state.pressed ) ? c.color.colorActive : c.color.colorBackground );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.fill( c.color.colorCaptionLabel );
txtalign(p, c.label , c.getWidth() / 2 , c.getHeight() / 2 , p.CENTER , p.CENTER );
}
this.event['onPress'] = function( c , pointer ) {
c.broadcast( );
}
}
});
/* Numberbox */
var Numberbox = Controller.extend({
min: -100
, max: 100
, setup: function( ) {
this.value = 0;
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( c.color.colorBackground );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.fill( ( c.state.pressed ) ? c.color.colorActive : c.color.colorForeground );
var h = c.getHeight() / 2;
p.triangle( 0 , h - 6 , 6 , h , 0 , h + 6 );
p.fill( c.color.colorValueLabel );
c.valueLabel.set( c.getValue().toFixed( c.getDecimalPrecision( ) ) );
c.valueLabel.draw( p , c );
p.fill( c.color.colorCaptionLabel );
c.captionLabel.draw( p , c );
}
this.event['onPress'] = function( c , pointer ) {
c.broadcast( );
}
this.event['onDrag'] = function( c , pointer ) {
c.value += pointer.dy;
c.value = Math.min( c.max , Math.max( c.min , c.value ) );
c.broadcast( ) ;
}
}
, setRange: function ( theMin , theMax ) { this.min = theMin ; this.max = theMax ; return this ; }
});
/* Slider2D */
var Slider2D = Controller.extend({
cursorX: 0
, cursorY: 0
, cursorWidth: 10
, cursorHeight: 10
, isCrosshairs: true
, minX: 0
, minY: 0
, maxX: 100
, maxY: 100
, setup: function( ) {
this.value = 0;
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( c.color.colorBackground );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.noStroke( );
p.fill( c.state.dragged ? c.color.colorActive : c.color.colorForeground );
p.rect( c.cursorX , c.cursorY , c.cursorWidth , c.cursorHeight );
p.fill( c.color.colorValueLabel );
c.valueLabel.set( c.getValue()['x'].toFixed( c.getDecimalPrecision( ) ) );
c.valueLabel.draw( p , c );
p.fill( c.color.colorCaptionLabel );
c.captionLabel.draw( p , c );
}
this.event['onPress'] = function( c , pointer ) {
//this.event['onDrag']( c, pointer );
}
this.event['onDrag'] = function( c , pointer ) {
c.cursorX = Math.max( 0, Math.min( pointer.rx , c.getWidth() - c.cursorWidth ) );
c.cursorY = Math.max( 0, Math.min( pointer.ry , c.getHeight() - c.cursorHeight ) );
c.broadcast( ) ;
}
}
, getValue: function( ) {return { 'x' : map( this.cursorX , 0 , this.getWidth()-this.cursorWidth , this.minX , this.maxX ) , 'y' : map( this.cursorY , 0 , this.getHeight()-this.cursorHeight , this.minY , this.maxY) }; }
, setRange: function( theMinX , theMaxX , theMinY , theMaxY ) { this.minX = theMinX ; this.maxX = theMaxX ; this.minY = theMinY ; this.maxY = theMaxY ; return this ; }
, setMinX: function( theMinX ) { this.minX = theMinX; return this; }
, setMinY: function( theMinY ) { this.minY = theMinY; return this; }
, setMaxX: function( theMaxX ) { this.maxX = theMaxX; return this; }
, setMaxY: function( theMaxY ) { this.maxY = theMaxY; return this; }
, getMinX: function( ) { return this.minX; }
, getMinY: function( ) { return this.minY; }
, getMaxX: function( ) { return this.maxX; }
, getMaxY: function( ) { return this.maxY; }
, getCursorX: function( ) { return this.cursorX; }
, getCursorY: function( ) { return this.cursorY; }
, getCursorWidth: function( ) { return this.cursorWidth; }
, getCursorHeight: function( ) { return this.cursorHeight; }
, disableCrosshair: function( ) { this.isCrosshairs = false; return this; }
, enableCrosshair: function( ) { this.isCrosshairs = true; return this; }
});
var Knob = Controller.extend({
normalized: 0
, min: 0
, max: 100
, startAngle: Math.PI / 2 + Math.PI * 0.25
, angleRange: Math.PI + Math.PI / 2
, setup: function( ) {
this.view.display = function( p , c ) {
p.noStroke( );
p.ellipseMode(p.CENTER);
p.fill( c.color.colorBackground );
p.ellipse( c.getWidth( ) / 2 , c.getHeight( ) / 2 , c.getWidth( ) , c.getHeight( ) );
p.fill( ( c.state.pressed ) ? c.color.colorActive : c.color.colorForeground );
p.arc( c.getWidth( ) / 2 , c.getHeight( ) / 2 , c.getWidth( ) , c.getHeight( ) , c.startAngle , c.startAngle + c.angleRange * 0.01 );
p.arc( c.getWidth( ) / 2 , c.getHeight( ) / 2 , c.getWidth( ) , c.getHeight( ) , c.startAngle , c.startAngle + map( c.normalized , 0 , 1 , 0 , c.angleRange ) );
p.fill( c.color.colorBackground );
p.ellipse( c.getWidth( ) / 2 , c.getHeight( ) / 2 , c.getWidth( ) * 0.75 , c.getHeight( ) * 0.75 );
p.fill( c.color.colorCaptionLabel );
txtalign(p, c.getValue().toFixed( c.getDecimalPrecision( ) ) , c.getWidth() / 2 , c.getHeight() / 2 , p.CENTER , p.CENTER );
p.fill( c.color.colorValueLabel );
txtalign(p, c.label , c.getWidth() / 2 , c.getHeight() + 2 , p.CENTER , p.TOP );
}
this.event['onPress'] = function( c , pointer ) {
c.normalized = constrain( pointer.rx, 0 , c.getWidth( ) , 0 , 1 ) ;
c.state.active = true ;
c.broadcast( );
}
this.event['onDrag'] = function( c , pointer ) {
c.normalized = constrain( pointer.rx , 0 , c.getWidth( ) , 0 , 1 ) ;
c.broadcast( ) ;
}
}
, setRadius: function( theRadius ) { this.setSize( theRadius * 2 , theRadius * 2 ); return this; }
, getValue: function ( ) { return map( this.normalized , 0 , 1 , this.min , this.max ) ; }
, setRange: function ( theMin , theMax ) { this.min = theMin ; this.max = theMax ; return this ; }
});
/* Listbox */
var ListBox = Controller.extend( {
setup: function( ) {
this.state.open = true;
this.barHeight = 20;
this.items = [ ];
this.itemHeight = 30;
this.itemHover = -1;
this.itemIndex = 0;
this.itemRange = 6;
for(var i = 0 ; i<100;i++ ) {
this.items.push("item "+i);
}
var listboxitem = function ( p , c , i ) {
p.fill( c.color.colorBackground , (i==c.itemHover ? 255 : 120 ) );
p.rect( 0 , 0 , c.getWidth( ), c.itemHeight - 1 );
p.fill( c.color.colorCaptionLabel );
p.text( c.items[ i ] , 4 , 20 );
}
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( c.color.colorBackground );
p.rect( 0 , 0 , c.getWidth( ) , c.barHeight );
p.fill( c.color.colorForeground );
p.pushMatrix();
p.translate( c.getWidth( ) - 8 , c.barHeight / 2 -2 );
if( c.state.open ) { p.triangle( -3 , 0 , 3 , 0 , 0 , 3 ); } else { p.triangle( -3 , 3 , 3 , 3 , 0 , 0 ); }
p.popMatrix();
p.fill( 255 );
txt(p, c.label , 4 , 15 ); /* TODO */
if( c.state.open ) {
p.fill( c.color.colorBackground , 120 );
p.rect( 0 , c.barHeight , c.width , c.getHeight( ) - c.barHeight );
p.pushMatrix();
p.translate( 0 , c.barHeight + 1 );
for(var i = c.itemIndex; i < ( c.itemIndex + c.itemRange ) ; i++ ) {
listboxitem( p , c , i );
p.translate( 0 , c.itemHeight );
}
p.popMatrix( );
}
if(c.state.active && c.state.open) {
p.fill( c.color.colorForeground , 120 );
p.pushMatrix();
p.translate( c.width - 8 , c.barHeight + 4 );
var len = 20;
var pos = Math.floor( map( c.itemIndex, 0, c.items.length, 0, c.getHeight( ) - c.barHeight - len ) );
p.rect( 0 , pos , 4, len );
p.popMatrix();
}
}
this.event['onRelease'] = function( c , pointer ) {
var n = Math.floor( ( pointer.ry - c.barHeight ) / c.itemHeight );
if( n == -1 ) { c.state.open = !c.state.open; c.height = c.state.open ? c.barHeight + c.itemRange * c.itemHeight : c.barHeight; }
c.setValue( c.itemIndex + n );
c.broadcast( );
}
this.event['onDrag'] = function( c , pointer ) {
c.itemIndex += pointer.dy * 0.5;
c.itemIndex = Math.floor( Math.max( 0 , Math.min(c.itemIndex, c.items.length - c.itemRange ) ) );
c.itemHover = -1;
}
this.event['onLeave'] = function( c , pointer ) { c.itemHover = -1; }
this.event['onEnter'] = this.event['onMove'] = this.event['onEndDrag'] = function( c , pointer ) {
var n = Math.floor( ( pointer.ry - c.barHeight ) / c.itemHeight );
c.itemHover = c.itemIndex + n ;
}
}
, setHeight: function( h ) { this.height = this.barHeight + this.itemRange * this.itemHeight; }
});
/* Textfield */
var Textfield = Controller.extend({
strindex : 0
, setup: function( ) {
this.text = "";
this.strindex = 0;
this.captionLabel.align(LEFT , BOTTOM_OUTSIDE).setMargin('left' , 0 )
this.valueLabel.setMargin('left' , 4 ).setMargin('right' , 4 )
this.view.display = function( p , c ) {
p.noStroke( );
p.fill( c.state.active ? c.color.colorActive : c.color.colorForeground );
p.rect( 0 , 0 , c.getWidth( ) , c.getHeight( ) );
p.fill( c.color.colorBackground );
p.rect( 1 , 1 , c.getWidth( ) - 2 , c.getHeight( ) - 2 );
p.fill( c.color.colorCaptionLabel );
c.captionLabel.draw( p , c );
var t = c.text;
n = 0;
while(p.textWidth( t ) > ( c.getWidth() - ( c.valueLabel.margin.left + c.valueLabel.margin.right ) ) ) {
n++; t = t.substring(1, t.length);
}
c.valueLabel.set( t );
p.fill( c.color.colorValueLabel );
c.valueLabel.draw( p , c );
}
}
, keyPressed: function ( theKeyEvent ) {
if(this.state.active) {
switch(theKeyEvent.keyCode) {
case(13): this.broadcast(); this.text = ""; this.strindex = 0; break;
default: this.text += String.fromCharCode( theKeyEvent.charCode ); this.strindex++; break;
}
}
}
, keyDown: function ( theKeyEvent ) {
if(this.state.active) {
switch(theKeyEvent.keyCode) {
/* delete is not working in Safari */
case(8): this.text = this.text.slice(0, Math.max( 0 , this.strindex-1 ) ) + this.text.slice(this.strindex, this.text.len); this.strindex--; this.strindex = Math.max( 0 , this.strindex); break;
case(37): this.strindex--; this.strindex = Math.max( 0 , this.strindex ); break;
case(39): this.strindex++; this.strindex = Math.min( this.text.length , this.strindex ); break;
}
}
}
, mouseMoved: function ( pointer ) { }
, mousePressed: function ( pointer ) { this.state.active = true ; this.state.pressed = true; }
, mouseReleased: function ( pointer ) { this.color.colorForeground = 0xff009bd7 ; this.state.active = this.inside( pointer.rx , pointer.ry ) ? this.state.active : false ; this.state.pressed = false ; }
});
var CheckBox = Controller.extend({
spacingRow: 1
, spacingColumn: 1
, itemsPerRow: -1
, isMultipleChoice: false
, itemHeight: 9
, itemWidth: 9
, items: [ ]
, setup: function( ) {
this.addItem( "a" , "b" );
}
, sayHello: function( ) {
console.log("hello..");
}
, addItem: function( theName , theValue ) {
var target = this;
var t = C.add( new Toggle( this.name+"-"+theName ).setSize( this.itemWidth , this.itemHeight ).setPosition( 0 , 0 ) ).setCaptionLabel( theName );
t.captionLabel.align( RIGHT_OUTSIDE , CENTER ).margin.left = 4;
t.addCallback( t , 'mouseReleased' , function( ev ) { target.sayHello(); } );
t.moveTo( this );
return this;
}
});
var Group = Controller.extend({
setup: function( ) {
this.state.open = true;
this.barHeight = 20;
this.yoff = -this.barHeight;
this.captionLabel.align( LEFT , TOP ).setMargin('left' , 4 ).setMargin( 'top' , -this.barHeight + 4 );
this.view.display = function( p , c ) {
if( c.state.open ) {
p.fill(c.color.colorBackground , 100);
p.noStroke();
p.rect(0 , 0 , c.getWidth() , c.getHeight() );
}
p.noStroke( );
p.fill( c.color.colorBackground );
p.rect( 0 , -c.barHeight , c.getWidth() , c.barHeight );
p.fill( c.color.colorForeground );
p.pushMatrix();
p.translate( c.width - 8 , -c.barHeight / 2 -2 );
if( c.state.open ) { p.triangle( -3 , 0 , 3 , 0 , 0 , 3 ); } else { p.triangle( -3 , 3 , 3 , 3 , 0 , 0 ); }
p.popMatrix();
p.fill( this.colorCaptionLabel );
c.captionLabel.draw( p , c );
}
this.event['onRelease'] = function( c , pointer ) { c.state.open = pointer.ry >= 0 ^ !c.state.open; }
this.event['onDrag'] = function( c , pointer ) { c.x += pointer.dx; c.y += pointer.dy; }
}
, getHeight: function() { return (this.state.open ? this.height : 0 ); }
});
// DropdownList, ListBox
// Tab, Group
// Slider2D
// Textfield
// Range
// CheckBox, RadioButton
// Numberbox
// Callback
// ControllerPlug
// ControllerView
// Canvas
var ControlEvent = Class.extend({
c: undefined
, init: function ( c ) { this.c = c; }
, getValue: function ( ) { return this.c.getValue(); }
, getController: function ( ) { return this.c; }
, getGroup: function ( ) { return this.c; }
, getName: function ( ) { return this.c.getName( ); }
, getId: function ( ) { return this.c.getId( ); }
, isFrom: function ( cc ) { if(C.get( cc ) !== undefined ) { return C.get( cc ).getName( ) === this.c.getName( ); } return this.c === cc; }
});
var ControlP5 = Class.extend({
init: function ( t ) { C.make( t ); }
, addSlider: function ( theIndex ) { return C.add( new Slider( theIndex ).setPosition( 0 , 0 ).setSize( 100 , 15 ) ); }
, addButton: function ( theIndex ) { return C.add( new Button( theIndex ).setPosition( 0 , 0 ).setSize( 50 , 30 ) ); }
, addBang: function ( theIndex ) { return C.add( new Bang( theIndex ).setPosition( 0 , 0 ).setSize( 50 , 30 ) ); }
, addToggle: function ( theIndex ) { return C.add( new Toggle( theIndex ).setPosition( 0 , 0 ).setSize( 40 , 20 ) ); }
, addNumberbox: function ( theIndex ) { return C.add( new Numberbox( theIndex ).setPosition( 0 , 0 ).setSize( 100 , 20 ) ); }
, addRange: function ( theIndex ) { } /* TODO */
, addKnob: function ( theIndex ) { return C.add( new Knob( theIndex ).setPosition( 0 , 0 ).setSize( 40 , 40 ) ); }
, addSlider2D: function ( theIndex ) { return C.add( new Slider2D( theIndex ).setPosition( 0 , 0 ).setSize( 50 , 50 ) ); }
, addTextfield: function ( theIndex ) { return C.add( new Textfield( theIndex ).setPosition( 0 , 0 ).setSize( 200 , 20 ) ); }
, addRadioButton: function ( theIndex ) { } /* TODO */
, addCheckBox: function ( theIndex ) { return C.add( new CheckBox( theIndex ).setPosition( 0 , 0 ).setSize( 200 , 20 ) ); }
, addTab: function ( theIndex ) { } /* TODO */
, addGroup: function ( theIndex ) { return C.add( new Group( theIndex ).setPosition( 0 , 0 ).setSize( 200 , 200 ) ); }
, addDropdownList: function ( theIndex ) { } /* TODO */
, addListBox: function ( theIndex ) { return C.add( new ListBox( theIndex ).setPosition( 0 , 0 ).setSize( 200 , 185 ) ); }
, addCanvas: function ( theIndex ) { } /* TODO */
, get: function ( theIndex ) { return C.get( theIndex ); }
, getAll: function ( ) { return C.get( ).controllers; }
, getAll: function ( theType ) { /* returns a list of all registered controllers of type theType */ }
, getFont: function ( ) { return C.get( ).font; }
, getListener: function ( theIndex ) { } /* TODO */
, getValue: function ( theIndex ) {return C.get( theIndex ).getValue( ); }
, isAutoDraw: function ( ) { return true; }
, isMouseOver: function ( ) { return false; }
, isMouseOver: function ( theController ) { return false; }
, isMoveable: function ( ) { return true ;}
, isShortcuts: function ( ) { return false; }
, addCallback: function ( theListener ) { }
, addCanvas: function ( theCanvas ) { }
, remove: function ( theIndex ) { }
, removeCallback: function ( theController ) { }
, removeCanvas: function ( theCanvas ) { }
, removeListener: function ( theListener ) { }
, setBroadcast: function ( b ) { }
, setMoveable: function ( b ) { }
, setFont: function ( thePFont ) { C.get( ).font = thePFont; return this; }
, setFont: function ( thePFont , theFontsize ) { C.get( ).font = thePFont; C.get( ).fontsize = theFontsize; return this; }
, setColor: function ( theColor ) { return this; }
, setColorActive: function ( theColor ) { return this; }
, setColorBackground: function ( theColor ) { return this; }
, setColorCaptionLabel: function ( theColor ) { return this; }
, setColorForeground: function ( theColor ) { return this; }
, setColorValueLabel: function ( theColor ) { return this; }
, disableShortcuts: function ( ) { return this; }
, enableShortcuts: function ( ) { return this; }
, hide: function ( ) { return this; }
, show: function ( ) { return this; }
, setAutoDraw: function ( b ) { return this; }
});
var txtboxed = function( p , theText , theX , theY , theAlignX , theAlignY , theW , theH ) {
p.pushMatrix( );
p.translate( theX , theY );
p.textAlign( theAlignX , theAlignY );
p.text( theText , 0 , 0 , theW , theH );
p.popMatrix() ;
}
var txtalign = function( p , theText , theX , theY , theAlignX , theAlignY ) {
p.pushMatrix( );
p.translate( theX , theY );
p.textAlign( theAlignX , theAlignY );
p.text( theText , 0 , 0 );
p.popMatrix() ;
}
var txt = function( p , theText , theX , theY ) {
p.pushMatrix( );
p.translate( theX , theY );
p.text( theText , 0 , 0 );
p.popMatrix() ;
}
};
// function numDecimals(x) {
// x = x.toString();
// if (x.indexOf('.') > -1) {
// return x.length - x.indexOf('.') - 1;
// } else {
// return 0;
// }
// }
//, setSize: function ( theW, theH ) { this.buffer = C.papplet( ).createGraphics( theW - 8 , theH); return this._super(theW, theH); }
// c.buffer.beginDraw();
// c.buffer.background( c.colorBackground );
// c.buffer.smooth();
// c.buffer.textFont( C.font( ));
// var off = -p.max( 0 , p.textWidth( c.text ) - c.buffer.width );
// c.buffer.fill( 255 );
// c.buffer.text(c.text , off , c.height/2 + 5 );
// c.buffer.endDraw();
// p.image(c.buffer, 4 , 0 );