diff --git a/src/syncomps/CheckBox.as b/src/syncomps/CheckBox.as index 3155057..30e4dcb 100644 --- a/src/syncomps/CheckBox.as +++ b/src/syncomps/CheckBox.as @@ -1,24 +1,20 @@ package syncomps { - import flash.accessibility.AccessibilityProperties; import flash.display.CapsStyle; import flash.display.Graphics; import flash.display.JointStyle; import flash.display.LineScaleMode; import flash.display.Shape; - import flash.display.Sprite; import flash.events.Event; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.text.TextField; - import flash.text.TextFieldAutoSize; import flash.ui.Keyboard; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.interfaces.graphics.ILabel; import syncomps.styles.DefaultLabelStyle; - import syncomps.styles.Style; import syncomps.styles.DefaultStyle; import syncomps.styles.StyleManager; @@ -34,31 +30,27 @@ package syncomps public static const DEF_HEIGHT:int = 32; protected static var DEFAULT_STYLE:Class = DefaultLabelStyle + private var b_dispatchClick:Boolean; private var b_selected:Boolean; - private var tf_label:SkinnableTextField; private var shp_graphic:Shape; - private var b_dispatchClick:Boolean; + private var cmpi_label:Label; - public function CheckBox() - { + public function CheckBox() { init() } private function init():void { shp_graphic = new Shape() - tf_label = new SkinnableTextField() - StyleManager.unregister(tf_label) - addChild(tf_label) - addChild(shp_graphic) + cmpi_label = new Label() + StyleManager.unregister(cmpi_label) + + addChild(cmpi_label) + drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND); - tf_label.selectable = tf_label.multiline = tf_label.mouseEnabled = false; selected = false //warning: these 3 lines redraws the graphics, label = null //so make sure width and height are preinitialized - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) - accessibilityProperties = new AccessibilityProperties() - addEventListener(MouseEvent.CLICK, toggleButton, false, 0, true); addEventListener(MouseEvent.MOUSE_UP, changeState, false, 0, true) addEventListener(MouseEvent.ROLL_OUT, changeState, false, 0, true) @@ -69,12 +61,13 @@ package syncomps addEventListener(MouseEvent.RELEASE_OUTSIDE, changeState, false, 0, true) addEventListener(KeyboardEvent.KEY_UP, dispatchClickEvent, false, 0, true) addEventListener(KeyboardEvent.KEY_DOWN, startDispatchClickEvent, false, 0, true) + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) } private function updateStyles(evt:StyleEvent):void { - tf_label.setStyle(evt.style, evt.value) - drawGraphics(width, height, str_state) + cmpi_label.setStyle(evt.style, evt.value) + drawGraphics(width, height, state) } private function changeState(evt:Event):void @@ -102,9 +95,9 @@ package syncomps if (b_dispatchClick) { resetButton() - dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, false)) - b_dispatchClick = false + toggleButton(null) } + b_dispatchClick = false } private function startDispatchClickEvent(evt:KeyboardEvent):void @@ -124,29 +117,14 @@ package syncomps DEFAULT_STYLE = styleClass } - override public function set width(value:Number):void - { - drawGraphics(value, height, str_state) - } - - override public function set height(value:Number):void - { - drawGraphics(width, value, str_state) - } - public function set label(text:String):void { - if (text && text.length) { - tf_label.text = text; - } - else { - tf_label.text = "" - } - drawGraphics(width, height, str_state) + cmpi_label.label = text + drawGraphics(width, height, state) } public function get label():String { - return tf_label.text + return cmpi_label.label } public function set labelPosition(position:int):void { @@ -158,7 +136,7 @@ package syncomps } public function get textField():TextField { - return tf_label + return cmpi_label.textField } override public function unload():void @@ -177,27 +155,32 @@ package syncomps public function resizeWidth():void { - tf_label.autoSize = TextFieldAutoSize.LEFT - var widthVal:Number = tf_label.width - switch(labelPosition) - { - case DefaultLabelStyle.LABEL_RIGHT: - case DefaultLabelStyle.LABEL_LEFT: - widthVal += 32; - break; - } - tf_label.autoSize = TextFieldAutoSize.NONE - width = widthVal + cmpi_label.resizeWidth() + drawGraphics(width, height, state) + } + + public function resizeHeight():void + { + cmpi_label.resizeHeight() + drawGraphics(width, height, state) } - public function resizeHeight():void { - height = tf_label.textHeight + 16 + /* DELEGATE syncomps.Label */ + + public function get iconSize():int { + return cmpi_label.iconSize; + } + + public function set iconSize(value:int):void + { + cmpi_label.iconSize = value; + drawGraphics(width, height, state) } private function toggleButton(evt:MouseEvent):void { selected = !selected - drawGraphics(width, height, str_state); + drawGraphics(width, height, state); dispatchEvent(new Event(Event.CHANGE, false, false)) } @@ -224,87 +207,37 @@ package syncomps { super.drawGraphics(width, height, state) const shapeGraphics:Graphics = shp_graphic.graphics - var xCenter:Number, yCenter:Number, size:Number, colourAlpha:Number; - var colour:uint = uint(getStyle(state)), checkHeight:int = height - 16 + var color:uint = uint(getStyle(state)), checkHeight:int = height - 16 + var size:Number = cmpi_label.iconSize / 2, colorAlpha:Number; if(!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) - } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF - var textHeight:int = tf_label.textHeight - if(checkHeight < textHeight - 8) { - checkHeight = textHeight - 8 - } - switch(labelPosition) - { - case DefaultLabelStyle.LABEL_RIGHT: - case DefaultLabelStyle.LABEL_LEFT: - tf_label.height = height - 4 - if((tf_label.height < textHeight && textHeight <= height) || (tf_label.textHeight && tf_label.height >= textHeight)) { - tf_label.height = textHeight - } - yCenter = height * 0.5; - size = checkHeight * 0.5 - tf_label.y = 0 - tf_label.y = (height - tf_label.height) * 0.5; - break; - case DefaultLabelStyle.LABEL_BELOW: - case DefaultLabelStyle.LABEL_ABOVE: - size = checkHeight * 0.3 - tf_label.height = height - (size * 2) - if((tf_label.height < textHeight && textHeight <= height) || (tf_label.textHeight && tf_label.height >= textHeight)) { - tf_label.height = textHeight - } - xCenter = width * 0.5; - tf_label.width = width; - break; - } - switch(labelPosition) - { - case DefaultLabelStyle.LABEL_RIGHT: - xCenter = size + 2; - tf_label.x = (xCenter + size) + 4 - tf_label.width = width - tf_label.x - break; - case DefaultLabelStyle.LABEL_LEFT: - tf_label.x = 0 - xCenter = width - (size + 2) - tf_label.width = width - ((size * 2) + 4) - break; - case DefaultLabelStyle.LABEL_BELOW: - tf_label.y = height - tf_label.height - tf_label.x = 0; - yCenter = size; - break; - case DefaultLabelStyle.LABEL_ABOVE: - tf_label.y = tf_label.x = 0; - yCenter = height - size - break; - default: - throw new Error("Invalid label position.") - break; + color = uint(getStyle(DefaultStyle.DISABLED)) } + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF //outer border (invisible) - shapeGraphics.clear() - shapeGraphics.beginFill(0, 0) - shapeGraphics.drawRect(0, 0, width, height) - shapeGraphics.endFill() + graphics.clear() + graphics.beginFill(0, 0) + graphics.drawRect(0, 0, width, height) + graphics.endFill() //checkbox + shapeGraphics.clear() shapeGraphics.lineStyle(1) - shapeGraphics.beginFill(colour, colourAlpha) - shapeGraphics.drawRect((xCenter - size), (yCenter - size), (size * 2), (size * 2)) + shapeGraphics.beginFill(color, colorAlpha) + shapeGraphics.drawRect(0, 0, (size * 2), (size * 2)) shapeGraphics.endFill() if (b_selected) { //draw tick shapeGraphics.lineStyle(2, 0, 1, false, LineScaleMode.NONE, CapsStyle.SQUARE, JointStyle.BEVEL, 5) - shapeGraphics.moveTo((xCenter + 1) - size, (yCenter - 1) + (size * 0.5)) - shapeGraphics.lineTo((xCenter + 1) - (size * 0.5), (yCenter - 1) + size) - shapeGraphics.lineTo((xCenter - 1) + size, (yCenter + 1) - size) - shapeGraphics.endFill() + shapeGraphics.moveTo(1, (size - 1) + (size * 0.5)) + shapeGraphics.lineTo((size + 1) - (size * 0.5), (size * 2) - 1) + shapeGraphics.lineTo((size * 2) - 1, 1) } + cmpi_label.icon = shp_graphic + cmpi_label.height = height + cmpi_label.width = width } } diff --git a/src/syncomps/ComboBox.as b/src/syncomps/ComboBox.as index 4774ce0..8733393 100644 --- a/src/syncomps/ComboBox.as +++ b/src/syncomps/ComboBox.as @@ -1,5 +1,6 @@ package syncomps { + import flash.display.InteractiveObject; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.events.TextEvent; @@ -8,9 +9,8 @@ package syncomps import flash.ui.Keyboard; import syncomps.data.DataElement; import syncomps.data.DataProvider; - import syncomps.events.ComboBoxEvent; import syncomps.events.DataProviderEvent; - import syncomps.events.ListCellEvent; + import syncomps.events.ListEvent; import flash.display.DisplayObject; import flash.display.Graphics; import flash.display.Shape; @@ -21,9 +21,9 @@ package syncomps import flash.text.TextField; import flash.text.TextFieldAutoSize; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; + import syncomps.interfaces.graphics.IAutoResize; import syncomps.interfaces.IDataProvider; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.ILabel; import syncomps.interfaces.ISynComponent; import syncomps.styles.ComboBoxStyle; import syncomps.styles.DefaultInnerTextStyle; @@ -32,12 +32,26 @@ package syncomps import syncomps.styles.DefaultStyle; import syncomps.styles.StyleManager; + /** + * Dispatched when the menu is toggled or when the selection changes. + */ [Event(name="change", type="flash.events.Event")] - [Event(name="CELL_CLICK", type="syncomps.events.ListCellEvent")] - [Event(name="MENU_STATE_CHANGE", type="syncomps.events.ComboBoxEvent")] - [Event(name="DATA_REFRESH", type="syncomps.events.DataProviderEvent")] - [Event(name="ITEM_ADDED", type="syncomps.events.DataProviderEvent")] - [Event(name = "ITEM_REMOVED", type = "syncomps.events.DataProviderEvent")] + /** + * Dispatched when a cell is clicked. + */ + [Event(name = "synLCECellClick", type = "syncomps.events.ListEvent")] + /** + * Dispatched when the dataProvider property is changed. + */ + [Event(name = "synDPEDataRefresh", type = "syncomps.events.DataProviderEvent")] + /** + * Dispatched when an item is added to the list. + */ + [Event(name = "synDPEItemAdded", type = "syncomps.events.DataProviderEvent")] + /** + * Dispatched when an item is removed from the list. + */ + [Event(name = "synDPEItemRemoved", type = "syncomps.events.DataProviderEvent")] /** * ... @@ -50,12 +64,15 @@ package syncomps protected static var DEFAULT_STYLE:Class = ComboBoxStyle - protected var cmpi_activeItem:TextInput; - protected var dp_provider:DataProvider; - protected var b_autoComplete:Boolean; - protected var i_selectedIndex:int; - protected var b_menuOpen:Boolean; - protected var cmpi_list:List; + private var cmpi_activeItem:TextInput; + private var dp_provider:DataProvider; + private var dp_master:DataProvider; + private var b_autoComplete:Boolean; + private var b_autoFilter:Boolean; + private var i_selectedIndex:int; + private var b_menuOpen:Boolean; + private var b_filtering:Boolean; + private var cmpi_list:List; public function ComboBox() { init() @@ -68,14 +85,15 @@ package syncomps StyleManager.unregister(cmpi_activeItem) cmpi_activeItem.addEventListener(Event.CHANGE, stopPropagation) + cmpi_activeItem.addEventListener(Event.CHANGE, filterDataOnChange, false, 0, true) cmpi_activeItem.addEventListener(FocusEvent.FOCUS_OUT, dispatchChangeOnKey, false, 0, true) cmpi_activeItem.addEventListener(TextEvent.TEXT_INPUT, autoCompleteText, false, 0, true) cmpi_activeItem.addEventListener(KeyboardEvent.KEY_DOWN, dispatchChangeOnKey, false, 0, true) cmpi_activeItem.addEventListener(MouseEvent.MOUSE_OVER, propagateMouseEvent, false, 0, true) - cmpi_activeItem.setStyle(DefaultInnerTextStyle.BORDER, 0x00000000) //no border colour by default - cmpi_activeItem.setStyle(DefaultStyle.BACKGROUND, 0x00000000) //no background colour when editable - cmpi_activeItem.setStyle(DefaultStyle.DISABLED, 0x00000000) //no background colour when not editable - cmpi_activeItem.borderColour = 0x00000000 + cmpi_activeItem.setStyle(DefaultInnerTextStyle.BORDER, 0x00000000) //no border color by default + cmpi_activeItem.setStyle(DefaultStyle.BACKGROUND, 0x00000000) //no background color when editable + cmpi_activeItem.setStyle(DefaultStyle.DISABLED, 0x00000000) //no background color when not editable + cmpi_activeItem.borderColor = 0x00000000 cmpi_activeItem.height = 24 cmpi_activeItem.width = 72 cmpi_activeItem.x = 4; @@ -85,8 +103,8 @@ package syncomps rowHeight = 24; i_selectedIndex = 0 drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) - cmpi_list.addEventListener(ListCellEvent.CELL_CLICK, propagateCellClick, false, 0, true); + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + cmpi_list.addEventListener(ListEvent.CELL_CLICK, propagateCellClick, false, 0, true); addEventListener(KeyboardEvent.KEY_UP, changeItem) addEventListener(KeyboardEvent.KEY_DOWN, changeState) @@ -98,6 +116,7 @@ package syncomps addEventListener(FocusEvent.FOCUS_OUT, changeState, false, 0, true) addEventListener(MouseEvent.MOUSE_DOWN, changeState, false, 0, true) addEventListener(MouseEvent.RELEASE_OUTSIDE, changeState, false, 0, true) + addEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, changeState, false, 0, true) cmpi_list.addEventListener(DataProviderEvent.ITEM_ADDED, updateEntries, false, 0, true) cmpi_list.addEventListener(DataProviderEvent.ITEM_REMOVED, updateEntries, false, 0, true) cmpi_list.addEventListener(DataProviderEvent.DATA_REFRESH, updateEntries, false, 0, true) @@ -105,21 +124,33 @@ package syncomps addChild(cmpi_activeItem) } + private function filterDataOnChange(evt:Event):void + { + if(!(dp_master && autoFilter && editable)) { + return; + } + var prevOpen:Boolean = menuOpen + var input:TextInput = evt.currentTarget as TextInput + var enteredText:String = input.value.toLocaleLowerCase() + b_filtering = enteredText && enteredText.length + dp_provider.items = dp_master.items.filter(function filter(item:Object, index:int, array:Array):Boolean { + return item.label.toLocaleLowerCase().indexOf(enteredText) != -1 + }) + input.value = enteredText + menuOpen = prevOpen + } + private function stopPropagation(evt:Event):void { - evt.stopImmediatePropagation() + evt.stopPropagation() } private function dispatchChangeOnKey(evt:Event):void { - if ((evt is FocusEvent) || (evt as KeyboardEvent).keyCode == Keyboard.ENTER) - { - if(evt is FocusEvent) { - trace(evt.target, evt.currentTarget, evt["relatedObject"], 'ee') - } - dispatchEvent(new Event(Event.CHANGE, evt.bubbles, false)) - if (stage && stage.focus) { - stage.focus = null - } + if (evt is FocusEvent && stage && stage.focus) { + stage.focus = null + } + else if ((evt is KeyboardEvent) && (evt as KeyboardEvent).keyCode == Keyboard.ENTER) { + dispatchEvent(new TextEvent(TextEvent.TEXT_INPUT, evt.bubbles, false, "")) } } @@ -130,17 +161,18 @@ package syncomps } var currIndex:int = cmpi_activeItem.caretIndex var currValue:String = (cmpi_activeItem.value.slice(0, currIndex) + evt.text).toLocaleLowerCase() - for (var i:uint = 0; i < dp_provider.length; ++i) + dp_provider.some(function completeText(item:Object, index:int, array:Array):Boolean { - var currTypeLabel:String = dp_provider.getItemAt(i).label - if (currTypeLabel && currTypeLabel.toLocaleLowerCase().indexOf(currValue) == 0) + var currTypeLabel:String = item.label + var matchText:Boolean = currTypeLabel && currTypeLabel.toLocaleLowerCase().indexOf(currValue) == 0 + if(matchText) { evt.preventDefault() cmpi_activeItem.value = currTypeLabel cmpi_activeItem.setSelection(currTypeLabel.length, currIndex + 1) - break; } - } + return matchText + }); } private function updateEntries(evt:DataProviderEvent):void @@ -148,7 +180,7 @@ package syncomps switch(evt.type) { case DataProviderEvent.ITEM_ADDED: - if(selectedIndex < 0 || selectedIndex >= dp_provider.length) { + if(selectedIndex < 0 || selectedIndex >= dp_provider.numItems) { selectedIndex = 0; } case DataProviderEvent.ITEM_REMOVED: @@ -160,8 +192,11 @@ package syncomps selectedIndex = -1; break; } + if (!b_filtering) { + dp_master = dp_provider.clone() + } if(menuOpen) { - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } dispatchEvent(evt) } @@ -170,7 +205,7 @@ package syncomps { switch(evt.style) { - //no border or background colour for these textfields + //no border or background color for these textfields case DefaultStyle.DISABLED: case DefaultStyle.BACKGROUND: case DefaultInnerTextStyle.BORDER: @@ -181,14 +216,15 @@ package syncomps break; } cmpi_list.setStyle(evt.style, evt.value) + drawGraphics(width, height, state) } - private function propagateCellClick(evt:ListCellEvent):void + private function propagateCellClick(evt:ListEvent):void { if (evt) { evt.preventDefault() - if(dispatchEvent(new ListCellEvent(evt.type, evt.index, evt.item, evt.bubbles, true))) { + if(dispatchEvent(new ListEvent(evt.type, evt.index, evt.item, evt.bubbles, true))) { selectedIndex = evt.index } } @@ -209,10 +245,15 @@ package syncomps drawGraphics(width, height, DefaultStyle.DOWN); } break; + case FocusEvent.MOUSE_FOCUS_CHANGE: + var relatedObject:InteractiveObject = (evt as FocusEvent).relatedObject + if(!relatedObject || !(contains(relatedObject) || cmpi_list.contains(relatedObject))) { + menuOpen = false + } + case FocusEvent.FOCUS_OUT: case MouseEvent.MOUSE_UP: case MouseEvent.RELEASE_OUTSIDE: case MouseEvent.ROLL_OUT: - case FocusEvent.FOCUS_OUT: drawGraphics(width, height, DefaultStyle.BACKGROUND); break; case MouseEvent.ROLL_OVER: @@ -226,7 +267,7 @@ package syncomps { var keyCode:int = evt.keyCode var index:int = selectedIndex - if(!(dp_provider && dp_provider.length)) { + if(!(dp_provider && dp_provider.numItems)) { return; } if (keyCode == Keyboard.DOWN) { @@ -245,13 +286,13 @@ package syncomps if(index < 0) { index = 0 } - else if(index >= dp_provider.length) { - index = dp_provider.length - 1 + else if(index >= dp_provider.numItems) { + index = dp_provider.numItems - 1 } if (selectedIndex != index) { selectedIndex = index - dispatchEvent(new ListCellEvent(ListCellEvent.CELL_CLICK, index, dp_provider.getItemAt(index), false, false)) + dispatchEvent(new ListEvent(ListEvent.CELL_CLICK, index, dp_provider.getItemAt(index), false, false)) } } @@ -280,7 +321,7 @@ package syncomps return; } menuOpen = false - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } public function set dataProvider(provider:DataProvider):void @@ -289,7 +330,7 @@ package syncomps return; } cmpi_list.dataProvider = dp_provider = provider - if (provider && provider.length) { + if (provider && provider.numItems) { label = provider.getItemAt(0).label } } @@ -304,13 +345,6 @@ package syncomps override public function setDefaultStyle(styleClass:Class):void { DEFAULT_STYLE = styleClass } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) - } - - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } override public function unload():void { @@ -344,8 +378,7 @@ package syncomps menuOpen = false; } - public function get selectedIndex():int - { + public function get selectedIndex():int { return i_selectedIndex; } @@ -357,11 +390,11 @@ package syncomps { menuOpen = false setSelectedCell(index) - if (0 <= index && index < dp_provider.length) + if (0 <= index && index < dp_provider.numItems) { var prevLabel:String = label; label = dp_provider.getItemAt(index).label - if (selectedIndex != index || label != prevLabel) { + if (!(selectedIndex == index && label == prevLabel)) { dispatchEvent(new Event(Event.CHANGE, false, false)) } } @@ -369,20 +402,24 @@ package syncomps public function get selectedItem():DataElement { - if(i_selectedIndex >= 0 && i_selectedIndex < dp_provider.length) { + if(i_selectedIndex >= 0 && i_selectedIndex < dp_provider.numItems) { return dp_provider.getItemAt(i_selectedIndex) } return null; } public function get numItems():uint { - return dp_provider.length + return dp_provider.numItems } public function addItem(item:Object):void { dp_provider.addItem(item) } + public function addItems(items:Array):void { + dp_provider.addItems(items) + } + public function addItemAt(item:Object, index:int):void { dp_provider.addItemAt(item, index) } @@ -398,25 +435,25 @@ package syncomps return dp_provider.removeItemAt(index) } - public function removeAll():void { - dp_provider.removeAll() + public function removeItems():void { + dp_provider.removeItems() } public function resizeWidth():void { - var maxStr:String = "" + var maxStr:String = ""; var prevPlaceholder:String = cmpi_activeItem.placeHolder - for (var i:uint = 0; i < dp_provider.length; ++i) + dp_provider.forEach(function calculateMaxWidth(item:Object, index:int, array:Array):void { - var currStr:String = dp_provider.getItemAt(i).label + var currStr:String = item.label if(currStr.length > maxStr.length) { maxStr = currStr } - } + }); cmpi_activeItem.placeHolder = maxStr cmpi_activeItem.resizeWidth() - cmpi_activeItem.placeHolder = prevPlaceholder width = cmpi_activeItem.width + 20 + cmpi_activeItem.placeHolder = prevPlaceholder } public function resizeHeight():void @@ -425,6 +462,30 @@ package syncomps height = cmpi_activeItem.height + 4 } + /* DELEGATE syncomps.data.DataProvider */ + + public function getItemBy(searchFunction:Function):DataElement { + return dp_provider.getItemBy(searchFunction); + } + + public function indexOf(searchFunction:Function, fromIndex:int = 0):int { + return dp_provider.indexOf(searchFunction, fromIndex); + } + + /* DELEGATE syncomps.List */ + + public function get cellSize():int { + return cmpi_list.cellSize; + } + + public function set cellSize(value:int):void { + cmpi_list.cellSize = value; + } + + public function set items(value:Array):void { + dp_provider.items = value; + } + public function get items():Array { return dp_provider.items } @@ -438,15 +499,14 @@ package syncomps } public function get rowHeight():int { - return cmpi_list.rowHeight; + return cmpi_list.cellSize; } public function set rowHeight(value:int):void { - cmpi_list.rowHeight = value; + cmpi_list.cellSize = value; } - public function get menuOpen():Boolean - { + public function get menuOpen():Boolean { return b_menuOpen; } @@ -459,46 +519,43 @@ package syncomps if (b_menuOpen != value) { b_menuOpen = value; - drawGraphics(width, height, str_state) - if (stage) - { - if (value) { - stage.addEventListener(MouseEvent.CLICK, hideList, false, 0, true) - } - else { - stage.removeEventListener(MouseEvent.CLICK, hideList) - } - } - dispatchEvent(new ComboBoxEvent(ComboBoxEvent.MENU_STATE_CHANGE, value, false, false)) + drawGraphics(width, height, state) + dispatchEvent(new Event(Event.CHANGE, false, false)) } } - public function get autoComplete():Boolean - { + public function get autoComplete():Boolean { return b_autoComplete; } - public function set autoComplete(value:Boolean):void - { + public function set autoComplete(value:Boolean):void { b_autoComplete = value; } + public function get autoFilter():Boolean { + return b_autoFilter; + } + + public function set autoFilter(value:Boolean):void { + b_autoFilter = value; + } + override protected function drawGraphics(width:int, height:int, state:String):void { super.drawGraphics(width, height, state) var bgGraphics:Graphics = graphics - var colour:uint, colourAlpha:Number + var color:uint, colorAlpha:Number if(enabled) { - colour = uint(getStyle(state)) + color = uint(getStyle(state)) } else { - colour = uint(getStyle(DefaultStyle.DISABLED)) + color = uint(getStyle(DefaultStyle.DISABLED)) } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF - cmpi_activeItem.width = width - 20 - if(width < 20) { - cmpi_activeItem.width = width + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + cmpi_activeItem.width = width - (24 + cmpi_activeItem.x) + if(width < 24) { + cmpi_activeItem.width = width - cmpi_activeItem.x } cmpi_activeItem.height = height - 4 var textHeight:int = cmpi_activeItem.textHeight + 4 @@ -514,52 +571,41 @@ package syncomps } bgGraphics.clear(); bgGraphics.lineStyle(1) - bgGraphics.beginFill(colour, colourAlpha) + bgGraphics.beginFill(color, colorAlpha) bgGraphics.drawRect(0, 0, width - 1, height - 1) bgGraphics.endFill() bgGraphics.beginFill(0, 1) if (menuOpen) { bgGraphics.drawTriangles(new [width - 12, height * 0.45, width - 16, height * 0.55, width - 8, height * 0.55]) - bgGraphics.endFill() if (stage) { var stagePt:Point, basePt:Point = new Point() var menuWidth:int, menuHeight:int; var sideWidth:int; - cmpi_list.hideScrollBars() cmpi_list.resizeHeight() - cmpi_list.resizeWidth() basePt.setTo(0, height - 1) stagePt = localToGlobal(basePt) sideWidth = stage.stageWidth - stagePt.x menuHeight = stage.stageHeight - stagePt.y + cmpi_list.displayScrollBars(false) if (menuHeight < cmpi_list.height && (stagePt.y / menuHeight) > 0.75) { menuHeight = cmpi_list.height - if (stagePt.y < menuHeight) - { + if (stagePt.y < menuHeight) { menuHeight = stagePt.y - cmpi_list.displayScrollBars(false) } basePt.setTo(0, 1 - menuHeight) stagePt = localToGlobal(basePt) } cmpi_list.y = stagePt.y - menuWidth = cmpi_list.width + 4 - if(menuWidth < width - 8) { - menuWidth = width - 8 - } - basePt.setTo((width - 8) - menuWidth, 0) + menuWidth = width - 8 + basePt.setTo(0, 0) stagePt = localToGlobal(basePt) - if (menuWidth < sideWidth) - { - basePt.setTo(0, 0) - stagePt = localToGlobal(basePt) - } - else if(menuWidth > stage.stageWidth - stagePt.x) { + if(menuWidth > stage.stageWidth - stagePt.x) { menuWidth = stage.stageWidth - stagePt.x } + if (stagePt.x < 0) { menuWidth += stagePt.x @@ -587,7 +633,7 @@ package syncomps protected function drawMenu(width:int, maxHeight:int):void { var height:int = maxHeight; - var reqHeight:int = (cmpi_list.numItems * cmpi_list.rowHeight) + 2 + var reqHeight:int = (cmpi_list.numItems * cmpi_list.cellSize) + 2 if(reqHeight < maxHeight) { height = reqHeight } @@ -597,6 +643,36 @@ package syncomps stage.addChild(cmpi_list) } } + + /* PROTECTED GETTERS AND SETTERS */ + + protected function get activeItem():TextInput { + return cmpi_activeItem; + } + + protected function set activeItem(value:TextInput):void { + cmpi_activeItem = value; + } + + protected function get filtering():Boolean { + return b_filtering; + } + + protected function set filtering(value:Boolean):void { + b_filtering = value; + } + + protected function get dropDown():List { + return cmpi_list; + } + + protected function set dropDown(value:List):void { + cmpi_list = value; + } + + public function get list():List { + return cmpi_list + } } } \ No newline at end of file diff --git a/src/syncomps/HBox.as b/src/syncomps/HBox.as new file mode 100644 index 0000000..d2e501b --- /dev/null +++ b/src/syncomps/HBox.as @@ -0,0 +1,284 @@ +package syncomps +{ + import flash.display.DisplayObject; + import flash.display.Sprite; + import syncomps.data.DataElement; + import syncomps.data.DataProvider; + import syncomps.events.DataProviderEvent; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.styles.DefaultStyle; + import syncomps.styles.ScrollPaneStyle; + /** + * ... + * @author Gimmick + */ + public class HBox extends SynComponent + { + protected static var DEFAULT_STYLE:Class = DefaultStyle + + private var dp_items:DataProvider + + private var cl_scrollPane:ScrollPane; + private var spr_contents:Sprite; + private var num_spacing:Number; + private var num_xPadding:Number; + private var num_yPadding:Number; + public function HBox() { + init() + } + + private function init():void + { + tabChildren = false; + spr_contents = new Sprite() + cl_scrollPane = new ScrollPane() + dataProvider = new DataProvider() + cl_scrollPane.source = spr_contents + cl_scrollPane.x = cl_scrollPane.y = 1 + num_spacing = num_xPadding = num_yPadding = 0 + + cl_scrollPane.setStyle(ScrollPaneStyle.SCROLL_POLICY, ScrollPaneStyle.POLICY_HORIZONTAL) + cl_scrollPane.displayScrollBars(false) + + addChild(cl_scrollPane) + drawGraphics(64, 64, DefaultStyle.BACKGROUND) + } + + override public function getDefaultStyle():Class { + return DEFAULT_STYLE + } + + override public function setDefaultStyle(styleClass:Class):void { + DEFAULT_STYLE = styleClass + } + + public function get dataProvider():DataProvider { + return dp_items + } + + public function set dataProvider(provider:DataProvider):void + { + if(provider && provider == dp_items) { + return; + } + if (dp_items) + { + dp_items.removeEventListener(DataProviderEvent.ITEM_ADDED, updateListOnEvent) + dp_items.removeEventListener(DataProviderEvent.ITEM_REMOVED, updateListOnEvent) + dp_items.removeEventListener(DataProviderEvent.DATA_REFRESH, updateListOnEvent) + } + dp_items = provider + if (provider) + { + provider.addEventListener(DataProviderEvent.ITEM_REMOVED, updateListOnEvent, false, 0, true) + provider.addEventListener(DataProviderEvent.DATA_REFRESH, updateListOnEvent, false, 0, true) + provider.addEventListener(DataProviderEvent.ITEM_ADDED, updateListOnEvent, false, 0, true) + } + rebuildList(0) + } + + private function updateListOnEvent(evt:DataProviderEvent):void + { + rebuildList(evt.index) + dispatchEvent(evt) + } + + private function rebuildList(start:uint):void + { + if (dp_items) + { + spr_contents.removeChildren(dp_items.numItems) + dp_items.forEach(function addChildren(item:DisplayObject, index:int, array:Array):void { + spr_contents.addChild(item) + }); + } + cl_scrollPane.refreshPane() + drawGraphics(width, height, state) + } + + override public function get height():Number { + return cl_scrollPane.height + cl_scrollPane.y + 1 + } + + override public function get width():Number { + return cl_scrollPane.width + cl_scrollPane.x + 1 + } + + override protected function drawGraphics(width:int, height:int, state:String):void + { + super.drawGraphics(width, height, state) + graphics.clear() + var color:uint = uint(getStyle(state)), colorAlpha:Number + if (!enabled) { + color = uint(getStyle(DefaultStyle.DISABLED)) + } + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + graphics.lineStyle(1, 0, colorAlpha) + graphics.beginFill(color, colorAlpha) + graphics.drawRect(0, 0, width - 1, height - 1) + cl_scrollPane.height = height - 2; + cl_scrollPane.width = width - 2; + var currX:Number = num_xPadding + const ySpace:Number = num_yPadding * 2 + dp_items.forEach(function alignItems(item:DisplayObject, index:int, array:Array):void + { + item.height = height - ySpace + item.y = num_yPadding + item.x = currX + + currX += item.width + num_spacing + }, this); + } + + public function resizeWidth():void + { + var maxWidth:int; + dp_items.forEach(function resizeAll(item:DisplayObject, index:int, array:Array):void + { + if(item is IAutoResize) { + (item as IAutoResize).resizeWidth(); + } + + if(item.width > maxWidth) { + maxWidth = item.width + } + }, this); + + drawGraphics(maxWidth, height, state) + } + + public function resizeHeight():void + { + var totalHeight:int + const spacing:Number = num_spacing; + dp_items.forEach(function resizeAll(item:DisplayObject, index:int, array:Array):void + { + if(item is IAutoResize) { + (item as IAutoResize).resizeHeight() + } + + totalHeight += item.height + spacing; + }, this); + drawGraphics(width, totalHeight, state) + } + + override public function unload():void + { + super.unload() + removeChildren() + dataProvider = null; + cl_scrollPane.unload() + spr_contents.removeChildren() + } + + public function displayScrollBars(forceDisplay:Boolean):void { + cl_scrollPane.displayScrollBars(forceDisplay); + } + + public function hideScrollBars():void { + cl_scrollPane.hideScrollBars(); + } + + public function addItem(item:Object):void { + dp_items.addItem(DisplayObject(item)); + } + + public function addItemAt(item:Object, index:int):void { + dp_items.addItemAt(DisplayObject(item), index); + } + + public function addItems(items:Array):void + { + dp_items.addItems(items.filter(function isDisplayObject(item:Object, index:int, array:Array):Boolean { + return item is DisplayObject + })); + } + + public function getItemAt(index:int):DataElement { + return dp_items.getItemAt(index); + } + + public function getItemBy(predicate:Function):DataElement { + return dp_items.getItemBy(predicate); + } + + public function indexOf(searchFunction:Function):int { + return dp_items.indexOf(searchFunction); + } + + public function get items():Array { + return dp_items.items; + } + + public function set items(value:Array):void + { + dp_items.items = value && value.filter(function isDisplayObject(item:Object, index:int, array:Array):Boolean { + return item is DisplayObject + }); + } + + public function get numItems():uint { + return dp_items.numItems; + } + + public function removeItem(item:Object):Object { + return dp_items.removeItem(DisplayObject(item)); + } + + public function removeItemAt(index:int):Object { + return dp_items.removeItemAt(index); + } + + public function removeItems():void { + dp_items.removeItems(); + } + + override public function set enabled(value:Boolean):void + { + if(value != cl_scrollPane.enabled) { + super.enabled = cl_scrollPane.enabled = value + } + } + + public function get spacing():Number { + return num_spacing; + } + + public function set spacing(value:Number):void + { + if (spacing != value) + { + num_spacing = value; + drawGraphics(width, height, state) + } + } + + public function get xPadding():Number { + return num_xPadding; + } + + public function set xPadding(value:Number):void + { + if (xPadding != value) + { + num_xPadding = value; + drawGraphics(width, height, state) + } + } + + public function get yPadding():Number { + return num_yPadding; + } + + public function set yPadding(value:Number):void + { + if (yPadding != value) + { + num_yPadding = value; + drawGraphics(width, height, state) + } + } + } + +} \ No newline at end of file diff --git a/src/syncomps/Label.as b/src/syncomps/Label.as new file mode 100644 index 0000000..75d75cb --- /dev/null +++ b/src/syncomps/Label.as @@ -0,0 +1,243 @@ +package syncomps +{ + import flash.display.DisplayObject; + import flash.display.Sprite; + import flash.events.TextEvent; + import flash.text.TextField; + import flash.text.TextLineMetrics; + import syncomps.events.StyleEvent; + import syncomps.styles.DefaultLabelStyle; + import syncomps.styles.DefaultStyle; + + /** + * ... + * @author Gimmick + */ + public class Label extends SynComponent + { + public static const DEF_WIDTH:uint = 96; + public static const DEF_HEIGHT:uint = 24; + protected static var DEFAULT_STYLE:Class = DefaultLabelStyle + + private var spr_icon:Sprite; + private var tf_label:SkinnableTextField + public function Label() + { + super() + init() + } + + private function init():void + { + tf_label = new SkinnableTextField() + spr_icon = new Sprite() + + mouseChildren = mouseEnabled = tabEnabled = false; + tf_label.selectable = tf_label.multiline = false; + addChild(tf_label) + addChild(spr_icon) + + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) + label = null + } + + override public function getDefaultStyle():Class { + return DEFAULT_STYLE + } + + override public function setDefaultStyle(styleClass:Class):void { + DEFAULT_STYLE = styleClass + } + + private function updateStyles(evt:StyleEvent):void + { + tf_label.setStyle(evt.style, evt.value) + drawGraphics(width, height, state) + } + + public function get iconSize():int { + return int(getStyle(DefaultStyle.ICON_SIZE)) + } + + public function set iconSize(value:int):void { + setStyle(DefaultStyle.ICON_SIZE, value) + } + + override protected function drawGraphics(width:int, height:int, state:String):void + { + if(width < 0 || height < 0) { + return; + } + super.drawGraphics(width, height, state) + graphics.clear() + graphics.beginFill(0, 0) + graphics.drawRect(0, 0, width, height) + graphics.endFill() + var iconSize:int = this.iconSize + var maxPadding:Number = (4 * (1 - Math.pow(1.2, -width))) + var labelPosition:int = int(getStyle(DefaultLabelStyle.LABEL_POSITION)) + switch(labelPosition) + { + case DefaultLabelStyle.LABEL_LEFT: + case DefaultLabelStyle.LABEL_RIGHT: + if(height < iconSize) { + iconSize = height + } + else if((iconSize + maxPadding) > width) { + iconSize = width - maxPadding + } + break; + case DefaultLabelStyle.LABEL_ABOVE: + case DefaultLabelStyle.LABEL_BELOW: + if(iconSize + maxPadding > height) { + iconSize = height - maxPadding + } + else if(iconSize > width) { + iconSize = width + } + break; + } + if (icon && icon.width && icon.height) { + spr_icon.width = spr_icon.height = iconSize + } + else { + maxPadding = 0 + } + tf_label.x = tf_label.y = spr_icon.x = spr_icon.y = 0 + switch(labelPosition) + { + case DefaultLabelStyle.LABEL_LEFT: + spr_icon.x = width - spr_icon.width + case DefaultLabelStyle.LABEL_RIGHT: //fallthrough + spr_icon.y = (height - spr_icon.height) / 2; + break; + case DefaultLabelStyle.LABEL_ABOVE: + spr_icon.y = height - spr_icon.height + case DefaultLabelStyle.LABEL_BELOW: //fallthrough + spr_icon.x = (width - spr_icon.width) / 2; + break; + } + switch(labelPosition) + { + case DefaultLabelStyle.LABEL_RIGHT: + tf_label.x = spr_icon.x + spr_icon.width + maxPadding + tf_label.width = width - tf_label.x + tf_label.height = height + break + case DefaultLabelStyle.LABEL_LEFT: + tf_label.width = spr_icon.x - maxPadding + tf_label.height = height + break; + case DefaultLabelStyle.LABEL_ABOVE: + spr_icon.y = height - (spr_icon.height) + tf_label.height = height - (spr_icon.y + maxPadding) + break; + case DefaultLabelStyle.LABEL_BELOW: + tf_label.height = height - tf_label.y + break; + } + } + + override public function unload():void + { + super.unload() + icon = null + removeChildren() + } + + public function resizeWidth():void + { + tf_label.width = tf_label.getLineMetrics(0).width + 4 + var extraSpace:Number = 0; + if(spr_icon.width) { + extraSpace = 4 * (1 - Math.pow(1.2, -(spr_icon.width + tf_label.width))) + } + drawGraphics(spr_icon.width + tf_label.width + extraSpace, height, state) + } + + private function autoSizeText():void + { + var lineMetrics:TextLineMetrics = tf_label.getLineMetrics(0) + tf_label.height = lineMetrics.height + lineMetrics.descent + tf_label.width = lineMetrics.width + } + + public function resizeHeight():void + { + var maxHeight:int = iconSize + tf_label.height = tf_label.textHeight + 4 + if(maxHeight < tf_label.height) { + maxHeight = tf_label.height + } + drawGraphics(width, maxHeight, state) + } + + public function get textField():TextField { + return tf_label + } + + public function get label():String { + return tf_label.text; + } + + public function set label(value:String):void + { + var prevWidth:Number = width + var prevHeight:Number = height + tf_label.text = value || ""; + autoSizeText() + drawGraphics(prevWidth, prevHeight, state) + } + + public function set htmlLabel(value:String):void + { + var prevWidth:Number = width + var prevHeight:Number = height + tf_label.htmlText = value || ""; + autoSizeText() + drawGraphics(prevWidth, prevHeight, state) + } + + public function get htmlLabel():String { + return tf_label.htmlText + } + + public function get icon():DisplayObject { + return (spr_icon.numChildren && spr_icon.getChildAt(0)) as DisplayObject; + } + + public function set icon(value:DisplayObject):void + { + spr_icon.removeChildren() + if (!value) { + return; + } + + spr_icon.addChild(value); + if (spr_icon.width && spr_icon.height) { + spr_icon.width = spr_icon.height = iconSize + } + drawGraphics(this.width, this.height, state) + } + + public function hideText():void + { + if (tf_label.parent) + { + removeChild(tf_label) + drawGraphics(width, height, state) + } + } + + public function showText():void + { + if (!tf_label.parent) + { + addChild(tf_label) + drawGraphics(width, height, state) + } + } + } + +} \ No newline at end of file diff --git a/src/syncomps/LabeledButton.as b/src/syncomps/LabeledButton.as index f58914e..97a9a87 100644 --- a/src/syncomps/LabeledButton.as +++ b/src/syncomps/LabeledButton.as @@ -2,6 +2,7 @@ package syncomps { import flash.display.Bitmap; import flash.display.BitmapData; + import flash.display.DisplayObject; import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; @@ -12,57 +13,54 @@ package syncomps import flash.geom.Point; import flash.text.TextField; import flash.text.TextFieldAutoSize; + import flash.text.TextFormat; + import flash.text.TextFormatAlign; import flash.ui.Keyboard; import syncomps.events.ButtonEvent; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.interfaces.graphics.IIcon; + import syncomps.interfaces.graphics.ILabel; import syncomps.styles.LabeledButtonStyle; import syncomps.styles.SkinnableTextStyle; import syncomps.styles.Style; import syncomps.styles.DefaultStyle; import syncomps.styles.StyleManager; - [Event(name = "CLICK", type = "syncomps.events.ButtonEvent")] + [Event(name = "synBEButtonClick", type = "syncomps.events.ButtonEvent")] /** * ... * @author Gimmick */ - public class LabeledButton extends SynComponent implements IAutoResize, ILabel + public class LabeledButton extends SynComponent implements IAutoResize, ILabel, IIcon { public static const DEF_WIDTH:int = 96 public static const DEF_HEIGHT:int = 32; protected static var DEFAULT_STYLE:Class = LabeledButtonStyle - private var tf_label:SkinnableTextField; - private var bmp_icon:Bitmap; + private var cmpi_label:Label private var b_emphasized:Boolean; - private var spr_group:Sprite; private var b_dispatchClick:Boolean; - private var num_maxWidth:Number; + private var shp_emphasizedOverlay:Shape public function LabeledButton() { init(); } private function init():void { - bmp_icon = new Bitmap() - spr_group = new Sprite() - tf_label = new SkinnableTextField() - StyleManager.unregister(tf_label) + cmpi_label = new Label() + shp_emphasizedOverlay = new Shape() + StyleManager.unregister(cmpi_label) - spr_group.addChild(bmp_icon) - spr_group.addChild(tf_label) - spr_group.x = 4; - tf_label.multiline = tf_label.enabled = tf_label.selectable = false; + cmpi_label.x = 4; drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) label = null; - showText() - addChild(spr_group) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + addChild(cmpi_label) + addChild(shp_emphasizedOverlay) + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) addEventListener(MouseEvent.CLICK, dispatchClickEvent, false, 0, true) addEventListener(MouseEvent.MOUSE_DOWN, changeState, false, 0, true) addEventListener(MouseEvent.MOUSE_UP, changeState, false, 0, true) @@ -76,15 +74,19 @@ package syncomps private function updateStyles(evt:StyleEvent):void { - tf_label.setStyle(evt.style, evt.value) - num_maxWidth = tf_label.getLineMetrics(0).width + 4 + var prevWidth:int = this.width, prevHeight:int = this.height + cmpi_label.setStyle(evt.style, evt.value) + + cmpi_label.resizeWidth() + cmpi_label.resizeHeight() + drawGraphics(prevWidth, prevHeight, state) } private function dispatchClickEvent(evt:Event):void { if (evt.type == MouseEvent.CLICK || b_dispatchClick) { - drawGraphics(width, height, DefaultStyle.BACKGROUND); + drawGraphics(width, height, DefaultStyle.HOVER); dispatchEvent(new ButtonEvent(ButtonEvent.CLICK, true, false)) } b_dispatchClick = false @@ -99,20 +101,12 @@ package syncomps } } - public function set label(text:String):void - { - var prevWidth:int = width; - var prevHeight:int = height; - tf_label.text = '' - if(text && text.length) { - tf_label.text = text - } - num_maxWidth = tf_label.getLineMetrics(0).width + 4 - drawGraphics(prevWidth, prevHeight, str_state) + public function set label(text:String):void { + cmpi_label.label = text } public function get label():String { - return tf_label.text + return cmpi_label.label } public function set emphasized(value:Boolean):void @@ -120,25 +114,17 @@ package syncomps if (b_emphasized != value) { b_emphasized = value - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } } public function get emphasized():Boolean { return b_emphasized } - public function set icon(bitmap:BitmapData):void + public function set icon(icon:DisplayObject):void { - var width:int = this.width - var height:int = this.height - bmp_icon.bitmapData = bitmap - tf_label.x = 0; - if (bmp_icon.width) - { - bmp_icon.width = bmp_icon.height = iconSize - tf_label.x = bmp_icon.width + 4; - } - drawGraphics(width, height, str_state) + cmpi_label.icon = icon + drawGraphics(width, height, state) } public function get iconSize():int { @@ -149,8 +135,8 @@ package syncomps setStyle(DefaultStyle.ICON_SIZE, value) } - public function get icon():BitmapData { - return bmp_icon.bitmapData + public function get icon():DisplayObject { + return cmpi_label.icon } private function changeState(evt:Event):void @@ -174,21 +160,18 @@ package syncomps public function resizeWidth():void { - tf_label.autoSize = TextFieldAutoSize.LEFT - var widthVal:Number = tf_label.width - if(bmp_icon.bitmapData && bmp_icon.parent) { - widthVal += bmp_icon.bitmapData.width + 16 - } - tf_label.autoSize = TextFieldAutoSize.NONE - width = widthVal + cmpi_label.resizeWidth() + width = cmpi_label.width + 16 } - public function resizeHeight():void { - height = tf_label.textHeight + 16 + public function resizeHeight():void + { + cmpi_label.resizeHeight() + height = cmpi_label.height + 16 } public function get textField():TextField { - return tf_label + return cmpi_label.textField } override public function getDefaultStyle():Class { @@ -197,49 +180,46 @@ package syncomps override public function setDefaultStyle(styleClass:Class):void { DEFAULT_STYLE = styleClass } + override protected function drawGraphics(width:int, height:int, state:String):void { - super.drawGraphics(width, height, state) - var colour:uint = uint(getStyle(state)), colourAlpha:Number; - var sizeShift:int = int(enabled && emphasized) + if(width < 0 || height < 0) { + return; + } + graphics.clear() + shp_emphasizedOverlay.graphics.clear() + super.drawGraphics(width, height, state) + var color:uint = uint(getStyle(state)), colorAlpha:Number; if (!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) - } - else if (emphasized) { - graphics.lineStyle(1, uint(getStyle(LabeledButtonStyle.EMPHASIZED_LINE_COLOR))) + color = uint(getStyle(DefaultStyle.DISABLED)) } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF - graphics.beginFill(colour, colourAlpha) - graphics.drawRect(0, 0, width - sizeShift, height - sizeShift); + + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + graphics.beginFill(color, colorAlpha) + graphics.drawRect(0, 0, width, height); graphics.endFill() - bmp_icon.x = 0 - var iconSpacing:int = 0; - if (bmp_icon.width && bmp_icon.height) { - iconSpacing = bmp_icon.width + cmpi_label.resizeWidth() + cmpi_label.resizeHeight() + if(cmpi_label.width > width) { + cmpi_label.width = width } - - tf_label.height = height - if(tf_label.textHeight && tf_label.height >= tf_label.textHeight + 4) { - tf_label.height = tf_label.textHeight + 4 + if(cmpi_label.height > height) { + cmpi_label.height = height } - tf_label.width = num_maxWidth - bmp_icon.y = (tf_label.height - bmp_icon.height) * 0.5 - if (tf_label.width > width - (8 + iconSpacing)) { - tf_label.width = width - (8 + iconSpacing) - } - spr_group.x = (width - spr_group.width) * 0.5 - spr_group.y = (height - spr_group.height) * 0.5 + cmpi_label.x = int((width - cmpi_label.width) * 0.5) + cmpi_label.y = int((height - cmpi_label.height) * 0.5) if (emphasized && enabled) { - graphics.lineStyle(undefined) - graphics.beginFill(uint(getStyle(LabeledButtonStyle.EMPHASIZED_LINE_COLOR)), 1) - graphics.drawTriangles(new [width - sizeShift, height * 0.25, width * 0.95, height * 0.5, width - sizeShift, height * 0.75]) - graphics.drawTriangles(new [sizeShift, height * 0.25, width * 0.05, height * 0.5, sizeShift, height * 0.75]) - graphics.endFill() + shp_emphasizedOverlay.graphics.lineStyle(1, uint(getStyle(LabeledButtonStyle.EMPHASIZED_LINE_COLOR))) + shp_emphasizedOverlay.graphics.drawRect(0, 0, width - 1, height - 1) + shp_emphasizedOverlay.graphics.beginFill(uint(getStyle(LabeledButtonStyle.EMPHASIZED_LINE_COLOR)), 1) + shp_emphasizedOverlay.graphics.drawTriangles(new [width - 1, height * 0.25, width * 0.95, height * 0.5, width - 1, height * 0.75]) + shp_emphasizedOverlay.graphics.drawTriangles(new [1, height * 0.25, width * 0.05, height * 0.5, 1, height * 0.75]) + shp_emphasizedOverlay.graphics.endFill() } } override public function unload():void @@ -256,22 +236,12 @@ package syncomps removeEventListener(KeyboardEvent.KEY_DOWN, startDispatchClickEvent) } - public function hideText():void - { - if (tf_label.parent) { - spr_group.removeChild(tf_label) - } + public function hideText():void { + cmpi_label.hideText() } public function showText():void { - spr_group.addChild(tf_label) - } - - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) + cmpi_label.showText() } } diff --git a/src/syncomps/List.as b/src/syncomps/List.as index 4a7855d..8e63414 100644 --- a/src/syncomps/List.as +++ b/src/syncomps/List.as @@ -1,34 +1,53 @@ package syncomps { + import flash.display.BitmapData; import flash.display.BlendMode; + import flash.display.DisplayObject; import flash.events.Event; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.geom.ColorTransform; + import flash.geom.Rectangle; import flash.ui.Keyboard; import syncomps.data.DataElement; import syncomps.data.DataProvider; import syncomps.events.DataProviderEvent; - import syncomps.events.ListCellEvent; + import syncomps.events.ListEvent; import flash.display.Bitmap; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Point; import syncomps.ScrollPane; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; + import syncomps.interfaces.IStyleDefinition; + import syncomps.interfaces.IStyleInternal; + import syncomps.interfaces.graphics.IAutoResize; import syncomps.interfaces.IDataProvider; + import syncomps.interfaces.graphics.IIcon; + import syncomps.interfaces.graphics.ILabel; + import syncomps.interfaces.ISynComponent; import syncomps.styles.DefaultListStyle; import syncomps.styles.ScrollPaneStyle; import syncomps.styles.Style; import syncomps.styles.DefaultStyle; [Event(name="change", type="flash.events.Event")] - [Event(name="CELL_CLICK", type="syncomps.events.ListCellEvent")] - [Event(name="MENU_STATE_CHANGE", type="syncomps.events.ComboBoxEvent")] - [Event(name="DATA_REFRESH", type="syncomps.events.DataProviderEvent")] - [Event(name="ITEM_ADDED", type="syncomps.events.DataProviderEvent")] - [Event(name = "ITEM_REMOVED", type = "syncomps.events.DataProviderEvent")] + /** + * Dispatched when a cell is clicked. + */ + [Event(name = "synLCECellClick", type = "syncomps.events.ListEvent")] + /** + * Dispatched when the dataProvider property is changed. + */ + [Event(name = "synDPEDataRefresh", type = "syncomps.events.DataProviderEvent")] + /** + * Dispatched when an item is added to the list. + */ + [Event(name = "synDPEItemAdded", type = "syncomps.events.DataProviderEvent")] + /** + * Dispatched when an item is removed from the list. + */ + [Event(name = "synDPEItemRemoved", type = "syncomps.events.DataProviderEvent")] /** * ... @@ -38,15 +57,19 @@ package syncomps { protected static var DEFAULT_STYLE:Class = DefaultListStyle - protected var dp_items:DataProvider; - protected var vec_list:Vector. + private var dp_items:DataProvider + private var vec_list:Vector. + private var fn_iconGenerator:Function; private var cl_scrollPane:ScrollPane; private var spr_contents:Sprite; private var i_selectedIndex:int; - private var i_cellHeight:int; - public function List() - { + private var i_cellSize:int; + private var i_columnWidth:int; + private var i_maxColumnsOrRows:int; + private var i_maxCellPerpendicularSize:int + private var cl_childStyleDefinition:IStyleInternal + public function List() { init() } @@ -54,13 +77,14 @@ package syncomps { tabChildren = false; i_selectedIndex = -1 - i_cellHeight = ListCell.DEF_HEIGHT - vec_list = new Vector.() + i_cellSize = ListCell.DEF_HEIGHT + vec_list = new Vector.() + cl_childStyleDefinition = new GenericStyle() cl_scrollPane = new ScrollPane() spr_contents = new Sprite() cl_scrollPane.x = cl_scrollPane.y = 1 cl_scrollPane.source = spr_contents - cl_scrollPane.lineScrollSize = i_cellHeight + cl_scrollPane.lineScrollSize = i_cellSize cl_scrollPane.setStyle(ScrollPaneStyle.SCROLL_POLICY, ScrollPaneStyle.POLICY_VERTICAL) cl_scrollPane.displayScrollBars(false) @@ -68,20 +92,30 @@ package syncomps addEventListener(FocusEvent.FOCUS_IN, selectItem) addEventListener(KeyboardEvent.KEY_DOWN, selectItem) addEventListener(KeyboardEvent.KEY_UP, passEventToCell) + cl_childStyleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateCellStyles) + maxColumnsOrRows = 1 drawGraphics(64, 64, DefaultStyle.BACKGROUND) } + private function updateCellStyles(evt:StyleEvent):void + { + vec_list.forEach(function updateStyles(item:DisplayObject, index:int, array:Vector.):void { + (item is ISynComponent) && (item as ISynComponent).setStyle(evt.style, evt.value) + }) + } + private function updateListOnChange(evt:Event):void { - for (var i:uint = 0; i < dp_items.length; ++i) { - setupListCell(vec_list[i], dp_items.getItemAt(i), (i & 1) != 0); - } + dp_items.forEach(function setupCells(item:Object, index:int, array:Array):void { + setupListCell(vec_list[index], item, darken(index)); + }); } override public function getDefaultStyle():Class { return DEFAULT_STYLE } + override public function setDefaultStyle(styleClass:Class):void { DEFAULT_STYLE = styleClass } @@ -123,42 +157,6 @@ package syncomps } } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) - } - - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - - public function get numItems():uint { - return dp_items.length - } - public function addItem(item:Object):void { - addItemAt(item, dp_items.length) - } - public function removeItem(item:Object):Object { - return dp_items.removeItem(item) - } - public function removeItemAt(index:int):Object { - return dp_items.removeItemAt(index) - } - public function addItemAt(item:Object, index:int):void { - dp_items.addItemAt(item, index) - } - public function getItemAt(index:int):DataElement { - return dp_items.getItemAt(index) - } - public function addItems(items:Array):void { - dp_items.addItems(items) - } - public function removeAll():void { - dp_items.removeAll() - } - public function get items():Array { - return dp_items.items - } - public function get dataProvider():DataProvider { return dp_items } @@ -213,136 +211,153 @@ package syncomps } } break; - default: - break; } dispatchEvent(evt) } - public function get rowHeight():int { - return i_cellHeight; + public function get maxCellPerpendicularSize():int { + return i_maxCellPerpendicularSize } - public function set rowHeight(value:int):void + public function set maxCellPerpendicularSize(value:int):void { - i_cellHeight = value; - cl_scrollPane.lineScrollSize = value + if (value != i_maxCellPerpendicularSize) + { + i_maxCellPerpendicularSize = value + drawGraphics(width, height, state) + } } - public function get selectedIndex():int + public function get cellSize():int { + return i_cellSize; + } + + public function set cellSize(value:int):void { + i_cellSize = value; + cl_scrollPane.lineScrollSize = value + drawGraphics(width, height, state) + } + + public function get selectedIndex():int { return i_selectedIndex; } - public function set selectedIndex(value:int):void - { + public function set selectedIndex(value:int):void { setSelectedCell(value) } - public function get iconFunction():Function - { + public function get iconFunction():Function { return fn_iconGenerator; } public function set listDirection(direction:String):void { setStyle(DefaultListStyle.LIST_DIRECTION, direction) - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } public function get listDirection():String { return String(getStyle(DefaultListStyle.LIST_DIRECTION)) } + public function set maxColumnsOrRows(max:int):void + { + if(max < 1) { + max = 1 + } + if (max != i_maxColumnsOrRows) + { + i_maxColumnsOrRows = max + rebuildList(0) + } + } + + public function get maxColumnsOrRows():int { + return i_maxColumnsOrRows + } + public function set iconFunction(value:Function):void { fn_iconGenerator = value; } private function rebuildList(start:uint):void { - var listCell:ListCell; + var listCell:DisplayObject if (dp_items) { var currItem:DataElement; - while (vec_list.length > dp_items.length) - { - listCell = vec_list.pop() - listCell.removeEventListener(MouseEvent.CLICK, dispatchClick) - spr_contents.removeChild(listCell) - listCell.unload() + while (vec_list.length > dp_items.numItems) { + unloadCell(vec_list.pop()) } for (var i:int = start; i < vec_list.length; ++i) { - setupListCell(vec_list[i], dp_items.getItemAt(i).objectProperty, (i & 1) != 0) + setupListCell(vec_list[i], dp_items.getItemAt(i).objectProperty, darken(i)) } - while (vec_list.length < dp_items.length) + while (vec_list.length < dp_items.numItems) { + var object:Object = dp_items.getItemAt(vec_list.length).objectProperty listCell = createListCell(); - listCell.index = vec_list.length; - setupListCell(listCell, dp_items.getItemAt(vec_list.length).objectProperty, (vec_list.length & 1) != 0) + setupListCell(listCell, object, darken(vec_list.length)) listCell.addEventListener(MouseEvent.CLICK, dispatchClick, false, 0, true) vec_list.push(listCell) spr_contents.addChild(listCell) } } - else while (vec_list.length) - { - listCell = vec_list.pop() - listCell.removeEventListener(MouseEvent.CLICK, dispatchClick) - spr_contents.removeChild(listCell) - listCell.unload() + else while (vec_list.length) { + unloadCell(vec_list.pop()) } cl_scrollPane.refreshPane() - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } - private function setupListCell(listCell:ListCell, objectProperties:Object, darkenCell:Boolean):void + private function setupListCell(listCell:DisplayObject, objectProperties:Object, darkenCell:Boolean):void { if (darkenCell) { listCell.transform.colorTransform = new ColorTransform(.95, .95, .95) //darken odd rows } - if(objectProperties.hasOwnProperty("label")) { - listCell.label = objectProperties.label + else { + listCell.transform.colorTransform = new ColorTransform() } - if(objectProperties.hasOwnProperty("icon") && objectProperties.icon) { - listCell.icon = objectProperties.icon + + if(objectProperties.hasOwnProperty("label") && listCell is ILabel) { + (listCell as ILabel).label = objectProperties.label } - else if (fn_iconGenerator != null) { - listCell.icon = fn_iconGenerator.call(listCell, objectProperties) + + var iconCell:IIcon = listCell as IIcon + if (iconCell) + { + if(objectProperties.hasOwnProperty("icon")) { + iconCell.icon = objectProperties.icon + } + else { + iconCell.icon = (fn_iconGenerator && fn_iconGenerator.call(listCell, objectProperties)) as DisplayObject + } } - else { - listCell.icon = null + + var styledCell:IStyleDefinition = listCell as IStyleDefinition + if (styledCell) { + styledCell.applyStyle(cl_childStyleDefinition) } } - private function createListCell():ListCell { - return ListCell(new (getStyle(DefaultListStyle.CELL_RENDERER) as Class)()) + private function createListCell():DisplayObject { + return (new (getStyle(DefaultListStyle.CELL_RENDERER) as Class)()) as DisplayObject } private function dispatchClick(evt:MouseEvent):void { - var index:int = (evt.currentTarget as ListCell).index - addEventListener(ListCellEvent.CELL_CLICK, setSelectedCellOnEvent, false, 0, true) - dispatchEvent(new ListCellEvent(ListCellEvent.CELL_CLICK, index, dp_items.getItemAt(index), false, true)) - } - - private function setSelectedCellOnEvent(evt:ListCellEvent):void - { - removeEventListener(ListCellEvent.CELL_CLICK, setSelectedCellOnEvent) - if (!evt.isDefaultPrevented()) { - setSelectedCell(evt.index) + var index:int = vec_list.indexOf(evt.currentTarget as DisplayObject) + if(dispatchEvent(new ListEvent(ListEvent.CELL_CLICK, index, dp_items.getItemAt(index), false, true))) { + setSelectedCell(index) } } private function setSelectedCell(index:uint):void { - for (var i:uint = 0; i < vec_list.length; ++i) { - vec_list[i].selected = false; - } if (index < vec_list.length) { - vec_list[index].selected = true; - var scaledIndex:int = i_cellHeight * index; - if ((scaledIndex + i_cellHeight) >= int(cl_scrollPane.verticalScrollPosition + height) || scaledIndex < cl_scrollPane.verticalScrollPosition) { + var scaledIndex:int = i_cellSize * index; + if ((scaledIndex + i_cellSize) >= int(cl_scrollPane.verticalScrollPosition + height) || scaledIndex < cl_scrollPane.verticalScrollPosition) { cl_scrollPane.verticalScrollPosition = scaledIndex } } @@ -361,35 +376,92 @@ package syncomps { super.drawGraphics(width, height, state) graphics.clear() - graphics.lineStyle(1) - var colour:uint = uint(getStyle(state)), colourAlpha:Number + var color:uint = uint(getStyle(state)), colorAlpha:Number if (!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) + color = uint(getStyle(DefaultStyle.DISABLED)) } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF - graphics.beginFill(colour, colourAlpha) + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + graphics.lineStyle(1, 0, colorAlpha) + graphics.beginFill(color, colorAlpha) graphics.drawRect(0, 0, width - 1, height - 1) - const cellHeight:int = i_cellHeight + const cellSize:int = i_cellSize cl_scrollPane.height = height - 2; cl_scrollPane.width = width - 2; - var currX:int - for (var i:uint = 0; i < vec_list.length; ++i) + var i:uint, currPos:int, max:Number = 0; + var barWidth:int = width, barHeight:int = height + if(cl_scrollPane.verticalScrollBar.parent) { + barWidth -= cl_scrollPane.verticalScrollBar.width + } + if(cl_scrollPane.horizontalScrollBar.parent) { + barHeight -= cl_scrollPane.horizontalScrollBar.height + } + while(i < vec_list.length) { - var cell:ListCell = vec_list[i] - if (listDirection == DefaultListStyle.HORIZONTAL) + for (var j:uint = 0; i < vec_list.length && j < maxColumnsOrRows; ++j, ++i) { - cell.x = currX - cell.resizeWidth(); - currX += cell.width; - cell.height = height - 2; + var cell:DisplayObject = vec_list[i] + if (listDirection == DefaultListStyle.HORIZONTAL) + { + cell.height = (barHeight / maxColumnsOrRows) - 2; + if(maxCellPerpendicularSize > 0 && cell.height > maxCellPerpendicularSize) { + cell.height = maxCellPerpendicularSize + } + cell.y = cell.height * j; + cell.x = currPos + cell.width = cellSize + if(cell.width > max) { + max = cell.width + } + } + else if (listDirection == DefaultListStyle.VERTICAL) + { + cell.width = (barWidth / maxColumnsOrRows) - 2; + if(maxCellPerpendicularSize > 0 && cell.width > maxCellPerpendicularSize) { + cell.width = maxCellPerpendicularSize + } + cell.x = j * cell.width; + cell.y = currPos + cell.height = cellSize; + if(cell.height > max) { + max = cell.height + } + } } - else if (listDirection == DefaultListStyle.VERTICAL) - { - cell.y = i * cellHeight; - cell.height = cellHeight; - cell.width = width - 2; + currPos += max + } + } + + public function resizeWidth():void + { + var maxWidth:int; + vec_list.forEach(function resizeItems(item:DisplayObject, index:int, array:Vector.):void + { + if(item is IAutoResize) { + (item as IAutoResize).resizeWidth(); + } + + if(maxWidth < item.width) { + maxWidth = item.width } + }); + if (listDirection == DefaultListStyle.VERTICAL) { + drawGraphics(maxWidth * maxColumnsOrRows, height, state) + } + else + { + var columnCount:int = Math.ceil(vec_list.length / maxColumnsOrRows) + drawGraphics(maxWidth * columnCount, height, state) + } + } + + public function resizeHeight():void + { + if (listDirection == DefaultListStyle.VERTICAL) { + drawGraphics(width, vec_list.length * cellSize / maxColumnsOrRows, state) + } + else { + drawGraphics(width, maxCellPerpendicularSize * maxColumnsOrRows, state) } } @@ -400,60 +472,130 @@ package syncomps dataProvider = null; cl_scrollPane.unload() spr_contents.removeChildren() - for (var i:uint = 0; i < vec_list.length; ++i) - { - var listCell:ListCell = vec_list[i] - listCell.removeEventListener(MouseEvent.CLICK, dispatchClick) - listCell.unload() - } + vec_list.forEach(function unloadItems(item:DisplayObject, index:int, array:Vector.):void { + unloadCell(item) + }); vec_list.length = 0; i_selectedIndex = -1; - i_cellHeight = ListCell.DEF_HEIGHT; + i_cellSize = ListCell.DEF_HEIGHT; } - public function resizeWidth():void + private function unloadCell(listCell:DisplayObject):void { - var maxWidth:int; - for (var i:uint = 0; i < vec_list.length; ++i) - { - var listCell:ListCell = vec_list[i]; - listCell.resizeWidth() - if(maxWidth < listCell.width) { - maxWidth = listCell.width - } + listCell.removeEventListener(MouseEvent.CLICK, dispatchClick) + if (listCell.parent == spr_contents) { + spr_contents.removeChild(listCell) + } + if (listCell is ISynComponent) { + (listCell as ISynComponent).unload() } - drawGraphics(maxWidth, height, str_state) } - - public function resizeHeight():void + public function calculateCellSize():int { - if (listDirection == DefaultListStyle.VERTICAL) { - drawGraphics(width, vec_list.length * i_cellHeight, str_state) - } - else { - drawGraphics(width, i_cellHeight, str_state) + const maxFit:Number = Math.ceil(vec_list.length / maxColumnsOrRows) + if (listDirection == DefaultListStyle.HORIZONTAL) { + return width / maxFit } + return height / maxFit } public function displayScrollBars(forceDisplay:Boolean):void { cl_scrollPane.displayScrollBars(forceDisplay); } - public function hideScrollBars():void - { + public function hideScrollBars():void { cl_scrollPane.hideScrollBars(); } + public function setCellStyle(style:Object, value:Object):void { + cl_childStyleDefinition.setStyle(style, value); + } + + public function getCellStyle(style:Object):Object { + return cl_childStyleDefinition.getStyle(style); + } + + /* DELEGATE syncomps.interfaces.IDataProvider */ + + public function addItem(item:Object):void { + dp_items.addItem(item); + } + + public function addItemAt(item:Object, index:int):void { + dp_items.addItemAt(item, index); + } + + public function addItems(items:Array):void { + dp_items.addItems(items); + } + + public function getItemAt(index:int):DataElement { + return dp_items.getItemAt(index); + } + + public function getItemBy(predicate:Function):DataElement { + return dp_items.getItemBy(predicate); + } + + public function indexOf(searchFunction:Function, fromIndex:int = 0):int { + return dp_items.indexOf(searchFunction, fromIndex); + } + + public function get items():Array { + return dp_items.items; + } + + public function set items(value:Array):void { + dp_items.items = value; + } + + public function get numItems():uint { + return dp_items.numItems; + } + + public function removeItem(item:Object):Object { + return dp_items.removeItem(item); + } + + public function removeItemAt(index:int):Object { + return dp_items.removeItemAt(index); + } + + public function removeItems():void { + dp_items.removeItems(); + } + override public function set enabled(value:Boolean):void { if(value == cl_scrollPane.enabled) { return; //no change } - for (var i:uint = 0; i < vec_list.length; ++i) { - vec_list[i].enabled = value; - } super.enabled = cl_scrollPane.enabled = value } + + private function darken(index:int):Boolean { + return index % ((maxColumnsOrRows * 2)) >= maxColumnsOrRows + } } +} + +import syncomps.styles.*; +import syncomps.events.StyleEvent; + +/** + * Generic style class that accepts all attributes. + */ +class GenericStyle extends Style +{ + public function GenericStyle() { + super() + } + + override public function setStyle(style:Object, value:Object):void + { + if(dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGING, style, value, true, true))) { + forceStyle(style, value) + } + } } \ No newline at end of file diff --git a/src/syncomps/ListCell.as b/src/syncomps/ListCell.as index a8f1c34..9539431 100644 --- a/src/syncomps/ListCell.as +++ b/src/syncomps/ListCell.as @@ -2,18 +2,24 @@ package syncomps { import flash.display.Bitmap; import flash.display.BitmapData; + import flash.display.DisplayObject; import flash.display.PixelSnapping; import flash.display.Sprite; import flash.events.Event; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; + import flash.events.TimerEvent; import flash.text.TextField; import flash.text.TextFieldAutoSize; + import flash.text.TextFormat; import flash.ui.Keyboard; + import flash.utils.Timer; + import syncomps.events.ButtonEvent; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.interfaces.graphics.IIcon; + import syncomps.interfaces.graphics.ILabel; import syncomps.styles.DefaultInnerTextStyle; import syncomps.styles.SkinnableTextStyle; import syncomps.styles.Style; @@ -26,17 +32,17 @@ package syncomps * ... * @author Gimmick */ - public class ListCell extends SynComponent implements IAutoResize, ILabel + public class ListCell extends SynComponent implements IAutoResize, ILabel, IIcon { public static const DEF_WIDTH:uint = 96; public static const DEF_HEIGHT:uint = 24; protected static var DEFAULT_STYLE:Class = DefaultInnerTextStyle private var i_index:int; - private var bmp_icon:Bitmap; + private var cmpi_label:Label; private var b_selected:Boolean; + private var cl_scrollTimer:Timer private var b_dispatchClick:Boolean; - private var tf_label:SkinnableTextField public function ListCell() { super() @@ -44,14 +50,13 @@ package syncomps } private function init():void { - tf_label = new SkinnableTextField() - bmp_icon = new Bitmap(null, PixelSnapping.ALWAYS, true) + cmpi_label = new Label() + cl_scrollTimer = new Timer(1000, 1) - tf_label.selectable = tf_label.multiline = tf_label.mouseEnabled = false; b_selected = false; - addChild(tf_label) + addChild(cmpi_label) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) label = null @@ -64,6 +69,11 @@ package syncomps addEventListener(MouseEvent.RELEASE_OUTSIDE, changeState, false, 0, true) addEventListener(KeyboardEvent.KEY_UP, dispatchClickEvent, false, 0, true) addEventListener(KeyboardEvent.KEY_DOWN, startDispatchClickEvent, false, 0, true) + cl_scrollTimer.addEventListener(TimerEvent.TIMER_COMPLETE, changeLabelScrollH, false, 0, true) + } + + private function changeLabelScrollH(evt:TimerEvent):void { + cmpi_label.textField.scrollH = cmpi_label.textField.maxScrollH } override public function getDefaultStyle():Class { @@ -73,8 +83,10 @@ package syncomps DEFAULT_STYLE = styleClass } - private function updateStyles(evt:StyleEvent):void { - tf_label.setStyle(evt.style, evt.value) + private function updateStyles(evt:StyleEvent):void + { + cmpi_label.setStyle(evt.style, evt.value) + drawGraphics(width, height, state) } private function changeState(evt:Event):void @@ -101,7 +113,7 @@ package syncomps { if (b_dispatchClick) { - dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, false)) + dispatchEvent(new ButtonEvent(ButtonEvent.CLICK, true, false)) b_dispatchClick = false } resetBackground() @@ -116,23 +128,6 @@ package syncomps } } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) - } - - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - - public function set selected(value:Boolean):void - { - b_selected = value - resetBackground() - } - public function get selected():Boolean { - return b_selected - } - public function get iconSize():int { return int(getStyle(DefaultStyle.ICON_SIZE)) } @@ -153,42 +148,33 @@ package syncomps override protected function drawGraphics(width:int, height:int, state:String):void { - var colour:uint = uint(getStyle(state)), colourAlpha:Number; + super.drawGraphics(width, height, state) + var color:uint = uint(getStyle(state)), colorAlpha:Number; + var maxPadding:Number = (8 * (1 - Math.pow(1.2, -width))) if (!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) + color = uint(getStyle(DefaultStyle.DISABLED)) } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF - super.drawGraphics(width, height, state) + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + graphics.clear(); - graphics.beginFill(colour, colourAlpha) + graphics.beginFill(color, colorAlpha) graphics.drawRect(0, 0, width, height) graphics.endFill() - tf_label.y = (height - (tf_label.height + 4)) * 0.5 - if (tf_label.y < 0) - { - tf_label.y = 0; - tf_label.height = height - } - bmp_icon.y = (height - (bmp_icon.height)) * 0.5 - if (width > 12 && bmp_icon.bitmapData) - { - addChild(bmp_icon) - bmp_icon.x = 8 - } - else if(bmp_icon.parent) { - removeChild(bmp_icon) - } - if (bmp_icon.parent) { - tf_label.x = bmp_icon.x + bmp_icon.width + 4 - } - else if(width > 8) { - tf_label.x = 8 + + cmpi_label.resizeHeight() + cmpi_label.x = maxPadding + cmpi_label.width = width - cmpi_label.x + if (height < cmpi_label.height) { + cmpi_label.height = height } - else { - tf_label.x = width * 0.25 + cmpi_label.y = (height - cmpi_label.height) * 0.5 + + cl_scrollTimer.reset(); + cmpi_label.textField.scrollH = 0 + if(cmpi_label.textField.maxScrollH && state == DefaultStyle.HOVER) { + cl_scrollTimer.start(); } - tf_label.width = width - tf_label.x } override public function unload():void @@ -209,66 +195,44 @@ package syncomps public function resizeWidth():void { - tf_label.autoSize = TextFieldAutoSize.LEFT - drawGraphics(tf_label.x + tf_label.width + 4, height, str_state) - tf_label.autoSize = TextFieldAutoSize.NONE + cmpi_label.resizeWidth() + drawGraphics(cmpi_label.x + cmpi_label.width + 4, height, state) } public function resizeHeight():void { - var maxHeight:int = bmp_icon.height - if(tf_label.height > maxHeight) { - maxHeight = tf_label.height - } - drawGraphics(width, maxHeight + 4, str_state) + cmpi_label.resizeHeight() + drawGraphics(width, height, state) } public function get textField():TextField { - return tf_label + return cmpi_label.textField } - public function get label():String - { - return tf_label.text; + public function get label():String { + return cmpi_label.label; } - public function set label(value:String):void - { - if (value && value.length) { - tf_label.text = value - } - else { - tf_label.text = " "; - } - tf_label.height = tf_label.textHeight + 4 - if (!(value && value.length)) { - tf_label.text = "" - } + public function set label(value:String):void { + cmpi_label.label = value || ""; } - public function get index():int - { + public function get index():int { return i_index; } - public function set index(value:int):void - { + public function set index(value:int):void { i_index = value; } - public function get icon():BitmapData { - return bmp_icon.bitmapData; + public function get icon():DisplayObject { + return cmpi_label.icon } - public function set icon(value:BitmapData):void + public function set icon(value:DisplayObject):void { - var width:int = this.width - var height:int = this.height - bmp_icon.bitmapData = value; - if (bmp_icon.width && bmp_icon.height) { - bmp_icon.width = bmp_icon.height = iconSize - } - drawGraphics(width, height, str_state) + cmpi_label.icon = value + drawGraphics(width, height, state) } } diff --git a/src/syncomps/NumericStepper.as b/src/syncomps/NumericStepper.as index 1f61d4c..fc9a024 100644 --- a/src/syncomps/NumericStepper.as +++ b/src/syncomps/NumericStepper.as @@ -17,7 +17,6 @@ package syncomps import flash.ui.Keyboard; import flash.utils.Timer; import syncomps.events.StyleEvent; - import syncomps.interfaces.ILabel; import syncomps.styles.DefaultInnerTextStyle; import syncomps.styles.SkinnableTextStyle; import syncomps.styles.Style; @@ -30,7 +29,7 @@ package syncomps * ... * @author Gimmick */ - public class NumericStepper extends SynComponent implements ILabel + public class NumericStepper extends SynComponent { public static const DEF_WIDTH:int = 96 public static const DEF_HEIGHT:int = 32; @@ -74,13 +73,13 @@ package syncomps addChild(spr_downButton) addChild(cmpi_valueField) cmpi_valueField.addEventListener(Event.CHANGE, validateInput, false, 0, true) - cmpi_valueField.setStyle(DefaultInnerTextStyle.BORDER, 0) //no border colour by default - cmpi_valueField.setStyle(DefaultStyle.BACKGROUND, 0) //no background colour when editable - cmpi_valueField.setStyle(DefaultStyle.DISABLED, 0) //no background colour when not editable + cmpi_valueField.setStyle(DefaultInnerTextStyle.BORDER, 0) //no border color by default + cmpi_valueField.setStyle(DefaultStyle.BACKGROUND, 0) //no background color when editable + cmpi_valueField.setStyle(DefaultStyle.DISABLED, 0) //no background color when not editable drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) addEventListener(MouseEvent.CLICK, resetTimer, false, 0, true) addEventListener(KeyboardEvent.KEY_UP, changeState, false, 0, true) addEventListener(KeyboardEvent.KEY_DOWN, changeState, false, 0, true) @@ -99,7 +98,7 @@ package syncomps { switch(evt.style) { - //no border or background colour for these textfields + //no border or background color for these textfields case DefaultStyle.DISABLED: case DefaultStyle.BACKGROUND: case DefaultInnerTextStyle.BORDER: @@ -237,7 +236,7 @@ package syncomps { editing = false value = getNumber(cmpi_valueField.value) - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) dispatchEvent(new Event(Event.CHANGE, false, false)) } } @@ -278,14 +277,6 @@ package syncomps DEFAULT_STYLE = styleClass } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) - } - - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - public function get value():Number { return num_value } @@ -299,7 +290,7 @@ package syncomps else if(num_value < num_min) { num_value = num_min } - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } private function changeValueOnEvent(evt:Event):void @@ -335,15 +326,15 @@ package syncomps override protected function drawGraphics(width:int, height:int, state:String):void { var shapeGraphics:Graphics - var colour:uint, colourAlpha:Number; + var color:uint, colorAlpha:Number; if (enabled) { - colour = uint(getStyle(state)) + color = uint(getStyle(state)) } else { - colour = uint(getStyle(DefaultStyle.DISABLED)) + color = uint(getStyle(DefaultStyle.DISABLED)) } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF super.drawGraphics(width, height, state) if (!editing) { @@ -360,7 +351,7 @@ package syncomps shapeGraphics = graphics shapeGraphics.clear(); shapeGraphics.lineStyle(1) - shapeGraphics.beginFill(colour, colourAlpha) + shapeGraphics.beginFill(color, colorAlpha) shapeGraphics.drawRect(0, 0, width - 1, height - 1) shapeGraphics.endFill() diff --git a/src/syncomps/PieMenu.as b/src/syncomps/PieMenu.as index dffa69d..e93fd3d 100644 --- a/src/syncomps/PieMenu.as +++ b/src/syncomps/PieMenu.as @@ -56,21 +56,23 @@ { var mEvt:MouseEvent = evt as MouseEvent var objects:Array = getObjectsUnderPoint(new Point(mEvt.stageX, mEvt.stageY)) - var index:int; - for (var i:int = objects.length - 1, sliceValue:int = -1; sliceValue == -1 && i >= 0; --i) + var index:int, sliceValue:int = -1 + objects.reverse().some(function findItem(item:DisplayObject, index:int, array:Array):Boolean { - if (!(objects[i] == shp_connectingLines || objects[i] == shp_pieMenuStar)) { - sliceValue = dp_menuItems.indexOfByField("objectProperty", objects[i]); + if (item == shp_connectingLines || item == shp_pieMenuStar) { + return false } - } + else sliceValue = indexOf(function indexByProperty(innerItem:Object, index:int, array:Array):Boolean { + return item == innerItem + }); + + return sliceValue != -1 + }, this); } i_sliceValue = sliceValue var state:String; switch(evt.type) { - case MouseEvent.CLICK: - trace("clicekd", evt.target) - break; case MouseEvent.MOUSE_DOWN: state = DefaultStyle.DOWN break; @@ -83,7 +85,7 @@ break; case Event.CHANGE: default: - state = str_state + state = this.state break; } drawGraphics(width, height, state); @@ -169,23 +171,20 @@ public function showMenu(width:uint, height:uint):void { - var i:uint b_menuOpen = true; addChild(shp_connectingLines) - const numItems:uint = dp_menuItems.length - const itemAngle:Number = 6.28318530718 / numItems //--> 2*PI / numItems const halfWidth:Number = 0.5 * width const halfHeight:Number = 0.5 * height - for (i = 0; i < dp_menuItems.length; ++i) + const itemAngle:Number = (Math.PI * 2) / dp_menuItems.numItems + dp_menuItems.forEach(function position(item:DisplayObject, index:int, array:Array):void { - var angle:Number = itemAngle * i - var currItem:DisplayObject = dp_menuItems.getItemAt(i).objectProperty as DisplayObject - var halfItemHeight:Number = 0.5 * currItem.height - var halfItemWidth:Number = 0.5 * currItem.width - currItem.x = (Math.cos(angle) * (halfWidth - halfItemWidth)) - (halfItemWidth); - currItem.y = (Math.sin(angle) * (halfHeight - halfItemHeight)) - (halfItemHeight); - addChild(currItem) - } + var angle:Number = itemAngle * index + var halfItemWidth:Number = 0.5 * item.width + var halfItemHeight:Number = 0.5 * item.height + item.x = (Math.cos(angle) * (halfWidth - halfItemWidth)) - (halfItemWidth); + item.y = (Math.sin(angle) * (halfHeight - halfItemHeight)) - (halfItemHeight); + addChild(item) + }, this); addChild(shp_pieMenuStar) drawGraphics(width, height, DefaultStyle.BACKGROUND) } @@ -205,11 +204,11 @@ dp_menuItems.addItemAt(DisplayObject(item), index) } - public function addItems(...items):void + public function addItems(items:Array):void { - for (var i:uint = 0; i < items.length; ++i) { - addItem(items[i]) - } + items.forEach(function add(item:DisplayObject, index:int, array:Array):void { + addItem(item) + }); } public function removeItem(item:Object):Object { @@ -224,10 +223,10 @@ return dp_menuItems.getItemAt(index) } - public function removeAll():void + public function removeItems():void { removeChildren() - dp_menuItems.removeAll() + dp_menuItems.removeItems() addChild(shp_connectingLines) addChild(shp_pieMenuStar) } @@ -236,6 +235,10 @@ return dp_menuItems.items; } + public function set items(items:Array):void { + dp_menuItems.items = items + } + public function get numItems():uint { return dp_menuItems.numItems; } @@ -248,5 +251,13 @@ return b_menuOpen; } + public function getItemBy(searchFunction:Function):DataElement { + return dp_menuItems.getItemBy(searchFunction); + } + + public function indexOf(searchFunction:Function, fromIndex:int = 0):int { + return dp_menuItems.indexOf(searchFunction, fromIndex); + } + } } \ No newline at end of file diff --git a/src/syncomps/RadioButton.as b/src/syncomps/RadioButton.as index f8bf532..3902aac 100644 --- a/src/syncomps/RadioButton.as +++ b/src/syncomps/RadioButton.as @@ -2,21 +2,18 @@ package syncomps { import flash.display.Graphics; import flash.display.Shape; - import flash.display.Sprite; import flash.events.Event; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.text.TextField; - import flash.text.TextFieldAutoSize; import flash.ui.Keyboard; + import syncomps.events.ButtonEvent; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.interfaces.graphics.ILabel; import syncomps.styles.DefaultLabelStyle; - import syncomps.styles.Style; import syncomps.styles.DefaultStyle; - import syncomps.styles.StyleManager; [Event(name="click", type="flash.events.MouseEvent")] /** @@ -29,11 +26,11 @@ package syncomps public static const DEF_HEIGHT:int = 32; protected static var DEFAULT_STYLE:Class = DefaultLabelStyle - private var tf_label:SkinnableTextField private var rdg_group:RadioButtonGroup; private var b_dispatchClick:Boolean private var b_selected:Boolean; private var shp_graphic:Shape; + private var cmpi_label:Label; private var obj_data:Object; public function RadioButton() { init() @@ -42,18 +39,17 @@ package syncomps private function init():void { shp_graphic = new Shape() - tf_label = new SkinnableTextField() - StyleManager.unregister(tf_label) - addChild(tf_label) + cmpi_label = new Label() + ////StyleManager.unregister(tf_label) + + addChild(cmpi_label) addChild(shp_graphic) - tf_label.selectable = tf_label.multiline = tf_label.mouseEnabled = false; drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND); selected = false //warning: redraws; place after adding children label = null addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) - addEventListener(MouseEvent.CLICK, selectButton, false, 0, true) addEventListener(MouseEvent.MOUSE_DOWN, changeState, false, 0, true) addEventListener(MouseEvent.RELEASE_OUTSIDE, changeState, false, 0, true) @@ -66,8 +62,10 @@ package syncomps addEventListener(KeyboardEvent.KEY_DOWN, startDispatchClickEvent, false, 0, true) } - private function updateStyles(evt:StyleEvent):void { - tf_label.setStyle(evt.style, evt.value) + private function updateStyles(evt:StyleEvent):void + { + cmpi_label.setStyle(evt.style, evt.value) + drawGraphics(width, height, state) } private function changeState(evt:Event):void @@ -100,7 +98,7 @@ package syncomps if (b_dispatchClick) { redrawButton() - dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, false)) + dispatchEvent(new ButtonEvent(ButtonEvent.CLICK, true, false)) b_dispatchClick = false } } @@ -121,27 +119,14 @@ package syncomps DEFAULT_STYLE = styleClass } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) - } - - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - public function set label(text:String):void { - if (text && text.length) { - tf_label.text = text; - } - else { - tf_label.text = " " - } - drawGraphics(width, height, str_state) + cmpi_label.label = text + drawGraphics(width, height, state) } public function get label():String { - return tf_label.text + return cmpi_label.label } public function set labelPosition(position:int):void { @@ -155,7 +140,7 @@ package syncomps private function selectButton(evt:MouseEvent):void { selected = true - drawGraphics(width, height, str_state); + drawGraphics(width, height, state); } private function redrawButton():void @@ -168,7 +153,7 @@ package syncomps } public function get textField():TextField { - return tf_label + return cmpi_label.textField } public function set selected(state:Boolean):void @@ -189,88 +174,43 @@ package syncomps { super.drawGraphics(width, height, state) const shapeGraphics:Graphics = shp_graphic.graphics - var colour:uint = uint(getStyle(state)), checkHeight:int = height - 16 - var xCenter:Number, yCenter:Number, size:Number; - var textHeight:int = tf_label.textHeight - var colourAlpha:Number; - if (!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) - } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF - if(checkHeight < textHeight - 8) { - checkHeight = textHeight - 8 - } - switch(labelPosition) - { - case DefaultLabelStyle.LABEL_RIGHT: - case DefaultLabelStyle.LABEL_LEFT: - tf_label.height = height - 4 - if((tf_label.height < textHeight && textHeight <= height) || (tf_label.textHeight && tf_label.height >= textHeight)) { - tf_label.height = textHeight - } - yCenter = height * 0.5; - size = checkHeight * 0.5 - tf_label.y = 0 - tf_label.y = (height - (tf_label.height + 4)) * 0.5; - break; - case DefaultLabelStyle.LABEL_BELOW: - case DefaultLabelStyle.LABEL_ABOVE: - size = checkHeight * 0.3 - tf_label.height = height - (size * 2) - if((tf_label.height < textHeight && textHeight <= height) || (tf_label.textHeight && tf_label.height >= textHeight)) { - tf_label.height = textHeight - } - xCenter = width * 0.5; - tf_label.width = width; - break; - } - switch(labelPosition) - { - case DefaultLabelStyle.LABEL_RIGHT: - xCenter = size + 2; - tf_label.x = (xCenter + size) + 4 - tf_label.width = width - tf_label.x - break; - case DefaultLabelStyle.LABEL_LEFT: - tf_label.x = 0 - xCenter = width - (size + 2) - tf_label.width = width - ((size * 2) + 4) - break; - case DefaultLabelStyle.LABEL_BELOW: - tf_label.y = height - tf_label.height - tf_label.x = 0; - yCenter = size; - break; - case DefaultLabelStyle.LABEL_ABOVE: - tf_label.y = tf_label.x = 0; - yCenter = height - size - break; - default: - throw new Error("Invalid label position.") - break; + var color:uint = uint(getStyle(state)), checkHeight:int = height - 16 + var size:Number = cmpi_label.iconSize / 2, colorAlpha:Number; + if(!enabled) { + color = uint(getStyle(DefaultStyle.DISABLED)) } + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + //outer border (invisible) + graphics.clear() + graphics.beginFill(0, 0) + graphics.drawRect(0, 0, width, height) + graphics.endFill() + + //checkbox shapeGraphics.clear() - shapeGraphics.beginFill(0, 0) - shapeGraphics.drawRect(0, 0, width, height) - shapeGraphics.endFill() shapeGraphics.lineStyle(1) - shapeGraphics.beginFill(colour, colourAlpha) - shapeGraphics.drawCircle(xCenter, yCenter, size); + shapeGraphics.beginFill(color, colorAlpha) + shapeGraphics.drawCircle(size, size, size); shapeGraphics.endFill() if (b_selected) { shapeGraphics.lineStyle(undefined) shapeGraphics.beginFill(0, 1) - shapeGraphics.drawCircle(xCenter, yCenter, size * 0.4); + shapeGraphics.drawCircle(size, size, size * 0.4); shapeGraphics.endFill() } + cmpi_label.icon = shp_graphic + cmpi_label.height = height + cmpi_label.width = width } override public function unload():void { super.unload() + + group = null; removeChildren() removeEventListener(MouseEvent.CLICK, selectButton) removeEventListener(MouseEvent.MOUSE_DOWN, changeState) @@ -281,26 +221,28 @@ package syncomps removeEventListener(FocusEvent.FOCUS_OUT, changeState) removeEventListener(KeyboardEvent.KEY_UP, dispatchClickEvent) removeEventListener(KeyboardEvent.KEY_DOWN, startDispatchClickEvent) - group = null; } public function resizeWidth():void { - tf_label.autoSize = TextFieldAutoSize.LEFT - var widthVal:Number = tf_label.width - switch(labelPosition) - { - case DefaultLabelStyle.LABEL_RIGHT: - case DefaultLabelStyle.LABEL_LEFT: - widthVal += 32; - break; - } - tf_label.autoSize = TextFieldAutoSize.NONE - width = widthVal + cmpi_label.resizeWidth() + drawGraphics(width, height, state) } - public function resizeHeight():void { - height = tf_label.textHeight + 16 + public function resizeHeight():void + { + cmpi_label.resizeHeight() + drawGraphics(width, height, state) + } + + public function get iconSize():int { + return cmpi_label.iconSize; + } + + public function set iconSize(value:int):void + { + cmpi_label.iconSize = value; + drawGraphics(width, height, state) } public function get group():RadioButtonGroup { diff --git a/src/syncomps/ScrollBar.as b/src/syncomps/ScrollBar.as index 7132c91..d30e020 100644 --- a/src/syncomps/ScrollBar.as +++ b/src/syncomps/ScrollBar.as @@ -1,23 +1,26 @@ package syncomps { import flash.display.DisplayObject; - import flash.events.FocusEvent; - import flash.events.KeyboardEvent; - import flash.ui.Keyboard; - import syncomps.events.ScrollEvent; import flash.display.Graphics; import flash.display.Sprite; import flash.events.Event; + import flash.events.FocusEvent; + import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.geom.Rectangle; + import flash.ui.Keyboard; import flash.utils.Timer; + import syncomps.events.ScrollEvent; import syncomps.events.StyleEvent; - import syncomps.styles.ScrollBarStyle; - import syncomps.styles.Style; import syncomps.styles.DefaultStyle; + import syncomps.styles.ScrollBarStyle; + + /** + * Dispatched when a scroll event occurs. + */ + [Event(name = "synScEScroll", type = "syncomps.events.ScrollEvent")] - [Event(name="SCROLL", type="syncomps.events.ScrollEvent")] /** * ... * @author Gimmick @@ -79,7 +82,7 @@ package syncomps value = 0 setScrollProperties(1, 0, 100) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) addEventListener(MouseEvent.CLICK, resetTimer, false, 0, true) addEventListener(KeyboardEvent.KEY_UP, changeState, false, 0, true) @@ -103,7 +106,7 @@ package syncomps private function updateStyles(evt:StyleEvent):void { b_scrollBarChange ||= (evt.style == ScrollBarStyle.SCROLL_DIRECTION) - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } private function changeState(evt:Event):void @@ -168,7 +171,7 @@ package syncomps //max = spr_rightButton.x - spr_thumb.width //min = spr_leftButton.x + spr_leftButton.width u_refreshMask = REFMASK_THUMB - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) if (direction == ScrollBarStyle.DIRECTION_VERTICAL) { moveThumbTo(spr_thumb.y) } @@ -269,7 +272,7 @@ package syncomps maxPosition = (spr_rightButton.x - spr_thumb.width) minPosition = (spr_leftButton.x + spr_leftButton.width) } - this.value = ((num_max - num_min) * ((value - minPosition) / (maxPosition - minPosition))) + num_min + this.value = ((maximum - minimum) * ((value - minPosition) / (maxPosition - minPosition))) + minimum } override protected function drawGraphics(width:int, height:int, state:String):void @@ -277,19 +280,19 @@ package syncomps var i:uint; var graphics:Graphics; var btnWidth:int, btnHeight:int; - var colour:uint = uint(getStyle(state)); + var color:uint = uint(getStyle(state)); var background:uint = uint(getStyle(DefaultStyle.BACKGROUND)); var backgroundSecondary:uint = uint(getStyle(ScrollBarStyle.BACKGROUND_SECONDARY)); - var backgroundSecondaryAlpha:Number, backgroundAlpha:Number, colourAlpha:Number, activeColourAlpha:Number; + var backgroundSecondaryAlpha:Number, backgroundAlpha:Number, colorAlpha:Number, activeColorAlpha:Number; super.drawGraphics(width, height, state) spr_leftButton.y = spr_rightButton.y = 0; - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; backgroundSecondaryAlpha = ((backgroundSecondary & 0xFF000000) >>> 24) / 0xFF; backgroundAlpha = ((background & 0xFF000000) >>> 24) / 0xFF; backgroundSecondary = backgroundSecondary & 0x00FFFFFF background = background & 0x00FFFFFF - colour = colour & 0x00FFFFFF + color = color & 0x00FFFFFF if (direction == ScrollBarStyle.DIRECTION_HORIZONTAL) { @@ -316,10 +319,14 @@ package syncomps btnWidth * 0.3, btnHeight * 0.5, //(left, middle) point * btnWidth * 0.6, btnHeight * 0.75 //(bottom, bottom) point * ]; - var rightVector:Vector. = new Vector.() - for (i = 0; i < leftVector.length; i += 2) { - rightVector.push(btnWidth - leftVector[i], btnHeight - leftVector[i + 1]) - } + var rightVector:Vector. = leftVector.map(function invert(item:Number, index:int, array:Vector.):Number + { + if(index & 1) { + return btnHeight - item + } + return btnWidth - item + }); + if (direction == ScrollBarStyle.DIRECTION_VERTICAL) { //transpose x, y coordinates @@ -344,56 +351,53 @@ package syncomps graphics = spr_leftButton.graphics if (u_refreshMask & REFMASK_LEFT) { - activeColor = colour - activeColourAlpha = colourAlpha + activeColor = color + activeColorAlpha = colorAlpha } else { activeColor = background - activeColourAlpha = backgroundAlpha + activeColorAlpha = backgroundAlpha } graphics.clear() graphics.beginFill(backgroundSecondary, backgroundSecondaryAlpha) graphics.drawRect(0, 0, btnWidth, btnHeight) graphics.endFill() - graphics.beginFill(activeColor, activeColourAlpha) + graphics.beginFill(activeColor, activeColorAlpha) graphics.drawTriangles(leftVector) graphics.endFill() graphics = spr_rightButton.graphics if (u_refreshMask & REFMASK_RIGHT) { - activeColor = colour - activeColourAlpha = colourAlpha + activeColor = color + activeColorAlpha = colorAlpha } else { activeColor = background - activeColourAlpha = backgroundAlpha + activeColorAlpha = backgroundAlpha } graphics.clear() graphics.beginFill(backgroundSecondary, backgroundSecondaryAlpha) graphics.drawRect(0, 0, btnWidth, btnHeight) graphics.endFill() - graphics.beginFill(activeColor, activeColourAlpha) + graphics.beginFill(activeColor, activeColorAlpha) graphics.drawTriangles(rightVector) graphics.endFill() graphics = spr_thumb.graphics graphics.clear() - if ((num_max > num_min) && (0 < num_pageSize && num_pageSize < (num_max - num_min))) + if ((maximum > minimum) && (0 < num_pageSize && num_pageSize < (maximum - minimum))) { var thumbSize:Number = getThumbSize() if(thumbSize < 4) { thumbSize = 4; } + activeColor = background + activeColorAlpha = backgroundAlpha if (u_refreshMask & REFMASK_THUMB) { - activeColor = colour - activeColourAlpha = colourAlpha - } - else - { - activeColor = background - activeColourAlpha = backgroundAlpha + activeColor = color + activeColorAlpha = colorAlpha } if (direction == ScrollBarStyle.DIRECTION_HORIZONTAL) { @@ -401,7 +405,7 @@ package syncomps graphics.beginFill(0, 0) graphics.drawRect(0, 0, thumbSize, height * 0.2) graphics.endFill() - graphics.beginFill(activeColor, activeColourAlpha) + graphics.beginFill(activeColor, activeColorAlpha) graphics.drawRect(0, height * 0.2, thumbSize, height * 0.6) graphics.endFill() graphics.beginFill(0, 0) @@ -415,16 +419,15 @@ package syncomps } else { + spr_thumb.x = 0; graphics.beginFill(0, 0) graphics.drawRect(0, 0, width * 0.2, thumbSize) graphics.endFill() - graphics.beginFill(activeColor, activeColourAlpha) + + graphics.beginFill(activeColor, activeColorAlpha) graphics.drawRect(width * 0.2, 0, width * 0.6, thumbSize) graphics.endFill() - graphics.beginFill(0, 0) - graphics.drawRect(width * 0.8, 0, width * 0.2, thumbSize) - graphics.endFill() rect_drag.x = 0 rect_drag.y = spr_leftButton.y + spr_leftButton.height @@ -432,6 +435,7 @@ package syncomps rect_drag.width = 0; } } + graphics.endFill() } @@ -440,10 +444,10 @@ package syncomps if (b_scrollBarChange) { if (direction == ScrollBarStyle.DIRECTION_HORIZONTAL) { - num_thumbSize = num_pageSize * (spr_rightButton.x - (spr_leftButton.x + spr_leftButton.width)) / (num_max - num_min) + num_thumbSize = num_pageSize * (spr_rightButton.x - (spr_leftButton.x + spr_leftButton.width)) / (maximum - minimum) } else { - num_thumbSize = num_pageSize * (spr_rightButton.y - (spr_leftButton.y + spr_leftButton.height)) / (num_max - num_min) + num_thumbSize = num_pageSize * (spr_rightButton.y - (spr_leftButton.y + spr_leftButton.height)) / (maximum - minimum) } b_scrollBarChange = false } @@ -476,7 +480,7 @@ package syncomps if (direction == ScrollBarStyle.DIRECTION_HORIZONTAL) { b_scrollBarChange = true } - drawGraphics(value, height, str_state) + super.width = value; } override public function set height(value:Number):void @@ -485,7 +489,7 @@ package syncomps if (direction == ScrollBarStyle.DIRECTION_VERTICAL) { b_scrollBarChange = true } - drawGraphics(width, value, str_state) + super.height = value } public function get value():Number { @@ -499,11 +503,11 @@ package syncomps if(num_stepSize) { newValue -= num % num_stepSize } - if(newValue > num_max) { - newValue = num_max + if(newValue > maximum) { + newValue = maximum } - else if(newValue < num_min) { - newValue = num_min + else if(newValue < minimum) { + newValue = minimum } if(newValue == num_value) { return; @@ -515,35 +519,32 @@ package syncomps //min = spr_leftButton.x + spr_leftButton.width //u = num_max * spr_thumb.x / (max - min) u_refreshMask = REFMASK_NONE - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) var minPosition:Number, maxPosition:Number; if (direction == ScrollBarStyle.DIRECTION_HORIZONTAL) { maxPosition = (spr_rightButton.x - spr_thumb.width) minPosition = (spr_leftButton.x + spr_leftButton.width) - spr_thumb.x = minPosition + ((newValue - num_min) * (maxPosition - minPosition) / (num_max - num_min)) + spr_thumb.x = minPosition + ((newValue - minimum) * (maxPosition - minPosition) / (maximum - minimum)) } else { maxPosition = (spr_rightButton.y - spr_thumb.height) minPosition = (spr_leftButton.y + spr_leftButton.height) - spr_thumb.y = minPosition + ((newValue - num_min) * (maxPosition - minPosition) / (num_max - num_min)) + spr_thumb.y = minPosition + ((newValue - minimum) * (maxPosition - minPosition) / (maximum - minimum)) } dispatchEvent(new ScrollEvent(ScrollEvent.SCROLL, newValue, direction, delta, false, false)) } - public function get minimum():Number - { + public function get minimum():Number { return num_min; } - public function get maximum():Number - { + public function get maximum():Number { return num_max; } - public function get pageSize():Number - { + public function get pageSize():Number { return num_pageSize; } @@ -556,7 +557,7 @@ package syncomps num_value = minimum u_refreshMask = REFMASK_NONE spr_thumb.x = spr_thumb.y = 0; - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) //0| |---------||100 //0||---------| |100 //0||___________________________| @@ -582,18 +583,15 @@ package syncomps setStyle(ScrollBarStyle.SCROLL_DIRECTION, value) } - public function get stepSize():Number - { + public function get stepSize():Number { return num_stepSize; } - public function set stepSize(value:Number):void - { + public function set stepSize(value:Number):void { num_stepSize = value; } - public function get dragging():Boolean - { + public function get dragging():Boolean { return b_dragging; } diff --git a/src/syncomps/ScrollPane.as b/src/syncomps/ScrollPane.as index 41e230f..cafef24 100644 --- a/src/syncomps/ScrollPane.as +++ b/src/syncomps/ScrollPane.as @@ -17,7 +17,8 @@ package syncomps import syncomps.styles.Style; import syncomps.styles.DefaultStyle; - [Event(name="SCROLL", type="syncomps.events.ScrollEvent")] + [Event(name="synScEScroll", type="syncomps.events.ScrollEvent")] + /** * ... * @author Gimmick @@ -59,7 +60,7 @@ package syncomps cl_verticalScroll.width = 16 addChild(spr_source) addChild(shp_source) - drawGraphics(DEF_WIDTH, DEF_HEIGHT, str_state) + drawGraphics(DEF_WIDTH, DEF_HEIGHT, state) cl_verticalScroll.addEventListener(ScrollEvent.SCROLL, scrollSourceVertical) cl_horizontalScroll.addEventListener(ScrollEvent.SCROLL, scrollSourceHorizontal) @@ -188,12 +189,12 @@ package syncomps override public function set width(value:Number):void { - drawGraphics(value, height, str_state) + super.width = value var prevScrollValue:Number = cl_horizontalScroll.value; if(b_displayScrollBars) { displayScrollBars(b_forceScrollDisplay) } - var contentBiggerThanPane:Boolean = dsp_source.width >= (value - pt_scrollSize.x) + var contentBiggerThanPane:Boolean = dsp_source && dsp_source.width >= (value - pt_scrollSize.x) cl_horizontalScroll.enabled = contentBiggerThanPane prevScrollValue *= int(contentBiggerThanPane) horizontalScrollPosition = prevScrollValue @@ -209,12 +210,12 @@ package syncomps override public function set height(value:Number):void { - drawGraphics(width, value, str_state) + super.height = value var prevScrollValue:Number = cl_verticalScroll.value; if(b_displayScrollBars) { displayScrollBars(b_forceScrollDisplay) } - var contentBiggerThanPane:Boolean = dsp_source.height >= (value - pt_scrollSize.y) + var contentBiggerThanPane:Boolean = dsp_source && dsp_source.height >= (value - pt_scrollSize.y) cl_verticalScroll.enabled = contentBiggerThanPane prevScrollValue *= int(contentBiggerThanPane) verticalScrollPosition = prevScrollValue @@ -326,17 +327,13 @@ package syncomps } cl_horizontalScroll.setScrollProperties(horizontalPageSize, 0, maxWidth) cl_verticalScroll.setScrollProperties(verticalPageSize, 0, maxHeight) - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) } public function hideScrollBars():void { - if (cl_horizontalScroll.parent) { - removeChild(cl_horizontalScroll) - } - if (cl_verticalScroll.parent) { - removeChild(cl_verticalScroll) - } + cl_verticalScroll.parent && cl_verticalScroll.parent.removeChild(cl_verticalScroll) + cl_horizontalScroll.parent && cl_horizontalScroll.parent.removeChild(cl_horizontalScroll) pt_scrollSize.setTo(cl_verticalScroll.width * int(cl_verticalScroll.parent != null), cl_horizontalScroll.height * int(cl_horizontalScroll.parent != null)) b_displayScrollBars = false; } @@ -353,7 +350,7 @@ package syncomps spr_source.x = spr_source.y = 0 spr_source.mask = shp_source } - drawGraphics(width, height, str_state) + drawGraphics(width, height, state) displayScrollBars(b_forceScrollDisplay) } @@ -384,7 +381,10 @@ package syncomps public function set horizontalScrollPosition(val:Number):void { var newValue:Number = val; - if(val < 0 || dsp_source.width < (width - pt_scrollSize.x)) { + if(!dsp_source) { + return; + } + else if(val < 0 || dsp_source.width < (width - pt_scrollSize.x)) { newValue = 0 } else if (val > dsp_source.width) { @@ -401,7 +401,10 @@ package syncomps public function set verticalScrollPosition(val:Number):void { var newValue:Number = val; - if(val < 0 || dsp_source.height < (height - pt_scrollSize.y)) { + if(!dsp_source) { + return; + } + else if(val < 0 || dsp_source.height < (height - pt_scrollSize.y)) { newValue = 0 } else if (val > dsp_source.height - (height - pt_scrollSize.y)) { diff --git a/src/syncomps/SkinnableTextField.as b/src/syncomps/SkinnableTextField.as index 9607fec..5c9696a 100644 --- a/src/syncomps/SkinnableTextField.as +++ b/src/syncomps/SkinnableTextField.as @@ -3,13 +3,21 @@ package syncomps import flash.text.TextField; import flash.text.TextFormat; import syncomps.events.StyleEvent; + import syncomps.interfaces.IStyleInternal; import syncomps.interfaces.ISynComponent; import syncomps.styles.SkinnableTextStyle; import syncomps.styles.Style; import syncomps.styles.StyleManager; - [Event(name="STYLE_CHANGE", type="syncomps.events.StyleEvent")] - [Event(name="STYLE_CHANGING", type="syncomps.events.StyleEvent")] + /** + * Dispatched when a style property is about to change. + */ + [Event(name="synStEStyleChanging", type="syncomps.events.StyleEvent")] + + /** + * Dispatched when a style property has changed. + */ + [Event(name="synStEStyleChange", type="syncomps.events.StyleEvent")] /** * ... @@ -19,7 +27,8 @@ package syncomps { protected static var DEFAULT_STYLE:Class = SkinnableTextStyle; - private var cl_style:Style; + //TODO add Label class which uses this and has icon control + private var cl_style:IStyleInternal private var b_enabled:Boolean; public function SkinnableTextField() { @@ -29,7 +38,7 @@ package syncomps private function init():void { - cl_style = (new (getDefaultStyle())()) as Style + cl_style = (new (getDefaultStyle())()) as IStyleInternal styleDefinition.addEventListener(StyleEvent.STYLE_CHANGING, updateStyles, false, 0, true) styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, applyStylesOnEvent, false, 0, true) StyleManager.register(this) @@ -58,14 +67,7 @@ package syncomps private function updateStyles(evt:StyleEvent):void { evt.preventDefault() - addEventListener(StyleEvent.STYLE_CHANGING, updateStyleOnChange, false, 0, true) - dispatchEvent(evt) - } - - private function updateStyleOnChange(evt:StyleEvent):void - { - removeEventListener(StyleEvent.STYLE_CHANGING, updateStyleOnChange) - if(!evt.isDefaultPrevented()) { + if (dispatchEvent(evt)) { styleDefinition.forceStyle(evt.style, evt.value) } } @@ -80,10 +82,6 @@ package syncomps public function unload():void { StyleManager.unregister(this) } - override public function get text():String - { - return super.text; - } override public function set text(value:String):void { @@ -92,30 +90,9 @@ package syncomps setTextFormat(getStyle(SkinnableTextStyle.TEXT_FORMAT) as TextFormat) } } - public function refresh():void - { - var textFormat:TextFormat = getStyle(SkinnableTextStyle.TEXT_FORMAT) as TextFormat - if (textFormat) - { - if (textFormat.color != null) - { - //color is common for all text in field - if(enabled) { - textFormat.color = getStyle(SkinnableTextStyle.ENABLED) - } - else { - textFormat.color = getStyle(SkinnableTextStyle.DISABLED) - } - } - setTextFormat(textFormat) - defaultTextFormat = textFormat - } - cl_style.refresh() - } /* DELEGATE IStyleDefinition */ - - public function get styleDefinition():Style { + public function get styleDefinition():IStyleInternal { return cl_style } @@ -129,7 +106,7 @@ package syncomps styleDefinition.setStyle(style, value); } - public function applyStyle(style:Style):void { + public function applyStyle(style:IStyleInternal):void { styleDefinition.applyStyle(style) } diff --git a/src/syncomps/Slider.as b/src/syncomps/Slider.as new file mode 100644 index 0000000..49a2eb9 --- /dev/null +++ b/src/syncomps/Slider.as @@ -0,0 +1,361 @@ +package syncomps +{ + import flash.display.CapsStyle; + import flash.display.DisplayObject; + import flash.display.Graphics; + import flash.display.LineScaleMode; + import flash.display.Sprite; + import flash.events.Event; + import flash.events.FocusEvent; + import flash.events.KeyboardEvent; + import flash.events.MouseEvent; + import flash.events.TimerEvent; + import flash.geom.Rectangle; + import flash.text.TextFormat; + import flash.text.TextFormatAlign; + import flash.ui.Keyboard; + import flash.utils.Timer; + import syncomps.events.ScrollEvent; + import syncomps.events.StyleEvent; + import syncomps.styles.DefaultStyle; + import syncomps.styles.ScrollBarStyle; + import syncomps.styles.SkinnableTextStyle; + import syncomps.styles.StyleManager; + + public class Slider extends SynComponent + { + public static const DEF_WIDTH:int = 96 + public static const DEF_HEIGHT:int = 32 + + protected static var DEFAULT_STYLE:Class = DefaultStyle + + private var spr_thumb:Sprite + private var num_max:Number; + private var num_min:Number; + private var b_dragging:Boolean; + private var rect_drag:Rectangle; + private var num_stepSize:Number; + private var num_pageSize:Number; + private var cmpi_end:Label + private var cmpi_start:Label + public function Slider() { + init() + } + private function init():void + { + num_stepSize = 1 + spr_thumb = new Sprite() + rect_drag = new Rectangle() + cmpi_end = new Label() + cmpi_start = new Label() + + StyleManager.unregister(cmpi_end) + StyleManager.unregister(cmpi_start) + + addChild(cmpi_end) + addChild(cmpi_start) + addChild(spr_thumb) + + cmpi_start.setStyle(SkinnableTextStyle.TEXT_FORMAT, new TextFormat(null, null, null, null, null, null, null, null, TextFormatAlign.LEFT)); + cmpi_end.setStyle(SkinnableTextStyle.TEXT_FORMAT, new TextFormat(null, null, null, null, null, null, null, null, TextFormatAlign.RIGHT)); + + setProperties(1, 0, 100) + drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) + moveThumbTo(0) + + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + addEventListener(KeyboardEvent.KEY_UP, changeState, false, 0, true) + addEventListener(MouseEvent.CLICK, changeState, false, 0, true) + addEventListener(MouseEvent.MOUSE_DOWN, changeState, false, 0, true) + addEventListener(MouseEvent.MOUSE_UP, changeState, false, 0, true) + addEventListener(MouseEvent.MOUSE_OVER, changeState, false, 0, true) + addEventListener(MouseEvent.ROLL_OUT, changeState, false, 0, true) + addEventListener(FocusEvent.FOCUS_IN, changeState, false, 0, true) + addEventListener(FocusEvent.FOCUS_OUT, changeState, false, 0, true) + addEventListener(KeyboardEvent.KEY_DOWN, changeState, false, 0, true) + addEventListener(MouseEvent.RELEASE_OUTSIDE, changeState, false, 0, true) + } + + override public function getDefaultStyle():Class { + return DEFAULT_STYLE + } + override public function setDefaultStyle(styleClass:Class):void { + DEFAULT_STYLE = styleClass + } + + private function updateStyles(evt:StyleEvent):void + { + var prevWidth:int = width, prevHeight:int = height + cmpi_start.setStyle(evt.style, evt.value) + cmpi_end.setStyle(evt.style, evt.value) + + cmpi_end.resizeWidth() + cmpi_start.resizeWidth() + drawGraphics(prevWidth, prevHeight, state) + } + + private function changeState(evt:Event):void + { + dragging &&= enabled + if(!enabled) { + return + } + else switch(evt.type) + { + case MouseEvent.CLICK: + if (evt.target == this) + { + var newX:Number = mouseX + if(newX < (height / 4) || newX > (width - (height / 4))) { + return + } + spr_thumb.x = newX + moveThumbTo(value) + dispatchEvent(new Event(Event.CHANGE, false, false)) + } + break + case KeyboardEvent.KEY_DOWN: + var keyCode:int = (evt as KeyboardEvent).keyCode + if(keyCode == Keyboard.LEFT || keyCode == Keyboard.DOWN) { + value -= stepSize + } + else if(keyCode == Keyboard.RIGHT || keyCode == Keyboard.UP) { + value += stepSize + } + else if (keyCode == Keyboard.HOME) { + value = minimum + } + else if (keyCode == Keyboard.END) { + value = maximum + } + drawGraphics(width, height, DefaultStyle.DOWN) + break; + case MouseEvent.MOUSE_DOWN: + if(evt.target == spr_thumb) { + dragging = true; + } + drawGraphics(width, height, DefaultStyle.DOWN) + break; + case MouseEvent.RELEASE_OUTSIDE: + dragging = false; + case FocusEvent.FOCUS_OUT: + case MouseEvent.ROLL_OUT: + drawGraphics(width, height, DefaultStyle.BACKGROUND) + break; + case MouseEvent.MOUSE_UP: + dragging = false + case KeyboardEvent.KEY_UP: + case MouseEvent.MOUSE_OVER: + case FocusEvent.FOCUS_IN: + drawGraphics(width, height, DefaultStyle.HOVER) + break; + } + } + + private function changeValueThumb(evt:MouseEvent):void + { + dispatchEvent(new Event(Event.CHANGE, false, false)) + drawGraphics(width, height, state) + } + + override protected function drawGraphics(width:int, height:int, state:String):void + { + if(width < 0 || height < 0) { + return + } + var graphics:Graphics; + var color:uint = uint(getStyle(state)); + var backgroundAlpha:Number, colorAlpha:Number; + var background:uint = uint(getStyle(DefaultStyle.BACKGROUND)); + const halfHeight:Number = height / 2 + + super.drawGraphics(width, height, state) + + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + backgroundAlpha = ((background & 0xFF000000) >>> 24) / 0xFF; + background = background & 0x00FFFFFF + color = color & 0x00FFFFFF + + var quarterHeight:Number = halfHeight / 2 + graphics = spr_thumb.graphics + graphics.clear() + graphics.lineStyle(0, background, backgroundAlpha, true, LineScaleMode.NONE) + graphics.beginFill(color, colorAlpha) + graphics.lineTo(quarterHeight, quarterHeight); + graphics.lineTo(quarterHeight, halfHeight); + graphics.lineTo(-quarterHeight, halfHeight); + graphics.lineTo(-quarterHeight, quarterHeight); + graphics.endFill(); + + graphics = this.graphics + graphics.clear() + graphics.beginFill(0, 0) + graphics.drawRect(0, 0, width, height) + graphics.endFill() + graphics.lineStyle(1, background, backgroundAlpha, true, LineScaleMode.NONE, CapsStyle.SQUARE) + graphics.moveTo(1, 0) + graphics.lineTo(width - 1, 0) + for (var i:Number = 0; i <= maximum; i += pageSize) + { + //draw vertical lines + var percent:Number = i / maximum + var xPos:Number = percent * (width - halfHeight) + graphics.moveTo(xPos + quarterHeight, halfHeight) + graphics.lineTo(xPos + quarterHeight, 0) + } + + for (i = stepSize; i < maximum; i += stepSize) + { + //draw vertical lines + percent = i / maximum + xPos = percent * (width - halfHeight) + graphics.moveTo(xPos + quarterHeight, quarterHeight) + graphics.lineTo(xPos + quarterHeight, 0) + } + cmpi_end.width = cmpi_start.width = width + cmpi_end.height = cmpi_start.height = height + rect_drag.x = quarterHeight + rect_drag.width = width - halfHeight + } + + override public function unload():void + { + if(stage) { + stage.removeEventListener(MouseEvent.MOUSE_MOVE, changeValueThumb) + } + super.unload() + removeChildren() + removeEventListener(KeyboardEvent.KEY_UP, changeState); + removeEventListener(MouseEvent.MOUSE_DOWN, changeState); + removeEventListener(MouseEvent.ROLL_OVER, changeState); + removeEventListener(MouseEvent.MOUSE_UP, changeState); + removeEventListener(MouseEvent.ROLL_OUT, changeState); + removeEventListener(FocusEvent.FOCUS_IN, changeState); + removeEventListener(FocusEvent.FOCUS_OUT, changeState); + removeEventListener(KeyboardEvent.KEY_DOWN, changeState); + removeEventListener(MouseEvent.RELEASE_OUTSIDE, changeState); + } + + public function get value():Number + { + var rawValue:Number = (((maximum - minimum) * ((spr_thumb.x - (height / 4)) / (width - (height / 2)))) + minimum) + var decimalPart:Number = rawValue % stepSize + rawValue -= decimalPart + if (decimalPart > (stepSize/2)) { + rawValue += stepSize + } + return rawValue + } + + public function set value(newValue:Number):void + { + if (num_stepSize) { + newValue += newValue % num_stepSize + } + + if(newValue > maximum) { + newValue = maximum + } + else if(newValue < minimum) { + newValue = minimum + } + + if(newValue == value) { + return; + } + + moveThumbTo(newValue) + drawGraphics(width, height, state) + dispatchEvent(new Event(Event.CHANGE, false, false)) + } + + private function moveThumbTo(newValue:Number):void { + spr_thumb.x = (height / 4) + ((newValue - minimum) * (width - (height / 2)) / (maximum - minimum)) + } + + public function get minimum():Number { + return num_min; + } + + public function get maximum():Number { + return num_max; + } + + public function setProperties(pageSize:Number, minimum:Number, maximum:Number):void + { + num_max = maximum + num_min = minimum + num_pageSize = pageSize + cmpi_end.label = maximum.toString() + cmpi_start.label = minimum.toString() + cmpi_start.resizeWidth() + cmpi_end.resizeWidth() + if(value > maximum) { + value = maximum + } + else if(value < minimum) { + value = minimum + } + drawGraphics(width, height, state) + //0| |---------||100 + //0||---------| |100 + //0||___________________________| + //-5 <- w -> 5 + // |---------------------------------------| + //(max+min) * (position / maxPosition) - min + //max = spr_rightButton.x - spr_thumb.width + //min = spr_leftButton.x + spr_leftButton.width + //u = num_max * spr_thumb.x / (max - min) + } + + public function get stepSize():Number { + return num_stepSize; + } + + public function set stepSize(value:Number):void + { + if (num_stepSize != value) + { + num_stepSize = value; + drawGraphics(width, height, state) + } + } + + public function get dragging():Boolean { + return b_dragging + } + + public function set dragging(dragging:Boolean):void + { + if (b_dragging == dragging) { + return; + } + + b_dragging = dragging; + if (dragging) + { + spr_thumb.startDrag(false, rect_drag) + stage && stage.addEventListener(MouseEvent.MOUSE_MOVE, changeValueThumb, false, 0, true); + } + else + { + moveThumbTo(value) + spr_thumb.stopDrag() + stage && stage.removeEventListener(MouseEvent.MOUSE_MOVE, changeValueThumb); + } + } + + public function get pageSize():Number { + return num_pageSize; + } + + public function set pageSize(value:Number):void + { + if (value != num_pageSize) + { + num_pageSize = value; + drawGraphics(width, height, state) + } + } + } +} \ No newline at end of file diff --git a/src/syncomps/SplitLabeledButton.as b/src/syncomps/SplitLabeledButton.as index c281e01..3e11d67 100644 --- a/src/syncomps/SplitLabeledButton.as +++ b/src/syncomps/SplitLabeledButton.as @@ -1,6 +1,7 @@ package syncomps { import flash.display.BitmapData; + import flash.display.DisplayObject; import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; @@ -11,26 +12,30 @@ package syncomps import syncomps.data.DataProvider; import syncomps.events.ButtonEvent; import syncomps.events.DataProviderEvent; - import syncomps.events.ListCellEvent; + import syncomps.events.ListEvent; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; + import syncomps.interfaces.graphics.IAutoResize; import syncomps.interfaces.IDataProvider; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.IIcon; + import syncomps.interfaces.graphics.ILabel; import syncomps.styles.SplitButtonStyle; import syncomps.styles.Style; import syncomps.styles.DefaultStyle; import syncomps.styles.StyleManager; [Event(name = "change", type = "flash.events.Event")] - [Event(name = "CLICK", type = "syncomps.events.ButtonEvent")] - [Event(name="CELL_CLICK", type="syncomps.events.ListCellEvent")] - [Event(name="MENU_STATE_CHANGE", type="syncomps.events.ComboBoxEvent")] + + [Event(name = "synBEButtonClick", type = "syncomps.events.ButtonEvent")] + + [Event(name = "synLCECellClick", type = "syncomps.events.ListEvent")] + + [Event(name = "synCBEMenuStateChange", type = "syncomps.events.ComboBoxEvent")] /** * ... * @author Gimmick */ - public class SplitLabeledButton extends SynComponent implements IDataProvider, IAutoResize, ILabel + public class SplitLabeledButton extends SynComponent implements IDataProvider, IAutoResize, ILabel, IIcon { public static const DEF_WIDTH:int = 96 public static const DEF_HEIGHT:int = 32; @@ -54,10 +59,10 @@ package syncomps StyleManager.unregister(cmpi_button) StyleManager.unregister(cmpi_dropdown) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) cmpi_dropdown.addEventListener(Event.CHANGE, updateButton, false, 0, true) - cmpi_dropdown.addEventListener(ListCellEvent.CELL_CLICK, setTextAndDispatch, false, 0, true) + cmpi_dropdown.addEventListener(ListEvent.CELL_CLICK, setTextAndDispatch, false, 0, true) cmpi_dropdown.addEventListener(DataProviderEvent.DATA_REFRESH, changeButtonText, false, 0, true) cmpi_dropdown.addEventListener(DataProviderEvent.ITEM_REMOVED, updateButton, false, 0, true) cmpi_button.addEventListener(ButtonEvent.CLICK, dispatchEvent, false, 0, true) @@ -68,11 +73,6 @@ package syncomps drawGraphics(DEF_WIDTH, DEF_HEIGHT, DefaultStyle.BACKGROUND) } - override public function get enabled():Boolean - { - return super.enabled; - } - override public function set enabled(value:Boolean):void { cmpi_button.enabled = cmpi_dropdown.enabled = value; @@ -115,6 +115,7 @@ package syncomps { cmpi_button.setStyle(evt.style, evt.value) cmpi_dropdown.setStyle(evt.style, evt.value) + drawGraphics(width, height, state) } override public function getDefaultStyle():Class { @@ -128,57 +129,36 @@ package syncomps { super.unload(); removeChildren(); - cmpi_dropdown.removeEventListener(ListCellEvent.CELL_CLICK, setTextAndDispatch) + cmpi_dropdown.removeEventListener(ListEvent.CELL_CLICK, setTextAndDispatch) } override protected function drawGraphics(width:int, height:int, state:String):void { super.drawGraphics(width, height, state); var graphics:Graphics = shp_baseGraphics.graphics - var colour:uint = uint(getStyle(DefaultStyle.BACKGROUND)) + var color:uint = uint(getStyle(DefaultStyle.BACKGROUND)) if(!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) + color = uint(getStyle(DefaultStyle.DISABLED)) } graphics.clear() - graphics.lineStyle(1, colour) - graphics.drawRect(0, 0, width - 1, height - 1) - graphics.lineStyle(1) - graphics.moveTo(width - 23, 4) - graphics.lineTo(width - 23, height - 4) - cmpi_dropdown.width = width; cmpi_dropdown.height = height cmpi_button.height = height - 2; + var offsetX:int; if (width > 24) { - cmpi_button.width = width - 24 + offsetX = 24 } - else { - cmpi_button.width = width; - } - } - - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) + graphics.moveTo(width - offsetX, 4) + graphics.lineTo(width - offsetX, height - 4) + cmpi_button.width = width - offsetX } - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - - private function setTextAndDispatch(evt:ListCellEvent):void + private function setTextAndDispatch(evt:ListEvent):void { evt.preventDefault() - addEventListener(ListCellEvent.CELL_CLICK, setTextAfterEvent) - dispatchEvent(new ListCellEvent(evt.type, evt.index, evt.item, false, true)) - } - - private function setTextAfterEvent(evt:ListCellEvent):void - { - removeEventListener(ListCellEvent.CELL_CLICK, setTextAfterEvent) - if(evt && evt.cancelable && evt.isDefaultPrevented()) { - return; + if(dispatchEvent(new ListEvent(ListEvent.CELL_CLICK, evt.index, evt.item, false, true))) { + selectedIndex = evt.index; } - selectedIndex = evt.index } public function resizeWidth():void @@ -197,6 +177,10 @@ package syncomps cmpi_dropdown.addItem(item); } + public function addItems(items:Array):void { + cmpi_dropdown.addItem(items); + } + public function addItemAt(item:Object, index:int):void { cmpi_dropdown.addItemAt(item, index); } @@ -213,6 +197,14 @@ package syncomps return cmpi_dropdown.getItemAt(index); } + public function getItemBy(searchFunction:Function):DataElement { + return cmpi_dropdown.getItemBy(searchFunction); + } + + public function indexOf(searchFunction:Function, fromIndex:int = 0):int { + return cmpi_dropdown.indexOf(searchFunction, fromIndex); + } + public function hideMenu():void { cmpi_dropdown.hideMenu(); } @@ -262,11 +254,15 @@ package syncomps cmpi_dropdown.showMenu(); } - public function removeAll():void { - cmpi_dropdown.removeAll() + public function removeItems():void { + cmpi_dropdown.removeItems() + } + + public function get list():List { + return cmpi_dropdown.list; } - public function get icon():BitmapData + public function get icon():DisplayObject { if(selectedItem) { return selectedItem.icon @@ -274,7 +270,7 @@ package syncomps return cmpi_button.icon } - public function set icon(value:BitmapData):void + public function set icon(value:DisplayObject):void { cmpi_button.icon = value; if(selectedItem) { @@ -286,6 +282,10 @@ package syncomps return cmpi_dropdown.items } + public function set items(items:Array):void { + cmpi_dropdown.items = items + } + public function get label():String { return cmpi_button.label; } diff --git a/src/syncomps/SynComponent.as b/src/syncomps/SynComponent.as index 65a1577..36ae8fd 100644 --- a/src/syncomps/SynComponent.as +++ b/src/syncomps/SynComponent.as @@ -5,6 +5,7 @@ package syncomps import flash.utils.getQualifiedClassName; import syncomps.events.StyleEvent; import syncomps.interfaces.IStyleDefinition; + import syncomps.interfaces.IStyleInternal; import syncomps.interfaces.ISynComponent; import syncomps.styles.Style; import syncomps.styles.StyleManager; @@ -14,14 +15,23 @@ package syncomps */ public class SynComponent extends Sprite implements ISynComponent { - protected var str_state:String; - protected var cl_style:Style; + private var str_state:String; + private var cl_style:IStyleInternal; public function SynComponent() { init(); } + private function init():void + { + cl_style = (new (getDefaultStyle())()) as IStyleInternal + styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, handleStyleChangeEvent, false, 0, true) + styleDefinition.addEventListener(StyleEvent.STYLE_CHANGING, updateStyles, false, 0, true) + StyleManager.register(this) + tabEnabled = true + } + //interface methods for IStyleDefinition - public function get styleDefinition():Style { + public function get styleDefinition():IStyleInternal { return cl_style } @@ -34,37 +44,20 @@ package syncomps public function getStyle(style:Object):Object { return styleDefinition.getStyle(style) } - public function applyStyle(style:Style):void { + public function applyStyle(style:IStyleInternal):void { styleDefinition.applyStyle(style) } public function getDefaultStyle():Class { return null } - public function setDefaultStyle(styleClass:Class):void { - return; - } - private function init():void - { - tabEnabled = true - cl_style = (new (getDefaultStyle())()) as Style - StyleManager.register(this) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, handleStyleChangeEvent, false, 0, true) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGING, updateStyles, false, 0, true) - } + public function setDefaultStyle(styleClass:Class):void { /* empty implementation - abstract method */ } private function updateStyles(evt:StyleEvent):void { evt.preventDefault() - addEventListener(StyleEvent.STYLE_CHANGING, updateStyleOnChange, false, 0, true) - dispatchEvent(evt) - } - - private function updateStyleOnChange(evt:StyleEvent):void - { - removeEventListener(StyleEvent.STYLE_CHANGING, updateStyleOnChange) - if(!evt.isDefaultPrevented()) { + if(dispatchEvent(evt)) { styleDefinition.forceStyle(evt.style, evt.value) } } @@ -105,10 +98,28 @@ package syncomps str_state = state } - public function refresh():void + override public function set width(value:Number):void + { + if(value < 0) { + value = 0; + } + drawGraphics(value, height, str_state); + } + + override public function set height(value:Number):void { - cl_style.refresh() - drawGraphics(width, height, str_state) + if(value < 0) { + value = 0; + } + drawGraphics(width, value, str_state); + } + + protected function get state():String { + return str_state; + } + + protected function set state(value:String):void { + str_state = value; } } diff --git a/src/syncomps/TextArea.as b/src/syncomps/TextArea.as new file mode 100644 index 0000000..e5ec304 --- /dev/null +++ b/src/syncomps/TextArea.as @@ -0,0 +1,90 @@ +package syncomps +{ + import flash.display.Sprite + import flash.events.Event; + import flash.events.MouseEvent; + import flash.events.TextEvent; + import flash.text.Font; + import flash.text.TextField; + import flash.text.TextFieldType; + import flash.text.TextFormat; + import flash.text.TextFieldAutoSize; + import flash.text.TextLineMetrics; + import syncomps.events.ScrollEvent; + import syncomps.events.StyleEvent; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.styles.DefaultInnerTextStyle; + import syncomps.styles.ScrollPaneStyle; + import syncomps.styles.SkinnableTextStyle; + import syncomps.styles.Style; + import syncomps.styles.DefaultStyle; + import syncomps.styles.StyleManager; + /** + * ... + * @author Gimmick + */ + public class TextArea extends TextInput + { + private var cmpi_scrollBars:ScrollBar; + private var num_prevTextHeight:Number; + public function TextArea() + { + super() + init() + } + + private function init():void + { + cmpi_scrollBars = new ScrollBar() + StyleManager.unregister(cmpi_scrollBars) + + num_prevTextHeight = 0.0; + placeHolderField.wordWrap = textField.wordWrap = true; + placeHolderField.multiline = textField.multiline = true; + cmpi_scrollBars.setScrollProperties(textField.height, 0, textField.maxScrollV) + addChild(cmpi_scrollBars) + cmpi_scrollBars.width = 16; + cmpi_scrollBars.visible = false + textField.addEventListener(Event.CHANGE, checkHeight) + textField.addEventListener(Event.SCROLL, changeScrollPosition) + cmpi_scrollBars.addEventListener(ScrollEvent.SCROLL, changeTextScroll) + } + + private function changeTextScroll(evt:ScrollEvent):void { + textField.scrollV = cmpi_scrollBars.value + } + + private function changeScrollPosition(evt:Event):void { + cmpi_scrollBars.value = textField.scrollV + } + + private function checkHeight(evt:Event):void + { + var textHeight:Number = textField.textHeight + if (textHeight != num_prevTextHeight) + { + cmpi_scrollBars.visible = textHeight > textField.height + cmpi_scrollBars.setScrollProperties(textField.bottomScrollV - textField.scrollV, 0, textField.maxScrollV) + textField.width = width + if(cmpi_scrollBars.visible) { + textField.width -= cmpi_scrollBars.width + } + num_prevTextHeight = textHeight + } + } + override public function set width(value:Number):void + { + super.width = value; + cmpi_scrollBars.x = width - cmpi_scrollBars.width + if(cmpi_scrollBars.visible) { + textField.width = width - cmpi_scrollBars.width + } + } + override public function set height(value:Number):void + { + super.height = value; + cmpi_scrollBars.height = value; + } + } + +} \ No newline at end of file diff --git a/src/syncomps/TextInput.as b/src/syncomps/TextInput.as index 2b81444..9a30881 100644 --- a/src/syncomps/TextInput.as +++ b/src/syncomps/TextInput.as @@ -10,20 +10,19 @@ import flash.text.TextFormat; import flash.text.TextFieldAutoSize; import syncomps.events.StyleEvent; - import syncomps.interfaces.IAutoResize; - import syncomps.interfaces.ILabel; + import syncomps.interfaces.graphics.IAutoResize; import syncomps.styles.DefaultInnerTextStyle; import syncomps.styles.SkinnableTextStyle; import syncomps.styles.Style; import syncomps.styles.DefaultStyle; import syncomps.styles.StyleManager; - public class TextInput extends SynComponent implements IAutoResize, ILabel + public class TextInput extends SynComponent implements IAutoResize { protected static var DEFAULT_STYLE:Class = DefaultInnerTextStyle private var fon_currentFont:Font - private var tf_label:SkinnableTextField; + private var cmpi_label:Label; private var tf_input:SkinnableTextField; private var tff_labelFormat:TextFormat; public function TextInput() { @@ -33,29 +32,28 @@ private function init():void { tabEnabled = false //tf_label is tabEnabled, not this - tf_label = new SkinnableTextField() + cmpi_label = new Label() tf_input = new SkinnableTextField() tff_labelFormat = new TextFormat() - StyleManager.unregister(tf_label) + StyleManager.unregister(cmpi_label) StyleManager.unregister(tf_input) - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) - tf_label.selectable = tf_label.multiline = tf_label.mouseEnabled = tf_label.tabEnabled = false - tf_label.defaultTextFormat = tff_labelFormat - tf_label.height = 24 + addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) + cmpi_label.setStyle(SkinnableTextStyle.TEXT_FORMAT, tff_labelFormat) + cmpi_label.height = 24 - tf_input.type = TextFieldType.INPUT - tf_input.multiline = false; - tf_input.enabled = true; - tf_input.height = 24; tf_input.width = 100; + tf_input.height = 24; + tf_input.enabled = true; + tf_input.multiline = false; + tf_input.type = TextFieldType.INPUT tf_input.addEventListener(Event.CHANGE, monitorTextInput, false, 0, true) tf_input.addEventListener(TextEvent.TEXT_INPUT, checkCharacterEmbedInput, false, 0, true) tf_input.addEventListener(MouseEvent.MOUSE_OVER, preventMouseOverCapture, false, 0, true) drawGraphics(100, 24, DefaultStyle.BACKGROUND) addChild(tf_input) - addChild(tf_label) + addChild(cmpi_label) } private function checkCharacterEmbedInput(evt:TextEvent):void @@ -65,17 +63,10 @@ var embed:Boolean = fon_currentFont.hasGlyphs(tf_input.text + evt.text) var embedFonts:String = SkinnableTextStyle.EMBED_FONTS tf_input.setStyle(embedFonts, embed) - tf_label.setStyle(embedFonts, embed) + cmpi_label.setStyle(embedFonts, embed) } } - override public function set width(value:Number):void { - drawGraphics(value, height, str_state) - } - override public function set height(value:Number):void { - drawGraphics(width, value, str_state) - } - public function get textHeight():int { return tf_input.textHeight } @@ -109,7 +100,7 @@ } } } - tf_label.setStyle(evt.style, value) + cmpi_label.setStyle(evt.style, value) } private function copyFormat(format:TextFormat, into:TextFormat):void @@ -154,13 +145,13 @@ private function monitorTextInput(evt:Event):void { - tf_label.visible = (tf_input.text == "" || !tf_input.text.length) + cmpi_label.visible = (tf_input.text == "" || !tf_input.text.length) if (fon_currentFont && getStyle(SkinnableTextStyle.EMBED_FONTS)) { var embed:Boolean = fon_currentFont.hasGlyphs(tf_input.text) var embedFonts:String = SkinnableTextStyle.EMBED_FONTS tf_input.setStyle(embedFonts, embed) - tf_label.setStyle(embedFonts, embed) + cmpi_label.setStyle(embedFonts, embed) } } @@ -172,11 +163,11 @@ } public function set placeHolder(value:String):void { - tf_label.text = value + cmpi_label.label = value } public function get placeHolder():String { - return tf_label.text + return cmpi_label.label } public function get value():String { @@ -188,18 +179,15 @@ } public function get placeHolderField():TextField { - return tf_label + return cmpi_label.textField } public function reset():void { - tf_input.text = "" + tf_input.text = ""; } - public function focus():void - { - if (stage) { - stage.focus = tf_input - } + public function focus():void { + stage && (stage.focus = tf_input) } public function set value(value:String):void @@ -216,16 +204,16 @@ override protected function drawGraphics(width:int, height:int, state:String):void { super.drawGraphics(width, height, state) - var colour:uint = uint(getStyle(state)) - var borderColour:uint = uint(getStyle(DefaultInnerTextStyle.BORDER)) + var color:uint = uint(getStyle(state)) + var borderColor:uint = uint(getStyle(DefaultInnerTextStyle.BORDER)) if(!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) + color = uint(getStyle(DefaultStyle.DISABLED)) } - tf_label.width = tf_input.width = width; - tf_label.height = tf_input.height = height + cmpi_label.width = tf_input.width = width; + cmpi_label.height = tf_input.height = height graphics.clear() - graphics.lineStyle(1, borderColour & 0x00FFFFFF, ((borderColour & 0xFF000000) >>> 24) / 0xFF) - graphics.beginFill(colour & 0x00FFFFFF, ((colour & 0xFF000000) >>> 24) / 0xFF); + graphics.lineStyle(1, borderColor & 0x00FFFFFF, ((borderColor & 0xFF000000) >>> 24) / 0xFF) + graphics.beginFill(color & 0x00FFFFFF, ((color & 0xFF000000) >>> 24) / 0xFF); graphics.drawRect(0, 0, width - 1, height - 1); } @@ -233,58 +221,50 @@ { super.unload() tf_input.removeEventListener(Event.CHANGE, monitorTextInput) - tf_label = null; + cmpi_label = null; tf_input = null; } /* DELEGATE flash.text.TextField */ - public function replaceSelectedText(value:String):void - { + public function replaceSelectedText(value:String):void { tf_input.replaceSelectedText(value); } - public function replaceText(beginIndex:int, endIndex:int, newText:String):void - { + public function replaceText(beginIndex:int, endIndex:int, newText:String):void { tf_input.replaceText(beginIndex, endIndex, newText); } - public function get restrict():String - { + public function get restrict():String { return tf_input.restrict; } - public function set restrict(value:String):void - { + public function set restrict(value:String):void { tf_input.restrict = value; } - public function get selectedText():String - { + public function get selectedText():String { return tf_input.selectedText; } - public function get selectionBeginIndex():int - { + public function get selectionBeginIndex():int { return tf_input.selectionBeginIndex; } - public function get selectionEndIndex():int - { + public function get selectionEndIndex():int { return tf_input.selectionEndIndex; } - public function setSelection(beginIndex:int, endIndex:int):void - { + public function setSelection(beginIndex:int, endIndex:int):void { tf_input.setSelection(beginIndex, endIndex); } + /* END DELEGATE */ + public function resizeWidth():void { - tf_label.autoSize = TextFieldAutoSize.LEFT - var widthVal:Number = tf_label.width - tf_label.autoSize = TextFieldAutoSize.NONE - width = widthVal + 16 + cmpi_label.resizeWidth() + width = cmpi_label.width + 16 } public function resizeHeight():void @@ -313,11 +293,11 @@ return uint(getStyle(DefaultStyle.BACKGROUND)) } - public function set borderColour(val:uint):void { + public function set borderColor(val:uint):void { setStyle(DefaultInnerTextStyle.BORDER, val) } - public function get borderColour():uint { + public function get borderColor():uint { return uint(getStyle(DefaultInnerTextStyle.BORDER)) } diff --git a/src/syncomps/ToggleIcon.as b/src/syncomps/ToggleIcon.as index bcbdb83..050e171 100644 --- a/src/syncomps/ToggleIcon.as +++ b/src/syncomps/ToggleIcon.as @@ -18,10 +18,11 @@ public function ToggleIcon() { init(null, null, false) } + public function update(bitmapOn:BitmapData, bitmapOff:BitmapData):void { bmp_off.bitmapData = bitmapOff - bmp_on.bitmapData = bitmapOn + bmp_on.bitmapData = bitmapOn } private function init(bitmapOn:BitmapData, bitmapOff:BitmapData, visibleInit:Boolean):void { diff --git a/src/syncomps/ToolTip.as b/src/syncomps/ToolTip.as index 1e970c3..14867bf 100644 --- a/src/syncomps/ToolTip.as +++ b/src/syncomps/ToolTip.as @@ -18,8 +18,8 @@ package syncomps import flash.text.TextFormat; import flash.utils.Timer; import syncomps.events.StyleEvent; - import syncomps.interfaces.ILabel; import syncomps.interfaces.IStyleDefinition; + import syncomps.interfaces.IStyleInternal; import syncomps.styles.DefaultInnerTextStyle; import syncomps.styles.Style; import syncomps.styles.DefaultStyle; @@ -29,28 +29,28 @@ package syncomps * ... * @author Gimmick */ - public class ToolTip extends NativeWindow implements IStyleDefinition, ILabel + public class ToolTip extends NativeWindow implements IStyleDefinition { public static const DEFAULT_OFFSET:int = 16 protected static var DEFAULT_STYLE:Class = DefaultInnerTextStyle - - private static const MAX_WIDTH:int = 380; + private static const MAX_WIDTH:Number = 380; private static var nwnd_toolTip:ToolTip; - private var cl_style:Style - private var num_hideDelay:Number; - private var shp_bg:Shape; private var tf_text:SkinnableTextField; - private var cl_timer:Timer; + private var cl_style:IStyleInternal private var b_enabled:Boolean; + private var i_maxWidth:int; + private var shp_bg:Shape; + private var cl_timer:Timer; + private var num_hideDelay:Number; public function ToolTip() { var options:NativeWindowInitOptions = new NativeWindowInitOptions() options.maximizable = options.minimizable = options.resizable = false; options.systemChrome = NativeWindowSystemChrome.NONE - options.transparent = true; options.type = NativeWindowType.LIGHTWEIGHT + options.transparent = true; super(options) init() @@ -63,31 +63,51 @@ package syncomps private function init():void { - shp_bg = new Shape() - cl_timer = new Timer(1000, 2) - tf_text = new SkinnableTextField() stage.scaleMode = StageScaleMode.NO_SCALE stage.align = StageAlign.TOP_LEFT + cl_timer = new Timer(1000, 2) + shp_bg = new Shape() + tf_text = new SkinnableTextField() + cl_style = (new (getDefaultStyle())()) as IStyleInternal + styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, redrawOnStyleChange, false, 0, true) + styleDefinition.addEventListener(StyleEvent.STYLE_CHANGING, updateStyles, false, 0, true) StyleManager.unregister(tf_text) + b_enabled = true + + maxWidth = MAX_WIDTH tf_text.selectable = tf_text.enabled = false; tf_text.antiAliasType = AntiAliasType.ADVANCED + tf_text.autoSize = TextFieldAutoSize.LEFT; tf_text.x = tf_text.y = 4; tf_text.width = 100; stage.addChild(shp_bg) stage.addChild(tf_text) - cl_style = (new (getDefaultStyle())()) as Style; - styleDefinition.addEventListener(StyleEvent.STYLE_CHANGE, updateStyles, false, 0, true) - cl_timer.addEventListener(TimerEvent.TIMER, toggleOnTimer, false, 0, true) + stage.tabChildren = false; + addEventListener(MouseEvent.ROLL_OVER, hideOnEvent, false, 0, true); + cl_timer.addEventListener(TimerEvent.TIMER, toggleOnTimer, false, 0, true); } - public function get textField():TextField { - return tf_text + private function updateStyles(evt:StyleEvent):void + { + evt.preventDefault() + if (dispatchEvent(evt)) { + styleDefinition.forceStyle(evt.style, evt.value) + } } - private function updateStyles(evt:StyleEvent):void { + private function redrawOnStyleChange(evt:StyleEvent):void + { + var bounds:Rectangle = textField.getBounds(null) + stage.stageWidth = bounds.width + 8 + stage.stageHeight = bounds.height + 8 tf_text.setStyle(evt.style, evt.value) + drawGraphics(stage.stageWidth, stage.stageHeight) + } + + private function hideOnEvent(evt:MouseEvent):void { + hide() } private function hide():void @@ -96,31 +116,6 @@ package syncomps cl_timer.reset() } - /* INTERFACE syncomps.interfaces.IStyleDefinition */ - - public function get styleDefinition():Style { - return cl_style; - } - - public function getStyle(style:Object):Object { - return cl_style.getStyle(style) - } - - public function setStyle(style:Object, value:Object):void { - cl_style.setStyle(style, value) - } - - public function applyStyle(style:Style):void { - cl_style.applyStyle(style) - } - - public function getDefaultStyle():Class { - return DEFAULT_STYLE - } - public function setDefaultStyle(styleClass:Class):void { - DEFAULT_STYLE = styleClass - } - private function toggleOnTimer(evt:TimerEvent):void { if (cl_timer.currentCount == 1) @@ -140,7 +135,6 @@ package syncomps } } visible = true - orderToFront() cl_timer.delay = num_hideDelay } else if(cl_timer.currentCount == 2) { @@ -148,75 +142,126 @@ package syncomps } } + /* DELEGATES */ + private function resetTimer():void { + cl_timer.reset() + } + + private function setDelays(timerDelay:Number, hideDelay:Number):void + { + cl_timer.delay = timerDelay + num_hideDelay = hideDelay + } + + private function startDisplay():void { + cl_timer.start() + } + + /* INTERFACE syncomps.interfaces.IStyleDefinition <=> DELEGATE syncomps.ToolTipGUI */ + public function get styleDefinition():IStyleInternal { + return cl_style + } + + public function getStyle(style:Object):Object { + return styleDefinition.getStyle(style); + } + + public function setStyle(style:Object, value:Object):void { + styleDefinition.setStyle(style, value); + } + + public function applyStyle(style:IStyleInternal):void { + styleDefinition.applyStyle(style) + } + + public function getDefaultStyle():Class { + return DEFAULT_STYLE + } + public function setDefaultStyle(styleClass:Class):void { + DEFAULT_STYLE = styleClass + } + + public function get textField():TextField { + return tf_text + } + + public function get maxWidth():int { + return i_maxWidth; + } + + public function set maxWidth(value:int):void { + i_maxWidth = value; + } + private function setText(text:String):void { tf_text.text = text; - tf_text.multiline = false; - tf_text.wordWrap = false; - tf_text.autoSize = TextFieldAutoSize.LEFT; - tf_text.text = text; - if (tf_text.width > MAX_WIDTH) - { - tf_text.multiline = true; - tf_text.wordWrap = true; - tf_text.width = MAX_WIDTH; + tf_text.multiline = tf_text.wordWrap = (tf_text.width > maxWidth) + if (tf_text.width > maxWidth) { + tf_text.width = maxWidth; } } private function drawGraphics(width:int, height:int):void { - var colour:uint = uint(getStyle(DefaultStyle.BACKGROUND)), colourAlpha:Number; - if (!enabled) { - colour = uint(getStyle(DefaultStyle.DISABLED)) + var color:uint = uint(getStyle(DefaultStyle.BACKGROUND)), colorAlpha:Number; + if (!b_enabled) { + color = uint(getStyle(DefaultStyle.DISABLED)) } - colourAlpha = ((colour & 0xFF000000) >>> 24) / 0xFF; - colour = colour & 0x00FFFFFF + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF shp_bg.graphics.clear() shp_bg.graphics.lineStyle(0, 0, 0.25) - shp_bg.graphics.beginFill(colour, colourAlpha) + shp_bg.graphics.beginFill(color, colorAlpha) shp_bg.graphics.drawRect(0, 0, width - 1, height - 1) shp_bg.graphics.endFill() } + public function set enabled(value:Boolean):void + { + b_enabled = value; + if (!value) { + hide() + } + } + + private static function get mainInstance():ToolTip { + return nwnd_toolTip || new ToolTip() + } + public static function get enabled():Boolean { return mainInstance.b_enabled } public static function set enabled(value:Boolean):void { - mainInstance.b_enabled = value + mainInstance.enabled = value } public static function hideToolTip():void { mainInstance.hide() } - private static function get mainInstance():ToolTip - { - if(!nwnd_toolTip) { - new ToolTip() - } - return nwnd_toolTip; - } - - public static function displayDelayed(text:String, x:Number, y:Number, delay:Number = 1000, hideDelay:Number = 6000):void + public static function displayDelayed(text:String, xVal:Number, yVal:Number, delay:Number = 1000, hideDelay:Number = 6000):void { var toolTip:ToolTip = mainInstance - toolTip.x = x; - toolTip.y = y; + toolTip.x = xVal; + toolTip.y = yVal; + toolTip.resetTimer() toolTip.setText(text) - toolTip.cl_timer.reset(); - toolTip.cl_timer.delay = delay - toolTip.num_hideDelay = hideDelay - toolTip.width = toolTip.tf_text.width + 8 - toolTip.height = toolTip.tf_text.height + 8 - toolTip.drawGraphics(toolTip.width, toolTip.height) - if(toolTip.b_enabled) { - toolTip.cl_timer.start(); + toolTip.setDelays(delay, hideDelay) + + var bounds:Rectangle = toolTip.textField.getBounds(null) + toolTip.stage.stageWidth = bounds.width + 8 + toolTip.stage.stageHeight = bounds.height + 8 + toolTip.drawGraphics(toolTip.stage.stageWidth, toolTip.stage.stageHeight) + + if(enabled) { + toolTip.startDisplay(); } } - public static function get styleDefinition():Style { + public static function get styleDefinition():IStyleInternal { return mainInstance.styleDefinition } @@ -228,7 +273,7 @@ package syncomps mainInstance.setStyle(style, value) } - public static function applyStyle(style:Style):void { + public static function applyStyle(style:IStyleInternal):void { mainInstance.applyStyle(style) } @@ -236,17 +281,26 @@ package syncomps return mainInstance && mainInstance.visible } + public static function get maxWidth():int { + return mainInstance.maxWidth + } + + public static function set maxWidth(maxWidth:int):void { + mainInstance.maxWidth = maxWidth + } public static function unload():void { var toolTip:ToolTip = mainInstance - if (toolTip.closed) { - return; + with (toolTip) + { + if (closed) { + return; + } + cl_timer.removeEventListener(TimerEvent.TIMER, toolTip.toggleOnTimer) + stage.removeChildren() + close() } - toolTip.cl_timer.removeEventListener(TimerEvent.TIMER, toolTip.toggleOnTimer) - toolTip.stage.removeChildren() - toolTip.close() } - } } \ No newline at end of file diff --git a/src/syncomps/ToolTipMessageManager.as b/src/syncomps/ToolTipMessageManager.as index 5e92d2d..a7f6778 100644 --- a/src/syncomps/ToolTipMessageManager.as +++ b/src/syncomps/ToolTipMessageManager.as @@ -69,7 +69,7 @@ package syncomps private function displayToolTipOnEvent(evt:MouseEvent):void { - var currTarget:DisplayObject = evt.target as DisplayObject + var currTarget:DisplayObject = evt.currentTarget as DisplayObject if (currTarget && currTarget.stage) { displayToolTip(evt.stageX, evt.stageY, currTarget.stage.nativeWindow, currTarget) } @@ -94,19 +94,16 @@ package syncomps private function setMessages(targets:Array, messages:Array):void { - for (var i:uint = 0; i < targets.length && i < messages.length; ++i) { - setMessage(targets[i] as InteractiveObject, messages[i] as String) - } + targets.forEach(function applyMessage(item:InteractiveObject, index:int, array:Array):void { + messages && index < messages.length && setMessage(item, messages[index] as String) + }, this); } private function removeMessages(targets:Array):void { - if (targets) - { - for (var i:uint = 0; i < targets.length; ++i) { - removeMessage(targets[i] as InteractiveObject) - } - } + targets && targets.forEach(function deleteMessage(item:InteractiveObject, index:int, array:Array):void { + removeMessage(item) + }, this); } private function unloadAll():void diff --git a/src/syncomps/VBox.as b/src/syncomps/VBox.as new file mode 100644 index 0000000..ceea879 --- /dev/null +++ b/src/syncomps/VBox.as @@ -0,0 +1,284 @@ +package syncomps +{ + import flash.display.DisplayObject; + import flash.display.Sprite; + import syncomps.data.DataElement; + import syncomps.data.DataProvider; + import syncomps.events.DataProviderEvent; + import syncomps.interfaces.graphics.IAutoResize; + import syncomps.styles.DefaultStyle; + import syncomps.styles.ScrollPaneStyle; + /** + * ... + * @author Gimmick + */ + public class VBox extends SynComponent + { + protected static var DEFAULT_STYLE:Class = DefaultStyle + + private var dp_items:DataProvider + + private var cl_scrollPane:ScrollPane; + private var spr_contents:Sprite; + private var num_spacing:Number; + private var num_xPadding:Number; + private var num_yPadding:Number; + public function VBox() { + init() + } + + private function init():void + { + tabChildren = false; + spr_contents = new Sprite() + cl_scrollPane = new ScrollPane() + dataProvider = new DataProvider() + cl_scrollPane.source = spr_contents + cl_scrollPane.x = cl_scrollPane.y = 1 + num_spacing = num_xPadding = num_yPadding = 0 + + cl_scrollPane.setStyle(ScrollPaneStyle.SCROLL_POLICY, ScrollPaneStyle.POLICY_VERTICAL) + cl_scrollPane.displayScrollBars(false) + + addChild(cl_scrollPane) + drawGraphics(64, 64, DefaultStyle.BACKGROUND) + } + + override public function getDefaultStyle():Class { + return DEFAULT_STYLE + } + + override public function setDefaultStyle(styleClass:Class):void { + DEFAULT_STYLE = styleClass + } + + public function get dataProvider():DataProvider { + return dp_items + } + + public function set dataProvider(provider:DataProvider):void + { + if(provider && provider == dp_items) { + return; + } + if (dp_items) + { + dp_items.removeEventListener(DataProviderEvent.ITEM_ADDED, updateListOnEvent) + dp_items.removeEventListener(DataProviderEvent.ITEM_REMOVED, updateListOnEvent) + dp_items.removeEventListener(DataProviderEvent.DATA_REFRESH, updateListOnEvent) + } + dp_items = provider + if (provider) + { + provider.addEventListener(DataProviderEvent.ITEM_REMOVED, updateListOnEvent, false, 0, true) + provider.addEventListener(DataProviderEvent.DATA_REFRESH, updateListOnEvent, false, 0, true) + provider.addEventListener(DataProviderEvent.ITEM_ADDED, updateListOnEvent, false, 0, true) + } + rebuildList(0) + } + + private function updateListOnEvent(evt:DataProviderEvent):void + { + rebuildList(evt.index) + dispatchEvent(evt) + } + + private function rebuildList(start:uint):void + { + if (dp_items) + { + spr_contents.removeChildren(dp_items.numItems) + dp_items.forEach(function addChildren(item:DisplayObject, index:int, array:Array):void { + spr_contents.addChild(item) + }); + } + cl_scrollPane.refreshPane() + drawGraphics(width, height, state) + } + + override public function get height():Number { + return cl_scrollPane.height + cl_scrollPane.y + 1 + } + + override public function get width():Number { + return cl_scrollPane.width + cl_scrollPane.x + 1 + } + + override protected function drawGraphics(width:int, height:int, state:String):void + { + super.drawGraphics(width, height, state) + graphics.clear() + var color:uint = uint(getStyle(state)), colorAlpha:Number + if (!enabled) { + color = uint(getStyle(DefaultStyle.DISABLED)) + } + colorAlpha = ((color & 0xFF000000) >>> 24) / 0xFF; + color = color & 0x00FFFFFF + graphics.lineStyle(1, 0, colorAlpha) + graphics.beginFill(color, colorAlpha) + graphics.drawRect(0, 0, width - 1, height - 1) + cl_scrollPane.height = height - 2; + cl_scrollPane.width = width - 2; + var currY:Number = num_yPadding + const xSpace:Number = num_xPadding * 2 + dp_items.forEach(function alignItems(item:DisplayObject, index:int, array:Array):void + { + item.width = width - xSpace + item.x = num_xPadding + item.y = currY + + currY += item.height + num_spacing + }, this); + } + + public function resizeWidth():void + { + var maxWidth:int; + dp_items.forEach(function resizeAll(item:DisplayObject, index:int, array:Array):void + { + if(item is IAutoResize) { + (item as IAutoResize).resizeWidth(); + } + + if(item.width > maxWidth) { + maxWidth = item.width + } + }, this); + + drawGraphics(maxWidth, height, state) + } + + public function resizeHeight():void + { + var totalHeight:int + const spacing:Number = num_spacing; + dp_items.forEach(function resizeAll(item:DisplayObject, index:int, array:Array):void + { + if(item is IAutoResize) { + (item as IAutoResize).resizeHeight() + } + + totalHeight += item.height + spacing; + }, this); + drawGraphics(width, totalHeight, state) + } + + override public function unload():void + { + super.unload() + removeChildren() + dataProvider = null; + cl_scrollPane.unload() + spr_contents.removeChildren() + } + + public function displayScrollBars(forceDisplay:Boolean):void { + cl_scrollPane.displayScrollBars(forceDisplay); + } + + public function hideScrollBars():void { + cl_scrollPane.hideScrollBars(); + } + + public function addItem(item:Object):void { + dp_items.addItem(DisplayObject(item)); + } + + public function addItemAt(item:Object, index:int):void { + dp_items.addItemAt(DisplayObject(item), index); + } + + public function addItems(items:Array):void + { + dp_items.addItems(items.filter(function isDisplayObject(item:Object, index:int, array:Array):Boolean { + return item is DisplayObject + })); + } + + public function getItemAt(index:int):DataElement { + return dp_items.getItemAt(index); + } + + public function getItemBy(predicate:Function):DataElement { + return dp_items.getItemBy(predicate); + } + + public function indexOf(searchFunction:Function):int { + return dp_items.indexOf(searchFunction); + } + + public function get items():Array { + return dp_items.items; + } + + public function set items(value:Array):void + { + dp_items.items = value && value.filter(function isDisplayObject(item:Object, index:int, array:Array):Boolean { + return item is DisplayObject + }); + } + + public function get numItems():uint { + return dp_items.numItems; + } + + public function removeItem(item:Object):Object { + return dp_items.removeItem(DisplayObject(item)); + } + + public function removeItemAt(index:int):Object { + return dp_items.removeItemAt(index); + } + + public function removeItems():void { + dp_items.removeItems(); + } + + override public function set enabled(value:Boolean):void + { + if(value != cl_scrollPane.enabled) { + super.enabled = cl_scrollPane.enabled = value + } + } + + public function get spacing():Number { + return num_spacing; + } + + public function set spacing(value:Number):void + { + if (spacing != value) + { + num_spacing = value; + drawGraphics(width, height, state) + } + } + + public function get xPadding():Number { + return num_xPadding; + } + + public function set xPadding(value:Number):void + { + if (xPadding != value) + { + num_xPadding = value; + drawGraphics(width, height, state) + } + } + + public function get yPadding():Number { + return num_yPadding; + } + + public function set yPadding(value:Number):void + { + if (yPadding != value) + { + num_yPadding = value; + drawGraphics(width, height, state) + } + } + } + +} \ No newline at end of file diff --git a/src/syncomps/data/DataElement.as b/src/syncomps/data/DataElement.as index 5610125..5aa97aa 100644 --- a/src/syncomps/data/DataElement.as +++ b/src/syncomps/data/DataElement.as @@ -23,7 +23,7 @@ package syncomps.data obj_proxy = new Object() } vec_properties = new Vector.(); - for(var prop:* in obj_proxy) { + for (var prop:* in obj_proxy) { vec_properties.push(prop) } } @@ -31,7 +31,7 @@ package syncomps.data { var functor:Function = getProperty(methodName) as Function if (functor != null) { - return functor.apply(null, args); + return functor.apply(this, args); } return undefined; } @@ -88,6 +88,7 @@ package syncomps.data internal function setDispatcher(dispatcher:EventDispatcher):void { cl_dispatcher = dispatcher } + /** * Returns the proxy's underlying object. */ diff --git a/src/syncomps/data/DataProvider.as b/src/syncomps/data/DataProvider.as index 32f4dca..5e6bdf9 100644 --- a/src/syncomps/data/DataProvider.as +++ b/src/syncomps/data/DataProvider.as @@ -1,5 +1,6 @@ package syncomps.data { + import flash.events.Event; import syncomps.events.DataProviderEvent; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; @@ -9,126 +10,295 @@ package syncomps.data * ... * @author Gimmick */ - public class DataProvider extends EventDispatcher implements IDataProvider + public class DataProvider implements IDataProvider { - private var arr_data:Array; - public function DataProvider() + private var arr_data:Array + private var cl_dispatcher:IEventDispatcher + public function DataProvider() { - init() + cl_dispatcher = new EventDispatcher(this) + arr_data = new DispatchedArray(cl_dispatcher) } - private function init():void - { - arr_data = new Array() - } - public function get length():uint { - return arr_data.length - } - public function get numItems():uint { - return length + + public function addItem(item:Object):void { + addItemAt(item, length) } - public function removeAll():void + + public function addItems(items:Array):void { - arr_data.length = 0; - dispatchEvent(new DataProviderEvent(DataProviderEvent.DATA_REFRESH, null, 0, false, false)) + items.forEach(function add(item:Object, index:int, array:Array):void { + addItem(item) + }, this) } - public function addItems(items:Array):void + public function addItemAt(item:Object, index:int):void { - for (var i:uint = 0; i < items.length; ++i) { - addItem(items[i]) + if (!(item is DataElement)) { + item = new DataElement(item) } + arr_data.insertAt(index, item) } - public function addItem(item:Object):void { - addItemAt(item, length) - } - public function getItemByField(field:String, value:Object):DataElement - { - var index:int = indexOfByField(field, value) - if(index != -1) { - return getItemAt(index) - } - return null; + + public function removeItems():void { + arr_data.length = 0; } - public function indexOfByField(field:String, value:Object):int + + public function removeItem(item:Object):Object { - if(!(field && value)) { - return -1 - } - for (var i:uint = 0; i < arr_data.length; ++i) + var found:Boolean = arr_data.some(function find(data:DataElement, index:int, array:Array):Boolean { - var item:Object = arr_data[i]; - if(item[field] == value) { - return i + var found:Boolean = (data == item) || (data.objectProperty == item); + if (found) { + removeItemAt(index) } + return found + }, this); + + if(found) { + return item } - return -1; + return null } - public function get dataProvider():DataProvider { - return this; + + public function removeItemAt(index:int):Object { + return arr_data.removeAt(index) } + public function getItemAt(index:int):DataElement { return arr_data[index] } - public function addItemAt(item:Object, index:int):void + + public function get items():Array { + return arr_data.concat(); + } + + public function set items(value:Array):void { - var itemToAdd:Object = item; - if (!(item is DataElement)) - { - itemToAdd = new DataElement(item); - itemToAdd.setDispatcher(this); - } - arr_data.insertAt(index, itemToAdd) - dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_ADDED, itemToAdd as DataElement, index, false, false)) + removeItems() + addItems(value) + } + + public function get numItems():uint { + return arr_data.length + } + + public function clone():DataProvider + { + var provider:DataProvider = new DataProvider() + provider.addItems(arr_data) + return provider } - public function removeItem(item:Object):Object { - return removeItemAt(findItem(item)) + /* DELEGATE flash.events.IEventDispatcher */ + + public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { + cl_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); + } + + public function dispatchEvent(event:Event):Boolean { + return cl_dispatcher.dispatchEvent(event); } - private function findItem(item:Object):int + public function hasEventListener(type:String):Boolean { + return cl_dispatcher.hasEventListener(type); + } + + public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void { + cl_dispatcher.removeEventListener(type, listener, useCapture); + } + + public function willTrigger(type:String):Boolean { + return cl_dispatcher.willTrigger(type); + } + + /* Functional-style methods */ + + public function filter(callback:Function, thisObject:* = null):IDataProvider { - if (item is DataElement) { - return arr_data.indexOf(item) + function filterer(item:DataElement, index:int, array:Array):Boolean { + return callback.call(thisObject, item.objectProperty, index, array) } - return indexOfByField("objectProperty", item) + var provider:DataProvider = new DataProvider() + provider.addItems(arr_data.filter(filterer, thisObject)); + return provider } - public function removeItemAt(index:int):Object + + public function forEach(callback:Function, thisObject:* = null):void { - if (index >= 0 && index < arr_data.length) - { - var item:DataElement = arr_data.removeAt(index); - var removedItem:Object = item.objectProperty - item.setDispatcher(null) - dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_REMOVED, item, index, false, false)) - return removedItem + function eachFor(item:DataElement, index:int, array:Array):void { + callback.call(thisObject, item.objectProperty, index, array) } - return null + arr_data.forEach(eachFor, thisObject); } - public function forceRefresh():void { - dispatchEvent(new DataProviderEvent(DataProviderEvent.DATA_REFRESH, null, 0, false, false)) + public function map(callback:Function, thisObject:* = null):IDataProvider + { + function mapper(item:DataElement, index:int, array:Array):* { + return callback.call(thisObject, item.objectProperty, index, array) + } + var provider:DataProvider = new DataProvider() + provider.addItems(arr_data.map(mapper, thisObject)); + return provider } - public function sort(...rest):void + public function some(callback:Function, thisObject:* = null):Boolean { - arr_data.sort.apply(null, rest); - forceRefresh() + function checkSome(item:DataElement, index:int, array:Array):Boolean { + return callback.call(thisObject, item.objectProperty, index, array) + } + return arr_data.some(checkSome, thisObject); } - public function sortOn(names:*, options:*= 0, ...rest):void + public function every(callback:Function, thisObject:* = null):Boolean { - arr_data.sortOn.apply(null, [names, options, rest]) - forceRefresh() + function checkEvery(item:DataElement, index:int, array:Array):Boolean { + return callback.call(thisObject, item.objectProperty, index, array) + } + return arr_data.every(checkEvery, thisObject); + } + + public function indexOf(searchFunction:Function, fromIndex:int = 0):int + { + var searchIndex:int = -1 + arr_data.some(function search(data:DataElement, index:int, array:Array):Boolean + { + if(index < fromIndex) { + return false + } + else if(searchFunction.call(this, data.objectProperty, index, array)) { + searchIndex = index + } + return searchIndex != -1 + }, this); + return searchIndex + } + + public function getItemBy(searchFunction:Function):DataElement { + return getItemAt(indexOf(searchFunction)) } - public function get items():Array + public function lastIndexOf(searchFunction:Function, fromIndex:int = int.MAX_VALUE):int { - var itemList:Array = new Array() - for (var i:uint = 0; i < arr_data.length; ++i) { - itemList.push((arr_data[i] as DataElement).objectProperty) + var searchIndex:int = -1 + if(fromIndex == int.MAX_VALUE) { + fromIndex = arr_data.length } - return itemList + var lastIndex:int = arr_data.length - fromIndex + arr_data.reverse() + arr_data.some(function search(data:DataElement, index:int, array:Array):Boolean + { + if(index < lastIndex) { + return false + } + var found:Boolean = searchFunction.call(this, data.objectProperty, index, array) + if(found) { + searchIndex = index + } + return found + }, this); + arr_data.reverse() + return searchIndex } } +} +import flash.events.Event; +import flash.events.EventDispatcher; +import flash.events.IEventDispatcher; +import syncomps.events.DataProviderEvent; +import syncomps.data.DataElement; + +dynamic internal class DispatchedArray extends Array implements IEventDispatcher +{ + private var cl_dispatcher:IEventDispatcher + public function DispatchedArray(dispatcher:IEventDispatcher) + { + super() + cl_dispatcher = dispatcher + } + + override AS3 function insertAt(index:int, element:*):void + { + super.insertAt(index, element); + dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_ADDED, DataElement(element), index, false, false)) + } + + override AS3 function pop():* + { + var obj:* = super.pop(); + if (obj !== undefined) { + dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_REMOVED, DataElement(obj), length + 1, false, false)) + } + return obj; + } + + override AS3 function push(...rest):uint + { + var prevLen:uint = length + var len:uint = super.push.apply(this, rest); + rest.forEach(function dispatch(item:Object, index:int, array:Array):void { + dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_ADDED, DataElement(item), index + prevLen, false, false)) + }); + return len; + } + + override AS3 function removeAt(index:int):* + { + var obj:* = super.removeAt(index); + dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_REMOVED, DataElement(obj), index, false, false)) + return obj + } + + override AS3 function reverse():Array + { + var array:Array = super.reverse(); + dispatchEvent(new DataProviderEvent(DataProviderEvent.DATA_REFRESH, null, 0, false, false)) + return array; + } + + override AS3 function shift():* + { + var obj:* = super.shift(); + if (obj !== undefined) { + dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_REMOVED, DataElement(obj), 0, false, false)) + } + return obj + } + + override AS3 function splice(...args):* + { + var retArr:Array = super.splice.apply(this, args) + dispatchEvent(new DataProviderEvent(DataProviderEvent.DATA_REFRESH, null, 0, false, false)) + return retArr + } + + override AS3 function unshift(...rest):uint + { + var len:uint = super.unshift.apply(this, rest) + rest.forEach(function dispatch(item:Object, index:int, array:Array):void { + dispatchEvent(new DataProviderEvent(DataProviderEvent.ITEM_ADDED, DataElement(item), index, false, false)) + }); + return len + } + + /* DELEGATE flash.events.IEventDispatcher */ + public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { + cl_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); + } + + public function dispatchEvent(event:Event):Boolean { + return cl_dispatcher.dispatchEvent(event); + } + + public function hasEventListener(type:String):Boolean { + return cl_dispatcher.hasEventListener(type); + } + + public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void { + cl_dispatcher.removeEventListener(type, listener, useCapture); + } + + public function willTrigger(type:String):Boolean { + return cl_dispatcher.willTrigger(type); + } } \ No newline at end of file diff --git a/src/syncomps/events/ButtonEvent.as b/src/syncomps/events/ButtonEvent.as index f61465a..1a126cf 100644 --- a/src/syncomps/events/ButtonEvent.as +++ b/src/syncomps/events/ButtonEvent.as @@ -5,16 +5,17 @@ package syncomps.events /** * @eventType syncomps.events.ButtonEvent.CLICK */ - [Event(name="CLICK", type="syncomps.events.ButtonEvent")] + [Event(name = "synBEButtonClick", type = "syncomps.events.ButtonEvent")] + /** * ... * @author Gimmick */ public class ButtonEvent extends Event { - public static const CLICK:String = "CLICK"; + public static const CLICK:String = "synBEButtonClick"; - public function ButtonEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) { + public function ButtonEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); } diff --git a/src/syncomps/events/DataProviderEvent.as b/src/syncomps/events/DataProviderEvent.as index 392fed5..472858d 100644 --- a/src/syncomps/events/DataProviderEvent.as +++ b/src/syncomps/events/DataProviderEvent.as @@ -6,17 +6,17 @@ package syncomps.events /** * @eventType syncomps.events.DatProviderEvent.ITEM_ADDED */ - [Event(name = "ITEM_ADDED", type = "syncomps.events.DataProviderEvent")] + [Event(name = "synDPEItemAdded", type = "syncomps.events.DataProviderEvent")] /** * @eventType syncomps.events.DatProviderEvent.ITEM_REMOVED */ - [Event(name = "ITEM_REMOVED", type = "syncomps.events.DataProviderEvent")] + [Event(name = "synDPEItemRemoved", type = "syncomps.events.DataProviderEvent")] /** * @eventType syncomps.events.DatProviderEvent.DATA_REFRESH */ - [Event(name = "DATA_REFRESH", type = "syncomps.events.DataProviderEvent")] + [Event(name = "synDPEDataRefresh", type = "syncomps.events.DataProviderEvent")] /** * ... @@ -24,12 +24,13 @@ package syncomps.events */ public class DataProviderEvent extends Event { - public static const ITEM_ADDED:String = "ITEM_ADDED" - static public const ITEM_REMOVED:String = "ITEM_REMOVED"; - static public const DATA_REFRESH:String = "DATA_REFRESH"; - private var obj_item:DataElement + public static const ITEM_ADDED:String = "synDPEItemAdded" + static public const ITEM_REMOVED:String = "synDPEItemRemoved"; + static public const DATA_REFRESH:String = "synDPEDataRefresh"; + private var i_index:int - public function DataProviderEvent(type:String, item:DataElement, index:int, bubbles:Boolean=false, cancelable:Boolean=false) + private var obj_item:DataElement + public function DataProviderEvent(type:String, item:DataElement, index:int, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); obj_item = item; diff --git a/src/syncomps/events/ListEvent.as b/src/syncomps/events/ListEvent.as new file mode 100644 index 0000000..7ec5586 --- /dev/null +++ b/src/syncomps/events/ListEvent.as @@ -0,0 +1,46 @@ +package syncomps.events +{ + import flash.events.Event; + import syncomps.data.DataElement; + + /** + * @eventType syncomps.events.ListEvent.CELL_CLICK + */ + [Event(name = "synLCECellClick", type = "syncomps.events.ListEvent")] + + /** + * ... + * @author Gimmick + */ + public class ListEvent extends Event + { + public static const CELL_CLICK:String = "synLCECellClick"; + + private var i_index:int; + private var obj_item:DataElement; + public function ListEvent(type:String, index:int, item:DataElement, bubbles:Boolean = false, cancelable:Boolean = false) + { + super(type, bubbles, cancelable); + i_index = index + obj_item = item; + } + + public override function clone():Event { + return new ListEvent(type, i_index, obj_item, bubbles, cancelable); + } + + public override function toString():String { + return formatToString("ListEvent", "type", "index", "bubbles", "cancelable", "eventPhase"); + } + + public function get index():int { + return i_index; + } + + public function get item():DataElement { + return obj_item; + } + + } + +} \ No newline at end of file diff --git a/src/syncomps/events/ScrollEvent.as b/src/syncomps/events/ScrollEvent.as index 4580bf3..17cbd53 100644 --- a/src/syncomps/events/ScrollEvent.as +++ b/src/syncomps/events/ScrollEvent.as @@ -5,7 +5,7 @@ package syncomps.events /** * @eventType syncomps.events.ScrollEvent.SCROLL */ - [Event(name = "SCROLL", type = "syncomps.events.ScrollEvent")] + [Event(name = "synScEScroll", type = "syncomps.events.ScrollEvent")] /** * ... @@ -13,16 +13,17 @@ package syncomps.events */ public class ScrollEvent extends Event { - public static const SCROLL:String = "SCROLL" + public static const SCROLL:String = "synScEScroll"; + + private var i_direction:int; private var num_delta:Number; private var num_scrollPosition:Number; - private var i_direction:int; - public function ScrollEvent(type:String, scrollPosition:Number, direction:int, delta:Number = 0, bubbles:Boolean=false, cancelable:Boolean=false) + public function ScrollEvent(type:String, scrollPosition:Number, direction:int, delta:Number = 0, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); - num_scrollPosition = scrollPosition num_delta = delta i_direction = direction; + num_scrollPosition = scrollPosition } public override function clone():Event { diff --git a/src/syncomps/events/StyleEvent.as b/src/syncomps/events/StyleEvent.as index 26e80a1..1ba34b0 100644 --- a/src/syncomps/events/StyleEvent.as +++ b/src/syncomps/events/StyleEvent.as @@ -5,12 +5,12 @@ package syncomps.events /** * @eventType syncomps.events.StyleEvent.STYLE_CHANGE */ - [Event(name = "STYLE_CHANGE", type = "syncomps.events.StyleEvent")] + [Event(name = "synStEStyleChange", type = "syncomps.events.StyleEvent")] /** * @eventType syncomps.events.StyleEvent.STYLE_CHANGING */ - [Event(name = "STYLE_CHANGING", type = "syncomps.events.StyleEvent")] + [Event(name = "synStEStyleChanging", type = "syncomps.events.StyleEvent")] /** * ... @@ -18,8 +18,8 @@ package syncomps.events */ public class StyleEvent extends Event { - public static const STYLE_CHANGE:String = "STYLE_CHANGE" - static public const STYLE_CHANGING:String = "STYLE_CHANGING"; + public static const STYLE_CHANGE:String = "synStEStyleChange"; + public static const STYLE_CHANGING:String = "synStEStyleChanging"; private var obj_style:Object; private var obj_value:Object; public function StyleEvent(type:String, style:Object, value:Object, bubbles:Boolean=false, cancelable:Boolean=false) diff --git a/src/syncomps/interfaces/IDataProvider.as b/src/syncomps/interfaces/IDataProvider.as index 697c401..1543b40 100644 --- a/src/syncomps/interfaces/IDataProvider.as +++ b/src/syncomps/interfaces/IDataProvider.as @@ -1,5 +1,6 @@ package syncomps.interfaces { + import flash.events.IEventDispatcher; import syncomps.data.DataElement; import syncomps.data.DataProvider; @@ -7,17 +8,24 @@ package syncomps.interfaces * ... * @author Gimmick */ - public interface IDataProvider + public interface IDataProvider extends IEventDispatcher { - function addItem(item:Object):void; - function addItemAt(item:Object, index:int):void; - function removeItem(item:Object):Object; - function removeItemAt(index:int):Object; - function getItemAt(index:int):DataElement; - function removeAll():void; - function get items():Array; - function get numItems():uint; - function get dataProvider():DataProvider + function addItem(item:Object):void + function addItems(items:Array):void + function addItemAt(item:Object, index:int):void + + function removeItems():void + function removeItem(item:Object):Object + function removeItemAt(index:int):Object + + function getItemAt(index:int):DataElement + function indexOf(searchFunction:Function, fromIndex:int = 0):int + function getItemBy(predicate:Function):DataElement + + function get items():Array + function set items(items:Array):void + + function get numItems():uint } } \ No newline at end of file diff --git a/src/syncomps/interfaces/IStyleDefinition.as b/src/syncomps/interfaces/IStyleDefinition.as index e79b020..1a6d2c8 100644 --- a/src/syncomps/interfaces/IStyleDefinition.as +++ b/src/syncomps/interfaces/IStyleDefinition.as @@ -1,17 +1,19 @@ package syncomps.interfaces { + import flash.events.IEventDispatcher; + import flash.utils.Dictionary; import syncomps.styles.Style; /** * ... * @author Gimmick */ - public interface IStyleDefinition + public interface IStyleDefinition extends IEventDispatcher { - function get styleDefinition():Style + function get styleDefinition():IStyleInternal function getStyle(style:Object):Object function setStyle(style:Object, value:Object):void - function applyStyle(style:Style):void + function applyStyle(style:IStyleInternal):void function getDefaultStyle():Class function setDefaultStyle(styleClass:Class):void } diff --git a/src/syncomps/interfaces/IStyleInternal.as b/src/syncomps/interfaces/IStyleInternal.as new file mode 100644 index 0000000..8ad728a --- /dev/null +++ b/src/syncomps/interfaces/IStyleInternal.as @@ -0,0 +1,18 @@ +package syncomps.interfaces +{ + import flash.utils.Dictionary; + + /** + * ... + * @author Gimmick + */ + public interface IStyleInternal extends IStyleDefinition + { + function forceStyle(style:Object, value:Object):void; + + function getInheritanceChain():Vector.; + function getStyleProperties():Dictionary; + function getFields():Array; + } + +} \ No newline at end of file diff --git a/src/syncomps/interfaces/ISynComponent.as b/src/syncomps/interfaces/ISynComponent.as index 063aed4..19a096c 100644 --- a/src/syncomps/interfaces/ISynComponent.as +++ b/src/syncomps/interfaces/ISynComponent.as @@ -1,17 +1,17 @@ package syncomps.interfaces { import flash.events.IEventDispatcher; + import syncomps.interfaces.graphics.IDisplayObject; /** * ... * @author Gimmick */ - public interface ISynComponent extends IStyleDefinition, IEventDispatcher + public interface ISynComponent extends IDisplayObject, IStyleDefinition { function unload():void; - function refresh():void; - function set enabled(value:Boolean):void; function get enabled():Boolean; + function set enabled(value:Boolean):void; } } \ No newline at end of file diff --git a/src/syncomps/interfaces/graphics/IAutoResize.as b/src/syncomps/interfaces/graphics/IAutoResize.as new file mode 100644 index 0000000..acb87c4 --- /dev/null +++ b/src/syncomps/interfaces/graphics/IAutoResize.as @@ -0,0 +1,14 @@ +package syncomps.interfaces.graphics +{ + + /** + * ... + * @author Gimmick + */ + public interface IAutoResize + { + function resizeWidth():void + function resizeHeight():void + } + +} \ No newline at end of file diff --git a/src/syncomps/interfaces/graphics/IDisplayObject.as b/src/syncomps/interfaces/graphics/IDisplayObject.as new file mode 100644 index 0000000..47a309f --- /dev/null +++ b/src/syncomps/interfaces/graphics/IDisplayObject.as @@ -0,0 +1,1156 @@ +package syncomps.interfaces.graphics +{ + import flash.events.EventDispatcher; + import flash.display.IBitmapDrawable; + import flash.display.DisplayObject; + import flash.display.Stage; + import flash.display.DisplayObjectContainer; + import flash.events.IEventDispatcher; + import flash.geom.Rectangle; + import flash.geom.Transform; + import flash.geom.Point; + import flash.display.LoaderInfo; + import flash.accessibility.AccessibilityProperties; + import flash.geom.Vector3D; + import flash.display.Shader; + import flash.geom.Matrix; + + /** + * [broadcast event] Dispatched when the display list is about to be updated and rendered. + * @eventType flash.events.Event.RENDER + */ + [Event(name="render", type="flash.events.Event")] + + /** + * Dispatched when a display object is about to be removed from the display list, + * either directly or through the removal of a sub tree in which the display object is contained. + * @eventType flash.events.Event.REMOVED_FROM_STAGE + */ + [Event(name="removedFromStage", type="flash.events.Event")] + + /** + * Dispatched when a display object is about to be removed from the display list. + * @eventType flash.events.Event.REMOVED + */ + [Event(name="removed", type="flash.events.Event")] + + /** + * [broadcast event] Dispatched when the playhead is exiting the current frame. + * @eventType flash.events.Event.EXIT_FRAME + */ + [Event(name="exitFrame", type="flash.events.Event")] + + /** + * [broadcast event] Dispatched after the constructors of frame display objects have run but before frame scripts have run. + * @eventType flash.events.Event.FRAME_CONSTRUCTED + */ + [Event(name="frameConstructed", type="flash.events.Event")] + + /** + * [broadcast event] Dispatched when the playhead is entering a new + * frame. + * @eventType flash.events.Event.ENTER_FRAME + */ + [Event(name="enterFrame", type="flash.events.Event")] + + /** + * Dispatched when a display object is added to the on stage display list, + * either directly or through the addition of a sub tree in which the display object is contained. + * @eventType flash.events.Event.ADDED_TO_STAGE + */ + [Event(name="addedToStage", type="flash.events.Event")] + + /** + * Dispatched when a display object is added to the display list. + * @eventType flash.events.Event.ADDED + */ + [Event(name="added", type="flash.events.Event")] + + /** + * The DisplayObject class is the base class for all objects that can be placed on + * the display list. The display list manages all objects displayed in the Flash runtimes. + * Use the DisplayObjectContainer class to arrange the display objects in the display list. + * DisplayObjectContainer objects can have child display objects, while other display objects, such as + * Shape and TextField objects, are "leaf" nodes that have only parents and siblings, no children. + * + *

The DisplayObject class supports basic functionality like the x and y position of + * an object, as well as more advanced properties of the object such as its transformation matrix. + *

DisplayObject is an abstract base class; therefore, you cannot call DisplayObject directly. Invoking + * new DisplayObject() throws an ArgumentError exception.

All display objects inherit from the DisplayObject class.

The DisplayObject class itself does not include any APIs for rendering content onscreen. + * For that reason, if you want create a custom subclass of the DisplayObject class, you will want + * to extend one of its subclasses that do have APIs for rendering content onscreen, + * such as the Shape, Sprite, Bitmap, SimpleButton, TextField, or MovieClip class.

The DisplayObject class contains several broadcast events. Normally, the target + * of any particular event is a specific DisplayObject instance. For example, + * the target of an added event is the specific DisplayObject instance + * that was added to the display list. Having a single target restricts the placement of + * event listeners to that target and in some cases the target's ancestors on the display list. + * With broadcast events, however, the target is not a specific DisplayObject instance, + * but rather all DisplayObject instances, including those that are not on the display list. + * This means that you can add a listener to any DisplayObject instance to listen for broadcast events. + * In addition to the broadcast events listed in the DisplayObject class's Events table, + * the DisplayObject class also inherits two broadcast events from the EventDispatcher + * class: activate and deactivate.

Some properties previously used in the ActionScript 1.0 and 2.0 MovieClip, TextField, and Button + * classes (such as _alpha, _height, _name, _width, + * _x, _y, and others) have equivalents in the ActionScript 3.0 + * DisplayObject class that are renamed so that they no longer begin with the underscore (_) character.

For more information, see the "Display Programming" chapter of the ActionScript 3.0 Developer's Guide.

+ * + * EXAMPLE: + * + * The following example uses the DisplayObjectExample class to + * draw an orange square in the corner of the Stage and then respond to events by displaying text + * information for each event. This task is accomplished by performing the following steps: + *
  1. Class properties are declared for the color and size of the square.
  2. The constructor calls the draw() method, which draws an orange square on + * the Stage at the default coordinates of x = 0, y = 0.
  3. The following event listener methods are attached to the square: + *
    • addedHandler() listens for added events, dispatched when the + * square is added to the display list.
    • enterFrameHandler() listens for enterFrame events, which have no + * real meaning in this example.
    • removedHandler() listens for removed events, dispatched when + * the square is removed from the display list, which happens when the square is clicked.
    • clickHandler() listens for click events, dispatched when the + * orange square is clicked.
    • renderHandler() listens for render events after the display + * list is updated.
+ * + * package { + * import flash.display.Sprite; + * + * public class DisplayObjectExample extends Sprite { + * function DisplayObjectExample() { + * var child:CustomDisplayObject = new CustomDisplayObject(); + * addChild(child); + * } + * } + * } + * + * import flash.display.DisplayObject; + * import flash.display.Sprite; + * import flash.display.Stage; + * import flash.display.StageAlign; + * import flash.display.StageScaleMode; + * import flash.events.*; + * + * class CustomDisplayObject extends Sprite { + * private var bgColor:uint = 0xFFCC00; + * private var size:uint = 80; + * + * function CustomDisplayObject() { + * draw(); + * addEventListener(Event.ADDED, addedHandler); + * addEventListener(Event.ENTER_FRAME, enterFrameHandler); + * addEventListener(Event.REMOVED, removedHandler); + * addEventListener(MouseEvent.CLICK, clickHandler); + * addEventListener(Event.RENDER, renderHandler); + * } + * + * private function draw():void { + * graphics.beginFill(bgColor); + * graphics.drawRect(0, 0, size, size); + * graphics.endFill(); + * } + * + * private function clickHandler(event:MouseEvent):void { + * trace("clickHandler: " + event); + * parent.removeChild(this); + * } + * + * private function addedHandler(event:Event):void { + * trace("addedHandler: " + event); + * stage.scaleMode = StageScaleMode.NO_SCALE; + * stage.align = StageAlign.TOP_LEFT; + * stage.addEventListener("resize", resizeHandler); + * } + * + * private function enterFrameHandler(event:Event):void { + * trace("enterFrameHandler: " + event); + * removeEventListener("enterFrame", enterFrameHandler); + * } + * + * private function removedHandler(event:Event):void { + * trace("removedHandler: " + event); + * stage.removeEventListener("resize", resizeHandler); + * } + * + * private function renderHandler(event:Event):void { + * trace("renderHandler: " + event); + * } + * + * private function resizeHandler(event:Event):void { + * trace("resizeHandler: " + event); + * } + * } + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + public interface IDisplayObject extends IEventDispatcher, IBitmapDrawable + { + /** + * The current accessibility options for this display object. If you modify the accessibilityProperties + * property or any of the fields within accessibilityProperties, you must call + * the Accessibility.updateProperties() method to make your changes take effect. + * + * Note: For an object created in the Flash authoring environment, the value of accessibilityProperties + * is prepopulated with any information you entered in the Accessibility panel for + * that object. + * @langversion 3.0 + * @playerversion Flash 9 + */ + function get accessibilityProperties () : flash.accessibility.AccessibilityProperties; + function set accessibilityProperties (value:AccessibilityProperties) : void; + + /** + * Indicates the alpha transparency value of the object specified. + * Valid values are 0 (fully transparent) to 1 (fully opaque). + * The default value is 1. Display objects with alpha + * set to 0 are active, even though they are invisible. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get alpha () : Number; + function set alpha (value:Number) : void; + + /** + * A value from the BlendMode class that specifies which blend mode to use. + * A bitmap can be drawn internally in two ways. If you have a blend mode enabled or an + * external clipping mask, the bitmap is drawn by adding a bitmap-filled square shape to the vector + * render. If you attempt to set this property to an invalid value, Flash runtimes set the value + * to BlendMode.NORMAL. + * + * The blendMode property affects each pixel of the display object. + * Each pixel is composed of three constituent + * colors (red, green, and blue), and each constituent color has a value between 0x00 and 0xFF. + * Flash Player or Adobe AIR compares each constituent color of one pixel in the movie clip with + * the corresponding color of the pixel in the background. For example, if blendMode + * is set to BlendMode.LIGHTEN, Flash Player or Adobe AIR compares the red value of the display object with + * the red value of the background, and uses the lighter of the two as the + * value for the red component of the displayed color.The following table describes the blendMode settings. + * The BlendMode class defines string values you can use. + * The illustrations in the table show blendMode values applied to a circular + * display object (2) superimposed on another display object (1).BlendMode ConstantIllustrationDescriptionBlendMode.NORMALThe display object appears in front of the background. Pixel values of the display object + * override those of the background. Where the display object is transparent, the background is + * visible.BlendMode.LAYERForces the creation of a transparency group for the display object. This means that the display + * object is pre-composed in a temporary buffer before it is processed further. This is done + * automatically if the display object is pre-cached using bitmap caching or if the display object is + * a display object container with at least one child object with a blendMode + * setting other than BlendMode.NORMAL. Not supported under GPU rendering. + * BlendMode.MULTIPLYMultiplies the values of the display object constituent colors by the colors of the background color, + * and then normalizes by dividing by 0xFF, + * resulting in darker colors. This setting is commonly used for shadows and depth effects. + * + * For example, if a constituent color (such as red) of one pixel in the display object and the + * corresponding color of the pixel in the background both have the value 0x88, the multiplied + * result is 0x4840. Dividing by 0xFF yields a value of 0x48 for that constituent color, + * which is a darker shade than the color of the display object or the color of the background.BlendMode.SCREENMultiplies the complement (inverse) of the display object color by the complement of the background + * color, resulting in a bleaching effect. This setting is commonly used for highlights or to remove black + * areas of the display object.BlendMode.LIGHTENSelects the lighter of the constituent colors of the display object and the color of the background (the + * colors with the larger values). This setting is commonly used for superimposing type. + * + * For example, if the display object has a pixel with an RGB value of 0xFFCC33, and the background + * pixel has an RGB value of 0xDDF800, the resulting RGB value for the displayed pixel is + * 0xFFF833 (because 0xFF > 0xDD, 0xCC < 0xF8, and 0x33 > 0x00 = 33). Not supported under GPU rendering.BlendMode.DARKENSelects the darker of the constituent colors of the display object and the colors of the + * background (the colors with the smaller values). This setting is commonly used for superimposing type. + * + * For example, if the display object has a pixel with an RGB value of 0xFFCC33, and the background + * pixel has an RGB value of 0xDDF800, the resulting RGB value for the displayed pixel is + * 0xDDCC00 (because 0xFF > 0xDD, 0xCC < 0xF8, and 0x33 > 0x00 = 33). Not supported under GPU rendering.BlendMode.DIFFERENCECompares the constituent colors of the display object with the colors of its background, and subtracts + * the darker of the values of the two constituent colors from the lighter value. This setting is commonly + * used for more vibrant colors. + * + * For example, if the display object has a pixel with an RGB value of 0xFFCC33, and the background + * pixel has an RGB value of 0xDDF800, the resulting RGB value for the displayed pixel is + * 0x222C33 (because 0xFF - 0xDD = 0x22, 0xF8 - 0xCC = 0x2C, and 0x33 - 0x00 = 0x33).BlendMode.ADDAdds the values of the constituent colors of the display object to the colors of its background, applying a + * ceiling of 0xFF. This setting is commonly used for animating a lightening dissolve between + * two objects. + * + * For example, if the display object has a pixel with an RGB value of 0xAAA633, and the background + * pixel has an RGB value of 0xDD2200, the resulting RGB value for the displayed pixel is + * 0xFFC833 (because 0xAA + 0xDD > 0xFF, 0xA6 + 0x22 = 0xC8, and 0x33 + 0x00 = 0x33).BlendMode.SUBTRACTSubtracts the values of the constituent colors in the display object from the values of the + * background color, applying a floor of 0. This setting is commonly used for animating a + * darkening dissolve between two objects. + * + * For example, if the display object has a pixel with an RGB value of 0xAA2233, and the background + * pixel has an RGB value of 0xDDA600, the resulting RGB value for the displayed pixel is + * 0x338400 (because 0xDD - 0xAA = 0x33, 0xA6 - 0x22 = 0x84, and 0x00 - 0x33 < 0x00).BlendMode.INVERTInverts the background.BlendMode.ALPHAApplies the alpha value of each pixel of the display object to the background. + * This requires the blendMode setting of the parent display object to be set to + * BlendMode.LAYER. + * For example, in the illustration, the parent display object, which is a white background, + * has blendMode = BlendMode.LAYER. Not supported under GPU rendering.BlendMode.ERASEErases the background based on the alpha value of the display object. This requires the + * blendMode of the parent display object to be set to + * BlendMode.LAYER. For example, in the + * illustration, the parent display object, which is a white background, has + * blendMode = BlendMode.LAYER. Not supported under GPU rendering.BlendMode.OVERLAYAdjusts the color of each pixel based on the darkness of the background. + * If the background is lighter than 50% gray, the display object and background colors are + * screened, which results in a lighter color. If the background is darker than 50% gray, + * the colors are multiplied, which results in a darker color. + * This setting is commonly used for shading effects. Not supported under GPU rendering.BlendMode.HARDLIGHTAdjusts the color of each pixel based on the darkness of the display object. + * If the display object is lighter than 50% gray, the display object and background colors are + * screened, which results in a lighter color. If the display object is darker than 50% gray, + * the colors are multiplied, which results in a darker color. + * This setting is commonly used for shading effects. Not supported under GPU rendering.BlendMode.SHADERN/AAdjusts the color using a custom shader routine. The shader that is used is specified + * as the Shader instance assigned to the blendShader property. Setting the + * blendShader property of a display object to a Shader instance + * automatically sets the display object's blendMode property to + * BlendMode.SHADER. If the blendMode property is set to + * BlendMode.SHADER without first setting the blendShader property, + * the blendMode property is set to BlendMode.NORMAL. Not supported under GPU rendering. + * @langversion 3.0 + * @playerversion Flash 9 + */ + function get blendMode () : String; + function set blendMode (value:String) : void; + + /** + * Sets a shader that is used for blending the foreground and background. When the + * blendMode property is set to BlendMode.SHADER, the specified + * Shader is used to create the blend mode output for the display object. + * + * Setting the blendShader property of a display object to a Shader instance + * automatically sets the display object's blendMode property to + * BlendMode.SHADER. If the blendShader property is set (which sets the + * blendMode property to BlendMode.SHADER), then the value of the + * blendMode property is changed, the blend mode can be reset to use the blend + * shader simply by setting the blendMode property to BlendMode.SHADER. + * The blendShader property does not need to be set again except to change the + * shader that's used for the blend mode.The Shader assigned to the blendShader property must specify at least two + * image4 inputs. The inputs do not need to be specified in code using the + * associated ShaderInput objects' input properties. The background display object + * is automatically + * used as the first input (the input with index 0). The foreground display object + * is used as the second input (the input with index 1). A shader used as a blend + * shader can specify more than two inputs. In that case, any additional input must be specified + * by setting its ShaderInput instance's input property.When you assign a Shader instance to this property the shader is copied internally. The + * blend operation uses that internal copy, not a reference to the original shader. Any changes + * made to the shader, such as changing a parameter value, input, or bytecode, are not applied + * to the copied shader that's used for the blend mode. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @throws ArgumentError When the shader output type is not compatible with this operation + * (the shader must specify a pixel4 + * output). + * @throws ArgumentError When the shader specifies fewer than two image inputs or the first + * two inputs are not image4 inputs. + * @throws ArgumentError When the shader specifies an image input that isn't provided. + * @throws ArgumentError When a ByteArray or Vector. instance is used as + * an input and the width + * and height properties aren't specified for the + * ShaderInput, or the specified values don't match the amount of + * data in the input object. See the ShaderInput.input + * property for more information. + */ + function set blendShader (value:Shader) : void; + + /** + * If set to true, Flash runtimes cache an internal bitmap representation of the + * display object. This caching can increase performance for display objects that contain complex + * vector content. + * + * All vector data for a display object that has a cached bitmap is drawn to the bitmap + * instead of the main display. If cacheAsBitmapMatrix is null or unsupported, + * the bitmap is then copied to the main display as unstretched, unrotated pixels snapped to + * the nearest pixel boundaries. Pixels are mapped 1 to 1 with + * the parent object. If the bounds of the bitmap change, the bitmap is recreated instead + * of being stretched.If cacheAsBitmapMatrix is non-null and supported, the object is drawn to the off-screen bitmap + * using that matrix and the stretched and/or rotated results of that rendering are used + * to draw the object to the main display.No internal bitmap is created unless the cacheAsBitmap property is set to + * true.After you set the cacheAsBitmap property to true, + * the rendering does not change, however the display object performs pixel snapping + * automatically. The animation speed can be significantly faster depending + * on the complexity of the vector content. + * The cacheAsBitmap property is automatically set to true + * whenever you apply a filter to a display object (when its filter array is not empty), + * and if a display object has a filter applied to it, cacheAsBitmap is reported as + * true for that display object, even if you set the property to false. + * If you clear all filters for a display object, the cacheAsBitmap setting changes to + * what it was last set to.A display object does not use a bitmap even if the cacheAsBitmap + * property is set to true and instead renders from vector data in the following cases:The bitmap is too large. + * In AIR 1.5 and Flash Player 10, the maximum size for a bitmap image is 8,191 pixels in width or height, + * and the total number of pixels cannot exceed 16,777,215 pixels. (So, if a bitmap image is 8,191 pixels + * wide, it can only be 2,048 pixels high.) In Flash Player 9 and earlier, the limitation is + * is 2880 pixels in height and 2,880 pixels in width.The bitmap fails to allocate (out of memory error). The cacheAsBitmap property is best used with movie clips that have + * mostly static content and that do not scale and rotate frequently. With such movie + * clips, cacheAsBitmap can lead to performance increases when the + * movie clip is translated (when its x and y position is changed). + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get cacheAsBitmap () : Boolean; + function set cacheAsBitmap (value:Boolean) : void; + + /** + * If non-null, this Matrix object defines how a display object is rendered when + * cacheAsBitmap is set to true. The application uses + * this matrix as a transformation matrix that is applied when rendering the bitmap version of + * the display object. + * + * AIR profile support: This feature is supported + * on mobile devices, but it is not supported on desktop operating systems. It also has + * limited support on AIR for TV devices. + * Specifically, on AIR for TV devices, supported transformations include scaling and translation, + * but not rotation and skewing. See + * + * AIR Profile Support for more information regarding API support across multiple profiles.With cacheAsBitmapMatrix set, the application retains a cached + * bitmap image across various 2D transformations, including translation, rotation, + * and scaling. If the application uses hardware acceleration, the object will + * be stored in video memory as a texture. This allows the GPU to apply + * the supported transformations to the object. The GPU + * can perform these transformations faster than the CPU.To use the hardware acceleration, set Rendering to GPU in + * the General tab of the iPhone Settings dialog box in Flash Professional CS5. + * Or set the renderMode property to gpu in the + * application descriptor file. Note that AIR for TV devices automatically + * use hardware acceleration if it is available.For example, the following code sends an untransformed bitmap representation + * of the display object to the GPU: + * + * matrix:Matrix = new Matrix(); // creates an identity matrix + * mySprite.cacheAsBitmapMatrix = matrix; + * mySprite.cacheAsBitmap = true; + * + * Usually, the identity matrix (new Matrix()) suffices. However, + * you can use another matrix, such as a scaled-down matrix, to upload + * a different bitmap to the GPU. For example, the following example applies + * a cacheAsBitmapMatrix matrix that is scaled by 0.5 on the x and y axes. + * The bitmap object that the GPU uses is smaller, however the GPU adjusts + * its size to match the transform.matrix property of the display object: + * + * matrix:Matrix = new Matrix(); // creates an identity matrix + * matrix.scale(0.5, 0.5); // scales the matrix + * mySprite.cacheAsBitmapMatrix = matrix; + * mySprite.cacheAsBitmap = true; + * + * Generally, you should choose to use a matrix that transforms the display object + * to the size that it will appear in the application. For example, if + * your application displays the bitmap version of the sprite scaled down by a half, + * use a matrix that scales down by a half. If you application will display + * the sprite larger than its current dimensions, use a matrix that + * scales up by that factor.Note: The cacheAsBitmapMatrix property + * is suitable for 2D transformations. If you need to apply transformations in 3D, + * you may do so by setting a 3D property of the object and manipulating its + * transform.matrix3D property. If the application is packaged + * using GPU mode, this allows the 3D transforms to be applied to + * the object by the GPU. The cacheAsBitmapMatrix is ignored + * for 3D objects. + * @langversion 3.0 + * @playerversion AIR 2.0 + */ + function get cacheAsBitmapMatrix () : flash.geom.Matrix; + function set cacheAsBitmapMatrix (value:Matrix) : void; + + /** + * An indexed array that contains each filter object currently associated with the display object. + * The flash.filters package contains several classes that define specific filters you can + * use. + * + * Filters can be applied in Flash Professional at design time, or at run time by using + * ActionScript code. To apply a filter by using ActionScript, you must make a temporary copy of the + * entire filters array, modify the temporary array, then assign the value + * of the temporary array back to the filters array. You cannot directly + * add a new filter object to the filters array.To add a filter by using ActionScript, perform the following steps (assume that the + * target display object is named myDisplayObject):Create a new filter object by using the constructor method of your chosen filter + * class.Assign the value of the myDisplayObject.filters array to a temporary array, such + * as one named myFilters.Add the new filter object to the myFilters temporary array.Assign the value of the temporary array to the myDisplayObject.filters array.If the filters array is undefined, you do not need to use a temporary array. + * Instead, you can directly assign an array literal that contains one or more filter objects that + * you create. The first example in the Examples section adds a drop shadow filter by using + * code that handles both defined and undefined filters arrays.To modify an existing filter object, + * you must use the technique of modifying a copy of the filters array:Assign the value of the filters array to a temporary array, such as one + * named myFilters.Modify the property by using the temporary array, myFilters. For example, + * to set the quality property of the first filter in the array, you could use the + * following code: myFilters[0].quality = 1;Assign the value of the temporary array to the filters array.At load time, if a display object has an associated filter, it is marked to cache itself as a + * transparent bitmap. From this point forward, as long as the display object has a valid filter list, + * the player caches the display object as a bitmap. This source bitmap is used as a source + * image for the filter effects. Each display object usually has two bitmaps: one with the + * original unfiltered source display object and another for the final image after filtering. + * The final image is used when rendering. As long as the display object does not + * change, the final image does not need updating.The flash.filters package includes classes for filters. For example, to create a DropShadow + * filter, you would write: + * + * + * import flash.filters.DropShadowFilter + * var myFilter:DropShadowFilter = new DropShadowFilter (distance, angle, color, alpha, blurX, blurY, quality, inner, knockout) + * + * + * You can use the is operator to determine the type of filter assigned to + * each index position in the filter array. For example, the following code shows + * how to determine the position of the first filter in the filters array that + * is a DropShadowFilter: + * + * + * + * import flash.text.TextField; + * import flash.filters.~~; + * var tf:TextField = new TextField(); + * var filter1:DropShadowFilter = new DropShadowFilter(); + * var filter2:GradientGlowFilter = new GradientGlowFilter(); + * tf.filters = [filter1, filter2]; + * + * tf.text = "DropShadow index: " + filterPosition(tf, DropShadowFilter).toString(); // 0 + * addChild(tf) + * + * function filterPosition(displayObject:DisplayObject, filterClass:Class):int { + * for (var i:uint = 0; i < displayObject.filters.length; i++) { + * if (displayObject.filters[i] is filterClass) { + * return i; + * } + * } + * return -1; + * } + * + * + * Note: Since you cannot directly add a new filter object to the + * DisplayObject.filters array, the following code has no + * effect on the target display object, named myDisplayObject: + * + * + * myDisplayObject.filters.push(myDropShadow); + * + * + * @langversion 3.0 + * @playerversion Flash 9 + * @throws ArgumentError When filters includes a ShaderFilter and the shader + * output type is not compatible with this operation + * (the shader must specify a pixel4 + * output). + * @throws ArgumentError When filters includes a ShaderFilter and the shader + * doesn't specify any image input or the first + * input is not an image4 input. + * @throws ArgumentError When filters includes a ShaderFilter and the shader + * specifies an image input that isn't provided. + * @throws ArgumentError When filters includes a ShaderFilter, a + * ByteArray or Vector. instance as + * a shader input, and the width + * and height properties aren't specified for the + * ShaderInput object, or the specified values don't match the amount of + * data in the input data. See the ShaderInput.input + * property for more information. + */ + function get filters () : Array; + function set filters (value:Array) : void; + + /** + * Indicates the height of the display object, in pixels. The height is calculated based on the bounds of the content of the display object. + * When you set the height property, the scaleY property is adjusted accordingly, as shown in the + * following code: + * + * + * + * var rect:Shape = new Shape(); + * rect.graphics.beginFill(0xFF0000); + * rect.graphics.drawRect(0, 0, 100, 100); + * trace(rect.scaleY) // 1; + * rect.height = 200; + * trace(rect.scaleY) // 2; + * + * Except for TextField and Video objects, a display object with no content (such as an empty sprite) has a height + * of 0, even if you try to set height to a different value. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get height () : Number; + function set height (value:Number) : void; + + /** + * Returns a LoaderInfo object containing information about loading the file + * to which this display object belongs. The loaderInfo property is defined only + * for the root display object of a SWF file or for a loaded Bitmap (not for a Bitmap that is drawn + * with ActionScript). To find the loaderInfo object associated with the SWF file that contains + * a display object named myDisplayObject, use myDisplayObject.root.loaderInfo. + * + * A large SWF file can monitor its download by calling + * this.root.loaderInfo.addEventListener(Event.COMPLETE, func). + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get loaderInfo () : flash.display.LoaderInfo; + + /** + * The calling display object is masked by the specified mask object. + * To ensure that masking works when the Stage is scaled, the mask display object + * must be in an active part of the display list. The mask object itself is not drawn. + * Set mask to null to remove the mask. + * + * To be able to scale a mask object, it must be on the display list. To be able to drag a mask Sprite object + * (by calling its startDrag() method), it must be on the display list. To call the + * startDrag() method for a mask sprite based on a mouseDown event + * being dispatched by the sprite, set the sprite's buttonMode property to true.When display objects are cached by setting the cacheAsBitmap property to + * true an the cacheAsBitmapMatrix property to a Matrix object, + * both the mask and the display object being masked must be part of the same cached + * bitmap. Thus, if the display object is cached, then the mask must be a child of the display object. + * If an ancestor of the display object on the display list is cached, then the mask must be a child of + * that ancestor or one of its descendents. If more than one ancestor of the masked object is cached, + * then the mask must be a descendent of the cached container closest to the masked object in the display list.Note: A single mask object cannot be used to mask more than one calling display object. + * When the mask is assigned to a second display object, it is removed as the mask of the first + * object, and that object's mask property becomes null. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get mask () : flash.display.DisplayObject; + function set mask (value:DisplayObject) : void; + + function get metaData () : Object; + function set metaData (data:Object) : void; + + /** + * Indicates the x coordinate of the mouse or user input device position, in pixels. + * + * Note: For a DisplayObject that has been rotated, the returned x coordinate will reflect the + * non-rotated object. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get mouseX () : Number; + + /** + * Indicates the y coordinate of the mouse or user input device position, in pixels. + * + * Note: For a DisplayObject that has been rotated, the returned y coordinate will reflect the + * non-rotated object. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get mouseY () : Number; + + /** + * Indicates the instance name of the DisplayObject. The object can be identified in + * the child list of its parent display object container by calling the + * getChildByName() method of the display object container. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + * @throws IllegalOperationError If you are attempting to set this property on an object that was + * placed on the timeline in the Flash authoring tool. + */ + function get name () : String; + function set name (value:String) : void; + + /** + * Specifies whether the display object is opaque with a certain background color. + * A transparent bitmap contains alpha + * channel data and is drawn transparently. An opaque bitmap has no alpha channel (and renders faster + * than a transparent bitmap). If the bitmap is opaque, you specify its own background color to use. + * + * If set to a number value, the surface is opaque (not transparent) with the RGB background + * color that the number specifies. If set to null (the default value), the display + * object has a transparent background.The opaqueBackground property is intended mainly for use with the + * cacheAsBitmap property, for rendering optimization. For display objects in which the + * cacheAsBitmap property is set to true, setting opaqueBackground can + * improve rendering performance.The opaque background region is not matched when calling the hitTestPoint() + * method with the shapeFlag parameter set to true.The opaque background region does not respond to mouse events. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get opaqueBackground () : Object; + function set opaqueBackground (value:Object) : void; + + /** + * Indicates the DisplayObjectContainer object that contains this display object. Use the parent + * property to specify a relative path to display objects that are above the + * current display object in the display list hierarchy. + * + * You can use parent to move up multiple levels in the display list as in the following: + * + * + * this.parent.parent.alpha = 20; + * + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + * @throws SecurityError The parent display object belongs to a security sandbox + * to which you do not have access. You can avoid this situation by having + * the parent movie call the Security.allowDomain() method. + */ + function get parent () : flash.display.DisplayObjectContainer; + + /** + * For a display object in a loaded SWF file, the root property is the + * top-most display object in the portion of the display list's tree structure represented by that SWF file. + * For a Bitmap object representing a loaded image file, the root property is the Bitmap object + * itself. For the instance of the main class of the first SWF file loaded, the root property is the + * display object itself. The root property of the Stage object is the Stage object itself. The root + * property is set to null for any display object that has not been added to the display list, unless + * it has been added to a display object container that is off the display list but that is a child of the + * top-most display object in a loaded SWF file. + * + * For example, if you create a new Sprite object by calling the Sprite() constructor method, + * its root property is null until you add it to the display list (or to a display + * object container that is off the display list but that is a child of the top-most display object in a SWF file).For a loaded SWF file, even though the Loader object used to load the file may not be on the display list, + * the top-most display object in the SWF file has its root property set to itself. The Loader object + * does not have its root property set until it is added as a child of a display object for which the + * root property is set. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get root () : flash.display.DisplayObject; + + /** + * Indicates the rotation of the DisplayObject instance, in degrees, from its original orientation. Values from 0 to 180 represent + * clockwise rotation; values from 0 to -180 represent counterclockwise rotation. Values outside this range are added to or + * subtracted from 360 to obtain a value within the range. For example, the statement my_video.rotation = 450 is the + * same as my_video.rotation = 90. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get rotation () : Number; + function set rotation (value:Number) : void; + + /** + * Indicates the x-axis rotation of the DisplayObject instance, in degrees, from its original orientation relative to the 3D parent container. Values from 0 to 180 represent + * clockwise rotation; values from 0 to -180 represent counterclockwise rotation. Values outside this range are added to or + * subtracted from 360 to obtain a value within the range. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @playerversion Lite 4 + */ + function get rotationX () : Number; + function set rotationX (value:Number) : void; + + /** + * Indicates the y-axis rotation of the DisplayObject instance, in degrees, from its original orientation relative to the 3D parent container. Values from 0 to 180 represent + * clockwise rotation; values from 0 to -180 represent counterclockwise rotation. Values outside this range are added to or + * subtracted from 360 to obtain a value within the range. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @playerversion Lite 4 + */ + function get rotationY () : Number; + function set rotationY (value:Number) : void; + + /** + * Indicates the z-axis rotation of the DisplayObject instance, in degrees, from its original orientation relative to the 3D parent container. Values from 0 to 180 represent + * clockwise rotation; values from 0 to -180 represent counterclockwise rotation. Values outside this range are added to or + * subtracted from 360 to obtain a value within the range. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @playerversion Lite 4 + */ + function get rotationZ () : Number; + function set rotationZ (value:Number) : void; + + /** + * The current scaling grid that is in effect. If set to null, + * the entire display object is scaled normally when any scale transformation is + * applied. + * + * When you define the scale9Grid property, the display object is divided into a + * grid with nine regions based on the scale9Grid rectangle, which defines the + * center region of the grid. The eight other regions of the grid are the following areas: The upper-left corner outside of the rectangleThe area above the rectangle The upper-right corner outside of the rectangleThe area to the left of the rectangleThe area to the right of the rectangleThe lower-left corner outside of the rectangleThe area below the rectangleThe lower-right corner outside of the rectangleYou can think of the eight regions outside of the center (defined by the rectangle) + * as being like a picture frame that has special rules applied to it when scaled.When the scale9Grid property is set and a display object is scaled, all text and + * gradients are scaled normally; however, for other types of objects the following rules apply:Content in the center region is scaled normally. Content in the corners is not scaled. Content in the top and bottom regions is scaled horizontally only. Content in the + * left and right regions is scaled vertically only.All fills (including bitmaps, video, and gradients) are stretched to fit their shapes.If a display object is rotated, all subsequent scaling is normal (and the + * scale9Grid property is ignored).For example, consider the following display object and a rectangle that is applied as the display + * object's scale9Grid:The display object.The red rectangle shows the scale9Grid.When the display object is scaled or stretched, the objects within the rectangle scale + * normally, but the objects outside of the rectangle scale according to the + * scale9Grid rules:Scaled to 75%:Scaled to 50%:Scaled to 25%:Stretched horizontally 150%: A common use for setting scale9Grid is to set up a display object to be used + * as a component, in which edge regions retain the same width when the component is scaled. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + * @maelexample The following creates a movie clip that contains a 20-pixel line (which forms a border) + * and a gradient fill. The movie clip scales based on the mouse position, and because of the + * scale9Grid set for the movie clip, the thickness of the 20-pixel line does not + * vary when the clip scales (although the gradient in the movie clip does scale): + * + * + * import flash.geom.Rectangle; + * import flash.geom.Matrix; + * + * this.createEmptyMovieClip("my_mc", this.getNextHighestDepth()); + * + * var grid:Rectangle = new Rectangle(20, 20, 260, 260); + * my_mc.scale9Grid = grid ; + * + * my_mc._x = 50; + * my_mc._y = 50; + * + * function onMouseMove() + * { + * my_mc._width = _xmouse; + * my_mc._height = _ymouse; + * } + * + * my_mc.lineStyle(20, 0xff3333, 100); + * var gradient_matrix:Matrix = new Matrix(); + * gradient_matrix.createGradientBox(15, 15, Math.PI, 10, 10); + * my_mc.beginGradientFill("radial", [0xffff00, 0x0000ff], + * [100, 100], [0, 0xFF], gradient_matrix, + * "reflect", "RGB", 0.9); + * my_mc.moveTo(0, 0); + * my_mc.lineTo(0, 300); + * my_mc.lineTo(300, 300); + * my_mc.lineTo(300, 0); + * my_mc.lineTo(0, 0); + * my_mc.endFill(); + * + * @throws ArgumentError If you pass an invalid argument to the method. + */ + function get scale9Grid () : flash.geom.Rectangle; + function set scale9Grid (innerRectangle:Rectangle) : void; + + /** + * Indicates the horizontal scale (percentage) of the object as applied from the registration point. The default + * registration point is (0,0). 1.0 equals 100% scale. + * + * Scaling the local coordinate system changes the x and y property values, which are defined in + * whole pixels. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get scaleX () : Number; + function set scaleX (value:Number) : void; + + /** + * Indicates the vertical scale (percentage) of an object as applied from the registration point of the object. The + * default registration point is (0,0). 1.0 is 100% scale. + * + * Scaling the local coordinate system changes the x and y property values, which are defined in + * whole pixels. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get scaleY () : Number; + function set scaleY (value:Number) : void; + + /** + * Indicates the depth scale (percentage) of an object as applied from the registration point of the object. The + * default registration point is (0,0). 1.0 is 100% scale. + * + * Scaling the local coordinate system changes the x, y and z property values, which are defined in + * whole pixels. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + */ + function get scaleZ () : Number; + function set scaleZ (value:Number) : void; + + /** + * The scroll rectangle bounds of the display object. + * The display object is cropped to the size + * defined by the rectangle, and it scrolls within the rectangle when you change the + * x and y properties of the scrollRect object. + * + * The properties of the scrollRect Rectangle object use the display object's coordinate space + * and are scaled just like the overall display object. The corner bounds of the cropped window on the scrolling + * display object are the origin of the display object (0,0) and the point defined by the + * width and height of the rectangle. They are not centered around the origin, but + * use the origin to define the upper-left corner of the area. A scrolled display object always + * scrolls in whole pixel increments. You can scroll an object left and right by setting the x property of the + * scrollRect Rectangle object. You can scroll an object up and down by setting + * the y property of the scrollRect Rectangle object. If the display object + * is rotated 90° and you scroll it left and right, the display object actually scrolls up and down.Note that changes to the scrollRect property are only processed when the object is rendered. + * Thus methods like localToGlobal may not produce the expected result if called immediately + * after modifying scrollRect.Note: Starting with Flash Player 11.4/AIR 3.4, negative values for the width or the height of the rectangle + * are changed to 0. + * @langversion 3.0 + * @playerversion Flash 9 + */ + function get scrollRect () : flash.geom.Rectangle; + function set scrollRect (value:Rectangle) : void; + + /** + * The Stage of the display object. A Flash runtime application has only one Stage object. + * For example, you can create and load multiple display objects into the display list, and the + * stage property of each display object refers to the same Stage object (even if the + * display object belongs to a loaded SWF file). + * + * If a display object is not added to the display list, its stage property is set to + * null. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get stage () : flash.display.Stage; + + /** + * An object with properties pertaining to a display object's matrix, color transform, and pixel bounds. + * The specific properties — matrix, colorTransform, and three read-only properties + * (concatenatedMatrix, concatenatedColorTransform, + * and pixelBounds) — are described in the entry for the Transform class. + * + * Each of the transform object's properties is itself an object. This concept is important because the only + * way to set new values for the matrix or colorTransform objects is to create a new object and copy that + * object into the transform.matrix or transform.colorTransform property.For example, to increase the tx value of a display object's matrix, you must make a + * copy of the entire matrix object, then copy the new object into the matrix property of the transform + * object: + * var myMatrix:Matrix = myDisplayObject.transform.matrix; + * myMatrix.tx += 10; + * myDisplayObject.transform.matrix = myMatrix; + * You cannot directly set the tx property. The following code has + * no effect on myDisplayObject: + * myDisplayObject.transform.matrix.tx += 10; + * You can also copy an entire transform object and assign it to another + * display object's transform property. For example, the following code + * copies the entire transform object from myOldDisplayObj to + * myNewDisplayObj:myNewDisplayObj.transform = myOldDisplayObj.transform;The resulting display object, myNewDisplayObj, now has the same values for its + * matrix, color transform, and pixel bounds as the old display object, myOldDisplayObj.Note that AIR for TV devices use hardware acceleration, if it is available, for color transforms. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get transform () : flash.geom.Transform; + function set transform (value:Transform) : void; + + /** + * Whether or not the display object is visible. Display objects that are not visible + * are disabled. For example, if visible=false for an InteractiveObject instance, + * it cannot be clicked. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get visible () : Boolean; + function set visible (value:Boolean) : void; + + /** + * Indicates the width of the display object, in pixels. The width is calculated based on the bounds of the content of the display object. + * When you set the width property, the scaleX property is adjusted accordingly, as shown in the + * following code: + * + * + * + * var rect:Shape = new Shape(); + * rect.graphics.beginFill(0xFF0000); + * rect.graphics.drawRect(0, 0, 100, 100); + * trace(rect.scaleX) // 1; + * rect.width = 200; + * trace(rect.scaleX) // 2; + * + * Except for TextField and Video objects, a display object with no content (such as an empty sprite) has a width + * of 0, even if you try to set width to a different value. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get width () : Number; + function set width (value:Number) : void; + + /** + * Indicates the x coordinate of the DisplayObject instance relative to the local coordinates of + * the parent DisplayObjectContainer. If the object is inside a DisplayObjectContainer that has + * transformations, it is in the local coordinate system of the enclosing DisplayObjectContainer. + * Thus, for a DisplayObjectContainer rotated 90° counterclockwise, the DisplayObjectContainer's + * children inherit a coordinate system that is rotated 90° counterclockwise. + * The object's coordinates refer to the registration point position. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get x () : Number; + function set x (value:Number) : void; + + /** + * Indicates the y coordinate of the DisplayObject instance relative to the local coordinates of + * the parent DisplayObjectContainer. If the object is inside a DisplayObjectContainer that has + * transformations, it is in the local coordinate system of the enclosing DisplayObjectContainer. + * Thus, for a DisplayObjectContainer rotated 90° counterclockwise, the DisplayObjectContainer's + * children inherit a coordinate system that is rotated 90° counterclockwise. + * The object's coordinates refer to the registration point position. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function get y () : Number; + function set y (value:Number) : void; + + /** + * Indicates the z coordinate position along the z-axis of the DisplayObject + * instance relative to the 3D parent container. The z property is used for + * 3D coordinates, not screen or pixel coordinates. + * When you set a z property for a display object to something other than the default + * value of 0, a corresponding Matrix3D object is automatically created. for adjusting a + * display object's position and orientation + * in three dimensions. When working with the z-axis, + * the existing behavior of x and y properties changes from screen or pixel coordinates to + * positions relative to the 3D parent container.For example, a child of the _root at position x = 100, y = 100, z = 200 + * is not drawn at pixel location (100,100). The child is drawn wherever the 3D projection + * calculation puts it. The calculation is: (x~~cameraFocalLength/cameraRelativeZPosition, y~~cameraFocalLength/cameraRelativeZPosition) + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + */ + function get z () : Number; + function set z (value:Number) : void; + + /** + * Returns a rectangle that defines the area of the display object relative to the coordinate system + * of the targetCoordinateSpace object. + * Consider the following code, which shows how the rectangle returned can vary depending on the + * targetCoordinateSpace parameter that you pass to the method: + * + * + * + * var container:Sprite = new Sprite(); + * container.x = 100; + * container.y = 100; + * this.addChild(container); + * var contents:Shape = new Shape(); + * contents.graphics.drawCircle(0,0,100); + * container.addChild(contents); + * trace(contents.getBounds(container)); + * // (x=-100, y=-100, w=200, h=200) + * trace(contents.getBounds(this)); + * // (x=0, y=0, w=200, h=200) + * + * + * Note: Use the localToGlobal() and + * globalToLocal() methods to convert the display object's local coordinates + * to display coordinates, or display coordinates to local coordinates, respectively.The getBounds() method is similar to the getRect() method; + * however, the Rectangle returned by the getBounds() method includes any strokes + * on shapes, whereas the Rectangle returned by the getRect() method does not. + * For an example, see the description of the getRect() method. + * @param targetCoordinateSpace The display object that defines the coordinate system to use. + * @return The rectangle that defines the area of the display object relative to + * the targetCoordinateSpace object's coordinate system. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function getBounds (targetCoordinateSpace:DisplayObject) : flash.geom.Rectangle; + + /** + * Returns a rectangle that defines the boundary of the display object, + * based on the coordinate system defined by the targetCoordinateSpace + * parameter, excluding any strokes on shapes. The values that the getRect() method + * returns are the same or smaller than those returned by the getBounds() method. + * + * Note: Use localToGlobal() and globalToLocal() methods + * to convert the display object's local coordinates to Stage coordinates, or Stage coordinates to + * local coordinates, respectively. + * @param targetCoordinateSpace The display object that defines the coordinate system to use. + * @return The rectangle that defines the area of the display object relative to + * the targetCoordinateSpace object's coordinate system. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function getRect (targetCoordinateSpace:DisplayObject) : flash.geom.Rectangle; + + /** + * Converts the point object from the Stage (global) coordinates + * to the display object's (local) coordinates. + * + * To use this method, first create an instance of the Point class. The + * x and y values that you assign represent global coordinates because they + * relate to the origin (0,0) of the main display area. Then pass the Point instance + * as the parameter to the globalToLocal() method. The method returns a new Point object with + * x and y values that relate to the origin of the display object + * instead of the origin of the Stage. + * @param point An object created with the Point class. The Point object + * specifies the x and y coordinates as properties. + * @return A Point object with coordinates relative to the display object. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function globalToLocal (point:Point) : flash.geom.Point; + + /** + * Converts a two-dimensional point from the Stage (global) coordinates to a + * three-dimensional display object's (local) coordinates. + * + * To use this method, first create an instance of the Point class. + * The x and y values that you assign to the Point object represent global + * coordinates because they are relative to the origin (0,0) of the main display area. + * Then pass the Point object to the globalToLocal3D() + * method as the point parameter. The method returns three-dimensional + * coordinates as a Vector3D object containing x, y, and + * z values that are relative to the origin + * of the three-dimensional display object. + * @param point A two dimensional Point object representing global x and y coordinates. + * @return A Vector3D object with coordinates relative to the three-dimensional + * display object. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @playerversion Lite 4 + */ + function globalToLocal3D (point:Point) : flash.geom.Vector3D; + + /** + * Evaluates the bounding box of the display object to see if it overlaps or intersects with the + * bounding box of the obj display object. + * @param obj The display object to test against. + * @return true if the bounding boxes of the display objects intersect; false if not. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function hitTestObject (obj:DisplayObject) : Boolean; + + /** + * Evaluates the display object to see if it overlaps or intersects with the + * point specified by the x and y parameters. + * The x and y parameters specify a point in the + * coordinate space of the Stage, not the display object container that contains the + * display object (unless that display object container is the Stage). + * @param x The x coordinate to test against this object. + * @param y The y coordinate to test against this object. + * @param shapeFlag Whether to check against the actual pixels of the object (true) + * or the bounding box (false). + * @return true if the display object overlaps or intersects with the specified point; + * false otherwise. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function hitTestPoint (x:Number, y:Number, shapeFlag:Boolean=false) : Boolean; + + /** + * Converts a three-dimensional point of the three-dimensional display + * object's (local) coordinates to a two-dimensional point in the Stage (global) coordinates. + * + * For example, you can only use two-dimensional coordinates (x,y) to + * draw with the display.Graphics methods. To draw a three-dimensional + * object, you need to map the three-dimensional coordinates of a + * display object to two-dimensional coordinates. First, create an instance of + * the Vector3D class that holds the x-, y-, and z- coordinates of the three-dimensional + * display object. Then pass the Vector3D object to the local3DToGlobal() + * method as the point3d parameter. The method returns a two-dimensional Point + * object that can be used + * with the Graphics API to draw the three-dimensional object. + * @param point3d A Vector3D object containing either a three-dimensional point or + * the coordinates of the three-dimensional display object. + * @return A two-dimensional point representing a three-dimensional point + * in two-dimensional space. + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @playerversion Lite 4 + */ + function local3DToGlobal (point3d:Vector3D) : flash.geom.Point; + + /** + * Converts the point object from the display object's (local) coordinates to the + * Stage (global) coordinates. + * + * This method allows you to convert any given x and y coordinates from + * values that are relative to the origin (0,0) of a specific display object (local coordinates) + * to values that are relative to the origin of the Stage (global coordinates).To use this method, first create an instance of the Point class. The + * x and y values that you assign represent local coordinates because they + * relate to the origin of the display object.You then pass the Point instance that you created as the parameter to + * the localToGlobal() method. The method returns a new Point object with + * x and y values that relate to the origin of the Stage + * instead of the origin of the display object. + * @param point The name or identifier of a point created with the Point class, specifying the + * x and y coordinates as properties. + * @return A Point object with coordinates relative to the Stage. + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion Lite 4 + */ + function localToGlobal (point:Point) : flash.geom.Point; + } + +} \ No newline at end of file diff --git a/src/syncomps/interfaces/graphics/IIcon.as b/src/syncomps/interfaces/graphics/IIcon.as new file mode 100644 index 0000000..b464950 --- /dev/null +++ b/src/syncomps/interfaces/graphics/IIcon.as @@ -0,0 +1,16 @@ +package syncomps.interfaces.graphics +{ + import flash.display.BitmapData; + import flash.display.DisplayObject; + + /** + * ... + * @author Gimmick + */ + public interface IIcon + { + function get icon():DisplayObject + function set icon(icon:DisplayObject):void + } + +} \ No newline at end of file diff --git a/src/syncomps/interfaces/graphics/ILabel.as b/src/syncomps/interfaces/graphics/ILabel.as new file mode 100644 index 0000000..a9cce6f --- /dev/null +++ b/src/syncomps/interfaces/graphics/ILabel.as @@ -0,0 +1,14 @@ +package syncomps.interfaces.graphics +{ + + /** + * ... + * @author Gimmick + */ + public interface ILabel + { + function get label():String + function set label(label:String):void + } + +} \ No newline at end of file diff --git a/src/syncomps/styles/ComboBoxStyle.as b/src/syncomps/styles/ComboBoxStyle.as index 7124c03..b5f7f41 100644 --- a/src/syncomps/styles/ComboBoxStyle.as +++ b/src/syncomps/styles/ComboBoxStyle.as @@ -4,16 +4,11 @@ package syncomps.styles * ... * @author Gimmick */ - public final class ComboBoxStyle extends Style + public class ComboBoxStyle extends DefaultInnerTextStyle { public static const MENU:String = "menuSkinColor" - public function ComboBoxStyle() - { - super([DefaultStyle, SkinnableTextStyle], [MENU]) - init() - } - private function init():void { - setStyle(MENU, 0xFFDEDEDE) + public function ComboBoxStyle() { + appendStyle(MENU, 0xFFDEDEDE) } } diff --git a/src/syncomps/styles/DefaultInnerTextStyle.as b/src/syncomps/styles/DefaultInnerTextStyle.as index ce217a6..757f10d 100644 --- a/src/syncomps/styles/DefaultInnerTextStyle.as +++ b/src/syncomps/styles/DefaultInnerTextStyle.as @@ -4,19 +4,14 @@ package syncomps.styles * ... * @author Gimmick */ - public final class DefaultInnerTextStyle extends Style + public class DefaultInnerTextStyle extends Style { public static const BORDER:String = "borderColor" public function DefaultInnerTextStyle() { - super([DefaultStyle, SkinnableTextStyle], [BORDER]) - init() + super([DefaultStyle, SkinnableTextStyle]) + appendStyle(BORDER, 0xFF000000) } - - private function init():void { - setStyle(BORDER, 0xFF000000) - } - } } \ No newline at end of file diff --git a/src/syncomps/styles/DefaultLabelStyle.as b/src/syncomps/styles/DefaultLabelStyle.as index 6c9d9e4..22f3378 100644 --- a/src/syncomps/styles/DefaultLabelStyle.as +++ b/src/syncomps/styles/DefaultLabelStyle.as @@ -4,20 +4,15 @@ package syncomps.styles * ... * @author Gimmick */ - public final class DefaultLabelStyle extends Style + public class DefaultLabelStyle extends DefaultInnerTextStyle { public static const LABEL_LEFT:int = 1; public static const LABEL_RIGHT:int = 2; public static const LABEL_ABOVE:int = 4; public static const LABEL_BELOW:int = 8; public static const LABEL_POSITION:String = "labelPosition" - public function DefaultLabelStyle() - { - super([DefaultStyle, SkinnableTextStyle], [LABEL_POSITION]) - init() - } - private function init():void { - setStyle(LABEL_POSITION, LABEL_RIGHT) + public function DefaultLabelStyle() { + appendStyle(LABEL_POSITION, LABEL_RIGHT) } } diff --git a/src/syncomps/styles/DefaultListStyle.as b/src/syncomps/styles/DefaultListStyle.as index cfae0e8..320b390 100644 --- a/src/syncomps/styles/DefaultListStyle.as +++ b/src/syncomps/styles/DefaultListStyle.as @@ -5,7 +5,7 @@ package syncomps.styles * ... * @author Gimmick */ - public final class DefaultListStyle extends Style + public class DefaultListStyle extends DefaultStyle { public static const CELL_RENDERER:String = "cellRenderer" public static const LIST_DIRECTION:String = "listDirection"; @@ -13,13 +13,8 @@ package syncomps.styles public static const VERTICAL:String = "vertical" public function DefaultListStyle() { - super([DefaultStyle], [CELL_RENDERER, LIST_DIRECTION]) - init() - } - private function init():void - { - setStyle(CELL_RENDERER, ListCell) - setStyle(LIST_DIRECTION, VERTICAL) + appendStyle(CELL_RENDERER, ListCell) + appendStyle(LIST_DIRECTION, VERTICAL) } } diff --git a/src/syncomps/styles/DefaultStyle.as b/src/syncomps/styles/DefaultStyle.as index d93e292..6f1527b 100644 --- a/src/syncomps/styles/DefaultStyle.as +++ b/src/syncomps/styles/DefaultStyle.as @@ -4,7 +4,7 @@ package syncomps.styles * ... * @author Gimmick */ - public final class DefaultStyle extends Style + public class DefaultStyle extends Style { public static const BACKGROUND:String = "backgroundSkinColor" public static const DISABLED:String = "disabledSkinColor" @@ -14,17 +14,13 @@ package syncomps.styles public static const DOWN:String = "downColor" public function DefaultStyle() { - super(null, [BACKGROUND, DISABLED, SELECTED, HOVER, DOWN, ICON_SIZE]) - init() - } - private function init():void - { - setStyle(ICON_SIZE, 16) - setStyle(DOWN, 0xFF4ABCE8) - setStyle(HOVER, 0xFFF1F1F1) - setStyle(DISABLED, 0xFFBBBBBB) - setStyle(SELECTED, 0xFFC0C0C0) - setStyle(BACKGROUND, 0xFFDEDEDE) + super() + appendStyle(BACKGROUND, 0xFFDEDEDE) + appendStyle(SELECTED, 0xFFC0C0C0) + appendStyle(DISABLED, 0xFFBBBBBB) + appendStyle(HOVER, 0xFFF1F1F1) + appendStyle(DOWN, 0xFF4ABCE8) + appendStyle(ICON_SIZE, 16) } } diff --git a/src/syncomps/styles/LabeledButtonStyle.as b/src/syncomps/styles/LabeledButtonStyle.as index c8ae351..06727f0 100644 --- a/src/syncomps/styles/LabeledButtonStyle.as +++ b/src/syncomps/styles/LabeledButtonStyle.as @@ -4,19 +4,12 @@ package syncomps.styles * ... * @author Gimmick */ - public final class LabeledButtonStyle extends Style + public class LabeledButtonStyle extends DefaultInnerTextStyle { public static const EMPHASIZED_LINE_COLOR:String = "emphasizedLineColor" - public function LabeledButtonStyle() - { - super([DefaultStyle, SkinnableTextStyle], [EMPHASIZED_LINE_COLOR]) - init() + public function LabeledButtonStyle() { + appendStyle(EMPHASIZED_LINE_COLOR, 0xFF000000) } - - private function init():void { - setStyle(EMPHASIZED_LINE_COLOR, 0xFF000000) - } - } } \ No newline at end of file diff --git a/src/syncomps/styles/ScrollBarStyle.as b/src/syncomps/styles/ScrollBarStyle.as index f0ec009..4740183 100644 --- a/src/syncomps/styles/ScrollBarStyle.as +++ b/src/syncomps/styles/ScrollBarStyle.as @@ -4,7 +4,7 @@ package syncomps.styles * ... * @author Gimmick */ - public final class ScrollBarStyle extends Style + public class ScrollBarStyle extends Style { public static const BACKGROUND_SECONDARY:String = "secondaryBackgroundColor" public static const SCROLL_DIRECTION:String = "scrollDirection" @@ -13,13 +13,9 @@ package syncomps.styles public static const DIRECTION_HORIZONTAL:int = 16; public function ScrollBarStyle() { - super([DefaultStyle], [BACKGROUND_SECONDARY, SCROLL_DIRECTION]) - init() - } - private function init():void - { - setStyle(BACKGROUND_SECONDARY, 0xFF444444) - setStyle(SCROLL_DIRECTION, DIRECTION_VERTICAL) + super([DefaultStyle]) + appendStyle(SCROLL_DIRECTION, DIRECTION_VERTICAL) + appendStyle(BACKGROUND_SECONDARY, 0xFF444444) } } diff --git a/src/syncomps/styles/ScrollPaneStyle.as b/src/syncomps/styles/ScrollPaneStyle.as index 33aad76..f3ef717 100644 --- a/src/syncomps/styles/ScrollPaneStyle.as +++ b/src/syncomps/styles/ScrollPaneStyle.as @@ -4,7 +4,7 @@ package syncomps.styles * ... * @author Gimmick */ - public final class ScrollPaneStyle extends Style + public class ScrollPaneStyle extends Style { public static const POLICY_HORIZONTAL:int = 1; public static const POLICY_VERTICAL:int = 2; @@ -18,16 +18,11 @@ package syncomps.styles public static const SCROLL_POLICY:String = "scrollPolicy" public function ScrollPaneStyle() { - super([DefaultStyle, ScrollBarStyle], [MASK_METHOD, SCROLL_SIZE, SCROLL_POLICY]) - init() + super([DefaultStyle, ScrollBarStyle]) + appendStyle(SCROLL_POLICY, POLICY_NONE) + appendStyle(MASK_METHOD, MASK) + appendStyle(SCROLL_SIZE, 1) } - private function init():void - { - setStyle(SCROLL_SIZE, 1) - setStyle(MASK_METHOD, MASK) - setStyle(SCROLL_POLICY, POLICY_NONE) - } - } } \ No newline at end of file diff --git a/src/syncomps/styles/SkinnableTextStyle.as b/src/syncomps/styles/SkinnableTextStyle.as index 1fb6ca5..882bac0 100644 --- a/src/syncomps/styles/SkinnableTextStyle.as +++ b/src/syncomps/styles/SkinnableTextStyle.as @@ -5,7 +5,7 @@ package syncomps.styles * ... * @author Gimmick */ - public final class SkinnableTextStyle extends Style + public class SkinnableTextStyle extends Style { public static const ENABLED:String = "enabledTextColor" public static const DISABLED:String = "disabledTextColor" @@ -14,16 +14,11 @@ package syncomps.styles public function SkinnableTextStyle() { - super(null, [EMBED_FONTS, TEXT_FORMAT, ENABLED, DISABLED]) - init() - } - - private function init():void - { - setStyle(ENABLED, 0xFF000000) - setStyle(DISABLED, 0xFF808080) - setStyle(EMBED_FONTS, false) - setStyle(TEXT_FORMAT, null) + super() + appendStyle(DISABLED, 0xFF808080) + appendStyle(ENABLED, 0xFF000000) + appendStyle(EMBED_FONTS, false) + appendStyle(TEXT_FORMAT, null) } } diff --git a/src/syncomps/styles/SplitButtonStyle.as b/src/syncomps/styles/SplitButtonStyle.as index de1dc22..51aedee 100644 --- a/src/syncomps/styles/SplitButtonStyle.as +++ b/src/syncomps/styles/SplitButtonStyle.as @@ -4,7 +4,7 @@ package syncomps.styles * ... * @author Gimmick */ - public final class SplitButtonStyle extends Style + public class SplitButtonStyle extends Style { public function SplitButtonStyle() { super([ComboBoxStyle, LabeledButtonStyle]) diff --git a/src/syncomps/styles/Style.as b/src/syncomps/styles/Style.as index edceb49..db11126 100644 --- a/src/syncomps/styles/Style.as +++ b/src/syncomps/styles/Style.as @@ -2,118 +2,117 @@ package syncomps.styles { import flash.events.EventDispatcher; import flash.utils.Dictionary; + import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; import syncomps.events.StyleEvent; import syncomps.interfaces.IStyleDefinition; + import syncomps.interfaces.IStyleInternal; + + /** + * Dispatched when a style property is changing. + */ + [Event(name = "synStEStyleChanging", type = "syncomps.events.StyleEvent")] + /** * The base class for all styles. Use this as an abstract class, which defines fields, or properties, used by the Style object. * @author Gimmick */ - public class Style extends EventDispatcher implements IStyleDefinition + public class Style extends EventDispatcher implements IStyleInternal { - protected var arr_fields:Array - private var arr_parents:Array + private var arr_fields:Array private var dct_styleSets:Dictionary + private var vec_parents:Vector. + /** - * - * @param baseStyles An array of Class + * Creates a style. + * @param baseStyles An array of Class which the style inherits properties from. + * @param fields The fields which are to be inherited from the parent styles. */ - public function Style(baseStyles:Array = null, fields:Array = null) + public function Style(baseStyles:Array = null) { - if(!fields) { - fields = new Array() - } - if(!baseStyles) { - baseStyles = new Array() - } - init(baseStyles, fields) - } - - private function init(inheritArray:Array, fieldArray:Array):void - { - arr_fields = fieldArray - dct_styleSets = new Dictionary(true) - arr_parents = inheritArray.concat() - for (var i:int = inheritArray.length - 1; i >= 0; --i) { - copyFrom(inheritArray[i] as Class) - } + var inheritArray:Vector. = Vector.(baseStyles || []); - addEventListener(StyleEvent.STYLE_CHANGING, setStyleOnEvent, false, 0, true) + arr_fields = new Array() + vec_parents = inheritArray + dct_styleSets = new Dictionary(true) + inheritArray.reverse().forEach(function copy(item:Class, index:int, array:Vector.):void { + copyFrom(item) + }); } - public function get styleDefinition():Style { + public function get styleDefinition():IStyleInternal { return this } public function getDefaultStyle():Class { - return Style + return getDefinitionByName(getQualifiedClassName(this)) as Class } - public function setDefaultStyle(styleClass:Class):void { - return; - } + public function setDefaultStyle(styleClass:Class):void { /* no default implementation: abstract */ } public function getStyle(style:Object):Object { return dct_styleSets[style] } - public function getStyleDefinition():Object + public function getStyleProperties():Dictionary { - var def:Object = {} - for (var i:Object in dct_styleSets) { - def[i] = dct_styleSets[i] + var properties:Dictionary = new Dictionary(true) + for (var prop:Object in dct_styleSets) { + properties[prop] = dct_styleSets[prop] } - return def + return properties } - public function setStyle(style:Object, value:Object):void + protected function appendStyle(style:Object, value:Object):void { - if ((style in dct_styleSets && nonStrictEquals(dct_styleSets[style], value)) || arr_fields.indexOf(style) == -1) { - return; + if(arr_fields.lastIndexOf(style) != -1) { + return; } - dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGING, style, value, true, true)) - } - - [Inline] - private final function nonStrictEquals(varA:*, varB:*):Boolean { - return (varA == varB) || (fastIsNaN(varA) && fastIsNaN(varB)) - } - - [Inline] - private final function fastIsNaN(varA:*):Boolean { - return varA !== varA //NaN == NaN or NaN === NaN is always false but 1===1 so + arr_fields.push(style) + forceStyle(style, value) } - private function setStyleOnEvent(evt:StyleEvent):void + public function setStyle(style:Object, value:Object):void { - if(!evt.isDefaultPrevented()) { - forceStyle(evt.style, evt.value) + if (arr_fields.indexOf(style) == -1 || (style in dct_styleSets && ((dct_styleSets[style] === value) || (dct_styleSets[style] == value) || (isNaN(dct_styleSets[style] as Number) && isNaN(value as Number))))) { + return; //do not set style if it is not present in traits, or if it is the same + } + else if(dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGING, style, value, true, true))) { + forceStyle(style, value) } } + public function getFields():Array { + return arr_fields && arr_fields.concat() + } + public function copyFrom(defaultStyleClass:Class):void { if(!defaultStyleClass) { return; } - var style:Style = new defaultStyleClass as Style - var defaultStyleSet:Dictionary = style.dct_styleSets - arr_fields = arr_fields.concat.apply(null, style.arr_fields) + + var style:IStyleInternal = new defaultStyleClass() as IStyleInternal + if(!dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGING, null, style, true, true))) { + return; + } + + var defaultStyleSet:Dictionary = style.getStyleProperties() + arr_fields = arr_fields.concat(style.getFields()) for (var prop:Object in defaultStyleSet) { dct_styleSets[prop] = defaultStyleSet[prop] } - var parents:Array = style.arr_parents; + + var parents:Vector. = style.getInheritanceChain() if (parents) { - if (!arr_parents) { - arr_parents = parents.concat().reverse() - } - else for (var i:uint = 0; i < parents.length; ++i) + vec_parents ||= parents.concat().reverse(); + parents.forEach(function addParents(item:Class, index:int, array:Vector.):void { - if(arr_parents.indexOf(parents[i]) == -1) { - arr_parents.unshift(parents[i]) + if(vec_parents.lastIndexOf(item) == -1) { + vec_parents.unshift(item); } - } + }); } dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGE, null, style, true, false)) } @@ -123,42 +122,25 @@ package syncomps.styles * Similar to copyFrom(), but does not introduce new properties. * @param style */ - public function applyStyle(style:Style):void + public function applyStyle(style:IStyleInternal):void { - if (style) - { - addEventListener(StyleEvent.STYLE_CHANGING, applyStyleOnEvent, false, 0, true) - dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGING, null, style, true, true)) - } - } - - private function applyStyleOnEvent(evt:StyleEvent):void - { - removeEventListener(StyleEvent.STYLE_CHANGING, applyStyleOnEvent) - if(evt.isDefaultPrevented()) { + if (!style) { return; } - var style:Style = evt.value as Style - var styleSet:Dictionary = style.dct_styleSets - for(var i:Object in dct_styleSets) { - dct_styleSets[i] = styleSet[i] + var styleSet:Dictionary = style.getStyleProperties() + for (var property:Object in dct_styleSets) + { + if (property in styleSet && dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGING, property, styleSet[property], true, true))) { + forceStyle(property, styleSet[property]) + } } - dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGE, null, evt.value, true, false)) } - public function getInheritanceChain():Array { - return arr_parents.concat() - } - - public function refresh():void - { - for (var prop:Object in dct_styleSets) { - dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGE, prop, dct_styleSets[prop], true, false)) - } - dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGE, null, null, true, false)) + public function getInheritanceChain():Vector. { + return vec_parents && vec_parents.concat() } - public function forceStyle(style:Object, value:Object):void + public function forceStyle(style:Object, value:Object):void { dct_styleSets[style] = value dispatchEvent(new StyleEvent(StyleEvent.STYLE_CHANGE, style, value, true, false)) diff --git a/src/syncomps/styles/StyleManager.as b/src/syncomps/styles/StyleManager.as index dcfcd5e..8ae7a34 100644 --- a/src/syncomps/styles/StyleManager.as +++ b/src/syncomps/styles/StyleManager.as @@ -6,16 +6,31 @@ package syncomps.styles import syncomps.ComboBox; import syncomps.TextInput; import syncomps.interfaces.IStyleDefinition; + import syncomps.interfaces.IStyleInternal; import syncomps.interfaces.ISynComponent; + /** * ... * @author Gimmick */ public class StyleManager { + /** + * The style bias. + */ + private static const STYLE_BIAS:int = -1; + /** + * The default bias, for when the type is not explicitly known. + */ + private static const DEFAULT_BIAS:int = 0; + /** + * The component bias. + */ + private static const COMPONENT_BIAS:int = 1; + private static var cl_styleManager:StyleManager private var dct_styleSets:Dictionary; - private var arr_setIndices:Array; + private var vec_setIndices:Vector. public function StyleManager() { init() @@ -27,7 +42,7 @@ package syncomps.styles private function init():void { - arr_setIndices = new Array() + vec_setIndices = new Vector.() dct_styleSets = new Dictionary(false) } @@ -36,20 +51,20 @@ package syncomps.styles if(!(component && component.styleDefinition)) { return; } - var style:Style = component.styleDefinition + var style:IStyleInternal = component.styleDefinition var styleClassObj:StyleChainData = registerClass(getQualifiedClassName(style)) if(!styleClassObj.parents) { styleClassObj.parents = style.getInheritanceChain() } var componentClassName:String = getQualifiedClassName(component) - var componentClassObj:StyleChainData = registerClass(componentClassName) + var componentClassObj:StyleChainData = registerClass(componentClassName, COMPONENT_BIAS) registerComponent(component) var classChildren:Dictionary = componentClassObj.children var objChildren:Dictionary = styleClassObj.children if (!classChildren) { componentClassObj.children = classChildren = new Dictionary(false); - for(var child:Object in objChildren) + for (var child:Object in objChildren) { var currComponent:ISynComponent = child as ISynComponent if(getQualifiedClassName(currComponent) == componentClassName) { @@ -61,77 +76,48 @@ package syncomps.styles refreshComponent(component) } - internal function unregister(component:ISynComponent):void + internal function unregisterDefinition(style:IStyleInternal):void { - if (component && component.styleDefinition) + if (!style) { + return; + } + var child:Object, prop:Object; + var styleClassName:String = getQualifiedClassName(style) + var styleData:StyleChainData = dct_styleSets[styleClassName]; + if (styleData) { - var className:String; - var childArr:Dictionary; - var continueDelete:Boolean; - var currObj:StyleChainData, child:Object, prop:Object; - currObj = dct_styleSets[component] as StyleChainData; - if (currObj) + //unlink entire component style from tree + var childArr:Dictionary = styleData.children + var continueDelete:Boolean = true; + for (child in childArr) { - //unlink child from tree - prop = currObj.properties as Dictionary - for(child in prop) { - delete prop[child]; - } - delete dct_styleSets[component] + continueDelete = false; //do not continue if any children remaining + break; } - className = getQualifiedClassName(component) - currObj = dct_styleSets[className] as StyleChainData - if (currObj) + for (prop in styleData.properties) { - //unlink component class from tree - childArr = currObj.children - if(component in childArr) { - delete childArr[component] - } - continueDelete = true; - for (child in childArr) - { - continueDelete = false; //do not continue if any children remaining - break; - } - for (prop in currObj.properties) - { - continueDelete = false; //do not continue delete if any prop is present - break; - } - if (continueDelete) { - delete dct_styleSets[className]; - } + continueDelete = false; //do not continue delete if any prop is present + break; } - className = getQualifiedClassName(component.styleDefinition) - currObj = dct_styleSets[className]; - if (currObj) + + if (continueDelete) { - //unlink entire component style from tree - childArr = currObj.children - if(component in childArr) { - delete childArr[component] - } - continueDelete = true; - for (child in childArr) - { - continueDelete = false; //do not continue if any children remaining - break; - } - for (prop in currObj.properties) - { - continueDelete = false; //do not continue delete if any prop is present - break; - } - if (continueDelete) - { - arr_setIndices.removeAt(arr_setIndices.indexOf(className)) - delete dct_styleSets[className]; - } + vec_setIndices.removeAt(vec_setIndices.indexOf(styleClassName)) + delete dct_styleSets[styleClassName]; } } } + internal function unregisterAll(component:ISynComponent):void + { + if (!component) { + return; + } + unregisterComponent(component) + unregisterClass(getQualifiedClassName(component)) + unregisterDefinition(component.styleDefinition) + } + internal function setComponentStyle(component:ISynComponent, style:Object, value:Object):void { registerComponent(component).properties[style] = value; } @@ -141,23 +127,73 @@ package syncomps.styles var currData:StyleChainData = dct_styleSets[component] as StyleChainData if (component && !currData) { - registerClass(getQualifiedClassName(component)) - dct_styleSets[component] = currData = new StyleChainData(new Dictionary(false), null, null) + var componentClassData:StyleChainData = registerClass(getQualifiedClassName(component), COMPONENT_BIAS) + dct_styleSets[component] = currData = new StyleChainData(new Dictionary(false), null, null, COMPONENT_BIAS); + (dct_styleSets[component] as StyleChainData).parents = componentClassData.parents = component.styleDefinition.getInheritanceChain() } return currData } - internal function registerClass(className:String):StyleChainData + private function unregisterComponent(component:ISynComponent):void + { + var currData:StyleChainData = dct_styleSets[component] as StyleChainData; + if (component && currData) + { + //unlink child from tree + function clearChildrenIfFound(className:String, component:ISynComponent):void + { + var childArr:Dictionary = (dct_styleSets[className] as StyleChainData).children + if(component in childArr) { + delete childArr[component] + } + } + clearChildrenIfFound(getQualifiedClassName(component), component) + clearChildrenIfFound(getQualifiedClassName(component.styleDefinition), component) + + var prop:Dictionary = currData.properties as Dictionary + for (var child:Object in prop) { + delete prop[child]; + } + delete dct_styleSets[component]; + } + } + + internal function registerClass(className:String, bias:int = DEFAULT_BIAS):StyleChainData { var currData:StyleChainData = dct_styleSets[className] as StyleChainData; if (!currData) { - arr_setIndices.push(className) - dct_styleSets[className] = currData = new StyleChainData(new Dictionary(false), new Dictionary(false), null) + vec_setIndices.push(className) + dct_styleSets[className] = currData = new StyleChainData(new Dictionary(false), new Dictionary(false), null, bias) } return currData } + private function unregisterClass(className:String):void + { + var currData:StyleChainData = dct_styleSets[className] as StyleChainData; + if (currData) + { + //unlink component class from tree + var childArr:Dictionary = currData.children + var continueDelete:Boolean = true; + for (var child:Object in childArr) + { + continueDelete = false; //do not continue if any children remaining + break; + } + for (var property:Object in currData.properties) + { + continueDelete = false; //do not continue delete if any property is present + break; + } + + if (continueDelete) { + delete dct_styleSets[className]; + } + } + } + public function setStyle(styleClass:Class, style:Object, value:Object, refreshAll:Boolean):void { var styleClassName:String = getQualifiedClassName(styleClass) @@ -174,25 +210,21 @@ package syncomps.styles return; } var children:Dictionary = styleDescriptor.children - for(var child:Object in children) { + for (var child:Object in children) { refreshComponent(child as ISynComponent); } } public function forceRefresh():void { - var indices:Array = arr_setIndices; - for (var j:int = indices.length - 1; j >= 0; --j) - { - var currValue:String = indices[j] as String; - if(!(currValue && dct_styleSets[currValue])) { - indices.removeAt(j) - } - } - indices.sort(sortStyleSets) - for (var i:uint = 0; i < indices.length; ++i) { - updateChildren(dct_styleSets[indices[i]]) - } + vec_setIndices = vec_setIndices.filter(filterNull).sort(sortStyleSets); + vec_setIndices.forEach(updateAllChildren) + } + private function filterNull(item:String, index:int, array:Vector.):Boolean { + return (item in dct_styleSets); + } + private function updateAllChildren(item:String, index:int, array:Vector.):void { + updateChildren(dct_styleSets[item]); } private function refreshComponent(component:ISynComponent):void @@ -200,24 +232,15 @@ package syncomps.styles if(!(component && component.styleDefinition)) { return; } - var style:Style = component.styleDefinition + var style:IStyleInternal = component.styleDefinition var currObj:StyleChainData = registerClass(getQualifiedClassName(style)) - var parents:Array = currObj.parents as Array //array of class - if(!parents) { - currObj.parents = parents = style.getInheritanceChain() - } - for (var i:uint = 0; i < parents.length; ++i) - { - //apply properties of classes from first to last - var currParent:Class = parents[i] as Class - if (currParent) { - applyStyleDefinition(style, registerClass(getQualifiedClassName(currParent))) - } - } + var parents:Vector. = (currObj.parents ||= style.getInheritanceChain()); + parents.forEach(function applyStyles(item:Class, index:int, array:Vector.):void { + item && applyStyleDefinition(style, registerClass(getQualifiedClassName(item), STYLE_BIAS)) //apply properties of classes from first to last + }) applyStyleDefinition(style, registerClass(getQualifiedClassName(style))) //style class-level styles applyStyleDefinition(component, registerClass(getQualifiedClassName(component))) //component class-level styles applyStyleDefinition(style, dct_styleSets[component] as StyleChainData) //component instance-level styles - style.refresh() } private function applyStyleDefinition(styleDefinition:IStyleDefinition, styleDescriptor:StyleChainData):void @@ -233,39 +256,45 @@ package syncomps.styles private function sortStyleSets(styleAName:String, styleBName:String):int { - var parentA:Array = dct_styleSets[styleAName].parents as Array - var parentB:Array = dct_styleSets[styleBName].parents as Array - if (parentA && parentB) + /** + * Selects style A, i.e. style A appears before style B. + */ + const A_FIRST:int = -1 + /** + * Selects style B, i.e. style B appears before style A. + */ + const B_FIRST:int = 1 + var styleDataA:StyleChainData = dct_styleSets[styleAName] as StyleChainData + var styleDataB:StyleChainData = dct_styleSets[styleBName] as StyleChainData + var styleBias:int = (styleDataA.bias - styleDataB.bias) + var parentA:Vector. = styleDataA.parents + var parentB:Vector. = styleDataB.parents + var favor:int; + + if(styleBias) { + return styleBias //always return the bias if it is not 0, i.e. if there is a bias difference + } + else if (parentA && parentB) { - if(parentA.indexOf(getDefinitionByName(styleBName)) != -1) { - return -1 //B is a child of A; A should come before B - } - else if(parentB.indexOf(getDefinitionByName(styleAName)) != -1) { - return 1 //A is a child of B; B should come before A - } - else if(parentA.length > parentB.length) { - return 1 //A has more parents than B; B should come before A + if(parentA.indexOf(getDefinitionByName(styleBName) as Class) != -1) { + favor = A_FIRST //B is a child of A; select style A first } - else if(parentB.length > parentA.length) { - return -1 //B has more parents than A; A should come before B + else if(parentB.indexOf(getDefinitionByName(styleAName) as Class) != -1) { + favor = B_FIRST //A is a child of B; select style B first } - return 0 + favor = (parentA.length - parentB.length) } else if(parentA) { - return -1 + favor = B_FIRST //styleB has no parents, but styleA does => select style B } else if(parentB) { - return 1 + favor = A_FIRST //styleA has no parents, but styleB does => select style A } - return 0; + return favor } - private static function get mainInstance():StyleManager - { - if(!cl_styleManager) { - new StyleManager() - } - return cl_styleManager; + private static function get mainInstance():StyleManager { + return cl_styleManager || new StyleManager() } public static function register(component:ISynComponent):void { @@ -305,7 +334,11 @@ package syncomps.styles } public static function unregister(component:ISynComponent):void { - mainInstance.unregister(component) + mainInstance.unregisterAll(component) + } + + public static function unregisterDefinition(style:IStyleInternal):void { + mainInstance.unregisterDefinition(style) } } @@ -314,13 +347,21 @@ package syncomps.styles import flash.utils.Dictionary; internal class StyleChainData { - public var properties:Dictionary; public var children:Dictionary - public var parents:Array - public function StyleChainData(properties:Dictionary, children:Dictionary, parents:Array) + public var properties:Dictionary; + public var parents:Vector. + /** + * Used to favor styles over component classes. Component classes have a bias of 1 and styles have a bias of -1. + * This is used to sort the order in which styles are processed in the updateAll() method. + * For example, by calling biasA - biasB, components are shifted lower down the hierarchy since their biases are higher than style biases. + */ + public var bias:int + + public function StyleChainData(properties:Dictionary, children:Dictionary, parents:Vector., bias:int) { this.properties = properties this.children = children this.parents = parents + this.bias = bias } } \ No newline at end of file