/**
* Copyright ShutheSL ( http://wonderfl.net/user/ShutheSL )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/lbrm
*/
// forked from aobyrne's forked from: forked from: SiON 88 Key Keyboard
// forked from tkinjo's SiON 88 Key Keyboard
package
{
import com.bit101.components.HBox;
import com.bit101.components.HUISlider;
import com.bit101.components.PushButton;
import flash.display.*;
import flash.events.*;
import flash.media.Sound;
import org.si.sion.SiONDriver;
import org.si.sion.SiONVoice;
import org.si.sion.utils.SiONPresetVoice;
[SWF(frameRate="60")]
/**
* ...
* @author tkinjo
*/
public class SionPiano extends Sprite
{
static public const STATE_STILL:String = "stateStill";
static public const STATE_MOVING:String = "stateMoving";
private var driver:SiONDriver = new SiONDriver();
private var presetVoice:SiONPresetVoice = new SiONPresetVoice();
private var voice:SiONVoice;
private var keyboard:MusicalKeyboard;
private var presetSelectPanel:PresetSelectPanel;
static private var console:Console;
private var counter:uint;
private var counterPeriod:uint=15;
private var scaleNum:uint = 60;
private var isFirst:Boolean=true;
private var index:uint;
private var state:String;
public function SionPiano():void
{
stage.align = StageAlign.TOP;
stage.scaleMode = StageScaleMode.NO_SCALE;
//addChild( settingPannel );
console = new Console(this);
keyboard = new MusicalKeyboard( 8, 40 );
addChild( keyboard );
keyboard.addEventListener(MusicalKeyEvent.PRESS, keybaordPressHandler);
//keyboard.addEventListener(MusicalKeyEvent.RELEASE, keybaordReleaseHandler);
voice = presetVoice["sine"];
driver.play();
//stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
addEventListener(Event.ENTER_FRAME, enterFrameHandler2);
var hBox:HBox = new HBox(this, 0, 370);
new PushButton(hBox, 0, 0, 'stop', doStop);
new PushButton(hBox, 0, 0, 'play', doContinue);
var hUISlider:HUISlider = new HUISlider(hBox, 0, 0, "speed", doChangeSpeed);
hUISlider.minimum = 1;
hUISlider.maximum = 20;
hUISlider.tick = 1;
hUISlider.value = counterPeriod;
presetSelectPanel = new PresetSelectPanel( presetVoice, this, 10, 10, 465 - 20, 360);
presetSelectPanel.addEventListener(Event.CHANGE, presetChangeHandler);
presetSelectPanel.signal.add(doChangeCategory);
state = STATE_MOVING;
switch (state)
{
case STATE_MOVING:
keyboard.visible = false;
break;
default:
break;
}
presetSelectPanel.selectRandom();
}
private function doChangeSpeed(e:Event):void
{
counterPeriod = HUISlider(e.target).value
}
private function doStop(e:Event):void
{
state = STATE_STILL
driver.stop();
driver.play();
keyboard.visible = true;
}
private function doContinue(e:Event):void
{
state = STATE_MOVING;
keyboard.visible = false;
}
private function doChangeCategory():void
{
presetSelectPanel.selectedCategory++;
cTrace( "presetSelectPanel.selectedCategory : " + presetSelectPanel.selectedCategory );
}
private function enterFrameHandler2(e:Event):void
{
removeEventListener(Event.ENTER_FRAME, enterFrameHandler2);
keyboard.paint();
keyboard.x = ( 465 - keyboard.width ) / 2;
keyboard.y = 465 - keyboard.x - keyboard.height;
keyboard.scaleX = keyboard.scaleY = 2;
}
private function keybaordPressHandler( event:MusicalKeyEvent ):void {
var keyType:MusicalKeyType = event.keyType;
cTrace( "Trace.traceObject(keyType) : " + Trace.traceObject(keyType) );
driver.noteOn( keyType.note, voice );
cTrace( "keyType.note : ----->" + keyType.note );
}
/*
private function keybaordReleaseHandler( event:MusicalKeyEvent ):void {
var keyType:MusicalKeyType = event.keyType;
driver.noteOff( keyType.note );
}
private function mouseUpHandler( event:MouseEvent ):void {
for ( var i:uint = 0; i < 128; i++ )
driver.noteOff( i );
}
//*/
private function enterFrameHandler( event:Event ):void {
var pressedKeyNotes:Vector.<Boolean> = keyboard.pressedKeyNotes;
var pressedKeyNotesLength:int = pressedKeyNotes.length;
switch (state)
{
case STATE_STILL:
for ( var i:uint = 0; i < pressedKeyNotesLength; i++ )
if( !pressedKeyNotes[ i ] )
driver.noteOff( i );
break;
case STATE_MOVING:
if (counter%counterPeriod==0)
{
index = scaleNum == 60?60 + 11: scaleNum - 1;
if (isFirst)
{
isFirst = false;
}
else
{
doNoteOff();
}
driver.noteOn(scaleNum, voice);
scaleNum++;
if (scaleNum>60+11)
{
scaleNum = 60;
presetSelectPanel.selectedVoiceIndex++;
cTrace( "presetSelectPanel.selectedVoiceIndex : " + presetSelectPanel.selectedVoiceIndex );
}
}
counter++
break;
default:
break;
}
}
private function doNoteOff():void
{
driver.noteOff(index);
}
private function presetChangeHandler( event:Event ):void {
voice = presetSelectPanel.selectedVoice;
}
private function cTrace(msg:String):void
{
traceIt(msg);
}
static public function traceIt(msg:String):void
{
console.traceThis(msg)
}
}
}
import com.bit101.components.Component;
import com.bit101.components.ListItem;
import com.bit101.components.Panel;
import com.bit101.components.PushButton;
import com.bit101.components.TextArea;
import com.bit101.components.VBox;
import com.bit101.components.VScrollBar;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.TextField;
import flash.ui.Keyboard;
import flash.utils.describeType;
import idv.cjcat.signals.ISignal;
import idv.cjcat.signals.Signal;
import org.si.sion.*;
import org.si.sion.utils.*;
class PresetSelectPanel extends Panel {
/**
* ...
* @eventType flash.events.Event.CHANGE
*/
[Event(name = "change", type = "Event")]
private var _selectedVoice:SiONVoice;
public function get selectedVoice():SiONVoice { return _selectedVoice; }
private var voiceList:List;
private var categoryList:List;
private var presetVoice:SiONPresetVoice;
public var signal:Signal;
public function PresetSelectPanel( presetVoice:SiONPresetVoice, parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number = 0, width:Number = 100, height:Number = 100 ):void {
super( parent, xpos, ypos );
this.presetVoice = presetVoice;
this.width = width;
this.height = height;
categoryList = new List( this, 10, 10 );
categoryList.width = width / 2 - 15;
categoryList.height = height - 20;
for each ( var category:Array in presetVoice.categolies )
categoryList.addItem( category[ "name" ] );
categoryList.selectedIndex = 0;
categoryList.addEventListener(Event.SELECT, categoryListSelectHandler);
voiceList = new List( this, categoryList.width + 20, 10 );
voiceList.width = categoryList.width;
voiceList.height = categoryList.height;
voiceListUpdate();
voiceList.selectedIndex = 0;
voiceList.addEventListener(Event.SELECT, voiceListSelectHandler);
setSelectedVoice();
signal = new Signal();
}
public function selectRandom():void
{
categoryList.selectedIndex = int(categoryList.items.length * Math.random());
}
private function voiceListUpdate():void {
voiceList.items = new Array();
/*
for each ( var voice:SiONVoice in presetVoice[ categoryList.selectedItem ] )
voiceList.addItem( voice.name );
//*/
//*
var voices:Array = presetVoice[ categoryList.selectedItem ];
var voicesLength:uint = presetVoice[ categoryList.selectedItem ].length;
for ( var i:uint = 0; i < voicesLength; i++ )
voiceList.addItem( voices[ i ].name );
//*/
}
private function categoryListSelectHandler( event:Event ):void {
voiceListUpdate();
voiceList.selectedIndex = 0;
setSelectedVoice();
}
private function voiceListSelectHandler( event:Event ):void {
setSelectedVoice();
}
private function setSelectedVoice():void {
_selectedVoice = presetVoice[ categoryList.selectedItem ][ voiceList.selectedIndex ];
dispatchEvent( new Event(Event.CHANGE) );
}
public function set selectedCategory(value:uint):void
{
if (categoryList.items.length<value)
{
return;
}
categoryList.selectedIndex = value;
voiceList.selectedIndex = 0;
voiceListUpdate();
}
public function get selectedCategory():uint { return categoryList.selectedIndex; }
public function set selectedVoiceIndex(value:uint):void
{
if (voiceList.items.length<=value)
{
cTrace('---------');
signal.dispatch();
return;
}
voiceList.selectedIndex = value;
}
private function cTrace(arg1:String):void
{
SionPiano.traceIt(arg1);
}
public function get selectedVoiceIndex():uint { return voiceList.selectedIndex; }
}
class MusicalKey extends Sprite {
/**
* ...
* @eventType MusicalKeyEvent.PRESS
*/
[Event(name = "press", type = "MusicalKeyEvent")]
/**
* ...
* @eventType MusicalKeyEvent.RELEASE
*/
[Event(name = "release", type = "MusicalKeyEvent")]
private var _type:MusicalKeyType;
public function get type():MusicalKeyType { return _type; }
private var _width:Number = 0;
override public function set width(value:Number):void
{
_width = value;
paint();
}
override public function get width():Number { return _width; }
private var _height:Number = 0;
override public function set height(value:Number):void
{
_height = value;
paint();
}
override public function get height():Number { return _height; }
private var mouseOver:Boolean = false;
private var mouseDown:Boolean = false;
public function MusicalKey( type:MusicalKeyType, width:Number, height:Number ):void {
_type = type;
this.width = width;
this.height = height;
addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
private function paint():void {
if ( !( width && height ) )
return;
graphics.clear();
graphics.lineStyle( 1 );
if ( mouseDown )
graphics.beginFill( 0xffcccc );
else if ( mouseOver )
graphics.beginFill( 0xccccff );
else if ( type.color == MusicalKeyType.COLOR_WHITE )
graphics.beginFill( 0xffffff );
else
graphics.beginFill( 0x666666 );
graphics.drawRect( 0, 0, width, height );
graphics.endFill();
}
private function mouseOverHandler( event:MouseEvent ):void {
if ( event.buttonDown )
mouseDown = true;
mouseOver = true;
paint();
if( event.buttonDown )
dispatchEvent( new MusicalKeyEvent( MusicalKeyEvent.PRESS, type ) );
}
private function mouseOutHandler( event:MouseEvent ):void {
mouseOver = false;
mouseDown = false;
paint();
if( event.buttonDown )
dispatchEvent( new MusicalKeyEvent( MusicalKeyEvent.RELEASE, type ) );
}
private function mouseDownHandler( event:MouseEvent ):void {
mouseDown = true;
paint();
dispatchEvent( new MusicalKeyEvent( MusicalKeyEvent.PRESS, type ) );
}
private function mouseUpHandler( event:MouseEvent ):void {
mouseDown = false;
paint();
dispatchEvent( new MusicalKeyEvent( MusicalKeyEvent.RELEASE, type ) );
}
}
class MusicalKeyEvent extends Event {
public static const PRESS:String = "press";
public static const RELEASE:String = "release";
private var _keyType:MusicalKeyType;
public function get keyType():MusicalKeyType { return _keyType; }
public function MusicalKeyEvent( type:String, keyType:MusicalKeyType, bubbles:Boolean = false, cancelable:Boolean = false ):void {
super( type, bubbles, cancelable );
_keyType = keyType;
}
}
class MusicalKeyboard extends Sprite {
/**
* ...
* @eventType MusicalKeyEvent.PRESS
*/
[Event(name = "press", type = "MusicalKeyEvent")]
/**
* ...
* @eventType MusicalKeyEvent.RELEASE
*/
[Event(name = "release", type = "MusicalKeyEvent")]
private var numKey:uint;
private var keyOffset:uint;
private var keyWidth:uint;
private var keyHeight:uint;
private function get numWhiteKey():uint {
var numWhiteKey:uint = 0;
for ( var i:uint = 0; i < numKey; i++ )
if ( MusicalKeyType.getKeyColor( ( i + keyOffset ) % 12 ) == MusicalKeyType.COLOR_WHITE )
numWhiteKey++;
return numWhiteKey;
}
private var _pressedKeyNotes:Vector.<Boolean> = new Vector.<Boolean>( 128 );
public function get pressedKeyNotes():Vector.<Boolean> { return _pressedKeyNotes; }
public function MusicalKeyboard( keyWidth:uint, keyHeight:uint, numKey:uint = 88, keyOffset:uint = 9 ):void
{
cTrace( "MusicalKeyboard : " + MusicalKeyboard );
this.numKey = numKey;
this.keyOffset = keyOffset;
this.keyWidth = keyWidth;
if ( keyWidth % 2 )
keyWidth--;
this.keyHeight = keyHeight;
if ( keyHeight % 2 )
keyHeight--;
//paint();
}
public function paint():void {
graphics.lineStyle( 1 );
var keyOffsetX:uint = getKeyOffsetX( keyOffset );
var octaveNum:uint;
var scaleNum:uint;
var octaveX:Number
var i:uint;
var key:MusicalKey;
for ( i = 0; i < numKey; i++ ) {
scaleNum = ( i + keyOffset ) % 12;
//cTrace( "scaleNum : " + scaleNum );
if ( MusicalKeyType.getKeyColor( scaleNum ) != MusicalKeyType.COLOR_WHITE )
continue;
octaveNum = ( i + keyOffset ) / 12;
//cTrace( "octaveNum : " + octaveNum );
key = new MusicalKey( new MusicalKeyType( scaleNum, octaveNum ), keyWidth, keyHeight );
octaveX = octaveNum * keyWidth * 7;
key.x = octaveX + getWhiteKeyX( MusicalKeyType.getKeyColorNum( scaleNum ) ) - keyOffsetX;
addChild( key );
key.addEventListener(MusicalKeyEvent.PRESS, keyPressHandler);
key.addEventListener(MusicalKeyEvent.RELEASE, keyReleaseHandler);
}
for ( i = 0; i < numKey; i++ ) {
scaleNum = ( i + keyOffset ) % 12;
if ( MusicalKeyType.getKeyColor( scaleNum ) != MusicalKeyType.COLOR_BLACK )
continue;
octaveNum = ( i + keyOffset ) / 12;
key = new MusicalKey( new MusicalKeyType( scaleNum, octaveNum ), keyWidth, keyHeight / 2 );
octaveX = octaveNum * keyWidth * 7;
key.x = octaveX + getBlackKeyX( MusicalKeyType.getKeyColorNum( scaleNum ) ) - keyOffsetX;
addChild( key );
key.addEventListener(MusicalKeyEvent.PRESS, keyPressHandler);
key.addEventListener(MusicalKeyEvent.RELEASE, keyReleaseHandler);
}
}
private function getKeyOffsetX( offset:uint ):Number {
var keyColorNum:uint = MusicalKeyType.getKeyColorNum( offset );
return MusicalKeyType.getKeyColor( offset ) == MusicalKeyType.COLOR_WHITE ? getWhiteKeyX( keyColorNum ) : getBlackKeyX( keyColorNum );
}
protected function getWhiteKeyX( scaleNum:uint ):Number {
return keyWidth * scaleNum;
}
protected function getBlackKeyX( scaleNum:uint ):Number {
if( scaleNum <= 1 )
return keyWidth * scaleNum + keyWidth / 2;
return keyWidth * ( scaleNum + 1 ) + keyWidth / 2;
}
private function keyPressHandler( event:MusicalKeyEvent ):void {
pressedKeyNotes[ event.keyType.note ] = true;
dispatchEvent( new MusicalKeyEvent( event.type, event.keyType ) );
cTrace( "event.keyType : " + event.keyType );
cTrace( "event.type : " + event.type );
}
private function keyReleaseHandler( event:MusicalKeyEvent ):void {
pressedKeyNotes[ event.keyType.note ] = false;
dispatchEvent( new MusicalKeyEvent( event.type, event.keyType ) );
}
private function cTrace(type:String):void
{
SionPiano.traceIt(type);
}
}
class MusicalKeyType {
public static const COLOR_WHITE:String = "white";
public static const COLOR_BLACK:String = "black";
public static const SCALE_C:String = "c";
public static const SCALE_D:String = "b";
public static const SCALE_E:String = "e";
public static const SCALE_F:String = "f";
public static const SCALE_G:String = "g";
public static const SCALE_A:String = "a";
public static const SCALE_B:String = "a";
private var _scale:String;
public function get scale():String { return _scale; }
private var _scaleNum:uint;
public function get scaleNum():uint { return _scaleNum; }
private var _color:String;
public function get color():String { return _color; }
private var _keyColorNum:uint;
public function get keyColorNum():uint { return _keyColorNum; }
private var _octave:int;
public function get octave():int { return _octave; }
public function get note():uint { return octave * 12 + 12 + scaleNum; }
public function MusicalKeyType( scaleNum:uint, octave:uint ):void {
_scaleNum = scaleNum;
_octave = octave;
switch( scaleNum ) {
case 0:
_color = COLOR_WHITE;
_scale = SCALE_C;
_keyColorNum = 0;
break;
case 1:
_color = COLOR_BLACK;
_scale = SCALE_C;
_keyColorNum = 0;
break;
case 2:
_color = COLOR_WHITE;
_scale = SCALE_D;
_keyColorNum = 1;
break;
case 3:
_color = COLOR_BLACK;
_scale = SCALE_D;
_keyColorNum = 1;
break;
case 4:
_color = COLOR_WHITE;
_scale = SCALE_E;
_keyColorNum = 2;
break;
case 5:
_color = COLOR_WHITE;
_scale = SCALE_F;
_keyColorNum = 3;
break;
case 6:
_color = COLOR_BLACK;
_scale = SCALE_F;
_keyColorNum = 2;
break;
case 7:
_color = COLOR_WHITE;
_scale = SCALE_G;
_keyColorNum = 4;
break;
case 8:
_color = COLOR_BLACK;
_scale = SCALE_G;
_keyColorNum = 3;
break;
case 9:
_color = COLOR_WHITE;
_scale = SCALE_A;
_keyColorNum = 5;
break;
case 10:
_color = COLOR_BLACK;
_scale = SCALE_A;
_keyColorNum = 4;
break;
case 11:
_color = COLOR_WHITE;
_scale = SCALE_B;
_keyColorNum = 6;
break;
}
}
public static function getKeyColor( scaleNum:uint ):String {
switch( scaleNum ) {
case 0:
case 2:
case 4:
case 5:
case 7:
case 9:
case 11:
return COLOR_WHITE;
}
return COLOR_BLACK;
}
public static function getKeyColorNum( scaleNum:uint ):uint {
switch( scaleNum ) {
case 0:
return 0;
case 1:
return 0;
case 2:
return 1;
case 3:
return 1;
case 4:
return 2;
case 5:
return 3;
case 6:
return 2;
case 7:
return 4;
case 8:
return 3;
case 9:
return 5;
case 10:
return 4;
case 11:
return 6;
}
return null;
}
}
class Console extends VBox
{
private var _textField:TextField;
private var _msprite:Sprite;
public function Console(msprite:Sprite)
{
super();
_msprite = msprite;
_msprite.addChild(this);
addChildAt(new PushButton(null, 0, 0, "clear", doClear), numChildren);;
var textArea:TextArea = TextArea(addChildAt(new TextArea(), numChildren));
_textField = textArea.textField
x = 465;
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
textArea.setSize(465, 350);
var sCKeyBoard:SCKeyBoard = new SCKeyBoard(stage);
sCKeyBoard.keyAndFunction =
{
Q:setDebuggerVisibility,
A:setDebuggerAlpha,
C:clear
}
}
private function clear():void
{
_textField.text = "";
}
private function setDebuggerAlpha():void
{
const debuggerAlpha:Number = 0.5;
alpha = alpha == debuggerAlpha?1:debuggerAlpha;
}
private function setDebuggerVisibility():void
{
visible = !visible;
}
private function onKeyDownHandler(e:KeyboardEvent):void
{
switch (e.keyCode)
{
case Keyboard.UP:
_textField.scrollV -= 10;
break;
case Keyboard.DOWN:
_textField.scrollV += 10;
break;
default:
break;
}
}
private function doClear(e:Event):void
{
_textField.text = "";
}
public function get textField():TextField
{
return _textField;
}
public function set textField(value:TextField):void
{
_textField = value;
}
public function traceThis(msg:String):void
{
_textField.appendText(msg + "\n");
_textField.scrollV = textField.maxScrollV;
}
}
class SCKeyBoard
{
private var _stage:Stage;
private var object:Object;
public var keyAndFunction:Object;
public function SCKeyBoard(stageArg:Stage)
{
_stage = stageArg;
_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
}
public function removeKey(key:String):void
{
var k:Object = keyAndFunction;
for (var name:String in k)
{
if (name==key)
{
trace( "(name==key) : " + (name==key) );
k[name] = null;
break;
}
}
}
public function addKeyAndFunction(key:String,callBack:Function):void
{
keyAndFunction[key] = callBack;
}
private function keyDownHandler(e:KeyboardEvent):void
{
if (!keyAndFunction)
{
throw new Error("keyAndFunction should be defined");
}
var callBack:Function;
if (keyAndFunction[String.fromCharCode(e.keyCode)])
{
trace( "keyAndFunction[String.fromCharCode(e.keyCode)] : " + keyAndFunction[String.fromCharCode(e.keyCode)] );
callBack = keyAndFunction[String.fromCharCode(e.keyCode)]
callBack();
}
}
}
class Trace
{
static private const SEPARATOR:String = "\n";
static private const VALUE_SEPARATOR:String = ":";
public function Trace()
{
}
/**
* http://www.learnosity.com/techblog/index.cfm/2008/2/6/AS3--Looping-over-properties-of-a-class
* @param objArg
* @return
*/
public static function traceObject(objArg:Object,separator:String="",valueSeparator:String=""):String
{
separator = separator == ""?SEPARATOR:separator;
valueSeparator = valueSeparator == ""?VALUE_SEPARATOR:valueSeparator;
//trace( "objArg : " + objArg );
var def : XML = describeType(objArg);
//trace( "def : " + def );
var output:String = "";
//Crazy:::::
var properties : XMLList = def..variable.@name + def..accessor.@name;
var number:int = 0;
//trace("accesors and variables:");
var p:String;
for each ( var property : String in properties )
{
p = property + valueSeparator+" " + objArg[property];
//trace(++number + "." + p);
output += separator + p;
}
return output;
}
public static function traceMethods(objArg:Object):void
{
var v:XMLList = describeType(objArg)..method;
var name:String;
var returnType:String;
trace("methods:");
var method:Function;
var value:*;
for (var j:int = 0; j < v.length(); j++)
{
name = v[j].@name;
returnType = v[j].@returnType;
method = objArg[name];
if (returnType!='void')
{
value = method();
}
else
{
value = "void";
}
trace((j+1)+"."+name +" : " + value);
}
}
}
/**
* List.as
* Keith Peters
* version 0.9.10
*
* A scrolling list of selectable items.
*
* Copyright (c) 2011 Keith Peters
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[Event(name="select", type="flash.events.Event")]
class List extends Component
{
protected var _items:Array;
protected var _itemHolder:Sprite;
protected var _panel:Panel;
protected var _listItemHeight:Number = 20;
protected var _listItemClass:Class =ListItem;
protected var _scrollbar:VScrollBar;
protected var _selectedIndex:int = -1;
protected var _defaultColor:uint = Style.LIST_DEFAULT;
protected var _alternateColor:uint = Style.LIST_ALTERNATE;
protected var _selectedColor:uint = Style.LIST_SELECTED;
protected var _rolloverColor:uint = Style.LIST_ROLLOVER;
protected var _alternateRows:Boolean = false;
/**
* Constructor
* @param parent The parent DisplayObjectContainer on which to add this List.
* @param xpos The x position to place this component.
* @param ypos The y position to place this component.
* @param items An array of items to display in the list. Either strings or objects with label property.
*/
public function List(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0, items:Array=null)
{
if(items != null)
{
_items = items;
}
else
{
_items = new Array();
}
super(parent, xpos, ypos);
}
/**
* Initilizes the component.
*/
protected override function init() : void
{
super.init();
setSize(100, 100);
addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
addEventListener(Event.RESIZE, onResize);
makeListItems();
fillItems();
}
/**
* Creates and adds the child display objects of this component.
*/
protected override function addChildren() : void
{
super.addChildren();
_panel = new Panel(this, 0, 0);
_panel.color = _defaultColor;
_itemHolder = new Sprite();
_panel.content.addChild(_itemHolder);
_scrollbar = new VScrollBar(this, 0, 0, onScroll);
_scrollbar.setSliderParams(0, 0, 0);
}
/**
* Creates all the list items based on data.
*/
protected function makeListItems():void
{
var item:ListItem;
while(_itemHolder.numChildren > 0)
{
item = ListItem(_itemHolder.getChildAt(0));
item.removeEventListener(MouseEvent.CLICK, onSelect);
_itemHolder.removeChildAt(0);
}
var numItems:int = Math.ceil(_height / _listItemHeight);
numItems = Math.min(numItems, _items.length);
numItems = Math.max(numItems, 1);
for(var i:int = 0; i < numItems; i++)
{
item = new _listItemClass(_itemHolder, 0, i * _listItemHeight);
item.setSize(width, _listItemHeight);
item.defaultColor = _defaultColor;
item.selectedColor = _selectedColor;
item.rolloverColor = _rolloverColor;
item.addEventListener(MouseEvent.CLICK, onSelect);
}
}
protected function fillItems():void
{
var offset:int = _scrollbar.value;
var numItems:int = Math.ceil(_height / _listItemHeight);
numItems = Math.min(numItems, _items.length);
for(var i:int = 0; i < numItems; i++)
{
var item:ListItem = _itemHolder.getChildAt(i) as ListItem;
if(offset + i < _items.length)
{
item.data = _items[offset + i];
}
else
{
item.data = "";
}
if(_alternateRows)
{
item.defaultColor = ((offset + i) % 2 == 0) ? _defaultColor : _alternateColor;
}
else
{
item.defaultColor = _defaultColor;
}
if(offset + i == _selectedIndex)
{
item.selected = true;
}
else
{
item.selected = false;
}
}
}
/**
* If the selected item is not in view, scrolls the list to make the selected item appear in the view.
*/
protected function scrollToSelection():void
{
var numItems:int = Math.ceil(_height / _listItemHeight);
if(_selectedIndex != -1)
{
if(_scrollbar.value > _selectedIndex)
{
// _scrollbar.value = _selectedIndex;
}
else if(_scrollbar.value + numItems < _selectedIndex)
{
_scrollbar.value = _selectedIndex - numItems + 1;
}
}
else
{
_scrollbar.value = 0;
}
fillItems();
}
///////////////////////////////////
// public methods
///////////////////////////////////
/**
* Draws the visual ui of the component.
*/
public override function draw() : void
{
super.draw();
_selectedIndex = Math.min(_selectedIndex, _items.length - 1);
// panel
_panel.setSize(_width, _height);
_panel.color = _defaultColor;
_panel.draw();
// scrollbar
_scrollbar.x = _width - 10;
var contentHeight:Number = _items.length * _listItemHeight;
_scrollbar.setThumbPercent(_height / contentHeight);
var pageSize:Number = Math.floor(_height / _listItemHeight);
_scrollbar.maximum = Math.max(0, _items.length - pageSize);
_scrollbar.pageSize = pageSize;
_scrollbar.height = _height;
_scrollbar.draw();
scrollToSelection();
}
/**
* Adds an item to the list.
* @param item The item to add. Can be a string or an object containing a string property named label.
*/
public function addItem(item:Object):void
{
_items.push(item);
invalidate();
makeListItems();
fillItems();
}
/**
* Adds an item to the list at the specified index.
* @param item The item to add. Can be a string or an object containing a string property named label.
* @param index The index at which to add the item.
*/
public function addItemAt(item:Object, index:int):void
{
index = Math.max(0, index);
index = Math.min(_items.length, index);
_items.splice(index, 0, item);
invalidate();
fillItems();
}
/**
* Removes the referenced item from the list.
* @param item The item to remove. If a string, must match the item containing that string. If an object, must be a reference to the exact same object.
*/
public function removeItem(item:Object):void
{
var index:int = _items.indexOf(item);
removeItemAt(index);
}
/**
* Removes the item from the list at the specified index
* @param index The index of the item to remove.
*/
public function removeItemAt(index:int):void
{
if(index < 0 || index >= _items.length) return;
_items.splice(index, 1);
invalidate();
fillItems();
}
/**
* Removes all items from the list.
*/
public function removeAll():void
{
_items.length = 0;
invalidate();
fillItems();
}
///////////////////////////////////
// event handlers
///////////////////////////////////
/**
* Called when a user selects an item in the list.
*/
protected function onSelect(event:Event):void
{
if(! (event.target is ListItem)) return;
var offset:int = _scrollbar.value;
for(var i:int = 0; i < _itemHolder.numChildren; i++)
{
if(_itemHolder.getChildAt(i) == event.target) _selectedIndex = i + offset;
ListItem(_itemHolder.getChildAt(i)).selected = false;
}
ListItem(event.target).selected = true;
dispatchEvent(new Event(Event.SELECT));
}
/**
* Called when the user scrolls the scroll bar.
*/
protected function onScroll(event:Event):void
{
fillItems();
}
/**
* Called when the mouse wheel is scrolled over the component.
*/
protected function onMouseWheel(event:MouseEvent):void
{
_scrollbar.value -= event.delta;
fillItems();
}
protected function onResize(event:Event):void
{
makeListItems();
fillItems();
}
///////////////////////////////////
// getter/setters
///////////////////////////////////
/**
* Sets / gets the index of the selected list item.
*/
public function set selectedIndex(value:int):void
{
if(value >= 0 && value < _items.length)
{
_selectedIndex = value;
// _scrollbar.value = _selectedIndex;
}
else
{
_selectedIndex = -1;
}
invalidate();
dispatchEvent(new Event(Event.SELECT));
}
public function get selectedIndex():int
{
return _selectedIndex;
}
/**
* Sets / gets the item in the list, if it exists.
*/
public function set selectedItem(item:Object):void
{
var index:int = _items.indexOf(item);
// if(index != -1)
// {
selectedIndex = index;
invalidate();
dispatchEvent(new Event(Event.SELECT));
// }
}
public function get selectedItem():Object
{
if(_selectedIndex >= 0 && _selectedIndex < _items.length)
{
return _items[_selectedIndex];
}
return null;
}
/**
* Sets/gets the default background color of list items.
*/
public function set defaultColor(value:uint):void
{
_defaultColor = value;
invalidate();
}
public function get defaultColor():uint
{
return _defaultColor;
}
/**
* Sets/gets the selected background color of list items.
*/
public function set selectedColor(value:uint):void
{
_selectedColor = value;
invalidate();
}
public function get selectedColor():uint
{
return _selectedColor;
}
/**
* Sets/gets the rollover background color of list items.
*/
public function set rolloverColor(value:uint):void
{
_rolloverColor = value;
invalidate();
}
public function get rolloverColor():uint
{
return _rolloverColor;
}
/**
* Sets the height of each list item.
*/
public function set listItemHeight(value:Number):void
{
_listItemHeight = value;
makeListItems();
invalidate();
}
public function get listItemHeight():Number
{
return _listItemHeight;
}
/**
* Sets / gets the list of items to be shown.
*/
public function set items(value:Array):void
{
_items = value;
invalidate();
}
public function get items():Array
{
return _items;
}
/**
* Sets / gets the class used to render list items. Must extend ListItem.
*/
public function set listItemClass(value:Class):void
{
_listItemClass = value;
makeListItems();
invalidate();
}
public function get listItemClass():Class
{
return _listItemClass;
}
/**
* Sets / gets the color for alternate rows if alternateRows is set to true.
*/
public function set alternateColor(value:uint):void
{
_alternateColor = value;
invalidate();
}
public function get alternateColor():uint
{
return _alternateColor;
}
/**
* Sets / gets whether or not every other row will be colored with the alternate color.
*/
public function set alternateRows(value:Boolean):void
{
_alternateRows = value;
invalidate();
}
public function get alternateRows():Boolean
{
return _alternateRows;
}
/**
* Sets / gets whether the scrollbar will auto hide when there is nothing to scroll.
*/
public function set autoHideScrollBar(value:Boolean):void
{
_scrollbar.autoHide = value;
}
public function get autoHideScrollBar():Boolean
{
return _scrollbar.autoHide;
}
}
/**
* Style.as
* Keith Peters
* version 0.9.10
*
* A collection of style variables used by the components.
* If you want to customize the colors of your components, change these values BEFORE instantiating any components.
*
* Copyright (c) 2011 Keith Peters
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
class Style
{
public static var TEXT_BACKGROUND:uint = 0xFFFFFF;
public static var BACKGROUND:uint = 0xCCCCCC;
public static var BUTTON_FACE:uint = 0xFFFFFF;
public static var BUTTON_DOWN:uint = 0xEEEEEE;
public static var INPUT_TEXT:uint = 0x333333;
public static var LABEL_TEXT:uint = 0x666666;
public static var DROPSHADOW:uint = 0x000000;
public static var PANEL:uint = 0xF3F3F3;
public static var PROGRESS_BAR:uint = 0xFFFFFF;
public static var LIST_DEFAULT:uint = 0xFFFFFF;
public static var LIST_ALTERNATE:uint = 0xF3F3F3;
public static var LIST_SELECTED:uint = 0xCCCCCC;
public static var LIST_ROLLOVER:uint = 0XDDDDDD;
public static var embedFonts:Boolean = true;
public static var fontName:String = "PF Ronda Seven";
public static var fontSize:Number = 8;
public static const DARK:String = "dark";
public static const LIGHT:String = "light";
/**
* Applies a preset style as a list of color values. Should be called before creating any components.
*/
public static function setStyle(style:String):void
{
switch(style)
{
case DARK:
Style.BACKGROUND = 0x444444;
Style.BUTTON_FACE = 0x666666;
Style.BUTTON_DOWN = 0x222222;
Style.INPUT_TEXT = 0xBBBBBB;
Style.LABEL_TEXT = 0xCCCCCC;
Style.PANEL = 0x666666;
Style.PROGRESS_BAR = 0x666666;
Style.TEXT_BACKGROUND = 0x555555;
Style.LIST_DEFAULT = 0x444444;
Style.LIST_ALTERNATE = 0x393939;
Style.LIST_SELECTED = 0x666666;
Style.LIST_ROLLOVER = 0x777777;
break;
case LIGHT:
default:
Style.BACKGROUND = 0xCCCCCC;
Style.BUTTON_FACE = 0xFFFFFF;
Style.BUTTON_DOWN = 0xEEEEEE;
Style.INPUT_TEXT = 0x333333;
Style.LABEL_TEXT = 0x666666;
Style.PANEL = 0xF3F3F3;
Style.PROGRESS_BAR = 0xFFFFFF;
Style.TEXT_BACKGROUND = 0xFFFFFF;
Style.LIST_DEFAULT = 0xFFFFFF;
Style.LIST_ALTERNATE = 0xF3F3F3;
Style.LIST_SELECTED = 0xCCCCCC;
Style.LIST_ROLLOVER = 0xDDDDDD;
break;
}
}
}