diff --git a/.gitignore b/.gitignore index fa09665370..316ccfac3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,23 @@ .DS_Store +Thumbs.db *.swc *.stackdump ._* *.local.properties -output -third-party \ No newline at end of file +*.p12 +out/ +output/ +third-party/ +signing/ +.actionScriptProperties +.flexLibProperties +.project +.settings/ +bin-debug/ +bin-release/ +html-template/ +.metadata/ +*.iml +.idea/ +archive/ +*.lnk \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e3c2c1d9d9..0000000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012 Josh Tynjala - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..c5985833d0 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,29 @@ +Simplified BSD License +====================== + +Copyright 2012-2014 Joshua Tynjala. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the copyright holders. \ No newline at end of file diff --git a/README.md b/README.md index e899cc681b..279f13d941 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,34 @@ -# Foxhole +# Feathers 2.1 Prerelease -Built on [Starling](http://gamua.com/starling/) for Adobe AIR and Flash Player, Foxhole consists of various UI controls designed for mobile, developed by [Josh Tynjala](http://twitter.com/joshtynjala). The author develops Foxhole to support real-world mobile applications that he develops, mostly games. +--- -To get started, you might want to check out the [API Documentation](http://www.flashtoolbox.com/foxhole-starling/documentation/) and the [Foxhole for Starling Examples](https://github.com/joshtynjala/foxhole-starling-examples). +**Warning:** This is a pre-release version of Feathers. It may contain bugs or unfinished features. It is not recommended for production apps because it is considered *unstable*. Use at your own risk. To download a stable build, visit the [Feathers website](http://feathersui.com/). -## Available Components +--- -Foxhole includes the following UI controls (in alphabetical order): - -### Button -A typical button control, with optional toggle support. Includes a label and an icon, both optional. - -### Label -A single-line, non-interactive text control. Uses bitmap fonts. A simplified replacement for `starling.text.TextField` that is built on `FoxholeControl`. - -### List -A touch-based, vertical list control. Has elastic edges and you can "throw" it. - -### PickerList -A control similar to a combo box. Appears as a button when closed. The list is displayed as a fullscreen overlay on top of the stage. - -### Progress Bar -Displays the progress of a task over time. Non-interactive. - -### Screen -An abstract class for implementing a single screen within a menu developed with `ScreenNavigator`. Includes common helper functionality, including back/menu/search hardware key callbacks, calculating scale from original resolution to current stage size, and template functions for initialize, layout and destroy. - -### ScreenHeader -A header that displays a title along with a horizontal regions on the sides for additional UI controls. The left side is typically for navigation (to display a back button, for example) and the right for additional actions. - -### ScreenNavigator -A state machine for menu systems. Uses events or signals to trigger navigation between screens or to call functions. Includes very simple dependency injection. - -### Slider -A typical horizontal or vertical slider control. - -### TabBar -A line of tabs, where one may be selected at a time. - -### TextInput -A text entry control that allows users to enter and edit a single line of uniformly-formatted text. Uses StageText. - -### ToggleSwitch -A sliding on/off switch. A common alternative to a checkbox in mobile environments. - - -## Dependencies - -The following external libraries are required. Other versions of the same library may work, but the version displayed below is the one currently used by the author. - -* [Starling](http://gamua.com/starling/) post-v1.0 (please use a commit newer than April 18, 2012) -* [GTween](http://gskinner.com/libraries/gtween/) v2.01 -* [as3-signals](https://github.com/robertpenner/as3-signals) v0.9 BETA +Say hello to [Feathers](http://feathersui.com/), a library of light-weight, skinnable, and extensible UI controls for mobile and desktop. The components run on [Starling Framework](http://starling-framework.org/) and the [Adobe Flash runtimes](http://gaming.adobe.com/technologies/) — offering blazing fast GPU powered graphics to create a smooth and responsive experience. Build completely standalone, native applications on iOS, Android, Windows, and Mac OS X, or target Adobe Flash Player in desktop browsers. Created by [Josh Tynjala](http://twitter.com/joshtynjala), Feathers is free and open source. ## Quick Links -* [Foxhole for Starling Examples](https://github.com/joshtynjala/foxhole-starling-examples) -* [API Documentation](http://www.flashtoolbox.com/foxhole-starling/documentation/) -* [Getting Started Article](https://github.com/joshtynjala/foxhole-starling/wiki/Getting-Started) -* [Official Foxhole Q&A thread on the Starling Forums](http://forum.starling-framework.org/topic/official-foxhole-components-qa) - -## Important Note +* [Website](http://feathersui.com/) +* [Documentation](http://wiki.starling-framework.org/feathers/start) +* [API Reference](http://feathersui.com/documentation/) +* [Discussion Forum](http://forum.starling-framework.org/forum/feathers) +* [Github Project](https://github.com/joshtynjala/feathers) -The core architecture and non-private APIs of Foxhole for Starling are still under active design and development. Basically, for the time being, absolutely everything is subject to change, and updating to new revisions may result in broken content. If something breaks after you update to the latest revision, and you can't figure out the new way to do something, please ask in the [Q&A thread](http://forum.starling-framework.org/topic/official-foxhole-components-qa) I have set up at the Starling Forum. +### News and Updates -## Tips +* [Like on Facebook](https://facebook.com/feathersui) +* [Follow on Twitter](https://twitter.com/feathersui) +* [Find on Google+](https://www.google.com/+feathersui) -* The components do not have default skins. However, you can try out one of the themes included with the [Foxhole for Starling Examples](https://github.com/joshtynjala/foxhole-starling-examples). +## Minimum Requirements -* In most cases any Starling display object is acceptable as a skin. However, the `ToggleSwitch` control works best with skins that supports `scrollRect` (it's not required, but recommended). Starling's core display objects do not implement `scrollRect` at this time. Subclasses of `Sprite` and `Image` with basic (but somewhat incomplete) implementations are included with Foxhole. +* Adobe AIR 15.0 or newer for mobile apps +* Adobe AIR 3.5 or newer for desktop apps +* Adobe Flash Player 11.5 or newer for web browser apps +* Starling Framework from Github -* Bitmap fonts are required for all text displayed in these UI controls. Use `BitmapFontTextFormat` to customize the text styles. `BitmapFont` from Starling has been subclassed to add the missing `base` property defined in `*.fnt` files. +## Downloads -* An Ant build script is included. Add a file called `sdk.local.properties` to override the location of the Flex SDK and `build.local.properties` to override the locations of the required third-party libraries. \ No newline at end of file +To download the latest stable version of Feathers, visit [feathersui.com](http://feathersui.com/). \ No newline at end of file diff --git a/RELEASENOTES.md b/RELEASENOTES.md new file mode 100644 index 0000000000..20d477b873 --- /dev/null +++ b/RELEASENOTES.md @@ -0,0 +1,649 @@ +# Feathers Release Notes + +Noteworthy changes in official, stable releases of [Feathers](http://feathersui.com/). + +## 2.0.1 + +* AddOnFunctionStyleProvider: fixed issue where function passed into constructor would be ignored. +* LayoutGroup: fixed issue where background skin would not validate after setting its dimensions. +* Scale3Image, Scale9Image, TiledImage: updated to listen for Event.FLATTEN to validate instead of overriding flatten() to remain compatible with the new flatten() function signature in Starling 1.6. +* StageTextTextEditor: fixed issue where StageText.stage was null, and calling drawViewPortToBitmapData() resulted in a runtime error. +* StageTextTextEditor: fixed issue where setFocus() didn't work if StageText.stage was null. +* TextInput: fixed issue where runtime error would be thrown after changing prompt from null to a valid string after input had validated. +* Themes: fixed issue in desktop themes where assets displayed at 4x instead of 2x on HiDPI Macs. +* Themes: fixed issue in desktop themes where PanelScreen and ScrollScreen would incorrectly use mobile scroll bars and behaviors. +* Themes: fixed issue where a subclass would add a style function for the ToggleSwitch class, and that would cause some ToggleSwitch instances to be missing skins. +* Themes: fixed issue where wrong arguments were passed to Texture.fromBitmap(). +* Added workarounds for stack overflow runtime errors when compiling with legacy Flex 4.6 compiler. + +## 2.0.0 + +* New style provider architecture for skinning and themes. +* Components may always be validated, even if they are not on the display list yet. +* New Text Editor: TextBlockTextEditor is a desktop-only text editor built on FTE, similar to TextBlockTextRenderer. +* New Text Editor: BitmapFontTextEditor is a desktop-only text editor built on bitmap fonts, similar to BitmapFontTextRenderer. +* All Components: subComponentProperties pattern is now stricter. If properties that don't exist are set, a runtime error will be thrown. +* BitmapFontTextRenderer: properly redraws when isEnabled is changed. +* BitmapFontTextRenderer: if textFormat is null, generates a default value so that something will be displayed (using Starling's embedded BitmapFont.MINI). +* Button: added minGap property that is used when gap is set to Number.POSITIVE_INFINITY. +* Button: pulled out toggle functionality into a subclass: ToggleButton. +* Button: removed now-useless autoFlatten property. +* Button: added new hasLabelTextRenderer that may be set to false to avoid creating the text renderer (for things like scroll bar or slider button sub-components). +* Button: fixed issue where button didn't return to up state when focus is changed with keyboard while in another state. +* Callout: added stagePadding property to set stagePaddingTop, stagePaddingRight, stagePaddingBottom, and stagePaddingLeft properties all at once. +* Callout: fixed issue where touch listener was removed when callout was removed, but it wasn't re-added when the same callout instance was shown again. +* DefaultGroupedListHeaderOrFooterRenderer: fixed issue where content wasn't disabled when isEnabled changed. +* Drawers: added optional overlaySkin property to fade in a display object over the content when a drawer is opened. +* Drawers: checks if event types are null before adding listeners. +* Drawers: open and close events now pass the display object in the event data. +* Drawers: fix for issue where wrong toggle duration may used sometimes. +* DropDownPopUpContentManager: added new gap property. +* FeathersControl: enforced as an abstract class. If you need a generic Feathers component wrapper for layoutData and things, use LayoutGroup. +* FeathersControl: added styleName and styleNameList property to replace nameList. The name property is no longer used for styling, and it will work for getChildByName() in the rare situations where it was broken. The nameList property is deprecated. +* FeathersControl: fixed issue where changing minTouchWidth or minTouchHeight did not update the hit area if the width or height wasn't changed at the same time. +* FeathersControl: fixed issue where component would validate when disposed. +* FeathersControl: fixed issue in setSize() where scaled dimensions weren't updated. +* FocusManager: support for custom IFocusManager instances and support for multiple Starling stages. +* FocusManager: fixed issue where disabled components could receive focus. +* Header: added useExtraPaddingForOSStatusBar property to support iOS 7 status bar behavior. +* Header: getters for leftItems, rightItems, and centerItems no longer duplicate the array. +* Header: now disposed leftItems, rightItems, and centerItems by default. Can be controlled with new disposeItems property. +* Header: fixed issue where title text renderer's isEnabled property wasn't properly updated. +* Header: fixed issue where the touchable property was incorrectly set to false on some children. +* IFocusDisplayObject: added new focusOwner property to allow pop-ups to be owned by another component. Allows the focus manager to manage focus order better with components like PickerList. +* ImageLoader: checks for lost context before creating a texture from a loaded URL. +* ImageLoader: fixed issue where isLoaded getter didn't always return true if the source is a texture. +* ImageLoader: fixed issue where loaded textures could be uploaded to wrong Starling instance if multiple Starling instances were active. +* Item Renderers: added skinField, skinFunction, and itemHasSkin for background skins from the data provider. +* Item Renderers: added isSelectableOnAccessoryTouch property to control whether the selection will change or not when the accessory is touched. +* Item Renderers: added minGap and minAccessoryGap properties that are used when gap or accessoryGap are set to Number.POSITIVE_INFINITY. +* ITextEditor, ITextRenderer: extend a new IBaselineTextControl interface that defines a common baseline property. +* Layouts: fixed issue where they didn't account for pivotX and pivotY. +* Layouts: when centering items, rounds the x and y positions to the nearest integer. +* LayoutGroup: added new backgroundSkin and backgroundDisabledSkin properties. +* List, GroupedList: if dataProvider property is changed, or the collection dispatches CollectionEventType.RESET, automatically behaves as if updateItemAt() were called on all item renderers. +* ListCollection, HierarchicalCollection: added dispose() function to support a way to dispose things like display objects or textures in items. +* NumericStepper: claims exclusive touch so that it won't repeat while scrolling with touch. +* NumericStepper: fixes for obscure situations where text input changes are not reflected in the value. +* NumericStepper: improved auto-measurement for values that are not integers. +* NumericStepper: added textInputGap and buttonGap properties. +* PageIndicator: added new interactionMode property to allow alternate precise selection of symbols on tap, instead of previous back/next behavior. +* Panel: added new outerPadding properties to support padding that is around the everything, including the header and footer. The existing (inner) padding properties only apply to the content between the header and footer. +* PanelScreen: turns on clipping by default. +* PickerList: added toggleButtonOnOpenAndClose property. +* PickerList: implements IFocusDisplayObject and manages focus of children better. +* PickerList: closes on enter key to match native behavior. +* PopUpManager: when centering a pop-up, rounds the x and y positions to the nearest integer. +* ProgressBar: fixed vertical fill so that it starts from the bottom and fills up. +* PropertyProxy: added toString() function to allow a PropertyProxy to be output to console. +* Scale3Image, Scale9Image, fixed issue where scaling smaller than the minimum size would cause overlapping instead of distortion when end regions weren't the same size. +* Scale3Textures, Scale9Textures: fixed rendering of textures with a scale property that isn't equal to 1. +* Screens: removed dpiScale, pixelScale, originalWidth, and originalHeight properties. The kinds of calculations these values were used for should be handled in the theme (or somewhere else outside of the screen if not using a theme). +* ScrollBar: increment and decrement buttons are hidden, like the thumb, if the minimum is equal to the maximum. The track fills the full dimensions. +* ScrollBar: fix for wrongly positioned track when direction is horizontal. +* ScrollContainer: fixed wrong measurement when using no layout with children at negative coordinates. +* Scroller: fixed issue where a floating scroll bar wouldn't disappear. +* Scroller: refactored scrolling behavior to more closely match iOS native scrolling. +* Scroller: touch overlay and background skins are added and removed instead of changing visible property. Works better with Monster Debugger. +* Scroller: fixes issue where events were dispatched for a completed scroll when the scroll position didn't actually change from calling throwTo(). +* Scroller: added support for a view port that doesn't necessarily auto-size to show its full content. In other words, a view port can choose to measure so that it needs to scroll. +* Scroller: fixed issue where background wasn't sized property when isEnabled was changed. +* Scroller: skips some unnecessary code when dimensions are explicit to improve performance. +* Scroller: added new measureViewPort property that can be set to false to exclude the view port from auto-measurement and only use the background skin. +* Scroller: automatically sets direction property on scroll bars, so that you don't need to, thanks to the new IDirectionalScrollBar interface. +* ScrollText: added disabledTextFormat property. +* ScrollText: may receive focus and use keyboard arrow keys to scroll. +* Slider: added new trackInteractionMode property to control whether touching the track updates the value by page or jumps directly to the nearest value. +* SmartDisplayObjectValueSelector: fixed issue where getValueTypeHandler() function had an extra parameter. +* SmartDisplayObjectValueSelector: added support for null value other than the default. +* SmartDisplayObjectValueSelector: stricter reuse of display objects. Type must match exactly. Fixes issue where Image is incorrectly reused because it is a subclass of Quad. +* StageTextTextEditor: fixed issue where measurement was wrong when text was an empty string. +* StageTextTextEditor: fixed issue on iOS where characters were masked immediately instead of showing in the clear for a moment. +* StageTextTextEditor: fixed issue where the clipboard menu appeared unexpectedly when multiline is true. +* StageTextTextEditor: draws StageText to BitmapData with double dimensions on Mac HiDPI, thanks to Adobe's bug fix. +* TabBarSlideTransitionManager: fixes bug where switching between tabs quickly would break the transition. +* Text: will use non-power-of-two textures for snapshots, if the Stage 3D profile supports it. +* Text: if a renderer or editor supports native filters, does some extra cleanup in dispose() that is actually unnecessary, but will ease some pressure if there's a memory leak. +* Text: fixed issue where snapshot wasn't updated when isEnabled changed. +* TextBlockTextRenderer: if elementFormat is null, generates a default value so that something will be displayed. +* TextBlockTextRenderer: fixed issue where width was calculated wrong when text ended in whitespace. +* TextFieldTextEditor, TextFieldTextRenderer: added useGutter property to allow removal of the 2-pixel "gutter" that Flash adds to a TextField. +* TextInput, TextArea: added hasFocus getter to allow checking focus, even if there is no focus manager. +* TextInput, Text Editors: added new selectionBeginIndex and selectionEndIndex properties. +* TextInput: fixes issue where prompt text renderer's isEnabled property wasn't updated. +* TextInput: added new verticalAlign property to support top, middle, bottom, or justify. +* TextInput: won't throw an error if there's no background skin, but auto-measurement will result in a width and height of 0, unless typicalText is set. +* TextInput: improved support for text editors that are completely on the Starling display list without a native overlay. +* TextInput: doesn't create prompt text renderer if prompt is null. +* TextArea: added stateToSkinFunction, similar to Button background skin. +* TextArea: fixed issue where background skin was sometimes missing. +* TextArea: added clearFocus() function match API of TextInput. +* TextArea: further improvements to positioning and scaling of texture snapshot. +* Text Editors: improved support for Mac HiDPI. +* Text Editors: added disabled font styles. +* Text Renderers: uses generateFilterRect() when using nativeFilters for improved texture dimensions. +* Text Renderers: ITextRenderer now has a first-class wordWrap property that is required by all renderers. +* TiledColumnsLayout, TiledRowsLayouts: fixed result of getScrollPositionForIndex() when paging is disable to allow the item to be properly centered. +* TiledColumnsLayout, TiledRowsLayouts: fixed calculation of tile count when padding is used. +* TiledColumnsLayout, TiledRowsLayout: added requestedRowCount and requestedColumnCount properties. +* ToggleSwitch: fixed issue where the isEnabled property of text renderers wasn't properly updated. +* ToggleSwitch: added toggleThumbSelection property to update the isSelected property of the thumb (if it's a ToggleButton) to match the isSelected property of the switch. +* ToggleSwitch: fixed issue where selection change wasn't animated when triggered with the keyboard instead of a touch. +* ToggleSwitch: added new setSelectionWithAnimation() method so that programmatic selection changes can be optionally animated. +* Examples: override initialize() instead of listening for FeathersEventType.INITIALIZE. +* Example Themes: rewritten using the new style provider system. +* Example Themes: tweaked padding, gap, dimensions, and other values to be based on a simple grid system for more consistency. + +### 2.0.0 Deprecated APIs + +All deprecated APIs are subject to the [Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy). Please migrate to the new APIs as soon as possible because the deprecated APIs **will** be removed in a future version of Feathers. + +The `nameList` property has been deprecated, and it is replaced by the `styleNameList` property. The `name` property is no longer connected to style names, and situations where it failed to work with `getChildByName()` have been resolved. The `styleName` property has been added to replace the former usage of the `name` property as a concatenated version of `nameList` (now, `styleNameList`). + +The `manageVisibility` property on layouts has been deprecated. In previous versions, this property could be used to improve performance of non-virtual layouts by hiding items that were outside the view port. However, other performance improvements have made it so that setting `manageVisibility` can now sometimes hurt performance instead of improving it. + +### 2.0.0 Default Behavior and API Changes + +This is a major update to Feathers, so it includes more breaking changes than usual. Be sure to read this section thoroughly to see if any of these changes will affect your apps. + +`TextFieldTextRenderer` and `TextFieldTextEditor` now have a `useGutter` property that controls whether the 2-pixel gutter around the edges of the `flash.text.TextField` will be used in measurement and layout. In previous versions of Feathers, the gutter was always enabled. The gutter is now disabled by default to allow text controls based on `TextField` to more easily align with other text controls. + +The `ITextRenderer` and `ITextEditor` interfaces now extend the `ITextBaselineControl` interface. In the case of `ITextEditor`, a new `baseline` getter is required. + +The `ITextRenderer` interface now requires a `wordWrap` property. + +The `IFocusDisplayObject` interface now requires a `focusOwner` property. + +Properties including `dpiScale`, `pixelScale`, `originalWidth`, `originalHeight`, and `originalDPI` have been removed from `Screen`, `ScrollScreen` and `PanelScreen`. The calculations previously offered by these properties should be handled in skinning code, such as the theme. + +The `Button` class no longer supports selection. This functionality has been moved into a subclass, `ToggleButton`. + +The `autoFlatten` property has been removed from the `Button` class. + +Setting the properties of a sub-component, such as using `thumbProperties` on a `Slider` to set properties on the slider's thumb sub-component, is now stricter. Previously, when a property did not exist, it was silently ignored. Now, an error will be thrown. + +If no text format is defined, `BitmapFontTextRenderer` defaults to using `BitmapFont.MINI` so that the text will always be rendered. Previously, it would render nothing. + +If no element format is defined, `TextBlockTextRenderer` defaults to using a new `ElementFormat` with default arguments so that the text will always be rendered. Previously, an error was thrown. + +A `trackInteractionMode` property has been added to `Slider`. In previous versions, `Slider` behaved as if `trackInteractionMode` were set to `Slider.TRACK_INTERACTION_MODE_BY_PAGE`. Now, the default value is `Slider.TRACK_INTERACTION_MODE_TO_VALUE`. + +A `verticalAlign` property has been added to `TextInput`. In previous versions, `TextInput` behaved as if `verticalAlign` were set to `TextInput.VERTICAL_ALIGN_JUSTIFY`. Now, the default value is `TextInput.VERTICAL_ALIGN_MIDDLE`. + +The `FeathersControl` class is now considered abstract. It will throw a runtime error if instantiated directly instead of being subclassed. If you need a generic Feathers component as a wrapper for another display object, use `LayoutGroup` instead. + +The `leftItems`, `rightItems`, and `centerItems` getters on the `Header` class no longer make a copy of their storage variables. Take care when modifying these values directly. + +Focus management now supports multiple Starling stages (for AIR desktop apps). The static `isEnabled` property has been removed. Instead, you should use the static `setEnabledForStage()` function: + +```as3 +FocusManager.setEnabledForStage( Starling.current.stage, true ); +``` + +All layouts now account for the `pivotX` and `pivotY` properties when positioning display objects. In previous versions, these properties were ignored. + +When the `direction` property of a `ProgressBar` is equal to `ProgressBar.DIRECTION_VERTICAL`, the fill now starts at the bottom and fills up. + +The increment button and decrement button sub-components of a `ScrollBar` are now hidden when the scroll bar's maximum scroll position is equal to its minimum scroll position, just like how the thumb is hidden. The track will be resized to fill the extra space where the buttons were previously rendered. + +When replacing the `dataProvider` of a `List` or `GroupedList` (or replacing the `data` property of a `ListCollection` or `HierarchicalCollection`), it is no longer necessary to call `updateItemAt()` on the new collection if it contains some of the same items as the previous collection. This behavior will happen automatically. + +## 1.3.1 + +* NumericStepper: fixed issue where using step to calculate a new value didn't account for the minimum value. +* NumericStepper: fixed issue where only some text was selected after changing value. +* TextInput: fixed issue where FOCUS_OUT event wasn't dispatched when used with a NumericStepper and FocusManager.isEnabled is true, causing NumericStepper to fail to update its value properly. +* Slider: fixed issue where using step to calculate a new value didn't account for the minimum value. +* Button: validates skin if the skin implements IValidating so that the skin resizes properly if button dimensions are tweened. +* Callout: fixed issue where callout incorrectly stopped content from resizing. +* Callout: fixed issue where content resizing wouldn't reposition callout to point to origin. +* TextInput: fixed issue where sometimes focus was not cleared on removal. +* TextBlockTextRenderer: fixed issue where sometimes an infinite loop was triggering when attempting to truncate. +* TextFieldTextEditor: fixed issue where existing text did not render with new text format. +* StageTextTextEditor, TextFieldTextEditor: fixed issue where multiple FOCUS_OUT events could be dispatched. +* TextArea: fixed positioning of texture snapshot when scrolling. +* TiledRowsLayout, TiledColumnsLayout: fixed issue where some tiles would be incorrectly invisible with top or left padding and manageVisibility. +* LayoutGroup: respects includeInLayout when no layout is specified. +* TextInput: fixed selection position on touch when displaying an icon. +* Gallery Example: updated to use HTTPS URLs since Flickr will soon require it. +* YouTubeFeeds Example: switched to category feeds since the older feeds were deprecated and displayed the wrong data. + +## 1.3.0 + +* New Component: ScrollScreen is new base class for ScreenNavigator screens that supports scrolling similar to ScrollContainer. +* New Component: TextBlockTextRenderer is a new text renderer that renders text with flash.text.engine.TextBlock, with a texture snapshot similar to TextFieldTextRenderer. +* More performance improvements with the help of Adobe Scout. +* Improved support for multiple windows in desktop AIR apps. +* Improved support for using scaleX and scaleY with Feathers components. +* Added support for Mac HiDPI resolutions. +* HorizontalLayout: added support for percentWidth and percentHeight with HorizontalLayoutData. +* VerticalLayout: added support for percentWidth and percentHeight with VerticalLayoutData. +* AnchorLayout: added support for percentWidth and percentHeight with AnchorLayoutData. +* HorizontalLayout: added optional firstGap and lastGap properties. +* VerticalLayout: added optional firstGap and lastGap properties. +* HorizontalLayout: added distributeWidths property to available divide available width equally to all items. +* HorizontalLayout: added distributeHeights property to available divide available height equally to all items. +* AnchorLayout: performance improvements. +* PickerList: added openList() and closeList() functions to open and close pop-up list programmatically. +* Screen: now extends LayoutGroup to support layouts. +* Scroller: final removal of scrollerProperties, which was deprecated in version 1.1.0. +* Scroller: support for placing the vertical scroll bar on the right for right-to-left locales. +* Scroller: added mouseWheelScrollStep property to support different steps on scroll bar and mouse wheel. +* ScrollText: now chooses exclusively between styleSheet or textFormat to avoid runtime error. +* ScrollText: added support for hyperlinks, including a new Event.TRIGGERED event when a link is clicked/tapped. +* TextFieldTextRenderer: now chooses exclusively between styleSheet or textFormat to avoid runtime error. +* TextFieldTextRenderer: added nativeFilters property to support rendering text with filters. +* BitmapFontTextRenderer: fixed issue where truncation happened when it wasn't necessary. +* BitmapFontTextRenderer: fixed kerning when font size is scaled. +* ImageLoader: added textureFormat property to specify a Context3DTextureFormat value. +* List: reuses its typical item renderer instead of creating a new one when measurement is required. +* ScrollContainer: added IScrollContainer interface including functions for "raw" children. +* Themes: "quiet" buttons now have a transparent up skin to blend into toolbars. +* Themes: broke apart initialize() function into multiple functions for better organization. +* Themes: support for optionally loading assets at runtime instead of embedding. +* Themes: now available as SWCs for easier project setup. +* MetalWorksMobileTheme: uses the new TextBlockTextRenderer. +* LayoutGroup: fix for empty spaces when an item is added more than once. +* ILayout: added new requiresLayoutOnScroll property to improve performance for static layouts. +* IValidating: new interface for objects that support validation. +* Scale9Image: implements IValidating to support forced validation and to put it in the ValidationQueue. +* Scale3Image: implements IValidating to support forced validation and to put it in the ValidationQueue. +* TiledImage: implements IValidating to support forced validation and to put it in the ValidationQueue. +* TabBar: support for more layout properties similar to ButtonGroup. +* Header: added optional centerItems property to support items in the center to replace the title. +* Item Renderers: added selectableField and selectableFunction to allow some item renderers to be selectable and some that are not selectable. +* Item Renderers: added enabledField and enabledFunction to allow some item renderers to be enabled and some that are not enabled. +* Item Renderers: added iconLabelField and iconLabelFunction similar to accessoryLabelField and accessoryLabelFunction. +* Item Renderers: support truncation of accessory label. +* DisplayListWatcher: extends EventDispatcher so that subclasses (themes) can dispatch events. +* DisplayListWatcher: now processes all matching named initializers instead of only the first match. +* PopUpManager: added IPopUpManager to support custom pop-up managers. +* PopUpManager: better support for multiple Starling instances. +* Alert: fixed issue where button group was disposed on close and caused runtime error. +* AnchorLayout: fixes for broken layouts with certain ordering of children. +* AnchorLayout: fixes to avoid runtime error when using children that don't implement ILayoutDisplayObject. +* Button: fix to long press duration being treated as an integer instead of floating point. +* Button: small fixes to layout edge cases. +* ButtonGroup: fix to allow buttons to be disabled and re-enabled. +* ButtonGroup: fix to properly remove event listners from data provider when data provider changes. +* BitmapFontTextRenderer: fix for centered text being blurred because its position wasn't rounded to an integer. +* Item Renderers: minor fixes to layout edge cases. +* StageTextTextEditor: fix for StageText not being properly hidden when text is empty. +* TextInput: fix for icon positioning using wrong padding value. +* ImageLoader: added optional textureQueueDuration property to upload textures after a short delay while delayTextureCreation is true. Previously, textures would not upload at all until delayTextureCreation was set to false again. +* ProgressBar: no longer sets touchable to false on skins. +* Panel: fix for failing to detect header and footer resizing. +* Drawers: fix for failing to detect drawer resizing. +* Scroller: fix for issue where an animated scroller with the scroll policy set to SCROLL_POLICY_OFF would incorrectly stop scrolling when touched. +* Scroller: fix for incorrect calculation of maximum scroll positions when pageWidth or pageHeight is set. +* TextFieldTextRenderer: fix for wrapping bug. +* HorizontalLayout: fix for getScrollPositionForIndex() to properly calculate scroll position for indices less than beforeVirtualizedItemCount. +* VerticalLayout: fix for getScrollPositionForIndex() to properly calculate scroll position for indices less than beforeVirtualizedItemCount. +* ScreenNavigator: fix for edge case where the screen was not resized properly with AUTO_SIZE_MODE_CONTENT. + +### 1.3.0 Deprecated APIs + +All deprecated APIs are subject to the [Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy). Please migrate to the new APIs as soon as possible because the deprecated APIs **will** be removed in a future version of Feathers. + +The `scrollerProperties` property on scrolling components, including List, GroupedList, ScrollText and ScrollContainer was originally deprecated in Feathers 1.1.0, and it has now been removed. Because these components now extend `Scroller` instead of adding a `Scroller` as a child, all of the properties that could be set through `scrollerProperties` can now be set directly on the components. + +### 1.3.0 API Changes + +Some changes have been made to Feathers that have the potential to break code in existing projects. Changes of this type may be considered [exceptions to the Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy#exceptions), and careful consideration is made to limit the impact of these changes on existing projects. Most developers using Feathers will not be affected by these changes, except perhaps, to observe improved stability and consistency. + +#### ILayout + +One change has been made to the `ILayout` interface. Custom implementations of `ILayout` created before Feathers 1.3.0 will have compiler errors until the required changes are made. + +The property `requiresLayoutOnScroll` has been added to `ILayout` to provide improved performance for static layouts that don't change when a container scrolls. + + This property can easily simulate the old behavior from Feathers 1.2.0, if required. The following implementation of `requiresLayoutOnScroll` can easily be copied into a custom implementations of `ILayout` to quickly migrate existing Feathers 1.2.0 implementations to behave exactly the same in Feathers 1.3.0: + + public function get requiresLayoutOnScroll():Boolean + { + return true; + } + +## 1.2.0 + +* New Component: Alert +* New Component: Drawers +* New Component: LayoutGroup +* New Component(s): LayoutGroupListItemRenderer, LayoutGroupGroupedListItemRenderer, LayoutGroupedListHeaderOrFooterRenderer +* FeathersControl: better support for scaleX and scaleY. Width and height are scaled. +* FeathersControl: dispatches FeathersEventType.CREATION_COMPLETE after the first validation. +* FeathersControl: added isCreated flag to indicate if FeathersEventType.CREATION_COMPLETE has been dispatched. +* FeathersControl: ensures that keyboard focus is ignored if disabled. +* FeathersControl: new protected functions setInvalidationFlag() and getInvalidationFlag() for better re-invalidation during draw(). +* FeathersControl: getChildByName() uses nameList.contains(). Doesn't work when an IFeathersControl is in a non-Feathers display object. +* Button: added FeathersEventType.LONG_PRESS event. +* Button: updates isEnabled on label text renderer and icon, if applicable. +* Button: label is always on top of the icon. +* List, GroupedList: Setting a new data provider will clear selection. Now, selection cannot be set before data provider is passed in. If the same selection is desired after a data provider change, it should be done manually. +* List, GroupedList: improved invalidation when various properties are changed. +* List, GroupedList: better handling of typical item to improve performance an accuracy of layout calculations. +* List, GroupedList: support for item renderers that can be deselected if multiple selection isn't enabled. +* ListCollection: removeAll() checks if length is 0 to avoid dispatching an event. +* GroupedList: improved handling of updateItemAt() to properly update whole groups. +* ImageLoader: added loadingTexture and errorTexture properties. +* ImageLoader: support for loading ATF files from URL. +* ToggleSwitch: on and off labels can be created with separate factories. +* Panel: header and footer contents can receive keyboard focus. +* ButtonGroup: properly resizes when data provider changes. +* ButtonGroup: support for padding around buttons. +* ButtonGroup: dispatches its own Event.TRIGGERED when any button is triggered. +* ButtonGroup: support for horizontal and vertical alignment. +* ButtonGroup, TabBar: better handling of custom names for first and last items. +* Callout: backgroundSkin is no longer required. +* Callout: show() function adds an argument for a custom overlay factory. +* Scale9Image, Scale3Image: support for scaling edge regions down to zero. Causes distortion, but removes overlapping. +* Scale9Image, Scale3Image, TiledImage, BitmapFontTextRenderer: uses batchable property from QuadBatch for improved performance. +* BitmapFontTextRenderer: fix for center and right alignment when using maxWidth. +* BitmapFontTextRenderer: fix for center and right alignment when no width or maxWidth is set. +* Scroller: support for minimum scroll positions less than zero. +* Scroller: improved draw() function to avoid extra invalidation. +* Scroller: new interactionMode value INTERACTION_MODE_TOUCH_AND_SCROLL_BARS. +* Scroller: added minimumDragDistance and minimumPageThrowVelocity. +* Scroller: fixed vertical page snapping. +* Scroller: supports custom page dimensions for snapping. +* Scroller: won't scroll with mouse wheel when scroll policy is off. +* Text editors: visibility fixes when text is empty. +* TextFieldTextEditor: support for rotation. +* StageTextTextEditor: doesn't clear text when displayAsPassword is changed. +* StageTextTextEditor: better scaling and support for rotation. +* TextFieldTextRenderer: supports using multiple textures if text width or height is greater than 2048 pixels. +* TextFieldTextRenderer: added disabledTextFormat property. +* TextInput, text renderers: dispatches soft keyboard events. +* TextInput: supports icon. +* TextInput: alternate name for search input. +* Screen, PanelScreen: better handling of back button that accounts for depth. +* ScreenNavigator: properly resizes if content is resized. +* ScreenNavigator: clears screen if removeScreen() is called for the active screen. +* ToggleGroup: added getItemIndex() and setItemIndex(). +* VerticalCenteredPopUpContentManager: touch must begin and end outside of content to close the content. +* DisplayListWatcher: added initializeObject() function to initialize display objects that are already added when a theme is created. +* PropertyProxy: support for QName values. +* SmartDisplayObjectValueSelector: fix to support uint values for Quads. +* SmartDisplayObjectValueSelector: support for ConcreteTexture. +* State value selectors: strict equality checks for null to support 0 values. +* VerticalLayout, HorizontalLayout: improved item validation to account for justify alignment. +* AnchorLayout: better measurement when using horizontalCenter or verticalCenter values. +* ValidationQueue: items are added to the queue faster with better sorting. +* ExclusiveTouch: allows a component to claim a touch so that nested scrolling components won't be in conflict. +* Label: added ALTERNATE_NAME_HEADING for larger text and ALTERNATE_NAME_DETAIL for smaller text. +* Default item renderers: better handling of data and fields. +* Default item renderers: support for delaying texture creation on scroll in ImageLoaders. +* Default item renderers: updates isEnabled on accessory, if applicable. +* Default item renderers: accessory is cleared if itemHasAccessory is set to false. +* Default item renderers: fix for measurement when label is missing and gap isn't needed. +* DefaultGroupedListHeaderOrFooterRenderer: contentLabel maxWidth is used for proper wrapping, if needed. +* DefaultGroupedListHeaderOrFooterRenderer: added support for justify alignments. +* Many performance improvements with the help of Adobe Scout. +* All built-in components ensure that sub-components are validated. +* Examples: use drawers component where applicable. +* Examples: new DrawersExplorer example. +* Examples: new DragAndDrop example for DragDropManager. +* Themes: updated to support new properties and alternate names. +* Documentation: many properties now list default values. +* Documentation: createSubComponent() and autoSizeIfNeeded() patterns are now documented parts of the architecture. +* Fixes to better support iOS 7. +* New minimum runtime versions. Target SWF version rolled back to 18 (Flash Player 11.5 and AIR 3.5) to offer easier BlackBerry 10 support. + +### 1.2.0 Deprecated APIs + +All deprecated APIs are subject to the [Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy). Please migrate to the new APIs as soon as possible because the deprecated APIs **will** be removed in a future version of Feathers. + +The `scrollerProperties` property on scrolling components, including List, GroupedList, ScrollText and ScrollContainer is deprecated. Because these components now extend `Scroller` instead of adding a `Scroller` as a child, all of the properties that could be set through `scrollerProperties` can now be set directly on the components. The `scrollerProperties` property was deprecated in Feathers 1.1.0, and it remains deprecated in Feathers 1.2.0. + +### 1.2.0 API Changes + +Some changes have been made to Feathers that have the potential to break code in existing projects. Changes of this type are considered [exceptions to the Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy#exceptions), and careful consideration is made to limit the impact of these changes on existing projects. Most developers using Feathers will not be affected by these changes, except perhaps, to observe improved stability and consistency. + +#### PopUpManager + +Two changes have been made to the `PopUpManager`. + +The function `isTopLevelPopUp()` has been modified to indicate if a pop-up is above the top-most modal overlay. Previously, this function indicated if a pop-up is the single top-most pop-up. + +When a pop-up is centered when calling `PopUpManager.addPopUp()`, the `PopUpManager` will automatically realign the pop-up if the stage or the pop-up is resized. If you prefer that the pop-up isn't realigned, change the argument to `false` and call `PopUpManager.centerPopUp()` instead. It will align the pop-up only once. If you previously manually repositioned the pop-up to keep it centered when it or the stage resized, you may remove that code. However, if the code remains, it should not cause conflicts with the new behavior. + +#### IVirtualLayout + +Three changes have been made to the `IVirtualLayout` interface. Custom implementations of `IVirtualLayout` created before Feathers 1.2.0 will have compiler errors until the required changes are made. It is expected that a small number of Feathers developers have created custom implementations of `IVirtualLayout`, so this change will have no impact on the majority of projects that are upgraded from older versions of Feathers. + +The `typicalItemWidth` and `typicalItemHeight` properties may be removed completely from custom `IVirtualLayout` implementations. In their place, the `typicalItem` property must be added. Components like `List` previously passed pre-calculated width and height values for a typical item display object. However, a layout may need to manipulate the typical item before calculating its dimensions. By giving more control to the layouts, their estimation of virtualized items will be more accurate. + +The new `typicalItem` property might be declared as follows: + + /** + * @private + */ + protected var _typicalItem:DisplayObject; + + /** + * @inheritDoc + */ + public function get typicalItem():DisplayObject + { + return this._typicalItem; + } + + /** + * @private + */ + public function set typicalItem(value:DisplayObject):void + { + if(this._typicalItem == value) + { + return; + } + this._typicalItem = value; + this.dispatchEventWith(Event.CHANGE); + } + +Usage of the new `typicalItem` property may depend on factors that are specific to each implementation. In general, an implementation will measure the typical item at the beginning of most of its public functions, including `layout()`, `getScrollPositionForIndex()`, `getVisibleIndicesAtScrollPosition()`, and `measureViewPort()`. If the typical item is a Feathers control, it should be validated. The following snippet shows the most basic case for how to request the typical item's dimensions: + + var measuredTypicalItemWidth:Number = 0; + var measuredTypicalItemHeight:Number = 0; + if( this._useVirtualLayout && this._typicalItem ) + { + if( this._typicalItem is IFeathersControl ) + { + //validate the typical item so that it reports the correct width and height + this._typicalItem.validate(); + } + + measuredTypicalItemWidth = this._typicalItem.width; + measuredTypicalItemHeight = this._typicalItem.height; + } + +If the typical item is a Feathers control, validate() should be called before requesting its dimensions. Optionally, the dimensions of a Feathers control may be reset to `NaN` in order to ask the control for its ideal dimensions. This will match the behavior introduced Feathers 1.1.x. However, in Feathers 1.2.0, the built-in layouts have chosen to reset the typical item's dimensions only when a flag is enabled. For many layouts, resetting the dimensions of the typical item is rarely required, and it may be undesireable. This change reverts the behavior to match Feathers 1.0.x, while still allowing advanced developers to re-enable the behavior introduced in Feathers 1.1.x. + +For more advanced code, take a look at one of the built-in layout classes, such as `VerticalLayout`. + +Note: The built-in layout classes repurpose the `typicalItemWidth` and `typicalItemHeight` properties that were removed from `IVirtualLayout` to work with a new `resetTypicalItemDimensionsOnMeasure` property. By default, setting these properties outside of a component like `List` will have no effect, which exactly matches the behavior from all older versions of Feathers. Custom layouts may elect to provide this same capability, but it is not required by the `IVirtualLayout` interface. + +#### GroupedList + +The `typicalHeader` and `typicalFooter` properties have been removed from `GroupedList` to support the better handling of typical items in virtual layouts, as discussed above. From now on, the `typicalItem` on a `GroupedList` is the only way to provide hints to the layout used by a `GroupedList`. + +## 1.1.1 + +This release includes minor updates to support Starling Framework 1.4 and a number of minor bug fixes. + +* Switches to Starling's implementation of the clipRect property. +* Uses Texture onRestore for internally managed textures, like in text controls. +* StageTextTextEditor: fix for displayAsPassword clearing the text. +* Panel: won't scroll if mouse wheel or touch occurs in header or footer. +* Panel: header and footer can be touched when content is scrolling. +* AeonDesktopTheme: uses a better disabled text color. +* SmartDisplayObjectStateValueSelector: properly supports uint color value of 0. +* Item Renderers: smarter handling of accessory resizing. +* Item Renderers: better measurement to account for NaN. +* Item Renderers: properly checks for _data, in addition to _owner, in commitData(). +* Label: sets proper text renderer dimensions if height is explicitly set. +* Radio: better handling of setting toggleGroup to avoid accidentally adding to defaultRadioGroup. +* Scroller: properly updates isEnabled on scroll bars when they are first created. +* Scroller: child touches are blocked until throw animation finishes to match native behavior. +* Scroll bars: better isEnabled handling. +* TextInput: better handling of focus when not visible. +* TextInput: better prompt handling. +* TextInput: fix to allow TextFieldTextEditor to be selected on focus in. +* TextInput: added clearFocus() to allow programmatic removal of focus in NumericStepper. +* TextFieldTextEditor: snapshot is properly hidden when text is cleared. +* ButtonGroup: properly resizes when data provider changes. +* GroupedList: requests proper typical item from data provider. +* ScrollText: better padding getter. +* PickerList: closes pop-up list on Event.TRIGGERED. +* PickerList: properly disposes pop-up list and IPopUpContentManager. +* NumericStepper: if TextInput sub-component is editable, it will be selected on focus in. +* TiledRowsLayout, TiledColumnsLayout: fixed manageVisibility implementation. +* TiledRowsLayout, TiledColumnsLayout: fixed bad positioning when useSquareTiles is true. + +## 1.1.0 + +* New Beta Component: NumericStepper. Add and subtract from a numeric value with buttons. Optional text editing. +* New Beta Component: TextArea. A multiline text input. Recommended for desktop only. Not recommended for mobile. +* New Beta Component: Panel. A new container subclassing ScrollContainer that adds a header and an optional footer. +* New Beta Component: PanelScreen. An IScreen implementation (similar to Screen) based on Panel. +* New Beta Layout: AnchorLayout. Added to support fluid layouts and relative positioning. Can position relative to parent container and also to other children of the parent container. +* Added FocusManager for keyboard navigation and interaction. Not intended for mobile. Use a desktop theme or set `FocusManager.isEnabled = true`. TextInput *cannot* use StageTextTextEditor when focus management is enabled. TextFieldTextEditor is recommended. +* All Components: sub-components are created from factories and can receive custom names for theming. +* Added ILayoutObject interface to support extra data for layouts to use, like includeInLayout property. +* List: support for optional multiple selection. +* TextInput: supports prompt/hint +* TextInput/StageTextTextEditor: supports multiline on mobile. +* PickerList: supports prompt when no item is selected. +* Slider: measurement now includes thumb dimensions and a new property called trackScaleMode has been added. +* Callout: disposal is more consistent. Set combination of disposeOnSelfClose and disposeContent. +* Callout: doesn't close when origin is touched. origin should now separately determine correct behavior. +* Callout: added origin and supportedDirections properties to make Callout capable of switching origins after creation. +* Item Renderers: properly handle accessory resizing if accessory is a FeathersControl. +* Item Renderers: fixes for a number of layout order, gap, and alignment combinations. +* PickerList: doesn't close when touching scroll bar. only item renderer touch will trigger a close. +* PopUpManager: Supports custom root to place pop-ups somewhere other than the stage. +* PopUpManager: modal pop-ups receive a different focus manager. +* ScreenNavigator: added hasScreen(), getScreen(), and getScreenIDs(). +* ScreenNavigator: added autoSizeMode property to select between sizing to fit stage or to fit content. +* ScreenNavigator: fix for broken transition if showScreen() is calleed before transition begins but after new screen is added to stage. +* Transitions: fix for quickStack constructor argument. +* ScrollContainer, List, GroupedList: better auto-sizing with a background skin. +* ScrollContainer: new alternate name for toolbar style. +* TextInput: exposed isEditable, maxChars, restrict, and displayAsPassword properties. +* BitmapFontTextRenderer, Scale3Image, Scale9Image: option to turn off the use of a separate QuadBatch. +* TextFieldTextEditor: better selection on mobile. +* TextFieldTextEditor: properly dispatches FeathersEventType.ENTER. +* Text Renderers and Editors: better snapshot disposal. +* TextFieldTextRenderer: better measurement to workaround runtime dimensions being wrong. +* TiledRowsLayout, TiledColumnsLayout: supports separate horizontal and vertical gaps. +* TiledRowsLayout, TiledColumnsLayout: more stable virtualized item renderer count to improve performance. +* TiledRowsLayout, TiledColumnsLayout: fixes for certain issues with paging. +* ButtonGroup: supports isEnabled as a property in the data provider. +* ImageLoader: added delayTextureCreation flag to avoid creating textures while scrolling (or during any action that requires best performance). +* Scroller: adds an invisible overlay during scrolling to block touch events on children. +* Scroller: exposes horizontal and vertical page count properties. +* Scroller: added FeathersEventType.SCROLL_START event. +* Scroller: scroll bars are hidden when stopScrolling() is called. +* Scroller: fix for velocity calculation. +* Button: better detection of click to avoid other display objects moving on top of button before TouchPhase.ENDED. +* Button: new styles for themes, including back, forward, call-to-action, quiet, and danger. +* List: if items are added or removed, selected indices are adjusted. +* List, GroupedList, ScrollContainer, and ScrollText all extend Scroller, instead of using it as a sub-component. The scrollerProperties property on each of these is now deprecated because all public properties of Scroller are now direct public properties of these components. Theme initializers that target Scroller will break because Scroller is no longer a sub-component, but a super class of classes like List. Move this stuff into initializers for List, GroupedList, ScrollContainer, and ScrollText. +* FeathersControl: setSizeInternal() is now stricter. It can never receive a NaN value for width or height. This is a common source of bugs, and throwing an error here will help make it easier to find those bugs. +* IVariableVirtualLayout: added function addToVariableVirtualCacheAtIndex() for more specific control over the cache of item dimensions. +* IVariableVirtualLayout: added function removeFromVariableVirtualCacheAtIndex() for more specific control over the cache of item dimensions. +* ScrollText: now properly handles visible and alpha properties. +* ListCollection: added removeAll(), addAll(), addAllAt() and contains(). +* Scroller: scrolling animates for mouse wheel. +* List, VerticalLayout, HorizontalLayout: optimized case where useVirtualLayout is true and hasVariableItemDimensions is false. +* HorizontalLayout, VerticalLayout, TiledRowsLayout, TiledColumnsLayout: added manageVisibility property to set items to false when not in view. Set to true to improve performance. +* Item Renderers: added stopScrollingOnAccessoryTouch property to make accessory touch behavior configurable. +* Screen: default value of originalDPI is DeviceCapabilities.dpi. It used to be 168. Can still be changed. +* MetalWorksMobileTheme and MinimalMobileTheme: major overhaul with improved skins and new alternate skins. +* AeonDesktopTheme: added some missing skins, like TabBar. +* AeonDesktopTheme: uses FocusManager. +* AzureMobileTheme: removed this example theme. Please feel free to continue using the old version, if desired. +* ComponentsExplorer: better button screen to show off various styles of buttons. +* Todos: new example. +* All Examples: Use PanelScreen instead of Screen and Header where appropriate. +* All Examples: Use AnchorLayout where appropriate. +* All Examples: Uses NumericStepper instead of Slider where appropriate. +* Added 96x96 icons to examples for Android xhdpi. Requires AIR 3.7. +* Extended API documentation with inline examples and improved descriptions. +* Added many new articles to the Feathers Manual. +* Now built with ASC 2.0. + +### 1.1.0 Deprecated APIs + +All deprecated APIs are subject to the [Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy). Please migrate to the new APIs as soon as possible because the deprecated APIs **will** be removed in a future version of Feathers. + +The `scrollerProperties` property on scrolling components, including List, GroupedList, ScrollText and ScrollContainer is deprecated. Because these components now extend `Scroller` instead of adding a `Scroller` as a child, all of the properties that could be set through `scrollerProperties` can now be set directly on the components. + +### 1.1.0 API Changes + +Some changes have been made to Feathers that have the potential to break code in existing projects. Changes of this type are considered [exceptions to the Feathers deprecation policy](http://wiki.starling-framework.org/feathers/deprecation-policy#exceptions), and careful consideration is made to limit the impact of these changes on existing projects. Most developers using Feathers will not be affected by these changes, except perhaps, to observe improved stability and consistency. + +#### IVariableVirtualLayout + +Two changes have been made to the `IVariableVirtualLayout` interface. Custom implementations of `IVariableVirtualLayout` created before Feathers 1.1.0 will have compiler errors until the required changes are made. It is expected that a very small number of Feathers developers have created custom implementations of `IVariableVirtualLayout`, so this change will have no impact on the vast majority of projects that are upgraded from older versions of Feathers. + +The functions `addToVariableVirtualCacheAtIndex()` and `removeFromVariableVirtualCacheAtIndex()` have been added to `IVariableVirtualLayout` to provide lower-level control over the cache of item dimensions. Instead of clearing the entire cache, a component may insert or remove a specific index from the cache. For instance, the `List` component uses these functions when its data provider is manipulated. These functions allow the layout to provide more accuracy to its virtualization and to improve performance. + + These two functions can easily simulate the old behavior from Feathers 1.0.x, if required. The following implementations of `addToVariableVirtualCacheAtIndex()` and `removeFromVariableVirtualCacheAtIndex()` can easily be copied into a custom implementations of `IVariableVirtualLayout` to quickly migrate existing Feathers 1.0.x implementations to behave exactly the same in Feathers 1.1.0: + + public function addToVariableVirtualCacheAtIndex(index:int, item:DisplayObject = null):void + { + this.resetVariableVirtualCache(); + } + + public function removeFromVariableVirtualCacheAtIndex(index:int, item:DisplayObject = null):void + { + this.resetVariableVirtualCache(); + } + +## 1.0.1 + +This release includes a number of bug fixes. + +* Scroller: FeathersEventType.SCROLL_COMPLETE always dispatched after last Event.SCROLL. +* ScrollBar, SimpleScrollBar: thumb position properly accounts for padding. +* Scroller: mouse wheel detection properly accounts for contentScaleFactor. +* ScreenNavigator: calling clearScreen() during a transition no longer causes a stack overflow. +* ScrollBar, SimpleScrollBar: can drag to minimum and maximum if they aren't a multiple of the step. +* Header: Fix for runtime error when rightItems aren't IFeathersDisplayObjects +* TextInput: better selection/cursor recovery when changing text programmatically. +* TextInput: Moved fontSize contentScaleFactor multiplication into StageTextTextEditor. +* FeathersControl: requires isInitialized to be true before it can validate. +* FeathersControl: clipRect properly accounts for scale. +* GroupedList: added missing documentation for setSelectedLocation(). +* ImageLoader: does a better job keeping aspect ratio when only one dimension is explicit. +* ImageLoader: properly scales content when dimensions are explicit. +* ImageLoader: no runtime errors if content loads after dispose. +* ScrollContainer, List, GroupedList, ScrollText: fix for detecting changes in scrollToPageIndex(). + +## 1.0.0 + +No major API changes since 1.0.0 BETA. Mostly bug fixes and minor improvements. + +* Fix for memory leaks in List, GroupedList, and ImageLoader +* PageIndicator properly handles ImageLoader or other IFeathersControl as symbol +* IGroupedListHeaderOrFooterRenderer extends IFeathersControl +* Header: fix for "middle" vertical alignment +* Updated for Starling Framework 1.3 + +## 1.0.0 BETA + +Initial release. The following major changes happened in the last month or two leading to the beta. + +* GTween library removed as a dependency. All animations switched to the Starling `Tween` class. +* as3-signals library removed as a dependency. Switched to Starling events. +* `TextInput`: supports swappable text editors, similar to the text renderers used for uneditable text. The default `StageTextTextEditor` uses `StageText` to allow text input, which is ideal for mobile. The `TextFieldTextEditor` uses a `TextField` of `TextFieldType.INPUT` instead, and it may be a better choice for desktop. A static function, `defaultTextEditorFactory`, has been added to `FeathersControl`. +* `TextInput`: now has events for focus in and out. +* Item renderers: Switched to `ImageLoader` for icon and accessory textures, which has a `source` property that supports `Texture` instances or `String` URLs to load textures from the web. Properties like `iconTextureField` and `accessoryTextureFunction` now have new names like `iconSourceField` and `accessorySourceFunction` because values other than textures are now allowed. Similarly, `iconImageFactory` and `accessoryImageFactory` have been renamed to `iconLoaderFactory` and `accessoryLoaderFactory`. +* Item renderers: accessory may be positioned. See `layoutOrder` and `accessoryPosition` properties. +* Added `dispose()` method to `AddedWatcher` so that theme resources like textures be disposed. +* Added `ScrollText` component to display text in an overlay on the native display list. Useful for long passages of text that may be too large to convert to a texture. +* `ScreenNavigator`: added events for transition start and complete. +* `ToggleSwitch`: `TRACK_LAYOUT_MODE_STRETCH` is now `TRACK_LAYOUT_MODE_ON_OFF`. +* `Slider`: `TRACK_LAYOUT_MODE_STRETCH` is now `TRACK_LAYOUT_MODE_MIN_MAX`. +* `ScrollBar`: `TRACK_LAYOUT_MODE_STRETCH` is now `TRACK_LAYOUT_MODE_MIN_MAX`. diff --git a/build.properties b/build.properties index 7b8efab63d..b770ee63d3 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,23 @@ starling.root = ${basedir}/third-party/starling -signals.root = ${basedir}/third-party/signals -gtween.root = ${basedir}/third-party/gtween +source.root = ${basedir}/source +examples.root = ${basedir}/examples +themes.root = ${basedir}/themes +api.root = ${basedir}/documentation/api-reference +help.root = ${basedir}/documentation/help + output.path = ${basedir}/output dependency.output = ${output.path}/dependencies -swc.output = ${output.path}/foxhole-starling.swc -docs.output = ${output.path}/documentation \ No newline at end of file +swc.output = ${output.path}/swc +help.output = ${output.path}/help +api.output = ${output.path}/api-reference +source.output = ${output.path}/source +examples.output = ${output.path}/examples +themes.output = ${output.path}/themes + +swf.version = 18 + +mxml.namespace = library://ns.feathersui.com/mxml + +feathers.version = 2.1 Prerelease + +footer.text = Feathers Website | Feathers Documentation | Github Project | Support Forum \ No newline at end of file diff --git a/build.xml b/build.xml index 47af0fe1cc..f281515b54 100644 --- a/build.xml +++ b/build.xml @@ -1,5 +1,5 @@ - + @@ -8,58 +8,392 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + + - - - - - - - - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/api-reference/templates/AC_OETags.js b/documentation/api-reference/templates/AC_OETags.js new file mode 100644 index 0000000000..17fc479c9b --- /dev/null +++ b/documentation/api-reference/templates/AC_OETags.js @@ -0,0 +1,129 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + + +//v1.0 +function AC_AddExtension(src, ext) +{ + if (src.indexOf('?') != -1) + return src.replace(/\?/, ext+'?'); + else + return src + ext; +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ' '; + str += ' + + + + + + + + + + toplevel.xml + API Documentation + API Documentation + + +
+ + AS3 + mx_internal + flash_proxy + object_proxy + mx_inner + flash10 + + + +
\ No newline at end of file diff --git a/documentation/api-reference/templates/ASDoc_terms.xml b/documentation/api-reference/templates/ASDoc_terms.xml new file mode 100644 index 0000000000..769bc7412d --- /dev/null +++ b/documentation/api-reference/templates/ASDoc_terms.xml @@ -0,0 +1,4210 @@ + + + + Localizable Terms + + + Localizable Terms + + + + + + + + +

Key (or Paragraph tag)

+
+ +

Value

+
+ +

Comment

+
+
+ + + + +

AS1tooltip

+
+ +

Tooltip for AS1 compatible examples

+
+ + +

Tooltip for AS1 compatible examples

+
+
+
+ + +

AS2tooltip

+
+ +

This example requires ActionScript 2.0

+
+ + +

Tooltip for AS2 compatible examples

+
+
+
+ + +

AS3tooltip

+
+ +

This example requires ActionScript 3.0

+
+ + +

Tooltip for AS3 compatible examples

+
+
+
+ + +

Type

+
+ +

Type

+
+ + +

Type

+
+
+
+ + +

Format

+
+ +

Format

+
+ + +

Format

+
+
+
+ + +

CSSInheritance

+
+ +

CSS Inheritance

+
+ + +

CSS Inheritance

+
+
+
+ + +

Properties

+
+ +

Properties

+
+ + +

Header for properties

+
+
+
+ + +

Property

+
+ +

property

+
+ + +

Text for property

+
+
+
+ + +

PropertyProperty

+
+ +

Property

+
+ + +

Text for property

+
+
+
+ + +

PropertyDetail

+
+ +

Property Detail

+
+ + +

Text for property

+
+
+
+ + +

Constructor

+
+ +

Constructor

+
+ + +

Header for constructor

+
+
+
+ + +

ConstructorDetail

+
+ +

Constructor Detail

+
+ + +

Header for constructor

+
+
+
+ + +

MethodDetail

+
+ +

Method Detail

+
+ + +

MethodDetail

+
+
+
+ + +

Methods

+
+ +

Methods

+
+ + +

Header for methods

+
+
+
+ + +

MethodMethod

+
+ +

Method

+
+ + +

text for method

+
+
+
+ + +

Method

+
+ +

method

+
+ + +

text for method

+
+
+
+ + +

Functions

+
+ +

Functions

+
+ + +

Header for functions

+
+
+
+ + +

FunctionFunction

+
+ +

Function

+
+ + +

text for function

+
+
+
+ + +

Function

+
+ +

function

+
+ + +

text for function

+
+
+
+ + +

Events

+
+ +

Events

+
+ + +

Header for events

+
+
+
+ + +

Event

+
+ +

Event

+
+ + +

text for event

+
+
+
+ + +

Styles

+
+ +

Styles

+
+ + +

Header for styles

+
+
+
+ + +

Style

+
+ +

Style

+
+ + +

text for style

+
+
+
+ + +

Effects

+
+ +

Effects

+
+ + +

Header for effects

+
+
+
+ + +

Effect

+
+ +

Effect

+
+ + +

text for effect

+
+
+
+ + +

Constants

+
+ +

Constants

+
+ + +

Header for constants

+
+
+
+ + +

Constant

+
+ +

Constant

+
+ + +

text for constant

+
+
+
+ + +

ConstantDetail

+
+ +

Constant Detail

+
+ + +

text for constant detail

+
+
+
+ + +

Interfaces

+
+ +

Interfaces

+
+ + +

Header for interfaces

+
+
+
+ + +

Interface

+
+ +

Interface

+
+ + +

text for interface

+
+
+
+ + +

Classes

+
+ +

Classes

+
+ + +

Header for classes

+
+
+
+ + +

ClassClass

+
+ +

Class

+
+ + +

*NAME* class

+
+
+
+ + +

Use

+
+ +

Use

+
+ + +

Header for use

+
+
+
+ + +

Usage

+
+ +

Usage

+
+ + +

Header for usage

+
+
+
+ + +

Example

+
+ +

Example

+
+ + +

Header for examples

+
+
+
+ + +

Examples

+
+ +

Examples

+
+ + +

Header for examples

+
+
+
+ + +

ViewExamples

+
+ +

View the examples

+
+ + +

View the examples

+
+
+
+ + +

searchLivedocs

+
+ +

Search

+
+ + +

Text for Search LiveDocs links

+
+
+
+ + +

allPackages

+
+ +

All Packages

+
+ + +

Text for All Packages links

+
+
+
+ + +

allMXPackages

+
+ +

All MX Packages

+
+ + +

Text for All MX Packages links

+
+
+
+ + +

allFlashPlayerPackages

+
+ +

All Flash Packages

+
+ + +

Text for All Flash Packages links

+
+
+
+ + +

allClasses

+
+ +

All Classes

+
+ + +

Text for All Classes links

+
+
+
+ + +

allMXClasses

+
+ +

All MX Classes

+
+ + +

Text for All MX Classes links

+
+
+
+ + +

allFlashClasses

+
+ +

All Flash Classes

+
+ + +

Text for All Flash Classes links

+
+
+
+ + +

LanguageElements

+
+ +

Language Elements

+
+ + +

Text for Language Elements links

+
+
+
+ + +

LanguageElement

+
+ +

Language Element

+
+ + +

Text for Language Element table header

+
+
+
+ + +

Index

+
+ +

Index

+
+ + +

Text for Index links

+
+
+
+ + +

deprecated_index

+
+ +

deprecated_index

+
+ + +

Text for deprecated_index

+
+
+
+ + +

Appendix

+
+ +

Appendixes

+
+ + +

Text for Appendixes links

+
+
+
+ + +

Description

+
+ +

Description

+
+ + +

Text for Appendixes links

+
+
+
+ + +

Conventions

+
+ +

Conventions

+
+ + +

Text for Conventions links

+
+
+
+ + +

Frames

+
+ +

Frames

+
+ + +

Text for link to frames version of help

+
+
+
+ + +

NoFrames

+
+ +

No Frames

+
+ + +

Text for link to no frames version of help

+
+
+
+ + +

MXMLOnly

+
+ +

MXML Only Components

+
+ + +

Text for link to MXML Only Components

+
+
+
+ + +

MXML Only Components

+
+ +

MXML Only Components

+
+ + +

Text for link to MXML Only Components

+
+
+
+ + +

SQLSupportInLocalDatabases

+
+ +

SQL support in local databases

+
+ + +

Text for SQL support in local databases

+
+
+
+ + +

SQL support in local databases

+
+ +

SQL support in local databases

+
+ + +

Text for SQL support in local databases

+
+
+
+ + +

MXMLSyntax

+
+ +

MXML Syntax

+
+ + +

Text for MXML Syntax

+
+
+
+ + +

ShowMXMLSyntax

+
+ +

Show MXML Syntax

+
+ + +

Text for Show MXML Syntax

+
+
+
+ + +

HideMXMLSyntax

+
+ +

Hide MXML Syntax

+
+ + +

Text for Hide MXML Syntax

+
+
+
+ + +

PlayerVersion

+
+ +

Player Version

+
+ + +

Text for player version label

+
+
+
+ + +

oldPlayerVersion

+
+ +

Runtime Versions

+
+ + +

Text for player version label

+
+
+
+ + +

LanguageVersion

+
+ +

Language Version

+
+ + +

Text for language version label

+
+
+
+ + +

andLater

+
+ +

??

+
+ + +

Suffix for "ActionScript N and later"

+
+
+
+ + +

seeAlso

+
+ +

See also

+
+ + +

See also header

+
+
+
+ + +

All

+
+ +

All

+
+ + +

Text for all index

+
+
+
+ + +

Unsupported

+
+ +

Unsupported

+
+ + +

Text for Unsupported

+
+
+
+ + +

TopLevel

+
+ +

Top Level

+
+ + +

Text for Top Level link

+
+
+
+ + +

fscommand2

+
+ +

<a href="global_functions.html#fscommand2()">fscommand2</a>fscommand2

+
+ + +

Text for fscommand2 link

+
+
+
+ + +

Operator

+
+ +

Operator

+
+ + +

Text for Operator link

+
+
+
+ + +

Operators

+
+ +

Operators

+
+ + +

Text for Operator link

+
+
+
+ + +

Statement

+
+ +

Statement

+
+ + +

Text for Statement link

+
+
+
+ + +

statement

+
+ +

Statement

+
+ + +

Text for statement type in statements.xsl

+
+
+
+ + +

Statements

+
+ +

Statements

+
+ + +

Text for Statement link

+
+
+
+ + +

SpecialType

+
+ +

Special Type

+
+ + +

Text for Special Type link

+
+
+
+ + +

SpecialTypes

+
+ +

Special Types

+
+ + +

Special Types

+
+
+
+ + +

SpecialTypeDetail

+
+ +

Special Type Detail

+
+ + +

Special Type Detail

+
+
+
+ + +

DeprecatedText

+
+ +

Deprecated Text

+
+ + +

Text for Deprecated classes

+
+
+
+ + +

DeprecatedClassesHeader

+
+ +

Deprecated Classes

+
+ + +

Header for Deprecated classes

+
+
+
+ + +

DeprecatedFunctionHeader

+
+ +

Deprecated Function

+
+ + +

Header for Deprecated Functions

+
+
+
+ + +

DeprecatedMethodHeader

+
+ +

Deprecated Methods

+
+ + +

Header for Deprecated Methods

+
+
+
+ + +

DeprecatedPropertiesHeader

+
+ +

Deprecated Properties

+
+ + +

Header for Deprecated Properties

+
+
+
+ + +

DeprecatedStylesHeader

+
+ +

Deprecated Styles

+
+ + +

Header for Deprecated Styles

+
+
+
+ + +

DeprecatedOperatorsHeader

+
+ +

Deprecated Operators

+
+ + +

Header for Deprecated Operators

+
+
+
+ + +

DeprecatedAsOf

+
+ +

Deprecated

+
+ + +

Text for Deprecated classes with a version

+
+
+
+ + +

DeprecatedIn

+
+ +

Deprecated

+
+ + +

Text for Deprecated classes with a version

+
+
+
+ + +

StaticMethodIn

+
+ +

Static Method

+
+ + +

Text for Static method

+
+
+
+ + +

MethodIn

+
+ +

Method

+
+ + +

Text for method

+
+
+
+ + +

PackageStaticFunctionIn

+
+ +

Package Static Function

+
+ + +

Text for static function in package

+
+
+
+ + +

PackageFunctionIn

+
+ +

Package Function

+
+ + +

Text for function in package

+
+
+
+ + +

CompilerDirective

+
+ +

Compiler Directive

+
+ + +

Text for Compiler Directive

+
+
+
+ + +

CompilerDirectives

+
+ +

Compiler Directives

+
+ + +

Text for Compiler Directives

+
+
+
+ + +

Protected

+
+ +

Protected

+
+ + +

Text for Protected

+
+
+
+ + +

Public

+
+ +

Public

+
+ + +

Text for Public

+
+
+
+ + +

Global

+
+ +

Global

+
+ + +

Text for Global

+
+
+
+ + +

GlobalFunction

+
+ +

Global Function

+
+ + +

Text for GlobalFunction

+
+
+
+ + +

GlobalFunctions

+
+ +

Global Functions

+
+ + +

Text for GlobalFunction

+
+
+
+ + +

GlobalProperties

+
+ +

Global Properties

+
+ + +

Text for Global Properties

+
+
+
+ + +

ConstructorInClass

+
+ +

Constructor

+
+ + +

Text for constructor in class

+
+
+
+ + +

ConstantStaticPropertyIn

+
+ +

Constant Static Property

+
+ + +

Text for constant static property in class

+
+
+
+ + +

StaticPropertyIn

+
+ +

Static Property

+
+ + +

Text for static property in class

+
+
+
+ + +

PropertyIn

+
+ +

Property

+
+ + +

Property in class

+
+
+
+ + +

ConstantPropertyIn

+
+ +

Constant Property

+
+ + +

Constant property in class

+
+
+
+ + +

PackageConstantStaticPropertyIn

+
+ +

Package Constant Static Property

+
+ + +

Package constant static property in class

+
+
+
+ + +

PackageConstantPropertyIn

+
+ +

Package Constant Property

+
+ + +

Package static property in class

+
+
+
+ + +

ConstantProperty

+
+ +

Constant Property

+
+ + +

constant property

+
+
+
+ + +

GlobalProperty

+
+ +

Global property

+
+ + +

Global property

+
+
+
+ + +

EventHandlerIn

+
+ +

Event handler

+
+ + +

Event handler in

+
+
+
+ + +

EventListenerIn

+
+ +

Event Listener

+
+ + +

Event Listener in

+
+
+
+ + +

EventIn

+
+ +

Event

+
+ + +

Event in

+
+
+
+ + +

GlobalEventHandler

+
+ +

Global event handler

+
+ + +

Global event handler

+
+
+
+ + +

GlobalEventListener

+
+ +

Global event listener

+
+ + +

Global event listener

+
+
+
+ + +

FinalDynamicClass

+
+ +

final dynamic class

+
+ + +

Final dynamic class

+
+
+
+ + +

FinalClass

+
+ +

final class

+
+ + +

Final class

+
+
+
+ + +

DynamicClass

+
+ +

dynamic class

+
+ + +

dynamic class

+
+
+
+ + +

InterfaceIn

+
+ +

interface

+
+ + +

interface

+
+
+
+ + +

ClassIn

+
+ +

class

+
+ + +

class

+
+
+
+ + +

FinalDynamicClassIn

+
+ +

final dynamic class

+
+ + +

final dynamic class

+
+
+
+ + +

FinalDynamicClassIn

+
+ +

final dynamic class

+
+ + +

final dynamic class

+
+
+
+ + +

FinalClassIn

+
+ +

Final Class

+
+ + +

final class

+
+
+
+ + +

DynamicClassIn

+
+ +

Dynamic Class

+
+ + +

dynamic class

+
+
+
+ + +

Package

+
+ +

package

+
+ + +

package

+
+
+
+ + +

PackagePackage

+
+ +

Package

+
+ + +

*NAME* package

+
+
+
+ + +

Packages

+
+ +

Packages

+
+ + +

package

+
+
+
+ + +

InnerClassSummary

+
+ +

Inner Class summary

+
+ + +

Inner Class summary

+
+
+
+ + +

HideInheritedPublicConstants

+
+ +

Hide Inherited Public Constants

+
+ + +

Text for Hide Inherited Public Constants

+
+
+
+ + +

ShowInheritedPublicConstants

+
+ +

Show Inherited Public Constants

+
+ + +

Text for Show Inherited Public Constants

+
+
+
+ + +

HideInheritedProtectedConstants

+
+ +

Hide Inherited Protected Constants

+
+ + +

Text for Hide Inherited Protected Constants

+
+
+
+ + +

ShowInheritedProtectedConstants

+
+ +

Show Inherited Protected Constants

+
+ + +

Text for Show Inherited Protected Constants

+
+
+
+ + +

HideInheritedPublicProperties

+
+ +

Hide Inherited Public Properties

+
+ + +

Text for Hide Inherited Public Properties

+
+
+
+ + +

ShowInheritedPublicProperties

+
+ +

Show Inherited Public Properties

+
+ + +

Text for Show Inherited Public Properties

+
+
+
+ + +

HideInheritedPublicMethods

+
+ +

Hide Inherited Public Methods

+
+ + +

Text for Hide Inherited Public Methods

+
+
+
+ + +

ShowInheritedPublicMethods

+
+ +

Show Inherited Public Methods

+
+ + +

Text for Show Inherited Public Methods

+
+
+
+ + +

HideInheritedProtectedMethods

+
+ +

Hide Inherited Protected Methods

+
+ + +

Text for Hide Inherited Protected Methods

+
+
+
+ + +

ShowInheritedProtectedMethods

+
+ +

Show Inherited Protected Methods

+
+ + +

Text for Show Inherited Protected Methods

+
+
+
+ + +

HideInheritedProtectedProperties

+
+ +

Hide Inherited Protected Properties

+
+ + +

Text for Hide Inherited Protected Properties

+
+
+
+ + +

ShowInheritedProtectedProperties

+
+ +

Show Inherited Protected Properties

+
+ + +

Text for Show Inherited Protected Properties

+
+
+
+ + +

HideInheritedEffects

+
+ +

Hide Inherited Effects

+
+ + +

Text for Hide Inherited Effects

+
+
+
+ + +

ShowInheritedEffects

+
+ +

Show Inherited Effects

+
+ + +

Text for Show Inherited Effects

+
+
+
+ + +

HideInheritedEvents

+
+ +

Hide Inherited Events

+
+ + +

Text for Hide Inherited Events

+
+
+
+ + +

ShowInheritedEvents

+
+ +

Show Inherited Events

+
+ + +

Text for Show Inherited Events

+
+
+
+ + +

TriggeringEvent

+
+ +

Triggering Event

+
+ + +

Text for TriggeringEvent

+
+
+
+ + +

DefaultValueIs

+
+ +

The default value is

+
+ + +

Text for The default value is

+
+
+
+ + +

Style_States_2

+
+ +

You can use the skin style to assign the skin for the following skin states:

+
+ + +

Text for The default value is

+
+
+
+ + +

DataBinding

+
+ +

This property can be used as the source for data binding.

+
+ + +

Text for This property can be used as the source for data binding.

+
+
+
+ + +

Implementation

+
+ +

Implementation

+
+ + +

Text for Implementation

+
+
+
+ + +

HideInheritedStyles

+
+ +

Hide Inherited Styles

+
+ + +

Text for Hide Inherited Styles

+
+
+
+ + +

ShowInheritedStyles

+
+ +

Show Inherited Styles

+
+ + +

Text for Show Inherited Styles

+
+
+
+ + +

InheritedFrom

+
+ +

Inherited From

+
+ + +

Text for inherited from class

+
+
+
+ + +

DefaultMXMLProperty

+
+ +

Default MXML Property

+
+ + +

Text for Default MXML Property

+
+
+
+ + +

Inheritance

+
+ +

Inheritance

+
+ + +

Text for Inheritance

+
+
+
+ + +

Implementors

+
+ +

Implementors

+
+ + +

Text for Implementors

+
+
+
+ + +

CompilerErrors

+
+ +

Compiler Errors

+
+ + +

Text for Compiler Errors

+
+
+
+ + +

CompilerWarnings

+
+ +

Compiler Warnings

+
+ + +

Text for Compiler Warnings

+
+
+
+ + +

RunTimeErrors

+
+ +

Runtime Errors

+
+ + +

Text for Runtime Errors

+
+
+
+ + +

CharacterSetCodes

+
+ +

Character Set Codes

+
+ + +

Text for Character Set Codes

+
+
+
+ + +

MotionXMLElements

+
+ +

Motion XML Elements

+
+ + +

Text for Motion XML Elements

+
+
+
+ + +

Timed Text XML Formats

+
+ +

Timed Text XML Formats

+
+ + +

Text for Timed Text XML Formats

+
+
+
+ + +

ExampleInstruct

+
+ +

Using examples in the ActionScript 3.0 Language Reference

+
+ + +

Text for Example Instruct

+
+
+
+ + +

Using examples in the ActionScript 3.0 Language and Components Reference

+
+ +

Using examples in the ActionScript 3.0 Language and Components Reference

+
+ + +

Text for Using examples in the ActionScript 3.0 Language and Components Reference

+
+
+
+ + +

ActionScript2Migration

+
+ +

ActionScript 2.0 Migration

+
+ + +

Text for ActionScript 2.0 Migration

+
+
+
+ + +

StatementsKeywordsDirectives

+
+ +

Statements, Keywords & Directives

+
+ + +

Statements, Keywords & Directives

+
+
+
+ + +

StatementsKeywordsDirectiveDetail

+
+ +

Statements, Keywords & Directive detail

+
+ + +

Statements, Keywords & Directives

+
+
+
+ + +

StatementsKeywords

+
+ +

Statements and Keywords

+
+ + +

Statements and Keywords

+
+
+
+ + +

FunctionsMethods

+
+ +

Functions and Methods

+
+ + +

Functions and Methods

+
+
+
+ + +

Symbols

+
+ +

Symbols

+
+ + +

Text for symbols (index letter list)

+
+
+
+ + +

Code

+
+ +

Code

+
+ + +

Code

+
+
+
+ + +

Message

+
+ +

Message

+
+ + +

Message

+
+
+
+ + +

InvalidActionScriptNote

+
+ +

* Note: This error indicates that the ActionScript in the SWF is invalid. If you believe that the file has not been corrupted, please report the problem to Adobe.

+
+ + +

* Note: This error indicates that the ActionScript in the SWF is invalid. If you believe that the file has not been corrupted, please report the problem to Adobe.

+
+
+
+ + +

Comments

+
+ +

Comments

+
+ + +

Comments

+
+
+
+ + +

OperatorDetail

+
+ +

Operator Detail

+
+ + +

OperatorDetail

+
+
+
+ + +

EventDetail

+
+ +

Event Detail

+
+ + +

Event Detail

+
+
+
+ + +

EventObjectType

+
+ +

Event Object Type

+
+ + +

Event Object Type

+
+
+
+ + +

Result

+
+ +

Result

+
+ + +

Result

+
+
+
+ + +

Operands

+
+ +

Operands

+
+ + +

Operands

+
+
+
+ + +

Parameters

+
+ +

Parameters

+
+ + +

Parameters

+
+
+
+ + +

TopLevelConstantsFunctions

+
+ +

Top Level Constants and Functions

+
+ + +

Top Level Constants and Functions

+
+
+
+ + +

Details

+
+ +

Details

+
+ + +

Details

+
+
+
+ + +

Summary

+
+ +

Summary

+
+ + +

Summary

+
+
+
+ + +

PackageList

+
+ +

Package List

+
+ + +

PackageList

+
+
+
+ + +

DefinedBy

+
+ +

Defined By

+
+ + +

PackageList

+
+
+
+ + +

Throws

+
+ +

Throws

+
+ + +

Throws

+
+
+
+ + +

Returns

+
+ +

Returns

+
+ + +

Returns

+
+
+
+ + +

StaticTypeDefinedInClass

+
+ +

Static Type Defined In Class

+
+ + +

Returns

+
+
+
+ + +

definition keyword

+
+ +

Definition keyword

+
+ + +

definition keyword

+
+
+
+ + +

primary expression keyword

+
+ +

Primary expression keyword

+
+ + +

primary expression keyword

+
+
+
+ + +

directive

+
+ +

Directive

+
+ + +

directive

+
+
+
+ + +

attribute keyword

+
+ +

Attribute Keyword

+
+ + +

Attribute Keyword

+
+
+
+ + +

namespace

+
+ +

Namespace

+
+ + +

namespace

+
+
+
+ + +

comment

+
+ +

Comment

+
+ + +

comment

+
+
+
+ + +

arithmetic

+
+ +

Arithmetic

+
+ + +

arithmetic

+
+
+
+ + +

string

+
+ +

String

+
+ + +

string

+
+
+
+ + +

assignment

+
+ +

Assignment

+
+ + +

assignment

+
+
+
+ + +

arithmetic compound assignment

+
+ +

Arithmetic compound assignment

+
+ + +

arithmetic compound assignment

+
+
+
+ + +

bitwise compound assignment

+
+ +

Bitwise compound assignment

+
+ + +

bitwise compound assignment

+
+
+
+ + +

bitwise

+
+ +

Bitwise

+
+ + +

bitwise

+
+
+
+ + +

comparison

+
+ +

Comparison

+
+ + +

comparison

+
+
+
+ + +

logical

+
+ +

Logical

+
+ + +

logical

+
+
+
+ + +

XML

+
+ +

XML

+
+ + +

XML

+
+
+
+ + +

other

+
+ +

Other

+
+ + +

other

+
+
+
+ + +

Supported Character Sets

+
+ +

Supported Character Sets

+
+ + +

Supported Character Sets

+
+
+
+ + +

Binding

+
+ +

Binding

+
+ + +

Binding

+
+
+
+ + +

Component

+
+ +

Component

+
+ + +

Component

+
+
+
+ + +

Metadata

+
+ +

Metadata

+
+ + +

Metadata

+
+
+
+ + +

Model

+
+ +

Model

+
+ + +

Model

+
+
+
+ + +

Script

+
+ +

Script

+
+ + +

Script

+
+
+
+ + +

XMLList

+
+ +

XMLList

+
+ + +

XMLList

+
+
+
+ + +

UseExamples

+
+ +

How to use examples

+
+ + +

Link for example blocks to example use instructions.

+
+
+
+ + +

FPH_Book_Title

+
+ +

ActionScript 3.0 Language and Components Reference

+
+ + +

ActionScript 3.0 Language and Components Reference

+
+
+
+ + +

FPH_Book_Directory

+
+ +

ActionScriptLangRefV3

+
+ + +

ActionScriptLangRefV3

+
+
+
+ + +

FPH_Book_Categories

+
+ +

languagereferences,as3,components3

+
+ + +

languagereferences,as3,components3

+
+
+
+ + +

FPH_Book_Language

+
+ +

en

+
+ + +

en

+
+
+
+ + +

FPH_Book_Version

+
+ +

3.0

+
+ + +

3.0

+
+
+
+ + +

FPH_Book_Sort

+
+ +

mm_3

+
+ + +

mm_3

+
+
+
+ + +

FPH_Lang_Elements_Name

+
+ +

Language Elements

+
+ + +

Language Elements

+
+
+
+ + +

FPH_All_Classes

+
+ +

All Classes

+
+ + +

All Classes

+
+
+
+ + +

FPH_All_Packages

+
+ +

All Packages

+
+ + +

All Packages

+
+
+
+ + +

FPH_Top_Level_Classes

+
+ +

Top Level classes

+
+ + +

Top Level classes

+
+
+
+ + +

FPH_Appendixes_Name

+
+ +

Appendixes

+
+ + +

Appendixes

+
+
+
+ + +

FPH_Appendixes_Tip_Text

+
+ +

Link to list of Appendixes

+
+ + +

Link to list of Appendixes

+
+
+
+ + +

FPH_Conventions_Name

+
+ +

Conventions

+
+ + +

Conventions

+
+
+
+ + +

FPH_Conventions_Tip_Text

+
+ +

Link to list of Conventions

+
+ + +

Link to list of Conventions

+
+
+
+ + +

FPH_Index_Name

+
+ +

Index

+
+ + +

Index

+
+
+
+ + +

FPH_Index_Tip_Text

+
+ +

Index of all classes, methods, properties and language elements

+
+ + +

Index of all classes, methods, properties and language elements

+
+
+
+ + +

FPH_Interface

+
+ +

interface

+
+ + +

interface

+
+
+
+ + +

FPH_Class

+
+ +

class

+
+ + +

class

+
+
+
+ + +

FPH_Constructor

+
+ +

Constructor

+
+ + +

Constructor

+
+
+
+ + +

FPH_Methods

+
+ +

Methods

+
+ + +

Methods

+
+
+
+ + +

FPH_Properties

+
+ +

Properties

+
+ + +

Properties

+
+
+
+ + +

FPH_Events

+
+ +

Events

+
+ + +

Events

+
+
+
+ + +

FPH_Operators

+
+ +

Operators

+
+ + +

Operators

+
+
+
+ + +

FPH_StatementsKeywordsDirectives

+
+ +

Statements, Keywords and Directives

+
+ + +

Statements, Keywords and Directives

+
+
+
+ + +

FPH_Special_Types

+
+ +

Special Types

+
+ + +

Special Types

+
+
+
+ + +

FPH_Styles

+
+ +

Styles

+
+ + +

Styles

+
+
+
+ + +

FPH_Global

+
+ +

Global

+
+ + +

Global

+
+
+
+ + +

FPH_Functions

+
+ +

Functions

+
+ + +

Functions

+
+
+
+ + +

FPH_Constants

+
+ +

Constants

+
+ + +

Constants

+
+
+
+ + +

FunctionDetail

+
+ +

Function detail

+
+ + +

function detail

+
+
+
+ + +

DefinedIn

+
+ +

Defined In

+
+ + +

defined in class

+
+
+
+ + +

AdobeLogo

+
+ +

Feathers Logo

+
+ + +

defined in class

+
+
+
+ + +

Implements

+
+ +

Implements

+
+ + +

Implements

+
+
+
+ + +

Subclasses

+
+ +

Subclasses

+
+ + +

Subclasses

+
+
+
+ + +

PleaseUse

+
+ +

Please Use

+
+ + +

Please Use

+
+
+
+ + +

GlobalConstants

+
+ +

Global Constants

+
+ + +

Text for Global Constants

+
+
+
+ + +

GlobalProperties

+
+ +

Global Properties

+
+ + +

Text for Global Properties

+
+
+
+ + +

PublicConstants

+
+ +

Public Constants

+
+ + +

Text for Public Constants

+
+
+
+ + +

PublicProperties

+
+ +

Public Properties

+
+ + +

Text for Public Properties

+
+
+
+ + +

ProtectedConstants

+
+ +

Protected Constants

+
+ + +

Text for Protected Constants

+
+
+
+ + +

ProtectedProperties

+
+ +

Protected Properties

+
+ + +

Text for Protected Properties

+
+
+
+ + +

ProtectedMethods

+
+ +

Protected Methods

+
+ + +

Text for Protected Methods

+
+
+
+ + +

PublicMethods

+
+ +

Public Methods

+
+ + +

Text for Public Methods

+
+
+
+ + +

GlobalMethods

+
+ +

Global Methods

+
+ + +

Text for Global Methods

+
+
+
+ + +

Pleaseuse

+
+ +

Please use

+
+ + +

Text for Please use

+
+
+
+ + +

DeprecatedSince

+
+ +

Deprecated Since

+
+ + +

Text for Deprecated Since

+
+
+
+ + +

Deprecated

+
+ +

Deprecated

+
+ + +

Text for Deprecated

+
+
+
+ + +

SymbolsIndex

+
+ +

Symbols Index

+
+ + +

Text for Symbols Index

+
+
+
+ + +

Compiler Errors

+
+ +

Compiler Errors

+
+ + +

Text for Compiler Errors

+
+
+
+ + +

Compiler Warnings

+
+ +

Compiler Warnings

+
+ + +

Text for Compiler Warnings

+
+
+
+ + +

Run-Time Errors

+
+ +

Run-Time Errors

+
+ + +

Text for Run-Time Errors

+
+
+
+ + +

ActionScript 2.0 Migration

+
+ +

ActionScript 2.0 Migration

+
+ + +

Text for ActionScript 2.0 Migration

+
+
+
+ + +

Character Set Codes

+
+ +

Character Set Codes

+
+ + +

Text for Character Set Codes

+
+
+
+ + +

Motion XML Elements

+
+ +

Motion XML Elements

+
+ + +

Text for Motion XML Elements

+
+
+
+ + +

Timed Text Tags

+
+ +

Timed Text Tags

+
+ + +

Text for Timed Text Tags

+
+
+
+ + +

Legal notices

+
+ +

Legal notices

+
+ + +

Text for Legal notices

+
+
+
+ + +

Legal Notices

+
+ +

Legal Notices

+
+ + +

Text for Legal Notices

+
+
+
+ + +

Using examples in the ActionScript 3.0 Language Reference

+
+ +

Using examples in the ActionScript 3.0 Language Reference

+
+ + +

Text for Using examples in the ActionScript 3.0 Language Reference

+
+
+
+ + +

List of deprecated elements

+
+ +

List of deprecated elements

+
+ + +

Text for List of deprecated elements

+
+
+
+ + +

DefinedByProperties

+
+ +

Defined By

+
+ + +

Text for "Defined By" column next to "Properties"

+
+
+
+ + +

DefinedByMethods

+
+ +

Defined By

+
+ + +

Text for "Defined By" column next to "Methods"

+
+
+
+ + +

DefinedByEvents

+
+ +

Defined By

+
+ + +

Text for "Defined By" column next to "Events"

+
+
+
+ + +

DefinedByStyles

+
+ +

Defined By

+
+ + +

Text for "Defined By" column next to "Styles"

+
+
+
+ + +

DefinedByEffects

+
+ +

Defined By

+
+ + +

Text for "Defined By" column next to "Effects"

+
+
+
+ + +

read

+
+ +

read

+
+ + +

Text for read

+
+
+
+ + +

write

+
+ +

write

+
+ + +

Text for write

+
+
+
+ + +

only

+
+ +

only

+
+ + +

Text for only

+
+
+
+ + +

static

+
+ +

static

+
+ + +

Text for static

+
+
+
+ + +

FinalStaticPropertyIn

+
+ +

Final static property

+
+ + +

Final static property

+
+
+
+ + +

FinalPropertyIn

+
+ +

Final property

+
+ + +

Final property

+
+
+
+ + +

PackageStaticPropertyIn

+
+ +

Package static property

+
+ + +

Package static property

+
+
+
+ + +

ProductVersion

+
+ +

Product Version

+
+ + +

Text for product version label

+
+
+
+ + +

ProductVersions

+
+ +

Product Versions

+
+ + +

Text for product versions label

+
+
+
+ + +

Since

+
+ +

Since

+
+ + +

Text for since label

+
+
+
+ + +

windowruntimeproperty

+
+ +

window.runtime property

+
+ + +

*JSLR*

+
+
+
+ + +

ShowInheritedProperties

+
+ +

Show Inherited Properties

+
+ + +

JSLR: Text for Show Inherited Properties

+
+
+
+ + +

ShowInheritedMethods

+
+ +

Show Inherited Methods

+
+ + +

JSLR: Text for Show Inherited Methods

+
+
+
+ + +

ShowInheritedConstants

+
+ +

Show Inherited Constants

+
+ + +

JSLR: Text for Show Inherited Constants

+
+
+
+ + +

JSLR_Book_Title

+
+ +

Adobe AIR Language Reference for HTML Developers

+
+ + +

JSLR: Text for Title

+
+
+
+ + +

JSLR_Index_Title

+
+ +

JavaScript Language Reference for The Adobe® Integrated Runtime (AIR™)

+
+ + +

JSLR: Text for Title

+
+
+
+ + +

SQLError_detail_messages

+
+ +

SQL error detail messages, ids, and arguments

+
+ + +

Text for SQLError detail messages

+
+
+
+ + +

RuntimeVersions

+
+ +

Runtime Versions

+
+ + +

Text for Runtime Version label

+
+
+
+ + +

Acrobat

+
+ +

Acrobat ActionScript API

+
+ + +

long name for Acrobat.

+
+
+
+ + +

SearchResults

+
+ +

Search Results

+
+ + +

Text for Search Results

+
+
+
+ + +

Search

+
+ +

Search

+
+ + +

Text for Search

+
+
+
+ + +

terms_AHV_SHORT_WORDS

+
+ +

Short and common words are excluded from the search database.

+
+ + +

Text for terms_AHV_SHORT_WORDS

+
+
+
+ + +

terms_AHV_NO_SEARCH_TERM

+
+ +

No search term entered.

+
+ + +

Text for terms_AHV_NO_SEARCH_TERM

+
+
+
+ + +

terms_AHV_MATCHES

+
+ +

Pages containing:

+
+ + +

Text for terms_AHV_MATCHES

+
+
+
+ + +

terms_AHV_NO_MATCHES

+
+ +

No pages contain:

+
+ + +

Text for terms_AHV_NO_MATCHES

+
+
+
+ + +

Override

+
+ +

override

+
+ + +

Text for Override

+
+
+
+ + +

SkinStates

+
+ +

Skin States

+
+ + +

Text for Skin States

+
+
+
+ + +

SkinState

+
+ +

Skin State

+
+ + +

Text for Skin State

+
+
+
+ + +

SkinParts

+
+ +

Skin Parts

+
+ + +

Text for Skin Parts

+
+
+
+ + +

SkinPart

+
+ +

Skin Part

+
+ + +

Text for Skin Part

+
+
+
+ + +

HideInheritedSkinStates

+
+ +

Hide Inherited Skin States

+
+ + +

Text for Hide Inherited Skin States

+
+
+
+ + +

ShowInheritedSkinStates

+
+ +

Show Inherited Skin States

+
+ + +

Text for Show Inherited Skin States

+
+
+
+ + +

HideInheritedSkinParts

+
+ +

Hide Inherited Skin Parts

+
+ + +

Text for Hide Inherited Skin Parts

+
+
+
+ + +

ShowInheritedSkinParts

+
+ +

Show Inherited Skin Parts

+
+ + +

Text for Show Inherited Skin Parts

+
+
+
+ + +

PartType

+
+ +

Part Type

+
+ + +

Text for Part Type

+
+
+
+ + +

Required

+
+ +

Required

+
+ + +

Text for Required

+
+
+
+ + +

Static

+
+ +

Static

+
+ + +

Text for Static

+
+
+
+ + +

Dynamic

+
+ +

Dynamic

+
+ + +

Text for Dynamic

+
+
+
+ + +

skinpartprefixed

+
+ +

This component uses skins made up of skin parts. Do not set the skin parts directly. The component's skin sets the skin parts.

+
+ + +

Text for This component uses skins made up of skin parts. Do not set the skin parts directly. The component's skin sets the skin parts.

+
+
+
+ + +

skinstateprefixed

+
+ +

To skin the component, implement a skin that defines the following states. Although you must implement all skin states, a skin state can be empty. An empty skin state specifies no changes to the default skin state.

+
+ + +

Text for To skin the component, implement a skin that defines the following states. Although you must implement all skin states, a skin state can be empty. An empty skin state specifies no changes to the default skin state.

+
+
+
+ + +

dynpropdesc

+
+ +

The %type% must return an object of type

+
+ + +

Text for The %type% must return an object of type

+
+
+
+ + +

unknown

+
+ +

unknown

+
+ + +

Text for unknown

+
+
+
+ + +

howtouseevents

+
+ +

Click for more information on events

+
+ + +

Text for Click for more information on events

+
+
+
+ + +

howtouseeffects

+
+ +

Click for more information on effects

+
+ + +

Text for Click for more information on effects

+
+
+
+ + +

howtousestyles

+
+ +

Click for more information on styles

+
+ + +

Text for Click for more information on styles

+
+
+
+ + +

howtouseskins

+
+ +

Click for more information on skins

+
+ + +

Text for Click for more information on skins

+
+
+
+ + + +

Theme

+
+ +

Theme

+
+ + +

Text for Theme

+
+
+
+ + +

altr.desc.1st

+
+ +

Starting with Flex %ver%, Adobe recommends that you use the %class% class as an alternative to this class.

+
+ + +

Text for Starting with Flex %ver%, Adobe recommends that you use the %class% class as an alternative to this class.

+
+
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/documentation/api-reference/templates/ClassHeader.xslt b/documentation/api-reference/templates/ClassHeader.xslt new file mode 100644 index 0000000000..a5d39d035a --- /dev/null +++ b/documentation/api-reference/templates/ClassHeader.xslt @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + globalClassifier: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/Classes.xslt b/documentation/api-reference/templates/Classes.xslt new file mode 100644 index 0000000000..7989d6b0c6 --- /dev/null +++ b/documentation/api-reference/templates/Classes.xslt @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + , + + + + + + , + + + + + , + + + + + , + + + + + , + + + + + + + + + + + + + + + + + + + + + . + false + + + + :public + + + + + + :internal + + + + + + + + . + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/Overviews_Base.xml b/documentation/api-reference/templates/Overviews_Base.xml new file mode 100644 index 0000000000..7429b17d96 --- /dev/null +++ b/documentation/api-reference/templates/Overviews_Base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/PostProcessing.xslt b/documentation/api-reference/templates/PostProcessing.xslt new file mode 100644 index 0000000000..00cdddf002 --- /dev/null +++ b/documentation/api-reference/templates/PostProcessing.xslt @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WARNING : Short Description not present for + + + + + + + + + + + + + + + + + + + + + + + WARNING : api Description not present for + + + + + + + + + + + + + + + + + + + + + + + + WARNING : Short Description not present for + + + + + + + + + + + + + + + + + + + + + + + WARNING : api Description not present for + + + + + + + + + + diff --git a/documentation/api-reference/templates/all-classes.xslt b/documentation/api-reference/templates/all-classes.xslt new file mode 100644 index 0000000000..c41babe896 --- /dev/null +++ b/documentation/api-reference/templates/all-classes.xslt @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + <xsl:choose> + <xsl:when test="$prog_language_name='javascript'" /> + <xsl:otherwise> + <xsl:value-of select="$title"/> + </xsl:otherwise> + </xsl:choose> + + + + + + + + + + +

+ + + +

+
+
+ + + + + + + +
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/documentation/api-reference/templates/all-index.xslt b/documentation/api-reference/templates/all-index.xslt new file mode 100644 index 0000000000..7f5d75ff46 --- /dev/null +++ b/documentation/api-reference/templates/all-index.xslt @@ -0,0 +1,1396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +,:!?/.^~*=%|&<>()[]{}" + + + + + + + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #config errmsg="" + + + + + <xsl:if test="$splitIndex and $letter"> + <xsl:value-of select="$localizedLetter"/> + </xsl:if> + <xsl:if test="not($splitIndex)"> + <xsl:value-of select="$config/title"/> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:value-of select="localizedIndex"/> + <xsl:call-template name="getPageTitlePostFix"/> + + + + + + + + + eclipseBody + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + Skin + + + + , + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + ) + + + + + + + + + + + + + + + + + + + + + + s.html + + + + + + ( + + + + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + () + + + + + + + + + + + + + + + + + + + global + + + + + + , + + + + + + + + + + + + + + + + + + + , + + + + + + + , + + + + + + + + + + + + + + + + Command for + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + ) + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + , + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ + + + + + + + + + + + +

+
+ +
 
+ BEGIN IONCOMMENTS +
+ END IONCOMMENTS + #include virtual="ionComments.ssi" +

+ + + +

+ #include virtual="/livedocs/googleAnalytics.ssi" + #include virtual="/ubi/analytics/analytics_ssi.html" +
+
+
+ +
+ + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + , + + + + , + + + + + + + + + + + + + + + + + , + + + + , + + + + + + + + + + + + + + + + + + + + + Compiler Directive + + + + + + + + + + , + + + + + + + + + + + + + + + , + + + + , + + + + + + , + + + + , + + + + + + + + + + + + + + + + + + + + , + + + + , + + + + + + , + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + , + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + [ + + + + + : + + + + + + + ... rest + + + ] + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + javascript:loadClassListFrame(' + + + + + ./class-list.html'); + + + + + + + + + + + +
diff --git a/documentation/api-reference/templates/asdoc-util.xslt b/documentation/api-reference/templates/asdoc-util.xslt new file mode 100644 index 0000000000..18d134fe12 --- /dev/null +++ b/documentation/api-reference/templates/asdoc-util.xslt @@ -0,0 +1,4211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> + + + + + January + February + March + April + May + June + July + August + September + October + November + December + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + A.M. + P.M. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + livedocs:no + + + + + + + + + + + + + + + + + + <br/> + + + + + + + + + + + ABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyz + + + + + + + + * + + +   + + + ° + + + + + + ® + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + stylesheet + style.css + text/css + screen + + + stylesheet + print.css + text/css + print + + + stylesheet + override.css + text/css + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + search.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  |  + + + + + + + + +  |  + + + + + + + + + + +  | + + + + + + + + + + + + + + + + <br/> + + + + + + +  |  + + + + + +  |  + + + + + + + + +  |  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + operator# + + + statement# + + + specialType# + + + statements + + + operators + + + special-types + + + + global + + . + + + + + + . + + + + + + + + #method: + + + #method: + + + #property: + + + #event: + + + #style: + + + #effect: + + + + + + + + + + + + + +

+ + + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _top + + + _top + + + + + + + + + + + + + + + + + <br/> + + + + + + + + + + + <br/> + + + + + + + + + + + + + + + + + + + + + + <br/> + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + &lt; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &gt; + + + + + + + + + + + . + &lt; + + + + + &gt; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + since + + + + + + + + + + . + + <br/> + + + + + +
+ +
+
+
+
+
+ + + + + + + + Review Needed. + + + + + + + + + + + + + + +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
						
+
+ + + +
	
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <br/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AIR-only + + diff --git a/documentation/api-reference/templates/asdoc.js b/documentation/api-reference/templates/asdoc.js new file mode 100644 index 0000000000..731fe65b89 --- /dev/null +++ b/documentation/api-reference/templates/asdoc.js @@ -0,0 +1,286 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2006-2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// +var ECLIPSE_FRAME_NAME = "ContentViewFrame"; +var eclipseBuild = false; +var liveDocsBaseUrl = "http://livedocs.adobe.com/flex/3"; +var liveDocsBookName = "langref"; +function findObject(objId) { + if (document.getElementById) + return document.getElementById(objId); + if (document.all) + return document.all[objId]; +} +function isEclipse() { + return eclipseBuild; +// return (window.name == ECLIPSE_FRAME_NAME) || (parent.name == ECLIPSE_FRAME_NAME) || (parent.parent.name == ECLIPSE_FRAME_NAME); +} +function configPage() { + setRowColorsInitial(true, "Property"); + setRowColorsInitial(true, "Method"); + setRowColorsInitial(true, "ProtectedMethod"); + setRowColorsInitial(true, "Event"); + setRowColorsInitial(true, "Style"); + + setRowColorsInitial(true, "SkinPart"); + setRowColorsInitial(true, "SkinState"); + + setRowColorsInitial(true, "Constant"); + if (isEclipse()) { + if (window.name != "classFrame") + { + var localRef = window.location.href.indexOf('?') != -1 ? window.location.href.substring(0, window.location.href.indexOf('?')) : window.location.href; + localRef = localRef.substring(localRef.indexOf("langref/") + 8); + if (window.location.search != "") + localRef += ("#" + window.location.search.substring(1)); + window.location.replace(baseRef + "index.html?" + localRef); + return; + } + else + { + setStyle(".eclipseBody", "display", "block"); +// var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; +// if (isIE == false && window.location.hash != "") + if (window.location.hash != "") + window.location.hash=window.location.hash.substring(1); + } + } + else if (window == top) { // no frames + findObject("titleTable").style.display = ""; + } + else { // frames + findObject("titleTable").style.display = "none"; + } + showTitle(asdocTitle); +} +function loadFrames(classFrameURL, classListFrameURL) { + var classListFrame = findObject("classListFrame"); + if(classListFrame != null && classListFrameContent!='') + classListFrame.document.location.href=classListFrameContent; + if (isEclipse()) { + var contentViewFrame = findObject(ECLIPSE_FRAME_NAME); + if (contentViewFrame != null && classFrameURL != '') + contentViewFrame.document.location.href=classFrameURL; + } + else { + var classFrame = findObject("classFrame"); + if(classFrame != null && classFrameContent!='') + classFrame.document.location.href=classFrameContent; + } +} +function showTitle(title) { + if (!isEclipse()) + top.document.title = title; +} +function loadClassListFrame(classListFrameURL) { + if (parent.frames["classListFrame"] != null) { + parent.frames["classListFrame"].location = classListFrameURL; + } + else if (parent.frames["packageFrame"] != null) { + if (parent.frames["packageFrame"].frames["classListFrame"] != null) { + parent.frames["packageFrame"].frames["classListFrame"].location = classListFrameURL; + } + } +} +function gotoLiveDocs(primaryURL, secondaryURL, locale) { + if (locale == "en-us") { + locale = ""; + } + else { + locale = "_" + locale.substring(3); + } + var url = liveDocsBaseUrl + locale + "/" + liveDocsBookName + "/index.html?" + primaryURL; + if (secondaryURL != null && secondaryURL != "") + url += ("&" + secondaryURL); + window.open(url, "mm_livedocs", "menubar=1,toolbar=1,status=1,scrollbars=1,resizable=yes"); +} +function findTitleTableObject(id) +{ + if (isEclipse()) + return parent.titlebar.document.getElementById(id); + else if (top.titlebar) + return top.titlebar.document.getElementById(id); + else + return document.getElementById(id); +} +function titleBar_setSubTitle(title) +{ + if (isEclipse() || top.titlebar) + findTitleTableObject("subTitle").childNodes.item(0).data = title; +} +function titleBar_setSubNav(showConstants,showProperties,showStyles,showSkinPart,showSkinState,showEffects,showEvents,showConstructor,showMethods,showExamples, + showPackageConstants,showPackageProperties,showPackageFunctions,showInterfaces,showClasses,showPackageUse) +{ + if (isEclipse() || top.titlebar) + { + findTitleTableObject("propertiesLink").style.display = showProperties ? "inline" : "none"; + findTitleTableObject("propertiesBar").style.display = (showProperties && (showPackageProperties || showConstructor || showMethods || showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("packagePropertiesLink").style.display = showPackageProperties ? "inline" : "none"; + findTitleTableObject("packagePropertiesBar").style.display = (showPackageProperties && (showConstructor || showMethods || showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showConstants || showEffects || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("constructorLink").style.display = showConstructor ? "inline" : "none"; + findTitleTableObject("constructorBar").style.display = (showConstructor && (showMethods || showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("methodsLink").style.display = showMethods ? "inline" : "none"; + findTitleTableObject("methodsBar").style.display = (showMethods && (showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("packageFunctionsLink").style.display = showPackageFunctions ? "inline" : "none"; + findTitleTableObject("packageFunctionsBar").style.display = (showPackageFunctions && (showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("eventsLink").style.display = showEvents ? "inline" : "none"; + findTitleTableObject("eventsBar").style.display = (showEvents && (showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("stylesLink").style.display = showStyles ? "inline" : "none"; + findTitleTableObject("stylesBar").style.display = (showStyles && (showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + + findTitleTableObject("SkinPartLink").style.display = showSkinPart ? "inline" : "none"; + findTitleTableObject("SkinPartBar").style.display = (showSkinPart && (showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + + findTitleTableObject("SkinStateLink").style.display = showSkinState ? "inline" : "none"; + findTitleTableObject("SkinStateBar").style.display = (showSkinState && (showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + + findTitleTableObject("effectsLink").style.display = showEffects ? "inline" : "none"; + findTitleTableObject("effectsBar").style.display = (showEffects && (showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("constantsLink").style.display = showConstants ? "inline" : "none"; + findTitleTableObject("constantsBar").style.display = (showConstants && (showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("packageConstantsLink").style.display = showPackageConstants ? "inline" : "none"; + findTitleTableObject("packageConstantsBar").style.display = (showPackageConstants && (showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("interfacesLink").style.display = showInterfaces ? "inline" : "none"; + findTitleTableObject("interfacesBar").style.display = (showInterfaces && (showClasses || showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("classesLink").style.display = showClasses ? "inline" : "none"; + findTitleTableObject("classesBar").style.display = (showClasses && (showPackageUse || showExamples)) ? "inline" : "none"; + findTitleTableObject("packageUseLink").style.display = showPackageUse ? "inline" : "none"; + findTitleTableObject("packageUseBar").style.display = (showPackageUse && showExamples) ? "inline" : "none"; + findTitleTableObject("examplesLink").style.display = showExamples ? "inline" : "none"; + } +} +function titleBar_gotoClassFrameAnchor(anchor) +{ + if (isEclipse()) + parent.classFrame.location = parent.classFrame.location.toString().split('#')[0] + "#" + anchor; + else + top.classFrame.location = top.classFrame.location.toString().split('#')[0] + "#" + anchor; +} +function setMXMLOnly() +{ + if (getCookie("showMXML") == "false") + { + toggleMXMLOnly(); + } +} +function toggleMXMLOnly() +{ + var mxmlDiv = findObject("mxmlSyntax"); + var mxmlShowLink = findObject("showMxmlLink"); + var mxmlHideLink = findObject("hideMxmlLink"); + if (mxmlDiv && mxmlShowLink && mxmlHideLink) + { + if (mxmlDiv.style.display == "none") + { + mxmlDiv.style.display = "block"; + mxmlShowLink.style.display = "none"; + mxmlHideLink.style.display = "inline"; + setCookie("showMXML","true", new Date(3000,1,1,1,1), "/", document.location.domain); + } + else + { + mxmlDiv.style.display = "none"; + mxmlShowLink.style.display = "inline"; + mxmlHideLink.style.display = "none"; + setCookie("showMXML","false", new Date(3000,1,1,1,1), "/", document.location.domain); + } + } +} +function showHideInherited() +{ + setInheritedVisible(getCookie("showInheritedConstant") == "true", "Constant"); + setInheritedVisible(getCookie("showInheritedProtectedConstant") == "true", "ProtectedConstant"); + setInheritedVisible(getCookie("showInheritedProperty") == "true", "Property"); + setInheritedVisible(getCookie("showInheritedProtectedProperty") == "true", "ProtectedProperty"); + setInheritedVisible(getCookie("showInheritedMethod") == "true", "Method"); + setInheritedVisible(getCookie("showInheritedProtectedMethod") == "true", "ProtectedMethod"); + setInheritedVisible(getCookie("showInheritedEvent") == "true", "Event"); + setInheritedVisible(getCookie("showInheritedStyle") == "true", "Style"); + + setInheritedVisible(getCookie("showInheritedSkinPart") == "true", "SkinPart"); + setInheritedVisible(getCookie("showInheritedSkinState") == "true", "SkinState"); + + setInheritedVisible(getCookie("showInheritedEffect") == "true", "Effect"); +} +function setInheritedVisible(show, selectorText) +{ + if (document.styleSheets[0].cssRules != undefined) + { + var rules = document.styleSheets[0].cssRules; + for (var i = 0; i < rules.length; i++) + { + if (rules[i].selectorText == ".hideInherited" + selectorText) + rules[i].style.display = show ? "" : "none"; + + if (rules[i].selectorText == ".showInherited" + selectorText) + rules[i].style.display = show ? "none" : ""; + } + } + else + { + document.styleSheets[0].addRule(".hideInherited" + selectorText, show ? "display:inline" : "display:none"); + document.styleSheets[0].addRule(".showInherited" + selectorText, show ? "display:none" : "display:inline"); + } + setCookie("showInherited" + selectorText, show ? "true" : "false", new Date(3000,1,1,1,1), "/", document.location.domain); + setRowColors(show, selectorText); +} +function setRowColors(show, selectorText) +{ + var rowColor = "#F2F2F2"; + var table = findObject("summaryTable" + selectorText); + if (table != null) + { + var rowNum = 0; + for (var i = 1; i < table.rows.length; i++) + { + if (table.rows[i].className.indexOf("hideInherited") == -1 || show) + { + rowNum++; + table.rows[i].bgColor = (rowNum % 2 == 0) ? rowColor : "#FFFFFF"; + } + } + } +} +function setRowColorsInitial(show, selectorText) +{ + var rowColor = "#F2F2F2"; + var table = findObject("summaryTable" + selectorText); + if (table != null) + { + var rowNum = 0; + for (var i = 1; i < table.rows.length; i++) + { + if (table.rows[i].className.indexOf("hideInherited") == -1 && show) + { + rowNum++; + table.rows[i].bgColor = (rowNum % 2 == 0) ? rowColor : "#FFFFFF"; + } + } + } +} +function setStyle(selectorText, styleName, newValue) +{ + if (document.styleSheets[0].cssRules != undefined) + { + var rules = document.styleSheets[0].cssRules; + for (var i = 0; i < rules.length; i++) + { + if (rules[i].selectorText == selectorText) + { + rules[i].style[styleName] = newValue; + break; + } + } + } + else + { + document.styleSheets[0].addRule(selectorText, styleName + ":" + newValue); + } +} diff --git a/documentation/api-reference/templates/class-files.xslt b/documentation/api-reference/templates/class-files.xslt new file mode 100644 index 0000000000..1d7ac7366a --- /dev/null +++ b/documentation/api-reference/templates/class-files.xslt @@ -0,0 +1,5604 @@ + + + + + + + + + + + + + + + + + + + + + + true + true + + + false + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + .html + + + + + + + + + + + + + + + + + + + + + + #config errmsg="" + + + + + + + + + + + + <xsl:if test="$isTopLevel='false'"> + <xsl:value-of select="$packageName"/> + <xsl:text>.</xsl:text> + </xsl:if> + <xsl:value-of select="$name"/> + <xsl:call-template name="getPageTitlePostFix"/> + + + +
+ + + + + + + + + + +
+ +
+ + + true + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + true + false + + + + + + + + <br/> + <br/> +
+ <br/> + + + +

+ + + + + + . + + + + + + + / + + + .html + + + class-list.html + + + /class-list.html + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + , + + + ) + + + + + + + + + + + + +
+ + + + + + + + + + + + + + () + + + + + + + + + + + +
+

+ + + + + + + + + + + + + + + + ( + + + + + + + + + , + + + ) + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + () + + + + +
+
+ + + + + + + + function + + + + ( + + ) + + + + + + + + + + + + + <br/> + <br/> + + + + + + + <br/> + + + + + +
+
+ + + + + + + + + + + <br/> + + + Example + + + <br/> + + + + + + +
+ + + + + + + + + + + + , + + + [ + + + + +
... + + + ... + + + + + + + + : + + + + + + + + + = + + " + + + + " + + + + = NaN + + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Parameters + + + + + + + + + + + + + +
+ + + + + + + + + + + + ... + + + ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + + + : + + + + + + + + + + + + </code> (default = + + " + + <code> + + </code> + + " + + ) + <code> + + + </code> (default = + <code> + + </code> + ) + <code> + + + + [optional] + + + + + + + +
+ +
+
+ + + + + + + + + +

+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <br/> + + + + <br/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+								
+							
+
+ + + + + <br/> + +
+ +
+
+								
+							
+
+
+ + + + +
+
+								
+							
+
+ + + + + <br/> + +
+ +
+
+								
+							
+
+
+
+ + + + + + + +

+ + + + + + + + + + + + + +

+ + + +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #EEEEEE + + + #EEDDDD + + + + + + + + + + + + +
+ + + + + Static + + + DefinedIn + + + + + + + InheritedFrom + + + + + +
+ + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + , + + + +
+
+ + + + + + + + + + + THIS CODE SHOULD NOT BE CALLED. If you see this message, please notify your local ASDocs contact or the tech team. + . + The + + class is + deprecated + + since + + + . + <br/> + <br/> + + + + + + +

+ Review Needed +

+
+ +
+ + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + +

+ + + + + + +
+ + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/class-list.xslt b/documentation/api-reference/templates/class-list.xslt new file mode 100644 index 0000000000..c546d8b3f2 --- /dev/null +++ b/documentation/api-reference/templates/class-list.xslt @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + class-list.html + + /class-list.html + + + + + + + + + <xsl:value-of select="$title"/> + + + + + + + + +

+ + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + +
+ &nbsp; +
+ + + + + +
+ + + +
+ &nbsp; +
+ + + + + +
+ + + () + +
+ &nbsp; +
+ + + + + +
+ + + + + + + + + + + + + + + + +
+ &nbsp; +
+ + + + + +
+ + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
diff --git a/documentation/api-reference/templates/class-parts.xslt b/documentation/api-reference/templates/class-parts.xslt new file mode 100644 index 0000000000..df066eff38 --- /dev/null +++ b/documentation/api-reference/templates/class-parts.xslt @@ -0,0 +1,1475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
ClassInterface + + + + + + final + + + dynamic + + + + class + + + interface + + + + + extends + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + +
+ + + + + + + + + + + + + + + + + + + + images/inherit-arrow.gif + + + Inheritance + + + + + + + + + + + + + + + + + images/inherit-arrow.gif + + + Inheritance + + + + + + + + + + + + + + + + + images/inherit-arrow.gif + + + Inheritance + + + + + + + + + + + + + + + + + +
Implements + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + +
+ Subclasses + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + +
+ + + <br/> + + + +

+ + <br/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + <br/> +

+ +

+
+
+ <br/> +
+ +

+ + + + + + + + + + + + + + + collapsed + + + <br/> + + + + expanded + + + +

+ +
+ + + + +

Skinning the component

+

To skin the component, implement a skin that defines the following skin states: <br/><br/> <br/><br/>While you must implement all skin states, a skin state can be empty. An empty skin state defines no changes to the default skin state.

+
+ + + + + + + <br/> +
+
+
+ + + +
+ + + + + + + + + : + + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + + + + + + + : + + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
diff --git a/documentation/api-reference/templates/class-summary.xslt b/documentation/api-reference/templates/class-summary.xslt new file mode 100644 index 0000000000..a040f87706 --- /dev/null +++ b/documentation/api-reference/templates/class-summary.xslt @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="$asdoc_terms/row[entry[1][p/text() = $localTitle]]/entry[2]/p"/> + <xsl:call-template name="getPageTitlePostFix"/> + + + + + + + + + eclipseBody + + + + + + + + + + + + + + + + + + +
+
+ +

+ + + + + + + + + + + +

+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+

+

+
+
+
+ +
+
diff --git a/documentation/api-reference/templates/cookies.js b/documentation/api-reference/templates/cookies.js new file mode 100644 index 0000000000..f828d08333 --- /dev/null +++ b/documentation/api-reference/templates/cookies.js @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2006-2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Read the JavaScript cookies tutorial at: + * http://www.netspade.com/articles/javascript/cookies.xml + */ + +/** + * Sets a Cookie with the given name and value. + * + * name Name of the cookie + * value Value of the cookie + * [expires] Expiration date of the cookie (default: end of current session) + * [path] Path where the cookie is valid (default: path of calling document) + * [domain] Domain where the cookie is valid + * (default: domain of calling document) + * [secure] Boolean value indicating if the cookie transmission requires a + * secure transmission + */ +function setCookie(name, value, expires, path, domain, secure) +{ + document.cookie= name + "=" + escape(value) + + ((expires) ? "; expires=" + expires.toGMTString() : "") + + ((path) ? "; path=" + path : "") + + ((domain) ? "; domain=" + domain : "") + + ((secure) ? "; secure" : ""); +} + +/** + * Gets the value of the specified cookie. + * + * name Name of the desired cookie. + * + * Returns a string containing value of specified cookie, + * or null if cookie does not exist. + */ +function getCookie(name) +{ + var dc = document.cookie; + var prefix = name + "="; + var begin = dc.indexOf("; " + prefix); + if (begin == -1) + { + begin = dc.indexOf(prefix); + if (begin != 0) return null; + } + else + { + begin += 2; + } + var end = document.cookie.indexOf(";", begin); + if (end == -1) + { + end = dc.length; + } + return unescape(dc.substring(begin + prefix.length, end)); +} + +/** + * Deletes the specified cookie. + * + * name name of the cookie + * [path] path of the cookie (must be same as path used to create cookie) + * [domain] domain of the cookie (must be same as domain used to create cookie) + */ +function deleteCookie(name, path, domain) +{ + if (getCookie(name)) + { + document.cookie = name + "=" + + ((path) ? "; path=" + path : "") + + ((domain) ? "; domain=" + domain : "") + + "; expires=Thu, 01-Jan-70 00:00:01 GMT"; + } +} diff --git a/documentation/api-reference/templates/effectsSummary.xslt b/documentation/api-reference/templates/effectsSummary.xslt new file mode 100644 index 0000000000..28a3143766 --- /dev/null +++ b/documentation/api-reference/templates/effectsSummary.xslt @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/eventsGeneratedSummary.xslt b/documentation/api-reference/templates/eventsGeneratedSummary.xslt new file mode 100644 index 0000000000..83951854a9 --- /dev/null +++ b/documentation/api-reference/templates/eventsGeneratedSummary.xslt @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/fieldSummary.xslt b/documentation/api-reference/templates/fieldSummary.xslt new file mode 100644 index 0000000000..1668ba44c3 --- /dev/null +++ b/documentation/api-reference/templates/fieldSummary.xslt @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
diff --git a/documentation/api-reference/templates/help.js b/documentation/api-reference/templates/help.js new file mode 100644 index 0000000000..1b6ba80a0b --- /dev/null +++ b/documentation/api-reference/templates/help.js @@ -0,0 +1,941 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + + +function closePopup() +{ + window.close(); +} +function scrollToNameAnchor() +{ + var nameAnchor = window.location.href; + var value = nameAnchor.split("nameAnchor="); + + if (value[1] != null) { + document.location =value[0]+"#"+ value[1]; + } +} +// HIDES AND SHOWS LARGE GRAPHICS IN THE CONTENT PAGES +function showHideImage(thisID, obj) +{ + + var imgElement = document.getElementById(thisID); + var imgText = obj; + + if( imgElement.className == "largeImage" ) + { + imgElement.src = "images/" + thisID + ".png"; + imgElement.className="smallImage"; + obj.className="showImageLink"; + obj.href="#"; + obj.firstChild.nodeValue = terms_AHV_LARGE_GRAPHIC; + window.focus(); + } + else + { + imgElement.src = "images/" + thisID + "_popup.png"; + imgElement.className="largeImage"; + obj.className="hideImageLink"; + obj.href="#"; + obj.firstChild.nodeValue = terms_AHV_SMALL_GRAPHIC; + window.focus(); + } +} +// js function for expand collapse menu functionality +function KeyCheck(e, tree, idx) +{ + var KeyID = (window.event) ? event.keyCode : e.keyCode; + var node = YAHOO.widget.TreeView.getNode(tree, idx); + switch(KeyID) + { + case 37: + // alert("Arrow Left"); + node.collapse(); + break; + case 39: + // alert("Arrow Right"); + node.expand(); + break; + } +} +// js function for hide/display mini-elements functionality +function toggleLayer(whichLayer) { + if (document.getElementById) { + // this is the way the standards work + var obj=document.getElementById(whichLayer); + var img = obj.previousSibling.firstChild.firstChild; + img.setAttribute("src","images/on.gif"); + var styleatt = obj.style; + styleatt.display = styleatt.display? "":"block"; + + //change the class of the h3 per design + if (obj.previousSibling.className === "topictitle3") { + obj.previousSibling.className ="topictitle3off"; + img.setAttribute("src","images/on.gif"); + } else if (obj.previousSibling.className === "topictitle3off") { + obj.previousSibling.className ="topictitle3"; + img.setAttribute("src","images/off.gif"); + } + } + else if (document.all) { + // this is the way old msie versions work + var style2 = document.all[whichLayer].style; + style2.display = style2.display? "":"block"; + } +} + function addBookmark( bm_url_str, bm_str_label ) { + parent.navigation.flashProxy.call('addBookmark', bm_url_str, bm_str_label ); +} + +var upperAsciiXlatTbl = new Array( +223,"ss", +230,"ae", +198,"ae", +156,"oe", +140,"oe", +240,"eth", +208,"eth", +141,"y", +159,"y" +); + +var maxNumberOfShownSearchHits = 30; +var showInputStringAlerts = 0; +var navigationCookie = ""; + +////////////// COOKIE-RELATED FUNCTIONS ///////////////////////////////////////// +// test the navigator object for cookie enabling +// additional code would need to be added for +// to support browsers pre navigator 4 or IE5 or +// other browsers that dont support +// the navigator object if any .. + function cookiesNotEnabled() +{ + return true; // We're not going to use cookies +} +/* + * This function parses comma-separated name=value + * argument pairs from the query string of the URL. + * It stores the name=value pairs in + * properties of an object and returns that object. + */ +function getArgs() +{ + var args = new Object(); + var query = window.location.search.substring(1); + // Get query string + if (query.length > 0) { + var pairs = query.split(","); + // Break at comma + for(var i = 0; i < pairs.length; i++) + { + var pos = pairs[i].indexOf('='); + // Look for "name=value" + if (pos == -1) continue; + // If not found, skip + var argname = pairs[i].substring(0,pos); + // Extract the name + var value = pairs[i].substring(pos+1); + // Extract the value + args[argname] = unescape(value); + // Store as a property + // In JavaScript 1.5, use decodeURIComponent( ) + // instead of escape( ) + } + } else { + args[name] = false; + } + return args; // Return the object +} + +/////////////////////////////// COOKIE-RELATED FUNCTIONS //////////////////////// +// Bill Dortch getCookieVal and GetCookie routines +function getCookieVal(offset) { + var endstr=document.cookie.indexOf(";",offset); + if (endstr==-1)endstr=document.cookie.length; + return unescape(document.cookie.substring(offset, endstr)); +} +function GetCookie(name) { + var arg=name+"="; + var alen=arg.length; + var clen=document.cookie.length; + var i=0; + + if (cookiesNotEnabled()) + { + var args = getArgs(); + if (args[name] !== false) { + return args[name]; + } + } else { + while(i maxNumberOfShownSearchHits ) ? maxNumberOfShownSearchHits : matchesArrIndices.length; + + for(var ndx=0, resultsArr = new Array(); ndx < ndxEnd; ndx++) { + resultsArr[resultsArr.length] = buildResultsStrOneLine(matchesArrIndices[ndx],matchesArrHits[ndx]); + } + + // Convert this 'resultsArr' into a single string that will be injected into this search page. + innerHTMLstring = "
    "; + for( var ndx=0; ndx < resultsArr.length; ndx++ ) { + innerHTMLstring = innerHTMLstring + resultsArr[ndx]; + } + innerHTMLstring = innerHTMLstring + "
"; + return innerHTMLstring; +} +//--------------------------------------------------- +function buildResultsStrOneLine(a,b) +{ + var retStr; + retStr = "
  • "; + + // for debug... + //retStr += "target=\"content\" "; + //retStr += "title=\"" + top.fileArr[a] + ".html-"; + //retStr += a + "-" + b + "\">"; + + // for production... + //retStr += "target=\"AdobeHelp\" >"; + + retStr += titleArr[a] + "
  • "; + return retStr; +} +//--------------------------------------------------- +// checkForHits +// Break up the search term into words. +// Check each of those words against... +// (a) cached titles and +// (b) cached content lines +// Perform the hit detection for each one, +// storing the results into (hits-ordered) +// 'matchesArrIndices' and +// 'matchesArrHits'. +//--------------------------------------------------- +function checkForHits() +{ + var inputWords = new Array(); + var tempArr = new Array(); + + // Split the search term into individual search words + tempArr = searchTerm.split(" "); + for(var ndx=0; ndx < tempArr.length; ndx++) { + if( tempArr[ndx].length ) { + inputWords[inputWords.length] = tempArr[ndx]; + } + } + + // Initialization + matchesArrHits = new Array(); + matchesArrIndices = new Array(); + + // Initialize the 'maskArr' and the 'hitsArr' + maskArr = new Array(); + hitsArr = new Array(); + for( var ndx = 0; ndx < fileArr.length; ndx++ ) { + maskArr[maskArr.length] = 1; + hitsArr[hitsArr.length] = 0; + } + + // Do checking for matches on EACH OF THE INPUT WORDS + for( var ndx = 0; ndx < inputWords.length; ndx++ ) { + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if( ! checkForHitsWordAgainstPages( inputWords[ndx] ) ) { + return; // No sense in continuing, match has failed. + } + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + for( var ndx2 = 0; ndx2 < hitsArr.length; ndx2++ ) { + if( hitsArr[ndx2] == 0 ) { + maskArr[ndx2] = 0; + } + else { + if( maskArr[ndx2] != 0 ) { + maskArr[ndx2] += hitsArr[ndx2]; + } + } + } + } + + // From the final 'maskArr', generate 'matchesArrHits' and 'matchesArrIndices' + for( var ndx = 0; ndx < maskArr.length; ndx++ ) { + if( maskArr[ndx] ) { + matchesArrHits[matchesArrHits.length] = maskArr[ndx]; + matchesArrIndices[matchesArrIndices.length] = ndx; + } + } + + // If there were any hits, then sort them by highest hits first + if( matchesArrIndices.length ) { + bubbleSortWithShadow(matchesArrHits, matchesArrIndices); + } +} +//--------------------------------------------------- +function checkForHitsWordAgainstPages(w) +{ + var hitAnywhere = 0; + + if(showInputStringAlerts){alert( "Length of sc2: " + sc2.length );} + + // Process each of the content lines (one per file/page) + for(var ndx=0; ndx < sc2.length; ndx++) { + + // Put the cached title into glob_title + glob_title = sc1[ndx]; + + // Put the cached content line into glob_phrase + glob_phrase = sc2[ndx]; + + if( maskArr[ndx] ) { + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if( document.isDblByte ) { + hitsArr[ndx] = checkForHitsWordAgainstTitleAndLine2(w,ndx); + } + else { + hitsArr[ndx] = checkForHitsWordAgainstTitleAndLine(w,ndx); + } + if( hitsArr[ndx] ) { + hitAnywhere = 1; + } + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + } + } + return hitAnywhere; +} +//--------------------------------------------------- +function checkForHitsWordAgainstTitleAndLine(w, lineNdx) +{ + var words; + var titleHitCnt = 0; + var contentHitCnt = 0; + var regex = new RegExp(w, "i"); + + // TITLE ......................................... + words = new Array(); + if(glob_title!=null){ + words = glob_title.split(" "); + } + // EXECUTE TITLE MATCH TEST + for( var ndx = 0; ndx < words.length; ndx++ ) { + if( w == words[ndx] ) { + titleHitCnt += 100; + break; + } + } + + // CONTENT ......................................... + words = new Array(); + if(glob_phrase!=null){ + words = glob_phrase.split(" "); + } + // EXECUTE CONTENT MATCH TEST + if( regex.test(glob_phrase) ) { // See if word is anywhere within the phrase first. + for( var ndx = 0; ndx < words.length; ndx++ ) { + if( w == words[ndx] ) { + contentHitCnt += getInstanceCount(lineNdx,ndx); + break; + } + //else if( w < words[ndx] ) { // If word is greater than the remaining words, leave + // break; + //} + } + } + + return titleHitCnt + contentHitCnt; +} +//--------------------------------------------------- +function checkForHitsWordAgainstTitleAndLine2(w, lineNdx) +{ + var titleHitCnt = 0; + var contentHitCnt = 0; + + // TITLE ......................................... + if( glob_title.indexOf(w) != -1 ) { + titleHitCnt = 100; + } + + // CONTENT ......................................... + contentHitCnt = indexesOf(glob_phrase,w); + + return titleHitCnt + contentHitCnt; +} +//--------------------------------------------------- +// checkTheInputString +// +// returns... +// empty string - if there is valid input to search +// message string - if there is NO VALID INPUT to search +//--------------------------------------------------- +function checkTheInputString() +{ + var myArr = new Array(); + var tempArr = new Array(); + var foundStopOrShortWord = 0; + var ptn1 = /\d\D/; + var ptn2 = /\D\d/; + + handleWhitespaceRemoval(); + searchTerm = searchTerm.replace (/(%20)+/g," ") ; + searchTerm = searchTerm.toLowerCase(); + + searchTerm = filterTheChars(searchTerm); + + handleWhitespaceRemoval(); + + if( searchTerm.length ) { + + // Split the searchTerm + tempArr = searchTerm.split(" ",100); + if(showInputStringAlerts){alert( "size of tempArr: " + tempArr.length );} + + // Handle periods + for( var ndx = 0; ndx < tempArr.length; ndx++ ) { + if( tempArr[ndx].charCodeAt(0) == 46 ) { // periods at the start of word + //tempArr[ndx] = tempArr[ndx].substr(1); // NOTE: We don't want to do this. (e.g. ".txt") + } + if( tempArr[ndx].charCodeAt(tempArr[ndx].length-1) == 46 ) { // end of word + tempArr[ndx] = tempArr[ndx].substr(0,tempArr[ndx].length-1); + } + } + + // Do stopwords and shortwords removal + for( var ndx = 0; ndx < tempArr.length; ndx++ ) { + var word = tempArr[ndx]; + if(showInputStringAlerts){alert( "Checking word: " + word );} + + if( ! sw[word] ) { + if( word.length < 2 ) { + foundStopOrShortWord = 1; + } + else if( (word.length > 2) || (ptn1.test(word) || ptn2.test(word)) ) { + myArr[myArr.length] = tempArr[ndx]; + } + else { + foundStopOrShortWord = 1; + } + } + else { + foundStopOrShortWord = 1; + } + } + + // Now reconstruct the searchTerm, based upon the 'myArr' + searchTerm = ""; + for( var ndx = 0; ndx < myArr.length; ndx++ ) { + searchTerm = searchTerm + myArr[ndx] + " "; + } + + handleWhitespaceRemoval(); + + if(showInputStringAlerts){alert( "FINAL SEARCH TERM: *" + searchTerm + "*" );} + + if( foundStopOrShortWord && ! searchTerm.length ) { + return MSG_stopAndShortWords; + } + srch_input_massaged = searchTerm; + return ""; + } + else { + return MSG_noSearchTermEntered; + } +} +//--------------------------------------------------- +function checkTheInputString2() // double-byte version +{ + var tempArr = new Array(); + + handleWhitespaceRemoval(); + searchTerm = searchTerm.toLowerCase(); + + if( searchTerm.length ) { + + // Split the searchTerm + tempArr = searchTerm.split(" ",100); + if(showInputStringAlerts){alert( "number of search terms: " + tempArr.length );} + + // Now reconstruct the searchTerm, based upon the 'tempArr' + searchTerm = ""; + for( var ndx = 0; ndx < tempArr.length; ndx++ ) { + searchTerm = searchTerm + tempArr[ndx] + " "; + } + handleWhitespaceRemoval(); + +if(showInputStringAlerts){alert( "Massaged search term: " + searchTerm );} + + srch_input_massaged = searchTerm; + return ""; + } + else { + return MSG_noSearchTermEntered; + } +} +//--------------------------------------------------- +function doIEsearch() +{ + var stStr = ""; + + document.forms[0].sh_term.value = srch_input_verbatim; + + if( srch_message.length ) { + document.getElementById("results").innerHTML = srch_message; + srch_message = ""; + } + else if( srch_1_shot ) { + srch_1_shot = 0; + + searchTerm = srch_input_massaged; + checkForHits(); // Sets: 'matchesArrIndices' and 'matchesArrHits' + + if( matchesArrIndices.length ) { // If there were matches/hits... /* Changed for CS4 */ + + stStr = "
    " + MSG_pagesContaining + "" + srch_input_massaged + "


    \n"; + + document.getElementById("results").innerHTML = stStr + buildHtmlResultsStr(); + } + else { /* Changed for CS4 */ + document.getElementById("results").innerHTML = MSG_noPagesContain + "" + srch_input_massaged + "

    "; + + } + //searching_message.style.visibility="visible"; + } + srch_input_verbatim = ""; +} +//--------------------------------------------------- +function getInstanceCount( lineIndex, wordIndex ) +{ + var instancesStr = instances[lineIndex]; // e.g. "1432931" + var ch = instancesStr.substr(wordIndex,1); + + return parseInt(ch); +} +//--------------------------------------------------- +function handleWhitespaceRemoval() +{ + var re_1 = /^\s/; + var re_2 = /\s$/; + var re_3 = /\s\s/; + var temp; + + // Remove leading whitespace + while( true ) { + temp = searchTerm.replace(re_1,""); + if( temp == searchTerm ) { + break; + } + searchTerm = temp; + } + // Remove trailing whitespace + while( true ) { + temp = searchTerm.replace(re_2,""); + if( temp == searchTerm ) { + break; + } + searchTerm = temp; + } + // Replace multiple contiguous spaces with a single space + while( searchTerm.search(re_3) != -1 ) { + temp = searchTerm.replace(re_3," "); + searchTerm = temp; + } +} +//-------------------------------------------------- +function isAcceptableChar(chrNdx) +{ + var acceptableChars = new Array( 32, 46, 95 ); // space, period, underscore + + for( var ndx = 0; ndx < acceptableChars.length; ndx++ ) { + if( chrNdx == acceptableChars[ndx] ) { + return true; + } + } + return false; +} +//-------------------------------------------------- +function indexesOf(str,ptn) +{ + var position = 0; + var hits = -1; + var start = -1; + + while( position != -1 ) { + position = str.indexOf(ptn, start+1); + hits += 1; + start = position; + } + return hits; +} +//-------------------------------------------------- +function filterTheChars(line) +{ + var retStr = "",tempStr; + var ch, chCode, retChr; + var ndx; + + for( ndx = 0; ndx < line.length; ndx++ ) { + ch = line.substr(ndx,1); + chCode = ch.charCodeAt(0); + + + if( (chCode >= 192) && (chCode <= 221) ) { // Handle capital upper-ASCII characters + chCode = chCode + 32; + retChr = ASCII_to_char(chCode); + } + else if( withinAcceptableRanges(chCode) || isAcceptableChar(chCode) ) { // Acceptable characters + retChr = ch; + } + else { + tempStr = isLigatureChar(chCode); + + if( tempStr.length ) { //Don't replace ligatures. + retChr = ch; + } + else { // Turn all else into space + retChr = " "; + } + } + + // Grow the return string + retStr += retChr; + } + + return retStr; +} +//-------------------------------------------------- +function isLigatureChar(codeToCheck) { + var xlatTblNdx, code, replStr = ""; + + for( xlatTblNdx = 0; xlatTblNdx < upperAsciiXlatTbl.length; xlatTblNdx+=2 ) { + + code = upperAsciiXlatTbl[xlatTblNdx]; + if( code == codeToCheck ) { + replStr = upperAsciiXlatTbl[xlatTblNdx+1]; + break; + } + } + + return replStr; +} +//-------------------------------------------------- +function respondToSearchButton() +{ + var myStr; + document.getElementById("results").innerHTML = ""; //We don't expect this to be slow enough to need a message. + srch_input_verbatim = document.forms[0].sh_term.value; + searchTerm = document.forms[0].sh_term.value; + + if( document.isDblByte ) { + myStr = checkTheInputString2(); + } + else { + myStr = checkTheInputString(); + } + + srch_message = myStr; + srch_1_shot = srch_message.length ? 0 : 1; + + doIEsearch(); +} +//-------------------------------------------------- +function respondToSearchLoad() +{ + var externalQuery = GetCookie("externalQuery"); + if (externalQuery == null) { + externalQuery = GetCookie("sh_term"); + } + + if (externalQuery != null) { + var myStr; + srch_input_verbatim = externalQuery; + searchTerm = externalQuery; + + if(document.isDblByte ) { + myStr = checkTheInputString2(); + } + else { + myStr = checkTheInputString(); + } + + srch_message = myStr; + srch_1_shot = srch_message.length ? 0 : 1; + + doIEsearch(); + } +} +//--------------------------------------------------- +function strReplace(orig,src,dest) +{ + var startPos=0; + var matchPos = orig.indexOf(src,startPos); + var retLine=""; + + while(matchPos != -1) { + retLine = retLine + orig.substring(startPos,matchPos) + dest; + startPos = matchPos+1; + matchPos = orig.indexOf(src,startPos); + } + if(! retLine.length) {return orig;} + else {return retLine+orig.substring(startPos,orig.length);} +} +//-------------------------------------------------- +function withinAcceptableRanges(chrNdx) +{ + var acceptableRanges = new Array( "48-57","65-90","97-122","224-229","231-239","241-246","248-253","255-255"); + + for( var ndx = 0; ndx < acceptableRanges.length; ndx++ ) { + var start_finish = new Array(); + + start_finish = acceptableRanges[ndx].split("-"); + + if( (chrNdx >= start_finish[0]) && (chrNdx <= start_finish[1]) ) { + return true; + } + } + return false; +} +//-------------------------------------------------- +function ASCII_to_char(num_in) +{ + var str_out = ""; + var num_out = parseInt(num_in); + + num_out = unescape('%' + num_out.toString(16)); + str_out += num_out; + + return unescape(str_out); +} +//-------------------------------------------------- +var agt=navigator.userAgent.toLowerCase(); +var use_ie_behavior = false; +var use_ie_6_behavior = false; +if (agt.indexOf("msie") != -1) { + use_ie_behavior = true; +} +if ((agt.indexOf("msie 5") != -1) || (agt.indexOf("msie 6") != -1)) { + use_ie_6_behavior = true; +} + +//-------------------------------------------------- + +var Url = { + + // public method for url encoding + encode : function (string) { + return escape(this._utf8_encode(string)); + }, + + // public method for url decoding + decode : function (string) { + return this._utf8_decode(unescape(string)); + }, + + // private method for UTF-8 encoding + _utf8_encode : function (string) { + string = string.replace(/\r\n/g,"\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } + else if((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } + else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }, + + // private method for UTF-8 decoding + _utf8_decode : function (utftext) { + var string = ""; + var i = 0; + var c = c1 = c2 = 0; + + while ( i < utftext.length ) { + + c = utftext.charCodeAt(i); + + if (c < 128) { + string += String.fromCharCode(c); + i++; + } + else if((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i+1); + string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } + else { + c2 = utftext.charCodeAt(i+1); + c3 = utftext.charCodeAt(i+2); + string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + + } + + return string; + } + +} diff --git a/documentation/api-reference/templates/images/AirIcon12x12.gif b/documentation/api-reference/templates/images/AirIcon12x12.gif new file mode 100644 index 0000000000..bc9ce69186 Binary files /dev/null and b/documentation/api-reference/templates/images/AirIcon12x12.gif differ diff --git a/documentation/api-reference/templates/images/P_AlternativeMetadataIndicator_30x28_N.png b/documentation/api-reference/templates/images/P_AlternativeMetadataIndicator_30x28_N.png new file mode 100644 index 0000000000..c59e19474b Binary files /dev/null and b/documentation/api-reference/templates/images/P_AlternativeMetadataIndicator_30x28_N.png differ diff --git a/documentation/api-reference/templates/images/collapsed.gif b/documentation/api-reference/templates/images/collapsed.gif new file mode 100644 index 0000000000..f803408c6e Binary files /dev/null and b/documentation/api-reference/templates/images/collapsed.gif differ diff --git a/documentation/api-reference/templates/images/detailHeaderRule.jpg b/documentation/api-reference/templates/images/detailHeaderRule.jpg new file mode 100644 index 0000000000..e73a03b5f8 Binary files /dev/null and b/documentation/api-reference/templates/images/detailHeaderRule.jpg differ diff --git a/documentation/api-reference/templates/images/detailSectionHeader.jpg b/documentation/api-reference/templates/images/detailSectionHeader.jpg new file mode 100644 index 0000000000..4979b551fd Binary files /dev/null and b/documentation/api-reference/templates/images/detailSectionHeader.jpg differ diff --git a/documentation/api-reference/templates/images/expanded.gif b/documentation/api-reference/templates/images/expanded.gif new file mode 100644 index 0000000000..33779b0a1a Binary files /dev/null and b/documentation/api-reference/templates/images/expanded.gif differ diff --git a/documentation/api-reference/templates/images/inherit-arrow.gif b/documentation/api-reference/templates/images/inherit-arrow.gif new file mode 100644 index 0000000000..bfb4ea7d85 Binary files /dev/null and b/documentation/api-reference/templates/images/inherit-arrow.gif differ diff --git a/documentation/api-reference/templates/images/inheritedSummary.gif b/documentation/api-reference/templates/images/inheritedSummary.gif new file mode 100644 index 0000000000..800b34b2fa Binary files /dev/null and b/documentation/api-reference/templates/images/inheritedSummary.gif differ diff --git a/documentation/api-reference/templates/images/logo.jpg b/documentation/api-reference/templates/images/logo.jpg new file mode 100644 index 0000000000..5840dcf345 Binary files /dev/null and b/documentation/api-reference/templates/images/logo.jpg differ diff --git a/documentation/api-reference/templates/images/titleTableBottom.jpg b/documentation/api-reference/templates/images/titleTableBottom.jpg new file mode 100644 index 0000000000..5c7c510918 Binary files /dev/null and b/documentation/api-reference/templates/images/titleTableBottom.jpg differ diff --git a/documentation/api-reference/templates/images/titleTableMiddle.jpg b/documentation/api-reference/templates/images/titleTableMiddle.jpg new file mode 100644 index 0000000000..c878113681 Binary files /dev/null and b/documentation/api-reference/templates/images/titleTableMiddle.jpg differ diff --git a/documentation/api-reference/templates/images/titleTableTop.jpg b/documentation/api-reference/templates/images/titleTableTop.jpg new file mode 100644 index 0000000000..f858cdf563 Binary files /dev/null and b/documentation/api-reference/templates/images/titleTableTop.jpg differ diff --git a/documentation/api-reference/templates/index-list.html b/documentation/api-reference/templates/index-list.html new file mode 100644 index 0000000000..aa8f36fabe --- /dev/null +++ b/documentation/api-reference/templates/index-list.html @@ -0,0 +1,71 @@ + + + ActionScript 3.0 Language and Components Reference + + + + + +

    Index +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AN
    BO
    CP
    DQ
    ER
    FS
    GT
    HU
    IV
    JW
    KX
    LY
    MZ
    + diff --git a/documentation/api-reference/templates/index.html b/documentation/api-reference/templates/index.html new file mode 100644 index 0000000000..e9ba6d84f5 --- /dev/null +++ b/documentation/api-reference/templates/index.html @@ -0,0 +1,40 @@ + + + ActionScript 3.0 Language and Components Reference + + + + + + + + + + <body> + <h2>Frame Alert</h2> + <p> + This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. + <br /> + Link to <a href="package-summary.html">Non-frame version.</a> + </p> + </body> + + + diff --git a/documentation/api-reference/templates/merge_dita_xml.xslt b/documentation/api-reference/templates/merge_dita_xml.xslt new file mode 100644 index 0000000000..37f7bb991e --- /dev/null +++ b/documentation/api-reference/templates/merge_dita_xml.xslt @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/methodSummary.xslt b/documentation/api-reference/templates/methodSummary.xslt new file mode 100644 index 0000000000..854a2e604e --- /dev/null +++ b/documentation/api-reference/templates/methodSummary.xslt @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + +

    +
    + + + + + + +
    +
    + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/documentation/api-reference/templates/mxml-tags.html b/documentation/api-reference/templates/mxml-tags.html new file mode 100644 index 0000000000..c917f3a1af --- /dev/null +++ b/documentation/api-reference/templates/mxml-tags.html @@ -0,0 +1,19 @@ + + + + MXML Only Components - Adobe Flex 3 Language Reference + + + +

    MXML Only Components

    + <mx:Binding>
    + <mx:Component>
    + <mx:Metadata>
    + <mx:Model>
    + <mx:Script>
    + <mx:Style>
    + <mx:XML>
    + <mx:XMLList>
    + + + diff --git a/documentation/api-reference/templates/override.css b/documentation/api-reference/templates/override.css new file mode 100644 index 0000000000..fa359d70d6 --- /dev/null +++ b/documentation/api-reference/templates/override.css @@ -0,0 +1,12 @@ +/* +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// +*/ \ No newline at end of file diff --git a/documentation/api-reference/templates/package-detail.xslt b/documentation/api-reference/templates/package-detail.xslt new file mode 100644 index 0000000000..7bd81808ad --- /dev/null +++ b/documentation/api-reference/templates/package-detail.xslt @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + package-detail.html + + /package-detail.html + + + + + class-list.html + + /class-list.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + #config errmsg="" + + + + + + + + + <xsl:if test="$isTopLevel='true'"> + <xsl:value-of select="$asdoc_terms/row[entry[1][p/text() = 'TopLevelConstantsFunctions']]/entry[2]/p"/> + </xsl:if> + <xsl:if test="$isTopLevel='false'"> + <xsl:value-of select="$name"/> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:value-of select="$asdoc_terms/row[entry[1][p/text() = 'Summary']]/entry[2]/p"/> + <xsl:call-template name="getPageTitlePostFix"/> + + + + + + eclipseBody + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    + BEGIN IONCOMMENTS +
    + END IONCOMMENTS + #include virtual="ionComments.ssi" +

    + + + +

    + #include virtual="/livedocs/googleAnalytics.ssi" + #include virtual="/ubi/analytics/analytics_ssi.html" + +
    +
    + +
    +
    +
    +
    +
    +
    +
    diff --git a/documentation/api-reference/templates/package-frame.html b/documentation/api-reference/templates/package-frame.html new file mode 100644 index 0000000000..199b29cf4d --- /dev/null +++ b/documentation/api-reference/templates/package-frame.html @@ -0,0 +1,18 @@ + + + ActionScript 3.0 Language and Components Reference + + + + + + <body> + <h2>Frame Alert</h2> + <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. + <br /> + Link to<a href="package-summary.html">Non-frame version.</a> + </p> + </body> + + + \ No newline at end of file diff --git a/documentation/api-reference/templates/package-list.xslt b/documentation/api-reference/templates/package-list.xslt new file mode 100644 index 0000000000..86fb70f377 --- /dev/null +++ b/documentation/api-reference/templates/package-list.xslt @@ -0,0 +1,200 @@ + + + + + + + + + + + + + <xsl:value-of select="$asdoc_terms/row[entry[1][p/text() = 'PackageList']]/entry[2]/p"/> - <xsl:value-of select="$title-base"/> + + + + + + + + + + + + + + + + + + + +
    + + + + + + + +
    + +
    + + + #include virtual="/livedocs/flex/3/langref/ionsearchform.ssi" + + + + +
    + + + + + + +
    + +
    + +   + +
    +
    + + + + +   + + +   + + + + + + +   + + +   + + + + + + + + + Index + + + + + + + + + + + + + + + + + + + + allClasses + + + + + allPackages + + + + + LanguageElements + + + + + Appendix + + + + + Index + + + + + Conventions + + + + + NoFrames + + + + + Properties + + + + + Constructor + + + + + Methods + + + + + Functions + + + + + Events + + + + + Effects + + + + + Constants + + + + + Interfaces + + + + + Classes + + + + + Examples + + + + + Styles + + + + + + SkinStates + + + + + SkinParts + + + + + + Symbols + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 80,* + + + + + 40%,60% + + + + + + + + + + + + + + + +
    diff --git a/documentation/api-reference/templates/style.css b/documentation/api-reference/templates/style.css new file mode 100644 index 0000000000..2e8a45291d --- /dev/null +++ b/documentation/api-reference/templates/style.css @@ -0,0 +1,578 @@ +/* +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// +*/ + +.titleTable { + width: 100%; +} +.titleTableTitle { + white-space: nowrap; + padding-left: 15px; + padding-right: 5px; + font-size: 13px; + height: 44px; + background-image: url(images/titleTableTop.jpg); + background-repeat: repeat-x; +} +.titleTableSearch { + white-space: nowrap; + background-image: url(images/titleTableTop.jpg); + background-repeat: repeat-x; + padding-right: 10px; + width: 220; +} +.searchForm { + margin-top: 0px; + margin-bottom: 0px; +} +.titleTableTopNav { + font-size: 12px; + background-image: url(images/titleTableTop.jpg); + background-repeat: repeat-x; +} +.titleTableLogo { + width: 76px; + height: 80px; + vertical-align: top; +} +.titleTableRow2 { + color: #000000; + height: 31px; + background-image: url(images/titleTableMiddle.jpg); + background-repeat: repeat-x; +} +.titleTableSubTitle { + font-size: 20px; + padding-left: 15px; + padding-right: 5px; +} +.titleTableSubNav { + //white-space: nowrap; + font-size: 12px; +} +.titleTableRow3 { + height: 5px; + background-image: url(images/titleTableBottom.jpg); + background-repeat: repeat-x; +} +.logoImage { + width: 76px; + height: 80px; +} + +.classHeaderTable { + margin-top: 20px; +} +.classHeaderTable td { + vertical-align: top; + padding-bottom: 4px; +} +.classHeaderTableLabel { + font-weight: bold; + padding-right: 15px; +} +.classSignature { + text-indent: -20px; + padding-left: 20px; +} +.inheritanceList { + text-indent: -20px; + padding-left: 20px; +} +.inheritArrow { + width: 15px; + height: 9px; +} +.mxmlSyntax { + margin-bottom: -13px; +} +.collapsedImage { + width: 9px; + height: 9px; + border: 0; +} +.expandedImage { + width: 9px; + height: 9px; + border: 0; +} +.classFrameContent { + margin-right: 5px; + margin-left: 10px; + margin-top: 10px; + margin-bottom: 10px; +} +.classFrameContent td { + white-space: nowrap; + padding-right: 5px; +} + +.eclipseBody { + display: none; +} + +/** html { + overflow-y:scroll; +}*/ + +img { + border:0; +} + +.annotation { + font-size: 20px; + margin-top: 20px; +} + +.label { + color: #444444; + font-weight: bold; +} + +strong { + color: #444444; +} + +.summarySection { + margin-left: 20px; + margin-right: 10px; +} +.summaryTableTitle { + font-weight: bold; + font-size: 18px; + padding-top: 20px; + padding-bottom: 5px; +} +* .summaryTable { + margin-top: 10px; + border: #999999 1px solid; + width: 100%; + margin-bottom: 20px; +} +html>body .summaryTable { + margin-top: 10px; + border: #999999 1px solid; + width: 100%; + margin-bottom: 20px; + margin-right: 10px; +} +.summaryTable th { + color: #FFFFFF; + background-color: #627C9D; + white-space: nowrap; +} +.summaryTable td { + border-top: #999999 1px solid; + vertical-align: top; +} +.summaryTablePaddingCol { + width: 5px; +} +.summaryTableInheritanceCol { + width: 14px; +} +.summaryTableSignatureCol { + padding-right: 10px; +} +.summaryTableOperatorCol { + padding-left: 10px; + padding-right: 10px; + font-weight: bold; +} +.summaryTableStatementCol { + padding-left: 10px; + padding-right: 10px; + font-weight: bold; + white-space: nowrap; +} +.summarySignature { + text-indent: -20px; + padding-left: 20px; +} +.summaryTableOwnerCol { + padding-right: 10px; + width: 10px; +} +.summaryTableCol, .summaryTableSecondCol { +} +.signatureLink { + font-weight: bold; +} +.summaryTableDescription { + color: #333333; +} +.summaryTableLastCol { + padding-right: 10px; +} +.inheritedSummaryImage { + width: 14px; + height: 14px; +} + +.showHideLink { +} +.showHideLinkImage { + width: 9px; + height: 9px; +} +.hideInheritedConstant { + display: none; +} +.showInheritedConstant { + display: inline; +} +.hideInheritedProtectedConstant { + display: none; +} +.showInheritedProtectedConstant { + display: inline; +} +.hideInheritedProperty { + display: none; +} +.showInheritedProperty { + display: inline; +} +.hideInheritedProtectedProperty { + display: none; +} +.showInheritedProtectedProperty { + display: inline; +} +.hideInheritedMethod { + display: none; +} +.showInheritedMethod { + display: inline; +} +.hideInheritedProtectedMethod { + display: none; +} +.showInheritedProtectedMethod { + display: inline; +} +.hideInheritedEvent { + display: none; +} +.showInheritedEvent { + display: inline; +} +.hideInheritedStyle { + display: none; +} +.showInheritedStyle { + display: inline; +} +.hideInheritedEffect { + display: none; +} +.showInheritedEffect { + display: inline; +} + + +.detailSectionHeader { + color: #434343; + font-size: 18px; + padding-left: 10px; + padding-top: 4px; + padding-bottom: 4px; + margin-top: 40px; + margin-bottom: 3px; + background-image: url(images/detailSectionHeader.jpg); + background-repeat: repeat-x; +} +.detailHeader { + margin-left: 20px; + margin-top: 10px; + margin-bottom: 3px; +} +.detailHeaderName { + font-weight: bold; + font-size: 16px; + vertical-align: baseline; + white-space: nowrap; +} +.detailHeaderType { + font-size: 12px; + vertical-align: baseline; + padding-right: 10px; + padding-left: 7px; + white-space: nowrap; +} +.detailHeaderParens { + font-size: 14px; + font-weight: bold; + padding-left: 1px; + padding-bottom: 2px; +} +.detailHeaderRule { + background-image: url(images/detailHeaderRule.jpg); + background-repeat: repeat-x; + width: 100%; + background-position: 50%; +} +.detailBody { + margin-left: 20px; + margin-right: 15px; + margin-bottom: 20px; +} +.exampleHeader { + background-color: #C8D1DF; + padding-left: 10px; + padding-top: 3px; + padding-bottom: 3px; +} + +.seeAlso { + margin-top: -13px; + padding-left: 20px; +} + +/* +#header { + padding: 0; + margin: 0; + border: 2px solid +} +*/ + +body { + font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; + color: #000000; + background-color:#FFFFFF; + margin: 0px; + padding: 0px; +} + +body, td, th { + font-size: 13px; +} + +.MainContent { + margin-left: 20px; + margin-right: 10px; + margin-bottom: 10px; +} + +code { + font-family: "Lucida Console", "Courier New", Courier, monospace; + font-size: 12px; +} +pre { + font-family: "Lucida Console", "Courier New", Courier, monospace; + font-size: 12px; +} + +th { + text-align: left; + font-weight: bold; + vertical-align: bottom; +} + +table { + background-color: white; +} + +table.withBorder { + border-color: #BBBBBB; + border-width: 1px; + border-style: solid; +} + +.innertable { + border-collapse: collapse; /* to eliminate the default table cellspacing=2 */ +} + +.innertable th { + border: 1px solid #000000; + background:#DDDDDD; + padding: 2px 3px 2px 3px; +} + +.innertable td { + border: 1px solid #000000; + padding: 2px 3px 2px 3px; +} + +.paramSpacer { + font-size: 5px; +} + +/* Custom Classes */ +.row0 { + background-color: #F2F2F2; +} + +.row1 { + background-color: #FFFFFF; +} + +.prow0 { + background-color: #F2F2F2; +} + +.prow1 { + background-color: #FFFFFF; +} + +.idxrow { + padding-top: 5px; +} + +.SummaryTableHeader { + background-color: #CCCCCC; +} + +.InheritedTableHeader { + background-color: #EEEEEE; +} + +.PackageTableHeader { + background-color: #EEEEEE; +} + + +/* Links */ +a:link { + color: #0000CC; + text-decoration: none; +} + +a:visited { + color: #0000CC; + text-decoration: none; +} + +a:hover { + text-decoration: underline; + color: #0000CC; +} + +a:active { + text-decoration: none; + color: #CC0000; +} + +/* Headings */ +h1, h2, h3, h4, h5, h6 { + font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif; + font-weight: bold; + margin-top: 3px; + margin-bottom: 3px; + letter-spacing: 1px; + width: 90%; +} + +h1 { + font-size: 18px; +} + +h2 { + font-size: 16px; +} + +h3 { + font-size: 14px; +} + +h4 { + font-size: 12px; + color: #666666; +} + +h5 { + font-size: 11px; +} +.copyright { + margin-top: 30px; + color: #777777; + font-size: 10px; + padding-bottom: 5px; +} +.inheritanceList { + line-height: 19px; +} +.private { + color: #999999; +} +.flashonly { + color: #000000; +} +.flexonly { + display:none; + color: #000000; +} +.hide { + display:none; +} +.feedbackLink { +/* display:none; */ +} + +/* IE */ +* html .listing { + width: 93%; + padding-left: 6%; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 5px; + overflow-x: auto; + background-color: #F2F2F2; + margin-bottom: 10px; + margin-top: 10px; + font-family: "Lucida Console", "Courier New", Courier, monospace; + font-size: 12px; +} + +/* Firefox, Netscape */ +html>body .listing pre +{ + overflow: auto; + padding-left: 40px; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 5px; + background-color: #F2F2F2; + margin-top: 10px; + margin-bottom: 10px; + font-family: "Lucida Console", "Courier New", Courier, monospace; + font-size: 12px; +} + +.listingIcons +{ + padding: 0px; + margin-top: 10px; + height: 15px; +} + +.pageTop +{ + height:10px; +} + +.hideInheritedSkinState { + display: none; +} + +.showInheritedSkinState { + display: inline; +} + +.hideInheritedSkinPart { + display: none; +} + +.showInheritedSkinPart { + display: inline; +} diff --git a/documentation/api-reference/templates/stylesSummary.xslt b/documentation/api-reference/templates/stylesSummary.xslt new file mode 100644 index 0000000000..230e09c85d --- /dev/null +++ b/documentation/api-reference/templates/stylesSummary.xslt @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/api-reference/templates/title-bar.html b/documentation/api-reference/templates/title-bar.html new file mode 100644 index 0000000000..58707a2805 --- /dev/null +++ b/documentation/api-reference/templates/title-bar.html @@ -0,0 +1,42 @@ + + + ActionScript 3.0 Language Reference + + + + + + +$for(include-before)$ +$include-before$ +$endfor$ +$if(toc)$ + +$endif$ +$body$ +$for(include-after)$ +$include-after$ +$endfor$ + + diff --git a/documentation/help/wiki/migrating-themes.html b/documentation/help/wiki/migrating-themes.html new file mode 100644 index 0000000000..6d300e11af --- /dev/null +++ b/documentation/help/wiki/migrating-themes.html @@ -0,0 +1,180 @@ + +

    Migrating legacy themes to Feathers 2.0

    +
    + +

    +Feathers 2.0 includes a new skinning architecture. The DisplayListWatcher class that legacy themes extended still exists, and you can continue using it for the foreseeable future. However, if you're ready to modernize your theme to take advantage of the new style provider system, you will need to make a number of fundamental changes to your themes. +

    + +
    + +

    Extend a new class: StyleNameFunctionTheme

    +
    + +

    +A legacy theme will extend the feathers.core.DisplayListWatcher class. +

    +
    // legacy
    +public class CustomTheme extends DisplayListWatcher
    + +

    +To create a modern theme, extend feathers.themes.StyleNameFunctionTheme instead. +

    +
    // modern
    +public class CustomTheme extends StyleNameFunctionTheme
    + +

    +After this change, if you try to compile, you will probably see a number of errors. We need to make a few more changes, but they're pretty straightforward. +

    + +
    + +

    Replace calls to setInitializerForClass()

    +
    + +

    +The modern StyleNameFunctionTheme still calls functions that set properties on components, similar to legacy themes. You can still use strings (called style names) to differentiate between components of the same type that need to have different appearances. The API has changed a bit for setting these functions, though. +

    + +

    +In a legacy theme, you might call setInitializerForClass() and pass in a class and a function. You could optionally pass in a style name as the optional third argument, to specify function for alternate styles: +

    +
    // legacy
    +this.setInitializerForClass( Button, setButtonStyles );
    +this.setInitializerForClass( Button, setCustomButtonStyles, "my-custom-button" );
    + +

    +In a modern theme, you first ask for then global style provider for a specific class. Then, you can either set its default style function or set a function for a specific style name: +

    +
    // modern
    +this.getStyleProviderForClass(Button).defaultStyleFunction = setButtonStyles;
    +this.getStyleProviderForClass(Button).setFunctionForStyleName( "my-custom-button", setCustomButtonStyles );
    + +
    + +

    The quick-and-dirty way

    +
    + +

    +Replacing every call to setInitializerForClass() can be time consuming and tedious. If you need to migrate faster, and you want to worry about cleaning things up later, you can copy the following function into your theme class: +

    +
    public function setInitializerForClass(type:Class, styleFunction:Function, styleName:String = null):void
    +{
    +	var styleProvider:StyleNameFunctionStyleProvider = this.getStyleProviderForClass(type);
    +	if(styleName)
    +	{
    +		styleProvider.setFunctionForStyleName(styleName, styleFunction);
    +	}
    +	else
    +	{
    +		styleProvider.defaultStyleFunction = styleFunction;
    +	}
    +}
    + +

    +As you can see, it implements setInitializerForClass() with the same function signature, but it uses style providers under the hood. +

    + +
    + +

    Replace calls to setInitializerForClassAndSubclasses()

    +
    + +

    +There is no direct replacement for this function. It mainly existed to work around limitations in the legacy architecture where a subclass wouldnt be automatically skinned like its superclass. A modern theme will treat subclasses the same as their superclasses (unless a component chooses to opt out), so this function is no longer necessary for its original purpose. +

    + +

    +Here's an example of calling setInitializerForClassAndSubclasses() in a legacy theme: +

    +
    // legacy
    +this.setInitializerForClassAndSubclasses( Scroller, setScrollerStyles );
    + +

    +You should switch to calling that function directly when you style the subclasses. For instance, if you have a function that sets common styles on the Scroller class, you would call that function in a function that sets specific styles on the List class. +

    +
    // modern
    +protected function setListStyles( list:List ):void
    +{
    +	this.setScrollerStyles( list );
    + 
    +	// set other styles here
    +}
    + +

    +When an instance of the List class (or any of its subclasses) needs to be styled, setScrollerStyles() will be called too. +

    + +
    + +

    Replace calls to exclude()

    +
    + +

    +In a legacy theme, you could exclude a component from being skinned by passing it to the exclude() function defined by DisplayListWatcher. +

    +
    // legacy
    +theme.exclude( button );
    + +

    +In a modern theme, you can remove a component's style provider: +

    +
    // modern
    +button.styleProvider = null;
    + +

    +Make sure you do that before the component initializes. That's when the theme is asked to style the component. By default, a component will initialize when it is added to the stage. +

    + +
    + +

    Replace name and nameList with styleName and styleNameList

    +
    + +

    +In order to fix some issues developers had using getChildByName(), Feathers no longer uses the name and nameList properties to indicate to the theme that it should give a component an alternate visual appearance. +

    + +

    +In a legacy theme, you would add a string to the nameList property (or set the name property directly): +

    +
    // legacy
    +button.nameList.add( "my-custom-button" );
    +// or
    +button.name = "my-custom-button";
    + +

    +In a modern theme, you should use the styleNameList or styleName properties instead: +

    +
    // modern
    +button.styleNameList.add( "my-custom-button" );
    +// or
    +button.styleName = "my-custom-button";
    + +

    +The nameList property still exists, temporarily. It simply maps to the styleNameList property so that legacy code will continue to work. However, the nameList property is considered deprecated, and it will be removed in a future version of Feathers. +

    + +

    +The name property is no longer used for styling Feathers components at all. It does not map to the styleName property the way that nameList maps to the styleNameList property. This change makes a strict distinction between name and styleName in order to fix issues using getChildByName() with Feathers components. +

    + +
    + + + + \ No newline at end of file diff --git a/examples/ComponentsExplorer/README.md b/examples/ComponentsExplorer/README.md new file mode 100644 index 0000000000..f688f48674 --- /dev/null +++ b/examples/ComponentsExplorer/README.md @@ -0,0 +1,13 @@ +# Feathers Components Explorer + +A little bit of everything in [Feathers](http://feathersui.com/), presented as a mobile app. Includes screens for each component, with configurable options. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Components Explorer](http://feathersui.com/examples/components-explorer/) in your browser. \ No newline at end of file diff --git a/examples/ComponentsExplorer/assets/images/icons-readme.txt b/examples/ComponentsExplorer/assets/images/icons-readme.txt new file mode 100644 index 0000000000..d72dc7c13a --- /dev/null +++ b/examples/ComponentsExplorer/assets/images/icons-readme.txt @@ -0,0 +1 @@ +Icons by Glyphish - glyphish.com \ No newline at end of file diff --git a/examples/ComponentsExplorer/assets/images/skull-white.png b/examples/ComponentsExplorer/assets/images/skull-white.png new file mode 100644 index 0000000000..5dd4d91107 Binary files /dev/null and b/examples/ComponentsExplorer/assets/images/skull-white.png differ diff --git a/examples/ComponentsExplorer/assets/images/skull.png b/examples/ComponentsExplorer/assets/images/skull.png new file mode 100644 index 0000000000..805ea694f6 Binary files /dev/null and b/examples/ComponentsExplorer/assets/images/skull.png differ diff --git a/examples/ComponentsExplorer/build.properties b/examples/ComponentsExplorer/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/ComponentsExplorer/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/ComponentsExplorer/build.xml b/examples/ComponentsExplorer/build.xml new file mode 100644 index 0000000000..6178b4c7f9 --- /dev/null +++ b/examples/ComponentsExplorer/build.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ComponentsExplorer/sdk.properties b/examples/ComponentsExplorer/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/ComponentsExplorer/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/ComponentsExplorer-app.xml b/examples/ComponentsExplorer/source/ComponentsExplorer-app.xml new file mode 100644 index 0000000000..0b9f03b01b --- /dev/null +++ b/examples/ComponentsExplorer/source/ComponentsExplorer-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.ComponentsExplorer + Feathers Components + Feathers Components + 2.0.1 + Components Explorer example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + ComponentsExplorer.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/ComponentsExplorer.as b/examples/ComponentsExplorer/source/ComponentsExplorer.as new file mode 100644 index 0000000000..4a88edb291 --- /dev/null +++ b/examples/ComponentsExplorer/source/ComponentsExplorer.as @@ -0,0 +1,155 @@ +package +{ + import feathers.examples.componentsExplorer.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class ComponentsExplorer extends Sprite + { + public function ComponentsExplorer() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/ComponentsExplorerWeb.as b/examples/ComponentsExplorer/source/ComponentsExplorerWeb.as new file mode 100644 index 0000000000..8d59c67cd7 --- /dev/null +++ b/examples/ComponentsExplorer/source/ComponentsExplorerWeb.as @@ -0,0 +1,59 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class ComponentsExplorerWeb extends MovieClip + { + public function ComponentsExplorerWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.componentsExplorer.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/Main.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/Main.as new file mode 100644 index 0000000000..407c4b586f --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/Main.as @@ -0,0 +1,289 @@ +package feathers.examples.componentsExplorer +{ + import feathers.controls.Drawers; + import feathers.controls.ScreenNavigator; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.StackScreenNavigator; + import feathers.controls.StackScreenNavigatorItem; + import feathers.examples.componentsExplorer.data.EmbeddedAssets; + import feathers.examples.componentsExplorer.data.GroupedListSettings; + import feathers.examples.componentsExplorer.data.ItemRendererSettings; + import feathers.examples.componentsExplorer.data.ListSettings; + import feathers.examples.componentsExplorer.data.NumericStepperSettings; + import feathers.examples.componentsExplorer.data.SliderSettings; + import feathers.examples.componentsExplorer.screens.AlertScreen; + import feathers.examples.componentsExplorer.screens.ButtonGroupScreen; + import feathers.examples.componentsExplorer.screens.ButtonScreen; + import feathers.examples.componentsExplorer.screens.CalloutScreen; + import feathers.examples.componentsExplorer.screens.GroupedListScreen; + import feathers.examples.componentsExplorer.screens.GroupedListSettingsScreen; + import feathers.examples.componentsExplorer.screens.ItemRendererScreen; + import feathers.examples.componentsExplorer.screens.ItemRendererSettingsScreen; + import feathers.examples.componentsExplorer.screens.LabelScreen; + import feathers.examples.componentsExplorer.screens.ListScreen; + import feathers.examples.componentsExplorer.screens.ListSettingsScreen; + import feathers.examples.componentsExplorer.screens.MainMenuScreen; + import feathers.examples.componentsExplorer.screens.NumericStepperScreen; + import feathers.examples.componentsExplorer.screens.NumericStepperSettingsScreen; + import feathers.examples.componentsExplorer.screens.PageIndicatorScreen; + import feathers.examples.componentsExplorer.screens.PickerListScreen; + import feathers.examples.componentsExplorer.screens.ProgressBarScreen; + import feathers.examples.componentsExplorer.screens.ScrollTextScreen; + import feathers.examples.componentsExplorer.screens.SliderScreen; + import feathers.examples.componentsExplorer.screens.SliderSettingsScreen; + import feathers.examples.componentsExplorer.screens.TabBarScreen; + import feathers.examples.componentsExplorer.screens.TextInputScreen; + import feathers.examples.componentsExplorer.screens.ToggleScreen; + import feathers.examples.componentsExplorer.themes.ComponentsExplorerTheme; + import feathers.motion.transitions.Cover; + import feathers.motion.transitions.Reveal; + import feathers.motion.transitions.ScreenSlidingStackTransitionManager; + import feathers.motion.transitions.Slide; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.events.Event; + + public class Main extends Drawers + { + private static const MAIN_MENU:String = "mainMenu"; + private static const ALERT:String = "alert"; + private static const BUTTON:String = "button"; + private static const BUTTON_SETTINGS:String = "buttonSettings"; + private static const BUTTON_GROUP:String = "buttonGroup"; + private static const CALLOUT:String = "callout"; + private static const GROUPED_LIST:String = "groupedList"; + private static const GROUPED_LIST_SETTINGS:String = "groupedListSettings"; + private static const ITEM_RENDERER:String = "itemRenderer"; + private static const ITEM_RENDERER_SETTINGS:String = "itemRendererSettings"; + private static const LABEL:String = "label"; + private static const LIST:String = "list"; + private static const LIST_SETTINGS:String = "listSettings"; + private static const NUMERIC_STEPPER:String = "numericStepper"; + private static const NUMERIC_STEPPER_SETTINGS:String = "numericStepperSettings"; + private static const PAGE_INDICATOR:String = "pageIndicator"; + private static const PICKER_LIST:String = "pickerList"; + private static const PROGRESS_BAR:String = "progressBar"; + private static const SCROLL_TEXT:String = "scrollText"; + private static const SLIDER:String = "slider"; + private static const SLIDER_SETTINGS:String = "sliderSettings"; + private static const TAB_BAR:String = "tabBar"; + private static const TEXT_INPUT:String = "textInput"; + private static const TOGGLES:String = "toggles"; + + private static const MAIN_MENU_EVENTS:Object = + { + showAlert: ALERT, + showButton: BUTTON, + showButtonGroup: BUTTON_GROUP, + showCallout: CALLOUT, + showGroupedList: GROUPED_LIST, + showItemRenderer: ITEM_RENDERER, + showLabel: LABEL, + showList: LIST, + showNumericStepper: NUMERIC_STEPPER, + showPageIndicator: PAGE_INDICATOR, + showPickerList: PICKER_LIST, + showProgressBar: PROGRESS_BAR, + showScrollText: SCROLL_TEXT, + showSlider: SLIDER, + showTabBar: TAB_BAR, + showTextInput: TEXT_INPUT, + showToggles: TOGGLES + }; + + public function Main() + { + super(); + } + + private var _navigator:StackScreenNavigator; + private var _menu:MainMenuScreen; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + EmbeddedAssets.initialize(); + + new ComponentsExplorerTheme(); + + this._navigator = new StackScreenNavigator(); + this.content = this._navigator; + + var alertItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(AlertScreen); + alertItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(ALERT, alertItem); + + var buttonItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ButtonScreen); + buttonItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(BUTTON, buttonItem); + + var buttonGroupItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ButtonGroupScreen); + buttonGroupItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(BUTTON_GROUP, buttonGroupItem); + + var calloutItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(CalloutScreen); + calloutItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(CALLOUT, calloutItem); + + var groupedListSettings:GroupedListSettings = new GroupedListSettings(); + var groupedListItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(GroupedListScreen); + groupedListItem.setScreenIDForPushEvent(GroupedListScreen.SHOW_SETTINGS, GROUPED_LIST_SETTINGS); + groupedListItem.addPopEvent(Event.COMPLETE); + groupedListItem.properties.settings = groupedListSettings; + this._navigator.addScreen(GROUPED_LIST, groupedListItem); + + var groupedListSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(GroupedListSettingsScreen); + groupedListSettingsItem.addPopEvent(Event.COMPLETE); + groupedListSettingsItem.properties.settings = groupedListSettings; + //custom push and pop transitions for this settings screen + groupedListSettingsItem.pushTransition = Cover.createCoverUpTransition(); + groupedListSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(GROUPED_LIST_SETTINGS, groupedListSettingsItem); + + var itemRendererSettings:ItemRendererSettings = new ItemRendererSettings(); + var itemRendererItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ItemRendererScreen); + itemRendererItem.setScreenIDForPushEvent(ItemRendererScreen.SHOW_SETTINGS, ITEM_RENDERER_SETTINGS); + itemRendererItem.addPopEvent(Event.COMPLETE); + itemRendererItem.properties.settings = itemRendererSettings; + this._navigator.addScreen(ITEM_RENDERER, itemRendererItem); + + var itemRendererSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ItemRendererSettingsScreen); + itemRendererSettingsItem.addPopEvent(Event.COMPLETE); + itemRendererSettingsItem.properties.settings = itemRendererSettings; + //custom push and pop transitions for this settings screen + itemRendererSettingsItem.pushTransition = Cover.createCoverUpTransition(); + itemRendererSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(ITEM_RENDERER_SETTINGS, itemRendererSettingsItem); + + var labelItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(LabelScreen); + labelItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(LABEL, labelItem); + + var listSettings:ListSettings = new ListSettings(); + var listItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ListScreen); + listItem.setScreenIDForPushEvent(ListScreen.SHOW_SETTINGS, LIST_SETTINGS); + listItem.addPopEvent(Event.COMPLETE); + listItem.properties.settings = listSettings; + this._navigator.addScreen(LIST, listItem); + + var listSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ListSettingsScreen); + listSettingsItem.addPopEvent(Event.COMPLETE); + listSettingsItem.properties.settings = listSettings; + //custom push and pop transitions for this settings screen + listSettingsItem.pushTransition = Cover.createCoverUpTransition(); + listSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(LIST_SETTINGS, listSettingsItem); + + var numericStepperSettings:NumericStepperSettings = new NumericStepperSettings(); + var numericStepperItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(NumericStepperScreen); + numericStepperItem.setScreenIDForPushEvent(NumericStepperScreen.SHOW_SETTINGS, NUMERIC_STEPPER_SETTINGS); + numericStepperItem.addPopEvent(Event.COMPLETE); + numericStepperItem.properties.settings = numericStepperSettings; + this._navigator.addScreen(NUMERIC_STEPPER, numericStepperItem); + + var numericStepperSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(NumericStepperSettingsScreen); + numericStepperSettingsItem.addPopEvent(Event.COMPLETE); + numericStepperSettingsItem.properties.settings = numericStepperSettings; + //custom push and pop transitions for this settings screen + numericStepperSettingsItem.pushTransition = Cover.createCoverUpTransition(); + numericStepperSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(NUMERIC_STEPPER_SETTINGS, numericStepperSettingsItem); + + var pageIndicatorItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(PageIndicatorScreen); + pageIndicatorItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(PAGE_INDICATOR, pageIndicatorItem); + + var pickerListItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(PickerListScreen); + pickerListItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(PICKER_LIST, pickerListItem); + + var progressBarItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ProgressBarScreen); + progressBarItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(PROGRESS_BAR, progressBarItem); + + var scrollTextItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ScrollTextScreen); + scrollTextItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(SCROLL_TEXT, scrollTextItem); + + var sliderSettings:SliderSettings = new SliderSettings(); + var sliderItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(SliderScreen); + sliderItem.setScreenIDForPushEvent(SliderScreen.SHOW_SETTINGS, SLIDER_SETTINGS); + sliderItem.addPopEvent(Event.COMPLETE); + sliderItem.properties.settings = sliderSettings; + this._navigator.addScreen(SLIDER, sliderItem); + + var sliderSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(SliderSettingsScreen); + sliderSettingsItem.addPopEvent(Event.COMPLETE); + sliderSettingsItem.properties.settings = sliderSettings; + //custom push and pop transitions for this settings screen + sliderSettingsItem.pushTransition = Cover.createCoverUpTransition(); + sliderSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(SLIDER_SETTINGS, sliderSettingsItem); + + var tabBarItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TabBarScreen); + tabBarItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(TAB_BAR, tabBarItem); + + var textInputItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TextInputScreen); + textInputItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(TEXT_INPUT, textInputItem); + + var togglesItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ToggleScreen); + togglesItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(TOGGLES, togglesItem); + + if(DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + //we don't want the screens bleeding outside the navigator's + //bounds on top of a drawer when a transition is active, so + //enable clipping. + this._navigator.clipContent = true; + this._menu = new MainMenuScreen(); + for(var eventType:String in MAIN_MENU_EVENTS) + { + this._menu.addEventListener(eventType, mainMenuEventHandler); + } + this._menu.height = 200; + this.leftDrawer = this._menu; + this.leftDrawerDockMode = Drawers.DOCK_MODE_BOTH; + } + else + { + var mainMenuItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(MainMenuScreen); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_ALERT, ALERT); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_BUTTON, BUTTON); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_BUTTON_GROUP, BUTTON_GROUP); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_CALLOUT, CALLOUT); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_GROUPED_LIST, GROUPED_LIST); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_ITEM_RENDERER, ITEM_RENDERER); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_LABEL, LABEL); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_LIST, LIST); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_NUMERIC_STEPPER, NUMERIC_STEPPER); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_PAGE_INDICATOR, PAGE_INDICATOR); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_PICKER_LIST, PICKER_LIST); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_PROGRESS_BAR, PROGRESS_BAR); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_SCROLL_TEXT, SCROLL_TEXT); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_SLIDER, SLIDER); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_TAB_BAR, TAB_BAR); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_TEXT_INPUT, TEXT_INPUT); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_TOGGLES, TOGGLES); + this._navigator.addScreen(MAIN_MENU, mainMenuItem); + this._navigator.rootScreenID = MAIN_MENU; + } + + this._navigator.pushTransition = Slide.createSlideLeftTransition(); + this._navigator.popTransition = Slide.createSlideRightTransition(); + } + + private function mainMenuEventHandler(event:Event):void + { + var screenName:String = MAIN_MENU_EVENTS[event.type] as String; + //since this navigation is triggered by an external menu, we don't + //want to push a new screen onto the stack. we want to start fresh. + this._navigator.rootScreenID = screenName; + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/EmbeddedAssets.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/EmbeddedAssets.as new file mode 100644 index 0000000000..eec70d7907 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/EmbeddedAssets.as @@ -0,0 +1,24 @@ +package feathers.examples.componentsExplorer.data +{ + import starling.textures.Texture; + + public class EmbeddedAssets + { + [Embed(source="/../assets/images/skull.png")] + private static const SKULL_ICON_DARK_EMBEDDED:Class; + + [Embed(source="/../assets/images/skull-white.png")] + private static const SKULL_ICON_LIGHT_EMBEDDED:Class; + + public static var SKULL_ICON_DARK:Texture; + + public static var SKULL_ICON_LIGHT:Texture; + + public static function initialize():void + { + //we can't create these textures until Starling is ready + SKULL_ICON_DARK = Texture.fromBitmap(new SKULL_ICON_DARK_EMBEDDED()); + SKULL_ICON_LIGHT = Texture.fromBitmap(new SKULL_ICON_LIGHT_EMBEDDED()); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/GroupedListSettings.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/GroupedListSettings.as new file mode 100644 index 0000000000..13e28e028a --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/GroupedListSettings.as @@ -0,0 +1,16 @@ +package feathers.examples.componentsExplorer.data +{ + public class GroupedListSettings + { + public static const STYLE_NORMAL:String = "normal"; + public static const STYLE_INSET:String = "inset"; + + public function GroupedListSettings() + { + } + + public var isSelectable:Boolean = true; + public var hasElasticEdges:Boolean = true; + public var style:String = STYLE_NORMAL; + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ItemRendererSettings.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ItemRendererSettings.as new file mode 100644 index 0000000000..44ad0f6560 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ItemRendererSettings.as @@ -0,0 +1,28 @@ +package feathers.examples.componentsExplorer.data +{ + import feathers.controls.Button; + import feathers.controls.renderers.BaseDefaultItemRenderer; + + public class ItemRendererSettings + { + public static const ICON_ACCESSORY_TYPE_DISPLAY_OBJECT:String = "Display Object"; + public static const ICON_ACCESSORY_TYPE_TEXTURE:String = "Texture"; + public static const ICON_ACCESSORY_TYPE_LABEL:String = "Label"; + + public function ItemRendererSettings() + { + } + + public var hasIcon:Boolean = true; + public var hasAccessory:Boolean = true; + public var layoutOrder:String = BaseDefaultItemRenderer.LAYOUT_ORDER_LABEL_ICON_ACCESSORY; + public var iconType:String = ICON_ACCESSORY_TYPE_TEXTURE; + public var iconPosition:String = Button.ICON_POSITION_LEFT; + public var useInfiniteGap:Boolean = false; + public var accessoryPosition:String = BaseDefaultItemRenderer.ACCESSORY_POSITION_RIGHT; + public var accessoryType:String = ICON_ACCESSORY_TYPE_DISPLAY_OBJECT; + public var useInfiniteAccessoryGap:Boolean = true; + public var horizontalAlign:String = Button.HORIZONTAL_ALIGN_LEFT; + public var verticalAlign:String = Button.VERTICAL_ALIGN_MIDDLE; + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ListSettings.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ListSettings.as new file mode 100644 index 0000000000..b19865b769 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ListSettings.as @@ -0,0 +1,13 @@ +package feathers.examples.componentsExplorer.data +{ + public class ListSettings + { + public function ListSettings() + { + } + + public var isSelectable:Boolean = true; + public var hasElasticEdges:Boolean = true; + public var allowMultipleSelection:Boolean = false; + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/NumericStepperSettings.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/NumericStepperSettings.as new file mode 100644 index 0000000000..5f2ffd4a3a --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/NumericStepperSettings.as @@ -0,0 +1,11 @@ +package feathers.examples.componentsExplorer.data +{ + public class NumericStepperSettings + { + public function NumericStepperSettings() + { + } + + public var step:Number = 1; + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/SliderSettings.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/SliderSettings.as new file mode 100644 index 0000000000..80b61b8326 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/SliderSettings.as @@ -0,0 +1,13 @@ +package feathers.examples.componentsExplorer.data +{ + public class SliderSettings + { + public function SliderSettings() + { + } + + public var step:Number = 1; + public var page:Number = 10; + public var liveDragging:Boolean = true; + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/AlertScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/AlertScreen.as new file mode 100644 index 0000000000..095eb1e5db --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/AlertScreen.as @@ -0,0 +1,104 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Alert; + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + public class AlertScreen extends PanelScreen + { + public function AlertScreen() + { + super(); + } + + private var _showAlertButton:Button; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Alert"; + + this.layout = new AnchorLayout(); + + this._showAlertButton = new Button(); + this._showAlertButton.label = "Show Alert"; + this._showAlertButton.addEventListener(Event.TRIGGERED, showAlertButton_triggeredHandler); + var buttonGroupLayoutData:AnchorLayoutData = new AnchorLayoutData(); + buttonGroupLayoutData.horizontalCenter = 0; + buttonGroupLayoutData.verticalCenter = 0; + this._showAlertButton.layoutData = buttonGroupLayoutData; + this.addChild(this._showAlertButton); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function showAlertButton_triggeredHandler(event:Event):void + { + var alert:Alert = Alert.show("I just wanted you to know that I have a very important message to share with you.", "Alert", new ListCollection( + [ + { label: "OK" }, + { label: "Cancel" } + ])); + alert.addEventListener(Event.CLOSE, alert_closeHandler); + } + + private function alert_closeHandler(event:Event, data:Object):void + { + if(data) + { + trace("alert closed with button:", data.label); + } + else + { + trace("alert closed without button"); + } + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonGroupScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonGroupScreen.as new file mode 100644 index 0000000000..7438e5d8e7 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonGroupScreen.as @@ -0,0 +1,95 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.ButtonGroup; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ButtonGroupScreen extends PanelScreen + { + public function ButtonGroupScreen() + { + super(); + } + + private var _buttonGroup:ButtonGroup; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Button Group"; + + this.layout = new AnchorLayout(); + + this._buttonGroup = new ButtonGroup(); + this._buttonGroup.dataProvider = new ListCollection( + [ + { label: "One", triggered: button_triggeredHandler }, + { label: "Two", triggered: button_triggeredHandler }, + { label: "Three", triggered: button_triggeredHandler }, + { label: "Four", triggered: button_triggeredHandler }, + ]); + var buttonGroupLayoutData:AnchorLayoutData = new AnchorLayoutData(); + buttonGroupLayoutData.horizontalCenter = 0; + buttonGroupLayoutData.verticalCenter = 0; + this._buttonGroup.layoutData = buttonGroupLayoutData; + this.addChild(this._buttonGroup); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function button_triggeredHandler(event:Event):void + { + var button:Button = Button(event.currentTarget); + trace(button.label + " triggered."); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonScreen.as new file mode 100644 index 0000000000..eba35a6582 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonScreen.as @@ -0,0 +1,151 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.ImageLoader; + import feathers.controls.PanelScreen; + import feathers.controls.ToggleButton; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ButtonScreen extends PanelScreen + { + public static var globalStyleProvider:IStyleProvider; + + public static const CHILD_STYLE_NAME_ICON_BUTTON:String = "components-explorer-button-screen-icon-button"; + + public function ButtonScreen() + { + super(); + } + + private var _normalButton:Button; + private var _disabledButton:Button; + private var _iconButton:Button; + private var _toggleButton:ToggleButton; + private var _callToActionButton:Button; + private var _quietButton:Button; + private var _dangerButton:Button; + private var _sampleBackButton:Button; + private var _forwardButton:Button; + + private var _icon:ImageLoader; + + override protected function get defaultStyleProvider():IStyleProvider + { + return ButtonScreen.globalStyleProvider; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Button"; + + this._normalButton = new Button(); + this._normalButton.label = "Normal Button"; + this._normalButton.addEventListener(Event.TRIGGERED, normalButton_triggeredHandler); + this.addChild(this._normalButton); + + this._disabledButton = new Button(); + this._disabledButton.label = "Disabled Button"; + this._disabledButton.isEnabled = false; + this.addChild(this._disabledButton); + + this._iconButton = new Button(); + //since it's a skin, we'll specif an icon in the theme + this._iconButton.styleNameList.add(CHILD_STYLE_NAME_ICON_BUTTON); + this._iconButton.label = "Icon Button"; + this._iconButton.defaultIcon = this._icon; + this.addChild(this._iconButton); + + this._toggleButton = new ToggleButton(); + this._toggleButton.label = "Toggle Button"; + this._toggleButton.isSelected = true; + this._toggleButton.addEventListener(Event.CHANGE, toggleButton_changeHandler); + this.addChild(this._toggleButton); + + this._callToActionButton = new Button(); + this._callToActionButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON); + this._callToActionButton.label = "Call to Action Button"; + this.addChild(this._callToActionButton); + + this._dangerButton = new Button(); + this._dangerButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_DANGER_BUTTON); + this._dangerButton.label = "Danger Button"; + this.addChild(this._dangerButton); + + this._sampleBackButton = new Button(); + this._sampleBackButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + this._sampleBackButton.label = "Back Button"; + this.addChild(this._sampleBackButton); + + this._forwardButton = new Button(); + this._forwardButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_FORWARD_BUTTON); + this._forwardButton.label = "Forward Button"; + this.addChild(this._forwardButton); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + this._quietButton = new Button(); + this._quietButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_QUIET_BUTTON); + this._quietButton.label = "Quiet Button"; + header.rightItems = new + [ + this._quietButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function normalButton_triggeredHandler(event:Event):void + { + trace("normal button triggered.") + } + + private function toggleButton_changeHandler(event:Event):void + { + trace("toggle button changed:", this._toggleButton.isSelected); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/CalloutScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/CalloutScreen.as new file mode 100644 index 0000000000..832f365074 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/CalloutScreen.as @@ -0,0 +1,205 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Callout; + import feathers.controls.Header; + import feathers.controls.Label; + import feathers.controls.PanelScreen; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class CalloutScreen extends PanelScreen + { + private static const CONTENT_TEXT:String = "Thank you for trying Feathers.\nHappy coding."; + + public static var globalStyleProvider:IStyleProvider; + + public function CalloutScreen() + { + super(); + } + + private var _rightButton:Button; + private var _downButton:Button; + private var _upButton:Button; + private var _leftButton:Button; + private var _message:Label; + + private var _topLeftLayoutData:AnchorLayoutData; + private var _topRightLayoutData:AnchorLayoutData; + private var _bottomRightLayoutData:AnchorLayoutData; + private var _bottomLeftLayoutData:AnchorLayoutData; + + private var _layoutPadding:Number = 0; + + public function get layoutPadding():Number + { + return this._layoutPadding; + } + + public function set layoutPadding(value:Number):void + { + if(this._layoutPadding == value) + { + return; + } + this._layoutPadding = value; + this.invalidate(INVALIDATION_FLAG_LAYOUT); + } + + override protected function get defaultStyleProvider():IStyleProvider + { + return CalloutScreen.globalStyleProvider; + } + + override public function dispose():void + { + //the message won't be on the display list when the screen is + //disposed, so dispose it manually + if(this._message) + { + this._message.dispose(); + this._message = null; + } + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Callout"; + + this.layout = new AnchorLayout(); + this._topLeftLayoutData = new AnchorLayoutData(); + this._topRightLayoutData = new AnchorLayoutData(); + this._bottomRightLayoutData = new AnchorLayoutData(); + this._bottomLeftLayoutData = new AnchorLayoutData(); + + this._rightButton = new Button(); + this._rightButton.label = "Right"; + this._rightButton.addEventListener(Event.TRIGGERED, rightButton_triggeredHandler); + this._rightButton.layoutData = this._topLeftLayoutData; + this.addChild(this._rightButton); + + this._downButton = new Button(); + this._downButton.label = "Down"; + this._downButton.addEventListener(Event.TRIGGERED, downButton_triggeredHandler); + this._downButton.layoutData = this._topRightLayoutData; + this.addChild(this._downButton); + + this._upButton = new Button(); + this._upButton.label = "Up"; + this._upButton.addEventListener(Event.TRIGGERED, upButton_triggeredHandler); + this._upButton.layoutData = this._bottomLeftLayoutData; + this.addChild(this._upButton); + + this._leftButton = new Button(); + this._leftButton.label = "Left"; + this._leftButton.addEventListener(Event.TRIGGERED, leftButton_triggeredHandler); + this._leftButton.layoutData = this._bottomRightLayoutData; + this.addChild(this._leftButton); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + override protected function draw():void + { + var layoutInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_LAYOUT); + + if(layoutInvalid) + { + this._topLeftLayoutData.top = this._layoutPadding; + this._topLeftLayoutData.left = this._layoutPadding; + this._topRightLayoutData.top = this._layoutPadding; + this._topRightLayoutData.right = this._layoutPadding; + this._bottomLeftLayoutData.bottom = this._layoutPadding; + this._bottomLeftLayoutData.left = this._layoutPadding; + this._bottomRightLayoutData.bottom = this._layoutPadding; + this._bottomRightLayoutData.right = this._layoutPadding; + } + + //never forget to call super.draw() + super.draw(); + } + + private function showCallout(origin:DisplayObject, direction:String):void + { + if(!this._message) + { + this._message = new Label(); + this._message.text = CONTENT_TEXT; + } + var callout:Callout = Callout.show(DisplayObject(this._message), origin, direction); + //we're reusing the message every time that this screen shows a + //callout, so we don't want the message to be disposed. we'll + //dispose of it manually later when the screen is disposed. + callout.disposeContent = false; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function rightButton_triggeredHandler(event:Event):void + { + this.showCallout(this._rightButton, Callout.DIRECTION_RIGHT); + } + + private function downButton_triggeredHandler(event:Event):void + { + this.showCallout(this._downButton, Callout.DIRECTION_DOWN); + } + + private function upButton_triggeredHandler(event:Event):void + { + this.showCallout(this._upButton, Callout.DIRECTION_UP); + } + + private function leftButton_triggeredHandler(event:Event):void + { + this.showCallout(this._leftButton, Callout.DIRECTION_LEFT) + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListScreen.as new file mode 100644 index 0000000000..e95a1e8162 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListScreen.as @@ -0,0 +1,197 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.GroupedList; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.renderers.DefaultGroupedListItemRenderer; + import feathers.controls.renderers.IGroupedListItemRenderer; + import feathers.data.HierarchicalCollection; + import feathers.events.FeathersEventType; + import feathers.examples.componentsExplorer.data.GroupedListSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + [Event(name="showSettings",type="starling.events.Event")] + + public class GroupedListScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function GroupedListScreen() + { + super(); + } + + public var settings:GroupedListSettings; + + private var _list:GroupedList; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Grouped List"; + + this.layout = new AnchorLayout(); + + var groups:Array = + [ + { + header: "A", + children: + [ + { text: "Aardvark" }, + { text: "Alligator" }, + { text: "Alpaca" }, + { text: "Anteater" }, + ] + }, + { + header: "B", + children: + [ + { text: "Baboon" }, + { text: "Bear" }, + { text: "Beaver" }, + ] + }, + { + header: "C", + children: + [ + { text: "Canary" }, + { text: "Cat" }, + ] + }, + { + header: "D", + children: + [ + { text: "Deer" }, + { text: "Dingo" }, + { text: "Dog" }, + { text: "Dolphin" }, + { text: "Donkey" }, + { text: "Dragonfly" }, + { text: "Duck" }, + { text: "Dung Beetle" }, + ] + }, + { + header: "E", + children: + [ + { text: "Eagle" }, + { text: "Earthworm" }, + { text: "Eel" }, + { text: "Elk" }, + ] + }, + { + header: "F", + children: + [ + { text: "Fox" }, + ] + } + ]; + groups.fixed = true; + + this._list = new GroupedList(); + if(this.settings.style == GroupedListSettings.STYLE_INSET) + { + this._list.styleNameList.add(GroupedList.ALTERNATE_STYLE_NAME_INSET_GROUPED_LIST); + } + this._list.dataProvider = new HierarchicalCollection(groups); + this._list.typicalItem = { text: "Item 1000" }; + this._list.isSelectable = this.settings.isSelectable; + this._list.hasElasticEdges = this.settings.hasElasticEdges; + this._list.clipContent = false; + this._list.autoHideBackground = true; + this._list.itemRendererFactory = function():IGroupedListItemRenderer + { + var renderer:DefaultGroupedListItemRenderer = new DefaultGroupedListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "text"; + return renderer; + }; + this._list.addEventListener(Event.CHANGE, list_changeHandler); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChildAt(this._list, 0); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this._list.revealScrollBars(); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + + private function list_changeHandler(event:Event):void + { + trace("GroupedList onChange:", this._list.selectedGroupIndex, this._list.selectedItemIndex); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListSettingsScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListSettingsScreen.as new file mode 100644 index 0000000000..8fa79c3e74 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListSettingsScreen.as @@ -0,0 +1,136 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.controls.ToggleSwitch; + import feathers.data.ListCollection; + import feathers.examples.componentsExplorer.data.GroupedListSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class GroupedListSettingsScreen extends PanelScreen + { + public function GroupedListSettingsScreen() + { + super(); + } + + public var settings:GroupedListSettings; + + private var _list:List; + + private var _stylePicker:PickerList; + private var _isSelectableToggle:ToggleSwitch; + private var _hasElasticEdgesToggle:ToggleSwitch; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Grouped List Settings"; + + this.layout = new AnchorLayout(); + + this._stylePicker = new PickerList(); + this._stylePicker.dataProvider = new ListCollection(new + [ + GroupedListSettings.STYLE_NORMAL, + GroupedListSettings.STYLE_INSET + ]); + this._stylePicker.typicalItem = GroupedListSettings.STYLE_NORMAL; + this._stylePicker.listProperties.typicalItem = GroupedListSettings.STYLE_NORMAL; + this._stylePicker.selectedItem = this.settings.style; + this._stylePicker.addEventListener(Event.CHANGE, stylePicker_changeHandler); + + this._isSelectableToggle = new ToggleSwitch(); + this._isSelectableToggle.isSelected = this.settings.isSelectable; + this._isSelectableToggle.addEventListener(Event.CHANGE, isSelectableToggle_changeHandler); + + this._hasElasticEdgesToggle = new ToggleSwitch(); + this._hasElasticEdgesToggle.isSelected = this.settings.hasElasticEdges; + this._hasElasticEdgesToggle.addEventListener(Event.CHANGE, hasElasticEdgesToggle_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "Group Style", accessory: this._stylePicker }, + { label: "isSelectable", accessory: this._isSelectableToggle }, + { label: "hasElasticEdges", accessory: this._hasElasticEdgesToggle }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function stylePicker_changeHandler(event:Event):void + { + this.settings.style = this._stylePicker.selectedItem as String; + } + + private function isSelectableToggle_changeHandler(event:Event):void + { + this.settings.isSelectable = this._isSelectableToggle.isSelected; + } + + private function hasElasticEdgesToggle_changeHandler(event:Event):void + { + this.settings.hasElasticEdges = this._hasElasticEdgesToggle.isSelected; + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererScreen.as new file mode 100644 index 0000000000..a0e097c165 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererScreen.as @@ -0,0 +1,273 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ToggleSwitch; + import feathers.data.ListCollection; + import feathers.examples.componentsExplorer.data.EmbeddedAssets; + import feathers.examples.componentsExplorer.data.ItemRendererSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + [Event(name="showSettings",type="starling.events.Event")] + + public class ItemRendererScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public static var globalStyleProvider:IStyleProvider; + + public function ItemRendererScreen() + { + super(); + } + + private var _list:List; + private var _listItem:Object; + + private var _itemRendererGap:Number = 0; + + public function get itemRendererGap():Number + { + return this._itemRendererGap; + } + + public function set itemRendererGap(value:Number):void + { + if(this._itemRendererGap == value) + { + return; + } + this._itemRendererGap = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + private var _settings:ItemRendererSettings; + + public function get settings():ItemRendererSettings + { + return this._settings; + } + + public function set settings(value:ItemRendererSettings):void + { + if(this._settings == value) + { + return; + } + this._settings = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + override protected function get defaultStyleProvider():IStyleProvider + { + return ItemRendererScreen.globalStyleProvider; + } + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemIconOrAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize()! + super.initialize(); + + this.title = "Item Renderer"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + + this._listItem = { text: "Primary Text" }; + this._list.itemRendererProperties.labelField = "text"; + this._list.dataProvider = new ListCollection([this._listItem]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.isSelectable = false; + this._list.clipContent = false; + this._list.autoHideBackground = true; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + override protected function draw():void + { + if(this.settings.hasIcon) + { + switch(this.settings.iconType) + { + case ItemRendererSettings.ICON_ACCESSORY_TYPE_LABEL: + { + this._listItem.iconText = "Icon Text"; + this._list.itemRendererProperties.iconLabelField = "iconText"; + + //clear these in case this setting has changed + delete this._listItem.iconTexture; + delete this._listItem.icon; + break; + } + case ItemRendererSettings.ICON_ACCESSORY_TYPE_TEXTURE: + { + this._listItem.iconTexture = EmbeddedAssets.SKULL_ICON_LIGHT; + this._list.itemRendererProperties.iconSourceField = "iconTexture"; + + //clear these in case this setting has changed + delete this._listItem.iconText; + delete this._listItem.icon; + break; + } + default: + { + this._listItem.icon = new ToggleSwitch(); + this._list.itemRendererProperties.iconField = "icon"; + + //clear these in case this setting has changed + delete this._listItem.iconText; + delete this._listItem.iconTexture; + + } + } + this._list.itemRendererProperties.iconPosition = this.settings.iconPosition; + } + if(this.settings.hasAccessory) + { + switch(this.settings.accessoryType) + { + case ItemRendererSettings.ICON_ACCESSORY_TYPE_LABEL: + { + this._listItem.accessoryText = "Accessory Text"; + this._list.itemRendererProperties.accessoryLabelField = "accessoryText"; + + //clear these in case this setting has changed + delete this._listItem.accessoryTexture; + delete this._listItem.accessory; + break; + } + case ItemRendererSettings.ICON_ACCESSORY_TYPE_TEXTURE: + { + this._listItem.accessoryTexture = EmbeddedAssets.SKULL_ICON_LIGHT; + this._list.itemRendererProperties.accessorySourceField = "accessoryTexture"; + break; + } + default: + { + this._listItem.accessory = new ToggleSwitch(); + this._list.itemRendererProperties.accessoryField = "accessory"; + + //clear these in case this setting has changed + delete this._listItem.accessoryText; + delete this._listItem.accessoryTexture; + } + } + this._list.itemRendererProperties.accessoryPosition = this.settings.accessoryPosition; + } + if(this.settings.useInfiniteGap) + { + this._list.itemRendererProperties.gap = Number.POSITIVE_INFINITY; + } + else + { + this._list.itemRendererProperties.gap = this._itemRendererGap; + } + if(this.settings.useInfiniteAccessoryGap) + { + this._list.itemRendererProperties.accessoryGap = Number.POSITIVE_INFINITY; + } + else + { + this._list.itemRendererProperties.accessoryGap = this._itemRendererGap; + } + this._list.itemRendererProperties.horizontalAlign = this.settings.horizontalAlign; + this._list.itemRendererProperties.verticalAlign = this.settings.verticalAlign; + this._list.itemRendererProperties.layoutOrder = this.settings.layoutOrder; + + //ideally, styles like gap, accessoryGap, horizontalAlign, + //verticalAlign, layoutOrder, iconPosition, and accessoryPosition + //will be handled in the theme. + //this is a special case because this screen is designed to + //configure those styles at runtime + + //never forget to call super.draw()! + super.draw(); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function disposeItemIconOrAccessory(item:Object):void + { + if(item.hasOwnProperty("icon")) + { + DisplayObject(item.icon).dispose(); + } + if(item.hasOwnProperty("accessory")) + { + DisplayObject(item.accessory).dispose(); + } + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererSettingsScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererSettingsScreen.as new file mode 100644 index 0000000000..601fc5c6b2 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererSettingsScreen.as @@ -0,0 +1,315 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.GroupedList; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.controls.ToggleSwitch; + import feathers.controls.renderers.BaseDefaultItemRenderer; + import feathers.data.HierarchicalCollection; + import feathers.data.ListCollection; + import feathers.examples.componentsExplorer.data.ItemRendererSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ItemRendererSettingsScreen extends PanelScreen + { + private static const GAP_LABEL_INFINITE:String = "Fill Available Space"; + private static const GAP_LABEL_DEFAULT:String = "No Fill"; + + public function ItemRendererSettingsScreen() + { + super(); + } + + public var settings:ItemRendererSettings; + + private var _list:GroupedList; + private var _gapPicker:PickerList; + private var _hasIconToggle:ToggleSwitch; + private var _hasAccessoryToggle:ToggleSwitch; + private var _layoutOrderPicker:PickerList; + private var _iconPositionPicker:PickerList; + private var _iconTypePicker:PickerList; + private var _accessoryPositionPicker:PickerList; + private var _accessoryTypePicker:PickerList; + private var _accessoryGapPicker:PickerList; + private var _horizontalAlignPicker:PickerList; + private var _verticalAlignPicker:PickerList; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(null, disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Item Renderer Settings"; + + this.layout = new AnchorLayout(); + + this._hasIconToggle = new ToggleSwitch(); + this._hasIconToggle.isSelected = this.settings.hasIcon; + this._hasIconToggle.addEventListener(Event.CHANGE, hasIconToggle_changeHandler); + + this._iconTypePicker = new PickerList(); + this._iconTypePicker.typicalItem = ItemRendererSettings.ICON_ACCESSORY_TYPE_DISPLAY_OBJECT; + this._iconTypePicker.dataProvider = new ListCollection(new + [ + ItemRendererSettings.ICON_ACCESSORY_TYPE_DISPLAY_OBJECT, + ItemRendererSettings.ICON_ACCESSORY_TYPE_TEXTURE, + ItemRendererSettings.ICON_ACCESSORY_TYPE_LABEL, + ]); + this._iconTypePicker.listProperties.typicalItem = ItemRendererSettings.ICON_ACCESSORY_TYPE_DISPLAY_OBJECT; + this._iconTypePicker.selectedItem = this.settings.iconType; + this._iconTypePicker.addEventListener(Event.CHANGE, iconTypePicker_changeHandler); + + this._iconPositionPicker = new PickerList(); + this._iconPositionPicker.typicalItem = Button.ICON_POSITION_RIGHT_BASELINE; + this._iconPositionPicker.dataProvider = new ListCollection(new + [ + Button.ICON_POSITION_TOP, + Button.ICON_POSITION_RIGHT, + Button.ICON_POSITION_BOTTOM, + Button.ICON_POSITION_LEFT, + Button.ICON_POSITION_LEFT_BASELINE, + Button.ICON_POSITION_RIGHT_BASELINE, + //Button.ICON_POSITION_MANUAL, + ]); + this._iconPositionPicker.listProperties.typicalItem = Button.ICON_POSITION_RIGHT_BASELINE; + this._iconPositionPicker.selectedItem = this.settings.iconPosition; + this._iconPositionPicker.addEventListener(Event.CHANGE, iconPositionPicker_changeHandler); + + this._gapPicker = new PickerList(); + this._gapPicker.dataProvider = new ListCollection( + [ + { label: GAP_LABEL_INFINITE, value: true }, + { label: GAP_LABEL_DEFAULT, value: false }, + ]); + this._gapPicker.typicalItem = this._gapPicker.dataProvider.getItemAt(0); + this._gapPicker.listProperties.typicalItem = this._gapPicker.dataProvider.getItemAt(0); + this._gapPicker.selectedItem = this._gapPicker.dataProvider.getItemAt(this.settings.useInfiniteGap ? 0 : 1); + this._gapPicker.addEventListener(Event.CHANGE, gapPicker_changeHandler); + + this._hasAccessoryToggle = new ToggleSwitch(); + this._hasAccessoryToggle.isSelected = this.settings.hasAccessory; + this._hasAccessoryToggle.addEventListener(Event.CHANGE, hasAccessoryToggle_changeHandler); + + this._accessoryTypePicker = new PickerList(); + this._accessoryTypePicker.typicalItem = ItemRendererSettings.ICON_ACCESSORY_TYPE_DISPLAY_OBJECT; + this._accessoryTypePicker.dataProvider = new ListCollection(new + [ + ItemRendererSettings.ICON_ACCESSORY_TYPE_DISPLAY_OBJECT, + ItemRendererSettings.ICON_ACCESSORY_TYPE_TEXTURE, + ItemRendererSettings.ICON_ACCESSORY_TYPE_LABEL, + ]); + this._accessoryTypePicker.listProperties.typicalItem = ItemRendererSettings.ICON_ACCESSORY_TYPE_DISPLAY_OBJECT; + this._accessoryTypePicker.selectedItem = this.settings.accessoryType; + this._accessoryTypePicker.addEventListener(Event.CHANGE, accessoryTypePicker_changeHandler); + + this._accessoryPositionPicker = new PickerList(); + this._accessoryPositionPicker.typicalItem = BaseDefaultItemRenderer.ACCESSORY_POSITION_BOTTOM; + this._accessoryPositionPicker.dataProvider = new ListCollection(new + [ + BaseDefaultItemRenderer.ACCESSORY_POSITION_TOP, + BaseDefaultItemRenderer.ACCESSORY_POSITION_RIGHT, + BaseDefaultItemRenderer.ACCESSORY_POSITION_BOTTOM, + BaseDefaultItemRenderer.ACCESSORY_POSITION_LEFT, + //BaseDefaultItemRenderer.ACCESSORY_POSITION_MANUAL, + ]); + this._accessoryPositionPicker.listProperties.typicalItem = BaseDefaultItemRenderer.ACCESSORY_POSITION_BOTTOM; + this._accessoryPositionPicker.selectedItem = this.settings.accessoryPosition; + this._accessoryPositionPicker.addEventListener(Event.CHANGE, accessoryPositionPicker_changeHandler); + + this._accessoryGapPicker = new PickerList(); + this._accessoryGapPicker.dataProvider = new ListCollection( + [ + { label: GAP_LABEL_INFINITE, value: true }, + { label: GAP_LABEL_DEFAULT, value: false }, + ]); + this._accessoryGapPicker.typicalItem = this._accessoryGapPicker.dataProvider.getItemAt(0); + this._accessoryGapPicker.listProperties.typicalItem = this._accessoryGapPicker.dataProvider.getItemAt(0); + this._accessoryGapPicker.selectedItem = this._accessoryGapPicker.dataProvider.getItemAt(this.settings.useInfiniteAccessoryGap ? 0 : 1); + this._accessoryGapPicker.addEventListener(Event.CHANGE, accessoryGapPicker_changeHandler); + + this._layoutOrderPicker = new PickerList(); + this._layoutOrderPicker.typicalItem = BaseDefaultItemRenderer.LAYOUT_ORDER_LABEL_ACCESSORY_ICON; + this._layoutOrderPicker.dataProvider = new ListCollection(new + [ + BaseDefaultItemRenderer.LAYOUT_ORDER_LABEL_ICON_ACCESSORY, + BaseDefaultItemRenderer.LAYOUT_ORDER_LABEL_ACCESSORY_ICON, + ]); + this._layoutOrderPicker.listProperties.typicalItem = BaseDefaultItemRenderer.LAYOUT_ORDER_LABEL_ACCESSORY_ICON; + this._layoutOrderPicker.selectedItem = this.settings.layoutOrder; + this._layoutOrderPicker.addEventListener(Event.CHANGE, layoutOrderPicker_changeHandler); + + this._horizontalAlignPicker = new PickerList(); + this._horizontalAlignPicker.dataProvider = new ListCollection(new + [ + Button.HORIZONTAL_ALIGN_LEFT, + Button.HORIZONTAL_ALIGN_CENTER, + Button.HORIZONTAL_ALIGN_RIGHT, + ]); + this._horizontalAlignPicker.typicalItem = Button.HORIZONTAL_ALIGN_CENTER; + this._horizontalAlignPicker.listProperties.typicalItem = Button.HORIZONTAL_ALIGN_CENTER; + this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; + this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); + + this._verticalAlignPicker = new PickerList(); + this._verticalAlignPicker.dataProvider = new ListCollection(new + [ + Button.VERTICAL_ALIGN_TOP, + Button.VERTICAL_ALIGN_MIDDLE, + Button.VERTICAL_ALIGN_BOTTOM, + ]); + this._verticalAlignPicker.typicalItem = Button.VERTICAL_ALIGN_MIDDLE; + this._verticalAlignPicker.listProperties.typicalItem = Button.VERTICAL_ALIGN_MIDDLE; + this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; + this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); + + this._list = new GroupedList(); + this._list.styleNameList.add(GroupedList.ALTERNATE_STYLE_NAME_INSET_GROUPED_LIST); + this._list.isSelectable = false; + this._list.dataProvider = new HierarchicalCollection( + [ + { + header: "Layout", + children: + [ + { label: "layoutOrder", accessory: this._layoutOrderPicker }, + { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, + { label: "verticalAlign", accessory: this._verticalAlignPicker }, + ] + }, + { + header: "Icon", + children: + [ + { label: "Has Icon", accessory: this._hasIconToggle }, + { label: "Icon Type", accessory: this._iconTypePicker }, + { label: "iconPosition", accessory: this._iconPositionPicker }, + { label: "gap", accessory: this._gapPicker }, + ] + }, + { + header: "Accessory", + children: + [ + { label: "Has Accessory", accessory: this._hasAccessoryToggle }, + { label: "Accessory Type", accessory: this._accessoryTypePicker }, + { label: "accessoryPosition", accessory: this._accessoryPositionPicker }, + { label: "accessoryGap", accessory: this._accessoryGapPicker }, + ] + }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function hasIconToggle_changeHandler(event:Event):void + { + this.settings.hasIcon = this._hasIconToggle.isSelected + } + + private function iconTypePicker_changeHandler(event:Event):void + { + this.settings.iconType = this._iconTypePicker.selectedItem as String; + } + + private function iconPositionPicker_changeHandler(event:Event):void + { + this.settings.iconPosition = this._iconPositionPicker.selectedItem as String; + } + + private function gapPicker_changeHandler(event:Event):void + { + this.settings.useInfiniteGap = this._gapPicker.selectedIndex == 0; + } + + private function hasAccessoryToggle_changeHandler(event:Event):void + { + this.settings.hasAccessory = this._hasAccessoryToggle.isSelected + } + + private function accessoryTypePicker_changeHandler(event:Event):void + { + this.settings.accessoryType = this._accessoryTypePicker.selectedItem as String; + } + + private function accessoryPositionPicker_changeHandler(event:Event):void + { + this.settings.accessoryPosition = this._accessoryPositionPicker.selectedItem as String; + } + + private function accessoryGapPicker_changeHandler(event:Event):void + { + this.settings.useInfiniteAccessoryGap = this._accessoryGapPicker.selectedIndex == 0; + } + + private function layoutOrderPicker_changeHandler(event:Event):void + { + this.settings.layoutOrder = this._layoutOrderPicker.selectedItem as String; + } + + private function horizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.horizontalAlign = this._horizontalAlignPicker.selectedItem as String; + } + + private function verticalAlignPicker_changeHandler(event:Event):void + { + this.settings.verticalAlign = this._verticalAlignPicker.selectedItem as String; + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/LabelScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/LabelScreen.as new file mode 100644 index 0000000000..f8cba682ea --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/LabelScreen.as @@ -0,0 +1,100 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Label; + import feathers.controls.PanelScreen; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class LabelScreen extends PanelScreen + { + public static var globalStyleProvider:IStyleProvider; + + public function LabelScreen() + { + super(); + } + + private var _normalLabel:Label; + private var _disabledLabel:Label; + private var _headingLabel:Label; + private var _detailLabel:Label; + + override protected function get defaultStyleProvider():IStyleProvider + { + return LabelScreen.globalStyleProvider; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Label"; + + this._normalLabel = new Label(); + this._normalLabel.text = "This is a normal label."; + this.addChild(this._normalLabel); + + this._disabledLabel = new Label(); + this._disabledLabel.text = "A label may be disabled."; + this._disabledLabel.isEnabled = false; + this.addChild(this._disabledLabel); + + this._headingLabel = new Label(); + this._headingLabel.styleNameList.add(Label.ALTERNATE_STYLE_NAME_HEADING); + this._headingLabel.text = "A heading label is for larger, more important text."; + this.addChild(this._headingLabel); + + this._detailLabel = new Label(); + this._detailLabel.styleNameList.add(Label.ALTERNATE_STYLE_NAME_DETAIL); + this._detailLabel.text = "While a detail label is for smaller, less important text."; + this.addChild(this._detailLabel); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListScreen.as new file mode 100644 index 0000000000..60f66913ae --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListScreen.as @@ -0,0 +1,144 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.examples.componentsExplorer.data.ListSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + [Event(name="showSettings",type="starling.events.Event")] + + public class ListScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function ListScreen() + { + super(); + } + + public var settings:ListSettings; + + private var _list:List; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "List"; + + this.layout = new AnchorLayout(); + + var items:Array = []; + for(var i:int = 0; i < 150; i++) + { + var item:Object = {text: "Item " + (i + 1).toString()}; + items[i] = item; + } + items.fixed = true; + + this._list = new List(); + this._list.dataProvider = new ListCollection(items); + this._list.typicalItem = {text: "Item 1000"}; + this._list.isSelectable = this.settings.isSelectable; + this._list.allowMultipleSelection = this.settings.allowMultipleSelection; + this._list.hasElasticEdges = this.settings.hasElasticEdges; + //optimization to reduce draw calls. + //only do this if the header or other content covers the edges of + //the list. otherwise, the list items may be displayed outside of + //the list's bounds. + this._list.clipContent = false; + this._list.autoHideBackground = true; + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "text"; + return renderer; + }; + this._list.addEventListener(Event.CHANGE, list_changeHandler); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this._list.revealScrollBars(); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + + private function list_changeHandler(event:Event):void + { + var selectedIndices:Vector. = this._list.selectedIndices; + trace("List onChange:", selectedIndices.length > 0 ? selectedIndices : this._list.selectedIndex); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListSettingsScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListSettingsScreen.as new file mode 100644 index 0000000000..0e3e850ef2 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListSettingsScreen.as @@ -0,0 +1,128 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ToggleSwitch; + import feathers.data.ListCollection; + import feathers.examples.componentsExplorer.data.ListSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ListSettingsScreen extends PanelScreen + { + public function ListSettingsScreen() + { + super(); + } + + public var settings:ListSettings; + + private var _list:List; + + private var _isSelectableToggle:ToggleSwitch; + private var _allowMultipleSelectionToggle:ToggleSwitch; + private var _hasElasticEdgesToggle:ToggleSwitch; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "List Settings"; + + this.layout = new AnchorLayout(); + + this._isSelectableToggle = new ToggleSwitch(); + this._isSelectableToggle.isSelected = this.settings.isSelectable; + this._isSelectableToggle.addEventListener(Event.CHANGE, isSelectableToggle_changeHandler); + + this._allowMultipleSelectionToggle = new ToggleSwitch(); + this._allowMultipleSelectionToggle.isSelected = this.settings.allowMultipleSelection; + this._allowMultipleSelectionToggle.addEventListener(Event.CHANGE, allowMultipleSelectionToggle_changeHandler); + + this._hasElasticEdgesToggle = new ToggleSwitch(); + this._hasElasticEdgesToggle.isSelected = this.settings.hasElasticEdges; + this._hasElasticEdgesToggle.addEventListener(Event.CHANGE, hasElasticEdgesToggle_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "isSelectable", accessory: this._isSelectableToggle }, + { label: "allowMultipleSelection", accessory: this._allowMultipleSelectionToggle }, + { label: "hasElasticEdges", accessory: this._hasElasticEdgesToggle }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function isSelectableToggle_changeHandler(event:Event):void + { + this.settings.isSelectable = this._isSelectableToggle.isSelected; + } + + private function allowMultipleSelectionToggle_changeHandler(event:Event):void + { + this.settings.allowMultipleSelection = this._allowMultipleSelectionToggle.isSelected; + } + + private function hasElasticEdgesToggle_changeHandler(event:Event):void + { + this.settings.hasElasticEdges = this._hasElasticEdgesToggle.isSelected; + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/MainMenuScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/MainMenuScreen.as new file mode 100644 index 0000000000..a735efeea8 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/MainMenuScreen.as @@ -0,0 +1,170 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.StackScreenNavigatorItem; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.StandardIcons; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.events.Event; + import starling.textures.Texture; + + [Event(name="complete",type="starling.events.Event")] + [Event(name="showAlert",type="starling.events.Event")] + [Event(name="showButton",type="starling.events.Event")] + [Event(name="showButtonGroup",type="starling.events.Event")] + [Event(name="showCallout",type="starling.events.Event")] + [Event(name="showGroupedList",type="starling.events.Event")] + [Event(name="showItemRenderer",type="starling.events.Event")] + [Event(name="showList",type="starling.events.Event")] + [Event(name="showNumericStepper",type="starling.events.Event")] + [Event(name="showPageIndicator",type="starling.events.Event")] + [Event(name="showPickerList",type="starling.events.Event")] + [Event(name="showProgressBar",type="starling.events.Event")] + [Event(name="showScrollText",type="starling.events.Event")] + [Event(name="showSlider",type="starling.events.Event")] + [Event(name="showTabBar",type="starling.events.Event")] + [Event(name="showTextInput",type="starling.events.Event")] + [Event(name="showToggles",type="starling.events.Event")] + + public class MainMenuScreen extends PanelScreen + { + public static const SHOW_ALERT:String = "showAlert"; + public static const SHOW_BUTTON:String = "showButton"; + public static const SHOW_BUTTON_GROUP:String = "showButtonGroup"; + public static const SHOW_CALLOUT:String = "showCallout"; + public static const SHOW_GROUPED_LIST:String = "showGroupedList"; + public static const SHOW_ITEM_RENDERER:String = "showItemRenderer"; + public static const SHOW_LABEL:String = "showLabel"; + public static const SHOW_LIST:String = "showList"; + public static const SHOW_NUMERIC_STEPPER:String = "showNumericStepper"; + public static const SHOW_PAGE_INDICATOR:String = "showPageIndicator"; + public static const SHOW_PICKER_LIST:String = "showPickerList"; + public static const SHOW_PROGRESS_BAR:String = "showProgressBar"; + public static const SHOW_SCROLL_TEXT:String = "showScrollText"; + public static const SHOW_SLIDER:String = "showSlider"; + public static const SHOW_TAB_BAR:String = "showTabBar"; + public static const SHOW_TEXT_INPUT:String = "showTextInput"; + public static const SHOW_TOGGLES:String = "showToggles"; + + public function MainMenuScreen() + { + super(); + } + + private var _list:List; + + public var savedVerticalScrollPosition:Number = 0; + public var savedSelectedIndex:int = -1; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Feathers"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { label: "Alert", event: SHOW_ALERT }, + { label: "Button", event: SHOW_BUTTON }, + { label: "Button Group", event: SHOW_BUTTON_GROUP }, + { label: "Callout", event: SHOW_CALLOUT }, + { label: "Grouped List", event: SHOW_GROUPED_LIST }, + { label: "Item Renderer", event: SHOW_ITEM_RENDERER }, + { label: "Label", event: SHOW_LABEL }, + { label: "List", event: SHOW_LIST }, + { label: "Numeric Stepper", event: SHOW_NUMERIC_STEPPER }, + { label: "Page Indicator", event: SHOW_PAGE_INDICATOR }, + { label: "Picker List", event: SHOW_PICKER_LIST }, + { label: "Progress Bar", event: SHOW_PROGRESS_BAR }, + { label: "Scroll Text", event: SHOW_SCROLL_TEXT }, + { label: "Slider", event: SHOW_SLIDER}, + { label: "Tab Bar", event: SHOW_TAB_BAR }, + { label: "Text Input", event: SHOW_TEXT_INPUT }, + { label: "Toggles", event: SHOW_TOGGLES }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this._list.verticalScrollPosition = this.savedVerticalScrollPosition; + + var isTablet:Boolean = DeviceCapabilities.isTablet(Starling.current.nativeStage); + var itemRendererAccessorySourceFunction:Function = null; + if(!isTablet) + { + itemRendererAccessorySourceFunction = this.accessorySourceFunction; + } + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "label"; + renderer.accessorySourceFunction = itemRendererAccessorySourceFunction; + return renderer; + }; + + if(isTablet) + { + this._list.addEventListener(Event.CHANGE, list_changeHandler); + this._list.selectedIndex = 0; + this._list.revealScrollBars(); + } + else + { + this._list.selectedIndex = this.savedSelectedIndex; + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + this.addChild(this._list); + } + + private function accessorySourceFunction(item:Object):Texture + { + return StandardIcons.listDrillDownAccessoryTexture; + } + + private function transitionInCompleteHandler(event:Event):void + { + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this._list.selectedIndex = -1; + this._list.addEventListener(Event.CHANGE, list_changeHandler); + } + this._list.revealScrollBars(); + } + + private function list_changeHandler(event:Event):void + { + var eventType:String = this._list.selectedItem.event as String; + if(DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.dispatchEventWith(eventType); + return; + } + + //save the list's scroll position and selected index so that we + //can restore some context when this screen when we return to it + //again later. + this.dispatchEventWith(eventType, false, + { + savedVerticalScrollPosition: this._list.verticalScrollPosition, + savedSelectedIndex: this._list.selectedIndex + }); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperScreen.as new file mode 100644 index 0000000000..0f796fc9af --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperScreen.as @@ -0,0 +1,109 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.examples.componentsExplorer.data.NumericStepperSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + [Event(name="showSettings",type="starling.events.Event")] + + public class NumericStepperScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function NumericStepperScreen() + { + super(); + } + + public var settings:NumericStepperSettings; + + private var _stepper:NumericStepper; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Numeric Stepper"; + + this.layout = new AnchorLayout(); + + this._stepper = new NumericStepper(); + this._stepper.minimum = 0; + this._stepper.maximum = 100; + this._stepper.value = 50; + this._stepper.step = this.settings.step; + this._stepper.addEventListener(Event.CHANGE, slider_changeHandler); + var stepperLayoutData:AnchorLayoutData = new AnchorLayoutData(); + stepperLayoutData.horizontalCenter = 0; + stepperLayoutData.verticalCenter = 0; + this._stepper.layoutData = stepperLayoutData; + this.addChild(this._stepper); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function slider_changeHandler(event:Event):void + { + trace("numeric stepper change:", this._stepper.value); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperSettingsScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperSettingsScreen.as new file mode 100644 index 0000000000..4ce6a4428c --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperSettingsScreen.as @@ -0,0 +1,108 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.data.ListCollection; + import feathers.examples.componentsExplorer.data.NumericStepperSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class NumericStepperSettingsScreen extends PanelScreen + { + public function NumericStepperSettingsScreen() + { + super(); + } + + public var settings:NumericStepperSettings; + + private var _list:List; + private var _stepStepper:NumericStepper; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Numeric Stepper Settings"; + + this.layout = new AnchorLayout(); + + this._stepStepper = new NumericStepper(); + this._stepStepper.minimum = 1; + this._stepStepper.maximum = 20; + this._stepStepper.step = 1; + this._stepStepper.value = this.settings.step; + this._stepStepper.addEventListener(Event.CHANGE, stepStepper_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "step", accessory: this._stepStepper }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function stepStepper_changeHandler(event:Event):void + { + this.settings.step = this._stepStepper.value; + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PageIndicatorScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PageIndicatorScreen.as new file mode 100644 index 0000000000..2d3ac3e5b2 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PageIndicatorScreen.as @@ -0,0 +1,89 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PageIndicator; + import feathers.controls.PanelScreen; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class PageIndicatorScreen extends PanelScreen + { + public function PageIndicatorScreen() + { + super(); + } + + private var _pageIndicator:PageIndicator; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Page Indicator"; + + this.layout = new AnchorLayout(); + + this._pageIndicator = new PageIndicator(); + this._pageIndicator.pageCount = 5; + this._pageIndicator.addEventListener(Event.CHANGE, pageIndicator_changeHandler); + var pageIndicatorLayoutData:AnchorLayoutData = new AnchorLayoutData(); + pageIndicatorLayoutData.left = 0; + pageIndicatorLayoutData.right = 0; + pageIndicatorLayoutData.verticalCenter = 0; + this._pageIndicator.layoutData = pageIndicatorLayoutData; + this.addChild(this._pageIndicator); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function pageIndicator_changeHandler(event:Event):void + { + trace("page indicator change:", this._pageIndicator.selectedIndex); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PickerListScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PickerListScreen.as new file mode 100644 index 0000000000..8ef7569d4a --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PickerListScreen.as @@ -0,0 +1,124 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class PickerListScreen extends PanelScreen + { + public function PickerListScreen() + { + super(); + } + + private var _list:PickerList; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Picker List"; + + this.layout = new AnchorLayout(); + + var items:Array = []; + for(var i:int = 0; i < 150; i++) + { + var item:Object = {text: "Item " + (i + 1).toString()}; + items[i] = item; + } + items.fixed = true; + + this._list = new PickerList(); + this._list.prompt = "Select an Item"; + this._list.dataProvider = new ListCollection(items); + //normally, the first item is selected, but let's show the prompt + this._list.selectedIndex = -1; + var listLayoutData:AnchorLayoutData = new AnchorLayoutData(); + listLayoutData.horizontalCenter = 0; + listLayoutData.verticalCenter = 0; + this._list.layoutData = listLayoutData; + this.addChildAt(this._list, 0); + + //the typical item helps us set an ideal width for the button + //if we don't use a typical item, the button will resize to fit + //the currently selected item. + this._list.typicalItem = { text: "Select an Item" }; + this._list.labelField = "text"; + + this._list.listFactory = function():List + { + var list:List = new List(); + //notice that we're setting typicalItem on the list separately. we + //may want to have the list measure at a different width, so it + //might need a different typical item than the picker list's button. + list.typicalItem = { text: "Item 1000" }; + list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + //notice that we're setting labelField on the item renderers + //separately. the default item renderer has a labelField property, + //but a custom item renderer may not even have a label, so + //PickerList cannot simply pass its labelField down to item + //renderers automatically + renderer.labelField = "text"; + return renderer; + }; + return list; + }; + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ProgressBarScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ProgressBarScreen.as new file mode 100644 index 0000000000..d83506eac8 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ProgressBarScreen.as @@ -0,0 +1,117 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.ProgressBar; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.animation.Tween; + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ProgressBarScreen extends PanelScreen + { + public static var globalStyleProvider:IStyleProvider; + + public function ProgressBarScreen() + { + super(); + } + + private var _horizontalProgress:ProgressBar; + private var _verticalProgress:ProgressBar; + + private var _horizontalProgressTween:Tween; + private var _verticalProgressTween:Tween; + + override protected function get defaultStyleProvider():IStyleProvider + { + return ProgressBarScreen.globalStyleProvider; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Progress Bar"; + + this._horizontalProgress = new ProgressBar(); + this._horizontalProgress.direction = ProgressBar.DIRECTION_HORIZONTAL; + this._horizontalProgress.minimum = 0; + this._horizontalProgress.maximum = 1; + this._horizontalProgress.value = 0; + this.addChild(this._horizontalProgress); + + this._verticalProgress = new ProgressBar(); + this._verticalProgress.direction = ProgressBar.DIRECTION_VERTICAL; + this._verticalProgress.minimum = 0; + this._verticalProgress.maximum = 100; + this._verticalProgress.value = 0; + this.addChild(this._verticalProgress); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this._horizontalProgressTween = new Tween(this._horizontalProgress, 5); + this._horizontalProgressTween.animate("value", 1); + this._horizontalProgressTween.repeatCount = int.MAX_VALUE; + Starling.juggler.add(this._horizontalProgressTween); + + this._verticalProgressTween = new Tween(this._verticalProgress, 8); + this._verticalProgressTween.animate("value", 100); + this._verticalProgressTween.repeatCount = int.MAX_VALUE; + Starling.juggler.add(this._verticalProgressTween); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + if(this._horizontalProgressTween) + { + Starling.juggler.remove(this._horizontalProgressTween); + this._horizontalProgressTween = null; + } + if(this._verticalProgressTween) + { + Starling.juggler.remove(this._verticalProgressTween); + this._verticalProgressTween = null; + } + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ScrollTextScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ScrollTextScreen.as new file mode 100644 index 0000000000..0ca1d5a246 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ScrollTextScreen.as @@ -0,0 +1,79 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.ScrollText; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ScrollTextScreen extends PanelScreen + { + public function ScrollTextScreen() + { + super(); + } + + private var _scrollText:ScrollText; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Scroll Text"; + + this.layout = new AnchorLayout(); + + this._scrollText = new ScrollText(); + this._scrollText.text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nSed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.\n\nNeque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?\n\nAt vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."; + this._scrollText.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._scrollText); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderScreen.as new file mode 100644 index 0000000000..ed4d33df79 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderScreen.as @@ -0,0 +1,125 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.Slider; + import feathers.examples.componentsExplorer.data.SliderSettings; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + [Event(name="showSettings",type="starling.events.Event")] + + public class SliderScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public static var globalStyleProvider:IStyleProvider; + + public function SliderScreen() + { + super(); + } + + public var settings:SliderSettings; + + private var _horizontalSlider:Slider; + private var _verticalSlider:Slider; + + override protected function get defaultStyleProvider():IStyleProvider + { + return SliderScreen.globalStyleProvider; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Slider"; + + this._horizontalSlider = new Slider(); + this._horizontalSlider.direction = Slider.DIRECTION_HORIZONTAL; + this._horizontalSlider.minimum = 0; + this._horizontalSlider.maximum = 100; + this._horizontalSlider.value = 50; + this._horizontalSlider.step = this.settings.step; + this._horizontalSlider.page = this.settings.page; + this._horizontalSlider.liveDragging = this.settings.liveDragging; + this._horizontalSlider.addEventListener(Event.CHANGE, horizontalSlider_changeHandler); + this.addChild(this._horizontalSlider); + + this._verticalSlider = new Slider(); + this._verticalSlider.direction = Slider.DIRECTION_VERTICAL; + this._verticalSlider.minimum = 0; + this._verticalSlider.maximum = 100; + this._verticalSlider.value = 50; + this._verticalSlider.step = this.settings.step; + this._verticalSlider.page = this.settings.page; + this._verticalSlider.liveDragging = this.settings.liveDragging; + this._verticalSlider.addEventListener(Event.CHANGE, horizontalSlider_changeHandler); + this.addChild(this._verticalSlider); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function horizontalSlider_changeHandler(event:Event):void + { + trace("slider change:", this._horizontalSlider.value.toString()); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderSettingsScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderSettingsScreen.as new file mode 100644 index 0000000000..160daf277b --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderSettingsScreen.as @@ -0,0 +1,134 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.controls.ToggleSwitch; + import feathers.data.ListCollection; + import feathers.examples.componentsExplorer.data.SliderSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class SliderSettingsScreen extends PanelScreen + { + public function SliderSettingsScreen() + { + super(); + } + + public var settings:SliderSettings; + + private var _list:List; + private var _liveDraggingToggle:ToggleSwitch; + private var _stepStepper:NumericStepper; + private var _pageStepper:NumericStepper; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Slider Settings"; + + this.layout = new AnchorLayout(); + + this._liveDraggingToggle = new ToggleSwitch(); + this._liveDraggingToggle.isSelected = this.settings.liveDragging; + this._liveDraggingToggle.addEventListener(Event.CHANGE, liveDraggingToggle_changeHandler); + + this._stepStepper = new NumericStepper(); + this._stepStepper.minimum = 1; + this._stepStepper.maximum = 20; + this._stepStepper.step = 1; + this._stepStepper.value = this.settings.step; + this._stepStepper.addEventListener(Event.CHANGE, stepStepper_changeHandler); + + this._pageStepper = new NumericStepper(); + this._pageStepper.minimum = 1; + this._pageStepper.maximum = 20; + this._pageStepper.step = 1; + this._pageStepper.value = this.settings.page; + this._pageStepper.addEventListener(Event.CHANGE, pageStepper_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "liveDragging", accessory: this._liveDraggingToggle }, + { label: "step", accessory: this._stepStepper }, + { label: "page", accessory: this._pageStepper }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function liveDraggingToggle_changeHandler(event:Event):void + { + this.settings.liveDragging = this._liveDraggingToggle.isSelected; + } + + private function stepStepper_changeHandler(event:Event):void + { + this.settings.step = this._stepStepper.value; + } + + private function pageStepper_changeHandler(event:Event):void + { + this.settings.page = this._pageStepper.value; + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TabBarScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TabBarScreen.as new file mode 100644 index 0000000000..c629bbcd1e --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TabBarScreen.as @@ -0,0 +1,101 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Label; + import feathers.controls.PanelScreen; + import feathers.controls.TabBar; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class TabBarScreen extends PanelScreen + { + public function TabBarScreen() + { + super(); + } + + private var _tabBar:TabBar; + private var _label:Label; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Tab Bar"; + + this.layout = new AnchorLayout(); + + this._tabBar = new TabBar(); + this._tabBar.dataProvider = new ListCollection( + [ + { label: "One" }, + { label: "Two" }, + { label: "Three" }, + ]); + this._tabBar.addEventListener(Event.CHANGE, tabBar_changeHandler); + this._tabBar.layoutData = new AnchorLayoutData(NaN, 0, 0, 0); + this.addChild(this._tabBar); + + this._label = new Label(); + this._label.text = "selectedIndex: " + this._tabBar.selectedIndex.toString(); + var labelLayoutData:AnchorLayoutData = new AnchorLayoutData(); + labelLayoutData.horizontalCenter = 0; + labelLayoutData.verticalCenter = 0; + this._label.layoutData = labelLayoutData; + this.addChild(DisplayObject(this._label)); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function tabBar_changeHandler(event:Event):void + { + this._label.text = "selectedIndex: " + this._tabBar.selectedIndex.toString(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TextInputScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TextInputScreen.as new file mode 100644 index 0000000000..599b8200b3 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TextInputScreen.as @@ -0,0 +1,105 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.TextInput; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class TextInputScreen extends PanelScreen + { + public static var globalStyleProvider:IStyleProvider; + + public function TextInputScreen() + { + } + + private var _input:TextInput; + private var _disabledInput:TextInput; + private var _passwordInput:TextInput; + private var _notEditableInput:TextInput; + private var _searchInput:TextInput; + + override protected function get defaultStyleProvider():IStyleProvider + { + return TextInputScreen.globalStyleProvider; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Text Input"; + + this._input = new TextInput(); + this._input.prompt = "Normal Text Input"; + this.addChild(this._input); + + this._disabledInput = new TextInput(); + this._disabledInput.prompt = "Disabled Input"; + this._disabledInput.isEnabled = false; + this.addChild(this._disabledInput); + + this._searchInput = new TextInput(); + this._searchInput.styleNameList.add(TextInput.ALTERNATE_STYLE_NAME_SEARCH_TEXT_INPUT); + this._searchInput.prompt = "Search Input"; + this.addChild(this._searchInput); + + this._passwordInput = new TextInput(); + this._passwordInput.prompt = "Password Input"; + this._passwordInput.displayAsPassword = true; + this.addChild(this._passwordInput); + + this._notEditableInput = new TextInput(); + this._notEditableInput.prompt = "Not Editable"; + this._notEditableInput.isEditable = false; + this.addChild(this._notEditableInput); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ToggleScreen.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ToggleScreen.as new file mode 100644 index 0000000000..d2f077d0d6 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ToggleScreen.as @@ -0,0 +1,181 @@ +package feathers.examples.componentsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Check; + import feathers.controls.Header; + import feathers.controls.LayoutGroup; + import feathers.controls.PanelScreen; + import feathers.controls.Radio; + import feathers.controls.ToggleSwitch; + import feathers.core.ToggleGroup; + import feathers.layout.ILayout; + import feathers.skins.IStyleProvider; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class ToggleScreen extends PanelScreen + { + public static var globalStyleProvider:IStyleProvider; + + public function ToggleScreen() + { + super(); + } + + private var _toggleSwitchContainer:LayoutGroup; + private var _checkContainer:LayoutGroup; + private var _radioContainer:LayoutGroup; + private var _toggleSwitch:ToggleSwitch; + private var _check1:Check; + private var _check2:Check; + private var _check3:Check; + private var _radio1:Radio; + private var _radio2:Radio; + private var _radio3:Radio; + private var _radioGroup:ToggleGroup; + + override protected function get defaultStyleProvider():IStyleProvider + { + return ToggleScreen.globalStyleProvider; + } + + protected var _innerLayout:ILayout; + + public function get innerLayout():ILayout + { + return this._innerLayout; + } + + public function set innerLayout(value:ILayout):void + { + if(this._innerLayout == value) + { + return; + } + this._innerLayout = value; + this.invalidate(INVALIDATION_FLAG_LAYOUT); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Toggles"; + + this._toggleSwitchContainer = new LayoutGroup(); + this.addChild(this._toggleSwitchContainer); + + this._toggleSwitch = new ToggleSwitch(); + this._toggleSwitch.isSelected = false; + this._toggleSwitch.addEventListener(Event.CHANGE, toggleSwitch_changeHandler); + this._toggleSwitchContainer.addChild(this._toggleSwitch); + + this._checkContainer = new LayoutGroup(); + this.addChild(this._checkContainer); + + this._check1 = new Check(); + this._check1.isSelected = false; + this._check1.label = "Check 1"; + this._checkContainer.addChild(this._check1); + + this._check2 = new Check(); + this._check2.isSelected = false; + this._check2.label = "Check 2"; + this._checkContainer.addChild(this._check2); + + this._check3 = new Check(); + this._check3.isSelected = false; + this._check3.label = "Check 3"; + this._checkContainer.addChild(this._check3); + + this._radioGroup = new ToggleGroup(); + this._radioGroup.addEventListener(Event.CHANGE, radioGroup_changeHandler); + + this._radioContainer = new LayoutGroup(); + this.addChild(this._radioContainer); + + this._radio1 = new Radio(); + this._radio1.label = "Radio 1"; + this._radioGroup.addItem(this._radio1); + this._radioContainer.addChild(this._radio1); + + this._radio2 = new Radio(); + this._radio2.label = "Radio 2"; + this._radioGroup.addItem(this._radio2); + this._radioContainer.addChild(this._radio2); + + this._radio3 = new Radio(); + this._radio3.label = "Radio 3"; + this._radioGroup.addItem(this._radio3); + this._radioContainer.addChild(this._radio3); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + override protected function draw():void + { + var layoutInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_LAYOUT); + + if(layoutInvalid) + { + this._toggleSwitchContainer.layout = this._innerLayout; + this._checkContainer.layout = this._innerLayout; + this._radioContainer.layout = this._innerLayout; + } + + super.draw(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function toggleSwitch_changeHandler(event:Event):void + { + trace("toggle switch isSelected:", this._toggleSwitch.isSelected); + } + + private function radioGroup_changeHandler(event:Event):void + { + trace("radio group change:", this._radioGroup.selectedIndex); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} \ No newline at end of file diff --git a/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/themes/ComponentsExplorerTheme.as b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/themes/ComponentsExplorerTheme.as new file mode 100644 index 0000000000..6077f874e8 --- /dev/null +++ b/examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/themes/ComponentsExplorerTheme.as @@ -0,0 +1,135 @@ +package feathers.examples.componentsExplorer.themes +{ + import feathers.controls.Button; + import feathers.controls.ImageLoader; + import feathers.controls.PanelScreen; + import feathers.examples.componentsExplorer.data.EmbeddedAssets; + import feathers.examples.componentsExplorer.screens.ButtonScreen; + import feathers.examples.componentsExplorer.screens.CalloutScreen; + import feathers.examples.componentsExplorer.screens.ItemRendererScreen; + import feathers.examples.componentsExplorer.screens.LabelScreen; + import feathers.examples.componentsExplorer.screens.ProgressBarScreen; + import feathers.examples.componentsExplorer.screens.SliderScreen; + import feathers.examples.componentsExplorer.screens.TextInputScreen; + import feathers.examples.componentsExplorer.screens.ToggleScreen; + import feathers.layout.HorizontalLayout; + import feathers.layout.VerticalLayout; + import feathers.themes.MetalWorksMobileTheme; + + public class ComponentsExplorerTheme extends MetalWorksMobileTheme + { + public function ComponentsExplorerTheme() + { + super(); + } + + override protected function initializeStyleProviders():void + { + super.initializeStyleProviders(); + + this.getStyleProviderForClass(ButtonScreen).defaultStyleFunction = this.setButtonScreenStyles; + this.getStyleProviderForClass(Button).setFunctionForStyleName(ButtonScreen.CHILD_STYLE_NAME_ICON_BUTTON, this.setButtonScreenIconButtonStyles); + + this.getStyleProviderForClass(CalloutScreen).defaultStyleFunction = this.setCalloutScreenStyles; + this.getStyleProviderForClass(LabelScreen).defaultStyleFunction = this.setLabelScreenStyles; + this.getStyleProviderForClass(ItemRendererScreen).defaultStyleFunction = this.setItemRendererScreenStyles; + this.getStyleProviderForClass(ProgressBarScreen).defaultStyleFunction = this.setProgressBarScreenStyles; + this.getStyleProviderForClass(SliderScreen).defaultStyleFunction = this.setSliderScreenStyles; + this.getStyleProviderForClass(TextInputScreen).defaultStyleFunction = this.setTextInputScreenStyles; + this.getStyleProviderForClass(ToggleScreen).defaultStyleFunction = this.setToggleScreenStyles; + } + + protected function setButtonScreenIconButtonStyles(button:Button):void + { + //don't forget to set styles from the super class, if required + this.setButtonStyles(button); + + var icon:ImageLoader = new ImageLoader(); + icon.source = EmbeddedAssets.SKULL_ICON_DARK; + //the icon will be blurry if it's not on a whole pixel. ImageLoader + //can snap to pixels to fix that issue. + icon.snapToPixels = true; + icon.textureScale = this.scale; + button.defaultIcon = icon; + } + + protected function setButtonScreenStyles(screen:ButtonScreen):void + { + var verticalLayout:VerticalLayout = new VerticalLayout(); + verticalLayout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER; + verticalLayout.verticalAlign = VerticalLayout.VERTICAL_ALIGN_TOP; + verticalLayout.padding = this.gutterSize; + verticalLayout.gap = this.smallGutterSize; + screen.layout = verticalLayout; + + screen.verticalScrollPolicy = PanelScreen.SCROLL_POLICY_ON; + } + + protected function setCalloutScreenStyles(screen:CalloutScreen):void + { + screen.layoutPadding = this.gutterSize; + } + + protected function setItemRendererScreenStyles(screen:ItemRendererScreen):void + { + screen.itemRendererGap = this.gutterSize; + } + + protected function setLabelScreenStyles(screen:LabelScreen):void + { + var verticalLayout:VerticalLayout = new VerticalLayout(); + verticalLayout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_JUSTIFY; + verticalLayout.verticalAlign = VerticalLayout.VERTICAL_ALIGN_TOP; + verticalLayout.padding = this.gutterSize; + verticalLayout.gap = this.smallGutterSize; + screen.layout = verticalLayout; + + screen.verticalScrollPolicy = PanelScreen.SCROLL_POLICY_ON; + } + + protected function setProgressBarScreenStyles(screen:ProgressBarScreen):void + { + var layout:HorizontalLayout = new HorizontalLayout(); + layout.horizontalAlign = HorizontalLayout.HORIZONTAL_ALIGN_CENTER; + layout.verticalAlign = HorizontalLayout.VERTICAL_ALIGN_MIDDLE; + layout.gap = this.gutterSize; + screen.layout = layout; + } + + protected function setSliderScreenStyles(screen:SliderScreen):void + { + var layout:HorizontalLayout = new HorizontalLayout(); + layout.horizontalAlign = HorizontalLayout.HORIZONTAL_ALIGN_CENTER; + layout.verticalAlign = HorizontalLayout.VERTICAL_ALIGN_MIDDLE; + layout.gap = this.gutterSize; + screen.layout = layout; + } + + protected function setTextInputScreenStyles(screen:TextInputScreen):void + { + var verticalLayout:VerticalLayout = new VerticalLayout(); + verticalLayout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER; + verticalLayout.verticalAlign = VerticalLayout.VERTICAL_ALIGN_TOP; + verticalLayout.padding = this.gutterSize; + verticalLayout.gap = this.smallGutterSize; + screen.layout = verticalLayout; + + screen.verticalScrollPolicy = PanelScreen.SCROLL_POLICY_ON; + } + + protected function setToggleScreenStyles(screen:ToggleScreen):void + { + var layout:VerticalLayout = new VerticalLayout(); + layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER; + layout.verticalAlign = VerticalLayout.VERTICAL_ALIGN_MIDDLE; + layout.gap = this.gutterSize; + screen.layout = layout; + + var innerLayout:HorizontalLayout = new HorizontalLayout(); + innerLayout.horizontalAlign = HorizontalLayout.HORIZONTAL_ALIGN_CENTER; + innerLayout.verticalAlign = HorizontalLayout.VERTICAL_ALIGN_MIDDLE; + innerLayout.gap = this.gutterSize; + screen.innerLayout = innerLayout; + } + } +} diff --git a/examples/DisplayObjectExplorer/README.md b/examples/DisplayObjectExplorer/README.md new file mode 100644 index 0000000000..9c2983b99e --- /dev/null +++ b/examples/DisplayObjectExplorer/README.md @@ -0,0 +1,13 @@ +# Display Object Explorer for Feathers + +Demonstrates the resizing behavior of `Scale9Image`, `Scale3Image`, and `TiledImage` display objects from [Feathers](http://feathersui.com/). + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Display Object Explorer](http://feathersui.com/examples/display-object-explorer/) in your browser. \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/assets/images/horizontal-grip.png b/examples/DisplayObjectExplorer/assets/images/horizontal-grip.png new file mode 100644 index 0000000000..a1a5b23e97 Binary files /dev/null and b/examples/DisplayObjectExplorer/assets/images/horizontal-grip.png differ diff --git a/examples/DisplayObjectExplorer/assets/images/scale3.png b/examples/DisplayObjectExplorer/assets/images/scale3.png new file mode 100644 index 0000000000..50612e14f7 Binary files /dev/null and b/examples/DisplayObjectExplorer/assets/images/scale3.png differ diff --git a/examples/DisplayObjectExplorer/assets/images/scale9.png b/examples/DisplayObjectExplorer/assets/images/scale9.png new file mode 100644 index 0000000000..78253e5fe6 Binary files /dev/null and b/examples/DisplayObjectExplorer/assets/images/scale9.png differ diff --git a/examples/DisplayObjectExplorer/assets/images/tile-pattern.png b/examples/DisplayObjectExplorer/assets/images/tile-pattern.png new file mode 100644 index 0000000000..9e767e1f02 Binary files /dev/null and b/examples/DisplayObjectExplorer/assets/images/tile-pattern.png differ diff --git a/examples/DisplayObjectExplorer/assets/images/vertical-grip.png b/examples/DisplayObjectExplorer/assets/images/vertical-grip.png new file mode 100644 index 0000000000..1500db3c16 Binary files /dev/null and b/examples/DisplayObjectExplorer/assets/images/vertical-grip.png differ diff --git a/examples/DisplayObjectExplorer/build.properties b/examples/DisplayObjectExplorer/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/DisplayObjectExplorer/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/build.xml b/examples/DisplayObjectExplorer/build.xml new file mode 100644 index 0000000000..5da16c422d --- /dev/null +++ b/examples/DisplayObjectExplorer/build.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/sdk.properties b/examples/DisplayObjectExplorer/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/DisplayObjectExplorer/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/source/DisplayObjectExplorer-app.xml b/examples/DisplayObjectExplorer/source/DisplayObjectExplorer-app.xml new file mode 100644 index 0000000000..70bb942e11 --- /dev/null +++ b/examples/DisplayObjectExplorer/source/DisplayObjectExplorer-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.DisplayObjectExplorer + Feathers Display Objects + Feathers Display Objects + 2.0.1 + Display Object Explorer example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + DisplayObjectExplorer.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/source/DisplayObjectExplorer.as b/examples/DisplayObjectExplorer/source/DisplayObjectExplorer.as new file mode 100644 index 0000000000..cc689406e5 --- /dev/null +++ b/examples/DisplayObjectExplorer/source/DisplayObjectExplorer.as @@ -0,0 +1,152 @@ +package +{ + import feathers.examples.displayObjects.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="640",height="960",frameRate="60",backgroundColor="#4a4137")] + public class DisplayObjectExplorer extends Sprite + { + public function DisplayObjectExplorer() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + } +} \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/source/DisplayObjectExplorerWeb.as b/examples/DisplayObjectExplorer/source/DisplayObjectExplorerWeb.as new file mode 100644 index 0000000000..fcd3a2950c --- /dev/null +++ b/examples/DisplayObjectExplorer/source/DisplayObjectExplorerWeb.as @@ -0,0 +1,56 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class DisplayObjectExplorerWeb extends MovieClip + { + public function DisplayObjectExplorerWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.displayObjects.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/Main.as b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/Main.as new file mode 100644 index 0000000000..548fedb00a --- /dev/null +++ b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/Main.as @@ -0,0 +1,107 @@ +package feathers.examples.displayObjects +{ + import feathers.controls.LayoutGroup; + import feathers.controls.ScreenNavigator; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.TabBar; + import feathers.data.ListCollection; + import feathers.examples.displayObjects.screens.Scale3ImageScreen; + import feathers.examples.displayObjects.screens.Scale9ImageScreen; + import feathers.examples.displayObjects.screens.TiledImageScreen; + import feathers.examples.displayObjects.themes.DisplayObjectExplorerTheme; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.motion.transitions.TabBarSlideTransitionManager; + + import starling.events.Event; + import starling.events.ResizeEvent; + + public class Main extends LayoutGroup + { + private static const SCALE_9_IMAGE:String = "scale9Image"; + private static const SCALE_3_IMAGE:String = "scale3Image"; + private static const TILED_IMAGE:String = "tiledImage"; + + public function Main() + { + } + + private var _navigator:ScreenNavigator; + private var _tabBar:TabBar; + private var _transitionManager:TabBarSlideTransitionManager; + + override protected function initialize():void + { + super.initialize(); + + this.layout = new AnchorLayout(); + + this.setSize(this.stage.stageWidth, this.stage.stageHeight); + + this.stage.addEventListener(ResizeEvent.RESIZE, stage_resizeHandler); + + new DisplayObjectExplorerTheme(); + + this._navigator = new ScreenNavigator(); + this._navigator.addScreen(SCALE_9_IMAGE, new ScreenNavigatorItem(Scale9ImageScreen)); + this._navigator.addScreen(SCALE_3_IMAGE, new ScreenNavigatorItem(Scale3ImageScreen)); + this._navigator.addScreen(TILED_IMAGE, new ScreenNavigatorItem(TiledImageScreen)); + this._navigator.addEventListener(Event.CHANGE, navigator_changeHandler); + this.addChild(this._navigator); + + this._tabBar = new TabBar(); + this._tabBar.addEventListener(Event.CHANGE, tabBar_changeHandler); + this.addChild(this._tabBar); + this._tabBar.dataProvider = new ListCollection( + [ + { label: "Scale 9", action: SCALE_9_IMAGE }, + { label: "Scale 3", action: SCALE_3_IMAGE }, + { label: "Tiled", action: TILED_IMAGE } + ]); + + var tabBarLayoutData:AnchorLayoutData = new AnchorLayoutData(); + tabBarLayoutData.right = 0; + tabBarLayoutData.bottom = 0; + tabBarLayoutData.left = 0; + this._tabBar.layoutData = tabBarLayoutData; + + var navigatorLayoutData:AnchorLayoutData = new AnchorLayoutData(); + navigatorLayoutData.top = 0; + navigatorLayoutData.right = 0; + navigatorLayoutData.bottom = 0; + navigatorLayoutData.left = 0; + navigatorLayoutData.bottomAnchorDisplayObject = this._tabBar; + this._navigator.layoutData = navigatorLayoutData; + + this._navigator.showScreen(SCALE_9_IMAGE); + + this._transitionManager = new TabBarSlideTransitionManager(this._navigator, this._tabBar); + this._transitionManager.duration = 0.4; + } + + private function navigator_changeHandler(event:Event):void + { + var dataProvider:ListCollection = this._tabBar.dataProvider; + var itemCount:int = dataProvider.length; + for(var i:int = 0; i < itemCount; i++) + { + var item:Object = dataProvider.getItemAt(i); + if(this._navigator.activeScreenID == item.action) + { + this._tabBar.selectedIndex = i; + break; + } + } + } + + private function tabBar_changeHandler(event:Event):void + { + this._navigator.showScreen(this._tabBar.selectedItem.action); + } + + private function stage_resizeHandler(event:ResizeEvent):void + { + this.setSize(this.stage.stageWidth, this.stage.stageHeight); + } + } +} diff --git a/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/Scale3ImageScreen.as b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/Scale3ImageScreen.as new file mode 100644 index 0000000000..0231cbc095 --- /dev/null +++ b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/Scale3ImageScreen.as @@ -0,0 +1,182 @@ +package feathers.examples.displayObjects.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Screen; + import feathers.display.Scale3Image; + import feathers.examples.displayObjects.themes.DisplayObjectExplorerTheme; + import feathers.skins.IStyleProvider; + import feathers.textures.Scale3Textures; + + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + import starling.textures.Texture; + + public class Scale3ImageScreen extends Screen + { + [Embed(source="/../assets/images/scale3.png")] + private static const SCALE_3_TEXTURE:Class; + + public static var globalStyleProvider:IStyleProvider; + + public function Scale3ImageScreen() + { + } + + private var _header:Header; + private var _image:Scale3Image; + private var _rightButton:Button; + private var _bottomButton:Button; + + private var _minDisplayObjectWidth:Number; + private var _minDisplayObjectHeight:Number; + private var _maxDisplayObjectWidth:Number; + private var _maxDisplayObjectHeight:Number; + private var _startX:Number; + private var _startY:Number; + private var _startWidth:Number; + private var _startHeight:Number; + private var _rightTouchPointID:int = -1; + private var _bottomTouchPointID:int = -1; + + private var _texture:Texture; + + private var _padding:Number = 0; + + public function get padding():Number + { + return this._padding; + } + + public function set padding(value:Number):void + { + if(this._padding == value) + { + return; + } + this._padding = value; + this.invalidate(INVALIDATION_FLAG_LAYOUT); + } + + override protected function get defaultStyleProvider():IStyleProvider + { + return Scale3ImageScreen.globalStyleProvider; + } + + override public function dispose():void + { + if(this._texture) + { + this._texture.dispose(); + this._texture = null; + } + super.dispose(); + } + + override protected function initialize():void + { + this._header = new Header(); + this._header.title = "Scale 3 Image"; + this.addChild(this._header); + + this._texture = Texture.fromEmbeddedAsset(SCALE_3_TEXTURE, false); + var textures:Scale3Textures = new Scale3Textures(this._texture, 60, 80, Scale3Textures.DIRECTION_HORIZONTAL); + this._image = new Scale3Image(textures); + this._image.width /= 2; + this._image.height /= 2; + this._minDisplayObjectWidth = this._image.width; + this._minDisplayObjectHeight = this._image.height; + this.addChild(this._image); + + this._rightButton = new Button(); + this._rightButton.styleNameList.add(DisplayObjectExplorerTheme.THEME_NAME_RIGHT_GRIP); + this._rightButton.addEventListener(TouchEvent.TOUCH, rightButton_touchHandler); + this.addChild(this._rightButton); + + this._bottomButton = new Button(); + this._bottomButton.styleNameList.add(DisplayObjectExplorerTheme.THEME_NAME_BOTTOM_GRIP); + this._bottomButton.addEventListener(TouchEvent.TOUCH, bottomButton_touchHandler); + this.addChild(this._bottomButton); + } + + override protected function draw():void + { + this._header.width = this.actualWidth; + this._header.validate(); + + this._image.x = this._padding; + this._image.y = this._header.height + this._padding; + + this._rightButton.validate(); + this._bottomButton.validate(); + + this._maxDisplayObjectWidth = this.actualWidth - this._rightButton.width - this._image.x; + this._maxDisplayObjectHeight = this.actualHeight - this._bottomButton.height - this._image.y; + + this._image.width = Math.max(this._minDisplayObjectWidth, Math.min(this._maxDisplayObjectWidth, this._image.width)); + this._image.height = Math.max(this._minDisplayObjectHeight, Math.min(this._maxDisplayObjectHeight, this._image.height)); + + this.layoutButtons(); + } + + private function layoutButtons():void + { + this._rightButton.x = this._image.x + this._image.width; + this._rightButton.y = this._image.y + (this._image.height - this._rightButton.height) / 2; + + this._bottomButton.x = this._image.x + (this._image.width - this._bottomButton.width) / 2; + this._bottomButton.y = this._image.y + this._image.height; + } + + private function rightButton_touchHandler(event:TouchEvent):void + { + var touch:Touch = event.getTouch(this._rightButton); + if(!touch || (this._rightTouchPointID >= 0 && touch.id != this._rightTouchPointID)) + { + return; + } + + if(touch.phase == TouchPhase.BEGAN) + { + this._rightTouchPointID = touch.id; + this._startX = touch.globalX; + this._startWidth = this._image.width; + } + else if(touch.phase == TouchPhase.MOVED) + { + this._image.width = Math.min(this._maxDisplayObjectWidth, Math.max(this._image.height, this._minDisplayObjectWidth, this._startWidth + touch.globalX - this._startX)); + this.layoutButtons() + } + else if(touch.phase == TouchPhase.ENDED) + { + this._rightTouchPointID = -1; + } + } + + private function bottomButton_touchHandler(event:TouchEvent):void + { + var touch:Touch = event.getTouch(this._bottomButton); + if(!touch || (this._bottomTouchPointID >= 0 && touch.id != this._bottomTouchPointID)) + { + return; + } + + if(touch.phase == TouchPhase.BEGAN) + { + this._bottomTouchPointID = touch.id; + this._startY = touch.globalY; + this._startHeight = this._image.height; + } + else if(touch.phase == TouchPhase.MOVED) + { + this._image.height = Math.min(this._image.width, this._maxDisplayObjectHeight, Math.max(this._minDisplayObjectHeight, this._startHeight + touch.globalY - this._startY)); + this.layoutButtons() + } + else if(touch.phase == TouchPhase.ENDED) + { + this._bottomTouchPointID = -1; + } + } + } +} diff --git a/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/Scale9ImageScreen.as b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/Scale9ImageScreen.as new file mode 100644 index 0000000000..4c9c81c5ae --- /dev/null +++ b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/Scale9ImageScreen.as @@ -0,0 +1,182 @@ +package feathers.examples.displayObjects.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Screen; + import feathers.display.Scale9Image; + import feathers.examples.displayObjects.themes.DisplayObjectExplorerTheme; + import feathers.skins.IStyleProvider; + import feathers.textures.Scale9Textures; + + import flash.geom.Rectangle; + + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + import starling.textures.Texture; + + public class Scale9ImageScreen extends Screen + { + [Embed(source="/../assets/images/scale9.png")] + private static const SCALE_9_TEXTURE:Class; + + public static var globalStyleProvider:IStyleProvider; + + public function Scale9ImageScreen() + { + } + + private var _header:Header; + private var _image:Scale9Image; + private var _rightButton:Button; + private var _bottomButton:Button; + + private var _minDisplayObjectWidth:Number; + private var _minDisplayObjectHeight:Number; + private var _maxDisplayObjectWidth:Number; + private var _maxDisplayObjectHeight:Number; + private var _startX:Number; + private var _startY:Number; + private var _startWidth:Number; + private var _startHeight:Number; + private var _rightTouchPointID:int = -1; + private var _bottomTouchPointID:int = -1; + + private var _texture:Texture; + + private var _padding:Number = 0; + + public function get padding():Number + { + return this._padding; + } + + public function set padding(value:Number):void + { + if(this._padding == value) + { + return; + } + this._padding = value; + this.invalidate(INVALIDATION_FLAG_LAYOUT); + } + + override protected function get defaultStyleProvider():IStyleProvider + { + return Scale9ImageScreen.globalStyleProvider; + } + + override public function dispose():void + { + if(this._texture) + { + this._texture.dispose(); + this._texture = null; + } + super.dispose(); + } + + override protected function initialize():void + { + this._header = new Header(); + this._header.title = "Scale 9 Image"; + this.addChild(this._header); + + this._texture = Texture.fromEmbeddedAsset(SCALE_9_TEXTURE, false); + var textures:Scale9Textures = new Scale9Textures(this._texture, new Rectangle(20, 20, 20, 20)); + this._image = new Scale9Image(textures); + this._minDisplayObjectWidth = 40; + this._minDisplayObjectHeight = 40; + this.addChild(this._image); + + this._rightButton = new Button(); + this._rightButton.styleNameList.add(DisplayObjectExplorerTheme.THEME_NAME_RIGHT_GRIP); + this._rightButton.addEventListener(TouchEvent.TOUCH, rightButton_touchHandler); + this.addChild(this._rightButton); + + this._bottomButton = new Button(); + this._bottomButton.styleNameList.add(DisplayObjectExplorerTheme.THEME_NAME_BOTTOM_GRIP); + this._bottomButton.addEventListener(TouchEvent.TOUCH, bottomButton_touchHandler); + this.addChild(this._bottomButton); + } + + override protected function draw():void + { + this._header.width = this.actualWidth; + this._header.validate(); + + this._image.x = this._padding; + this._image.y = this._header.height + this._padding; + + this._rightButton.validate(); + this._bottomButton.validate(); + + this._maxDisplayObjectWidth = this.actualWidth - this._rightButton.width - this._image.x; + this._maxDisplayObjectHeight = this.actualHeight - this._bottomButton.height - this._image.y; + + this._image.width = Math.max(this._minDisplayObjectWidth, Math.min(this._maxDisplayObjectWidth, this._image.width)); + this._image.height = Math.max(this._minDisplayObjectHeight, Math.min(this._maxDisplayObjectHeight, this._image.height)); + + this.layoutButtons(); + } + + private function layoutButtons():void + { + this._rightButton.x = this._image.x + this._image.width; + this._rightButton.y = this._image.y + (this._image.height - this._rightButton.height) / 2; + + this._bottomButton.x = this._image.x + (this._image.width - this._bottomButton.width) / 2; + this._bottomButton.y = this._image.y + this._image.height; + } + + private function rightButton_touchHandler(event:TouchEvent):void + { + var touch:Touch = event.getTouch(this._rightButton); + if(!touch || (this._rightTouchPointID >= 0 && touch.id != this._rightTouchPointID)) + { + return; + } + + if(touch.phase == TouchPhase.BEGAN) + { + this._rightTouchPointID = touch.id; + this._startX = touch.globalX; + this._startWidth = this._image.width; + } + else if(touch.phase == TouchPhase.MOVED) + { + this._image.width = Math.min(this._maxDisplayObjectWidth, Math.max(this._minDisplayObjectWidth, this._startWidth + touch.globalX - this._startX)); + this.layoutButtons() + } + else if(touch.phase == TouchPhase.ENDED) + { + this._rightTouchPointID = -1; + } + } + + private function bottomButton_touchHandler(event:TouchEvent):void + { + var touch:Touch = event.getTouch(this._bottomButton); + if(!touch || (this._bottomTouchPointID >= 0 && touch.id != this._bottomTouchPointID)) + { + return; + } + + if(touch.phase == TouchPhase.BEGAN) + { + this._bottomTouchPointID = touch.id; + this._startY = touch.globalY; + this._startHeight = this._image.height; + } + else if(touch.phase == TouchPhase.MOVED) + { + this._image.height = Math.min(this._maxDisplayObjectHeight, Math.max(this._minDisplayObjectHeight, this._startHeight + touch.globalY - this._startY)); + this.layoutButtons() + } + else if(touch.phase == TouchPhase.ENDED) + { + this._bottomTouchPointID = -1; + } + } + } +} diff --git a/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/TiledImageScreen.as b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/TiledImageScreen.as new file mode 100644 index 0000000000..f631b08eea --- /dev/null +++ b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/screens/TiledImageScreen.as @@ -0,0 +1,179 @@ +package feathers.examples.displayObjects.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Screen; + import feathers.display.TiledImage; + import feathers.examples.displayObjects.themes.DisplayObjectExplorerTheme; + import feathers.skins.IStyleProvider; + + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + import starling.textures.Texture; + + public class TiledImageScreen extends Screen + { + [Embed(source="/../assets/images/tile-pattern.png")] + private static const TILE_TEXTURE:Class; + + public static var globalStyleProvider:IStyleProvider; + + public function TiledImageScreen() + { + } + + private var _header:Header; + private var _image:TiledImage; + private var _rightButton:Button; + private var _bottomButton:Button; + + private var _minDisplayObjectWidth:Number; + private var _minDisplayObjectHeight:Number; + private var _maxDisplayObjectWidth:Number; + private var _maxDisplayObjectHeight:Number; + private var _startX:Number; + private var _startY:Number; + private var _startWidth:Number; + private var _startHeight:Number; + private var _rightTouchPointID:int = -1; + private var _bottomTouchPointID:int = -1; + + private var _texture:Texture; + + private var _padding:Number = 0; + + public function get padding():Number + { + return this._padding; + } + + public function set padding(value:Number):void + { + if(this._padding == value) + { + return; + } + this._padding = value; + this.invalidate(INVALIDATION_FLAG_LAYOUT); + } + + override protected function get defaultStyleProvider():IStyleProvider + { + return TiledImageScreen.globalStyleProvider; + } + + override public function dispose():void + { + if(this._texture) + { + this._texture.dispose(); + this._texture = null; + } + super.dispose(); + } + + override protected function initialize():void + { + this._header = new Header(); + this._header.title = "Tiled Image"; + this.addChild(this._header); + + this._texture = Texture.fromEmbeddedAsset(TILE_TEXTURE); + + this._image = new TiledImage(this._texture); + this._minDisplayObjectWidth = this._image.width; + this._minDisplayObjectHeight = this._image.height; + this.addChild(this._image); + + this._rightButton = new Button(); + this._rightButton.styleNameList.add(DisplayObjectExplorerTheme.THEME_NAME_RIGHT_GRIP); + this._rightButton.addEventListener(TouchEvent.TOUCH, rightButton_touchHandler); + this.addChild(this._rightButton); + + this._bottomButton = new Button(); + this._bottomButton.styleNameList.add(DisplayObjectExplorerTheme.THEME_NAME_BOTTOM_GRIP); + this._bottomButton.addEventListener(TouchEvent.TOUCH, bottomButton_touchHandler); + this.addChild(this._bottomButton); + } + + override protected function draw():void + { + this._header.width = this.actualWidth; + this._header.validate(); + + this._image.x = this._padding; + this._image.y = this._header.height + this._padding; + + this._rightButton.validate(); + this._bottomButton.validate(); + + this._maxDisplayObjectWidth = this.actualWidth - this._rightButton.width - this._image.x; + this._maxDisplayObjectHeight = this.actualHeight - this._bottomButton.height - this._image.y; + + this._image.width = Math.max(this._minDisplayObjectWidth, Math.min(this._maxDisplayObjectWidth, this._image.width)); + this._image.height = Math.max(this._minDisplayObjectHeight, Math.min(this._maxDisplayObjectHeight, this._image.height)); + + this.layoutButtons(); + } + + private function layoutButtons():void + { + this._rightButton.x = this._image.x + this._image.width; + this._rightButton.y = this._image.y + (this._image.height - this._rightButton.height) / 2; + + this._bottomButton.x = this._image.x + (this._image.width - this._bottomButton.width) / 2; + this._bottomButton.y = this._image.y + this._image.height; + } + + private function rightButton_touchHandler(event:TouchEvent):void + { + var touch:Touch = event.getTouch(this._rightButton); + if(!touch || (this._rightTouchPointID >= 0 && touch.id != this._rightTouchPointID)) + { + return; + } + + if(touch.phase == TouchPhase.BEGAN) + { + this._rightTouchPointID = touch.id; + this._startX = touch.globalX; + this._startWidth = this._image.width; + } + else if(touch.phase == TouchPhase.MOVED) + { + this._image.width = Math.min(this._maxDisplayObjectWidth, Math.max(this._minDisplayObjectWidth, this._startWidth + touch.globalX - this._startX)); + this.layoutButtons() + } + else if(touch.phase == TouchPhase.ENDED) + { + this._rightTouchPointID = -1; + } + } + + private function bottomButton_touchHandler(event:TouchEvent):void + { + var touch:Touch = event.getTouch(this._bottomButton); + if(!touch || (this._bottomTouchPointID >= 0 && touch.id != this._bottomTouchPointID)) + { + return; + } + + if(touch.phase == TouchPhase.BEGAN) + { + this._bottomTouchPointID = touch.id; + this._startY = touch.globalY; + this._startHeight = this._image.height; + } + else if(touch.phase == TouchPhase.MOVED) + { + this._image.height = Math.min(this._maxDisplayObjectHeight, Math.max(this._minDisplayObjectHeight, this._startHeight + touch.globalY - this._startY)); + this.layoutButtons() + } + else if(touch.phase == TouchPhase.ENDED) + { + this._bottomTouchPointID = -1; + } + } + } +} diff --git a/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/themes/DisplayObjectExplorerTheme.as b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/themes/DisplayObjectExplorerTheme.as new file mode 100644 index 0000000000..2ada437dd5 --- /dev/null +++ b/examples/DisplayObjectExplorer/source/feathers/examples/displayObjects/themes/DisplayObjectExplorerTheme.as @@ -0,0 +1,77 @@ +package feathers.examples.displayObjects.themes +{ + import feathers.controls.Button; + import feathers.examples.displayObjects.screens.Scale3ImageScreen; + import feathers.examples.displayObjects.screens.Scale9ImageScreen; + import feathers.examples.displayObjects.screens.TiledImageScreen; + import feathers.themes.MetalWorksMobileTheme; + + import starling.display.Image; + import starling.textures.Texture; + + public class DisplayObjectExplorerTheme extends MetalWorksMobileTheme + { + [Embed(source="/../assets/images/horizontal-grip.png")] + private static const HORIZONTAL_GRIP:Class; + + [Embed(source="/../assets/images/vertical-grip.png")] + private static const VERTICAL_GRIP:Class; + + public static const THEME_NAME_RIGHT_GRIP:String = "right-grip"; + public static const THEME_NAME_BOTTOM_GRIP:String = "bottom-grip"; + + public function DisplayObjectExplorerTheme() + { + super(); + } + + private var _rightGripTexture:Texture; + private var _bottomGripTexture:Texture; + + override protected function initializeTextures():void + { + super.initializeTextures(); + this._rightGripTexture = Texture.fromEmbeddedAsset(VERTICAL_GRIP, false); + this._bottomGripTexture = Texture.fromEmbeddedAsset(HORIZONTAL_GRIP, false); + } + + override protected function initializeStyleProviders():void + { + super.initializeStyleProviders(); + this.getStyleProviderForClass(Button).setFunctionForStyleName(THEME_NAME_RIGHT_GRIP, setRightGripStyles); + this.getStyleProviderForClass(Button).setFunctionForStyleName(THEME_NAME_BOTTOM_GRIP, setBottomGripStyles); + this.getStyleProviderForClass(Scale9ImageScreen).defaultStyleFunction = setScale9ImageScreenStyles; + this.getStyleProviderForClass(Scale3ImageScreen).defaultStyleFunction = setScale3ImageScreenStyles; + this.getStyleProviderForClass(TiledImageScreen).defaultStyleFunction = setTiledImageScreenStyles; + } + + private function setRightGripStyles(button:Button):void + { + var rightSkin:Image = new Image(this._rightGripTexture); + rightSkin.scaleX = rightSkin.scaleY = this.scale; + button.defaultSkin = rightSkin; + } + + private function setBottomGripStyles(button:Button):void + { + var bottomSkin:Image = new Image(this._bottomGripTexture); + bottomSkin.scaleX = bottomSkin.scaleY = this.scale; + button.defaultSkin = bottomSkin; + } + + private function setScale9ImageScreenStyles(screen:Scale9ImageScreen):void + { + screen.padding = 30 * this.scale; + } + + private function setScale3ImageScreenStyles(screen:Scale3ImageScreen):void + { + screen.padding = 30 * this.scale; + } + + private function setTiledImageScreenStyles(screen:TiledImageScreen):void + { + screen.padding = 30 * this.scale; + } + } +} diff --git a/examples/DragAndDrop/README.md b/examples/DragAndDrop/README.md new file mode 100644 index 0000000000..5aace47d96 --- /dev/null +++ b/examples/DragAndDrop/README.md @@ -0,0 +1,13 @@ +# Feathers Drag and Drop + +A very simple of drag and drop in [Feathers](http://feathersui.com/). Includes examples of implementing the `IDragSource` and `IDropTarget` interfaces. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the AeonDesktopTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/AeonDesktopTheme/swc/AeonDesktopTheme.swc + +## Web Demo + +View the [Drag and Drop Example](http://feathersui.com/examples/drag-and-drop/) in your web browser. \ No newline at end of file diff --git a/examples/DragAndDrop/build.properties b/examples/DragAndDrop/build.properties new file mode 100644 index 0000000000..5cfbcdf8b4 --- /dev/null +++ b/examples/DragAndDrop/build.properties @@ -0,0 +1,6 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksDesktopTheme/source +output.path = ${basedir}/output + +swf.version = 18 \ No newline at end of file diff --git a/examples/DragAndDrop/build.xml b/examples/DragAndDrop/build.xml new file mode 100644 index 0000000000..c145db29d1 --- /dev/null +++ b/examples/DragAndDrop/build.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/DragAndDrop/sdk.properties b/examples/DragAndDrop/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/DragAndDrop/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/DragAndDrop/source/DragAndDrop.as b/examples/DragAndDrop/source/DragAndDrop.as new file mode 100644 index 0000000000..5d264603cc --- /dev/null +++ b/examples/DragAndDrop/source/DragAndDrop.as @@ -0,0 +1,71 @@ +package +{ + import feathers.examples.dragDrop.Main; + + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.geom.Rectangle; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class DragAndDrop extends Sprite + { + public function DragAndDrop() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + this._starling.start(); + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/DragAndDrop/source/feathers/examples/dragDrop/DragSource.as b/examples/DragAndDrop/source/feathers/examples/dragDrop/DragSource.as new file mode 100644 index 0000000000..65fee3ce6d --- /dev/null +++ b/examples/DragAndDrop/source/feathers/examples/dragDrop/DragSource.as @@ -0,0 +1,98 @@ +package feathers.examples.dragDrop +{ + import feathers.controls.LayoutGroup; + import feathers.dragDrop.DragData; + import feathers.dragDrop.DragDropManager; + import feathers.dragDrop.IDragSource; + import feathers.events.DragDropEvent; + + import starling.display.DisplayObject; + import starling.display.Quad; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class DragSource extends LayoutGroup implements IDragSource + { + public function DragSource(dragFormat:String) + { + this._dragFormat = dragFormat; + this.addEventListener(TouchEvent.TOUCH, touchHandler); + this.addEventListener(DragDropEvent.DRAG_START, dragStartHandler); + this.addEventListener(DragDropEvent.DRAG_COMPLETE, dragCompleteHandler); + } + + private var _background:Quad; + private var _touchID:int = -1; + private var _draggedObject:DisplayObject; + private var _dragFormat:String; + + override protected function initialize():void + { + this._background = new Quad(1, 1, 0x36322e); + this.addChildAt(this._background, 0); + } + + override protected function draw():void + { + super.draw(); + this._background.width = this.actualWidth; + this._background.height = this.actualHeight; + } + + private function touchHandler(event:TouchEvent):void + { + if(DragDropManager.isDragging) + { + //one drag at a time, please + return; + } + if(this._touchID >= 0) + { + var touch:Touch = event.getTouch(this._draggedObject, null, this._touchID); + if(touch.phase == TouchPhase.MOVED) + { + this._touchID = -1; + + var avatar:Quad = new Quad(100, 100, 0xff8800); + avatar.alpha = 0.5; + + var dragData:DragData = new DragData(); + dragData.setDataForFormat(this._dragFormat, this._draggedObject); + DragDropManager.startDrag(this, touch, dragData, avatar, -avatar.width / 2, -avatar.height / 2); + } + else if(touch.phase == TouchPhase.ENDED) + { + this._touchID = -1; + } + } + else + { + touch = event.getTouch(this, TouchPhase.BEGAN); + if(!touch || touch.target == this || touch.target == this._background) + { + return; + } + this._touchID = touch.id; + this._draggedObject = touch.target; + } + } + + private function dragStartHandler(event:DragDropEvent, dragData:DragData):void + { + //the drag was started with the call to DragDropManager.startDrag() + } + + private function dragCompleteHandler(event:DragDropEvent, dragData:DragData):void + { + if(event.isDropped) + { + //the object was dropped somewhere + } + else + { + //the drag cancelled and the object was not dropped + } + } + } +} diff --git a/examples/DragAndDrop/source/feathers/examples/dragDrop/DropTarget.as b/examples/DragAndDrop/source/feathers/examples/dragDrop/DropTarget.as new file mode 100644 index 0000000000..7abdf0bf7a --- /dev/null +++ b/examples/DragAndDrop/source/feathers/examples/dragDrop/DropTarget.as @@ -0,0 +1,66 @@ +package feathers.examples.dragDrop +{ + import feathers.controls.LayoutGroup; + import feathers.dragDrop.DragData; + import feathers.dragDrop.DragDropManager; + import feathers.dragDrop.IDropTarget; + import feathers.events.DragDropEvent; + + import starling.display.DisplayObject; + import starling.display.Quad; + + public class DropTarget extends LayoutGroup implements IDropTarget + { + private static const DEFAULT_COLOR:uint = 0x36322e; + private static const HOVER_COLOR:uint = 0x26221e; + + public function DropTarget(dragFormat:String) + { + this._dragFormat = dragFormat; + this.addEventListener(DragDropEvent.DRAG_ENTER, dragEnterHandler); + this.addEventListener(DragDropEvent.DRAG_EXIT, dragExitHandler); + this.addEventListener(DragDropEvent.DRAG_DROP, dragDropHandler); + } + + private var _background:Quad; + private var _dragFormat:String; + + override protected function initialize():void + { + this._background = new Quad(1, 1, DEFAULT_COLOR); + this.addChildAt(this._background, 0); + } + + override protected function draw():void + { + super.draw(); + this._background.width = this.actualWidth; + this._background.height = this.actualHeight; + } + + private function dragEnterHandler(event:DragDropEvent, dragData:DragData):void + { + if(!dragData.hasDataForFormat(this._dragFormat)) + { + return; + } + DragDropManager.acceptDrag(this); + this._background.color = HOVER_COLOR; + } + + private function dragExitHandler(event:DragDropEvent, dragData:DragData):void + { + this._background.color = DEFAULT_COLOR; + } + + private function dragDropHandler(event:DragDropEvent, dragData:DragData):void + { + var droppedObject:DisplayObject = DisplayObject(dragData.getDataForFormat(this._dragFormat)) + droppedObject.x = event.localX - droppedObject.width / 2; + droppedObject.y = event.localY - droppedObject.height / 2; + this.addChild(droppedObject); + + this._background.color = DEFAULT_COLOR; + } + } +} diff --git a/examples/DragAndDrop/source/feathers/examples/dragDrop/Main.as b/examples/DragAndDrop/source/feathers/examples/dragDrop/Main.as new file mode 100644 index 0000000000..3e52761435 --- /dev/null +++ b/examples/DragAndDrop/source/feathers/examples/dragDrop/Main.as @@ -0,0 +1,79 @@ +package feathers.examples.dragDrop +{ + import feathers.controls.Button; + import feathers.controls.Label; + import feathers.dragDrop.IDragSource; + import feathers.dragDrop.IDropTarget; + import feathers.themes.MetalWorksDesktopTheme; + + import starling.display.Quad; + import starling.display.Sprite; + import starling.events.Event; + + public class Main extends Sprite implements IDragSource, IDropTarget + { + private static const DRAG_FORMAT:String = "draggableQuad"; + + public function Main() + { + this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + } + + private var _draggableQuad:Quad; + private var _dragSource:DragSource; + private var _dropTarget:DropTarget; + private var _resetButton:Button; + + private function reset():void + { + this._draggableQuad.x = 40; + this._draggableQuad.y = 40; + this._dragSource.addChild(this._draggableQuad); + } + + private function addedToStageHandler(event:Event):void + { + new MetalWorksDesktopTheme(); + + this._draggableQuad = new Quad(100, 100, 0xff8800); + + this._dragSource = new DragSource(DRAG_FORMAT); + this._dragSource.width = 320; + this._dragSource.height = 420; + this._dragSource.x = 80; + this._dragSource.y = 80; + this.addChild(this._dragSource); + + this._dropTarget = new DropTarget(DRAG_FORMAT); + this._dropTarget.width = 320; + this._dropTarget.height = 420; + this._dropTarget.x = 560; + this._dropTarget.y = 80; + this.addChild(this._dropTarget); + + this._resetButton = new Button(); + this._resetButton.label = "Reset"; + this._resetButton.addEventListener(Event.TRIGGERED, resetButton_triggeredHandler); + this.addChild(this._resetButton); + + this._resetButton.validate(); + this._resetButton.x = (this.stage.stageWidth - this._resetButton.width) / 2; + this._resetButton.y = this.stage.stageHeight - this._resetButton.height - 80; + + var instructions:Label = new Label(); + instructions.text = "Drag the square from the left container to the right container."; + this.addChild(instructions); + + instructions.validate(); + instructions.x = (this.stage.stageWidth - instructions.width) / 2; + instructions.y = (this._dragSource.y - instructions.height) / 2; + + this.reset(); + } + + private function resetButton_triggeredHandler(event:Event):void + { + this.reset(); + } + } +} diff --git a/examples/DrawersExplorer/README.md b/examples/DrawersExplorer/README.md new file mode 100644 index 0000000000..a619557ee4 --- /dev/null +++ b/examples/DrawersExplorer/README.md @@ -0,0 +1,13 @@ +# Feathers Drawers Explorer + +A look at some of the options available to the `Drawers` component in [Feathers](http://feathersui.com/), presented as a mobile app. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Drawers Explorer](http://feathersui.com/examples/drawers-explorer/) in your browser. \ No newline at end of file diff --git a/examples/DrawersExplorer/build.properties b/examples/DrawersExplorer/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/DrawersExplorer/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/DrawersExplorer/build.xml b/examples/DrawersExplorer/build.xml new file mode 100644 index 0000000000..d14bf6f334 --- /dev/null +++ b/examples/DrawersExplorer/build.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/DrawersExplorer/sdk.properties b/examples/DrawersExplorer/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/DrawersExplorer/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/DrawersExplorer/source/DrawersExplorer-app.xml b/examples/DrawersExplorer/source/DrawersExplorer-app.xml new file mode 100644 index 0000000000..de9a1194e6 --- /dev/null +++ b/examples/DrawersExplorer/source/DrawersExplorer-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.DrawersExplorer + Drawers + Drawers + 2.0.1 + Drawers Explorer example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + DrawersExplorer.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/DrawersExplorer/source/DrawersExplorer.as b/examples/DrawersExplorer/source/DrawersExplorer.as new file mode 100644 index 0000000000..151503929e --- /dev/null +++ b/examples/DrawersExplorer/source/DrawersExplorer.as @@ -0,0 +1,155 @@ +package +{ + import feathers.examples.drawersExplorer.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class DrawersExplorer extends Sprite + { + public function DrawersExplorer() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/DrawersExplorer/source/DrawersExplorerWeb.as b/examples/DrawersExplorer/source/DrawersExplorerWeb.as new file mode 100644 index 0000000000..67439c7bfe --- /dev/null +++ b/examples/DrawersExplorer/source/DrawersExplorerWeb.as @@ -0,0 +1,59 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class DrawersExplorerWeb extends MovieClip + { + public function DrawersExplorerWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.drawersExplorer.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/Main.as b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/Main.as new file mode 100644 index 0000000000..e44eca9974 --- /dev/null +++ b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/Main.as @@ -0,0 +1,116 @@ +package feathers.examples.drawersExplorer +{ + import feathers.controls.Drawers; + import feathers.examples.drawersExplorer.skins.DrawersExplorerTheme; + import feathers.examples.drawersExplorer.views.ContentView; + import feathers.examples.drawersExplorer.views.DrawerView; + + import starling.display.Sprite; + import starling.events.Event; + + public class Main extends Sprite + { + public function Main() + { + super(); + this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + } + + private var _drawers:Drawers; + + private function changeDockMode(drawer:DrawerView, dockMode:String):void + { + switch(drawer) + { + case this._drawers.topDrawer: + { + this._drawers.topDrawerDockMode = dockMode; + break; + } + case this._drawers.rightDrawer: + { + this._drawers.rightDrawerDockMode = dockMode; + break; + } + case this._drawers.bottomDrawer: + { + this._drawers.bottomDrawerDockMode = dockMode; + break; + } + case this._drawers.leftDrawer: + { + this._drawers.leftDrawerDockMode = dockMode; + break; + } + } + } + + private function addedToStageHandler(event:Event):void + { + new DrawersExplorerTheme(); + + this._drawers = new Drawers(); + + //a drawer may be opened by dragging from the edge of the content + //you can also set it to drag from anywhere inside the content + //or you can disable gestures entirely and only open a drawer when + //an event is dispatched by the content or by calling a function + //on the drawer component to open a drawer programmatically. + this._drawers.openGesture = Drawers.OPEN_GESTURE_DRAG_CONTENT_EDGE; + + this._drawers.content = new ContentView(); + //these events are dispatched by the content + //Drawers listens for each of these events and opens the drawer + //associated with an event when it is dispatched + this._drawers.topDrawerToggleEventType = ContentView.TOGGLE_TOP_DRAWER; + this._drawers.rightDrawerToggleEventType = ContentView.TOGGLE_RIGHT_DRAWER; + this._drawers.bottomDrawerToggleEventType = ContentView.TOGGLE_BOTTOM_DRAWER; + this._drawers.leftDrawerToggleEventType = ContentView.TOGGLE_LEFT_DRAWER; + + var topDrawer:DrawerView = new DrawerView("Top"); + topDrawer.styleNameList.add(DrawersExplorerTheme.THEME_NAME_TOP_AND_BOTTOM_DRAWER); + topDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_NONE, drawer_dockNoneHandler); + topDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_BOTH, drawer_dockBothHandler); + //a drawer may be any display object + this._drawers.topDrawer = topDrawer; + //by default, a drawer is not docked. it may be opened and closed + //based on user interaction or events dispatched by the content. + this._drawers.topDrawerDockMode = Drawers.DOCK_MODE_NONE; + + var rightDrawer:DrawerView = new DrawerView("Right"); + rightDrawer.styleNameList.add(DrawersExplorerTheme.THEME_NAME_LEFT_AND_RIGHT_DRAWER); + rightDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_NONE, drawer_dockNoneHandler); + rightDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_BOTH, drawer_dockBothHandler); + this._drawers.rightDrawer = rightDrawer; + this._drawers.rightDrawerDockMode = Drawers.DOCK_MODE_NONE; + + var bottomDrawer:DrawerView = new DrawerView("Bottom"); + bottomDrawer.styleNameList.add(DrawersExplorerTheme.THEME_NAME_TOP_AND_BOTTOM_DRAWER); + bottomDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_NONE, drawer_dockNoneHandler); + bottomDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_BOTH, drawer_dockBothHandler); + this._drawers.bottomDrawer = bottomDrawer; + this._drawers.bottomDrawerDockMode = Drawers.DOCK_MODE_NONE; + + var leftDrawer:DrawerView = new DrawerView("Left"); + leftDrawer.styleNameList.add(DrawersExplorerTheme.THEME_NAME_LEFT_AND_RIGHT_DRAWER); + leftDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_NONE, drawer_dockNoneHandler); + leftDrawer.addEventListener(DrawerView.CHANGE_DOCK_MODE_TO_BOTH, drawer_dockBothHandler); + this._drawers.leftDrawer = leftDrawer; + this._drawers.leftDrawerDockMode = Drawers.DOCK_MODE_NONE; + + this.addChild(this._drawers); + } + + private function drawer_dockNoneHandler(event:Event):void + { + var drawer:DrawerView = DrawerView(event.currentTarget); + this.changeDockMode(drawer, Drawers.DOCK_MODE_NONE); + } + + private function drawer_dockBothHandler(event:Event):void + { + var drawer:DrawerView = DrawerView(event.currentTarget); + this.changeDockMode(drawer, Drawers.DOCK_MODE_BOTH); + } + } +} \ No newline at end of file diff --git a/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/skins/DrawersExplorerTheme.as b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/skins/DrawersExplorerTheme.as new file mode 100644 index 0000000000..acf8a7944f --- /dev/null +++ b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/skins/DrawersExplorerTheme.as @@ -0,0 +1,61 @@ +package feathers.examples.drawersExplorer.skins +{ + import feathers.examples.drawersExplorer.views.ContentView; + import feathers.examples.drawersExplorer.views.DrawerView; + import feathers.layout.HorizontalLayout; + import feathers.layout.VerticalLayout; + import feathers.themes.MetalWorksMobileTheme; + + import starling.display.Quad; + + public class DrawersExplorerTheme extends MetalWorksMobileTheme + { + public static const THEME_NAME_TOP_AND_BOTTOM_DRAWER:String = "drawers-explorer-top-and-bottom-drawer"; + public static const THEME_NAME_LEFT_AND_RIGHT_DRAWER:String = "drawers-explorer-left-and-right-drawer"; + + public function DrawersExplorerTheme() + { + super(); + } + + override protected function initializeStyleProviders():void + { + super.initializeStyleProviders(); + this.getStyleProviderForClass(ContentView).defaultStyleFunction = setContentViewStyles; + this.getStyleProviderForClass(DrawerView).setFunctionForStyleName(THEME_NAME_TOP_AND_BOTTOM_DRAWER, setTopAndBottomDrawerViewStyles); + this.getStyleProviderForClass(DrawerView).setFunctionForStyleName(THEME_NAME_LEFT_AND_RIGHT_DRAWER, setLeftAndRightDrawerViewStyles); + } + + protected function setContentViewStyles(view:ContentView):void + { + var layout:VerticalLayout = new VerticalLayout(); + layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER; + layout.padding = 20 * this.scale; + view.layout = layout; + } + + protected function setLeftAndRightDrawerViewStyles(view:DrawerView):void + { + view.backgroundSkin = new Quad(10, 10, LIST_BACKGROUND_COLOR); + + var layout:VerticalLayout = new VerticalLayout(); + layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER; + layout.verticalAlign = VerticalLayout.VERTICAL_ALIGN_MIDDLE; + layout.padding = 20 * this.scale; + layout.gap = 20 * this.scale; + view.layout = layout; + } + + protected function setTopAndBottomDrawerViewStyles(view:DrawerView):void + { + view.backgroundSkin = new Quad(10, 10, GROUPED_LIST_HEADER_BACKGROUND_COLOR); + + var layout:HorizontalLayout = new HorizontalLayout(); + layout.horizontalAlign = HorizontalLayout.HORIZONTAL_ALIGN_CENTER; + layout.verticalAlign = HorizontalLayout.VERTICAL_ALIGN_MIDDLE; + layout.padding = 20 * this.scale; + layout.gap = 20 * this.scale; + view.layout = layout; + } + } +} diff --git a/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/ContentView.as b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/ContentView.as new file mode 100644 index 0000000000..370e9839ee --- /dev/null +++ b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/ContentView.as @@ -0,0 +1,106 @@ +package feathers.examples.drawersExplorer.views +{ + import feathers.controls.Button; + import feathers.controls.Panel; + import feathers.controls.ScrollContainer; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.IStyleProvider; + + import starling.events.Event; + + public class ContentView extends ScrollContainer + { + public static var globalStyleProvider:IStyleProvider; + + public static const TOGGLE_TOP_DRAWER:String = "toggleTopDrawer"; + public static const TOGGLE_RIGHT_DRAWER:String = "toggleRightDrawer"; + public static const TOGGLE_BOTTOM_DRAWER:String = "toggleBottomDrawer"; + public static const TOGGLE_LEFT_DRAWER:String = "toggleLeftDrawer"; + + public function ContentView() + { + + } + + private var _topButton:Button; + private var _rightButton:Button; + private var _bottomButton:Button; + private var _leftButton:Button; + + override protected function get defaultStyleProvider():IStyleProvider + { + return ContentView.globalStyleProvider; + } + + override protected function initialize():void + { + var openControlsPanel:Panel = new Panel(); + openControlsPanel.headerProperties.title = "Open Drawers"; + openControlsPanel.layout = new AnchorLayout(); + this.addChild(openControlsPanel); + + this._topButton = new Button(); + this._topButton.label = "Top"; + this._topButton.addEventListener(Event.TRIGGERED, topButton_triggeredHandler); + var topLayoutData:AnchorLayoutData = new AnchorLayoutData(); + topLayoutData.horizontalCenter = 0; + this._topButton.layoutData = topLayoutData; + openControlsPanel.addChild(this._topButton); + + this._rightButton = new Button(); + this._rightButton.label = "Right"; + this._rightButton.addEventListener(Event.TRIGGERED, rightButton_triggeredHandler); + var rightLayoutData:AnchorLayoutData = new AnchorLayoutData(); + rightLayoutData.verticalCenter = 0; + this._rightButton.layoutData = rightLayoutData; + openControlsPanel.addChild(this._rightButton); + + this._bottomButton = new Button(); + this._bottomButton.label = "Bottom"; + this._bottomButton.addEventListener(Event.TRIGGERED, bottomButton_triggeredHandler); + var bottomLayoutData:AnchorLayoutData = new AnchorLayoutData(); + bottomLayoutData.horizontalCenter = 0; + this._bottomButton.layoutData = bottomLayoutData; + openControlsPanel.addChild(this._bottomButton); + + this._leftButton = new Button(); + this._leftButton.label = "Left"; + this._leftButton.addEventListener(Event.TRIGGERED, leftButton_triggeredHandler); + var leftLayoutData:AnchorLayoutData = new AnchorLayoutData(); + leftLayoutData.verticalCenter = 0; + this._leftButton.layoutData = leftLayoutData; + openControlsPanel.addChild(this._leftButton); + + this._topButton.validate(); + var verticalOffset:Number = this._topButton.height * 1.5; + topLayoutData.verticalCenter = -verticalOffset; + bottomLayoutData.verticalCenter = verticalOffset; + + this._rightButton.validate(); + var horizontalOffset:Number = this._rightButton.width; + rightLayoutData.horizontalCenter = horizontalOffset; + leftLayoutData.horizontalCenter = -horizontalOffset; + } + + private function topButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(TOGGLE_TOP_DRAWER); + } + + private function rightButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(TOGGLE_RIGHT_DRAWER); + } + + private function bottomButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(TOGGLE_BOTTOM_DRAWER); + } + + private function leftButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(TOGGLE_LEFT_DRAWER); + } + } +} diff --git a/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/DrawerView.as b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/DrawerView.as new file mode 100644 index 0000000000..392fc6f8d6 --- /dev/null +++ b/examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/DrawerView.as @@ -0,0 +1,62 @@ +package feathers.examples.drawersExplorer.views +{ + import feathers.controls.Check; + import feathers.controls.Label; + import feathers.controls.ScrollContainer; + import feathers.skins.IStyleProvider; + + import starling.events.Event; + + public class DrawerView extends ScrollContainer + { + public static var globalStyleProvider:IStyleProvider; + + public static const CHANGE_DOCK_MODE_TO_NONE:String = "changeDockModeToNone"; + public static const CHANGE_DOCK_MODE_TO_BOTH:String = "changeDockModeToBoth"; + + public function DrawerView(title:String) + { + super(); + this._title = title; + } + + private var _title:String; + private var _titleLabel:Label; + private var _dockCheck:Check; + + override protected function get defaultStyleProvider():IStyleProvider + { + return DrawerView.globalStyleProvider; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this._titleLabel = new Label(); + this._titleLabel.styleNameList.add(Label.ALTERNATE_STYLE_NAME_HEADING); + this._titleLabel.text = this._title; + this.addChild(this._titleLabel); + + this._dockCheck = new Check(); + this._dockCheck.isSelected = false; + this._dockCheck.label = "Dock"; + this._dockCheck.addEventListener(Event.CHANGE, dockCheck_changeHandler); + this.addChild(this._dockCheck); + } + + private function dockCheck_changeHandler(event:Event):void + { + if(this._dockCheck.isSelected) + { + this.dispatchEventWith(CHANGE_DOCK_MODE_TO_BOTH); + } + else + { + this.dispatchEventWith(CHANGE_DOCK_MODE_TO_NONE); + } + } + + } +} diff --git a/examples/Gallery/README.md b/examples/Gallery/README.md new file mode 100644 index 0000000000..9e3e6e967a --- /dev/null +++ b/examples/Gallery/README.md @@ -0,0 +1,17 @@ +# Gallery Example for Feathers + +Displays a simple gallery of images from the [Flickr API](http://www.flickr.com/services/api/) using [Feathers](http://feathersui.com/). This example shows how to use a horizontal layout and a custom item renderer with a List component. Additionally, this example demonstrates how to [extend a theme](http://feathersui.com/help/extending-themes.html) by adding a new style to the `MetalWorksMobileTheme` example theme. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +Additionally, you will need a [Flickr API key](https://www.flickr.com/services/apps/create/apply/). Pass in this API key by defining a conditional constant named `CONFIG::FLICKR_API_KEY`. If you are compiling with an IDE, conditional constants are usually defined somewhere in your project's settings. On the command line, you may use the `-define` compiler argument: + + -define+=CONFIG::FLICKR_API_KEY,'your flickr api key' + +## Web Demo + +View the [Gallery Example](http://feathersui.com/examples/gallery/) in your browser. \ No newline at end of file diff --git a/examples/Gallery/build.properties b/examples/Gallery/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/Gallery/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/Gallery/build.xml b/examples/Gallery/build.xml new file mode 100644 index 0000000000..51c819f0a7 --- /dev/null +++ b/examples/Gallery/build.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Gallery/sdk.properties b/examples/Gallery/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/Gallery/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/Gallery/source/Gallery-app.xml b/examples/Gallery/source/Gallery-app.xml new file mode 100644 index 0000000000..28ef91fe3a --- /dev/null +++ b/examples/Gallery/source/Gallery-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.Gallery + Feathers Gallery + Feathers Gallery + 2.0.1 + Gallery example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + Gallery.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/Gallery/source/Gallery.as b/examples/Gallery/source/Gallery.as new file mode 100644 index 0000000000..3077f0ff9d --- /dev/null +++ b/examples/Gallery/source/Gallery.as @@ -0,0 +1,153 @@ +package +{ + import feathers.examples.gallery.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class Gallery extends Sprite + { + public function Gallery() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/Gallery/source/GalleryWeb.as b/examples/Gallery/source/GalleryWeb.as new file mode 100644 index 0000000000..2869c8c295 --- /dev/null +++ b/examples/Gallery/source/GalleryWeb.as @@ -0,0 +1,89 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.geom.Rectangle; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class GalleryWeb extends MovieClip + { + public function GalleryWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + this.mouseEnabled = this.mouseChildren = false; + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.gallery.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.start(); + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + } + + private function enterFrameHandler(event:Event):void + { + if(this.stage.stageWidth > 0 && this.stage.stageHeight > 0) + { + this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler); + this.start(); + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function loaderInfo_completeHandler(event:Event):void + { + if(this.stage.stageWidth == 0 || this.stage.stageHeight == 0) + { + this.addEventListener(Event.ENTER_FRAME, enterFrameHandler); + return; + } + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/Gallery/source/feathers/examples/gallery/GalleryItem.as b/examples/Gallery/source/feathers/examples/gallery/GalleryItem.as new file mode 100644 index 0000000000..412d301ffa --- /dev/null +++ b/examples/Gallery/source/feathers/examples/gallery/GalleryItem.as @@ -0,0 +1,16 @@ +package feathers.examples.gallery +{ + public class GalleryItem + { + public function GalleryItem(title:String, url:String, thumbURL:String) + { + this.title = title; + this.url = url; + this.thumbURL = thumbURL; + } + + public var title:String; + public var url:String; + public var thumbURL:String; + } +} diff --git a/examples/Gallery/source/feathers/examples/gallery/GalleryItemRenderer.as b/examples/Gallery/source/feathers/examples/gallery/GalleryItemRenderer.as new file mode 100644 index 0000000000..d14468e90c --- /dev/null +++ b/examples/Gallery/source/feathers/examples/gallery/GalleryItemRenderer.as @@ -0,0 +1,410 @@ +package feathers.examples.gallery +{ + import feathers.controls.ImageLoader; + import feathers.controls.List; + import feathers.controls.renderers.IListItemRenderer; + import feathers.core.FeathersControl; + import feathers.events.FeathersEventType; + + import flash.geom.Point; + import flash.utils.Dictionary; + + import starling.animation.Transitions; + import starling.animation.Tween; + import starling.core.Starling; + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class GalleryItemRenderer extends FeathersControl implements IListItemRenderer + { + /** + * @private + */ + private static const HELPER_POINT:Point = new Point(); + + /** + * @private + */ + private static const HELPER_TOUCHES_VECTOR:Vector. = new []; + + /** + * @private + * This will only work in a single list. If this item renderer needs to + * be used by multiple lists, this data should be stored differently. + */ + private static const CACHED_BOUNDS:Dictionary = new Dictionary(false); + + /** + * Constructor. + */ + public function GalleryItemRenderer() + { + this.isQuickHitAreaEnabled = true; + this.addEventListener(TouchEvent.TOUCH, touchHandler); + this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler) + } + + /** + * @private + */ + protected var image:ImageLoader; + + /** + * @private + */ + protected var touchPointID:int = -1; + + /** + * @private + */ + protected var fadeTween:Tween; + + /** + * @private + */ + private var _index:int = -1; + + /** + * @inheritDoc + */ + public function get index():int + { + return this._index; + } + + /** + * @private + */ + public function set index(value:int):void + { + if(this._index == value) + { + return; + } + this._index = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + /** + * @private + */ + protected var _owner:List; + + /** + * @inheritDoc + */ + public function get owner():List + { + return List(this._owner); + } + + /** + * @private + */ + public function set owner(value:List):void + { + if(this._owner == value) + { + return; + } + if(this._owner) + { + this._owner.removeEventListener(FeathersEventType.SCROLL_START, owner_scrollStartHandler); + this._owner.removeEventListener(FeathersEventType.SCROLL_COMPLETE, owner_scrollCompleteHandler); + } + this._owner = value; + if(this._owner) + { + if(this.image) + { + this.image.delayTextureCreation = this._owner.isScrolling; + } + this._owner.addEventListener(FeathersEventType.SCROLL_START, owner_scrollStartHandler); + this._owner.addEventListener(FeathersEventType.SCROLL_COMPLETE, owner_scrollCompleteHandler); + } + this.invalidate(INVALIDATION_FLAG_DATA); + } + + /** + * @private + */ + private var _data:GalleryItem; + + /** + * @inheritDoc + */ + public function get data():Object + { + return this._data; + } + + /** + * @private + */ + public function set data(value:Object):void + { + if(this._data == value) + { + return; + } + this.touchPointID = -1; + this._data = GalleryItem(value); + this.invalidate(INVALIDATION_FLAG_DATA); + } + + /** + * @private + */ + private var _isSelected:Boolean; + + /** + * @inheritDoc + */ + public function get isSelected():Boolean + { + return this._isSelected; + } + + /** + * @private + */ + public function set isSelected(value:Boolean):void + { + if(this._isSelected == value) + { + return; + } + this._isSelected = value; + this.dispatchEventWith(Event.CHANGE); + } + + /** + * @private + */ + override protected function initialize():void + { + this.image = new ImageLoader(); + this.image.textureQueueDuration = 0.25; + this.image.addEventListener(Event.COMPLETE, image_completeHandler); + this.image.addEventListener(FeathersEventType.ERROR, image_errorHandler); + this.addChild(this.image); + } + + /** + * @private + */ + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + var selectionInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SELECTED); + var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE); + + if(dataInvalid) + { + if(this.fadeTween) + { + this.fadeTween.advanceTime(Number.MAX_VALUE); + } + if(this._data) + { + this.image.visible = false; + this.image.source = this._data.thumbURL; + } + else + { + this.image.source = null; + } + } + + sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid; + + if(sizeInvalid) + { + this.image.width = this.actualWidth; + this.image.height = this.actualHeight; + } + } + + /** + * @private + */ + protected function autoSizeIfNeeded():Boolean + { + var needsWidth:Boolean = isNaN(this.explicitWidth); + var needsHeight:Boolean = isNaN(this.explicitHeight); + if(!needsWidth && !needsHeight) + { + return false; + } + + this.image.width = this.image.height = NaN; + this.image.validate(); + var newWidth:Number = this.explicitWidth; + if(needsWidth) + { + if(this.image.isLoaded) + { + if(!CACHED_BOUNDS.hasOwnProperty(this._index)) + { + CACHED_BOUNDS[this._index] = new Point(); + } + var boundsFromCache:Point = Point(CACHED_BOUNDS[this._index]); + //also save it to a cache so that we can reuse the width and + //height values later if the same image needs to be loaded + //again. + newWidth = boundsFromCache.x = this.image.width; + } + else + { + if(CACHED_BOUNDS.hasOwnProperty(this._index)) + { + //if the image isn't loaded yet, but we've loaded it at + //least once before, we can use a cached value to avoid + //jittering when the image resizes + boundsFromCache = Point(CACHED_BOUNDS[this._index]); + newWidth = boundsFromCache.x; + } + else + { + //default to 100 if we've never displayed an image for + //this index yet. + newWidth = 100; + } + + } + } + var newHeight:Number = this.explicitHeight; + if(needsHeight) + { + if(this.image.isLoaded) + { + if(!CACHED_BOUNDS.hasOwnProperty(this._index)) + { + CACHED_BOUNDS[this._index] = new Point(); + } + boundsFromCache = Point(CACHED_BOUNDS[this._index]); + newHeight = boundsFromCache.y = this.image.height; + } + else + { + if(CACHED_BOUNDS.hasOwnProperty(this._index)) + { + boundsFromCache = Point(CACHED_BOUNDS[this._index]); + newHeight = boundsFromCache.y; + } + else + { + newHeight = 100; + } + } + } + return this.setSizeInternal(newWidth, newHeight, false); + } + + /** + * @private + */ + protected function fadeTween_onComplete():void + { + this.fadeTween = null; + } + + /** + * @private + */ + protected function removedFromStageHandler(event:Event):void + { + this.touchPointID = -1; + } + + /** + * @private + */ + protected function touchHandler(event:TouchEvent):void + { + var touches:Vector. = event.getTouches(this, null, HELPER_TOUCHES_VECTOR); + if(touches.length == 0) + { + return; + } + if(this.touchPointID >= 0) + { + var touch:Touch; + for each(var currentTouch:Touch in touches) + { + if(currentTouch.id == this.touchPointID) + { + touch = currentTouch; + break; + } + } + if(!touch) + { + HELPER_TOUCHES_VECTOR.length = 0; + return; + } + if(touch.phase == TouchPhase.ENDED) + { + this.touchPointID = -1; + + touch.getLocation(this, HELPER_POINT); + if(this.hitTest(HELPER_POINT, true) != null && !this._isSelected) + { + this.isSelected = true; + } + } + } + else + { + for each(touch in touches) + { + if(touch.phase == TouchPhase.BEGAN) + { + this.touchPointID = touch.id; + break; + } + } + } + HELPER_TOUCHES_VECTOR.length = 0; + } + + /** + * @private + */ + protected function owner_scrollStartHandler(event:Event):void + { + this.touchPointID = -1; + this.image.delayTextureCreation = true; + } + + /** + * @private + */ + protected function owner_scrollCompleteHandler(event:Event):void + { + this.image.delayTextureCreation = false; + } + + /** + * @private + */ + protected function image_completeHandler(event:Event):void + { + this.image.alpha = 0; + this.image.visible = true; + this.fadeTween = new Tween(this.image, 1, Transitions.EASE_OUT); + this.fadeTween.fadeTo(1); + this.fadeTween.onComplete = fadeTween_onComplete; + Starling.juggler.add(this.fadeTween); + this.invalidate(INVALIDATION_FLAG_SIZE); + } + + protected function image_errorHandler(event:Event):void + { + this.invalidate(INVALIDATION_FLAG_SIZE); + } + + } +} diff --git a/examples/Gallery/source/feathers/examples/gallery/GalleryTheme.as b/examples/Gallery/source/feathers/examples/gallery/GalleryTheme.as new file mode 100644 index 0000000000..98fcb3585b --- /dev/null +++ b/examples/Gallery/source/feathers/examples/gallery/GalleryTheme.as @@ -0,0 +1,32 @@ +package feathers.examples.gallery +{ + import feathers.controls.List; + import feathers.themes.MetalWorksMobileTheme; + + /** + * Extends MetalWorksMobileTheme to make some app-specific styling tweaks + */ + public class GalleryTheme extends MetalWorksMobileTheme + { + public function GalleryTheme() + { + super(true) + } + + override protected function initializeStyleProviders():void + { + super.initializeStyleProviders(); + this.getStyleProviderForClass(List).setFunctionForStyleName(Main.THUMBNAIL_LIST_NAME, this.setThumbnailListStyles); + } + + protected function setThumbnailListStyles(list:List):void + { + //start with the default list styles. we could start from scratch, + //if we wanted, but we're only making minor changes. + super.setListStyles(list); + + //we're not displaying scroll bars + list.scrollBarDisplayMode = List.SCROLL_BAR_DISPLAY_MODE_NONE; + } + } +} diff --git a/examples/Gallery/source/feathers/examples/gallery/Main.as b/examples/Gallery/source/feathers/examples/gallery/Main.as new file mode 100644 index 0000000000..68da0bd085 --- /dev/null +++ b/examples/Gallery/source/feathers/examples/gallery/Main.as @@ -0,0 +1,217 @@ +package feathers.examples.gallery +{ + import feathers.controls.Label; + import feathers.controls.List; + import feathers.data.ListCollection; + import feathers.layout.HorizontalLayout; + + import flash.display.Bitmap; + import flash.display.Loader; + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + import flash.system.LoaderContext; + + import starling.animation.Transitions; + import starling.animation.Tween; + import starling.core.Starling; + import starling.display.Image; + import starling.display.Sprite; + import starling.events.Event; + import starling.events.ResizeEvent; + import starling.textures.Texture; + + public class Main extends Sprite + { + //used by the extended theme + public static const THUMBNAIL_LIST_NAME:String = "thumbnailList"; + + private static const LOADER_CONTEXT:LoaderContext = new LoaderContext(true); + private static const FLICKR_URL:String = "https://api.flickr.com/services/rest/?method=flickr.interestingness.getList&api_key=" + CONFIG::FLICKR_API_KEY + "&format=rest"; + private static const FLICKR_PHOTO_URL:String = "https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}_{size}.jpg"; + + public function Main() + { + this.addEventListener(starling.events.Event.ADDED_TO_STAGE, addedToStageHandler); + } + + protected var selectedImage:Image; + protected var list:List; + protected var message:Label; + protected var apiLoader:URLLoader; + protected var loader:Loader; + protected var fadeTween:Tween; + protected var originalImageWidth:Number; + protected var originalImageHeight:Number; + + protected function layout():void + { + this.list.width = this.stage.stageWidth; + this.list.height = 100; + this.list.y = this.stage.stageHeight - this.list.height; + + if(this.selectedImage) + { + var availableHeight:Number = this.stage.stageHeight - this.list.height; + var widthScale:Number = this.stage.stageWidth / this.originalImageWidth; + var heightScale:Number = availableHeight / this.originalImageHeight; + this.selectedImage.scaleX = this.selectedImage.scaleY = Math.min(1, widthScale, heightScale); + this.selectedImage.x = (this.stage.stageWidth - this.selectedImage.width) / 2; + this.selectedImage.y = (availableHeight - this.selectedImage.height) / 2; + } + + this.message.validate(); + availableHeight = this.stage.stageHeight - this.list.height; + this.message.x = (this.stage.stageWidth - this.message.width) / 2; + this.message.y = (availableHeight - this.message.height) / 2; + } + + protected function list_changeHandler(event:starling.events.Event):void + { + var item:GalleryItem = GalleryItem(this.list.selectedItem); + if(!item) + { + if(this.selectedImage) + { + this.selectedImage.visible = false; + } + return; + } + if(this.loader) + { + this.loader.unloadAndStop(true); + } + else + { + this.loader = new Loader(); + this.loader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, loader_completeHandler); + this.loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loader_errorHandler); + this.loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_errorHandler); + } + this.loader.load(new URLRequest(item.url), LOADER_CONTEXT); + if(this.selectedImage) + { + this.selectedImage.visible = false; + } + if(this.fadeTween) + { + Starling.juggler.remove(this.fadeTween); + this.fadeTween = null; + } + this.message.text = "Loading..."; + this.layout(); + } + + protected function addedToStageHandler(event:starling.events.Event):void + { + //this is an *extended* version of MetalWorksMobileTheme + new GalleryTheme(); + + this.apiLoader = new URLLoader(); + this.apiLoader.addEventListener(flash.events.Event.COMPLETE, apiLoader_completeListener); + this.apiLoader.addEventListener(IOErrorEvent.IO_ERROR, apiLoader_errorListener); + this.apiLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, apiLoader_errorListener); + this.apiLoader.load(new URLRequest(FLICKR_URL)); + + this.stage.addEventListener(ResizeEvent.RESIZE, stage_resizeHandler); + + var listLayout:HorizontalLayout = new HorizontalLayout(); + listLayout.verticalAlign = HorizontalLayout.VERTICAL_ALIGN_JUSTIFY; + listLayout.hasVariableItemDimensions = true; + + this.list = new List(); + this.list.styleNameList.add(THUMBNAIL_LIST_NAME); + this.list.layout = listLayout; + this.list.horizontalScrollPolicy = List.SCROLL_POLICY_ON; + this.list.snapScrollPositionsToPixels = true; + this.list.itemRendererType = GalleryItemRenderer; + this.list.addEventListener(starling.events.Event.CHANGE, list_changeHandler); + this.addChild(this.list); + + this.message = new Label(); + this.message.text = "Loading..."; + this.addChild(this.message); + + this.layout(); + } + + protected function stage_resizeHandler(event:ResizeEvent):void + { + this.layout(); + } + + protected function apiLoader_completeListener(event:flash.events.Event):void + { + var result:XML = XML(this.apiLoader.data); + if(result.attribute("stat") == "fail") + { + message.text = "Unable to load the list of images from Flickr at this time."; + this.layout(); + return; + } + var items:Vector. = new []; + var photosList:XMLList = result.photos.photo; + var photoCount:int = photosList.length(); + for(var i:int = 0; i < photoCount; i++) + { + var photoXML:XML = photosList[i]; + var url:String = FLICKR_PHOTO_URL.replace("{farm-id}", photoXML.@farm.toString()); + url = url.replace("{server-id}", photoXML.@server.toString()); + url = url.replace("{id}", photoXML.@id.toString()); + url = url.replace("{secret}", photoXML.@secret.toString()); + var thumbURL:String = url.replace("{size}", "t"); + url = url.replace("{size}", "b"); + var title:String = photoXML.@title.toString(); + items.push(new GalleryItem(title, url, thumbURL)); + } + + this.message.text = ""; + + this.list.dataProvider = new ListCollection(items); + this.list.selectedIndex = 0; + } + + protected function apiLoader_errorListener(event:flash.events.Event):void + { + this.message.text = "Error loading images."; + this.layout(); + } + + protected function loader_completeHandler(event:flash.events.Event):void + { + var texture:Texture = Texture.fromBitmap(Bitmap(this.loader.content)); + if(this.selectedImage) + { + this.selectedImage.texture.dispose(); + this.selectedImage.texture = texture; + this.selectedImage.scaleX = this.selectedImage.scaleY = 1; + this.selectedImage.readjustSize(); + } + else + { + this.selectedImage = new Image(texture); + this.addChildAt(this.selectedImage, 1); + } + this.originalImageWidth = this.selectedImage.width; + this.originalImageHeight = this.selectedImage.height; + this.selectedImage.alpha = 0; + this.selectedImage.visible = true; + + this.fadeTween = new Tween(this.selectedImage, 0.5, Transitions.EASE_OUT); + this.fadeTween.fadeTo(1); + Starling.juggler.add(this.fadeTween); + + this.message.text = ""; + + this.layout(); + } + + protected function loader_errorHandler(event:flash.events.Event):void + { + this.message.text = "Error loading image."; + this.layout(); + } + } +} diff --git a/examples/HelloWorld/README.md b/examples/HelloWorld/README.md new file mode 100644 index 0000000000..e72a1998ec --- /dev/null +++ b/examples/HelloWorld/README.md @@ -0,0 +1,13 @@ +# Hello World Example for Feathers + +A very simple example that creates a Button control from the [Feathers](http://feathersui.com/) library, presented as a mobile app. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Hello World Example](http://feathersui.com/examples/hello-world/) in your browser. \ No newline at end of file diff --git a/examples/HelloWorld/build.properties b/examples/HelloWorld/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/HelloWorld/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/HelloWorld/build.xml b/examples/HelloWorld/build.xml new file mode 100644 index 0000000000..409580d062 --- /dev/null +++ b/examples/HelloWorld/build.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/HelloWorld/sdk.properties b/examples/HelloWorld/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/HelloWorld/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/HelloWorld/source/HelloWorld-app.xml b/examples/HelloWorld/source/HelloWorld-app.xml new file mode 100644 index 0000000000..1a32c39d2a --- /dev/null +++ b/examples/HelloWorld/source/HelloWorld-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.HelloWorld + Feathers Hello World + Feathers Hello World + 2.0.1 + Hello World example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + HelloWorld.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/HelloWorld/source/HelloWorld.as b/examples/HelloWorld/source/HelloWorld.as new file mode 100644 index 0000000000..dc784bfc6c --- /dev/null +++ b/examples/HelloWorld/source/HelloWorld.as @@ -0,0 +1,152 @@ +package +{ + import feathers.examples.helloWorld.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class HelloWorld extends Sprite + { + public function HelloWorld() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/HelloWorld/source/HelloWorldWeb.as b/examples/HelloWorld/source/HelloWorldWeb.as new file mode 100644 index 0000000000..5dcdf49fc5 --- /dev/null +++ b/examples/HelloWorld/source/HelloWorldWeb.as @@ -0,0 +1,56 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class HelloWorldWeb extends MovieClip + { + public function HelloWorldWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.helloWorld.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/HelloWorld/source/feathers/examples/helloWorld/Main.as b/examples/HelloWorld/source/feathers/examples/helloWorld/Main.as new file mode 100644 index 0000000000..485c54bc5c --- /dev/null +++ b/examples/HelloWorld/source/feathers/examples/helloWorld/Main.as @@ -0,0 +1,86 @@ +package feathers.examples.helloWorld +{ + import feathers.controls.Button; + import feathers.controls.Callout; + import feathers.controls.Label; + import feathers.themes.MetalWorksMobileTheme; + + import starling.display.Sprite; + import starling.events.Event; + + /** + * An example to help you get started with Feathers. Creates a "theme" and + * displays a Button component that you can trigger. + * + *

    Note: This example requires the MetalWorksMobileTheme, which is one of + * the themes included with Feathers.

    + * + * @see http://feathersui.com/help/getting-started.html + */ + public class Main extends Sprite + { + /** + * Constructor. + */ + public function Main() + { + //we'll initialize things after we've been added to the stage + this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + } + + /** + * The Feathers Button control that we'll be creating. + */ + protected var button:Button; + + /** + * Where the magic happens. Start after the main class has been added + * to the stage so that we can access the stage property. + */ + protected function addedToStageHandler(event:Event):void + { + this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + + //create the theme. this class will automatically pass skins to any + //Feathers component that is added to the stage. components do not + //have default skins, so you must always use a theme or skin the + //components manually. you should always create a theme immediately + //when your app starts up to ensure that all components are + //properly skinned. + //see http://feathersui.com/help/themes.html + new MetalWorksMobileTheme(); + + //create a button and give it some text to display. + this.button = new Button(); + this.button.label = "Click Me"; + + //an event that tells us when the user has tapped the button. + this.button.addEventListener(Event.TRIGGERED, button_triggeredHandler); + + //add the button to the display list, just like you would with any + //other Starling display object. this is where the theme give some + //skins to the button. + this.addChild(this.button); + + //the button won't have a width and height until it "validates". it + //will validate on its own before the next frame is rendered by + //Starling, but we want to access the dimension immediately, so tell + //it to validate right now. + this.button.validate(); + + //center the button + this.button.x = Math.round((this.stage.stageWidth - this.button.width) / 2); + this.button.y = Math.round((this.stage.stageHeight - this.button.height) / 2); + } + + /** + * Listener for the Button's Event.TRIGGERED event. + */ + protected function button_triggeredHandler(event:Event):void + { + var label:Label = new Label(); + label.text = "Hi, I'm Feathers!\nHave a nice day."; + Callout.show(label, this.button); + } + } +} diff --git a/examples/LayoutExplorer/README.md b/examples/LayoutExplorer/README.md new file mode 100644 index 0000000000..c62a24798f --- /dev/null +++ b/examples/LayoutExplorer/README.md @@ -0,0 +1,13 @@ +# Layout Explorer for Feathers + +Demonstrations of each layout available in [Feathers](http://feathersui.com/) for the List and LayoutContainer components, presented as a mobile app. Includes screens for each layout, with configurable options. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Layout Explorer Example](http://feathersui.com/examples/layout-explorer/) in your browser. \ No newline at end of file diff --git a/examples/LayoutExplorer/build.properties b/examples/LayoutExplorer/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/LayoutExplorer/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/LayoutExplorer/build.xml b/examples/LayoutExplorer/build.xml new file mode 100644 index 0000000000..0dc98018de --- /dev/null +++ b/examples/LayoutExplorer/build.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/LayoutExplorer/sdk.properties b/examples/LayoutExplorer/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/LayoutExplorer/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/LayoutExplorer/source/LayoutExplorer-app.xml b/examples/LayoutExplorer/source/LayoutExplorer-app.xml new file mode 100644 index 0000000000..2cd58dd497 --- /dev/null +++ b/examples/LayoutExplorer/source/LayoutExplorer-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.LayoutExplorer + Feathers Layouts + Feathers Layouts + 2.0.1 + Layout Explorer example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + LayoutExplorer.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/LayoutExplorer/source/LayoutExplorer.as b/examples/LayoutExplorer/source/LayoutExplorer.as new file mode 100644 index 0000000000..8259900719 --- /dev/null +++ b/examples/LayoutExplorer/source/LayoutExplorer.as @@ -0,0 +1,153 @@ +package +{ + import feathers.examples.layoutExplorer.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class LayoutExplorer extends Sprite + { + public function LayoutExplorer() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/LayoutExplorer/source/LayoutExplorerWeb.as b/examples/LayoutExplorer/source/LayoutExplorerWeb.as new file mode 100644 index 0000000000..a9fc1ec821 --- /dev/null +++ b/examples/LayoutExplorer/source/LayoutExplorerWeb.as @@ -0,0 +1,56 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class LayoutExplorerWeb extends MovieClip + { + public function LayoutExplorerWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.layoutExplorer.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/Main.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/Main.as new file mode 100644 index 0000000000..a567a34325 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/Main.as @@ -0,0 +1,169 @@ +package feathers.examples.layoutExplorer +{ + import feathers.controls.Drawers; + import feathers.controls.StackScreenNavigator; + import feathers.controls.StackScreenNavigatorItem; + import feathers.examples.layoutExplorer.data.HorizontalLayoutSettings; + import feathers.examples.layoutExplorer.data.TiledColumnsLayoutSettings; + import feathers.examples.layoutExplorer.data.TiledRowsLayoutSettings; + import feathers.examples.layoutExplorer.data.VerticalLayoutSettings; + import feathers.examples.layoutExplorer.screens.AnchorLayoutScreen; + import feathers.examples.layoutExplorer.screens.HorizontalLayoutScreen; + import feathers.examples.layoutExplorer.screens.HorizontalLayoutSettingsScreen; + import feathers.examples.layoutExplorer.screens.MainMenuScreen; + import feathers.examples.layoutExplorer.screens.TiledColumnsLayoutScreen; + import feathers.examples.layoutExplorer.screens.TiledColumnsLayoutSettingsScreen; + import feathers.examples.layoutExplorer.screens.TiledRowsLayoutScreen; + import feathers.examples.layoutExplorer.screens.TiledRowsLayoutSettingsScreen; + import feathers.examples.layoutExplorer.screens.VerticalLayoutScreen; + import feathers.examples.layoutExplorer.screens.VerticalLayoutSettingsScreen; + import feathers.motion.transitions.Cover; + import feathers.motion.transitions.Reveal; + import feathers.motion.transitions.Slide; + import feathers.system.DeviceCapabilities; + import feathers.themes.MetalWorksMobileTheme; + + import starling.core.Starling; + import starling.events.Event; + + public class Main extends Drawers + { + private static const MAIN_MENU:String = "mainMenu"; + private static const ANCHOR:String = "anchor"; + private static const HORIZONTAL:String = "horizontal"; + private static const VERTICAL:String = "vertical"; + private static const TILED_ROWS:String = "tiledRows"; + private static const TILED_COLUMNS:String = "tiledColumns"; + private static const HORIZONTAL_SETTINGS:String = "horizontalSettings"; + private static const VERTICAL_SETTINGS:String = "verticalSettings"; + private static const TILED_ROWS_SETTINGS:String = "tiledRowsSettings"; + private static const TILED_COLUMNS_SETTINGS:String = "tiledColumnsSettings"; + + private static const MAIN_MENU_EVENTS:Object = + { + showAnchor: ANCHOR, + showHorizontal: HORIZONTAL, + showVertical: VERTICAL, + showTiledRows: TILED_ROWS, + showTiledColumns: TILED_COLUMNS + }; + + public function Main() + { + super(); + } + + private var _navigator:StackScreenNavigator; + private var _menu:MainMenuScreen; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + new MetalWorksMobileTheme(); + + this._navigator = new StackScreenNavigator(); + //we're using Drawers because we want to display the menu on the + //side when running on tablets. + this.content = this._navigator; + + var anchorItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(AnchorLayoutScreen); + anchorItem.addPopEvent(Event.COMPLETE); + this._navigator.addScreen(ANCHOR, anchorItem); + + var horizontalLayoutSettings:HorizontalLayoutSettings = new HorizontalLayoutSettings(); + var horizontalItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(HorizontalLayoutScreen); + horizontalItem.setScreenIDForPushEvent(HorizontalLayoutScreen.SHOW_SETTINGS, HORIZONTAL_SETTINGS); + horizontalItem.addPopEvent(Event.COMPLETE); + horizontalItem.properties.settings = horizontalLayoutSettings; + this._navigator.addScreen(HORIZONTAL, horizontalItem); + + var horizontalSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(HorizontalLayoutSettingsScreen); + horizontalSettingsItem.addPopEvent(Event.COMPLETE); + horizontalSettingsItem.properties.settings = horizontalLayoutSettings; + horizontalSettingsItem.pushTransition = Cover.createCoverUpTransition(); + horizontalSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(HORIZONTAL_SETTINGS, horizontalSettingsItem); + + var verticalLayoutSettings:VerticalLayoutSettings = new VerticalLayoutSettings(); + var verticalItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(VerticalLayoutScreen); + verticalItem.setScreenIDForPushEvent(VerticalLayoutScreen.SHOW_SETTINGS, VERTICAL_SETTINGS); + verticalItem.addPopEvent(Event.COMPLETE); + verticalItem.properties.settings = verticalLayoutSettings; + this._navigator.addScreen(VERTICAL, verticalItem); + + var verticalSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(VerticalLayoutSettingsScreen); + verticalSettingsItem.addPopEvent(Event.COMPLETE); + verticalSettingsItem.properties.settings = verticalLayoutSettings; + verticalSettingsItem.pushTransition = Cover.createCoverUpTransition(); + verticalSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(VERTICAL_SETTINGS, verticalSettingsItem); + + var tiledRowsLayoutSettings:TiledRowsLayoutSettings = new TiledRowsLayoutSettings(); + var tiledRowsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TiledRowsLayoutScreen); + tiledRowsItem.setScreenIDForPushEvent(TiledRowsLayoutScreen.SHOW_SETTINGS, TILED_ROWS_SETTINGS); + tiledRowsItem.addPopEvent(Event.COMPLETE); + tiledRowsItem.properties.settings = tiledRowsLayoutSettings; + this._navigator.addScreen(TILED_ROWS, tiledRowsItem); + + var tiledRowsSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TiledRowsLayoutSettingsScreen); + tiledRowsSettingsItem.addPopEvent(Event.COMPLETE); + tiledRowsSettingsItem.properties.settings = tiledRowsLayoutSettings; + tiledRowsSettingsItem.pushTransition = Cover.createCoverUpTransition(); + tiledRowsSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(TILED_ROWS_SETTINGS, tiledRowsSettingsItem); + + var tiledColumnsLayoutSettings:TiledColumnsLayoutSettings = new TiledColumnsLayoutSettings(); + var tiledColumnsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TiledColumnsLayoutScreen); + tiledColumnsItem.setScreenIDForPushEvent(TiledColumnsLayoutScreen.SHOW_SETTINGS, TILED_COLUMNS_SETTINGS); + tiledColumnsItem.addPopEvent(Event.COMPLETE); + tiledColumnsItem.properties.settings = tiledColumnsLayoutSettings; + this._navigator.addScreen(TILED_COLUMNS, tiledColumnsItem); + + var tiledColumnsSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TiledColumnsLayoutSettingsScreen); + tiledColumnsSettingsItem.addPopEvent(Event.COMPLETE); + tiledColumnsSettingsItem.properties.settings = tiledColumnsLayoutSettings; + tiledColumnsSettingsItem.pushTransition = Cover.createCoverUpTransition(); + tiledColumnsSettingsItem.popTransition = Reveal.createRevealDownTransition(); + this._navigator.addScreen(TILED_COLUMNS_SETTINGS, tiledColumnsSettingsItem); + + if(DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + //we don't want the screens bleeding outside the navigator's + //bounds on top of a drawer when a transition is active, so + //enable clipping. + this._navigator.clipContent = true; + this._menu = new MainMenuScreen(); + for(var eventType:String in MAIN_MENU_EVENTS) + { + this._menu.addEventListener(eventType, mainMenuEventHandler); + } + this.leftDrawer = this._menu; + this.leftDrawerDockMode = Drawers.DOCK_MODE_BOTH; + } + else + { + var mainMenuItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(MainMenuScreen); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_ANCHOR, ANCHOR); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_HORIZONTAL, HORIZONTAL); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_VERTICAL, VERTICAL); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_TILED_ROWS, TILED_ROWS); + mainMenuItem.setScreenIDForPushEvent(MainMenuScreen.SHOW_TILED_COLUMNS, TILED_COLUMNS); + this._navigator.addScreen(MAIN_MENU, mainMenuItem); + this._navigator.rootScreenID = MAIN_MENU; + } + + this._navigator.pushTransition = Slide.createSlideLeftTransition(); + this._navigator.popTransition = Slide.createSlideRightTransition(); + } + + private function mainMenuEventHandler(event:Event):void + { + var screenName:String = MAIN_MENU_EVENTS[event.type] as String; + //since this navigation is triggered by an external menu, we don't + //want to push a new screen onto the stack. we want to start fresh. + this._navigator.rootScreenID = screenName; + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/HorizontalLayoutSettings.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/HorizontalLayoutSettings.as new file mode 100644 index 0000000000..1da3a97113 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/HorizontalLayoutSettings.as @@ -0,0 +1,20 @@ +package feathers.examples.layoutExplorer.data +{ + import feathers.layout.HorizontalLayout; + + public class HorizontalLayoutSettings + { + public function HorizontalLayoutSettings() + { + } + + public var itemCount:int = 75; + public var horizontalAlign:String = HorizontalLayout.HORIZONTAL_ALIGN_LEFT; + public var verticalAlign:String = HorizontalLayout.VERTICAL_ALIGN_TOP; + public var gap:Number = 2; + public var paddingTop:Number = 0; + public var paddingRight:Number = 0; + public var paddingBottom:Number = 0; + public var paddingLeft:Number = 0; + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledColumnsLayoutSettings.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledColumnsLayoutSettings.as new file mode 100644 index 0000000000..532cb703dc --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledColumnsLayoutSettings.as @@ -0,0 +1,24 @@ +package feathers.examples.layoutExplorer.data +{ + import feathers.layout.TiledColumnsLayout; + + public class TiledColumnsLayoutSettings + { + public function TiledColumnsLayoutSettings() + { + } + + public var itemCount:int = 75; + public var paging:String = TiledColumnsLayout.PAGING_NONE; + public var horizontalAlign:String = TiledColumnsLayout.HORIZONTAL_ALIGN_LEFT; + public var verticalAlign:String = TiledColumnsLayout.VERTICAL_ALIGN_TOP; + public var tileHorizontalAlign:String = TiledColumnsLayout.TILE_HORIZONTAL_ALIGN_LEFT; + public var tileVerticalAlign:String = TiledColumnsLayout.TILE_VERTICAL_ALIGN_TOP; + public var horizontalGap:Number = 2; + public var verticalGap:Number = 2; + public var paddingTop:Number = 0; + public var paddingRight:Number = 0; + public var paddingBottom:Number = 0; + public var paddingLeft:Number = 0; + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledRowsLayoutSettings.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledRowsLayoutSettings.as new file mode 100644 index 0000000000..38c1f5a86c --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledRowsLayoutSettings.as @@ -0,0 +1,24 @@ +package feathers.examples.layoutExplorer.data +{ + import feathers.layout.TiledRowsLayout; + + public class TiledRowsLayoutSettings + { + public function TiledRowsLayoutSettings() + { + } + + public var paging:String = TiledRowsLayout.PAGING_NONE; + public var itemCount:int = 75; + public var horizontalAlign:String = TiledRowsLayout.HORIZONTAL_ALIGN_LEFT; + public var verticalAlign:String = TiledRowsLayout.VERTICAL_ALIGN_TOP; + public var tileHorizontalAlign:String = TiledRowsLayout.TILE_HORIZONTAL_ALIGN_LEFT; + public var tileVerticalAlign:String = TiledRowsLayout.TILE_VERTICAL_ALIGN_TOP; + public var horizontalGap:Number = 2; + public var verticalGap:Number = 2; + public var paddingTop:Number = 0; + public var paddingRight:Number = 0; + public var paddingBottom:Number = 0; + public var paddingLeft:Number = 0; + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/VerticalLayoutSettings.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/VerticalLayoutSettings.as new file mode 100644 index 0000000000..b1f214c77d --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/VerticalLayoutSettings.as @@ -0,0 +1,20 @@ +package feathers.examples.layoutExplorer.data +{ + import feathers.layout.VerticalLayout; + + public class VerticalLayoutSettings + { + public function VerticalLayoutSettings() + { + } + + public var itemCount:int = 75; + public var horizontalAlign:String = VerticalLayout.HORIZONTAL_ALIGN_LEFT; + public var verticalAlign:String = VerticalLayout.VERTICAL_ALIGN_TOP; + public var gap:Number = 2; + public var paddingTop:Number = 0; + public var paddingRight:Number = 0; + public var paddingBottom:Number = 0; + public var paddingLeft:Number = 0; + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/AnchorLayoutScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/AnchorLayoutScreen.as new file mode 100644 index 0000000000..e4283a18f3 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/AnchorLayoutScreen.as @@ -0,0 +1,106 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Label; + import feathers.controls.PanelScreen; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class AnchorLayoutScreen extends PanelScreen + { + public function AnchorLayoutScreen() + { + super(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Anchor Layout"; + + this.layout = new AnchorLayout(); + + var centeredLayoutData:AnchorLayoutData = new AnchorLayoutData(); + centeredLayoutData.horizontalCenter = 0; + centeredLayoutData.verticalCenter = 0; + var label1:Label = new Label(); + label1.text = "(Rotate device to see the layout update!)"; + label1.layoutData = centeredLayoutData; + this.addChild(label1); + + var topRightLayoutData:AnchorLayoutData = new AnchorLayoutData(); + topRightLayoutData.top = 20; + topRightLayoutData.right = 20; + var button1:Button = new Button(); + button1.label = "This button is positioned\nat the top right corner."; + button1.layoutData = topRightLayoutData; + this.addChild(button1); + + var fillBottomLayoutData:AnchorLayoutData = new AnchorLayoutData(); + fillBottomLayoutData.left = 20; + fillBottomLayoutData.right = 20; + fillBottomLayoutData.bottom = 20; + var button2:Button = new Button(); + button2.label = "This button stretches across the bottom."; + button2.layoutData = fillBottomLayoutData; + this.addChild(button2); + + var relativeLayoutData:AnchorLayoutData = new AnchorLayoutData(); + relativeLayoutData.bottom = 20; + relativeLayoutData.bottomAnchorDisplayObject = button2; + relativeLayoutData.horizontalCenter = 0; + var label2:Label = new Label(); + label2.text = "The label is positioned relative to the button."; + label2.layoutData = relativeLayoutData; + this.addChild(label2); + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutScreen.as new file mode 100644 index 0000000000..5416fbe4f3 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutScreen.as @@ -0,0 +1,120 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.ScrollContainer; + import feathers.events.FeathersEventType; + import feathers.examples.layoutExplorer.data.HorizontalLayoutSettings; + import feathers.layout.HorizontalLayout; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.display.Quad; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + [Event(name="showSettings",type="starling.events.Event")] + + public class HorizontalLayoutScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function HorizontalLayoutScreen() + { + super(); + } + + public var settings:HorizontalLayoutSettings; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Horizontal Layout"; + + var layout:HorizontalLayout = new HorizontalLayout(); + layout.gap = this.settings.gap; + layout.paddingTop = this.settings.paddingTop; + layout.paddingRight = this.settings.paddingRight; + layout.paddingBottom = this.settings.paddingBottom; + layout.paddingLeft = this.settings.paddingLeft; + layout.horizontalAlign = this.settings.horizontalAlign; + layout.verticalAlign = this.settings.verticalAlign; + + this.layout = layout; + //when the scroll policy is set to on, the "elastic" edges will be + //active even when the max scroll position is zero + this.horizontalScrollPolicy = ScrollContainer.SCROLL_POLICY_ON; + this.snapScrollPositionsToPixels = true; + + var minQuadSize:Number = Math.min(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight) / 15; + for(var i:int = 0; i < this.settings.itemCount; i++) + { + var size:Number = (minQuadSize + minQuadSize * 2 * Math.random()); + var quad:Quad = new Quad(size, size, 0xff8800); + this.addChild(quad); + } + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this.revealScrollBars(); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutSettingsScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutSettingsScreen.as new file mode 100644 index 0000000000..f7af977f61 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutSettingsScreen.as @@ -0,0 +1,218 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.data.ListCollection; + import feathers.examples.layoutExplorer.data.HorizontalLayoutSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.layout.HorizontalLayout; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class HorizontalLayoutSettingsScreen extends PanelScreen + { + public function HorizontalLayoutSettingsScreen() + { + super(); + } + + public var settings:HorizontalLayoutSettings; + + private var _list:List; + + private var _itemCountStepper:NumericStepper; + private var _gapStepper:NumericStepper; + private var _paddingTopStepper:NumericStepper; + private var _paddingRightStepper:NumericStepper; + private var _paddingBottomStepper:NumericStepper; + private var _paddingLeftStepper:NumericStepper; + private var _horizontalAlignPicker:PickerList; + private var _verticalAlignPicker:PickerList; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Horizontal Layout Settings"; + + this.layout = new AnchorLayout(); + + this._itemCountStepper = new NumericStepper(); + this._itemCountStepper.minimum = 1; + //the layout can certainly handle more. this value is arbitrary. + this._itemCountStepper.maximum = 100; + this._itemCountStepper.step = 1; + this._itemCountStepper.value = this.settings.itemCount; + this._itemCountStepper.addEventListener(Event.CHANGE, itemCountStepper_changeHandler); + + this._horizontalAlignPicker = new PickerList(); + this._horizontalAlignPicker.typicalItem = HorizontalLayout.HORIZONTAL_ALIGN_CENTER; + this._horizontalAlignPicker.dataProvider = new ListCollection(new + [ + HorizontalLayout.HORIZONTAL_ALIGN_LEFT, + HorizontalLayout.HORIZONTAL_ALIGN_CENTER, + HorizontalLayout.HORIZONTAL_ALIGN_RIGHT + ]); + this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; + this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); + + this._verticalAlignPicker = new PickerList(); + this._verticalAlignPicker.typicalItem = HorizontalLayout.VERTICAL_ALIGN_BOTTOM; + this._verticalAlignPicker.dataProvider = new ListCollection(new + [ + HorizontalLayout.VERTICAL_ALIGN_TOP, + HorizontalLayout.VERTICAL_ALIGN_MIDDLE, + HorizontalLayout.VERTICAL_ALIGN_BOTTOM, + HorizontalLayout.VERTICAL_ALIGN_JUSTIFY + ]); + this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; + this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); + + this._gapStepper = new NumericStepper(); + this._gapStepper.minimum = 0; + //these maximum values are completely arbitrary + this._gapStepper.maximum = 100; + this._gapStepper.step = 1; + this._gapStepper.value = this.settings.gap; + this._gapStepper.addEventListener(Event.CHANGE, gapStepper_changeHandler); + + this._paddingTopStepper = new NumericStepper(); + this._paddingTopStepper.minimum = 0; + this._paddingTopStepper.maximum = 100; + this._paddingTopStepper.step = 1; + this._paddingTopStepper.value = this.settings.paddingTop; + this._paddingTopStepper.addEventListener(Event.CHANGE, paddingTopStepper_changeHandler); + + this._paddingRightStepper = new NumericStepper(); + this._paddingRightStepper.minimum = 0; + this._paddingRightStepper.maximum = 100; + this._paddingRightStepper.step = 1; + this._paddingRightStepper.value = this.settings.paddingRight; + this._paddingRightStepper.addEventListener(Event.CHANGE, paddingRightStepper_changeHandler); + + this._paddingBottomStepper = new NumericStepper(); + this._paddingBottomStepper.minimum = 0; + this._paddingBottomStepper.maximum = 100; + this._paddingBottomStepper.step = 1; + this._paddingBottomStepper.value = this.settings.paddingBottom; + this._paddingBottomStepper.addEventListener(Event.CHANGE, paddingBottomStepper_changeHandler); + + this._paddingLeftStepper = new NumericStepper(); + this._paddingLeftStepper.minimum = 0; + this._paddingLeftStepper.maximum = 100; + this._paddingLeftStepper.step = 1; + this._paddingLeftStepper.value = this.settings.paddingLeft; + this._paddingLeftStepper.addEventListener(Event.CHANGE, paddingLeftStepper_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "Item Count", accessory: this._itemCountStepper }, + { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, + { label: "verticalAlign", accessory: this._verticalAlignPicker }, + { label: "gap", accessory: this._gapStepper }, + { label: "paddingTop", accessory: this._paddingTopStepper }, + { label: "paddingRight", accessory: this._paddingRightStepper }, + { label: "paddingBottom", accessory: this._paddingBottomStepper }, + { label: "paddingLeft", accessory: this._paddingLeftStepper }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function itemCountStepper_changeHandler(event:Event):void + { + this.settings.itemCount = this._itemCountStepper.value; + } + + private function horizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.horizontalAlign = this._horizontalAlignPicker.selectedItem as String; + } + + private function verticalAlignPicker_changeHandler(event:Event):void + { + this.settings.verticalAlign = this._verticalAlignPicker.selectedItem as String; + } + + private function gapStepper_changeHandler(event:Event):void + { + this.settings.gap = this._gapStepper.value; + } + + private function paddingTopStepper_changeHandler(event:Event):void + { + this.settings.paddingTop = this._paddingTopStepper.value; + } + + private function paddingRightStepper_changeHandler(event:Event):void + { + this.settings.paddingRight = this._paddingRightStepper.value; + } + + private function paddingBottomStepper_changeHandler(event:Event):void + { + this.settings.paddingBottom = this._paddingBottomStepper.value; + } + + private function paddingLeftStepper_changeHandler(event:Event):void + { + this.settings.paddingLeft = this._paddingLeftStepper.value; + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/MainMenuScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/MainMenuScreen.as new file mode 100644 index 0000000000..15aa3de204 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/MainMenuScreen.as @@ -0,0 +1,137 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.StandardIcons; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.events.Event; + import starling.textures.Texture; + + [Event(name="showAnchor",type="starling.events.Event")] + + [Event(name="showHorizontal",type="starling.events.Event")] + + [Event(name="showVertical",type="starling.events.Event")] + + [Event(name="showTiledRows",type="starling.events.Event")] + + [Event(name="showTiledColumns",type="starling.events.Event")] + + public class MainMenuScreen extends PanelScreen + { + public static const SHOW_ANCHOR:String = "showAnchor"; + public static const SHOW_HORIZONTAL:String = "showHorizontal"; + public static const SHOW_VERTICAL:String = "showVertical"; + public static const SHOW_TILED_ROWS:String = "showTiledRows"; + public static const SHOW_TILED_COLUMNS:String = "showTiledColumns"; + + public function MainMenuScreen() + { + super(); + } + + private var _list:List; + + public var savedVerticalScrollPosition:Number = 0; + public var savedSelectedIndex:int = -1; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Layouts in Feathers"; + + var isTablet:Boolean = DeviceCapabilities.isTablet(Starling.current.nativeStage); + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { text: "Anchor", event: SHOW_ANCHOR }, + { text: "Horizontal", event: SHOW_HORIZONTAL }, + { text: "Vertical", event: SHOW_VERTICAL }, + { text: "Tiled Rows", event: SHOW_TILED_ROWS }, + { text: "Tiled Columns", event: SHOW_TILED_COLUMNS }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.verticalScrollPosition = this.savedVerticalScrollPosition; + + var itemRendererAccessorySourceFunction:Function = null; + if(!isTablet) + { + itemRendererAccessorySourceFunction = this.accessorySourceFunction; + } + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "text"; + renderer.accessorySourceFunction = itemRendererAccessorySourceFunction; + return renderer; + }; + + if(isTablet) + { + this._list.addEventListener(Event.CHANGE, list_changeHandler); + this._list.selectedIndex = 0; + this._list.revealScrollBars(); + } + else + { + this._list.selectedIndex = this.savedSelectedIndex; + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + this.addChild(this._list); + } + + private function accessorySourceFunction(item:Object):Texture + { + return StandardIcons.listDrillDownAccessoryTexture; + } + + private function transitionInCompleteHandler(event:Event):void + { + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this._list.selectedIndex = -1; + this._list.addEventListener(Event.CHANGE, list_changeHandler); + } + this._list.revealScrollBars(); + } + + private function list_changeHandler(event:Event):void + { + var eventType:String = this._list.selectedItem.event as String; + if(DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.dispatchEventWith(eventType); + return; + } + + //save the list's scroll position and selected index so that we + //can restore some context when this screen when we return to it + //again later. + this.dispatchEventWith(eventType, false, + { + savedVerticalScrollPosition: this._list.verticalScrollPosition, + savedSelectedIndex: this._list.selectedIndex + }); + + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutScreen.as new file mode 100644 index 0000000000..403c77ce7b --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutScreen.as @@ -0,0 +1,123 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.events.FeathersEventType; + import feathers.examples.layoutExplorer.data.TiledColumnsLayoutSettings; + import feathers.layout.TiledColumnsLayout; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.display.Quad; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + [Event(name="showSettings",type="starling.events.Event")] + + public class TiledColumnsLayoutScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function TiledColumnsLayoutScreen() + { + super(); + } + + public var settings:TiledColumnsLayoutSettings; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Tiled Columns Layout"; + + var layout:TiledColumnsLayout = new TiledColumnsLayout(); + layout.paging = this.settings.paging; + layout.horizontalGap = this.settings.horizontalGap; + layout.verticalGap = this.settings.verticalGap; + layout.paddingTop = this.settings.paddingTop; + layout.paddingRight = this.settings.paddingRight; + layout.paddingBottom = this.settings.paddingBottom; + layout.paddingLeft = this.settings.paddingLeft; + layout.horizontalAlign = this.settings.horizontalAlign; + layout.verticalAlign = this.settings.verticalAlign; + layout.tileHorizontalAlign = this.settings.tileHorizontalAlign; + layout.tileVerticalAlign = this.settings.tileVerticalAlign; + + this.layout = layout; + this.snapToPages = this.settings.paging != TiledColumnsLayout.PAGING_NONE; + this.snapScrollPositionsToPixels = true; + + var minQuadSize:Number = Math.min(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight) / 15; + for(var i:int = 0; i < this.settings.itemCount; i++) + { + var size:Number = minQuadSize + minQuadSize * 2 * Math.random(); + var quad:Quad = new Quad(size, size, 0xff8800); + this.addChild(quad); + } + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this.headerFactory = this.customHeaderFactory; + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this.revealScrollBars(); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutSettingsScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutSettingsScreen.as new file mode 100644 index 0000000000..d0fd24846d --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutSettingsScreen.as @@ -0,0 +1,287 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.data.ListCollection; + import feathers.examples.layoutExplorer.data.TiledColumnsLayoutSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.layout.TiledColumnsLayout; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class TiledColumnsLayoutSettingsScreen extends PanelScreen + { + public function TiledColumnsLayoutSettingsScreen() + { + super(); + } + + public var settings:TiledColumnsLayoutSettings; + + private var _list:List; + + private var _itemCountStepper:NumericStepper; + private var _pagingPicker:PickerList; + private var _horizontalGapStepper:NumericStepper; + private var _verticalGapStepper:NumericStepper; + private var _paddingTopStepper:NumericStepper; + private var _paddingRightStepper:NumericStepper; + private var _paddingBottomStepper:NumericStepper; + private var _paddingLeftStepper:NumericStepper; + private var _horizontalAlignPicker:PickerList; + private var _verticalAlignPicker:PickerList; + private var _tileHorizontalAlignPicker:PickerList; + private var _tileVerticalAlignPicker:PickerList; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Tiled Columns Layout Settings"; + + this.layout = new AnchorLayout(); + + this._itemCountStepper = new NumericStepper(); + this._itemCountStepper.minimum = 1; + //the layout can certainly handle more. this value is arbitrary. + this._itemCountStepper.maximum = 100; + this._itemCountStepper.step = 1; + this._itemCountStepper.value = this.settings.itemCount; + this._itemCountStepper.addEventListener(Event.CHANGE, itemCountStepper_changeHandler); + + this._pagingPicker = new PickerList(); + this._pagingPicker.typicalItem = TiledColumnsLayout.PAGING_HORIZONTAL; + this._pagingPicker.dataProvider = new ListCollection(new + [ + TiledColumnsLayout.PAGING_NONE, + TiledColumnsLayout.PAGING_HORIZONTAL, + TiledColumnsLayout.PAGING_VERTICAL + ]); + this._pagingPicker.selectedItem = this.settings.paging; + this._pagingPicker.addEventListener(Event.CHANGE, pagingPicker_changeHandler); + + this._horizontalAlignPicker = new PickerList(); + this._horizontalAlignPicker.typicalItem = TiledColumnsLayout.HORIZONTAL_ALIGN_CENTER; + this._horizontalAlignPicker.dataProvider = new ListCollection(new + [ + TiledColumnsLayout.HORIZONTAL_ALIGN_LEFT, + TiledColumnsLayout.HORIZONTAL_ALIGN_CENTER, + TiledColumnsLayout.HORIZONTAL_ALIGN_RIGHT + ]); + this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; + this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); + + this._verticalAlignPicker = new PickerList(); + this._verticalAlignPicker.typicalItem = TiledColumnsLayout.VERTICAL_ALIGN_BOTTOM; + this._verticalAlignPicker.dataProvider = new ListCollection(new + [ + TiledColumnsLayout.VERTICAL_ALIGN_TOP, + TiledColumnsLayout.VERTICAL_ALIGN_MIDDLE, + TiledColumnsLayout.VERTICAL_ALIGN_BOTTOM + ]); + this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; + this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); + + this._tileHorizontalAlignPicker = new PickerList(); + this._tileHorizontalAlignPicker.typicalItem = TiledColumnsLayout.TILE_HORIZONTAL_ALIGN_CENTER; + this._tileHorizontalAlignPicker.dataProvider = new ListCollection(new + [ + TiledColumnsLayout.TILE_HORIZONTAL_ALIGN_LEFT, + TiledColumnsLayout.TILE_HORIZONTAL_ALIGN_CENTER, + TiledColumnsLayout.TILE_HORIZONTAL_ALIGN_RIGHT, + TiledColumnsLayout.TILE_HORIZONTAL_ALIGN_JUSTIFY + ]); + this._tileHorizontalAlignPicker.selectedItem = this.settings.tileHorizontalAlign; + this._tileHorizontalAlignPicker.addEventListener(Event.CHANGE, tileHorizontalAlignPicker_changeHandler); + + this._tileVerticalAlignPicker = new PickerList(); + this._tileVerticalAlignPicker.typicalItem = TiledColumnsLayout.TILE_VERTICAL_ALIGN_BOTTOM; + this._tileVerticalAlignPicker.dataProvider = new ListCollection(new + [ + TiledColumnsLayout.TILE_VERTICAL_ALIGN_TOP, + TiledColumnsLayout.TILE_VERTICAL_ALIGN_MIDDLE, + TiledColumnsLayout.TILE_VERTICAL_ALIGN_BOTTOM, + TiledColumnsLayout.TILE_VERTICAL_ALIGN_JUSTIFY + ]); + this._tileVerticalAlignPicker.selectedItem = this.settings.tileVerticalAlign; + this._tileVerticalAlignPicker.addEventListener(Event.CHANGE, tileVerticalAlignPicker_changeHandler); + + this._horizontalGapStepper = new NumericStepper(); + this._horizontalGapStepper.minimum = 0; + //these maximum values are completely arbitrary + this._horizontalGapStepper.maximum = 100; + this._horizontalGapStepper.step = 1; + this._horizontalGapStepper.value = this.settings.horizontalGap; + this._horizontalGapStepper.addEventListener(Event.CHANGE, horizontalGapStepper_changeHandler); + + this._verticalGapStepper = new NumericStepper(); + this._verticalGapStepper.minimum = 0; + this._verticalGapStepper.maximum = 100; + this._verticalGapStepper.step = 1; + this._verticalGapStepper.value = this.settings.verticalGap; + this._verticalGapStepper.addEventListener(Event.CHANGE, verticalGapStepper_changeHandler); + + this._paddingTopStepper = new NumericStepper(); + this._paddingTopStepper.minimum = 0; + this._paddingTopStepper.maximum = 100; + this._paddingTopStepper.step = 1; + this._paddingTopStepper.value = this.settings.paddingTop; + this._paddingTopStepper.addEventListener(Event.CHANGE, paddingTopStepper_changeHandler); + + this._paddingRightStepper = new NumericStepper(); + this._paddingRightStepper.minimum = 0; + this._paddingRightStepper.maximum = 100; + this._paddingRightStepper.step = 1; + this._paddingRightStepper.value = this.settings.paddingRight; + this._paddingRightStepper.addEventListener(Event.CHANGE, paddingRightStepper_changeHandler); + + this._paddingBottomStepper = new NumericStepper(); + this._paddingBottomStepper.minimum = 0; + this._paddingBottomStepper.maximum = 100; + this._paddingBottomStepper.step = 1; + this._paddingBottomStepper.value = this.settings.paddingBottom; + this._paddingBottomStepper.addEventListener(Event.CHANGE, paddingBottomStepper_changeHandler); + + this._paddingLeftStepper = new NumericStepper(); + this._paddingLeftStepper.minimum = 0; + this._paddingLeftStepper.maximum = 100; + this._paddingLeftStepper.step = 1; + this._paddingLeftStepper.value = this.settings.paddingLeft; + this._paddingLeftStepper.addEventListener(Event.CHANGE, paddingLeftStepper_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "Item Count", accessory: this._itemCountStepper }, + { label: "Paging", accessory: this._pagingPicker }, + { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, + { label: "verticalAlign", accessory: this._verticalAlignPicker }, + { label: "tileHorizontalAlign", accessory: this._tileHorizontalAlignPicker }, + { label: "tileVerticalAlign", accessory: this._tileVerticalAlignPicker }, + { label: "horizontalGap", accessory: this._horizontalGapStepper }, + { label: "verticalGap", accessory: this._verticalGapStepper }, + { label: "paddingTop", accessory: this._paddingTopStepper }, + { label: "paddingRight", accessory: this._paddingRightStepper }, + { label: "paddingBottom", accessory: this._paddingBottomStepper }, + { label: "paddingLeft", accessory: this._paddingLeftStepper }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function itemCountStepper_changeHandler(event:Event):void + { + this.settings.itemCount = this._itemCountStepper.value; + } + + private function pagingPicker_changeHandler(event:Event):void + { + this.settings.paging = this._pagingPicker.selectedItem as String; + } + + private function horizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.horizontalAlign = this._horizontalAlignPicker.selectedItem as String; + } + + private function verticalAlignPicker_changeHandler(event:Event):void + { + this.settings.verticalAlign = this._verticalAlignPicker.selectedItem as String; + } + + private function tileHorizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.tileHorizontalAlign = this._tileHorizontalAlignPicker.selectedItem as String; + } + + private function tileVerticalAlignPicker_changeHandler(event:Event):void + { + this.settings.tileVerticalAlign = this._tileVerticalAlignPicker.selectedItem as String; + } + + private function horizontalGapStepper_changeHandler(event:Event):void + { + this.settings.horizontalGap = this._horizontalGapStepper.value; + } + + private function verticalGapStepper_changeHandler(event:Event):void + { + this.settings.verticalGap = this._verticalGapStepper.value; + } + + private function paddingTopStepper_changeHandler(event:Event):void + { + this.settings.paddingTop = this._paddingTopStepper.value; + } + + private function paddingRightStepper_changeHandler(event:Event):void + { + this.settings.paddingRight = this._paddingRightStepper.value; + } + + private function paddingBottomStepper_changeHandler(event:Event):void + { + this.settings.paddingBottom = this._paddingBottomStepper.value; + } + + private function paddingLeftStepper_changeHandler(event:Event):void + { + this.settings.paddingLeft = this._paddingLeftStepper.value; + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutScreen.as new file mode 100644 index 0000000000..c5ee43a268 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutScreen.as @@ -0,0 +1,123 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.events.FeathersEventType; + import feathers.examples.layoutExplorer.data.TiledRowsLayoutSettings; + import feathers.layout.TiledRowsLayout; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.display.Quad; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + [Event(name="showSettings",type="starling.events.Event")] + + public class TiledRowsLayoutScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function TiledRowsLayoutScreen() + { + super(); + } + + public var settings:TiledRowsLayoutSettings; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Tiled Rows Layout"; + + var layout:TiledRowsLayout = new TiledRowsLayout(); + layout.paging = this.settings.paging; + layout.horizontalGap = this.settings.horizontalGap; + layout.verticalGap = this.settings.verticalGap; + layout.paddingTop = this.settings.paddingTop; + layout.paddingRight = this.settings.paddingRight; + layout.paddingBottom = this.settings.paddingBottom; + layout.paddingLeft = this.settings.paddingLeft; + layout.horizontalAlign = this.settings.horizontalAlign; + layout.verticalAlign = this.settings.verticalAlign; + layout.tileHorizontalAlign = this.settings.tileHorizontalAlign; + layout.tileVerticalAlign = this.settings.tileVerticalAlign; + + this.layout = layout; + this.snapToPages = this.settings.paging != TiledRowsLayout.PAGING_NONE; + this.snapScrollPositionsToPixels = true; + + var minQuadSize:Number = Math.min(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight) / 15; + for(var i:int = 0; i < this.settings.itemCount; i++) + { + var size:Number = (minQuadSize + minQuadSize * 2 * Math.random()); + var quad:Quad = new Quad(size, size, 0xff8800); + this.addChild(quad); + } + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this.headerFactory = this.customHeaderFactory; + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this.revealScrollBars(); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutSettingsScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutSettingsScreen.as new file mode 100644 index 0000000000..d6b6575a68 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutSettingsScreen.as @@ -0,0 +1,287 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.data.ListCollection; + import feathers.examples.layoutExplorer.data.TiledRowsLayoutSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.layout.TiledRowsLayout; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class TiledRowsLayoutSettingsScreen extends PanelScreen + { + public function TiledRowsLayoutSettingsScreen() + { + super(); + } + + public var settings:TiledRowsLayoutSettings; + + private var _list:List; + + private var _itemCountStepper:NumericStepper; + private var _pagingPicker:PickerList; + private var _horizontalGapStepper:NumericStepper; + private var _verticalGapStepper:NumericStepper; + private var _paddingTopStepper:NumericStepper; + private var _paddingRightStepper:NumericStepper; + private var _paddingBottomStepper:NumericStepper; + private var _paddingLeftStepper:NumericStepper; + private var _horizontalAlignPicker:PickerList; + private var _verticalAlignPicker:PickerList; + private var _tileHorizontalAlignPicker:PickerList; + private var _tileVerticalAlignPicker:PickerList; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Tiled Rows Layout Settings"; + + this.layout = new AnchorLayout(); + + this._itemCountStepper = new NumericStepper(); + this._itemCountStepper.minimum = 1; + //the layout can certainly handle more. this value is arbitrary. + this._itemCountStepper.maximum = 100; + this._itemCountStepper.step = 1; + this._itemCountStepper.value = this.settings.itemCount; + this._itemCountStepper.addEventListener(Event.CHANGE, itemCountStepper_changeHandler); + + this._pagingPicker = new PickerList(); + this._pagingPicker.typicalItem = TiledRowsLayout.PAGING_HORIZONTAL; + this._pagingPicker.dataProvider = new ListCollection(new + [ + TiledRowsLayout.PAGING_NONE, + TiledRowsLayout.PAGING_HORIZONTAL, + TiledRowsLayout.PAGING_VERTICAL + ]); + this._pagingPicker.selectedItem = this.settings.paging; + this._pagingPicker.addEventListener(Event.CHANGE, pagingPicker_changeHandler); + + this._horizontalAlignPicker = new PickerList(); + this._horizontalAlignPicker.typicalItem = TiledRowsLayout.HORIZONTAL_ALIGN_CENTER; + this._horizontalAlignPicker.dataProvider = new ListCollection(new + [ + TiledRowsLayout.HORIZONTAL_ALIGN_LEFT, + TiledRowsLayout.HORIZONTAL_ALIGN_CENTER, + TiledRowsLayout.HORIZONTAL_ALIGN_RIGHT + ]); + this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; + this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); + + this._verticalAlignPicker = new PickerList(); + this._verticalAlignPicker.typicalItem = TiledRowsLayout.VERTICAL_ALIGN_BOTTOM; + this._verticalAlignPicker.dataProvider = new ListCollection(new + [ + TiledRowsLayout.VERTICAL_ALIGN_TOP, + TiledRowsLayout.VERTICAL_ALIGN_MIDDLE, + TiledRowsLayout.VERTICAL_ALIGN_BOTTOM + ]); + this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; + this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); + + this._tileHorizontalAlignPicker = new PickerList(); + this._tileHorizontalAlignPicker.typicalItem = TiledRowsLayout.TILE_HORIZONTAL_ALIGN_CENTER; + this._tileHorizontalAlignPicker.dataProvider = new ListCollection(new + [ + TiledRowsLayout.TILE_HORIZONTAL_ALIGN_LEFT, + TiledRowsLayout.TILE_HORIZONTAL_ALIGN_CENTER, + TiledRowsLayout.TILE_HORIZONTAL_ALIGN_RIGHT, + TiledRowsLayout.TILE_HORIZONTAL_ALIGN_JUSTIFY + ]); + this._tileHorizontalAlignPicker.selectedItem = this.settings.tileHorizontalAlign; + this._tileHorizontalAlignPicker.addEventListener(Event.CHANGE, tileHorizontalAlignPicker_changeHandler); + + this._tileVerticalAlignPicker = new PickerList(); + this._tileVerticalAlignPicker.typicalItem = TiledRowsLayout.TILE_VERTICAL_ALIGN_BOTTOM; + this._tileVerticalAlignPicker.dataProvider = new ListCollection(new + [ + TiledRowsLayout.TILE_VERTICAL_ALIGN_TOP, + TiledRowsLayout.TILE_VERTICAL_ALIGN_MIDDLE, + TiledRowsLayout.TILE_VERTICAL_ALIGN_BOTTOM, + TiledRowsLayout.TILE_VERTICAL_ALIGN_JUSTIFY + ]); + this._tileVerticalAlignPicker.selectedItem = this.settings.tileVerticalAlign; + this._tileVerticalAlignPicker.addEventListener(Event.CHANGE, tileVerticalAlignPicker_changeHandler); + + this._horizontalGapStepper = new NumericStepper(); + this._horizontalGapStepper.minimum = 0; + //these maximum values are completely arbitrary + this._horizontalGapStepper.maximum = 100; + this._horizontalGapStepper.step = 1; + this._horizontalGapStepper.value = this.settings.horizontalGap; + this._horizontalGapStepper.addEventListener(Event.CHANGE, horizontalGapStepper_changeHandler); + + this._verticalGapStepper = new NumericStepper(); + this._verticalGapStepper.minimum = 0; + this._verticalGapStepper.maximum = 100; + this._verticalGapStepper.step = 1; + this._verticalGapStepper.value = this.settings.verticalGap; + this._verticalGapStepper.addEventListener(Event.CHANGE, verticalGapStepper_changeHandler); + + this._paddingTopStepper = new NumericStepper(); + this._paddingTopStepper.minimum = 0; + this._paddingTopStepper.maximum = 100; + this._paddingTopStepper.step = 1; + this._paddingTopStepper.value = this.settings.paddingTop; + this._paddingTopStepper.addEventListener(Event.CHANGE, paddingTopStepper_changeHandler); + + this._paddingRightStepper = new NumericStepper(); + this._paddingRightStepper.minimum = 0; + this._paddingRightStepper.maximum = 100; + this._paddingRightStepper.step = 1; + this._paddingRightStepper.value = this.settings.paddingRight; + this._paddingRightStepper.addEventListener(Event.CHANGE, paddingRightStepper_changeHandler); + + this._paddingBottomStepper = new NumericStepper(); + this._paddingBottomStepper.minimum = 0; + this._paddingBottomStepper.maximum = 100; + this._paddingBottomStepper.step = 1; + this._paddingBottomStepper.value = this.settings.paddingBottom; + this._paddingBottomStepper.addEventListener(Event.CHANGE, paddingBottomStepper_changeHandler); + + this._paddingLeftStepper = new NumericStepper(); + this._paddingLeftStepper.minimum = 0; + this._paddingLeftStepper.maximum = 100; + this._paddingLeftStepper.step = 1; + this._paddingLeftStepper.value = this.settings.paddingLeft; + this._paddingLeftStepper.addEventListener(Event.CHANGE, paddingLeftStepper_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "Item Count", accessory: this._itemCountStepper }, + { label: "Paging", accessory: this._pagingPicker }, + { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, + { label: "verticalAlign", accessory: this._verticalAlignPicker }, + { label: "tileHorizontalAlign", accessory: this._tileHorizontalAlignPicker }, + { label: "tileVerticalAlign", accessory: this._tileVerticalAlignPicker }, + { label: "horizontalGap", accessory: this._horizontalGapStepper }, + { label: "verticalGap", accessory: this._verticalGapStepper }, + { label: "paddingTop", accessory: this._paddingTopStepper }, + { label: "paddingRight", accessory: this._paddingRightStepper }, + { label: "paddingBottom", accessory: this._paddingBottomStepper }, + { label: "paddingLeft", accessory: this._paddingLeftStepper }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function itemCountStepper_changeHandler(event:Event):void + { + this.settings.itemCount = this._itemCountStepper.value; + } + + private function pagingPicker_changeHandler(event:Event):void + { + this.settings.paging = this._pagingPicker.selectedItem as String; + } + + private function horizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.horizontalAlign = this._horizontalAlignPicker.selectedItem as String; + } + + private function verticalAlignPicker_changeHandler(event:Event):void + { + this.settings.verticalAlign = this._verticalAlignPicker.selectedItem as String; + } + + private function tileHorizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.tileHorizontalAlign = this._tileHorizontalAlignPicker.selectedItem as String; + } + + private function tileVerticalAlignPicker_changeHandler(event:Event):void + { + this.settings.tileVerticalAlign = this._tileVerticalAlignPicker.selectedItem as String; + } + + private function horizontalGapStepper_changeHandler(event:Event):void + { + this.settings.horizontalGap = this._horizontalGapStepper.value; + } + + private function verticalGapStepper_changeHandler(event:Event):void + { + this.settings.verticalGap = this._verticalGapStepper.value; + } + + private function paddingTopStepper_changeHandler(event:Event):void + { + this.settings.paddingTop = this._paddingTopStepper.value; + } + + private function paddingRightStepper_changeHandler(event:Event):void + { + this.settings.paddingRight = this._paddingRightStepper.value; + } + + private function paddingBottomStepper_changeHandler(event:Event):void + { + this.settings.paddingBottom = this._paddingBottomStepper.value; + } + + private function paddingLeftStepper_changeHandler(event:Event):void + { + this.settings.paddingLeft = this._paddingLeftStepper.value; + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutScreen.as new file mode 100644 index 0000000000..9efa477d26 --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutScreen.as @@ -0,0 +1,120 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.ScrollContainer; + import feathers.events.FeathersEventType; + import feathers.examples.layoutExplorer.data.VerticalLayoutSettings; + import feathers.layout.VerticalLayout; + import feathers.system.DeviceCapabilities; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.display.Quad; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + [Event(name="showSettings",type="starling.events.Event")] + + public class VerticalLayoutScreen extends PanelScreen + { + public static const SHOW_SETTINGS:String = "showSettings"; + + public function VerticalLayoutScreen() + { + super(); + } + + public var settings:VerticalLayoutSettings; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Vertical Layout"; + + var layout:VerticalLayout = new VerticalLayout(); + layout.gap = this.settings.gap; + layout.paddingTop = this.settings.paddingTop; + layout.paddingRight = this.settings.paddingRight; + layout.paddingBottom = this.settings.paddingBottom; + layout.paddingLeft = this.settings.paddingLeft; + layout.horizontalAlign = this.settings.horizontalAlign; + layout.verticalAlign = this.settings.verticalAlign; + + this.layout = layout; + //when the scroll policy is set to on, the "elastic" edges will be + //active even when the max scroll position is zero + this.verticalScrollPolicy = ScrollContainer.SCROLL_POLICY_ON; + this.snapScrollPositionsToPixels = true; + + var minQuadSize:Number = Math.min(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight) / 15; + for(var i:int = 0; i < this.settings.itemCount; i++) + { + var size:Number = (minQuadSize + minQuadSize * 2 * Math.random()); + var quad:Quad = new Quad(size, size, 0xff8800); + this.addChild(quad); + } + + this.headerFactory = this.customHeaderFactory; + + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + this.backButtonHandler = this.onBackButton; + } + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + //this screen doesn't use a back button on tablets because the main + //app's uses a split layout + if(!DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var backButton:Button = new Button(); + backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + backButton.label = "Back"; + backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + backButton + ]; + } + var settingsButton:Button = new Button(); + settingsButton.label = "Settings"; + settingsButton.addEventListener(Event.TRIGGERED, settingsButton_triggeredHandler); + header.rightItems = new + [ + settingsButton + ]; + return header; + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this.revealScrollBars(); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function settingsButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(SHOW_SETTINGS); + } + } +} diff --git a/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutSettingsScreen.as b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutSettingsScreen.as new file mode 100644 index 0000000000..e23b5dff4f --- /dev/null +++ b/examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutSettingsScreen.as @@ -0,0 +1,218 @@ +package feathers.examples.layoutExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.NumericStepper; + import feathers.controls.PanelScreen; + import feathers.controls.PickerList; + import feathers.data.ListCollection; + import feathers.examples.layoutExplorer.data.VerticalLayoutSettings; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.layout.VerticalLayout; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class VerticalLayoutSettingsScreen extends PanelScreen + { + public function VerticalLayoutSettingsScreen() + { + super(); + } + + public var settings:VerticalLayoutSettings; + + private var _list:List; + + private var _itemCountStepper:NumericStepper; + private var _gapStepper:NumericStepper; + private var _paddingTopStepper:NumericStepper; + private var _paddingRightStepper:NumericStepper; + private var _paddingBottomStepper:NumericStepper; + private var _paddingLeftStepper:NumericStepper; + private var _horizontalAlignPicker:PickerList; + private var _verticalAlignPicker:PickerList; + + override public function dispose():void + { + //icon and accessory display objects in the list's data provider + //won't be automatically disposed because feathers cannot know if + //they need to be used again elsewhere or not. we need to dispose + //them manually. + this._list.dataProvider.dispose(disposeItemAccessory); + + //never forget to call super.dispose() because you don't want to + //create a memory leak! + super.dispose(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Vertical Layout Settings"; + + this.layout = new AnchorLayout(); + + this._itemCountStepper = new NumericStepper(); + this._itemCountStepper.minimum = 1; + //the layout can certainly handle more. this value is arbitrary. + this._itemCountStepper.maximum = 100; + this._itemCountStepper.step = 1; + this._itemCountStepper.value = this.settings.itemCount; + this._itemCountStepper.addEventListener(Event.CHANGE, itemCountStepper_changeHandler); + + this._horizontalAlignPicker = new PickerList(); + this._horizontalAlignPicker.typicalItem = VerticalLayout.HORIZONTAL_ALIGN_CENTER; + this._horizontalAlignPicker.dataProvider = new ListCollection(new + [ + VerticalLayout.HORIZONTAL_ALIGN_LEFT, + VerticalLayout.HORIZONTAL_ALIGN_CENTER, + VerticalLayout.HORIZONTAL_ALIGN_RIGHT, + VerticalLayout.HORIZONTAL_ALIGN_JUSTIFY + ]); + this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; + this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); + + this._verticalAlignPicker = new PickerList(); + this._verticalAlignPicker.typicalItem = VerticalLayout.VERTICAL_ALIGN_BOTTOM; + this._verticalAlignPicker.dataProvider = new ListCollection(new + [ + VerticalLayout.VERTICAL_ALIGN_TOP, + VerticalLayout.VERTICAL_ALIGN_MIDDLE, + VerticalLayout.VERTICAL_ALIGN_BOTTOM + ]); + this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; + this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); + + this._gapStepper = new NumericStepper(); + this._gapStepper.minimum = 0; + //these maximum values are completely arbitrary + this._gapStepper.maximum = 100; + this._gapStepper.step = 1; + this._gapStepper.value = this.settings.gap; + this._gapStepper.addEventListener(Event.CHANGE, gapStepper_changeHandler); + + this._paddingTopStepper = new NumericStepper(); + this._paddingTopStepper.minimum = 0; + this._paddingTopStepper.maximum = 100; + this._paddingTopStepper.step = 1; + this._paddingTopStepper.value = this.settings.paddingTop; + this._paddingTopStepper.addEventListener(Event.CHANGE, paddingTopStepper_changeHandler); + + this._paddingRightStepper = new NumericStepper(); + this._paddingRightStepper.minimum = 0; + this._paddingRightStepper.maximum = 100; + this._paddingRightStepper.step = 1; + this._paddingRightStepper.value = this.settings.paddingRight; + this._paddingRightStepper.addEventListener(Event.CHANGE, paddingRightStepper_changeHandler); + + this._paddingBottomStepper = new NumericStepper(); + this._paddingBottomStepper.minimum = 0; + this._paddingBottomStepper.maximum = 100; + this._paddingBottomStepper.step = 1; + this._paddingBottomStepper.value = this.settings.paddingBottom; + this._paddingBottomStepper.addEventListener(Event.CHANGE, paddingBottomStepper_changeHandler); + + this._paddingLeftStepper = new NumericStepper(); + this._paddingLeftStepper.minimum = 0; + this._paddingLeftStepper.maximum = 100; + this._paddingLeftStepper.step = 1; + this._paddingLeftStepper.value = this.settings.paddingLeft; + this._paddingLeftStepper.addEventListener(Event.CHANGE, paddingLeftStepper_changeHandler); + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection( + [ + { label: "Item Count", accessory: this._itemCountStepper }, + { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, + { label: "verticalAlign", accessory: this._verticalAlignPicker }, + { label: "gap", accessory: this._gapStepper }, + { label: "paddingTop", accessory: this._paddingTopStepper }, + { label: "paddingRight", accessory: this._paddingRightStepper }, + { label: "paddingBottom", accessory: this._paddingBottomStepper }, + { label: "paddingLeft", accessory: this._paddingLeftStepper }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + var doneButton:Button = new Button(); + doneButton.label = "Done"; + doneButton.addEventListener(Event.TRIGGERED, doneButton_triggeredHandler); + header.rightItems = new + [ + doneButton + ]; + return header; + } + + private function disposeItemAccessory(item:Object):void + { + DisplayObject(item.accessory).dispose(); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function doneButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function itemCountStepper_changeHandler(event:Event):void + { + this.settings.itemCount = this._itemCountStepper.value; + } + + private function horizontalAlignPicker_changeHandler(event:Event):void + { + this.settings.horizontalAlign = this._horizontalAlignPicker.selectedItem as String; + } + + private function verticalAlignPicker_changeHandler(event:Event):void + { + this.settings.verticalAlign = this._verticalAlignPicker.selectedItem as String; + } + + private function gapStepper_changeHandler(event:Event):void + { + this.settings.gap = this._gapStepper.value; + } + + private function paddingTopStepper_changeHandler(event:Event):void + { + this.settings.paddingTop = this._paddingTopStepper.value; + } + + private function paddingRightStepper_changeHandler(event:Event):void + { + this.settings.paddingRight = this._paddingRightStepper.value; + } + + private function paddingBottomStepper_changeHandler(event:Event):void + { + this.settings.paddingBottom = this._paddingBottomStepper.value; + } + + private function paddingLeftStepper_changeHandler(event:Event):void + { + this.settings.paddingLeft = this._paddingLeftStepper.value; + } + } +} diff --git a/examples/MXML/README.md b/examples/MXML/README.md new file mode 100644 index 0000000000..2603f96c1e --- /dev/null +++ b/examples/MXML/README.md @@ -0,0 +1,3 @@ +# MXML Example for Feathers + +A very simple example that uses MXML with the [Feathers](http://feathersui.com/) open source UI components library. \ No newline at end of file diff --git a/examples/MXML/build.properties b/examples/MXML/build.properties new file mode 100644 index 0000000000..7435b342a9 --- /dev/null +++ b/examples/MXML/build.properties @@ -0,0 +1,8 @@ +mxml.namespace = library://ns.feathersui.com/mxml +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/MXML/build.xml b/examples/MXML/build.xml new file mode 100644 index 0000000000..02eab21294 --- /dev/null +++ b/examples/MXML/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/MXML/sdk.properties b/examples/MXML/sdk.properties new file mode 100644 index 0000000000..b7ead6d54e --- /dev/null +++ b/examples/MXML/sdk.properties @@ -0,0 +1,18 @@ +# The location of the Flex SDK. +# Override flexsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flexsdk.root = C:/Users/Josh Tynjala/Development/Flex/sdks/4.6.0.23201B_AIR15.0 +flexsdk.lib = ${flexsdk.root}/lib +flexframework.root = ${flexsdk.root}/frameworks +flexframework.lib = ${flexframework.root}/libs +flexframework.rsls = ${flexframework.root}/rsls + +# The location of the AIR SDK. May be different than the Flex SDK. +airsdk.root = ${flexsdk.root} +airsdk.lib = ${airsdk.root}/lib + +# path to compiler jars +asdoc = ${flexsdk.lib}/asdoc.jar +compc = ${flexsdk.lib}/compc.jar +mxmlc = ${flexsdk.lib}/mxmlc.jar +adt = ${airsdk.lib}/adt.jar \ No newline at end of file diff --git a/examples/MXML/source/MXML-app.xml b/examples/MXML/source/MXML-app.xml new file mode 100644 index 0000000000..032c8d6497 --- /dev/null +++ b/examples/MXML/source/MXML-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.MXML + Feathers MXML + Feathers MXML + 2.0.1 + MXML example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + MXML.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/MXML/source/MXML.as b/examples/MXML/source/MXML.as new file mode 100644 index 0000000000..cc6dab2057 --- /dev/null +++ b/examples/MXML/source/MXML.as @@ -0,0 +1,155 @@ +package +{ + import feathers.examples.mxml.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class MXML extends Sprite + { + public function MXML() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/MXML/source/feathers/examples/mxml/Main.as b/examples/MXML/source/feathers/examples/mxml/Main.as new file mode 100644 index 0000000000..a64ac30e73 --- /dev/null +++ b/examples/MXML/source/feathers/examples/mxml/Main.as @@ -0,0 +1,64 @@ +package feathers.examples.mxml +{ + import feathers.controls.ScreenNavigator; + import feathers.controls.ScreenNavigatorItem; + import feathers.examples.mxml.screens.SampleScreen; + import feathers.examples.mxml.screens.SettingsScreen; + import feathers.motion.transitions.ScreenSlidingStackTransitionManager; + import feathers.motion.transitions.ScreenSlidingStackTransitionManager; + import feathers.themes.MetalWorksMobileTheme; + + import starling.display.Sprite; + import starling.events.Event; + import starling.events.ResizeEvent; + + public class Main extends Sprite + { + private static const SAMPLE_SCREEN:String = "sample"; + private static const SETTINGS_SCREEN:String = "settings"; + + public function Main() + { + this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); + } + + private var _navigator:ScreenNavigator; + + private function addedToStageHandler(event:Event):void + { + new MetalWorksMobileTheme(); + + this.stage.addEventListener(ResizeEvent.RESIZE, stage_resizeHandler); + + this._navigator = new ScreenNavigator(); + this.addChild(this._navigator); + + this._navigator.addScreen(SAMPLE_SCREEN, new ScreenNavigatorItem(SampleScreen, + { + settings: SETTINGS_SCREEN + })); + + this._navigator.addScreen(SETTINGS_SCREEN, new ScreenNavigatorItem(SettingsScreen, + { + complete: SAMPLE_SCREEN + })); + + new ScreenSlidingStackTransitionManager(this._navigator); + + this._navigator.showScreen(SAMPLE_SCREEN); + } + + private function removedFromStageHandler(event:Event):void + { + this.stage.removeEventListener(ResizeEvent.RESIZE, stage_resizeHandler); + } + + private function stage_resizeHandler(event:Event):void + { + this._navigator.width = this.stage.stageWidth; + this._navigator.height = this.stage.stageHeight; + } + + } +} diff --git a/examples/MXML/source/feathers/examples/mxml/screens/SampleScreen.mxml b/examples/MXML/source/feathers/examples/mxml/screens/SampleScreen.mxml new file mode 100644 index 0000000000..b6a4a8d355 --- /dev/null +++ b/examples/MXML/source/feathers/examples/mxml/screens/SampleScreen.mxml @@ -0,0 +1,62 @@ + + + + [Event(name="settings",type="starling.events.Event")] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/MXML/source/feathers/examples/mxml/screens/SettingsScreen.mxml b/examples/MXML/source/feathers/examples/mxml/screens/SettingsScreen.mxml new file mode 100644 index 0000000000..fc49a87fcf --- /dev/null +++ b/examples/MXML/source/feathers/examples/mxml/screens/SettingsScreen.mxml @@ -0,0 +1,51 @@ + + + + [Event(name="complete",type="starling.events.Event")] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/TestFeathers/source/TestFeathers.as b/examples/TestFeathers/source/TestFeathers.as new file mode 100644 index 0000000000..66d47c3aab --- /dev/null +++ b/examples/TestFeathers/source/TestFeathers.as @@ -0,0 +1,91 @@ +package +{ + import feathers.tests.ButtonTests; + import feathers.tests.GroupedListTests; + import feathers.tests.LayoutGroupTests; + import feathers.tests.ListCollectionWithArrayTests; + import feathers.tests.ListTests; + import feathers.tests.PickerListTests; + import feathers.tests.ProgressBarTests; + import feathers.tests.ScrollContainerTests; + import feathers.tests.SliderHorizontalTests; + import feathers.tests.TabBarEmptyDataProviderTests; + import feathers.tests.TabBarTests; + import feathers.tests.ToggleButtonTests; + import feathers.tests.ToggleGroupTests; + import feathers.tests.ToggleSwitchTests; + + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.system.System; + + import org.flexunit.internals.TraceListener; + import org.flexunit.runner.FlexUnitCore; + + import starling.core.Starling; + import starling.display.Sprite; + import starling.events.Event; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class TestFeathers extends flash.display.Sprite + { + public static var starlingRoot:starling.display.Sprite; + + public function TestFeathers() + { + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + this.loaderInfo.addEventListener(flash.events.Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _flexunit:FlexUnitCore; + + private function loaderInfo_completeHandler(event:flash.events.Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(starling.display.Sprite, this.stage); + this._starling.enableErrorChecking = false; + this._starling.addEventListener(starling.events.Event.ROOT_CREATED, starling_rootCreatedHandler); + this._starling.start(); + } + + private function starling_rootCreatedHandler(event:starling.events.Event):void + { + starlingRoot = starling.display.Sprite(this._starling.root); + this._flexunit = new FlexUnitCore(); + this._flexunit.addListener(new TraceListener()); + this._flexunit.addEventListener(FlexUnitCore.TESTS_COMPLETE, flexunit_testsCompleteHandler); + this._flexunit.run( + [ + ButtonTests, + GroupedListTests, + LayoutGroupTests, + ListTests, + ListCollectionWithArrayTests, + PickerListTests, + ProgressBarTests, + ScrollContainerTests, + SliderHorizontalTests, + ToggleButtonTests, + ToggleGroupTests, + ToggleSwitchTests, + TabBarTests, + TabBarEmptyDataProviderTests, + ]); + } + + private function flexunit_testsCompleteHandler(event:flash.events.Event):void + { + System.exit(0); + } + + } +} \ No newline at end of file diff --git a/examples/TestFeathers/source/feathers/tests/ButtonTests.as b/examples/TestFeathers/source/feathers/tests/ButtonTests.as new file mode 100644 index 0000000000..43b3444024 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ButtonTests.as @@ -0,0 +1,112 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.events.FeathersEventType; + + import flash.geom.Point; + + import org.flexunit.Assert; + import org.flexunit.async.Async; + + import starling.display.DisplayObject; + + import starling.display.Quad; + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class ButtonTests + { + private var _button:Button; + + [Before] + public function prepare():void + { + this._button = new Button(); + this._button.label = "Click Me"; + this._button.defaultSkin = new Quad(200, 200); + TestFeathers.starlingRoot.addChild(this._button); + this._button.validate(); + } + + [After] + public function cleanup():void + { + this._button.removeFromParent(true); + this._button = null; + } + + [Test] + public function testTriggeredEvent():void + { + var hasTriggered:Boolean = false; + this._button.addEventListener(Event.TRIGGERED, function(event:Event):void + { + hasTriggered = true; + }); + var position:Point = new Point(10, 10); + var target:DisplayObject = this._button.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + //this touch does not move at all, so it should result in triggering + //the button. + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertTrue("TEvent.TRIGGERED was not dispatched", hasTriggered); + } + + [Test] + public function testTouchMoveOutsideBeforeTriggeredEvent():void + { + var hasTriggered:Boolean = false; + this._button.addEventListener(Event.TRIGGERED, function(event:Event):void + { + hasTriggered = true; + }); + var position:Point = new Point(10, 10); + var target:DisplayObject = this._button.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.globalX = 1000; //move the touch way outside the bounds of the button + touch.phase = TouchPhase.MOVED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertFalse("Event.TRIGGERED was incorrectly dispatched", hasTriggered); + } + + [Test(async)] + public function testLongPressEvent():void + { + var hasLongPressed:Boolean = false; + this._button.isLongPressEnabled = true; + this._button.addEventListener(FeathersEventType.LONG_PRESS, function():void + { + hasLongPressed = true; + }); + var touch:Touch = new Touch(0); + touch.target = this._button; + touch.phase = TouchPhase.BEGAN; + touch.globalX = 10; + touch.globalY = 10; + var touches:Vector. = new [touch]; + this._button.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Async.delayCall(this, function():void + { + Assert.assertTrue("FeathersEventType.LONG_PRESS was not dispatched", hasLongPressed); + }, 600); + } + + } +} diff --git a/examples/TestFeathers/source/feathers/tests/GroupedListTests.as b/examples/TestFeathers/source/feathers/tests/GroupedListTests.as new file mode 100644 index 0000000000..24b9516d0a --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/GroupedListTests.as @@ -0,0 +1,401 @@ +package feathers.tests +{ + import feathers.controls.GroupedList; + import feathers.controls.renderers.DefaultGroupedListHeaderOrFooterRenderer; + import feathers.controls.renderers.DefaultGroupedListItemRenderer; + import feathers.data.HierarchicalCollection; + + import flash.geom.Point; + + import org.flexunit.Assert; + + import starling.display.DisplayObject; + + import starling.display.Quad; + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class GroupedListTests + { + private var _list:GroupedList; + + [Before] + public function prepare():void + { + this._list = new GroupedList(); + this._list.dataProvider = new HierarchicalCollection( + [ + { + header: { label: "A" }, + children: + [ + {label: "One"}, + {label: "Two"}, + {label: "Three"}, + ] + }, + { + header: { label: "B" }, + children: + [ + {label: "Four"}, + {label: "Five"}, + {label: "Six"}, + ] + } + ]); + this._list.itemRendererFactory = function():DefaultGroupedListItemRenderer + { + var itemRenderer:DefaultGroupedListItemRenderer = new DefaultGroupedListItemRenderer(); + itemRenderer.defaultSkin = new Quad(200, 200); + return itemRenderer; + }; + this._list.headerRendererFactory = function():DefaultGroupedListHeaderOrFooterRenderer + { + var headerRenderer:DefaultGroupedListHeaderOrFooterRenderer = new DefaultGroupedListHeaderOrFooterRenderer(); + headerRenderer.backgroundSkin = new Quad(200, 200); + return headerRenderer; + }; + TestFeathers.starlingRoot.addChild(this._list); + this._list.validate(); + } + + [After] + public function cleanup():void + { + this._list.removeFromParent(true); + this._list = null; + } + + [Test] + public function testProgrammaticSelectionChange():void + { + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.setSelectedLocation(0, 1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedGroupIndex property was not changed", + beforeSelectedGroupIndex === this._list.selectedGroupIndex); + Assert.assertFalse("The selectedItemIndex property was not changed", + beforeSelectedItemIndex === this._list.selectedItemIndex); + Assert.assertFalse("The selectedItem property was not changed", + beforeSelectedItem === this._list.selectedItem); + } + + [Test] + public function testInteractiveSelectionChange():void + { + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(10, 410); + var target:DisplayObject = this._list.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + //this touch does not move at all, so it should result in triggering + //the button. + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedGroupIndex property was not changed", + beforeSelectedGroupIndex === this._list.selectedGroupIndex); + Assert.assertFalse("The selectedItemIndex property was not changed", + beforeSelectedItemIndex === this._list.selectedItemIndex); + } + + [Test] + public function testRemoveItemBeforeSelectedItemIndex():void + { + this._list.setSelectedLocation(1, 1); + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(1, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was incorrectly changed", + beforeSelectedGroupIndex, this._list.selectedGroupIndex); + Assert.assertFalse("The selectedItemIndex property was not changed", + beforeSelectedItemIndex === this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveItemAfterSelectedItemIndex():void + { + this._list.setSelectedLocation(1, 1); + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(1, 2); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was incorrectly changed", + beforeSelectedGroupIndex, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was incorrectly changed", + beforeSelectedItemIndex, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveSelectedItemIndex():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(1, 1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testReplaceItemAtSelectedItemIndex():void + { + this._list.setSelectedLocation(1, 1); + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.setItemAt({ label: "New Item" }, beforeSelectedGroupIndex, beforeSelectedItemIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was not changed to -1", + -1, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was not changed to -1", + -1, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testDeselectAllOnNullDataProvider():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider = null; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was not set to -1", + -1, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was not set to -1", + -1, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._list.selectedItem); + } + + [Test] + public function testDeselectAllOnDataProviderRemoveAll():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeAll(); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was not set to -1", + -1, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was not set to -1", + -1, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._list.selectedItem); + } + + [Test] + public function testAddItemBeforeSelectedItemIndex():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.addItemAt({label: "New Item"}, 1, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was incorrectly changed", + beforeSelectedGroupIndex, this._list.selectedGroupIndex); + Assert.assertFalse("The selectedItemIndex property was not changed", + beforeSelectedItemIndex === this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testAddGroupBeforeSelectedGroupIndex():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.addItemAt( + { + header: "New Group", + children: + [ + { label: "New Item 1" }, + { label: "New Item 2" }, + ] + }, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedGroupIndex property was not changed", + beforeSelectedGroupIndex === this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was incorrectly changed", + beforeSelectedItemIndex, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveGroupBeforeSelectedGroupIndex():void + { + this._list.setSelectedLocation(1, 1); + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedGroupIndex property was not changed", + beforeSelectedGroupIndex === this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was incorrectly changed", + beforeSelectedItemIndex, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveGroupAfterSelectedGroupIndex():void + { + this._list.setSelectedLocation(1, 1); + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var beforeSelectedItemIndex:int = this._list.selectedItemIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(2); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was incorrectly changed", + beforeSelectedGroupIndex, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was incorrectly changed", + beforeSelectedItemIndex, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveGroupAtSelectedGroupIndex():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testReplaceGroupAtSelectedGroupIndex():void + { + this._list.setSelectedLocation(1, 1); + var beforeSelectedGroupIndex:int = this._list.selectedGroupIndex; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.setItemAt( + { + header: "New Group", + children: + [ + { label: "New Item 1" }, + { label: "New Item 2" }, + ] + }, beforeSelectedGroupIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedGroupIndex property was not changed to -1", + -1, this._list.selectedGroupIndex); + Assert.assertStrictlyEquals("The selectedItemIndex property was not changed to -1", + -1, this._list.selectedItemIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testDisposeWithoutChangeEvent():void + { + this._list.setSelectedLocation(1, 1); + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dispose(); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/LayoutGroupTests.as b/examples/TestFeathers/source/feathers/tests/LayoutGroupTests.as new file mode 100644 index 0000000000..04070a752d --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/LayoutGroupTests.as @@ -0,0 +1,201 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.LayoutGroup; + + import org.flexunit.Assert; + + import starling.display.Quad; + import starling.events.Event; + + public class LayoutGroupTests + { + //note: the background width is purposefully smaller than the item width + private static const BACKGROUND_WIDTH:Number = 200; + //note: the background height is purposefully larger than the item height + private static const BACKGROUND_HEIGHT:Number = 250; + + //note: the item width is purposefully larger than the background width + private static const ITEM_WIDTH:Number = 210; + //note: the item height is purposefully smaller than the background height + private static const ITEM_HEIGHT:Number = 160; + + private var _group:LayoutGroup; + + [Before] + public function prepare():void + { + this._group = new LayoutGroup(); + TestFeathers.starlingRoot.addChild(this._group); + this._group.validate(); + } + + [After] + public function cleanup():void + { + this._group.removeFromParent(true); + this._group = null; + } + + [Test] + public function testAutoSizeWithBackground():void + { + this._group.backgroundSkin = new Quad(BACKGROUND_WIDTH, BACKGROUND_HEIGHT); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + BACKGROUND_WIDTH, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + BACKGROUND_HEIGHT, this._group.height); + } + + [Test] + public function testAutoSizeWithChildAtOrigin():void + { + this._group.addChild(new Quad(ITEM_WIDTH, ITEM_HEIGHT)); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + ITEM_WIDTH, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + ITEM_HEIGHT, this._group.height); + } + + [Test] + public function testAutoSizeWithChild():void + { + var child:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child.x = 120; + child.y = 130; + this._group.addChild(child); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + child.x + ITEM_WIDTH, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + child.y + ITEM_HEIGHT, this._group.height); + } + + [Test] + public function testAutoSizeWithChildPositionedWithBoundsFullyInNegative():void + { + var child:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child.x = -420; + child.y = -430; + this._group.addChild(child); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + 0, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + 0, this._group.height); + } + + [Test] + public function testAutoSizeWithChildPositionedWithBoundsInBothPositiveAndNegative():void + { + var child:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child.x = -Math.round(ITEM_WIDTH / 4); + child.y = -Math.round(ITEM_HEIGHT / 3); + this._group.addChild(child); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + child.x + ITEM_WIDTH, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + child.y + ITEM_HEIGHT, this._group.height); + } + + [Test] + public function testAutoSizeWithMultipleChildren():void + { + var child1:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child1.x = 0; + child1.y = 130; + this._group.addChild(child1); + var child2:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child2.x = 120; + child2.y = 0; + this._group.addChild(child2); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + child2.x + ITEM_WIDTH, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + child1.y + ITEM_HEIGHT, this._group.height); + } + + [Test] + public function testAutoSizeChildAndBackground():void + { + this._group.addChild(new Quad(ITEM_WIDTH, ITEM_HEIGHT)); + this._group.backgroundSkin = new Quad(BACKGROUND_WIDTH, BACKGROUND_HEIGHT); + this._group.validate(); + Assert.assertStrictlyEquals("The width of the layout group was not calculated correctly.", + ITEM_WIDTH, this._group.width); + Assert.assertStrictlyEquals("The height of the layout group was not calculated correctly.", + BACKGROUND_HEIGHT, this._group.height); + } + + [Test] + public function testResizeWhenAddingChild():void + { + var originalWidth:Number = this._group.width; + var originalHeight:Number = this._group.height; + var hasResized:Boolean = false; + this._group.addEventListener(Event.RESIZE, function(event:Event):void + { + hasResized = true; + }); + this._group.addChild(new Quad(ITEM_WIDTH, ITEM_HEIGHT)); + this._group.validate(); + Assert.assertTrue("Event.RESIZE was not dispatched", hasResized); + Assert.assertFalse("The width of the layout group was not changed.", + originalWidth === this._group.width); + Assert.assertFalse("The height of the layout group was not changed.", + originalHeight === this._group.height); + } + + [Test] + public function testResizeWhenRemovingChild():void + { + var child:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + this._group.addChild(child); + this._group.validate(); + var originalWidth:Number = this._group.width; + var originalHeight:Number = this._group.height; + + var hasResized:Boolean = false; + this._group.addEventListener(Event.RESIZE, function(event:Event):void + { + hasResized = true; + }); + this._group.removeChild(child); + this._group.validate(); + Assert.assertTrue("Event.RESIZE was not dispatched", hasResized); + Assert.assertFalse("The width of the layout group was not changed.", + originalWidth === this._group.width); + Assert.assertFalse("The height of the layout group was not changed.", + originalHeight === this._group.height); + } + + [Test] + public function testResizeWhenResizingFeathersControlChild():void + { + var child:Button = new Button(); + child.defaultSkin = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + this._group.addChild(child); + this._group.validate(); + + var originalWidth:Number = this._group.width; + var originalHeight:Number = this._group.height; + var hasResized:Boolean = false; + this._group.addEventListener(Event.RESIZE, function(event:Event):void + { + hasResized = true; + }); + child.width = ITEM_WIDTH * 2; + child.height = ITEM_HEIGHT * 2; + this._group.validate(); + Assert.assertTrue("Event.RESIZE was not dispatched", hasResized); + Assert.assertFalse("The width of the layout group was not changed.", + originalWidth === this._group.width); + Assert.assertFalse("The height of the layout group was not changed.", + originalHeight === this._group.height); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ListCollectionWithArrayTests.as b/examples/TestFeathers/source/feathers/tests/ListCollectionWithArrayTests.as new file mode 100644 index 0000000000..5c379863e5 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ListCollectionWithArrayTests.as @@ -0,0 +1,229 @@ +package feathers.tests +{ + import feathers.data.ListCollection; + import feathers.events.CollectionEventType; + + import org.flexunit.Assert; + + import starling.events.Event; + + public class ListCollectionWithArrayTests + { + private var _collection:ListCollection; + + [Before] + public function prepare():void + { + this._collection = new ListCollection( + [ + { label: "One" }, + { label: "Two" }, + { label: "Three" }, + ]); + } + + [After] + public function cleanup():void + { + this._collection = null; + } + + [Test] + public function testRemoveAll():void + { + var hasChanged:Boolean = false; + this._collection.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var hasReset:Boolean = false; + this._collection.addEventListener(CollectionEventType.RESET, function(event:Event):void + { + hasReset = true; + }); + this._collection.removeAll(); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("CollectionEventType.RESET was not dispatched", hasReset); + Assert.assertStrictlyEquals("The length property was not changed to 0", + 0, this._collection.length); + } + + [Test] + public function testRemoveItemAt():void + { + var itemToRemove:Object = this._collection.getItemAt(1); + var originalLength:int = this._collection.length; + var expectedIndex:int = 1; + var hasChanged:Boolean = false; + this._collection.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var hasRemovedItem:Boolean = false; + var indexFromEvent:int = -1; + this._collection.addEventListener(CollectionEventType.REMOVE_ITEM, function(event:Event, index:int):void + { + hasRemovedItem = true; + indexFromEvent = index; + }); + this._collection.removeItemAt(expectedIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("CollectionEventType.REMOVE_ITEM was not dispatched", hasRemovedItem); + Assert.assertStrictlyEquals("The length property was not changed", + originalLength - 1, this._collection.length); + Assert.assertStrictlyEquals("The item was not removed", + -1, this._collection.getItemIndex(itemToRemove)); + Assert.assertStrictlyEquals("The CollectionEventType.REMOVE_ITEM event data was not the correct index", + expectedIndex, indexFromEvent); + } + + [Test] + public function testRemoveItem():void + { + var expectedIndex:int = 1; + var itemToRemove:Object = this._collection.getItemAt(expectedIndex); + var originalLength:int = this._collection.length; + var hasChanged:Boolean = false; + this._collection.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var hasRemovedItem:Boolean = false; + var indexFromEvent:int = -1; + this._collection.addEventListener(CollectionEventType.REMOVE_ITEM, function(event:Event, index:int):void + { + hasRemovedItem = true; + indexFromEvent = index; + }); + this._collection.removeItem(itemToRemove); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("CollectionEventType.REMOVE_ITEM was not dispatched", hasRemovedItem); + Assert.assertStrictlyEquals("The length property was not changed", + originalLength - 1, this._collection.length); + Assert.assertStrictlyEquals("The item was not removed", + -1, this._collection.getItemIndex(itemToRemove)); + Assert.assertStrictlyEquals("The CollectionEventType.REMOVE_ITEM event data was not the correct index", + expectedIndex, indexFromEvent); + } + + [Test] + public function testAddItem():void + { + var itemToAdd:Object = { label: "New Item" }; + var originalLength:int = this._collection.length; + var expectedIndex:int = originalLength; + var hasChanged:Boolean = false; + this._collection.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var hasAddedItem:Boolean = false; + var indexFromEvent:int = -1; + this._collection.addEventListener(CollectionEventType.ADD_ITEM, function(event:Event, index:int):void + { + hasAddedItem = true; + indexFromEvent = index; + }); + this._collection.addItem(itemToAdd); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("CollectionEventType.ADD_ITEM was not dispatched", hasAddedItem); + Assert.assertStrictlyEquals("The length property was not changed", + originalLength + 1, this._collection.length); + Assert.assertStrictlyEquals("The item was not added at the correct index", + expectedIndex, this._collection.getItemIndex(itemToAdd)); + Assert.assertStrictlyEquals("The CollectionEventType.ADD_ITEM event data was not the correct index", + expectedIndex, indexFromEvent); + } + + [Test] + public function testAddItemAt():void + { + var itemToAdd:Object = { label: "New Item" }; + var expectedIndex:int = 1; + var originalLength:int = this._collection.length; + var hasChanged:Boolean = false; + this._collection.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var hasAddedItem:Boolean = false; + var indexFromEvent:int = -1; + this._collection.addEventListener(CollectionEventType.ADD_ITEM, function(event:Event, index:int):void + { + hasAddedItem = true; + indexFromEvent = index; + }); + this._collection.addItemAt(itemToAdd, expectedIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("CollectionEventType.ADD_ITEM was not dispatched", hasAddedItem); + Assert.assertStrictlyEquals("The length property was not changed", + originalLength + 1, this._collection.length); + Assert.assertStrictlyEquals("The item was not added at the correct index", + expectedIndex, this._collection.getItemIndex(itemToAdd)); + Assert.assertStrictlyEquals("The CollectionEventType.ADD_ITEM event data was not the correct index", + expectedIndex, indexFromEvent); + } + + [Test] + public function testSetItemAt():void + { + var itemToAdd:Object = { label: "New Item" }; + var expectedIndex:int = 1; + var originalLength:int = this._collection.length; + var hasChanged:Boolean = false; + this._collection.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var hasAddedItem:Boolean = false; + var indexFromEvent:int = -1; + this._collection.addEventListener(CollectionEventType.REPLACE_ITEM, function(event:Event, index:int):void + { + hasAddedItem = true; + indexFromEvent = index; + }); + this._collection.setItemAt(itemToAdd, expectedIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("CollectionEventType.REPLACE_ITEM was not dispatched", hasAddedItem); + Assert.assertStrictlyEquals("The length property was incorrectly changed", + originalLength, this._collection.length); + Assert.assertStrictlyEquals("The item was not added at the correct index", + expectedIndex, this._collection.getItemIndex(itemToAdd)); + Assert.assertStrictlyEquals("The CollectionEventType.REPLACE_ITEM event data was not the correct index", + expectedIndex, indexFromEvent); + } + + [Test] + public function testContainsWithItemInCollection():void + { + var item:Object = this._collection.getItemAt(1); + Assert.assertStrictlyEquals("contains() incorrectly returned false", + true, this._collection.contains(item)); + } + + [Test] + public function testContainsWithItemNotInCollection():void + { + var item:Object = {}; + Assert.assertStrictlyEquals("contains() incorrectly returned true", + false, this._collection.contains(item)); + } + + [Test] + public function testGetItemIndexWithItemInCollection():void + { + var expectedIndex:int = 1; + var item:Object = this._collection.getItemAt(expectedIndex); + Assert.assertStrictlyEquals("getItemIndex() returned the incorrect value", + expectedIndex, this._collection.getItemIndex(item)); + } + + [Test] + public function testGetItemIndexWithItemNotInCollection():void + { + var item:Object = {}; + Assert.assertStrictlyEquals("getItemIndex() returned the incorrect value", + -1, this._collection.getItemIndex(item)); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ListTests.as b/examples/TestFeathers/source/feathers/tests/ListTests.as new file mode 100644 index 0000000000..6a2340d359 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ListTests.as @@ -0,0 +1,237 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.List; + import feathers.controls.TabBar; + import feathers.controls.ToggleButton; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.data.ListCollection; + + import flash.geom.Point; + + import org.flexunit.Assert; + + import starling.display.DisplayObject; + import starling.display.Quad; + + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class ListTests + { + private var _list:List; + + [Before] + public function prepare():void + { + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { label: "One" }, + { label: "Two" }, + { label: "Three" }, + ]); + this._list.itemRendererFactory = function():DefaultListItemRenderer + { + var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + itemRenderer.defaultSkin = new Quad(200, 200); + return itemRenderer; + }; + TestFeathers.starlingRoot.addChild(this._list); + this._list.validate(); + } + + [After] + public function cleanup():void + { + this._list.removeFromParent(true); + this._list = null; + } + + [Test] + public function testProgrammaticSelectionChange():void + { + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.selectedIndex = 1; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + Assert.assertFalse("The selectedItem property was not changed", + beforeSelectedItem === this._list.selectedItem); + } + + [Test] + public function testInteractiveSelectionChange():void + { + var beforeSelectedIndex:Boolean = this._list.selectedIndex; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(10, 210); + var target:DisplayObject = this._list.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + //this touch does not move at all, so it should result in triggering + //the button. + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + } + + [Test] + public function testRemoveItemBeforeSelectedIndex():void + { + this._list.selectedIndex = 1; + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveItemAfterSelectedIndex():void + { + this._list.selectedIndex = 1; + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(2); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveSelectedIndex():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testReplaceItemAtSelectedIndex():void + { + this._list.selectedIndex = 1; + var beforeSelectedIndex:int = this._list.selectedIndex; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.setItemAt({ label: "New Item" }, beforeSelectedIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testDeselectAllOnNullDataProvider():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider = null; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._list.selectedItem); + } + + [Test] + public function testDeselectAllOnDataProviderRemoveAll():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeAll(); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._list.selectedItem); + } + + [Test] + public function testAddItemBeforeSelectedIndex():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.addItemAt({label: "New Item"}, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testDisposeWithoutChangeEvent():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dispose(); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/PickerListTests.as b/examples/TestFeathers/source/feathers/tests/PickerListTests.as new file mode 100644 index 0000000000..a62711464e --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/PickerListTests.as @@ -0,0 +1,319 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.List; + import feathers.controls.PickerList; + import feathers.controls.popups.DropDownPopUpContentManager; + import feathers.core.PopUpManager; + import feathers.data.ListCollection; + + import flash.geom.Point; + + import org.flexunit.Assert; + + import starling.display.DisplayObject; + + import starling.display.DisplayObjectContainer; + + import starling.display.Quad; + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class PickerListTests + { + private static const BUTTON_NAME:String = "button"; + private static const LIST_NAME:String = "list"; + + private var _list:PickerList; + + [Before] + public function prepare():void + { + this._list = new PickerList(); + this._list.dataProvider = new ListCollection( + [ + { label: "One" }, + { label: "Two" }, + { label: "Three" }, + ]); + this._list.popUpContentManager = new DropDownPopUpContentManager(); + this._list.buttonFactory = function():Button + { + var track:Button = new Button(); + track.name = BUTTON_NAME; + track.defaultSkin = new Quad(200, 200); + return track; + }; + this._list.listFactory = function():List + { + var list:List = new List(); + list.name = LIST_NAME; + return list; + }; + TestFeathers.starlingRoot.addChild(this._list); + this._list.validate(); + } + + [After] + public function cleanup():void + { + this._list.removeFromParent(true); + this._list = null; + } + + [Test] + public function testProgrammaticOpenAndCloseEvents():void + { + var hasOpened:Boolean = false; + this._list.addEventListener(Event.OPEN, function(event:Event):void + { + hasOpened = true; + }); + var hasClosed:Boolean = false; + this._list.addEventListener(Event.CLOSE, function(event:Event):void + { + hasClosed = true; + }); + + this._list.openList(); + //the picker list may require validation before opening or closing + this._list.validate(); + + Assert.assertTrue("Event.OPEN was not dispatched", hasOpened); + Assert.assertNotNull("The pop-up list was not added to the PopUpManager", + PopUpManager.root.getChildByName(LIST_NAME)); + + this._list.closeList(); + this._list.validate(); + + Assert.assertTrue("Event.CLOSE was not dispatched", hasClosed); + Assert.assertNull("The list's parent property is not null", + PopUpManager.root.getChildByName(LIST_NAME)); + } + + [Test] + public function testCloseOnDispose():void + { + var hasClosed:Boolean = false; + this._list.addEventListener(Event.CLOSE, function(event:Event):void + { + hasClosed = true; + }); + + this._list.openList(); + this._list.validate(); + + this._list.dispose(); + + Assert.assertTrue("Event.CLOSE was not dispatched", hasClosed); + } + + [Test] + public function testInteractiveOpenEvent():void + { + var hasOpened:Boolean = false; + this._list.addEventListener(Event.OPEN, function(event:Event):void + { + hasOpened = true; + }); + var hasClosed:Boolean = false; + this._list.addEventListener(Event.CLOSE, function(event:Event):void + { + hasClosed = true; + }); + + var position:Point = new Point(100, 100); + var target:DisplayObject = this._list.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + //this touch does not move at all, so it should result in triggering + //the button. + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + //the picker list may require validation before opening or closing + this._list.validate(); + + Assert.assertTrue("Event.OPEN was not dispatched", hasOpened); + Assert.assertNotNull("The pop-up list was not added to the PopUpManager", + PopUpManager.root.getChildByName(LIST_NAME)); + } + + [Test] + public function testSetPopUpListDataProvider():void + { + this._list.openList(); + //the picker list may require validation before opening or closing + this._list.validate(); + + var popUpList:List = PopUpManager.root.getChildByName(LIST_NAME) as List; + + Assert.assertStrictlyEquals("The pop-up list data provider was not set", + this._list.dataProvider, popUpList.dataProvider); + } + + [Test] + public function testProgrammaticSelectionChange():void + { + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.selectedIndex = 1; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + Assert.assertFalse("The selectedItem property was not changed", + beforeSelectedItem === this._list.selectedItem); + } + + [Test] + public function testRemoveItemBeforeSelectedIndex():void + { + this._list.selectedIndex = 1; + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveItemAfterSelectedIndex():void + { + this._list.selectedIndex = 1; + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(2); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testRemoveSelectedIndex():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeItemAt(1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testReplaceItemAtSelectedIndex():void + { + this._list.selectedIndex = 1; + var beforeSelectedIndex:int = this._list.selectedIndex; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.setItemAt({ label: "New Item" }, beforeSelectedIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not changed to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not changed to null", + null, this._list.selectedItem); + } + + [Test] + public function testDeselectAllOnNullDataProvider():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider = null; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._list.selectedItem); + } + + [Test] + public function testDeselectAllOnDataProviderRemoveAll():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.removeAll(); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._list.selectedItem); + } + + [Test] + public function testAddItemBeforeSelectedIndex():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + var beforeSelectedIndex:int = this._list.selectedIndex; + var beforeSelectedItem:Object = this._list.selectedItem; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dataProvider.addItemAt({label: "New Item"}, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._list.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._list.selectedItem); + } + + [Test] + public function testDisposeWithoutChangeEvent():void + { + this._list.selectedIndex = 1; + var hasChanged:Boolean = false; + this._list.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._list.dispose(); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ProgressBarTests.as b/examples/TestFeathers/source/feathers/tests/ProgressBarTests.as new file mode 100644 index 0000000000..e00c525f88 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ProgressBarTests.as @@ -0,0 +1,47 @@ +package feathers.tests +{ + import feathers.controls.ProgressBar; + + import org.flexunit.Assert; + + import starling.display.Quad; + + public class ProgressBarTests + { + private static const BACKGROUND_WIDTH:Number = 200; + private static const BACKGROUND_HEIGHT:Number = 20; + private static const FILL_WIDTH:Number = 18; + private static const FILL_HEIGHT:Number = 14; + + private var _progress:ProgressBar; + + [Before] + public function prepare():void + { + this._progress = new ProgressBar(); + this._progress.minimum = 0; + this._progress.maximum = 10; + this._progress.value = 5; + this._progress.backgroundSkin = new Quad(BACKGROUND_WIDTH, BACKGROUND_HEIGHT); + this._progress.fillSkin = new Quad(FILL_WIDTH, FILL_HEIGHT); + TestFeathers.starlingRoot.addChild(this._progress); + this._progress.validate(); + } + + [After] + public function cleanup():void + { + this._progress.removeFromParent(true); + this._progress = null; + } + + [Test] + public function testAutoSize():void + { + Assert.assertStrictlyEquals("The width of the progress bar was not calculated correctly.", + BACKGROUND_WIDTH, this._progress.width); + Assert.assertStrictlyEquals("The height of the progress bar was not calculated correctly.", + BACKGROUND_HEIGHT, this._progress.height); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ScrollContainerTests.as b/examples/TestFeathers/source/feathers/tests/ScrollContainerTests.as new file mode 100644 index 0000000000..a97a515154 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ScrollContainerTests.as @@ -0,0 +1,173 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.ScrollContainer; + + import org.flexunit.Assert; + + import starling.display.Quad; + import starling.events.Event; + + public class ScrollContainerTests + { + //note: the background width is purposefully smaller than the item width + private static const BACKGROUND_WIDTH:Number = 200; + //note: the background height is purposefully larger than the item height + private static const BACKGROUND_HEIGHT:Number = 250; + + //note: the item width is purposefully larger than the background width + private static const ITEM_WIDTH:Number = 210; + //note: the item height is purposefully smaller than the background height + private static const ITEM_HEIGHT:Number = 160; + + private var _container:ScrollContainer; + + [Before] + public function prepare():void + { + this._container = new ScrollContainer(); + TestFeathers.starlingRoot.addChild(this._container); + this._container.validate(); + } + + [After] + public function cleanup():void + { + this._container.removeFromParent(true); + this._container = null; + } + + [Test] + public function testAutoSizeWithBackground():void + { + this._container.backgroundSkin = new Quad(BACKGROUND_WIDTH, BACKGROUND_HEIGHT); + this._container.validate(); + Assert.assertStrictlyEquals("The width of the scroll container was not calculated correctly.", + BACKGROUND_WIDTH, this._container.width); + Assert.assertStrictlyEquals("The height of the scroll container was not calculated correctly.", + BACKGROUND_HEIGHT, this._container.height); + } + + [Test] + public function testAutoSizeWithChildAtOrigin():void + { + this._container.addChild(new Quad(ITEM_WIDTH, ITEM_HEIGHT)); + this._container.validate(); + Assert.assertStrictlyEquals("The width of the scroll container was not calculated correctly.", + ITEM_WIDTH, this._container.width); + Assert.assertStrictlyEquals("The height of the scroll container was not calculated correctly.", + ITEM_HEIGHT, this._container.height); + } + + [Test] + public function testAutoSizeWithChild():void + { + var child:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child.x = 120; + child.y = 130; + this._container.addChild(child); + this._container.validate(); + Assert.assertStrictlyEquals("The width of the scroll container was not calculated correctly.", + child.x + ITEM_WIDTH, this._container.width); + Assert.assertStrictlyEquals("The height of the scroll container was not calculated correctly.", + child.y + ITEM_HEIGHT, this._container.height); + } + + [Test] + public function testAutoSizeWithMultipleChildren():void + { + var child1:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child1.x = 0; + child1.y = 130; + this._container.addChild(child1); + var child2:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + child2.x = 120; + child2.y = 0; + this._container.addChild(child2); + this._container.validate(); + Assert.assertStrictlyEquals("The width of the scroll container was not calculated correctly.", + child2.x + ITEM_WIDTH, this._container.width); + Assert.assertStrictlyEquals("The height of the scroll container was not calculated correctly.", + child1.y + ITEM_HEIGHT, this._container.height); + } + + [Test] + public function testAutoSizeChildAndBackground():void + { + this._container.addChild(new Quad(ITEM_WIDTH, ITEM_HEIGHT)); + this._container.backgroundSkin = new Quad(BACKGROUND_WIDTH, BACKGROUND_HEIGHT); + this._container.validate(); + Assert.assertStrictlyEquals("The width of the scroll container was not calculated correctly.", + ITEM_WIDTH, this._container.width); + Assert.assertStrictlyEquals("The height of the scroll container was not calculated correctly.", + BACKGROUND_HEIGHT, this._container.height); + } + + [Test] + public function testResizeWhenAddingChild():void + { + var originalWidth:Number = this._container.width; + var originalHeight:Number = this._container.height; + var hasResized:Boolean = false; + this._container.addEventListener(Event.RESIZE, function(event:Event):void + { + hasResized = true; + }); + this._container.addChild(new Quad(ITEM_WIDTH, ITEM_HEIGHT)); + this._container.validate(); + Assert.assertTrue("Event.RESIZE was not dispatched", hasResized); + Assert.assertFalse("The width of the layout group was not changed.", + originalWidth === this._container.width); + Assert.assertFalse("The height of the layout group was not changed.", + originalHeight === this._container.height); + } + + [Test] + public function testResizeWhenRemovingChild():void + { + var child:Quad = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + this._container.addChild(child); + this._container.validate(); + var originalWidth:Number = this._container.width; + var originalHeight:Number = this._container.height; + + var hasResized:Boolean = false; + this._container.addEventListener(Event.RESIZE, function(event:Event):void + { + hasResized = true; + }); + this._container.removeChild(child); + this._container.validate(); + Assert.assertTrue("Event.RESIZE was not dispatched", hasResized); + Assert.assertFalse("The width of the layout group was not changed.", + originalWidth === this._container.width); + Assert.assertFalse("The height of the layout group was not changed.", + originalHeight === this._container.height); + } + + [Test] + public function testResizeWhenResizingFeathersControlChild():void + { + var child:Button = new Button(); + child.defaultSkin = new Quad(ITEM_WIDTH, ITEM_HEIGHT); + this._container.addChild(child); + this._container.validate(); + + var originalWidth:Number = this._container.width; + var originalHeight:Number = this._container.height; + var hasResized:Boolean = false; + this._container.addEventListener(Event.RESIZE, function(event:Event):void + { + hasResized = true; + }); + child.width = ITEM_WIDTH * 2; + child.height = ITEM_HEIGHT * 2; + this._container.validate(); + Assert.assertTrue("Event.RESIZE was not dispatched", hasResized); + Assert.assertFalse("The width of the layout group was not changed.", + originalWidth === this._container.width); + Assert.assertFalse("The height of the layout group was not changed.", + originalHeight === this._container.height); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/SliderHorizontalTests.as b/examples/TestFeathers/source/feathers/tests/SliderHorizontalTests.as new file mode 100644 index 0000000000..86406e28c6 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/SliderHorizontalTests.as @@ -0,0 +1,268 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.Slider; + + import flash.geom.Point; + + import org.flexunit.Assert; + + import starling.display.DisplayObject; + import starling.display.Quad; + + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class SliderHorizontalTests + { + private static const THUMB_NAME:String = "thumb"; + private static const TRACK_NAME:String = "track"; + private static const TRACK_WIDTH:Number = 200; + private static const TRACK_HEIGHT:Number = 20; + private static const THUMB_WIDTH:Number = 20; + private static const THUMB_HEIGHT:Number = 20; + + private var _slider:Slider; + + [Before] + public function prepare():void + { + this._slider = new Slider(); + this._slider.direction = Slider.DIRECTION_HORIZONTAL; + this._slider.trackLayoutMode = Slider.TRACK_LAYOUT_MODE_SINGLE; + this._slider.minimumTrackFactory = function():Button + { + var track:Button = new Button(); + track.name = TRACK_NAME; + track.defaultSkin = new Quad(TRACK_WIDTH, TRACK_HEIGHT); + return track; + }; + this._slider.thumbFactory = function():Button + { + var thumb:Button = new Button(); + thumb.name = THUMB_NAME; + thumb.defaultSkin = new Quad(THUMB_WIDTH, THUMB_HEIGHT); + return thumb; + }; + TestFeathers.starlingRoot.addChild(this._slider); + this._slider.validate(); + } + + [After] + public function cleanup():void + { + this._slider.removeFromParent(true); + this._slider = null; + } + + [Test] + public function testSingleTrackAutoSize():void + { + Assert.assertStrictlyEquals("The width of the slider was not calculated correctly.", + TRACK_WIDTH, this._slider.width); + Assert.assertStrictlyEquals("The height of the slider was not calculated correctly.", + TRACK_HEIGHT, this._slider.height); + } + + [Test] + public function testProgrammaticSelectionChange():void + { + this._slider.minimum = 0; + this._slider.maximum = 10; + this._slider.value = 5; + var hasChanged:Boolean = false; + this._slider.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._slider.value = 6; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + } + + [Test] + public function testInteractiveSelectionChangeWithDraggingThumb():void + { + var beforeValue:Number = 5; + this._slider.minimum = 0; + this._slider.maximum = 10; + this._slider.value = beforeValue; + //validate to position the thumb correctly. + this._slider.validate(); + var hasChanged:Boolean = false; + this._slider.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(TRACK_WIDTH / 2, THUMB_HEIGHT / 2); + var target:DisplayObject = this._slider.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the slider's thumb", + this._slider.getChildByName(THUMB_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.MOVED; + touch.globalX = position.x + THUMB_WIDTH * 2; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("The value property was not changed to a greater value", + beforeValue < this._slider.value); + } + + [Test] + public function testInteractiveSelectionChangeWithDraggingThumbBeyondRightEdgeOfTrack():void + { + var beforeValue:Number = 5; + this._slider.minimum = 0; + this._slider.maximum = 10; + this._slider.value = beforeValue; + //validate to position the thumb correctly. + this._slider.validate(); + var hasChanged:Boolean = false; + this._slider.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(TRACK_WIDTH / 2, THUMB_HEIGHT / 2); + var target:DisplayObject = this._slider.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the slider's thumb", + this._slider.getChildByName(THUMB_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.MOVED; + touch.globalX = position.x + TRACK_WIDTH; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The value property was not equal to the maximum value", + this._slider.maximum, this._slider.value); + } + + [Test] + public function testInteractiveSelectionChangeWithDraggingThumbBeyondLeftEdgeOfTrack():void + { + var beforeValue:Number = 5; + this._slider.minimum = 0; + this._slider.maximum = 10; + this._slider.value = beforeValue; + //validate to position the thumb correctly. + this._slider.validate(); + var hasChanged:Boolean = false; + this._slider.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(TRACK_WIDTH / 2, THUMB_HEIGHT / 2); + var target:DisplayObject = this._slider.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the slider's thumb", + this._slider.getChildByName(THUMB_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.MOVED; + touch.globalX = position.x - TRACK_WIDTH; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The value property was not equal to the minimum value", + this._slider.minimum, this._slider.value); + } + + [Test] + public function testInteractiveSelectionChangeWithTouchToLeftOfTrack():void + { + var beforeValue:Number = 5; + this._slider.minimum = 0; + this._slider.maximum = 10; + this._slider.value = beforeValue; + //validate to position the thumb correctly. + this._slider.validate(); + var hasChanged:Boolean = false; + this._slider.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(TRACK_WIDTH / 3, THUMB_HEIGHT / 2); + var target:DisplayObject = this._slider.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the slider's track", + this._slider.getChildByName(TRACK_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("The value property was not less than the previous value", + beforeValue > this._slider.value); + } + + [Test] + public function testInteractiveSelectionChangeWithTouchToRightOfTrack():void + { + var beforeValue:Number = 5; + this._slider.minimum = 0; + this._slider.maximum = 10; + this._slider.value = beforeValue; + //validate to position the thumb correctly. + this._slider.validate(); + var hasChanged:Boolean = false; + this._slider.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(2 * TRACK_WIDTH / 3, THUMB_HEIGHT / 2); + var target:DisplayObject = this._slider.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the slider's track", + this._slider.getChildByName(TRACK_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertTrue("The value property was not greater than the previous value", + beforeValue < this._slider.value); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/TabBarEmptyDataProviderTests.as b/examples/TestFeathers/source/feathers/tests/TabBarEmptyDataProviderTests.as new file mode 100644 index 0000000000..5bdbc6c105 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/TabBarEmptyDataProviderTests.as @@ -0,0 +1,68 @@ +package feathers.tests +{ + import feathers.controls.TabBar; + import feathers.controls.ToggleButton; + import feathers.data.ListCollection; + + import org.flexunit.Assert; + + import starling.display.Quad; + import starling.events.Event; + + public class TabBarEmptyDataProviderTests + { + private var _tabBar:TabBar; + + [Before] + public function prepare():void + { + this._tabBar = new TabBar(); + this._tabBar.tabFactory = function():ToggleButton + { + var tab:ToggleButton = new ToggleButton(); + tab.defaultSkin = new Quad(200, 200); + return tab; + } + TestFeathers.starlingRoot.addChild(this._tabBar); + this._tabBar.validate(); + } + + [After] + public function cleanup():void + { + this._tabBar.removeFromParent(true); + this._tabBar = null; + } + + [Test] + public function testNoSelection():void + { + Assert.assertStrictlyEquals("The selectedIndex property was not equal to -1", + -1, this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not equal to null", + null, this._tabBar.selectedItem); + } + + [Test] + public function testSelectFirstItemOnSetDataProvider():void + { + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var dataProvider:ListCollection = new ListCollection( + [ + { label: "One" }, + { label: "Two" }, + { label: "Three" }, + ]); + this._tabBar.dataProvider = dataProvider; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not equal to 0", + 0, this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not equal to the first item", + dataProvider.getItemAt(0), this._tabBar.selectedItem); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/TabBarTests.as b/examples/TestFeathers/source/feathers/tests/TabBarTests.as new file mode 100644 index 0000000000..b439c12b69 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/TabBarTests.as @@ -0,0 +1,236 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.TabBar; + import feathers.controls.ToggleButton; + import feathers.data.ListCollection; + + import flash.geom.Point; + + import org.flexunit.Assert; + + import starling.display.DisplayObject; + import starling.display.Quad; + + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class TabBarTests + { + private var _tabBar:TabBar; + + [Before] + public function prepare():void + { + this._tabBar = new TabBar(); + this._tabBar.dataProvider = new ListCollection( + [ + { label: "One" }, + { label: "Two" }, + { label: "Three" }, + ]); + this._tabBar.tabFactory = function():ToggleButton + { + var tab:ToggleButton = new ToggleButton(); + tab.defaultSkin = new Quad(200, 200); + return tab; + } + TestFeathers.starlingRoot.addChild(this._tabBar); + this._tabBar.validate(); + } + + [After] + public function cleanup():void + { + this._tabBar.removeFromParent(true); + this._tabBar = null; + } + + [Test] + public function testProgrammaticSelectionChange():void + { + var beforeSelectedIndex:int = this._tabBar.selectedIndex; + var beforeSelectedItem:Object = this._tabBar.selectedItem; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.selectedIndex = 1; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._tabBar.selectedIndex); + Assert.assertFalse("The selectedItem property was not changed", + beforeSelectedItem === this._tabBar.selectedItem); + } + + [Test] + public function testInteractiveSelectionChange():void + { + var beforeSelectedIndex:Boolean = this._tabBar.selectedIndex; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(210, 10); + var target:DisplayObject = this._tabBar.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + //this touch does not move at all, so it should result in triggering + //the button. + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._tabBar.selectedIndex); + } + + [Test] + public function testRemoveItemBeforeSelectedIndex():void + { + this._tabBar.selectedIndex = 1; + var beforeSelectedIndex:int = this._tabBar.selectedIndex; + var beforeSelectedItem:Object = this._tabBar.selectedItem; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider.removeItemAt(0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._tabBar.selectedItem); + } + + [Test] + public function testRemoveItemAfterSelectedIndex():void + { + this._tabBar.selectedIndex = 1; + var beforeSelectedIndex:int = this._tabBar.selectedIndex; + var beforeSelectedItem:Object = this._tabBar.selectedItem; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider.removeItemAt(2); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._tabBar.selectedItem); + } + + [Test] + public function testRemoveSelectedIndex():void + { + this._tabBar.selectedIndex = 1; + var beforeSelectedIndex:int = this._tabBar.selectedIndex; + var beforeSelectedItem:Object = this._tabBar.selectedItem; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider.removeItemAt(1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._tabBar.selectedIndex); + Assert.assertFalse("The selectedItem property was not changed", + beforeSelectedItem === this._tabBar.selectedItem); + } + + [Test] + public function testReplaceItemAtSelectedIndex():void + { + this._tabBar.selectedIndex = 1; + var beforeSelectedIndex:int = this._tabBar.selectedIndex; + var beforeSelectedItem:Object = this._tabBar.selectedItem; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider.setItemAt({ label: "New Item" }, beforeSelectedIndex); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._tabBar.selectedIndex); + Assert.assertFalse("The selectedItem property was not changed", + beforeSelectedItem === this._tabBar.selectedItem); + } + + [Test] + public function testDeselectAllOnNullDataProvider():void + { + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider = null; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._tabBar.selectedItem); + } + + [Test] + public function testDeselectAllOnDataProviderRemoveAll():void + { + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider.removeAll(); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._tabBar.selectedItem); + } + + [Test] + public function testAddItemBeforeSelectedIndex():void + { + this._tabBar.selectedIndex = 1; + var hasChanged:Boolean = false; + var beforeSelectedIndex:int = this._tabBar.selectedIndex; + var beforeSelectedItem:Object = this._tabBar.selectedItem; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dataProvider.addItemAt({label: "New Item"}, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._tabBar.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was incorrectly changed", + beforeSelectedItem, this._tabBar.selectedItem); + } + + [Test] + public function testDisposeWithoutChangeEvent():void + { + this._tabBar.selectedIndex = 1; + var hasChanged:Boolean = false; + this._tabBar.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._tabBar.dispose(); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ToggleButtonTests.as b/examples/TestFeathers/source/feathers/tests/ToggleButtonTests.as new file mode 100644 index 0000000000..106702d9fa --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ToggleButtonTests.as @@ -0,0 +1,110 @@ +package feathers.tests +{ + import feathers.controls.ToggleButton; + + import flash.geom.Point; + + import org.flexunit.Assert; + + import starling.display.DisplayObject; + + import starling.display.Quad; + + import starling.events.Event; + + import starling.events.Touch; + + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class ToggleButtonTests + { + private var _button:ToggleButton; + + [Before] + public function prepare():void + { + this._button = new ToggleButton(); + this._button.isSelected = true; + this._button.label = "Click Me"; + this._button.defaultSkin = new Quad(200, 200); + TestFeathers.starlingRoot.addChild(this._button); + this._button.validate(); + } + + [After] + public function cleanup():void + { + this._button.removeFromParent(true); + this._button = null; + } + + [Test] + public function testProgrammaticChangeEvent():void + { + var beforeIsSelected:Boolean = this._button.isSelected; + var hasChanged:Boolean = false; + this._button.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._button.isSelected = !this._button.isSelected; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("This isSelected property was not changed", beforeIsSelected === this._button.isSelected); + } + + [Test] + public function testInteractiveChangeEvent():void + { + var beforeIsSelected:Boolean = this._button.isSelected; + var hasChanged:Boolean = false; + this._button.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(10, 10); + var target:DisplayObject = this._button.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + //this touch does not move at all, so it should result in triggering + //the button. + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("This isSelected property was not changed", beforeIsSelected === this._button.isSelected); + } + + [Test] + public function testTouchMoveOutsideBeforeChangeEvent():void + { + var beforeIsSelected:Boolean = this._button.isSelected; + var hasChanged:Boolean = false; + this._button.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(10, 10); + var target:DisplayObject = this._button.stage.hitTest(position, true); + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.x; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.globalX = 1000; //move the touch way outside the bounds of the button + touch.phase = TouchPhase.MOVED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The isSelected property was incorrectly changed", + beforeIsSelected, this._button.isSelected); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ToggleGroupTests.as b/examples/TestFeathers/source/feathers/tests/ToggleGroupTests.as new file mode 100644 index 0000000000..8b52e85ad5 --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ToggleGroupTests.as @@ -0,0 +1,259 @@ +package feathers.tests +{ + import feathers.controls.ToggleButton; + import feathers.core.IToggle; + import feathers.core.ToggleGroup; + + import org.flexunit.Assert; + + import starling.events.Event; + + public class ToggleGroupTests + { + private var _group:ToggleGroup; + + [Before] + public function prepare():void + { + this._group = new ToggleGroup(); + } + + [After] + public function cleanup():void + { + this._group = null; + } + + [Test] + public function testDefaultSelectedIndexIsNegativeOne():void + { + Assert.assertStrictlyEquals("The selectedIndex property is not equal to -1", + -1, this._group.selectedIndex); + } + + [Test] + public function testUpdatesSelectedIndexWhenAddingFirstItem():void + { + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.addItem(new ToggleButton()); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property is not equal to 0", + 0, this._group.selectedIndex); + } + + [Test] + public function testSettingSelectedIndexDispatchesChangeEvent():void + { + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.selectedIndex = 1; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + } + + [Test] + public function testSettingSelectedIndexToSameValueDispatchesNoEvent():void + { + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.selectedIndex = 0; + Assert.assertFalse("Event.CHANGE was not dispatched", hasChanged); + } + + [Test] + public function testChangingItemSelectionDispatchesChangeEvent():void + { + var itemAtIndex1:ToggleButton = new ToggleButton(); + this._group.addItem(new ToggleButton()); + this._group.addItem(itemAtIndex1); + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + itemAtIndex1.isSelected = true; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + } + + [Test] + public function testRemoveItemBeforeSelectedItem():void + { + var itemAtIndex0:ToggleButton = new ToggleButton(); + this._group.addItem(itemAtIndex0); + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + this._group.selectedIndex = 1; + var beforeSelectedIndex:int = this._group.selectedIndex; + var beforeSelectedItem:Object = this._group.selectedItem; + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.removeItem(itemAtIndex0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._group.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem was incorrectly changed", + beforeSelectedItem, this._group.selectedItem); + } + + [Test] + public function testRemoveAfterSelectedIndex():void + { + var itemAtIndex2:ToggleButton = new ToggleButton(); + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + this._group.addItem(itemAtIndex2); + this._group.selectedIndex = 1; + var beforeSelectedIndex:int = this._group.selectedIndex; + var beforeSelectedItem:Object = this._group.selectedItem; + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.removeItem(itemAtIndex2); + Assert.assertFalse("Event.CHANGE was incorrectly dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._group.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem was incorrectly changed", + beforeSelectedItem, this._group.selectedItem); + } + + [Test] + public function testRemoveSelectedItem():void + { + var itemAtIndex1:ToggleButton = new ToggleButton(); + this._group.addItem(new ToggleButton()); + this._group.addItem(itemAtIndex1); + this._group.addItem(new ToggleButton()); + this._group.selectedIndex = 1; + var beforeSelectedIndex:int = this._group.selectedIndex; + var beforeSelectedItem:IToggle = this._group.selectedItem; + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.removeItem(itemAtIndex1); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was incorrectly changed", + beforeSelectedIndex, this._group.selectedIndex); + Assert.assertFalse("The selectedItem was not changed", + beforeSelectedItem === this._group.selectedItem); + } + + [Test] + public function testDeselectAllOnRemoveAllItems():void + { + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + var hasChanged:Boolean = false; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.removeAllItems(); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertStrictlyEquals("The selectedIndex property was not set to -1", + -1, this._group.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem property was not set to null", + null, this._group.selectedItem); + } + + [Test] + public function testSetSelectedItemIndex():void + { + var itemAtIndex1:ToggleButton = new ToggleButton(); + this._group.addItem(new ToggleButton()); + this._group.addItem(itemAtIndex1); + this._group.addItem(new ToggleButton()); + this._group.selectedIndex = 1; + var hasChanged:Boolean = false; + var beforeSelectedIndex:int = this._group.selectedIndex; + var beforeSelectedItem:IToggle = this._group.selectedItem; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.setItemIndex(itemAtIndex1, 2); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._group.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem was incorrectly changed", + beforeSelectedItem, this._group.selectedItem); + } + + [Test] + public function testSetItemIndexBeforeSelectedItem():void + { + var itemAtIndex0:ToggleButton = new ToggleButton(); + this._group.addItem(itemAtIndex0); + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + this._group.selectedIndex = 1; + var hasChanged:Boolean = false; + var beforeSelectedIndex:int = this._group.selectedIndex; + var beforeSelectedItem:IToggle = this._group.selectedItem; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.setItemIndex(itemAtIndex0, 2); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._group.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem was incorrectly changed", + beforeSelectedItem, this._group.selectedItem); + } + + [Test] + public function testSetItemIndexAfterSelectedItem():void + { + var itemAtIndex2:ToggleButton = new ToggleButton(); + this._group.addItem(new ToggleButton()); + this._group.addItem(new ToggleButton()); + this._group.addItem(itemAtIndex2); + this._group.selectedIndex = 1; + var hasChanged:Boolean = false; + var beforeSelectedIndex:int = this._group.selectedIndex; + var beforeSelectedItem:IToggle = this._group.selectedItem; + this._group.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._group.setItemIndex(itemAtIndex2, 0); + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The selectedIndex property was not changed", + beforeSelectedIndex === this._group.selectedIndex); + Assert.assertStrictlyEquals("The selectedItem was incorrectly changed", + beforeSelectedItem, this._group.selectedItem); + } + + [Test] + public function testHasItem():void + { + var item:ToggleButton = new ToggleButton(); + Assert.assertFalse("hasItem() incorrectly returned true.", this._group.hasItem(item)); + this._group.addItem(item); + Assert.assertTrue("hasItem() incorrectly returned false.", this._group.hasItem(item)); + this._group.removeItem(item); + Assert.assertFalse("hasItem() incorrectly returned true.", this._group.hasItem(item)); + } + } +} diff --git a/examples/TestFeathers/source/feathers/tests/ToggleSwitchTests.as b/examples/TestFeathers/source/feathers/tests/ToggleSwitchTests.as new file mode 100644 index 0000000000..3f7245600d --- /dev/null +++ b/examples/TestFeathers/source/feathers/tests/ToggleSwitchTests.as @@ -0,0 +1,188 @@ +package feathers.tests +{ + import feathers.controls.Button; + import feathers.controls.Slider; + import feathers.controls.ToggleSwitch; + + import flash.geom.Point; + + import org.flexunit.Assert; + import org.flexunit.async.Async; + + import starling.display.DisplayObject; + import starling.display.Quad; + + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + public class ToggleSwitchTests + { + private static const THUMB_NAME:String = "thumb"; + private static const TRACK_NAME:String = "track"; + private static const TRACK_WIDTH:Number = 50; + private static const TRACK_HEIGHT:Number = 20; + private static const THUMB_WIDTH:Number = 20; + private static const THUMB_HEIGHT:Number = 20; + + private var _toggle:ToggleSwitch; + + [Before] + public function prepare():void + { + this._toggle = new ToggleSwitch(); + this._toggle.trackLayoutMode = Slider.TRACK_LAYOUT_MODE_SINGLE; + this._toggle.onTrackFactory = function():Button + { + var track:Button = new Button(); + track.name = TRACK_NAME; + track.defaultSkin = new Quad(TRACK_WIDTH, TRACK_HEIGHT); + return track; + }; + this._toggle.thumbFactory = function():Button + { + var thumb:Button = new Button(); + thumb.name = THUMB_NAME; + thumb.defaultSkin = new Quad(THUMB_WIDTH, THUMB_HEIGHT, 0xff0000); + return thumb; + }; + TestFeathers.starlingRoot.addChild(this._toggle); + this._toggle.validate(); + } + + [After] + public function cleanup():void + { + this._toggle.removeFromParent(true); + this._toggle = null; + } + + [Test] + public function testSingleTrackAutoSize():void + { + Assert.assertStrictlyEquals("The width of the toggle switch was not calculated correctly.", + TRACK_WIDTH, this._toggle.width); + Assert.assertStrictlyEquals("The height of the toggle switch was not calculated correctly.", + TRACK_HEIGHT, this._toggle.height); + } + + [Test] + public function testProgrammaticSelectionChange():void + { + this._toggle.isSelected = false; + var hasChanged:Boolean = false; + this._toggle.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + this._toggle.isSelected = true; + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + } + + [Test] + public function testInteractiveSelectionChangeWithDraggingThumb():void + { + var oldSelected:Boolean = false; + this._toggle.isSelected = oldSelected; + //validate to position the thumb correctly. + this._toggle.validate(); + var hasChanged:Boolean = false; + this._toggle.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(THUMB_WIDTH / 2, THUMB_HEIGHT / 2); + var target:DisplayObject = this._toggle.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the toggle switch's thumb", + this._toggle.getChildByName(THUMB_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.MOVED; + touch.globalX = TRACK_WIDTH - THUMB_WIDTH / 2; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The isSelected property was not changed", + oldSelected === this._toggle.isSelected); + } + + [Test] + public function testInteractiveSelectionChangeWithTapThumb():void + { + var oldSelected:Boolean = false; + this._toggle.isSelected = oldSelected; + //validate to position the thumb correctly. + this._toggle.validate(); + var hasChanged:Boolean = false; + this._toggle.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(THUMB_WIDTH / 2, THUMB_HEIGHT / 2); + var target:DisplayObject = this._toggle.stage.hitTest(position, true); + + Assert.assertStrictlyEquals("The hit test did not return the toggle switch's thumb", + this._toggle.getChildByName(THUMB_NAME).name, target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The isSelected property was not changed", + oldSelected === this._toggle.isSelected); + } + + [Test] + public function testInteractiveSelectionChangeWithTapTrack():void + { + var oldSelected:Boolean = false; + this._toggle.isSelected = oldSelected; + //validate to position the thumb correctly. + this._toggle.validate(); + var hasChanged:Boolean = false; + this._toggle.addEventListener(Event.CHANGE, function(event:Event):void + { + hasChanged = true; + }); + var position:Point = new Point(TRACK_WIDTH - THUMB_WIDTH / 2, THUMB_HEIGHT / 2); + var target:DisplayObject = this._toggle.stage.hitTest(position, true); + + //we don't care what is hit as long as its not the thumb + Assert.assertTrue("The hit test did not return a display object contained by the toggle switch", + this._toggle.contains(target)); + Assert.assertFalse("The hit test incorrectly returned the toggle switch's thumb", + this._toggle.getChildByName(THUMB_NAME).name === target.name); + + var touch:Touch = new Touch(0); + touch.target = target; + touch.phase = TouchPhase.BEGAN; + touch.globalX = position.x; + touch.globalY = position.y; + var touches:Vector. = new [touch]; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + touch.phase = TouchPhase.ENDED; + target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH, touches)); + + Assert.assertTrue("Event.CHANGE was not dispatched", hasChanged); + Assert.assertFalse("The isSelected property was not changed", + oldSelected === this._toggle.isSelected); + } + } +} diff --git a/examples/TileList/Default-568h@2x.png b/examples/TileList/Default-568h@2x.png new file mode 100644 index 0000000000..56cfbc1f00 Binary files /dev/null and b/examples/TileList/Default-568h@2x.png differ diff --git a/examples/TileList/Default-Landscape.png b/examples/TileList/Default-Landscape.png new file mode 100644 index 0000000000..c9ca20eae6 Binary files /dev/null and b/examples/TileList/Default-Landscape.png differ diff --git a/examples/TileList/Default-Landscape@2x.png b/examples/TileList/Default-Landscape@2x.png new file mode 100644 index 0000000000..b415d03e35 Binary files /dev/null and b/examples/TileList/Default-Landscape@2x.png differ diff --git a/examples/TileList/Default-Portrait.png b/examples/TileList/Default-Portrait.png new file mode 100644 index 0000000000..c4b8f7c132 Binary files /dev/null and b/examples/TileList/Default-Portrait.png differ diff --git a/examples/TileList/Default-Portrait@2x.png b/examples/TileList/Default-Portrait@2x.png new file mode 100644 index 0000000000..088c5934a1 Binary files /dev/null and b/examples/TileList/Default-Portrait@2x.png differ diff --git a/examples/TileList/Default.png b/examples/TileList/Default.png new file mode 100644 index 0000000000..53f30639a9 Binary files /dev/null and b/examples/TileList/Default.png differ diff --git a/examples/TileList/Default@2x.png b/examples/TileList/Default@2x.png new file mode 100644 index 0000000000..3ad4092b7d Binary files /dev/null and b/examples/TileList/Default@2x.png differ diff --git a/examples/TileList/README.md b/examples/TileList/README.md new file mode 100644 index 0000000000..b48366e438 --- /dev/null +++ b/examples/TileList/README.md @@ -0,0 +1,11 @@ +# Tile List Example for Feathers + +An example of customizing the List component in [Feathers](http://feathersui.com/) using a tile layout with paging. Includes some customization of the DefaultListItemRenderer layout to display an icon above text. + +## Web Demo + +View the [Tile List Example](http://feathersui.com/examples/tile-list/) in your browser. + +## Credits + +This example uses the free Buddycon Icon Set by [Webdesigner Depot](http://www.webdesignerdepot.com/) and [Orman Clark](http://www.ormanclark.com/). \ No newline at end of file diff --git a/examples/TileList/assets/images/arial20.fnt b/examples/TileList/assets/images/arial20.fnt new file mode 100644 index 0000000000..427fcabd84 --- /dev/null +++ b/examples/TileList/assets/images/arial20.fnt @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/TileList/assets/images/atlas.png b/examples/TileList/assets/images/atlas.png new file mode 100644 index 0000000000..ba75f0e2af Binary files /dev/null and b/examples/TileList/assets/images/atlas.png differ diff --git a/examples/TileList/assets/images/atlas.tps b/examples/TileList/assets/images/atlas.tps new file mode 100644 index 0000000000..95e616dc62 Binary files /dev/null and b/examples/TileList/assets/images/atlas.tps differ diff --git a/examples/TileList/assets/images/atlas.xml b/examples/TileList/assets/images/atlas.xml new file mode 100644 index 0000000000..7c1b97e512 --- /dev/null +++ b/examples/TileList/assets/images/atlas.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/TileList/assets/images/atlas/arial20.fnt b/examples/TileList/assets/images/atlas/arial20.fnt new file mode 100644 index 0000000000..427fcabd84 --- /dev/null +++ b/examples/TileList/assets/images/atlas/arial20.fnt @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/TileList/assets/images/atlas/arial20_0.png b/examples/TileList/assets/images/atlas/arial20_0.png new file mode 100644 index 0000000000..268ed4d2fd Binary files /dev/null and b/examples/TileList/assets/images/atlas/arial20_0.png differ diff --git a/examples/TileList/assets/images/atlas/bebo.png b/examples/TileList/assets/images/atlas/bebo.png new file mode 100644 index 0000000000..19973321bc Binary files /dev/null and b/examples/TileList/assets/images/atlas/bebo.png differ diff --git a/examples/TileList/assets/images/atlas/blogger.png b/examples/TileList/assets/images/atlas/blogger.png new file mode 100644 index 0000000000..bf218bfc8d Binary files /dev/null and b/examples/TileList/assets/images/atlas/blogger.png differ diff --git a/examples/TileList/assets/images/atlas/delicious.png b/examples/TileList/assets/images/atlas/delicious.png new file mode 100644 index 0000000000..fe2f58b1a8 Binary files /dev/null and b/examples/TileList/assets/images/atlas/delicious.png differ diff --git a/examples/TileList/assets/images/atlas/deviantart.png b/examples/TileList/assets/images/atlas/deviantart.png new file mode 100644 index 0000000000..2b2ce5b4cb Binary files /dev/null and b/examples/TileList/assets/images/atlas/deviantart.png differ diff --git a/examples/TileList/assets/images/atlas/digg.png b/examples/TileList/assets/images/atlas/digg.png new file mode 100644 index 0000000000..05cf2b124c Binary files /dev/null and b/examples/TileList/assets/images/atlas/digg.png differ diff --git a/examples/TileList/assets/images/atlas/facebook.png b/examples/TileList/assets/images/atlas/facebook.png new file mode 100644 index 0000000000..dfd933d695 Binary files /dev/null and b/examples/TileList/assets/images/atlas/facebook.png differ diff --git a/examples/TileList/assets/images/atlas/flickr.png b/examples/TileList/assets/images/atlas/flickr.png new file mode 100644 index 0000000000..4f9d4394e9 Binary files /dev/null and b/examples/TileList/assets/images/atlas/flickr.png differ diff --git a/examples/TileList/assets/images/atlas/friendfeed.png b/examples/TileList/assets/images/atlas/friendfeed.png new file mode 100644 index 0000000000..da05faf4aa Binary files /dev/null and b/examples/TileList/assets/images/atlas/friendfeed.png differ diff --git a/examples/TileList/assets/images/atlas/google.png b/examples/TileList/assets/images/atlas/google.png new file mode 100644 index 0000000000..74b5c30f02 Binary files /dev/null and b/examples/TileList/assets/images/atlas/google.png differ diff --git a/examples/TileList/assets/images/atlas/linkedin.png b/examples/TileList/assets/images/atlas/linkedin.png new file mode 100644 index 0000000000..757ad31e65 Binary files /dev/null and b/examples/TileList/assets/images/atlas/linkedin.png differ diff --git a/examples/TileList/assets/images/atlas/livejournal.png b/examples/TileList/assets/images/atlas/livejournal.png new file mode 100644 index 0000000000..5d344fe2aa Binary files /dev/null and b/examples/TileList/assets/images/atlas/livejournal.png differ diff --git a/examples/TileList/assets/images/atlas/myspace.png b/examples/TileList/assets/images/atlas/myspace.png new file mode 100644 index 0000000000..84f2683dea Binary files /dev/null and b/examples/TileList/assets/images/atlas/myspace.png differ diff --git a/examples/TileList/assets/images/atlas/newsvine.png b/examples/TileList/assets/images/atlas/newsvine.png new file mode 100644 index 0000000000..afbb5d34e5 Binary files /dev/null and b/examples/TileList/assets/images/atlas/newsvine.png differ diff --git a/examples/TileList/assets/images/atlas/normal-page-symbol.png b/examples/TileList/assets/images/atlas/normal-page-symbol.png new file mode 100644 index 0000000000..7ca1966af4 Binary files /dev/null and b/examples/TileList/assets/images/atlas/normal-page-symbol.png differ diff --git a/examples/TileList/assets/images/atlas/orkut.png b/examples/TileList/assets/images/atlas/orkut.png new file mode 100644 index 0000000000..ec9f12e7dc Binary files /dev/null and b/examples/TileList/assets/images/atlas/orkut.png differ diff --git a/examples/TileList/assets/images/atlas/picasa.png b/examples/TileList/assets/images/atlas/picasa.png new file mode 100644 index 0000000000..f3cea8213d Binary files /dev/null and b/examples/TileList/assets/images/atlas/picasa.png differ diff --git a/examples/TileList/assets/images/atlas/posterous.png b/examples/TileList/assets/images/atlas/posterous.png new file mode 100644 index 0000000000..76725fede0 Binary files /dev/null and b/examples/TileList/assets/images/atlas/posterous.png differ diff --git a/examples/TileList/assets/images/atlas/reddit.png b/examples/TileList/assets/images/atlas/reddit.png new file mode 100644 index 0000000000..884c99a743 Binary files /dev/null and b/examples/TileList/assets/images/atlas/reddit.png differ diff --git a/examples/TileList/assets/images/atlas/selected-page-symbol.png b/examples/TileList/assets/images/atlas/selected-page-symbol.png new file mode 100644 index 0000000000..079c6e602e Binary files /dev/null and b/examples/TileList/assets/images/atlas/selected-page-symbol.png differ diff --git a/examples/TileList/assets/images/atlas/slashdot.png b/examples/TileList/assets/images/atlas/slashdot.png new file mode 100644 index 0000000000..366721d432 Binary files /dev/null and b/examples/TileList/assets/images/atlas/slashdot.png differ diff --git a/examples/TileList/assets/images/atlas/stumbleupon.png b/examples/TileList/assets/images/atlas/stumbleupon.png new file mode 100644 index 0000000000..79a4cc2e8c Binary files /dev/null and b/examples/TileList/assets/images/atlas/stumbleupon.png differ diff --git a/examples/TileList/assets/images/atlas/technorati.png b/examples/TileList/assets/images/atlas/technorati.png new file mode 100644 index 0000000000..28d86d5da8 Binary files /dev/null and b/examples/TileList/assets/images/atlas/technorati.png differ diff --git a/examples/TileList/assets/images/atlas/tumblr.png b/examples/TileList/assets/images/atlas/tumblr.png new file mode 100644 index 0000000000..a54a7fb3e8 Binary files /dev/null and b/examples/TileList/assets/images/atlas/tumblr.png differ diff --git a/examples/TileList/assets/images/atlas/twitter.png b/examples/TileList/assets/images/atlas/twitter.png new file mode 100644 index 0000000000..5d4257fdab Binary files /dev/null and b/examples/TileList/assets/images/atlas/twitter.png differ diff --git a/examples/TileList/assets/images/atlas/viddler.png b/examples/TileList/assets/images/atlas/viddler.png new file mode 100644 index 0000000000..07f7890537 Binary files /dev/null and b/examples/TileList/assets/images/atlas/viddler.png differ diff --git a/examples/TileList/assets/images/atlas/vimeo.png b/examples/TileList/assets/images/atlas/vimeo.png new file mode 100644 index 0000000000..8373c00705 Binary files /dev/null and b/examples/TileList/assets/images/atlas/vimeo.png differ diff --git a/examples/TileList/assets/images/atlas/wordpress.png b/examples/TileList/assets/images/atlas/wordpress.png new file mode 100644 index 0000000000..116fc362bb Binary files /dev/null and b/examples/TileList/assets/images/atlas/wordpress.png differ diff --git a/examples/TileList/assets/images/atlas/yahoo.png b/examples/TileList/assets/images/atlas/yahoo.png new file mode 100644 index 0000000000..9a452e06fb Binary files /dev/null and b/examples/TileList/assets/images/atlas/yahoo.png differ diff --git a/examples/TileList/assets/images/atlas/yelp.png b/examples/TileList/assets/images/atlas/yelp.png new file mode 100644 index 0000000000..51059c4a31 Binary files /dev/null and b/examples/TileList/assets/images/atlas/yelp.png differ diff --git a/examples/TileList/assets/images/atlas/youtube.png b/examples/TileList/assets/images/atlas/youtube.png new file mode 100644 index 0000000000..e01e398f10 Binary files /dev/null and b/examples/TileList/assets/images/atlas/youtube.png differ diff --git a/examples/TileList/build.properties b/examples/TileList/build.properties new file mode 100644 index 0000000000..be7e6e7d64 --- /dev/null +++ b/examples/TileList/build.properties @@ -0,0 +1,6 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/TileList/build.xml b/examples/TileList/build.xml new file mode 100644 index 0000000000..823b9210a5 --- /dev/null +++ b/examples/TileList/build.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/TileList/sdk.properties b/examples/TileList/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/TileList/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/TileList/source/TileList-app.xml b/examples/TileList/source/TileList-app.xml new file mode 100644 index 0000000000..b98f22907b --- /dev/null +++ b/examples/TileList/source/TileList-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.TileList + Feathers TileList + Feathers TileList + 2.0.1 + TileList example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + TileList.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/TileList/source/TileList.as b/examples/TileList/source/TileList.as new file mode 100644 index 0000000000..5cb3dc1407 --- /dev/null +++ b/examples/TileList/source/TileList.as @@ -0,0 +1,153 @@ +package +{ + import feathers.examples.tileList.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#ffffff")] + public class TileList extends Sprite + { + public function TileList() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/TileList/source/TileListWeb.as b/examples/TileList/source/TileListWeb.as new file mode 100644 index 0000000000..780bd67c60 --- /dev/null +++ b/examples/TileList/source/TileListWeb.as @@ -0,0 +1,71 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#ffffff")] + public class TileListWeb extends MovieClip + { + public function TileListWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + this.mouseEnabled = this.mouseChildren = false; + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.tileList.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.start(); + } + + private function enterFrameHandler(event:Event):void + { + if(this.stage.stageWidth > 0 && this.stage.stageHeight > 0) + { + this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler); + this.start(); + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + if(this.stage.stageWidth == 0 || this.stage.stageHeight == 0) + { + this.addEventListener(Event.ENTER_FRAME, enterFrameHandler); + return; + } + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/TileList/source/feathers/examples/tileList/Main.as b/examples/TileList/source/feathers/examples/tileList/Main.as new file mode 100644 index 0000000000..2b7f3caaf8 --- /dev/null +++ b/examples/TileList/source/feathers/examples/tileList/Main.as @@ -0,0 +1,186 @@ +package feathers.examples.tileList +{ + import feathers.controls.Button; + import feathers.controls.LayoutGroup; + import feathers.controls.List; + import feathers.controls.PageIndicator; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.layout.TiledRowsLayout; + import feathers.text.BitmapFontTextFormat; + + import starling.display.Image; + import starling.events.Event; + import starling.events.ResizeEvent; + import starling.text.BitmapFont; + import starling.textures.Texture; + import starling.textures.TextureAtlas; + + public class Main extends LayoutGroup + { + [Embed(source="/../assets/images/atlas.png")] + private static const ICONS_IMAGE:Class; + + [Embed(source="/../assets/images/atlas.xml",mimeType="application/octet-stream")] + private static const ICONS_XML:Class; + + [Embed(source="/../assets/images/arial20.fnt",mimeType="application/octet-stream")] + private static const FONT_XML:Class; + + public function Main() + { + //the container will fill the whole stage and resize when the stage + //resizes. + this.autoSizeMode = LayoutGroup.AUTO_SIZE_MODE_STAGE; + } + + private var _iconAtlas:TextureAtlas; + private var _font:BitmapFont; + private var _list:List; + private var _pageIndicator:PageIndicator; + + override public function dispose():void + { + //don't forget to clean up textures and things! + if(this._iconAtlas) + { + this._iconAtlas.dispose(); + this._iconAtlas = null; + } + if(this._font) + { + this._font.dispose(); + this._font = null; + } + super.dispose(); + } + + override protected function initialize():void + { + //a nice, fluid layout + this.layout = new AnchorLayout(); + + //setting up some assets for skinning + this._iconAtlas = new TextureAtlas(Texture.fromBitmap(new ICONS_IMAGE(), false), XML(new ICONS_XML())); + this._font = new BitmapFont(this._iconAtlas.getTexture("arial20_0"), XML(new FONT_XML())); + var pageIndicatorNormalSymbol:Texture = this._iconAtlas.getTexture("normal-page-symbol"); + var pageIndicatorSelectedSymbol:Texture = this._iconAtlas.getTexture("selected-page-symbol"); + + //the page indicator can be used to scroll the list + this._pageIndicator = new PageIndicator(); + this._pageIndicator.pageCount = 1; + this._pageIndicator.normalSymbolFactory = function():Image + { + return new Image(pageIndicatorNormalSymbol); + } + this._pageIndicator.selectedSymbolFactory = function():Image + { + return new Image(pageIndicatorSelectedSymbol); + } + this._pageIndicator.direction = PageIndicator.DIRECTION_HORIZONTAL; + this._pageIndicator.gap = 4; + this._pageIndicator.padding = 6; + + //we listen to the change event to update the list's scroll position + this._pageIndicator.addEventListener(Event.CHANGE, pageIndicator_changeHandler); + + //we'll position the page indicator on the bottom and stretch its + //width to fill the container's width + var pageIndicatorLayoutData:AnchorLayoutData = new AnchorLayoutData(); + pageIndicatorLayoutData.bottom = 0; + pageIndicatorLayoutData.left = 0; + pageIndicatorLayoutData.right = 0; + this._pageIndicator.layoutData = pageIndicatorLayoutData; + + this.addChild(this._pageIndicator); + + //the data that will be displayed in the list + var collection:ListCollection = new ListCollection( + [ + { label: "Facebook", texture: this._iconAtlas.getTexture("facebook") }, + { label: "Twitter", texture: this._iconAtlas.getTexture("twitter") }, + { label: "Google", texture: this._iconAtlas.getTexture("google") }, + { label: "YouTube", texture: this._iconAtlas.getTexture("youtube") }, + { label: "StumbleUpon", texture: this._iconAtlas.getTexture("stumbleupon") }, + { label: "Yahoo", texture: this._iconAtlas.getTexture("yahoo") }, + { label: "Tumblr", texture: this._iconAtlas.getTexture("tumblr") }, + { label: "Blogger", texture: this._iconAtlas.getTexture("blogger") }, + { label: "Reddit", texture: this._iconAtlas.getTexture("reddit") }, + { label: "Flickr", texture: this._iconAtlas.getTexture("flickr") }, + { label: "Yelp", texture: this._iconAtlas.getTexture("yelp") }, + { label: "Vimeo", texture: this._iconAtlas.getTexture("vimeo") }, + { label: "LinkedIn", texture: this._iconAtlas.getTexture("linkedin") }, + { label: "Delicious", texture: this._iconAtlas.getTexture("delicious") }, + { label: "FriendFeed", texture: this._iconAtlas.getTexture("friendfeed") }, + { label: "MySpace", texture: this._iconAtlas.getTexture("myspace") }, + { label: "Digg", texture: this._iconAtlas.getTexture("digg") }, + { label: "DeviantArt", texture: this._iconAtlas.getTexture("deviantart") }, + { label: "Picasa", texture: this._iconAtlas.getTexture("picasa") }, + { label: "LiveJournal", texture: this._iconAtlas.getTexture("livejournal") }, + { label: "Slashdot", texture: this._iconAtlas.getTexture("slashdot") }, + { label: "Bebo", texture: this._iconAtlas.getTexture("bebo") }, + { label: "Viddler", texture: this._iconAtlas.getTexture("viddler") }, + { label: "Newsvine", texture: this._iconAtlas.getTexture("newsvine") }, + { label: "Posterous", texture: this._iconAtlas.getTexture("posterous") }, + { label: "Orkut", texture: this._iconAtlas.getTexture("orkut") }, + ]); + + this._list = new List(); + this._list.dataProvider = collection; + this._list.snapToPages = true; + this._list.scrollBarDisplayMode = List.SCROLL_BAR_DISPLAY_MODE_NONE; + this._list.horizontalScrollPolicy = List.SCROLL_POLICY_ON; + this._list.itemRendererFactory = tileListItemRendererFactory; + + //we listen to the scroll event to update the page indicator + this._list.addEventListener(Event.SCROLL, list_scrollHandler); + + //this is the list's layout... + var listLayout:TiledRowsLayout = new TiledRowsLayout(); + listLayout.paging = TiledRowsLayout.PAGING_HORIZONTAL; + listLayout.useSquareTiles = false; + listLayout.tileHorizontalAlign = TiledRowsLayout.TILE_HORIZONTAL_ALIGN_CENTER; + listLayout.horizontalAlign = TiledRowsLayout.HORIZONTAL_ALIGN_CENTER; + listLayout.padding = 20; + listLayout.gap = 20; + this._list.layout = listLayout; + + //...while this is the layout data used by the list's parent + var listLayoutData:AnchorLayoutData = new AnchorLayoutData(); + listLayoutData.top = 0; + listLayoutData.right = 0; + listLayoutData.bottom = 0; + listLayoutData.bottomAnchorDisplayObject = this._pageIndicator; + listLayoutData.left = 0; + //this list fills the container's width and the remaining height + //above the page indicator + this._list.layoutData = listLayoutData; + + this.addChild(this._list); + } + + protected function tileListItemRendererFactory():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + renderer.labelField = "label"; + renderer.iconSourceField = "texture"; + renderer.iconPosition = Button.ICON_POSITION_TOP; + renderer.defaultLabelProperties.textFormat = new BitmapFontTextFormat(this._font, NaN, 0x000000); + return renderer; + } + + protected function list_scrollHandler(event:Event):void + { + this._pageIndicator.pageCount = this._list.horizontalPageCount; + this._pageIndicator.selectedIndex = this._list.horizontalPageIndex; + } + + protected function pageIndicator_changeHandler(event:Event):void + { + this._list.scrollToPageIndex(this._pageIndicator.selectedIndex, 0, this._list.pageThrowDuration); + } + } +} diff --git a/examples/Todos/README.md b/examples/Todos/README.md new file mode 100644 index 0000000000..e42a8d903a --- /dev/null +++ b/examples/Todos/README.md @@ -0,0 +1,13 @@ +# Todos Example for Feathers + +This [Feathers](http://feathersui.com/) example mocks up a simple application to track things that need to get done. It extends the MetalWorksMobileTheme and uses a custom list item renderer that can switch into an editing mode to delete items. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Todos example](http://feathersui.com/examples/todos/) in your browser. \ No newline at end of file diff --git a/examples/Todos/build.properties b/examples/Todos/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/Todos/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/Todos/build.xml b/examples/Todos/build.xml new file mode 100644 index 0000000000..cd032827d1 --- /dev/null +++ b/examples/Todos/build.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Todos/sdk.properties b/examples/Todos/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/Todos/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/Todos/source/Todos-app.xml b/examples/Todos/source/Todos-app.xml new file mode 100644 index 0000000000..3f1d732540 --- /dev/null +++ b/examples/Todos/source/Todos-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.Todos + Todos + Todos + 2.0.1 + Todos example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + Todos.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/Todos/source/Todos.as b/examples/Todos/source/Todos.as new file mode 100644 index 0000000000..5e58a6f1f8 --- /dev/null +++ b/examples/Todos/source/Todos.as @@ -0,0 +1,155 @@ +package +{ + import feathers.examples.todos.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class Todos extends Sprite + { + public function Todos() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/Todos/source/TodosWeb.as b/examples/Todos/source/TodosWeb.as new file mode 100644 index 0000000000..dd49f5eaac --- /dev/null +++ b/examples/Todos/source/TodosWeb.as @@ -0,0 +1,57 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class TodosWeb extends MovieClip + { + public function TodosWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.todos.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.enableErrorChecking = false; + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/Todos/source/feathers/examples/todos/Main.as b/examples/Todos/source/feathers/examples/todos/Main.as new file mode 100644 index 0000000000..acc70476b5 --- /dev/null +++ b/examples/Todos/source/feathers/examples/todos/Main.as @@ -0,0 +1,142 @@ +package feathers.examples.todos +{ + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ScrollContainer; + import feathers.controls.TextInput; + import feathers.controls.ToggleButton; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.examples.todos.controls.TodoItemRenderer; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.themes.MetalWorksMobileTheme; + + import starling.display.DisplayObject; + import starling.events.Event; + + public class Main extends PanelScreen + { + public function Main() + { + this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); + } + + private var _input:TextInput; + private var _list:List; + private var _editButton:ToggleButton; + private var _toolbar:ScrollContainer; + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + header.titleAlign = Header.TITLE_ALIGN_PREFER_LEFT; + + if(!this._input) + { + this._input = new TextInput(); + this._input.prompt = "What needs to be done?"; + + //we can't get an enter key event without changing the returnKeyLabel + //not using ReturnKeyLabel.GO here so that it will build for web + this._input.textEditorProperties.returnKeyLabel = "go"; + + this._input.addEventListener(FeathersEventType.ENTER, input_enterHandler); + } + + header.rightItems = new + [ + this._input + ]; + + return header; + } + + private function customFooterFactory():ScrollContainer + { + if(!this._toolbar) + { + this._toolbar = new ScrollContainer(); + this._toolbar.styleNameList.add(ScrollContainer.ALTERNATE_STYLE_NAME_TOOLBAR); + } + else + { + this._toolbar.removeChildren(); + } + + if(!this._editButton) + { + this._editButton = new ToggleButton(); + this._editButton.label = "Edit"; + this._editButton.addEventListener(Event.CHANGE, editButton_changeHandler); + } + this._toolbar.addChild(this._editButton); + + return this._toolbar; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + new MetalWorksMobileTheme(); + + this.title = "TODOS"; + + this.width = this.stage.stageWidth; + this.height = this.stage.stageHeight; + + this.layout = new AnchorLayout(); + + this.headerFactory = this.customHeaderFactory; + this.footerFactory = this.customFooterFactory; + + this._list = new List(); + this._list.isSelectable = false; + this._list.dataProvider = new ListCollection(); + this._list.itemRendererType = TodoItemRenderer; + this._list.itemRendererProperties.labelField = "description"; + var listLayoutData:AnchorLayoutData = new AnchorLayoutData(0, 0, 0, 0); + listLayoutData.topAnchorDisplayObject = this._input; + this._list.layoutData = listLayoutData; + this.addChild(this._list); + } + + private function addedToStageHandler():void + { + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler); + } + + private function removedFromStageHandler():void + { + this.stage.removeEventListener(Event.RESIZE, stage_resizeHandler); + } + + private function input_enterHandler():void + { + if(!this._input.text) + { + return; + } + + this._list.dataProvider.addItem(new TodoItem(this._input.text)); + this._input.text = ""; + } + + private function editButton_changeHandler(event:Event):void + { + var isEditing:Boolean = this._editButton.isSelected; + this._list.itemRendererProperties.isEditable = isEditing; + this._input.visible = !isEditing; + } + + private function stage_resizeHandler():void + { + this.width = this.stage.stageWidth; + this.height = this.stage.stageHeight; + } + } +} diff --git a/examples/Todos/source/feathers/examples/todos/TodoItem.as b/examples/Todos/source/feathers/examples/todos/TodoItem.as new file mode 100644 index 0000000000..1863857f1a --- /dev/null +++ b/examples/Todos/source/feathers/examples/todos/TodoItem.as @@ -0,0 +1,14 @@ +package feathers.examples.todos +{ + public class TodoItem + { + public function TodoItem(description:String, isCompleted:Boolean = false) + { + this.description = description; + this.isCompleted = isCompleted; + } + + public var description:String; + public var isCompleted:Boolean; + } +} diff --git a/examples/Todos/source/feathers/examples/todos/controls/TodoItemRenderer.as b/examples/Todos/source/feathers/examples/todos/controls/TodoItemRenderer.as new file mode 100644 index 0000000000..5724c5c40b --- /dev/null +++ b/examples/Todos/source/feathers/examples/todos/controls/TodoItemRenderer.as @@ -0,0 +1,103 @@ +package feathers.examples.todos.controls +{ + import feathers.controls.Button; + import feathers.controls.Check; + import feathers.controls.List; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.examples.todos.TodoItem; + + import starling.events.Event; + + public class TodoItemRenderer extends DefaultListItemRenderer + { + public function TodoItemRenderer() + { + super(); + this.itemHasIcon = false; + this.itemHasAccessory = false; + } + + protected var check:Check; + protected var deleteButton:Button; + + private var _isEditable:Boolean = false; + + public function get isEditable():Boolean + { + return this._isEditable; + } + + public function set isEditable(value:Boolean):void + { + if(this._isEditable == value) + { + return; + } + this._isEditable = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + override public function dispose():void + { + if(this.check) + { + this.check.removeFromParent(true); + this.check = null; + } + if(this.deleteButton) + { + this.deleteButton.removeFromParent(true); + this.deleteButton = null; + } + super.dispose(); + } + + override protected function commitData():void + { + super.commitData(); + var item:TodoItem = this._data as TodoItem; + if(!item) + { + return; + } + if(!this.check) + { + this.check = new Check(); + this.check.addEventListener(Event.CHANGE, check_changeHandler); + } + this.check.isSelected = item.isCompleted; + this.check.isEnabled = !this._isEditable; + this.replaceIcon(this.check); + + if(!this.deleteButton) + { + this.deleteButton = new Button(); + this.deleteButton.label = "Delete"; + this.deleteButton.addEventListener(Event.TRIGGERED, deleteButton_triggeredHandler); + } + if(this._isEditable) + { + this.replaceAccessory(this.deleteButton); + } + else + { + this.replaceAccessory(null) + } + } + + protected function check_changeHandler(event:Event):void + { + var item:TodoItem = this._data as TodoItem; + if(!item) + { + return; + } + item.isCompleted = this.check.isSelected; + } + + protected function deleteButton_triggeredHandler(event:Event):void + { + List(this._owner).dataProvider.removeItemAt(this._index); + } + } +} diff --git a/examples/TrainTimes/Default-568h@2x.png b/examples/TrainTimes/Default-568h@2x.png new file mode 100644 index 0000000000..0abcde4e11 Binary files /dev/null and b/examples/TrainTimes/Default-568h@2x.png differ diff --git a/examples/TrainTimes/Default-Landscape.png b/examples/TrainTimes/Default-Landscape.png new file mode 100644 index 0000000000..646249b14d Binary files /dev/null and b/examples/TrainTimes/Default-Landscape.png differ diff --git a/examples/TrainTimes/Default-Landscape@2x.png b/examples/TrainTimes/Default-Landscape@2x.png new file mode 100644 index 0000000000..29543a0c71 Binary files /dev/null and b/examples/TrainTimes/Default-Landscape@2x.png differ diff --git a/examples/TrainTimes/Default-Portrait.png b/examples/TrainTimes/Default-Portrait.png new file mode 100644 index 0000000000..e890ae5d69 Binary files /dev/null and b/examples/TrainTimes/Default-Portrait.png differ diff --git a/examples/TrainTimes/Default-Portrait@2x.png b/examples/TrainTimes/Default-Portrait@2x.png new file mode 100644 index 0000000000..f37295eb14 Binary files /dev/null and b/examples/TrainTimes/Default-Portrait@2x.png differ diff --git a/examples/TrainTimes/Default.png b/examples/TrainTimes/Default.png new file mode 100644 index 0000000000..c2ee19d631 Binary files /dev/null and b/examples/TrainTimes/Default.png differ diff --git a/examples/TrainTimes/Default@2x.png b/examples/TrainTimes/Default@2x.png new file mode 100644 index 0000000000..7f9c42c41b Binary files /dev/null and b/examples/TrainTimes/Default@2x.png differ diff --git a/examples/TrainTimes/README.md b/examples/TrainTimes/README.md new file mode 100644 index 0000000000..8eb5f014be --- /dev/null +++ b/examples/TrainTimes/README.md @@ -0,0 +1,7 @@ +# Train Times Example for Feathers + +This [Feathers](http://feathersui.com/) example mocks up a simple application to view train schedules. It uses custom item renderers and a custom theme. + +## Web Demo + +View the [Train Times example](http://feathersui.com/examples/train-times/) in your browser. \ No newline at end of file diff --git a/examples/TrainTimes/assets/fonts/SourceSansPro-Bold.ttf b/examples/TrainTimes/assets/fonts/SourceSansPro-Bold.ttf new file mode 100644 index 0000000000..b8d40c0aa5 Binary files /dev/null and b/examples/TrainTimes/assets/fonts/SourceSansPro-Bold.ttf differ diff --git a/examples/TrainTimes/assets/fonts/SourceSansPro-BoldIt.ttf b/examples/TrainTimes/assets/fonts/SourceSansPro-BoldIt.ttf new file mode 100644 index 0000000000..ec3f24a7e4 Binary files /dev/null and b/examples/TrainTimes/assets/fonts/SourceSansPro-BoldIt.ttf differ diff --git a/examples/TrainTimes/assets/fonts/SourceSansPro-Regular.ttf b/examples/TrainTimes/assets/fonts/SourceSansPro-Regular.ttf new file mode 100644 index 0000000000..24962c7c87 Binary files /dev/null and b/examples/TrainTimes/assets/fonts/SourceSansPro-Regular.ttf differ diff --git a/examples/TrainTimes/assets/images/traintimes.png b/examples/TrainTimes/assets/images/traintimes.png new file mode 100644 index 0000000000..bef1dd842a Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes.png differ diff --git a/examples/TrainTimes/assets/images/traintimes.tps b/examples/TrainTimes/assets/images/traintimes.tps new file mode 100644 index 0000000000..4246098176 --- /dev/null +++ b/examples/TrainTimes/assets/images/traintimes.tps @@ -0,0 +1,155 @@ + + + + fileFormatVersion + 1 + variation + main + verbose + + autoSDSettings + + allowRotation + + quiet + + premultiplyAlpha + + shapeDebug + + dpi + 72 + dataFormat + sparrow + textureFileName + traintimes.png + flipPVR + + ditherType + NearestNeighbour + backgroundColor + 0 + libGdx + + filtering + + x + Linear + y + Linear + + + shapePadding + 1 + jpgQuality + 80 + pngOptimizationLevel + 0 + textureSubPath + + textureFormat + png + borderPadding + 1 + maxTextureSize + + width + 2048 + height + 2048 + + fixedTextureSize + + width + -1 + height + -1 + + reduceBorderArtifacts + + algorithmSettings + + algorithm + MaxRects + freeSizeMode + Best + sizeConstraints + POT + forceSquared + + forceWordAligned + + maxRects + + heuristic + Best + + basic + + sortBy + Best + order + Ascending + + + andEngine + + minFilter + Linear + packageName + Texture + javaFileName + traintimes.java + wrap + + s + Clamp + t + Clamp + + magFilter + MagLinear + + dataFileName + traintimes.xml + mainExtension + + forceIdenticalLayout + + outputFormat + RGBA8888 + autoAliasEnabled + + trimSpriteNames + + globalSpriteSettings + + scale + 1 + scaleMode + Smooth + innerPadding + 0 + extrude + 1 + trimThreshold + 1 + trimMode + Trim + heuristicMask + + + fileList + + traintimes + + ignoreFileList + + replaceList + + commonDivisorX + 1 + commonDivisorY + 1 + + diff --git a/examples/TrainTimes/assets/images/traintimes.xml b/examples/TrainTimes/assets/images/traintimes.xml new file mode 100644 index 0000000000..9b19233e43 --- /dev/null +++ b/examples/TrainTimes/assets/images/traintimes.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/examples/TrainTimes/assets/images/traintimes/back-icon.png b/examples/TrainTimes/assets/images/traintimes/back-icon.png new file mode 100644 index 0000000000..516e9d4198 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/back-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/cancel-icon.png b/examples/TrainTimes/assets/images/traintimes/cancel-icon.png new file mode 100644 index 0000000000..727dd99e7d Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/cancel-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/confirm-icon.png b/examples/TrainTimes/assets/images/traintimes/confirm-icon.png new file mode 100644 index 0000000000..c21cc6afdd Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/confirm-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/header-background.png b/examples/TrainTimes/assets/images/traintimes/header-background.png new file mode 100644 index 0000000000..c3940534fc Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/header-background.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/horizontal-scroll-bar-thumb-skin.png b/examples/TrainTimes/assets/images/traintimes/horizontal-scroll-bar-thumb-skin.png new file mode 100644 index 0000000000..c53de8a617 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/horizontal-scroll-bar-thumb-skin.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/main-background.png b/examples/TrainTimes/assets/images/traintimes/main-background.png new file mode 100644 index 0000000000..b3c86de139 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/main-background.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/station-list-first-normal-icon.png b/examples/TrainTimes/assets/images/traintimes/station-list-first-normal-icon.png new file mode 100644 index 0000000000..a97b124dac Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/station-list-first-normal-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/station-list-first-selected-icon.png b/examples/TrainTimes/assets/images/traintimes/station-list-first-selected-icon.png new file mode 100644 index 0000000000..16f7bfaa79 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/station-list-first-selected-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/station-list-last-normal-icon.png b/examples/TrainTimes/assets/images/traintimes/station-list-last-normal-icon.png new file mode 100644 index 0000000000..bf34b3c8b6 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/station-list-last-normal-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/station-list-last-selected-icon.png b/examples/TrainTimes/assets/images/traintimes/station-list-last-selected-icon.png new file mode 100644 index 0000000000..38e40f8449 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/station-list-last-selected-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/station-list-normal-icon.png b/examples/TrainTimes/assets/images/traintimes/station-list-normal-icon.png new file mode 100644 index 0000000000..25bdad25f7 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/station-list-normal-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/station-list-selected-icon.png b/examples/TrainTimes/assets/images/traintimes/station-list-selected-icon.png new file mode 100644 index 0000000000..0cee8646f5 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/station-list-selected-icon.png differ diff --git a/examples/TrainTimes/assets/images/traintimes/vertical-scroll-bar-thumb-skin.png b/examples/TrainTimes/assets/images/traintimes/vertical-scroll-bar-thumb-skin.png new file mode 100644 index 0000000000..dada031132 Binary files /dev/null and b/examples/TrainTimes/assets/images/traintimes/vertical-scroll-bar-thumb-skin.png differ diff --git a/examples/TrainTimes/build.properties b/examples/TrainTimes/build.properties new file mode 100644 index 0000000000..be7e6e7d64 --- /dev/null +++ b/examples/TrainTimes/build.properties @@ -0,0 +1,6 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/TrainTimes/build.xml b/examples/TrainTimes/build.xml new file mode 100644 index 0000000000..eec9aed63c --- /dev/null +++ b/examples/TrainTimes/build.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/TrainTimes/sdk.properties b/examples/TrainTimes/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/TrainTimes/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/TrainTimes/source/TrainTimes-app.xml b/examples/TrainTimes/source/TrainTimes-app.xml new file mode 100644 index 0000000000..ff541bea12 --- /dev/null +++ b/examples/TrainTimes/source/TrainTimes-app.xml @@ -0,0 +1,54 @@ + + + com.feathersui.examples.TrainTimes + Train Times + Train Times + 2.0.1 + Train Times example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + TrainTimes.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/TrainTimes/source/TrainTimes.as b/examples/TrainTimes/source/TrainTimes.as new file mode 100644 index 0000000000..90eb58cfdc --- /dev/null +++ b/examples/TrainTimes/source/TrainTimes.as @@ -0,0 +1,69 @@ +package +{ + import feathers.examples.trainTimes.Main; + + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.geom.Rectangle; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#424254")] + public class TrainTimes extends Sprite + { + public function TrainTimes() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + this._starling.start(); + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/TrainTimes/source/TrainTimesWeb.as b/examples/TrainTimes/source/TrainTimesWeb.as new file mode 100644 index 0000000000..db4f19582e --- /dev/null +++ b/examples/TrainTimes/source/TrainTimesWeb.as @@ -0,0 +1,57 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#424254")] + public class TrainTimesWeb extends MovieClip + { + public function TrainTimesWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.trainTimes.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.enableErrorChecking = false; + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/Main.as b/examples/TrainTimes/source/feathers/examples/trainTimes/Main.as new file mode 100644 index 0000000000..1b209b58e7 --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/Main.as @@ -0,0 +1,44 @@ +package feathers.examples.trainTimes +{ + + import feathers.controls.StackScreenNavigator; + import feathers.controls.StackScreenNavigatorItem; + import feathers.examples.trainTimes.screens.StationScreen; + import feathers.examples.trainTimes.screens.TimesScreen; + import feathers.examples.trainTimes.themes.TrainTimesTheme; + import feathers.motion.transitions.Slide; + + import starling.events.Event; + + public class Main extends StackScreenNavigator + { + private static const STATION_SCREEN:String = "stationScreen"; + private static const TIMES_SCREEN:String = "timesScreen"; + + public function Main() + { + super(); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + new TrainTimesTheme(); + + var stationScreenItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(StationScreen); + stationScreenItem.setScreenIDForPushEvent(Event.COMPLETE, TIMES_SCREEN); + this.addScreen(STATION_SCREEN, stationScreenItem); + + var timesScreenItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TimesScreen); + timesScreenItem.addPopEvent(Event.COMPLETE); + this.addScreen(TIMES_SCREEN, timesScreenItem); + + this.rootScreenID = STATION_SCREEN; + + this.pushTransition = Slide.createSlideLeftTransition(); + this.popTransition = Slide.createSlideRightTransition(); + } + } +} diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/controls/StationListItemRenderer.as b/examples/TrainTimes/source/feathers/examples/trainTimes/controls/StationListItemRenderer.as new file mode 100644 index 0000000000..45d968de81 --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/controls/StationListItemRenderer.as @@ -0,0 +1,747 @@ +package feathers.examples.trainTimes.controls +{ + import feathers.controls.Button; + import feathers.controls.ImageLoader; + import feathers.controls.Label; + import feathers.controls.List; + import feathers.controls.ScrollContainer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.core.FeathersControl; + import feathers.examples.trainTimes.model.StationData; + import feathers.skins.IStyleProvider; + + import flash.geom.Point; + + import starling.animation.Transitions; + import starling.animation.Tween; + import starling.core.Starling; + import starling.display.Quad; + import starling.events.Event; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + import starling.textures.Texture; + + public class StationListItemRenderer extends FeathersControl implements IListItemRenderer + { + public static const CHILD_STYLE_NAME_STATION_LIST_NAME_LABEL:String = "stationListNameLabel"; + public static const CHILD_STYLE_NAME_STATION_LIST_DETAILS_LABEL:String = "stationListDetailsLabel"; + public static const CHILD_STYLE_NAME_STATION_LIST_ACTION_CONTAINER:String = "stationListActionContainer"; + public static const CHILD_STYLE_NAME_STATION_LIST_CONFIRM_BUTTON:String = "stationListConfirmButton"; + public static const CHILD_STYLE_NAME_STATION_LIST_CANCEL_BUTTON:String = "stationListCancelButton"; + + private static const HELPER_POINT:Point = new Point(); + private static const HELPER_TOUCHES_VECTOR:Vector. = new []; + + private static const DEPART_FROM_TEXT:String = "DEPART FROM"; + private static const DEPARTING_FROM_TEXT:String = "DEPARTING FROM"; + private static const TRAVEL_TO_TEXT:String = "TRAVEL TO"; + private static const QUESTION_MARK:String = "?"; + + public static var globalStyleProvider:IStyleProvider; + + protected static function defaultLoaderFactory():ImageLoader + { + return new ImageLoader(); + } + + public function StationListItemRenderer() + { + this.addEventListener(TouchEvent.TOUCH, touchHandler); + } + + override protected function get defaultStyleProvider():IStyleProvider + { + return StationListItemRenderer.globalStyleProvider; + } + + protected var background:Quad; + protected var actionContainer:ScrollContainer; + protected var confirmButton:Button; + protected var cancelButton:Button; + protected var nameLabel:Label; + protected var detailsLabel:Label; + protected var icon:ImageLoader; + + protected var _touchPointID:int = -1; + + protected var _data:StationData; + + public function get data():Object + { + return this._data; + } + + public function set data(value:Object):void + { + if(this._data == value) + { + return; + } + this._data = StationData(value); + this.isSelectionWaitingToBeAnimated = false; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + protected var _index:int = -1; + + public function get index():int + { + return this._index; + } + + public function set index(value:int):void + { + this._index = value; + if(this._owner && this._owner.dataProvider) + { + this.isLastItem = this._index == this._owner.dataProvider.length - 1; + } + this.isFirstItem = this._index == 0; + } + + protected var _isFirstItem:Boolean = false; + + public function get isFirstItem():Boolean + { + return this._isFirstItem; + } + + public function set isFirstItem(value:Boolean):void + { + if(this._isFirstItem == value) + { + return; + } + this._isFirstItem = value; + this.invalidate(INVALIDATION_FLAG_SELECTED); + } + + protected var _isLastItem:Boolean = false; + + public function get isLastItem():Boolean + { + return this._isLastItem; + } + + public function set isLastItem(value:Boolean):void + { + if(this._isLastItem == value) + { + return; + } + this._isLastItem = value; + this.invalidate(INVALIDATION_FLAG_SELECTED); + } + + protected var _isInDestinationPhase:Boolean = false; + + public function get isInDestinationPhase():Boolean + { + return this._isInDestinationPhase; + } + + public function set isInDestinationPhase(value:Boolean):void + { + if(this._isInDestinationPhase == value) + { + return; + } + this._isInDestinationPhase = value; + this.invalidate(INVALIDATION_FLAG_SELECTED); + } + + protected var _owner:List; + + public function get owner():List + { + return this._owner; + } + + public function set owner(value:List):void + { + if(this._owner == value) + { + return; + } + if(this._owner) + { + this._owner.removeEventListener(Event.SCROLL, owner_scrollHandler); + } + this._owner = value; + if(this._owner) + { + this._owner.addEventListener(Event.SCROLL, owner_scrollHandler); + } + if(this._owner && this._owner.dataProvider) + { + this.isLastItem = this._index == this._owner.dataProvider.length - 1; + } + this.invalidate(INVALIDATION_FLAG_DATA); + } + + protected var isSelectionWaitingToBeAnimated:Boolean = false; + + protected var _isSelected:Boolean = false; + + public function get isSelected():Boolean + { + return this._isSelected; + } + + public function set isSelected(value:Boolean):void + { + if(this._isSelected == value) + { + return; + } + this._isSelected = value; + if(this.selectionTween) + { + Starling.juggler.remove(this.selectionTween); + this.selectionTween = null; + } + this.isSelectionWaitingToBeAnimated = !this.isInvalid(INVALIDATION_FLAG_DATA) && !this._data.isDepartingFromHere; + this.invalidate(INVALIDATION_FLAG_SELECTED); + this.dispatchEventWith(Event.CHANGE); + } + + protected var _normalIconTexture:Texture; + + public function get normalIconTexture():Texture + { + return this._normalIconTexture; + } + + public function set normalIconTexture(value:Texture):void + { + if(this._normalIconTexture == value) + { + return; + } + this._normalIconTexture = value; + this.invalidate(INVALIDATION_FLAG_SKIN); + } + + protected var _firstNormalIconTexture:Texture; + + public function get firstNormalIconTexture():Texture + { + return this._firstNormalIconTexture; + } + + public function set firstNormalIconTexture(value:Texture):void + { + if(this._firstNormalIconTexture == value) + { + return; + } + this._firstNormalIconTexture = value; + this.invalidate(INVALIDATION_FLAG_SKIN); + } + + protected var _lastNormalIconTexture:Texture; + + public function get lastNormalIconTexture():Texture + { + return this._lastNormalIconTexture; + } + + public function set lastNormalIconTexture(value:Texture):void + { + if(this._lastNormalIconTexture == value) + { + return; + } + this._lastNormalIconTexture = value; + this.invalidate(INVALIDATION_FLAG_SKIN); + } + + protected var _selectedIconTexture:Texture; + + public function get selectedIconTexture():Texture + { + return this._selectedIconTexture; + } + + public function set selectedIconTexture(value:Texture):void + { + if(this._selectedIconTexture == value) + { + return; + } + this._selectedIconTexture = value; + this.invalidate(INVALIDATION_FLAG_SKIN); + } + + protected var _firstSelectedIconTexture:Texture; + + public function get firstSelectedIconTexture():Texture + { + return this._firstSelectedIconTexture; + } + + public function set firstSelectedIconTexture(value:Texture):void + { + if(this._firstSelectedIconTexture == value) + { + return; + } + this._firstSelectedIconTexture = value; + this.invalidate(INVALIDATION_FLAG_SKIN); + } + + protected var _lastSelectedIconTexture:Texture; + + public function get lastSelectedIconTexture():Texture + { + return this._lastSelectedIconTexture; + } + + public function set lastSelectedIconTexture(value:Texture):void + { + if(this._lastSelectedIconTexture == value) + { + return; + } + this._lastSelectedIconTexture = value; + this.invalidate(INVALIDATION_FLAG_SKIN); + } + + protected var _iconLoaderFactory:Function = defaultLoaderFactory; + + public function get iconLoaderFactory():Function + { + return this._iconLoaderFactory; + } + + public function set iconLoaderFactory(value:Function):void + { + if(this._iconLoaderFactory == value) + { + return; + } + this._iconLoaderFactory = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + protected var _paddingTop:Number = 0; + + public function get paddingTop():Number + { + return this._paddingTop; + } + + public function set paddingTop(value:Number):void + { + if(this._paddingTop == value) + { + return; + } + this._paddingTop = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + protected var _paddingRight:Number = 0; + + public function get paddingRight():Number + { + return this._paddingRight; + } + + public function set paddingRight(value:Number):void + { + if(this._paddingRight == value) + { + return; + } + this._paddingRight = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + protected var _paddingBottom:Number = 0; + + public function get paddingBottom():Number + { + return this._paddingBottom; + } + + public function set paddingBottom(value:Number):void + { + if(this._paddingBottom == value) + { + return; + } + this._paddingBottom = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + protected var _paddingLeft:Number = 0; + + public function get paddingLeft():Number + { + return this._paddingLeft; + } + + public function set paddingLeft(value:Number):void + { + if(this._paddingLeft == value) + { + return; + } + this._paddingLeft = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + protected var _gap:Number = 0; + + public function get gap():Number + { + return this._gap; + } + + public function set gap(value:Number):void + { + if(this._gap == value) + { + return; + } + this._gap = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + public var confirmCallback:Function; + + protected var selectionTween:Tween; + + override protected function initialize():void + { + this.background = new Quad(10, 10, 0x3b2a41); + this.background.alpha = 0; + this.addChild(this.background); + + this.detailsLabel = new Label(); + this.detailsLabel.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_DETAILS_LABEL); + this.addChild(this.detailsLabel); + + this.nameLabel = new Label(); + this.nameLabel.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_NAME_LABEL); + this.addChild(this.nameLabel); + + this.actionContainer = new ScrollContainer(); + this.actionContainer.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_ACTION_CONTAINER); + this.actionContainer.horizontalScrollPolicy = ScrollContainer.SCROLL_POLICY_OFF; + this.actionContainer.verticalScrollPolicy = ScrollContainer.SCROLL_POLICY_OFF; + this.actionContainer.visible = false; + this.addChild(this.actionContainer); + + this.confirmButton = new Button(); + this.confirmButton.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_CONFIRM_BUTTON); + this.confirmButton.addEventListener(Event.TRIGGERED, confirmButton_triggeredHandler); + this.actionContainer.addChild(this.confirmButton); + + this.cancelButton = new Button(); + this.cancelButton.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_CANCEL_BUTTON); + this.cancelButton.addEventListener(Event.TRIGGERED, cancelButton_triggeredHandler); + this.actionContainer.addChild(this.cancelButton); + } + + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + var selectionInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SELECTED); + var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES); + var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE); + + if(stylesInvalid) + { + this.refreshIcon(); + } + + if(dataInvalid || selectionInvalid || stylesInvalid) + { + this.commitData(); + } + + sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid; + + if(dataInvalid || sizeInvalid || selectionInvalid) + { + this.layout(); + } + } + + protected function autoSizeIfNeeded():Boolean + { + var needsWidth:Boolean = isNaN(this.explicitWidth); + var needsHeight:Boolean = isNaN(this.explicitHeight); + if(!needsWidth && !needsHeight) + { + return false; + } + this.icon.validate(); + var newWidth:Number = this.explicitWidth; + if(needsWidth) + { + newWidth = this.icon.width; + newWidth += this._paddingLeft + this._paddingRight; + } + var newHeight:Number = this.explicitHeight; + if(needsHeight) + { + newHeight = this.icon.height; + } + return this.setSizeInternal(newWidth, newHeight, false); + } + + protected function refreshIcon():void + { + if(this.icon) + { + this.icon.removeFromParent(true); + } + + this.icon = ImageLoader(this._iconLoaderFactory()); + this.addChild(this.icon); + } + + protected function commitData():void + { + if(this._owner) + { + var nameLabelText:String = this._data.name; + if(this._isSelected) + { + nameLabelText += QUESTION_MARK; + } + this.nameLabel.text = nameLabelText; + + var displayAsSelected:Boolean = this._isSelected || this._data.isDepartingFromHere; + if(this.isFirstItem) + { + this.icon.source = displayAsSelected ? this._firstSelectedIconTexture : this._firstNormalIconTexture; + } + else if(this.isLastItem) + { + this.icon.source = displayAsSelected ? this._lastSelectedIconTexture : this._lastNormalIconTexture; + } + else + { + this.icon.source = displayAsSelected ? this._selectedIconTexture : this._normalIconTexture; + } + + if(this._data.isDepartingFromHere) + { + this.detailsLabel.text = DEPARTING_FROM_TEXT; + } + else if(this._isInDestinationPhase) + { + this.detailsLabel.text = TRAVEL_TO_TEXT; + } + else + { + this.detailsLabel.text = DEPART_FROM_TEXT; + } + + if(!this.isSelectionWaitingToBeAnimated) + { + this.background.alpha = displayAsSelected ? 1 : 0; + } + if(!this.isSelectionWaitingToBeAnimated || displayAsSelected) + { + this.detailsLabel.visible = displayAsSelected; + } + //the action container will disappear after the departure + //station has been selected, so it has different rules + if(!this._data.isDepartingFromHere && (!this.isSelectionWaitingToBeAnimated || this._isSelected)) + { + this.actionContainer.visible = this._isSelected; + this.actionContainer.alpha = this._isSelected ? 1 : 0; + } + } + else + { + this.nameLabel.text = null; + this.detailsLabel.text = null; + this.actionContainer.visible = false; + this.background.alpha = 0; + this.icon.source = null; + } + } + + protected function layout():void + { + this.background.width = this.actualWidth; + this.background.height = this.actualHeight; + + this.icon.validate(); + this.icon.x = this._paddingLeft; + var leftMarginWidth:Number = this._paddingLeft + this.icon.width + this._gap; + var availableLabelWidth:Number = this.actualWidth - this._paddingRight - leftMarginWidth; + var availableLabelHeight:Number = this.actualHeight - this._paddingTop - this._paddingBottom; + + this.actionContainer.width = availableLabelWidth; + + this.nameLabel.validate(); + this.detailsLabel.validate(); + this.actionContainer.validate(); + + var displayAsSelected:Boolean = this._isSelected || this._data.isDepartingFromHere; + if((displayAsSelected && this.isSelectionWaitingToBeAnimated) || + (!displayAsSelected && !this.isSelectionWaitingToBeAnimated)) + { + this.actionContainer.x = this.actualWidth; + this.detailsLabel.alpha = 0; + this.nameLabel.x = leftMarginWidth; + } + else + { + this.actionContainer.x = this.actualWidth - this.actionContainer.width; + this.detailsLabel.alpha = 1; + this.nameLabel.x = leftMarginWidth + (availableLabelWidth - this.nameLabel.width) / 2; + } + if(this.isSelectionWaitingToBeAnimated) + { + this.isSelectionWaitingToBeAnimated = false; + this.selectionTween = new Tween(this.nameLabel, 0.35, Transitions.EASE_OUT); + if(displayAsSelected) + { + this.selectionTween.animate("x", leftMarginWidth + (availableLabelWidth - this.nameLabel.width) / 2); + this.selectionTween.onComplete = selectionTween_onSelectComplete; + } + else + { + this.selectionTween.animate("x", leftMarginWidth); + this.selectionTween.onComplete = selectionTween_onDeselectComplete; + } + this.selectionTween.onUpdate = selectionTween_onUpdate; + Starling.juggler.add(this.selectionTween); + } + else if(this._data.isDepartingFromHere && this.actionContainer.visible) + { + this.selectionTween = new Tween(this.actionContainer, 0.35, Transitions.EASE_OUT); + this.selectionTween.fadeTo(0); + this.selectionTween.onComplete = selectionTween_onConfirmComplete; + Starling.juggler.add(this.selectionTween); + } + + this.nameLabel.y = (availableLabelHeight - this.nameLabel.height) / 2; + this.detailsLabel.x = leftMarginWidth + (availableLabelWidth - this.detailsLabel.width) / 2; + this.detailsLabel.y = this.nameLabel.y - this.detailsLabel.height + this.detailsLabel.height - this.detailsLabel.baseline; + this.actionContainer.y = this.actualHeight - this.actionContainer.height; + } + + protected function selectionTween_onUpdate():void + { + var ratio:Number = this.selectionTween.transitionFunc(this.selectionTween.currentTime / this.selectionTween.totalTime); + if(!this._isSelected) + { + ratio = 1 - ratio; + } + this.detailsLabel.alpha = this.background.alpha = ratio; + this.actionContainer.x = this.actualWidth - this.actionContainer.width * ratio; + } + + protected function selectionTween_onSelectComplete():void + { + this.selectionTween = null; + } + + protected function selectionTween_onDeselectComplete():void + { + this.detailsLabel.visible = false; + this.actionContainer.visible = false; + this.selectionTween = null; + } + + protected function selectionTween_onConfirmComplete():void + { + this.actionContainer.visible = false; + this.selectionTween = null; + } + + protected function selectionTween_onUnconfirmComplete():void + { + this.selectionTween = null; + } + + protected function touchHandler(event:TouchEvent):void + { + if(!this._isEnabled) + { + return; + } + + var touches:Vector. = event.getTouches(this, null, HELPER_TOUCHES_VECTOR); + if(touches.length == 0) + { + //end of hover + return; + } + if(this._touchPointID >= 0) + { + var touch:Touch; + for each(var currentTouch:Touch in touches) + { + if(currentTouch.id == this._touchPointID) + { + touch = currentTouch; + break; + } + } + + if(!touch) + { + //end of hover + HELPER_TOUCHES_VECTOR.length = 0; + return; + } + + if(touch.phase == TouchPhase.ENDED) + { + this._touchPointID = -1; + touch.getLocation(this, HELPER_POINT); + var isInBounds:Boolean = this.hitTest(HELPER_POINT, true) != null; + if(isInBounds) + { + if(!this._isSelected && !this._data.isDepartingFromHere) + { + this.isSelected = true; + } + } + } + } + else //if we get here, we don't have a saved touch ID yet + { + for each(touch in touches) + { + if(touch.phase == TouchPhase.BEGAN) + { + this._touchPointID = touch.id; + break; + } + } + } + HELPER_TOUCHES_VECTOR.length = 0; + } + + protected function owner_scrollHandler(event:Event):void + { + this._touchPointID = -1; + } + + protected function confirmButton_triggeredHandler(event:Event):void + { + if(this.confirmCallback == null) + { + return; + } + this.confirmCallback(); + } + + protected function cancelButton_triggeredHandler(event:Event):void + { + this._owner.selectedIndex = -1; + } + } +} diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/model/StationData.as b/examples/TrainTimes/source/feathers/examples/trainTimes/model/StationData.as new file mode 100644 index 0000000000..bed1ace381 --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/model/StationData.as @@ -0,0 +1,13 @@ +package feathers.examples.trainTimes.model +{ + public class StationData + { + public function StationData(name:String) + { + this.name = name; + } + + public var name:String; + public var isDepartingFromHere:Boolean = false; + } +} diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/model/TimeData.as b/examples/TrainTimes/source/feathers/examples/trainTimes/model/TimeData.as new file mode 100644 index 0000000000..9769dc04e1 --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/model/TimeData.as @@ -0,0 +1,16 @@ +package feathers.examples.trainTimes.model +{ + public class TimeData + { + public function TimeData(trainNumber:int, departureTime:Date, arrivalTime:Date) + { + this.trainNumber = trainNumber; + this.departureTime = departureTime; + this.arrivalTime = arrivalTime; + } + + public var trainNumber:int; + public var departureTime:Date; + public var arrivalTime:Date; + } +} diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/screens/StationScreen.as b/examples/TrainTimes/source/feathers/examples/trainTimes/screens/StationScreen.as new file mode 100644 index 0000000000..55b1b4cb9f --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/screens/StationScreen.as @@ -0,0 +1,200 @@ +package feathers.examples.trainTimes.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.Screen; + import feathers.data.ListCollection; + import feathers.examples.trainTimes.model.StationData; + + import flash.events.KeyboardEvent; + import flash.ui.Keyboard; + + import starling.animation.Transitions; + import starling.animation.Tween; + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class StationScreen extends Screen + { + public static const CHILD_STYLE_NAME_STATION_LIST:String = "stationList"; + + public function StationScreen() + { + this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); + this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); + } + + public var selectedDepartureStation:StationData; + public var selectedDestinationStation:StationData; + + private var _departureHeader:Header; + private var _destinationHeader:Header; + private var _backButton:Button; + private var _stationList:List; + + private var _headerTween:Tween; + + override protected function initialize():void + { + this._stationList = new List(); + this._stationList.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST); + this._stationList.dataProvider = new ListCollection( + [ + new StationData("Ten Stone Road"), + new StationData("Birch Grove"), + new StationData("East Elm Court"), + new StationData("Oakheart Hills"), + new StationData("Timber Ridge"), + new StationData("Old Mine Heights"), + new StationData("Granite Estates"), + ]) + this._stationList.itemRendererProperties.confirmCallback = stationList_onConfirm; + this._stationList.itemRendererProperties.isInDestinationPhase = false; + this.addChild(this._stationList); + + this._backButton = new Button(); + this._backButton.visible = false; + this._backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + + this._departureHeader = new Header(); + this._departureHeader.title = "Choose Departure Station"; + this.addChild(this._departureHeader); + + this._destinationHeader = new Header(); + this._destinationHeader.title = "Choose Destination Station"; + this._destinationHeader.leftItems = new + [ + this._backButton + ]; + this.addChild(this._destinationHeader); + } + + override protected function draw():void + { + this._departureHeader.width = this.actualWidth; + this._destinationHeader.width = this.actualWidth; + + var currentHeader:Header; + if(this.selectedDepartureStation) + { + currentHeader = this._destinationHeader; + this._destinationHeader.x = 0; + this._destinationHeader.visible = true; + this._departureHeader.x = this.actualWidth; + this._departureHeader.visible = false; + } + else + { + currentHeader = this._departureHeader; + this._destinationHeader.x = -this.actualWidth; + this._destinationHeader.visible = false; + this._departureHeader.x = 0; + this._departureHeader.visible = true; + } + + currentHeader.validate(); + this._stationList.y = currentHeader.height; + this._stationList.width = this.actualWidth; + this._stationList.height = this.actualHeight - this._stationList.y; + } + + private function onBackButton():void + { + this.selectedDepartureStation.isDepartingFromHere = false; + var index:int = this._stationList.dataProvider.getItemIndex(this.selectedDepartureStation); + this._stationList.dataProvider.updateItemAt(index); + this._stationList.selectedItem = this.selectedDepartureStation; + this.selectedDepartureStation = null; + this._backButton.visible = false; + this._departureHeader.title = "Choose Departure Station"; + this._stationList.itemRendererProperties.isInDestinationPhase = false; + + this._departureHeader.visible = true; + if(this._headerTween) + { + Starling.juggler.remove(this._headerTween); + this._headerTween = null; + } + this._headerTween = new Tween(this._departureHeader, 0.4, Transitions.EASE_OUT); + this._headerTween.animate("x", 0); + this._headerTween.onUpdate = headerTween_onUpdate; + this._headerTween.onComplete = headerTween_onDestinationHideComplete; + Starling.juggler.add(this._headerTween); + } + + private function stationList_onConfirm():void + { + if(this.selectedDepartureStation) + { + this.selectedDestinationStation = StationData(this._stationList.selectedItem); + this.dispatchEventWith(Event.COMPLETE); + return; + } + this.selectedDepartureStation = StationData(this._stationList.selectedItem); + this.selectedDepartureStation.isDepartingFromHere = true; + + this._departureHeader.title = "Choose Destination Station"; + this._backButton.visible = true; + + this._stationList.selectedIndex = -1; + this._stationList.itemRendererProperties.isInDestinationPhase = true; + + this._destinationHeader.visible = true; + if(this._headerTween) + { + Starling.juggler.remove(this._headerTween); + this._headerTween = null; + } + this._headerTween = new Tween(this._departureHeader, 0.4, Transitions.EASE_OUT); + this._headerTween.animate("x", this.actualWidth); + this._headerTween.onUpdate = headerTween_onUpdate; + this._headerTween.onComplete = headerTween_onDestinationShowComplete; + Starling.juggler.add(this._headerTween); + } + + private function headerTween_onUpdate():void + { + this._destinationHeader.x = this._departureHeader.x - this.actualWidth; + } + + private function headerTween_onDestinationShowComplete():void + { + this._departureHeader.visible = false; + this._headerTween = null; + } + + private function headerTween_onDestinationHideComplete():void + { + this._destinationHeader.visible = false; + this._headerTween = null; + } + + private function addedToStageHandler(event:Event):void + { + Starling.current.nativeStage.addEventListener(KeyboardEvent.KEY_DOWN, nativeStage_keyDownHandler, false, 0, true); + } + + private function removedFromStageHandler(event:Event):void + { + Starling.current.nativeStage.removeEventListener(KeyboardEvent.KEY_DOWN, nativeStage_keyDownHandler); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + + private function nativeStage_keyDownHandler(event:KeyboardEvent):void + { + if(event.keyCode == Keyboard.BACK && this.selectedDepartureStation) + { + event.preventDefault(); + this.onBackButton(); + } + } + } +} diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/screens/TimesScreen.as b/examples/TrainTimes/source/feathers/examples/trainTimes/screens/TimesScreen.as new file mode 100644 index 0000000000..3c8738c9ef --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/screens/TimesScreen.as @@ -0,0 +1,109 @@ +package feathers.examples.trainTimes.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.data.ListCollection; + import feathers.examples.trainTimes.model.TimeData; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class TimesScreen extends PanelScreen + { + public static const CHILD_STYLE_NAME_TIMES_LIST:String = "timesList"; + + private static const NORTH_TIMES:Vector. = new + [ + new TimeData(281, new Date(2013, 2, 6, 13, 5), new Date(2013, 2, 6, 13, 19)), + new TimeData(281, new Date(2013, 2, 6, 14, 5), new Date(2013, 2, 6, 14, 19)), + new TimeData(281, new Date(2013, 2, 6, 15, 5), new Date(2013, 2, 6, 15, 19)), + new TimeData(281, new Date(2013, 2, 6, 16, 5), new Date(2013, 2, 6, 16, 19)), + new TimeData(281, new Date(2013, 2, 6, 17, 5), new Date(2013, 2, 6, 17, 21)), + new TimeData(281, new Date(2013, 2, 6, 17, 35), new Date(2013, 2, 6, 17, 51)), + new TimeData(281, new Date(2013, 2, 6, 18, 5), new Date(2013, 2, 6, 18, 21)), + new TimeData(281, new Date(2013, 2, 6, 18, 35), new Date(2013, 2, 6, 18, 51)), + new TimeData(281, new Date(2013, 2, 6, 19, 5), new Date(2013, 2, 6, 19, 21)), + new TimeData(281, new Date(2013, 2, 6, 20, 1), new Date(2013, 2, 6, 20, 12)), + new TimeData(281, new Date(2013, 2, 6, 20, 41), new Date(2013, 2, 6, 20, 52)), + new TimeData(281, new Date(2013, 2, 6, 21, 41), new Date(2013, 2, 6, 21, 52)), + new TimeData(281, new Date(2013, 2, 6, 22, 41), new Date(2013, 2, 6, 22, 52)), + new TimeData(281, new Date(2013, 2, 6, 23, 41), new Date(2013, 2, 6, 23, 52)), + ]; + + public function TimesScreen() + { + super(); + } + + private var _backButton:Button; + private var _list:List; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Schedule"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.styleNameList.add(CHILD_STYLE_NAME_TIMES_LIST); + this._list.dataProvider = new ListCollection(NORTH_TIMES); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.itemRendererProperties.labelFunction = list_labelFunction; + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = this.onBackButton; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + this._backButton = new Button(); + this._backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new + [ + this._backButton + ]; + return header; + } + + private function list_labelFunction(item:TimeData):String + { + var departureTime:Date = item.departureTime; + var arrivalTime:Date = item.arrivalTime; + var duration:int = (arrivalTime.getTime() - departureTime.getTime()) / 1000 / 60; + return this.formatTimeAsString(departureTime) + "\t" + this.formatTimeAsString(arrivalTime) + "\t" + + item.trainNumber + "\t" + duration + "mins"; + } + + private function formatTimeAsString(time:Date):String + { + var hours:Number = time.hours; + var isAM:Boolean = hours < 12; + var hoursAsString:String = ((isAM ? hours : (hours - 12)) + 1).toString(); + var minutes:Number = time.minutes; + var minutesAsString:String = minutes < 10 ? "0" + minutes : minutes.toString(); + return hoursAsString + ":" + minutesAsString + (isAM ? "am" : "pm"); + } + + private function onBackButton():void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.onBackButton(); + } + } +} diff --git a/examples/TrainTimes/source/feathers/examples/trainTimes/themes/TrainTimesTheme.as b/examples/TrainTimes/source/feathers/examples/trainTimes/themes/TrainTimesTheme.as new file mode 100644 index 0000000000..f48603b2d5 --- /dev/null +++ b/examples/TrainTimes/source/feathers/examples/trainTimes/themes/TrainTimesTheme.as @@ -0,0 +1,398 @@ +package feathers.examples.trainTimes.themes +{ + import feathers.controls.Button; + import feathers.controls.Callout; + import feathers.controls.Header; + import feathers.controls.ImageLoader; + import feathers.controls.Label; + import feathers.controls.List; + import feathers.controls.ScrollContainer; + import feathers.controls.SimpleScrollBar; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.text.StageTextTextEditor; + import feathers.controls.text.TextFieldTextRenderer; + import feathers.core.FeathersControl; + import feathers.core.ITextEditor; + import feathers.core.ITextRenderer; + import feathers.core.PopUpManager; + import feathers.display.Scale3Image; + import feathers.display.Scale9Image; + import feathers.display.TiledImage; + import feathers.examples.trainTimes.controls.StationListItemRenderer; + import feathers.examples.trainTimes.screens.StationScreen; + import feathers.examples.trainTimes.screens.TimesScreen; + import feathers.layout.HorizontalLayout; + import feathers.system.DeviceCapabilities; + import feathers.textures.Scale3Textures; + import feathers.textures.Scale9Textures; + import feathers.themes.StyleNameFunctionTheme; + + import flash.display.BitmapData; + import flash.geom.Rectangle; + import flash.text.TextFormat; + + import starling.core.Starling; + import starling.display.DisplayObject; + import starling.display.Quad; + import starling.events.ResizeEvent; + import starling.textures.Texture; + import starling.textures.TextureAtlas; + + public class TrainTimesTheme extends StyleNameFunctionTheme + { + [Embed(source="/../assets/images/traintimes.png")] + protected static const ATLAS_IMAGE:Class; + + [Embed(source="/../assets/images/traintimes.xml",mimeType="application/octet-stream")] + protected static const ATLAS_XML:Class; + + [Embed(source="/../assets/fonts/SourceSansPro-Regular.ttf",fontName="SourceSansPro",mimeType="application/x-font",embedAsCFF="false")] + protected static const SOURCE_SANS_PRO_REGULAR:Class; + + [Embed(source="/../assets/fonts/SourceSansPro-Bold.ttf",fontName="SourceSansProBold",fontWeight="bold",mimeType="application/x-font",embedAsCFF="false")] + protected static const SOURCE_SANS_PRO_BOLD:Class; + + [Embed(source="/../assets/fonts/SourceSansPro-BoldIt.ttf",fontName="SourceSansProBoldItalic",fontWeight="bold",fontStyle="italic",mimeType="application/x-font",embedAsCFF="false")] + protected static const SOURCE_SANS_PRO_BOLD_ITALIC:Class; + + protected static const TIMES_LIST_ITEM_RENDERER_NAME:String = "traintimes-times-list-item-renderer"; + + protected static const ORIGINAL_DPI_IPHONE_RETINA:int = 326; + protected static const ORIGINAL_DPI_IPAD_RETINA:int = 264; + + protected static const HEADER_SCALE9_GRID:Rectangle = new Rectangle(0, 0, 4, 5); + protected static const SCROLL_BAR_THUMB_REGION1:int = 5; + protected static const SCROLL_BAR_THUMB_REGION2:int = 14; + + protected static const PRIMARY_TEXT_COLOR:uint = 0xe8caa4; + protected static const DETAIL_TEXT_COLOR:uint = 0x64908a; + + protected static function textRendererFactory():ITextRenderer + { + var renderer:TextFieldTextRenderer = new TextFieldTextRenderer(); + renderer.embedFonts = true; + return renderer; + } + + protected static function textEditorFactory():ITextEditor + { + return new StageTextTextEditor(); + } + + protected static function popUpOverlayFactory():DisplayObject + { + var quad:Quad = new Quad(100, 100, 0x1a1a1a); + quad.alpha = 0.85; + return quad; + } + + public function TrainTimesTheme() + { + super(); + this.initialize(); + } + + protected var scale:Number = 1; + + protected var primaryBackground:TiledImage; + + protected var defaultTextFormat:TextFormat; + protected var selectedTextFormat:TextFormat; + protected var headerTitleTextFormat:TextFormat; + protected var stationListNameTextFormat:TextFormat; + protected var stationListDetailTextFormat:TextFormat; + + protected var atlas:TextureAtlas; + protected var atlasBitmapData:BitmapData; + protected var mainBackgroundTexture:Texture; + protected var headerBackgroundTextures:Scale9Textures; + protected var stationListNormalIconTexture:Texture; + protected var stationListFirstNormalIconTexture:Texture; + protected var stationListLastNormalIconTexture:Texture; + protected var stationListSelectedIconTexture:Texture; + protected var stationListFirstSelectedIconTexture:Texture; + protected var stationListLastSelectedIconTexture:Texture; + protected var confirmIconTexture:Texture; + protected var cancelIconTexture:Texture; + protected var backIconTexture:Texture; + protected var horizontalScrollBarThumbSkinTextures:Scale3Textures; + protected var verticalScrollBarThumbSkinTextures:Scale3Textures; + + override public function dispose():void + { + if(this.primaryBackground) + { + Starling.current.stage.removeEventListener(ResizeEvent.RESIZE, stage_resizeHandler); + Starling.current.stage.removeChild(this.primaryBackground, true); + this.primaryBackground = null; + } + if(this.atlas) + { + this.atlas.dispose(); + this.atlas = null; + } + if(this.atlasBitmapData) + { + this.atlasBitmapData.dispose(); + this.atlasBitmapData = null; + } + super.dispose(); + } + + protected function initialize():void + { + this.initializeScale(); + this.initializeGlobals(); + this.initializeTextures(); + this.initializeStage(); + this.initializeStyleProviders(); + } + + protected function initializeStage():void + { + this.primaryBackground = new TiledImage(this.mainBackgroundTexture); + this.primaryBackground.width = Starling.current.stage.stageWidth; + this.primaryBackground.height = Starling.current.stage.stageHeight; + Starling.current.stage.addChildAt(this.primaryBackground, 0); + Starling.current.stage.addEventListener(ResizeEvent.RESIZE, stage_resizeHandler); + } + + protected function initializeScale():void + { + var scaledDPI:int = DeviceCapabilities.dpi / Starling.contentScaleFactor; + if(DeviceCapabilities.isTablet(Starling.current.nativeStage)) + { + var originalDPI:int = ORIGINAL_DPI_IPAD_RETINA; + } + else + { + originalDPI = ORIGINAL_DPI_IPHONE_RETINA; + } + + this.scale = scaledDPI / originalDPI; + } + + protected function initializeGlobals():void + { + FeathersControl.defaultTextRendererFactory = textRendererFactory; + FeathersControl.defaultTextEditorFactory = textEditorFactory; + + PopUpManager.overlayFactory = popUpOverlayFactory; + Callout.stagePaddingTop = Callout.stagePaddingRight = Callout.stagePaddingBottom = + Callout.stagePaddingLeft = 16 * this.scale; + } + + protected function initializeTextures():void + { + var atlasBitmapData:BitmapData = (new ATLAS_IMAGE()).bitmapData; + this.atlas = new TextureAtlas(Texture.fromBitmapData(atlasBitmapData, false), XML(new ATLAS_XML())); + if(Starling.handleLostContext) + { + this.atlasBitmapData = atlasBitmapData; + } + else + { + atlasBitmapData.dispose(); + } + + this.mainBackgroundTexture = this.atlas.getTexture("main-background"); + this.headerBackgroundTextures = new Scale9Textures(this.atlas.getTexture("header-background"), HEADER_SCALE9_GRID); + this.stationListNormalIconTexture = this.atlas.getTexture("station-list-normal-icon"); + this.stationListFirstNormalIconTexture = this.atlas.getTexture("station-list-first-normal-icon"); + this.stationListLastNormalIconTexture = this.atlas.getTexture("station-list-last-normal-icon"); + this.stationListSelectedIconTexture = this.atlas.getTexture("station-list-selected-icon"); + this.stationListFirstSelectedIconTexture = this.atlas.getTexture("station-list-first-selected-icon"); + this.stationListLastSelectedIconTexture = this.atlas.getTexture("station-list-last-selected-icon"); + this.confirmIconTexture = this.atlas.getTexture("confirm-icon"); + this.cancelIconTexture = this.atlas.getTexture("cancel-icon"); + this.backIconTexture = this.atlas.getTexture("back-icon"); + this.horizontalScrollBarThumbSkinTextures = new Scale3Textures(this.atlas.getTexture("horizontal-scroll-bar-thumb-skin"), SCROLL_BAR_THUMB_REGION1, SCROLL_BAR_THUMB_REGION2, Scale3Textures.DIRECTION_HORIZONTAL); + this.verticalScrollBarThumbSkinTextures = new Scale3Textures(this.atlas.getTexture("vertical-scroll-bar-thumb-skin"), SCROLL_BAR_THUMB_REGION1, SCROLL_BAR_THUMB_REGION2, Scale3Textures.DIRECTION_VERTICAL); + + //we need to use different font names because Flash runtimes seem to + //have a bug where setting defaultTextFormat on a TextField with a + //different TextFormat that has the same font name as the existing + //defaultTextFormat value causes the new TextFormat to be ignored, + //even if the new TextFormat has different bold or italic values. + //wtf, right? + var regularFontName:String = "SourceSansPro"; + var boldFontName:String = "SourceSansProBold"; + var boldItalicFontName:String = "SourceSansProBoldItalic"; + this.defaultTextFormat = new TextFormat(regularFontName, Math.round(36 * this.scale), PRIMARY_TEXT_COLOR); + this.selectedTextFormat = new TextFormat(boldFontName, Math.round(36 * this.scale), PRIMARY_TEXT_COLOR, true); + this.headerTitleTextFormat = new TextFormat(regularFontName, Math.round(36 * this.scale), PRIMARY_TEXT_COLOR); + this.stationListNameTextFormat = new TextFormat(boldItalicFontName, Math.round(48 * this.scale), PRIMARY_TEXT_COLOR, true, true); + this.stationListDetailTextFormat = new TextFormat(boldFontName, Math.round(24 * this.scale), DETAIL_TEXT_COLOR, true); + this.stationListDetailTextFormat.letterSpacing = 6 * this.scale; + } + + protected function initializeStyleProviders():void + { + this.getStyleProviderForClass(Button).defaultStyleFunction = setButtonStyles; + this.getStyleProviderForClass(Button).setFunctionForStyleName(StationListItemRenderer.CHILD_STYLE_NAME_STATION_LIST_CONFIRM_BUTTON, setConfirmButtonStyles); + this.getStyleProviderForClass(Button).setFunctionForStyleName(StationListItemRenderer.CHILD_STYLE_NAME_STATION_LIST_CANCEL_BUTTON, setCancelButtonStyles); + this.getStyleProviderForClass(Button).setFunctionForStyleName(SimpleScrollBar.DEFAULT_CHILD_STYLE_NAME_THUMB, setNoStyles); + this.getStyleProviderForClass(Label).defaultStyleFunction = setLabelStyles; + this.getStyleProviderForClass(Label).setFunctionForStyleName(StationListItemRenderer.CHILD_STYLE_NAME_STATION_LIST_NAME_LABEL, setStationListNameLabelStyles); + this.getStyleProviderForClass(Label).setFunctionForStyleName(StationListItemRenderer.CHILD_STYLE_NAME_STATION_LIST_DETAILS_LABEL, setStationListDetailLabelStyles); + this.getStyleProviderForClass(Header).defaultStyleFunction = setHeaderStyles; + this.getStyleProviderForClass(List).setFunctionForStyleName(StationScreen.CHILD_STYLE_NAME_STATION_LIST, setStationListStyles); + this.getStyleProviderForClass(List).setFunctionForStyleName(TimesScreen.CHILD_STYLE_NAME_TIMES_LIST, setTimesListStyles); + this.getStyleProviderForClass(DefaultListItemRenderer).setFunctionForStyleName(TIMES_LIST_ITEM_RENDERER_NAME, setTimesListItemRendererStyles); + this.getStyleProviderForClass(StationListItemRenderer).defaultStyleFunction = setStationListItemRendererStyles; + this.getStyleProviderForClass(ScrollContainer).setFunctionForStyleName(StationListItemRenderer.CHILD_STYLE_NAME_STATION_LIST_ACTION_CONTAINER, setActionContainerStyles); + } + + protected function imageLoaderFactory():ImageLoader + { + var image:ImageLoader = new ImageLoader(); + image.textureScale = this.scale; + return image; + } + + protected function horizontalScrollBarFactory():SimpleScrollBar + { + var scrollBar:SimpleScrollBar = new SimpleScrollBar(); + scrollBar.direction = SimpleScrollBar.DIRECTION_HORIZONTAL; + var defaultSkin:Scale3Image = new Scale3Image(this.horizontalScrollBarThumbSkinTextures, this.scale); + defaultSkin.width = 10 * this.scale; + scrollBar.thumbProperties.defaultSkin = defaultSkin; + scrollBar.paddingRight = scrollBar.paddingBottom = scrollBar.paddingLeft = 4 * this.scale; + return scrollBar; + } + + protected function verticalScrollBarFactory():SimpleScrollBar + { + var scrollBar:SimpleScrollBar = new SimpleScrollBar(); + scrollBar.direction = SimpleScrollBar.DIRECTION_VERTICAL; + var defaultSkin:Scale3Image = new Scale3Image(this.verticalScrollBarThumbSkinTextures, this.scale); + defaultSkin.height = 10 * this.scale; + scrollBar.thumbProperties.defaultSkin = defaultSkin; + scrollBar.paddingTop = scrollBar.paddingRight = scrollBar.paddingBottom = 4 * this.scale; + return scrollBar; + } + + protected function setNoStyles(target:DisplayObject):void {} + + protected function setLabelStyles(label:Label):void + { + label.textRendererProperties.textFormat = this.defaultTextFormat; + } + + protected function setStationListNameLabelStyles(label:Label):void + { + label.textRendererProperties.textFormat = this.stationListNameTextFormat; + } + + protected function setStationListDetailLabelStyles(label:Label):void + { + label.textRendererProperties.textFormat = this.stationListDetailTextFormat; + } + + protected function setButtonStyles(button:Button):void + { + var defaultIcon:ImageLoader = new ImageLoader(); + defaultIcon.source = this.backIconTexture; + defaultIcon.textureScale = this.scale; + defaultIcon.snapToPixels = true; + button.defaultIcon = defaultIcon; + button.minWidth = button.minHeight = 44 * this.scale; + button.minTouchWidth = button.minTouchHeight = 88 * this.scale; + } + + protected function setConfirmButtonStyles(button:Button):void + { + var defaultIcon:ImageLoader = new ImageLoader(); + defaultIcon.source = this.confirmIconTexture; + defaultIcon.textureScale = this.scale; + defaultIcon.snapToPixels = true; + button.defaultIcon = defaultIcon; + button.minWidth = button.minHeight = 44 * this.scale; + button.minTouchWidth = button.minTouchHeight = 88 * this.scale; + } + + protected function setCancelButtonStyles(button:Button):void + { + var defaultIcon:ImageLoader = new ImageLoader(); + defaultIcon.source = this.cancelIconTexture; + defaultIcon.textureScale = this.scale; + defaultIcon.snapToPixels = true; + button.defaultIcon = defaultIcon; + button.minWidth = button.minHeight = 44 * this.scale; + button.minTouchWidth = button.minTouchHeight = 88 * this.scale; + } + + protected function setHeaderStyles(header:Header):void + { + header.minWidth = 88 * this.scale; + header.minHeight = 88 * this.scale; + header.paddingTop = header.paddingRight = header.paddingBottom = + header.paddingLeft = 14 * this.scale; + header.titleAlign = Header.TITLE_ALIGN_PREFER_RIGHT; + + var backgroundSkin:Scale9Image = new Scale9Image(this.headerBackgroundTextures, this.scale); + header.backgroundSkin = backgroundSkin; + header.titleProperties.textFormat = this.headerTitleTextFormat; + } + + protected function setStationListStyles(list:List):void + { + list.horizontalScrollBarFactory = this.horizontalScrollBarFactory; + list.verticalScrollBarFactory = this.verticalScrollBarFactory; + + list.itemRendererType = StationListItemRenderer; + } + + protected function setTimesListStyles(list:List):void + { + list.horizontalScrollBarFactory = this.horizontalScrollBarFactory; + list.verticalScrollBarFactory = this.verticalScrollBarFactory; + list.itemRendererName = TIMES_LIST_ITEM_RENDERER_NAME; + } + + protected function setTimesListItemRendererStyles(renderer:DefaultListItemRenderer):void + { + var defaultSkin:Quad = new Quad(88 * this.scale, 88 * this.scale, 0xff00ff); + defaultSkin.alpha = 0; + renderer.defaultSkin = defaultSkin; + var defaultSelectedSkin:Quad = new Quad(88 * this.scale, 88 * this.scale, 0xcc2a41); + renderer.defaultSelectedSkin = defaultSelectedSkin; + renderer.defaultLabelProperties.textFormat = this.defaultTextFormat; + renderer.defaultSelectedLabelProperties.textFormat = this.selectedTextFormat; + renderer.paddingLeft = 8 * this.scale; + renderer.paddingRight = 16 * this.scale; + } + + protected function setStationListItemRendererStyles(renderer:StationListItemRenderer):void + { + renderer.paddingLeft = 44 * this.scale; + renderer.paddingRight = 32 * this.scale + renderer.iconLoaderFactory = imageLoaderFactory; + renderer.normalIconTexture = this.stationListNormalIconTexture; + renderer.firstNormalIconTexture = this.stationListFirstNormalIconTexture; + renderer.lastNormalIconTexture = this.stationListLastNormalIconTexture; + renderer.selectedIconTexture = this.stationListSelectedIconTexture; + renderer.firstSelectedIconTexture = this.stationListFirstSelectedIconTexture; + renderer.lastSelectedIconTexture = this.stationListLastSelectedIconTexture; + } + + protected function setActionContainerStyles(container:ScrollContainer):void + { + var backgroundSkin:Quad = new Quad(48 * this.scale, 48 * this.scale, 0xcc2a41); + container.backgroundSkin = backgroundSkin; + + var layout:HorizontalLayout = new HorizontalLayout(); + layout.paddingRight = 32 * this.scale; + layout.gap = 48 * this.scale; + layout.horizontalAlign = HorizontalLayout.HORIZONTAL_ALIGN_CENTER; + layout.verticalAlign = HorizontalLayout.VERTICAL_ALIGN_MIDDLE; + container.layout = layout; + } + + protected function stage_resizeHandler(event:ResizeEvent):void + { + this.primaryBackground.width = event.width; + this.primaryBackground.height = event.height; + } + } +} diff --git a/examples/TransitionsExplorer/README.md b/examples/TransitionsExplorer/README.md new file mode 100644 index 0000000000..f688f48674 --- /dev/null +++ b/examples/TransitionsExplorer/README.md @@ -0,0 +1,13 @@ +# Feathers Components Explorer + +A little bit of everything in [Feathers](http://feathersui.com/), presented as a mobile app. Includes screens for each component, with configurable options. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [Components Explorer](http://feathersui.com/examples/components-explorer/) in your browser. \ No newline at end of file diff --git a/examples/TransitionsExplorer/assets/images/test-pattern1.png b/examples/TransitionsExplorer/assets/images/test-pattern1.png new file mode 100644 index 0000000000..55755d7461 Binary files /dev/null and b/examples/TransitionsExplorer/assets/images/test-pattern1.png differ diff --git a/examples/TransitionsExplorer/assets/images/test-pattern2.png b/examples/TransitionsExplorer/assets/images/test-pattern2.png new file mode 100644 index 0000000000..ebca03e655 Binary files /dev/null and b/examples/TransitionsExplorer/assets/images/test-pattern2.png differ diff --git a/examples/TransitionsExplorer/build.properties b/examples/TransitionsExplorer/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/TransitionsExplorer/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/TransitionsExplorer/build.xml b/examples/TransitionsExplorer/build.xml new file mode 100644 index 0000000000..8349d75e86 --- /dev/null +++ b/examples/TransitionsExplorer/build.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/TransitionsExplorer/sdk.properties b/examples/TransitionsExplorer/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/TransitionsExplorer/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/TransitionsExplorer/source/TransitionsExplorer-app.xml b/examples/TransitionsExplorer/source/TransitionsExplorer-app.xml new file mode 100644 index 0000000000..129a92ce72 --- /dev/null +++ b/examples/TransitionsExplorer/source/TransitionsExplorer-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.TransitionsExplorer + Feathers Transitions + Transitions + 2.0.1 + Transitions Explorer example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + TransitionsExplorer.swf + landscape + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/TransitionsExplorer/source/TransitionsExplorer.as b/examples/TransitionsExplorer/source/TransitionsExplorer.as new file mode 100644 index 0000000000..853d483d16 --- /dev/null +++ b/examples/TransitionsExplorer/source/TransitionsExplorer.as @@ -0,0 +1,155 @@ +package +{ + import feathers.examples.transitionsExplorer.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class TransitionsExplorer extends Sprite + { + public function TransitionsExplorer() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/TransitionsExplorer/source/TransitionsExplorerWeb.as b/examples/TransitionsExplorer/source/TransitionsExplorerWeb.as new file mode 100644 index 0000000000..dd784520c2 --- /dev/null +++ b/examples/TransitionsExplorer/source/TransitionsExplorerWeb.as @@ -0,0 +1,59 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class TransitionsExplorerWeb extends MovieClip + { + public function TransitionsExplorerWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.transitionsExplorer.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/Main.as b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/Main.as new file mode 100644 index 0000000000..d814ae559f --- /dev/null +++ b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/Main.as @@ -0,0 +1,190 @@ +package feathers.examples.transitionsExplorer +{ + import feathers.controls.ImageLoader; + import feathers.controls.LayoutGroup; + import feathers.controls.ScreenNavigator; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.StackScreenNavigator; + import feathers.controls.StackScreenNavigatorItem; + import feathers.examples.transitionsExplorer.screens.AllTransitionsScreen; + import feathers.examples.transitionsExplorer.screens.ColorFadeTransitionScreen; + import feathers.examples.transitionsExplorer.screens.FadeTransitionScreen; + import feathers.examples.transitionsExplorer.screens.FourWayTransitionScreen; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.motion.transitions.Cover; + import feathers.motion.transitions.Cube; + import feathers.motion.transitions.Flip; + import feathers.motion.transitions.Reveal; + import feathers.motion.transitions.Slide; + import feathers.themes.MetalWorksMobileTheme; + + import starling.display.Quad; + + import starling.events.Event; + import starling.textures.Texture; + + public class Main extends LayoutGroup + { + [Embed(source="/../assets/images/test-pattern1.png")] + private static const TEST_PATTERN1:Class; + + [Embed(source="/../assets/images/test-pattern2.png")] + private static const TEST_PATTERN2:Class; + + private static const MENU_SCREEN_ID_ALL_TRANSITIONS:String = "allTransitions"; + private static const MENU_SCREEN_ID_COLOR_FADE:String = "colorFade"; + private static const MENU_SCREEN_ID_COVER:String = "cover"; + private static const MENU_SCREEN_ID_CUBE:String = "cube"; + private static const MENU_SCREEN_ID_FADE:String = "fade"; + private static const MENU_SCREEN_ID_FLIP:String = "flip"; + private static const MENU_SCREEN_ID_REVEAL:String = "reveal"; + private static const MENU_SCREEN_ID_SLIDE:String = "slide"; + + private static const CONTENT_SCREEN_ID_ONE:String = "one"; + private static const CONTENT_SCREEN_ID_TWO:String = "two"; + + public function Main() + { + this.autoSizeMode = LayoutGroup.AUTO_SIZE_MODE_STAGE; + } + + private var _menu:StackScreenNavigator; + private var _content:ScreenNavigator; + + override protected function initialize():void + { + new MetalWorksMobileTheme(); + + this.layout = new AnchorLayout(); + + this._menu = new StackScreenNavigator(); + this._menu.autoSizeMode = StackScreenNavigator.AUTO_SIZE_MODE_CONTENT; + var menuLayoutData:AnchorLayoutData = new AnchorLayoutData(); + menuLayoutData.top = 0; + menuLayoutData.bottom = 0; + menuLayoutData.left = 0; + this._menu.width = this.stage.stageWidth / 3; + this._menu.layoutData = new AnchorLayoutData(0, NaN, 0, 0); + this._menu.clipContent = true; + this.addChild(this._menu); + + var allTransitionsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(AllTransitionsScreen); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.COVER, MENU_SCREEN_ID_COVER); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.CUBE, MENU_SCREEN_ID_CUBE); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.FADE, MENU_SCREEN_ID_FADE); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.COLOR_FADE, MENU_SCREEN_ID_COLOR_FADE); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.FLIP, MENU_SCREEN_ID_FLIP); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.REVEAL, MENU_SCREEN_ID_REVEAL); + allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.SLIDE, MENU_SCREEN_ID_SLIDE); + this._menu.addScreen(MENU_SCREEN_ID_ALL_TRANSITIONS, allTransitionsItem); + + var colorFadeItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ColorFadeTransitionScreen); + colorFadeItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + colorFadeItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_COLOR_FADE, colorFadeItem); + + var coverItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FourWayTransitionScreen); + coverItem.properties.transitionName = "Cover"; + coverItem.properties.leftTransition = Cover.createCoverLeftTransition(); + coverItem.properties.rightTransition = Cover.createCoverRightTransition(); + coverItem.properties.upTransition = Cover.createCoverUpTransition(); + coverItem.properties.downTransition = Cover.createCoverDownTransition(); + coverItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + coverItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_COVER, coverItem); + + var cubeItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FourWayTransitionScreen); + cubeItem.properties.transitionName = "Cube"; + cubeItem.properties.leftTransition = Cube.createCubeLeftTransition(); + cubeItem.properties.rightTransition = Cube.createCubeRightTransition(); + cubeItem.properties.upTransition = Cube.createCubeUpTransition(); + cubeItem.properties.downTransition = Cube.createCubeDownTransition(); + cubeItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + cubeItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_CUBE, cubeItem); + + var fadeItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FadeTransitionScreen); + fadeItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + fadeItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_FADE, fadeItem); + + var flipItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FourWayTransitionScreen); + flipItem.properties.transitionName = "Flip"; + flipItem.properties.leftTransition = Flip.createFlipLeftTransition(); + flipItem.properties.rightTransition = Flip.createFlipRightTransition(); + flipItem.properties.upTransition = Flip.createFlipUpTransition(); + flipItem.properties.downTransition = Flip.createFlipDownTransition(); + flipItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + flipItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_FLIP, flipItem); + + var revealItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FourWayTransitionScreen); + revealItem.properties.transitionName = "Reveal"; + revealItem.properties.leftTransition = Reveal.createRevealLeftTransition(); + revealItem.properties.rightTransition = Reveal.createRevealRightTransition(); + revealItem.properties.upTransition = Reveal.createRevealUpTransition(); + revealItem.properties.downTransition = Reveal.createRevealDownTransition(); + revealItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + revealItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_REVEAL, revealItem); + + var slideItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FourWayTransitionScreen); + slideItem.properties.transitionName = "Slide"; + slideItem.properties.leftTransition = Slide.createSlideLeftTransition(); + slideItem.properties.rightTransition = Slide.createSlideRightTransition(); + slideItem.properties.upTransition = Slide.createSlideUpTransition(); + slideItem.properties.downTransition = Slide.createSlideDownTransition(); + slideItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); + slideItem.addPopEvent(Event.COMPLETE); + this._menu.addScreen(MENU_SCREEN_ID_SLIDE, slideItem); + + this._menu.pushScreen(MENU_SCREEN_ID_ALL_TRANSITIONS); + + this._menu.pushTransition = Slide.createSlideLeftTransition(); + this._menu.popTransition = Slide.createSlideRightTransition(); + + this._content = new ScreenNavigator(); + var contentLayoutData:AnchorLayoutData = new AnchorLayoutData(0, 0, 0, 0); + contentLayoutData.leftAnchorDisplayObject = this._menu; + this._content.layoutData = contentLayoutData; + this.addChildAt(this._content, 0); + + var content1:LayoutGroup = new LayoutGroup(); + content1.layout = new AnchorLayout(); + var image:ImageLoader = new ImageLoader(); + image.source = Texture.fromEmbeddedAsset(TEST_PATTERN1, false); + image.layoutData = new AnchorLayoutData(0, 0, 0, 0); + content1.addChild(image); + content1.backgroundSkin = new Quad(1, 1, 0x000000); + this._content.addScreen(CONTENT_SCREEN_ID_ONE, new ScreenNavigatorItem(content1)); + var content2:LayoutGroup = new LayoutGroup(); + content2.layout = new AnchorLayout(); + image = new ImageLoader(); + image.source = Texture.fromEmbeddedAsset(TEST_PATTERN2, false); + image.layoutData = new AnchorLayoutData(0, 0, 0, 0); + content2.addChild(image); + content2.backgroundSkin = new Quad(1, 1, 0xffffff); + this._content.addScreen(CONTENT_SCREEN_ID_TWO, new ScreenNavigatorItem(content2)); + + this._content.showScreen(CONTENT_SCREEN_ID_ONE); + + //we're not setting the transition on the content screen navigator + //because the screens will select their own transitions. + } + + private function getNextScreenID():String + { + if(this._content.activeScreenID == CONTENT_SCREEN_ID_ONE) + { + return CONTENT_SCREEN_ID_TWO; + } + return CONTENT_SCREEN_ID_ONE; + } + + private function transitionHandler(event:Event, transition:Function):void + { + this._content.showScreen(this.getNextScreenID(), transition); + } + } +} diff --git a/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/AllTransitionsScreen.as b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/AllTransitionsScreen.as new file mode 100644 index 0000000000..e537c5d245 --- /dev/null +++ b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/AllTransitionsScreen.as @@ -0,0 +1,108 @@ +package feathers.examples.transitionsExplorer.screens +{ + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.StackScreenNavigatorItem; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.StandardIcons; + + import starling.events.Event; + import starling.textures.Texture; + + public class AllTransitionsScreen extends PanelScreen + { + public static const COLOR_FADE:String = "colorFade"; + public static const COVER:String = "cover"; + public static const CUBE:String = "cube"; + public static const FADE:String = "fade"; + public static const FLIP:String = "flip"; + public static const REVEAL:String = "reveal"; + public static const SLIDE:String = "slide"; + + public function AllTransitionsScreen() + { + } + + private var _list:List; + + public var savedVerticalScrollPosition:Number = 0; + public var savedSelectedIndex:int = -1; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Transitions"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { label: "Color Fade", event: COLOR_FADE }, + { label: "Cover", event: COVER }, + { label: "Fade", event: FADE }, + { label: "Cube", event: CUBE }, + { label: "Flip", event: FLIP }, + { label: "Reveal", event: REVEAL }, + { label: "Slide", event: SLIDE }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + this._list.verticalScrollPosition = this.savedVerticalScrollPosition; + this._list.selectedIndex = this.savedSelectedIndex; + + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "label"; + renderer.accessorySourceFunction = accessorySourceFunction; + return renderer; + }; + + this._list.addEventListener(Event.TRIGGERED, list_triggeredHandler); + this.addChild(this._list); + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function accessorySourceFunction(item:Object):Texture + { + return StandardIcons.listDrillDownAccessoryTexture; + } + + private function transitionInCompleteHandler(event:Event):void + { + this._list.selectedIndex = -1; + this._list.revealScrollBars(); + } + + private function list_triggeredHandler(event:Event, item:Object):void + { + var eventType:String = item.event as String; + this.dispatchEventWith(eventType, false, + { + //we're going to save the position of the list so that when the user + //navigates back to this screen, they won't need to scroll back to + //the same position manually + savedVerticalScrollPosition: this._list.verticalScrollPosition, + //we'll also save the selected index to temporarily highlight + //the previously selected item when transitioning back + savedSelectedIndex: this._list.selectedIndex + }); + } + } +} diff --git a/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ColorFadeTransitionScreen.as b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ColorFadeTransitionScreen.as new file mode 100644 index 0000000000..b2df7ac3fd --- /dev/null +++ b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ColorFadeTransitionScreen.as @@ -0,0 +1,102 @@ +package feathers.examples.transitionsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.motion.transitions.Fade; + import feathers.motion.transitions.ColorFade; + + import starling.display.DisplayObject; + + import starling.events.Event; + + public class ColorFadeTransitionScreen extends PanelScreen + { + public static const TRANSITION:String = "transition"; + + private static function fadeToRandomColor(oldScreen:DisplayObject, newScreen:DisplayObject, completeCallback:Function):void + { + var randomColor:uint = Math.random() * 0xffffff; + ColorFade.createColorFadeTransition(randomColor)(oldScreen, newScreen, completeCallback); + } + + public function ColorFadeTransitionScreen() + { + super(); + } + + private var _list:List; + private var _backButton:Button; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Color Fade"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { label: "Black", transition: ColorFade.createBlackFadeToBlackTransition() }, + { label: "White", transition: ColorFade.createWhiteFadeTransition() }, + { label: "Custom", transition: fadeToRandomColor, accessory: "(random for demo)" }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "label"; + + renderer.accessoryLabelField = "accessory"; + return renderer; + }; + + this._list.addEventListener(Event.TRIGGERED, list_triggeredHandler); + this._list.revealScrollBars(); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + + this._backButton = new Button(); + this._backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + this._backButton.label = "Transitions"; + this._backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new [this._backButton]; + + return header; + } + + private function list_triggeredHandler(event:Event, item:Object):void + { + var transition:Function = item.transition as Function; + this.dispatchEventWith(TRANSITION, false, transition); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(Event.COMPLETE); + } + } +} diff --git a/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ContentScreen.as b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ContentScreen.as new file mode 100644 index 0000000000..ae74643542 --- /dev/null +++ b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ContentScreen.as @@ -0,0 +1,21 @@ +package feathers.examples.transitionsExplorer.screens +{ + import feathers.controls.Screen; + + import starling.display.Quad; + + public class ContentScreen extends Screen + { + public function ContentScreen() + { + } + + public var color:uint; + + override protected function initialize():void + { + this.backgroundSkin = new Quad(1, 1, this.color); + } + + } +} diff --git a/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FadeTransitionScreen.as b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FadeTransitionScreen.as new file mode 100644 index 0000000000..08ed78f88d --- /dev/null +++ b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FadeTransitionScreen.as @@ -0,0 +1,93 @@ +package feathers.examples.transitionsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.motion.transitions.Fade; + + import starling.display.DisplayObject; + + import starling.events.Event; + + public class FadeTransitionScreen extends PanelScreen + { + public static const TRANSITION:String = "transition"; + + public function FadeTransitionScreen() + { + super(); + } + + private var _list:List; + private var _backButton:Button; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = "Fade"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { label: "Fade In", transition: Fade.createFadeInTransition() }, + { label: "Fade Out", transition: Fade.createFadeOutTransition() }, + { label: "Crossfade", transition: Fade.createCrossfadeTransition() }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "label"; + return renderer; + }; + + this._list.addEventListener(Event.TRIGGERED, list_triggeredHandler); + this._list.revealScrollBars(); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + + this._backButton = new Button(); + this._backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + this._backButton.label = "Transitions"; + this._backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new [this._backButton]; + + return header; + } + + private function list_triggeredHandler(event:Event, item:Object):void + { + var transition:Function = item.transition as Function; + this.dispatchEventWith(TRANSITION, false, transition); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(Event.COMPLETE); + } + } +} diff --git a/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FourWayTransitionScreen.as b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FourWayTransitionScreen.as new file mode 100644 index 0000000000..9d9b829430 --- /dev/null +++ b/examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FourWayTransitionScreen.as @@ -0,0 +1,98 @@ +package feathers.examples.transitionsExplorer.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import starling.display.DisplayObject; + + import starling.events.Event; + + public class FourWayTransitionScreen extends PanelScreen + { + public static const TRANSITION:String = "transition"; + + public function FourWayTransitionScreen() + { + } + + private var _list:List; + private var _backButton:Button; + + public var transitionName:String; + public var upTransition:Function; + public var downTransition:Function; + public var leftTransition:Function; + public var rightTransition:Function; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = this.transitionName; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.dataProvider = new ListCollection( + [ + { label: "Left", transition: this.leftTransition }, + { label: "Right", transition: this.rightTransition }, + { label: "Up", transition: this.upTransition }, + { label: "Down", transition: this.downTransition }, + ]); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.clipContent = false; + this._list.autoHideBackground = true; + + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "label"; + return renderer; + }; + + this._list.addEventListener(Event.TRIGGERED, list_triggeredHandler); + this._list.revealScrollBars(); + this.addChild(this._list); + + this.headerFactory = this.customHeaderFactory; + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + + this._backButton = new Button(); + this._backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + this._backButton.label = "Transitions"; + this._backButton.addEventListener(Event.TRIGGERED, backButton_triggeredHandler); + header.leftItems = new [this._backButton]; + + return header; + } + + private function list_triggeredHandler(event:Event, item:Object):void + { + var transition:Function = item.transition as Function; + this.dispatchEventWith(TRANSITION, false, transition); + } + + private function backButton_triggeredHandler(event:Event):void + { + this.dispatchEventWith(Event.COMPLETE); + } + } +} diff --git a/examples/YouTubeFeeds/README.md b/examples/YouTubeFeeds/README.md new file mode 100644 index 0000000000..bb29109386 --- /dev/null +++ b/examples/YouTubeFeeds/README.md @@ -0,0 +1,13 @@ +# YouTube Feeds Example for Feathers + +A simple application that uses the [YouTube Data API](https://developers.google.com/youtube/2.0/reference) to display feeds using [Feathers](http://feathersui.com/) components. + +## Requirements + +In addition to Starling Framwork and Feathers, this example project requires the MetalWorksMobileTheme example theme. You can find the SWC file for this theme at the following location in the Feathers release build: + + themes/MetalWorksMobileTheme/swc/MetalWorksMobileTheme.swc + +## Web Demo + +View the [YouTube Feeds example](http://feathersui.com/examples/youtube-feeds/) in your browser. \ No newline at end of file diff --git a/examples/YouTubeFeeds/build.properties b/examples/YouTubeFeeds/build.properties new file mode 100644 index 0000000000..ec2b3c08a9 --- /dev/null +++ b/examples/YouTubeFeeds/build.properties @@ -0,0 +1,7 @@ +feathers.root = ${basedir}/../../source +starling.root = ${basedir}/../../third-party/starling +theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source +output.path = ${basedir}/output +icon.path = ${basedir}/../icons + +swf.version = 18 \ No newline at end of file diff --git a/examples/YouTubeFeeds/build.xml b/examples/YouTubeFeeds/build.xml new file mode 100644 index 0000000000..83fd8ce8d6 --- /dev/null +++ b/examples/YouTubeFeeds/build.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/YouTubeFeeds/sdk.properties b/examples/YouTubeFeeds/sdk.properties new file mode 100644 index 0000000000..0df2cde625 --- /dev/null +++ b/examples/YouTubeFeeds/sdk.properties @@ -0,0 +1,15 @@ +# The location of the SDK. +# Override flashsdk.root in sdk.local.properties (create that file if it +# doesn't already exist). +flashsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 + +# config files +flashplayer.config = ${flashsdk.root}/frameworks/flex-config.xml +airdesktop.config = ${flashsdk.root}/frameworks/air-config.xml +airmobile.config = ${flashsdk.root}/frameworks/airmobile-config.xml + +# path to compiler jars +asdoc = ${flashsdk.root}/lib/legacy/asdoc.jar +compc = ${flashsdk.root}/lib/compc-cli.jar +mxmlc = ${flashsdk.root}/lib/mxmlc-cli.jar +adt = ${flashsdk.root}/lib/adt.jar \ No newline at end of file diff --git a/examples/YouTubeFeeds/source/YouTubeFeeds-app.xml b/examples/YouTubeFeeds/source/YouTubeFeeds-app.xml new file mode 100644 index 0000000000..dfe68ced01 --- /dev/null +++ b/examples/YouTubeFeeds/source/YouTubeFeeds-app.xml @@ -0,0 +1,55 @@ + + + com.feathersui.examples.YouTubeFeeds + Feathers YouTube Feeds + Feathers YouTube Feeds + 2.0.1 + YouTube Feeds example application built with Feathers UI controls for Starling + 2014 Josh Tynjala + + + YouTubeFeeds.swf + true + true + true + direct + + + en + + + icon29.png + icon48.png + icon50.png + icon57.png + icon58.png + icon72.png + icon96.png + icon100.png + icon114.png + icon128.png + icon144.png + + + 16bit + + + + ]]> + + + + UIDeviceFamily + + 1 + 2 + + UIPrerenderedIcon + + ]]> + + high + + \ No newline at end of file diff --git a/examples/YouTubeFeeds/source/YouTubeFeeds.as b/examples/YouTubeFeeds/source/YouTubeFeeds.as new file mode 100644 index 0000000000..51c4a2fdd6 --- /dev/null +++ b/examples/YouTubeFeeds/source/YouTubeFeeds.as @@ -0,0 +1,154 @@ +package +{ + import feathers.examples.youtube.Main; + + import flash.display.Loader; + import flash.display.Sprite; + import flash.display.StageAlign; + import flash.display.StageOrientation; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.system.Capabilities; + import flash.utils.ByteArray; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class YouTubeFeeds extends Sprite + { + public function YouTubeFeeds() + { + if(this.stage) + { + this.stage.scaleMode = StageScaleMode.NO_SCALE; + this.stage.align = StageAlign.TOP_LEFT; + } + this.mouseEnabled = this.mouseChildren = false; + this.showLaunchImage(); + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + private var _launchImage:Loader; + private var _savedAutoOrients:Boolean; + + private function showLaunchImage():void + { + var filePath:String; + var isPortraitOnly:Boolean = false; + if(Capabilities.manufacturer.indexOf("iOS") >= 0) + { + if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) + { + var isCurrentlyPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; + } + else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) + { + isCurrentlyPortrait = this.stage.orientation == StageOrientation.DEFAULT || this.stage.orientation == StageOrientation.UPSIDE_DOWN; + filePath = isCurrentlyPortrait ? "Default-Portrait.png" : "Default-Landscape.png"; + } + else if(Capabilities.screenResolutionX == 640) + { + isPortraitOnly = true; + if(Capabilities.screenResolutionY == 1136) + { + filePath = "Default-568h@2x.png"; + } + else + { + filePath = "Default@2x.png"; + } + } + else if(Capabilities.screenResolutionX == 320) + { + isPortraitOnly = true; + filePath = "Default.png"; + } + } + + if(filePath) + { + var file:File = File.applicationDirectory.resolvePath(filePath); + if(file.exists) + { + var bytes:ByteArray = new ByteArray(); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.READ); + stream.readBytes(bytes, 0, stream.bytesAvailable); + stream.close(); + this._launchImage = new Loader(); + this._launchImage.loadBytes(bytes); + this.addChild(this._launchImage); + this._savedAutoOrients = this.stage.autoOrients; + this.stage.autoOrients = false; + if(isPortraitOnly) + { + this.stage.setOrientation(StageOrientation.DEFAULT); + } + } + } + } + + private function loaderInfo_completeHandler(event:Event):void + { + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + this._starling = new Starling(Main, this.stage); + this._starling.enableErrorChecking = false; + //this._starling.showStats = true; + this._starling.start(); + if(this._launchImage) + { + this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); + } + + this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, true); + this.stage.addEventListener(Event.DEACTIVATE, stage_deactivateHandler, false, 0, true); + } + + private function starling_rootCreatedHandler(event:Object):void + { + if(this._launchImage) + { + this.removeChild(this._launchImage); + this._launchImage.unloadAndStop(true); + this._launchImage = null; + this.stage.autoOrients = this._savedAutoOrients; + } + } + + private function stage_resizeHandler(event:Event):void + { + this._starling.stage.stageWidth = this.stage.stageWidth; + this._starling.stage.stageHeight = this.stage.stageHeight; + + var viewPort:Rectangle = this._starling.viewPort; + viewPort.width = this.stage.stageWidth; + viewPort.height = this.stage.stageHeight; + try + { + this._starling.viewPort = viewPort; + } + catch(error:Error) {} + //this._starling.showStatsAt(HAlign.LEFT, VAlign.BOTTOM); + } + + private function stage_deactivateHandler(event:Event):void + { + this._starling.stop(); + this.stage.addEventListener(Event.ACTIVATE, stage_activateHandler, false, 0, true); + } + + private function stage_activateHandler(event:Event):void + { + this.stage.removeEventListener(Event.ACTIVATE, stage_activateHandler); + this._starling.start(); + } + + } +} \ No newline at end of file diff --git a/examples/YouTubeFeeds/source/YouTubeFeedsWeb.as b/examples/YouTubeFeeds/source/YouTubeFeedsWeb.as new file mode 100644 index 0000000000..f53aed0aa9 --- /dev/null +++ b/examples/YouTubeFeeds/source/YouTubeFeedsWeb.as @@ -0,0 +1,57 @@ +package +{ + import feathers.system.DeviceCapabilities; + + import flash.display.MovieClip; + import flash.display.StageAlign; + import flash.display.StageScaleMode; + import flash.events.Event; + import flash.ui.ContextMenu; + import flash.utils.getDefinitionByName; + + import starling.core.Starling; + + [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] + public class YouTubeFeedsWeb extends MovieClip + { + public function YouTubeFeedsWeb() + { + var menu:ContextMenu = new ContextMenu(); + menu.hideBuiltInItems(); + this.contextMenu = menu; + + if(this.stage) + { + this.stage.align = StageAlign.TOP_LEFT; + this.stage.scaleMode = StageScaleMode.NO_SCALE; + } + + //pretends to be an iPhone Retina screen + DeviceCapabilities.dpi = 326; + DeviceCapabilities.screenPixelWidth = 960; + DeviceCapabilities.screenPixelHeight = 640; + + this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); + } + + private var _starling:Starling; + + private function start():void + { + this.gotoAndStop(2); + this.graphics.clear(); + + Starling.handleLostContext = true; + Starling.multitouchEnabled = true; + var MainType:Class = getDefinitionByName("feathers.examples.youtube.Main") as Class; + this._starling = new Starling(MainType, this.stage); + this._starling.enableErrorChecking = false; + this._starling.start(); + } + + private function loaderInfo_completeHandler(event:Event):void + { + this.start(); + } + } +} \ No newline at end of file diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/Main.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/Main.as new file mode 100644 index 0000000000..7cf2569722 --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/Main.as @@ -0,0 +1,76 @@ +package feathers.examples.youtube +{ + import feathers.controls.ScreenNavigator; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.StackScreenNavigator; + import feathers.controls.StackScreenNavigatorItem; + import feathers.examples.youtube.models.VideoDetails; + import feathers.examples.youtube.models.VideoFeed; + import feathers.examples.youtube.models.YouTubeModel; + import feathers.examples.youtube.screens.ListVideosScreen; + import feathers.examples.youtube.screens.MainMenuScreen; + import feathers.examples.youtube.screens.VideoDetailsScreen; + import feathers.motion.transitions.ScreenSlidingStackTransitionManager; + import feathers.motion.transitions.Slide; + import feathers.themes.MetalWorksMobileTheme; + + import starling.events.Event; + + public class Main extends StackScreenNavigator + { + private static const MAIN_MENU:String = "mainMenu"; + private static const LIST_VIDEOS:String = "listVideos"; + private static const VIDEO_DETAILS:String = "videoDetails"; + + public function Main() + { + super(); + } + + private var _model:YouTubeModel; + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + new MetalWorksMobileTheme(); + + this._model = new YouTubeModel(); + + var mainMenuItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(MainMenuScreen); + mainMenuItem.setFunctionForPushEvent(MainMenuScreen.LIST_VIDEOS, this.mainMenuScreen_listVideosHandler); + this.addScreen(MAIN_MENU, mainMenuItem); + + var listVideosItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ListVideosScreen); + listVideosItem.setFunctionForPushEvent(ListVideosScreen.SHOW_VIDEO_DETAILS, this.listVideos_showVideoDetails); + listVideosItem.addPopEvent(Event.COMPLETE); + listVideosItem.properties.model = this._model; + this.addScreen(LIST_VIDEOS, listVideosItem); + + var videoDetailsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(VideoDetailsScreen); + videoDetailsItem.addPopEvent(Event.COMPLETE); + videoDetailsItem.properties.model = this._model; + this.addScreen(VIDEO_DETAILS, videoDetailsItem); + + this.rootScreenID = MAIN_MENU; + + this.pushTransition = Slide.createSlideLeftTransition(); + this.popTransition = Slide.createSlideRightTransition(); + } + + private function mainMenuScreen_listVideosHandler(event:Event, mainMenuProperties:Object):void + { + var screen:MainMenuScreen = MainMenuScreen(this.activeScreen); + this._model.selectedList = screen.selectedCategory; + this.pushScreen(LIST_VIDEOS, mainMenuProperties); + } + + private function listVideos_showVideoDetails(event:Event, listVideosProperties:Object):void + { + var screen:ListVideosScreen = ListVideosScreen(this.activeScreen); + this._model.selectedVideo = screen.selectedVideo; + this.pushScreen(VIDEO_DETAILS, listVideosProperties); + } + } +} diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoDetails.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoDetails.as new file mode 100644 index 0000000000..854d2f126c --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoDetails.as @@ -0,0 +1,18 @@ +package feathers.examples.youtube.models +{ + public class VideoDetails + { + public function VideoDetails(title:String = null, author:String = null, url:String = null, description:String = null) + { + this.title = title; + this.author = author; + this.url = url; + this.description = description; + } + + public var title:String; + public var author:String; + public var url:String; + public var description:String; + } +} diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoFeed.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoFeed.as new file mode 100644 index 0000000000..41b7dd4ee8 --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoFeed.as @@ -0,0 +1,14 @@ +package feathers.examples.youtube.models +{ + public class VideoFeed + { + public function VideoFeed(name:String = null, url:String = null) + { + this.name = name; + this.url = url; + } + + public var name:String; + public var url:String; + } +} diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/models/YouTubeModel.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/models/YouTubeModel.as new file mode 100644 index 0000000000..82c68f5f85 --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/models/YouTubeModel.as @@ -0,0 +1,9 @@ +package feathers.examples.youtube.models +{ + public class YouTubeModel + { + public var selectedList:VideoFeed; + public var selectedVideo:VideoDetails; + public var cachedLists:Object = {}; + } +} diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/ListVideosScreen.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/ListVideosScreen.as new file mode 100644 index 0000000000..de45270718 --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/ListVideosScreen.as @@ -0,0 +1,289 @@ +package feathers.examples.youtube.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.Label; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.ScreenNavigatorItem; + import feathers.controls.StackScreenNavigatorItem; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.examples.youtube.models.VideoDetails; + import feathers.examples.youtube.models.YouTubeModel; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import flash.events.ErrorEvent; + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + [Event(name="showVideoDetails",type="starling.events.Event")] + + public class ListVideosScreen extends PanelScreen + { + public static const SHOW_VIDEO_DETAILS:String = "showVideoDetails"; + + public function ListVideosScreen() + { + super(); + this.addEventListener(starling.events.Event.REMOVED_FROM_STAGE, removedFromStageHandler); + } + + private var _backButton:Button; + private var _list:List; + private var _message:Label; + + private var _isTransitioning:Boolean = false; + + private var _model:YouTubeModel; + + public function get model():YouTubeModel + { + return this._model; + } + + public function set model(value:YouTubeModel):void + { + if(this._model == value) + { + return; + } + this._model = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + public var savedVerticalScrollPosition:Number = 0; + public var savedSelectedIndex:int = -1; + public var savedDataProvider:ListCollection; + + private var _loader:URLLoader; + private var _savedLoaderData:*; + + public function get selectedVideo():VideoDetails + { + if(!this._list) + { + return null; + } + return this._list.selectedItem as VideoDetails; + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.title = this._model.selectedList.name; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + renderer.labelField = "title"; + renderer.accessoryLabelField = "author"; + //no accessory and anything interactive, so we can use the quick + //hit area to improve performance. + renderer.isQuickHitAreaEnabled = true; + return renderer; + } + //when navigating to video details, we save this information to + //restore the list when later navigating back to this screen. + if(this.savedDataProvider) + { + this._list.dataProvider = this.savedDataProvider; + this._list.selectedIndex = this.savedSelectedIndex; + this._list.verticalScrollPosition = this.savedVerticalScrollPosition; + } + this.addChild(this._list); + + this._message = new Label(); + this._message.text = "Loading..."; + this._message.layoutData = new AnchorLayoutData(NaN, NaN, NaN, NaN, 0, 0); + //hide the loading message if we're using restored results + this._message.visible = this.savedDataProvider === null; + this.addChild(this._message); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = onBackButton; + + this._isTransitioning = true; + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + this._backButton = new Button(); + this._backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + this._backButton.label = "Back"; + this._backButton.addEventListener(starling.events.Event.TRIGGERED, onBackButton); + header.leftItems = new + [ + this._backButton + ]; + return header; + } + + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + + //only load the list of videos if don't have restored results + if(!this.savedDataProvider && dataInvalid) + { + this._list.dataProvider = null; + if(this._model && this._model.selectedList) + { + if(this._loader) + { + this.cleanUpLoader(); + } + if(this._model.cachedLists.hasOwnProperty(this._model.selectedList.url)) + { + this._message.visible = false; + this._list.dataProvider = ListCollection(this._model.cachedLists[this._model.selectedList.url]); + + //show the scroll bars so that the user knows they can scroll + this._list.revealScrollBars(); + } + else + { + this._loader = new URLLoader(); + this._loader.addEventListener(flash.events.Event.COMPLETE, loader_completeHandler); + this._loader.addEventListener(IOErrorEvent.IO_ERROR, loader_errorHandler); + this._loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_errorHandler); + this._loader.load(new URLRequest(this._model.selectedList.url)); + } + } + } + + //never forget to call super.draw()! + super.draw(); + } + + private function cleanUpLoader():void + { + if(!this._loader) + { + return; + } + this._loader.removeEventListener(flash.events.Event.COMPLETE, loader_completeHandler); + this._loader.removeEventListener(IOErrorEvent.IO_ERROR, loader_errorHandler); + this._loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_errorHandler); + this._loader = null; + } + + private function parseFeed(feed:XML):void + { + this._message.visible = false; + + var atom:Namespace = feed.namespace(); + var media:Namespace = feed.namespace("media"); + + var items:Vector. = new []; + var entries:XMLList = feed.atom::entry; + var entryCount:int = entries.length(); + for(var i:int = 0; i < entryCount; i++) + { + var entry:XML = entries[i]; + var item:VideoDetails = new VideoDetails(); + item.title = entry.atom::title[0].toString(); + item.author = entry.atom::author[0].atom::name[0].toString(); + item.url = entry.media::group[0].media::player[0].@url.toString(); + item.description = entry.media::group[0].media::description[0].toString(); + items.push(item); + } + var collection:ListCollection = new ListCollection(items); + this._model.cachedLists[this._model.selectedList.url] = collection; + this._list.dataProvider = collection; + + //show the scroll bars so that the user knows they can scroll + this._list.revealScrollBars(); + } + + private function onBackButton(event:starling.events.Event = null):void + { + this.dispatchEventWith(starling.events.Event.COMPLETE); + } + + private function removedFromStageHandler(event:starling.events.Event):void + { + this.cleanUpLoader(); + } + + private function transitionInCompleteHandler(event:starling.events.Event):void + { + this._isTransitioning = false; + + if(this._savedLoaderData) + { + this.parseFeed(new XML(this._savedLoaderData)); + this._savedLoaderData = null; + } + + this._list.selectedIndex = -1; + this._list.addEventListener(starling.events.Event.CHANGE, list_changeHandler); + this._list.revealScrollBars(); + } + + private function list_changeHandler(event:starling.events.Event):void + { + if(this._list.selectedIndex < 0) + { + return; + } + + this.dispatchEventWith(SHOW_VIDEO_DETAILS, false, + { + //we're going to save the position of the list so that when the user + //navigates back to this screen, they won't need to scroll back to + //the same position manually + savedVerticalScrollPosition: this._list.verticalScrollPosition, + //we'll also save the selected index to temporarily highlight + //the previously selected item when transitioning back + savedSelectedIndex: this._list.selectedIndex, + //and we'll save the data provider so that we don't need to reload + //data when we return to this screen. we can restore it. + savedDataProvider: this._list.dataProvider + }); + } + + private function loader_completeHandler(event:flash.events.Event):void + { + var loaderData:* = this._loader.data; + this.cleanUpLoader(); + if(this._isTransitioning) + { + //if this screen is still transitioning in, the we'll save the + //feed until later to ensure that the animation isn't affected. + this._savedLoaderData = loaderData; + return; + } + this.parseFeed(new XML(loaderData)); + } + + private function loader_errorHandler(event:ErrorEvent):void + { + this.cleanUpLoader(); + this._message.text = "Unable to load data. Please try again later."; + this._message.visible = true; + this.invalidate(INVALIDATION_FLAG_STYLES); + trace(event.toString()); + } + } +} diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/MainMenuScreen.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/MainMenuScreen.as new file mode 100644 index 0000000000..ff28461751 --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/MainMenuScreen.as @@ -0,0 +1,240 @@ +package feathers.examples.youtube.screens +{ + import feathers.controls.Label; + import feathers.controls.List; + import feathers.controls.PanelScreen; + import feathers.controls.StackScreenNavigatorItem; + import feathers.controls.renderers.DefaultListItemRenderer; + import feathers.controls.renderers.IListItemRenderer; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.examples.youtube.models.VideoFeed; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + import feathers.skins.StandardIcons; + + import flash.events.ErrorEvent; + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.net.URLLoader; + import flash.net.URLRequest; + + import starling.events.Event; + import starling.textures.Texture; + + [Event(name="listVideos",type="starling.events.Event")] + + public class MainMenuScreen extends PanelScreen + { + public static const LIST_VIDEOS:String = "listVideos"; + + private static const CATEGORIES_URL:String = "http://gdata.youtube.com/schemas/2007/categories.cat"; + private static const FEED_URL_BEFORE:String = "http://gdata.youtube.com/feeds/api/standardfeeds/US/most_popular_"; + private static const FEED_URL_AFTER:String = "?v=2"; + + public function MainMenuScreen() + { + this.addEventListener(starling.events.Event.REMOVED_FROM_STAGE, removedFromStageHandler); + } + + private var _list:List; + + private var _loader:URLLoader; + private var _message:Label; + + public var savedVerticalScrollPosition:Number = 0; + public var savedSelectedIndex:int = -1; + public var savedDataProvider:ListCollection; + + public function get selectedCategory():VideoFeed + { + if(!this._list) + { + return null; + } + return this._list.selectedItem as VideoFeed; + } + + override protected function initialize():void + { + super.initialize(); + + this.title = "YouTube Feeds"; + + this.layout = new AnchorLayout(); + + this._list = new List(); + this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this._list.itemRendererFactory = function():IListItemRenderer + { + var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); + + //enable the quick hit area to optimize hit tests when an item + //is only selectable and doesn't have interactive children. + renderer.isQuickHitAreaEnabled = true; + + renderer.labelField = "name"; + renderer.accessorySourceFunction = accessorySourceFunction; + return renderer; + } + //when navigating to video results, we save this information to + //restore the list when later navigating back to this screen. + if(this.savedDataProvider) + { + this._list.dataProvider = this.savedDataProvider; + this._list.selectedIndex = this.savedSelectedIndex; + this._list.verticalScrollPosition = this.savedVerticalScrollPosition; + } + this.addChild(this._list); + + this._message = new Label(); + this._message.text = "Loading..."; + this._message.layoutData = new AnchorLayoutData(NaN, NaN, NaN, NaN, 0, 0); + //hide the loading message if we're using restored results + this._message.visible = this.savedDataProvider === null; + this.addChild(this._message); + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + + //only load the list of videos if don't have restored results + if(!this.savedDataProvider && dataInvalid) + { + this._list.dataProvider = null; + this._message.visible = true; + if(this._loader) + { + this.cleanUpLoader(); + } + this._loader = new URLLoader(); + this._loader.addEventListener(flash.events.Event.COMPLETE, loader_completeHandler); + this._loader.addEventListener(IOErrorEvent.IO_ERROR, loader_errorHandler); + this._loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_errorHandler); + this._loader.load(new URLRequest(CATEGORIES_URL)); + } + + //never forget to call super.draw()! + super.draw(); + } + + private function cleanUpLoader():void + { + if(!this._loader) + { + return; + } + this._loader.removeEventListener(flash.events.Event.COMPLETE, loader_completeHandler); + this._loader.removeEventListener(IOErrorEvent.IO_ERROR, loader_errorHandler); + this._loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_errorHandler); + this._loader = null; + } + + private function parseFeed(feed:XML):void + { + this._message.visible = false; + + var atom:Namespace = feed.namespace("atom"); + var yt:Namespace = feed.namespace("yt"); + var deprecatedElement:QName = new QName(yt, "deprecated"); + var browsableElement:QName = new QName(yt, "browsable"); + + var items:Vector. = new []; + var categories:XMLList = feed.atom::category; + var categoryCount:int = categories.length(); + for(var i:int = 0; i < categoryCount; i++) + { + var category:XML = categories[i]; + var item:VideoFeed = new VideoFeed(); + if(category.elements(deprecatedElement).length() > 0) + { + continue; + } + var browsable:XMLList = category.elements(browsableElement); + if(browsable.length() < 0) + { + continue; + } + var regions:String = browsable[0].@regions.toString(); + if(regions.toString().indexOf("US") < 0) + { + continue; + } + item.name = category.@label[0].toString(); + var term:String = category.@term[0].toString(); + item.url = FEED_URL_BEFORE + encodeURI(term) + FEED_URL_AFTER; + items.push(item); + } + var collection:ListCollection = new ListCollection(items); + this._list.dataProvider = collection; + + //show the scroll bars so that the user knows they can scroll + this._list.revealScrollBars(); + } + + private function accessorySourceFunction(item:Object):Texture + { + return StandardIcons.listDrillDownAccessoryTexture; + } + + private function removedFromStageHandler(event:starling.events.Event):void + { + this.cleanUpLoader(); + } + + private function transitionInCompleteHandler(event:starling.events.Event):void + { + this._list.selectedIndex = -1; + this._list.addEventListener(starling.events.Event.CHANGE, list_changeHandler); + + this._list.revealScrollBars(); + } + + private function list_changeHandler(event:starling.events.Event):void + { + this.dispatchEventWith(LIST_VIDEOS, false, + { + //we're going to save the position of the list so that when the user + //navigates back to this screen, they won't need to scroll back to + //the same position manually + savedVerticalScrollPosition: this._list.verticalScrollPosition, + //we'll also save the selected index to temporarily highlight + //the previously selected item when transitioning back + savedSelectedIndex: this._list.selectedIndex, + //and we'll save the data provider so that we don't need to reload + //data when we return to this screen. we can restore it. + savedDataProvider: this._list.dataProvider + }); + } + + private function loader_completeHandler(event:flash.events.Event):void + { + try + { + var loaderData:* = this._loader.data; + this.parseFeed(new XML(loaderData)); + } + catch(error:Error) + { + this._message.text = "Unable to load data. Please try again later."; + this._message.visible = true; + this.invalidate(INVALIDATION_FLAG_STYLES); + trace(error.toString()); + } + this.cleanUpLoader(); + } + + private function loader_errorHandler(event:ErrorEvent):void + { + this.cleanUpLoader(); + this._message.text = "Unable to load data. Please try again later."; + this._message.visible = true; + this.invalidate(INVALIDATION_FLAG_STYLES); + trace(event.toString()); + } + } +} diff --git a/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/VideoDetailsScreen.as b/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/VideoDetailsScreen.as new file mode 100644 index 0000000000..c587c7a322 --- /dev/null +++ b/examples/YouTubeFeeds/source/feathers/examples/youtube/screens/VideoDetailsScreen.as @@ -0,0 +1,131 @@ +package feathers.examples.youtube.screens +{ + import feathers.controls.Button; + import feathers.controls.Header; + import feathers.controls.PanelScreen; + import feathers.controls.ScrollText; + import feathers.events.FeathersEventType; + import feathers.examples.youtube.models.YouTubeModel; + import feathers.layout.AnchorLayout; + import feathers.layout.AnchorLayoutData; + + import flash.net.URLRequest; + import flash.net.navigateToURL; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Event(name="complete",type="starling.events.Event")] + + public class VideoDetailsScreen extends PanelScreen + { + public function VideoDetailsScreen() + { + super(); + } + + private var _backButton:Button; + private var _watchButton:Button; + private var _scrollText:ScrollText; + + private var _model:YouTubeModel; + + public function get model():YouTubeModel + { + return this._model; + } + + public function set model(value:YouTubeModel):void + { + if(this._model == value) + { + return; + } + this._model = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + override protected function initialize():void + { + //never forget to call super.initialize() + super.initialize(); + + this.layout = new AnchorLayout(); + + this._scrollText = new ScrollText(); + this._scrollText.isHTML = true; + this._scrollText.verticalScrollPolicy = ScrollText.SCROLL_POLICY_ON; + this._scrollText.layoutData = new AnchorLayoutData(0, 0, 0, 0); + this.addChild(this._scrollText); + + this.headerFactory = this.customHeaderFactory; + + this.backButtonHandler = onBackButton; + + this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); + } + + private function customHeaderFactory():Header + { + var header:Header = new Header(); + + this._backButton = new Button(); + this._backButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_BACK_BUTTON); + this._backButton.label = "Back"; + this._backButton.addEventListener(Event.TRIGGERED, onBackButton); + header.leftItems = new + [ + this._backButton + ]; + + this._watchButton = new Button(); + this._watchButton.label = "Watch"; + this._watchButton.addEventListener(Event.TRIGGERED, watchButton_triggeredHandler); + header.rightItems = new + [ + this._watchButton + ]; + + return header; + } + + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + if(dataInvalid) + { + if(this._model && this._model.selectedVideo) + { + this.title = this._model.selectedVideo.title; + var content:String = '

    ' + this._model.selectedVideo.title + '

    '; + content += '

    ' + this._model.selectedVideo.author + '


    '; + content += this._model.selectedVideo.description.replace(/\r\n/g, "
    "); + this._scrollText.text = content; + } + else + { + this.title = null; + this._scrollText.text = ""; + } + } + + //never forget to call super.draw()! + super.draw(); + } + + private function onBackButton(event:Event = null):void + { + this.dispatchEventWith(Event.COMPLETE); + } + + private function transitionInCompleteHandler(event:Event):void + { + this.revealScrollBars(); + } + + private function watchButton_triggeredHandler(event:Event):void + { + navigateToURL(new URLRequest(this._model.selectedVideo.url), "_blank"); + } + } +} diff --git a/examples/build.xml b/examples/build.xml new file mode 100644 index 0000000000..69f3212edd --- /dev/null +++ b/examples/build.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/icons/Default-568h@2x.png b/examples/icons/Default-568h@2x.png new file mode 100644 index 0000000000..9a7a8efefb Binary files /dev/null and b/examples/icons/Default-568h@2x.png differ diff --git a/examples/icons/Default-Landscape.png b/examples/icons/Default-Landscape.png new file mode 100644 index 0000000000..00840d548b Binary files /dev/null and b/examples/icons/Default-Landscape.png differ diff --git a/examples/icons/Default-Landscape@2x.png b/examples/icons/Default-Landscape@2x.png new file mode 100644 index 0000000000..a5e5d3eb39 Binary files /dev/null and b/examples/icons/Default-Landscape@2x.png differ diff --git a/examples/icons/Default-Portrait.png b/examples/icons/Default-Portrait.png new file mode 100644 index 0000000000..0c5bd0cc02 Binary files /dev/null and b/examples/icons/Default-Portrait.png differ diff --git a/examples/icons/Default-Portrait@2x.png b/examples/icons/Default-Portrait@2x.png new file mode 100644 index 0000000000..1a26f4317e Binary files /dev/null and b/examples/icons/Default-Portrait@2x.png differ diff --git a/examples/icons/Default.png b/examples/icons/Default.png new file mode 100644 index 0000000000..0e999f24c7 Binary files /dev/null and b/examples/icons/Default.png differ diff --git a/examples/icons/Default@2x.png b/examples/icons/Default@2x.png new file mode 100644 index 0000000000..98d51b46e0 Binary files /dev/null and b/examples/icons/Default@2x.png differ diff --git a/examples/icons/icon100.png b/examples/icons/icon100.png new file mode 100644 index 0000000000..537e725373 Binary files /dev/null and b/examples/icons/icon100.png differ diff --git a/examples/icons/icon114.png b/examples/icons/icon114.png new file mode 100644 index 0000000000..d717d58ee3 Binary files /dev/null and b/examples/icons/icon114.png differ diff --git a/examples/icons/icon128.png b/examples/icons/icon128.png new file mode 100644 index 0000000000..00d6a82de5 Binary files /dev/null and b/examples/icons/icon128.png differ diff --git a/examples/icons/icon144.png b/examples/icons/icon144.png new file mode 100644 index 0000000000..ab455d6e0d Binary files /dev/null and b/examples/icons/icon144.png differ diff --git a/examples/icons/icon29.png b/examples/icons/icon29.png new file mode 100644 index 0000000000..58f8fc17ca Binary files /dev/null and b/examples/icons/icon29.png differ diff --git a/examples/icons/icon48.png b/examples/icons/icon48.png new file mode 100644 index 0000000000..1cc719a194 Binary files /dev/null and b/examples/icons/icon48.png differ diff --git a/examples/icons/icon50.png b/examples/icons/icon50.png new file mode 100644 index 0000000000..8e7d1aaebf Binary files /dev/null and b/examples/icons/icon50.png differ diff --git a/examples/icons/icon57.png b/examples/icons/icon57.png new file mode 100644 index 0000000000..7cc86b9548 Binary files /dev/null and b/examples/icons/icon57.png differ diff --git a/examples/icons/icon58.png b/examples/icons/icon58.png new file mode 100644 index 0000000000..282f748084 Binary files /dev/null and b/examples/icons/icon58.png differ diff --git a/examples/icons/icon72.png b/examples/icons/icon72.png new file mode 100644 index 0000000000..410c3e2084 Binary files /dev/null and b/examples/icons/icon72.png differ diff --git a/examples/icons/icon96.png b/examples/icons/icon96.png new file mode 100644 index 0000000000..fe82eaf620 Binary files /dev/null and b/examples/icons/icon96.png differ diff --git a/mxml-manifest.xml b/mxml-manifest.xml new file mode 100644 index 0000000000..21bfc30dde --- /dev/null +++ b/mxml-manifest.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package-descriptions.xml b/package-descriptions.xml new file mode 100644 index 0000000000..76d375f1f9 --- /dev/null +++ b/package-descriptions.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk.properties b/sdk.properties index 4103d20c72..d970e44c18 100644 --- a/sdk.properties +++ b/sdk.properties @@ -1,18 +1,24 @@ -# The location of the Flex SDK. +# The location of the AIR SDK with ASC 2.0 +airsdk.root = /Users/joshtynjala/Development/Flash/sdks/AIR15.0.0.356 +airsdk.bin = ${airsdk.root}/bin +airsdk.lib = ${airsdk.root}/lib +airsdk.config = ${airsdk.root}/frameworks/flex-config.xml +airsdk.framework = ${airsdk.root}/frameworks + +# path to compiler jars +asdoc = ${airsdk.lib}/legacy/asdoc.jar +compc = ${airsdk.lib}/compc-cli.jar +mxmlc = ${airsdk.lib}/mxmlc-cli.jar +adt = ${airsdk.lib}/adt.jar + +# The location of the Flex SDK, to build Feathers with MXML support. # Override flexsdk.root in sdk.local.properties (create that file if it # doesn't already exist). -flexsdk.root = C:/Users/Josh/Development/Flex/sdks/4.6.0.23201B_AIR3.2 +flexsdk.root = C:/Users/Josh Tynjala/Development/Flex/sdks/4.6.0.23201B_AIR15.0 flexsdk.lib = ${flexsdk.root}/lib flexframework.root = ${flexsdk.root}/frameworks flexframework.lib = ${flexframework.root}/libs -flexframework.rsls = ${flexframework.root}/rsls +flex.compc = ${flexsdk.lib}/compc.jar -# The location of the AIR SDK. May be different than the Flex SDK. -airsdk.root = ${flexsdk.root} -airsdk.lib = ${airsdk.root}/lib - -# path to compiler jars -asdoc = ${flexsdk.lib}/asdoc.jar -compc = ${flexsdk.lib}/compc.jar -mxmlc = ${flexsdk.lib}/mxmlc.jar -adt = ${airsdk.lib}/adt.jar \ No newline at end of file +# The location of the pandoc tool used to generate the help files +pandoc = /usr/local/bin/pandoc \ No newline at end of file diff --git a/source/feathers/controls/Alert.as b/source/feathers/controls/Alert.as new file mode 100644 index 0000000000..74927550bc --- /dev/null +++ b/source/feathers/controls/Alert.as @@ -0,0 +1,996 @@ +/* +Feathers +Copyright 2012-2014 Joshua Tynjala. All Rights Reserved. + +This program is free software. You can redistribute and/or modify it in +accordance with the terms of the accompanying license agreement. +*/ +package feathers.controls +{ + import feathers.core.FeathersControl; + import feathers.core.IFeathersControl; + import feathers.core.ITextRenderer; + import feathers.core.IValidating; + import feathers.core.PopUpManager; + import feathers.core.PropertyProxy; + import feathers.data.ListCollection; + import feathers.layout.VerticalLayout; + import feathers.skins.IStyleProvider; + + import starling.display.DisplayObject; + import starling.events.Event; + + [Exclude(name="layout",kind="property")] + [Exclude(name="footer",kind="property")] + [Exclude(name="footerFactory",kind="property")] + [Exclude(name="footerProperties",kind="property")] + [Exclude(name="customFooterName",kind="property")] + [Exclude(name="customFooterStyleName",kind="property")] + [Exclude(name="createFooter",kind="method")] + + /** + * Dispatched when the alert is closed. The data property of + * the event object will contain the item from the ButtonGroup + * data provider for the button that is triggered. If no button is + * triggered, then the data property will be null. + * + *

    The properties of the event object have the following values:

    + * + * + * + * + * + * + *
    PropertyValue
    bubblesfalse
    currentTargetThe Object that defines the + * event listener that handles the event. For example, if you use + * myButton.addEventListener() to register an event listener, + * myButton is the value of the currentTarget.
    datanull
    targetThe Object that dispatched the event; + * it is not always the Object listening for the event. Use the + * currentTarget property to always access the Object + * listening for the event.
    + * + * @eventType starling.events.Event.CLOSE + */ + [Event(name="close",type="starling.events.Event")] + + /** + * Displays a message in a modal pop-up with a title and a set of buttons. + * + *

    In general, an Alert isn't instantiated directly. + * Instead, you will typically call the static function + * Alert.show(). This is not required, but it result in less + * code and no need to manually manage calls to the PopUpManager.

    + * + *

    In the following example, an alert is shown when a Button + * is triggered:

    + * + * + * button.addEventListener( Event.TRIGGERED, button_triggeredHandler ); + * + * function button_triggeredHandler( event:Event ):void + * { + * var alert:Alert = Alert.show( "This is an alert!", "Hello World", new ListCollection( + * [ + * { label: "OK" } + * ]); + * } + * + * @see ../../../help/alert.html How to use the Feathers Alert component + */ + public class Alert extends Panel + { + /** + * The default value added to the styleNameList of the header. + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const DEFAULT_CHILD_STYLE_NAME_HEADER:String = "feathers-alert-header"; + + /** + * DEPRECATED: Replaced by Alert.DEFAULT_CHILD_STYLE_NAME_HEADER. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Alert#DEFAULT_CHILD_STYLE_NAME_HEADER + */ + public static const DEFAULT_CHILD_NAME_HEADER:String = DEFAULT_CHILD_STYLE_NAME_HEADER; + + /** + * The default value added to the styleNameList of the button group. + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP:String = "feathers-alert-button-group"; + + /** + * DEPRECATED: Replaced by Alert.DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Alert#DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP + */ + public static const DEFAULT_CHILD_NAME_BUTTON_GROUP:String = DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP; + + /** + * The default value added to the styleNameList of the message. + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const DEFAULT_CHILD_STYLE_NAME_MESSAGE:String = "feathers-alert-message"; + + /** + * DEPRECATED: Replaced by Alert.DEFAULT_CHILD_STYLE_NAME_MESSAGE. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Alert#DEFAULT_CHILD_STYLE_NAME_MESSAGE + */ + public static const DEFAULT_CHILD_NAME_MESSAGE:String = DEFAULT_CHILD_STYLE_NAME_MESSAGE; + + /** + * Returns a new Alert instance when Alert.show() + * is called. If one wishes to skin the alert manually, a custom factory + * may be provided. + * + *

    This function is expected to have the following signature:

    + * + *
    function():Alert
    + * + *

    The following example shows how to create a custom alert factory:

    + * + * + * Alert.alertFactory = function():Alert + * { + * var alert:Alert = new Alert(); + * //set properties here! + * return alert; + * }; + * + * @see #show() + */ + public static var alertFactory:Function = defaultAlertFactory; + + /** + * Returns an overlay to display with a alert that is modal. Uses the + * standard overlayFactory of the PopUpManager + * by default, but you can use this property to provide your own custom + * overlay, if you prefer. + * + *

    This function is expected to have the following signature:

    + *
    function():DisplayObject
    + * + *

    The following example uses a semi-transparent Quad as + * a custom overlay:

    + * + * + * Alert.overlayFactory = function():Quad + * { + * var quad:Quad = new Quad(10, 10, 0x000000); + * quad.alpha = 0.75; + * return quad; + * }; + * + * @see feathers.core.PopUpManager#overlayFactory + * + * @see #show() + */ + public static var overlayFactory:Function; + + /** + * The default IStyleProvider for all Alert + * components. + * + * @default null + * @see feathers.core.FeathersControl#styleProvider + */ + public static var globalStyleProvider:IStyleProvider; + + /** + * The default factory that creates alerts when Alert.show() + * is called. To use a different factory, you need to set + * Alert.alertFactory to a Function + * instance. + * + * @see #show() + * @see #alertFactory + */ + public static function defaultAlertFactory():Alert + { + return new Alert(); + } + + /** + * Creates an alert, sets common properties, and adds it to the + * PopUpManager with the specified modal and centering + * options. + * + *

    In the following example, an alert is shown when a + * Button is triggered:

    + * + * + * button.addEventListener( Event.TRIGGERED, button_triggeredHandler ); + * + * function button_triggeredHandler( event:Event ):void + * { + * var alert:Alert = Alert.show( "This is an alert!", "Hello World", new ListCollection( + * [ + * { label: "OK" } + * ]); + * } + */ + public static function show(message:String, title:String = null, buttons:ListCollection = null, + icon:DisplayObject = null, isModal:Boolean = true, isCentered:Boolean = true, + customAlertFactory:Function = null, customOverlayFactory:Function = null):Alert + { + var factory:Function = customAlertFactory; + if(factory == null) + { + factory = alertFactory != null ? alertFactory : defaultAlertFactory; + } + var alert:Alert = Alert(factory()); + alert.title = title; + alert.message = message; + alert.buttonsDataProvider = buttons; + alert.icon = icon; + factory = customOverlayFactory; + if(factory == null) + { + factory = overlayFactory; + } + PopUpManager.addPopUp(alert, isModal, isCentered, factory); + return alert; + } + + /** + * @private + */ + protected static function defaultButtonGroupFactory():ButtonGroup + { + return new ButtonGroup(); + } + + /** + * Constructor. + */ + public function Alert() + { + super(); + this.headerName = DEFAULT_CHILD_STYLE_NAME_HEADER; + this.footerName = DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP; + this.buttonGroupFactory = defaultButtonGroupFactory; + } + + /** + * The value added to the styleNameList of the alert's + * message text renderer. This variable is protected so + * that sub-classes can customize the message style name in their + * constructors instead of using the default style name defined by + * DEFAULT_CHILD_STYLE_NAME_MESSAGE. + * + * @see feathers.core.FeathersControl#styleNameList + */ + protected var messageStyleName:String = DEFAULT_CHILD_STYLE_NAME_MESSAGE; + + /** + * DEPRECATED: Replaced by messageStyleName. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see #messageStyleName + */ + protected function get messageName():String + { + return this.messageStyleName; + } + + /** + * @private + */ + protected function set messageName(value:String):void + { + this.messageStyleName = value; + } + + /** + * The header sub-component. + * + *

    For internal use in subclasses.

    + */ + protected var headerHeader:Header; + + /** + * The button group sub-component. + * + *

    For internal use in subclasses.

    + */ + protected var buttonGroupFooter:ButtonGroup; + + /** + * The message text renderer sub-component. + * + *

    For internal use in subclasses.

    + */ + protected var messageTextRenderer:ITextRenderer; + + /** + * @private + */ + override protected function get defaultStyleProvider():IStyleProvider + { + return Alert.globalStyleProvider; + } + + /** + * @private + */ + protected var _message:String = null; + + /** + * The alert's main text content. + */ + public function get message():String + { + return this._message; + } + + /** + * @private + */ + public function set message(value:String):void + { + if(this._message == value) + { + return; + } + this._message = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + /** + * @private + */ + protected var _icon:DisplayObject; + + /** + * The alert's optional icon content to display next to the text. + */ + public function get icon():DisplayObject + { + return this._icon; + } + + /** + * @private + */ + public function set icon(value:DisplayObject):void + { + if(this._icon == value) + { + return; + } + var oldDisplayListBypassEnabled:Boolean = this.displayListBypassEnabled; + this.displayListBypassEnabled = false; + if(this._icon) + { + this.removeChild(this._icon); + } + this._icon = value; + if(this._icon) + { + this.addChild(this._icon); + } + this.displayListBypassEnabled = oldDisplayListBypassEnabled; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + /** + * @private + */ + protected var _gap:Number = 0; + + /** + * The space, in pixels, between the alert's icon and its message text + * renderer. + * + *

    In the following example, the gap is set to 20 pixels:

    + * + * + * alert.gap = 20; + * + * @default 0 + */ + public function get gap():Number + { + return this._gap; + } + + /** + * @private + */ + public function set gap(value:Number):void + { + if(this._gap == value) + { + return; + } + this._gap = value; + this.invalidate(INVALIDATION_FLAG_LAYOUT); + } + + /** + * @private + */ + protected var _buttonsDataProvider:ListCollection; + + /** + * The data provider of the alert's ButtonGroup. + */ + public function get buttonsDataProvider():ListCollection + { + return this._buttonsDataProvider; + } + + /** + * @private + */ + public function set buttonsDataProvider(value:ListCollection):void + { + if(this._buttonsDataProvider == value) + { + return; + } + this._buttonsDataProvider = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _messageFactory:Function; + + /** + * A function used to instantiate the alert's message text renderer + * sub-component. By default, the alert will use the global text + * renderer factory, FeathersControl.defaultTextRendererFactory(), + * to create the message text renderer. The message text renderer must + * be an instance of ITextRenderer. This factory can be + * used to change properties on the message text renderer when it is + * first created. For instance, if you are skinning Feathers components + * without a theme, you might use this factory to style the message text + * renderer. + * + *

    If you are not using a theme, the message factory can be used to + * provide skin the message text renderer with appropriate text styles.

    + * + *

    The factory should have the following function signature:

    + *
    function():ITextRenderer
    + * + *

    In the following example, a custom message factory is passed to + * the alert:

    + * + * + * alert.messageFactory = function():ITextRenderer + * { + * var messageRenderer:TextFieldTextRenderer = new TextFieldTextRenderer(); + * messageRenderer.textFormat = new TextFormat( "_sans", 12, 0xff0000 ); + * return messageRenderer; + * } + * + * @default null + * + * @see #message + * @see feathers.core.ITextRenderer + * @see feathers.core.FeathersControl#defaultTextRendererFactory + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + */ + public function get messageFactory():Function + { + return this._messageFactory; + } + + /** + * @private + */ + public function set messageFactory(value:Function):void + { + if(this._messageFactory == value) + { + return; + } + this._messageFactory = value; + this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER); + } + + /** + * @private + */ + protected var _messageProperties:PropertyProxy; + + /** + * A set of key/value pairs to be passed down to the alert's message + * text renderer. The message text renderer is an ITextRenderer + * instance. The available properties depend on which + * ITextRenderer implementation is returned by + * messageFactory. The most common implementations are + * BitmapFontTextRenderer and TextFieldTextRenderer. + * + *

    In the following example, some properties are set for the alert's + * message text renderer (this example assumes that the message text + * renderer is a BitmapFontTextRenderer):

    + * + * + * alert.messageProperties.textFormat = new BitmapFontTextFormat( bitmapFont ); + * alert.messageProperties.wordWrap = true; + * + *

    If the subcomponent has its own subcomponents, their properties + * can be set too, using attribute @ notation. For example, + * to set the skin on the thumb which is in a SimpleScrollBar, + * which is in a List, you can use the following syntax:

    + *
    list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
    + * + *

    Setting properties in a messageFactory function instead + * of using messageProperties will result in better + * performance.

    + * + * @default null + * + * @see #messageFactory + * @see feathers.core.ITextRenderer + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + */ + public function get messageProperties():Object + { + if(!this._messageProperties) + { + this._messageProperties = new PropertyProxy(childProperties_onChange); + } + return this._messageProperties; + } + + /** + * @private + */ + public function set messageProperties(value:Object):void + { + if(this._messageProperties == value) + { + return; + } + if(value && !(value is PropertyProxy)) + { + value = PropertyProxy.fromObject(value); + } + if(this._messageProperties) + { + this._messageProperties.removeOnChangeCallback(childProperties_onChange); + } + this._messageProperties = PropertyProxy(value); + if(this._messageProperties) + { + this._messageProperties.addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * A function used to generate the alerts's button group sub-component. + * The button group must be an instance of ButtonGroup. + * This factory can be used to change properties on the button group + * when it is first created. For instance, if you are skinning Feathers + * components without a theme, you might use this factory to set skins + * and other styles on the button group. + * + *

    The function should have the following signature:

    + *
    function():ButtonGroup
    + * + *

    In the following example, a custom button group factory is + * provided to the alert:

    + * + * + * alert.buttonGroupFactory = function():ButtonGroup + * { + * return new ButtonGroup(); + * }; + * + * @default null + * + * @see feathers.controls.ButtonGroup + * @see #buttonGroupProperties + */ + public function get buttonGroupFactory():Function + { + return super.footerFactory; + } + + /** + * @private + */ + public function set buttonGroupFactory(value:Function):void + { + super.footerFactory = value; + } + + /** + * A style name to add to the alert's button group sub-component. + * Typically used by a theme to provide different styles to different alerts. + * + *

    In the following example, a custom button group style name is + * passed to the alert:

    + * + * + * alert.customButtonGroupStyleName = "my-custom-button-group"; + * + *

    In your theme, you can target this sub-component style name to + * provide different styles than the default:

    + * + * + * getStyleProviderForClass( ButtonGroup ).setFunctionForStyleName( "my-custom-button-group", setCustomButtonGroupStyles ); + * + * @default null + * + * @see #DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP + * @see feathers.core.FeathersControl#styleNameList + * @see #buttonGroupFactory + * @see #buttonGroupProperties + */ + public function get customButtonGroupStyleName():String + { + return super.customFooterStyleName; + } + + /** + * @private + */ + public function set customButtonGroupStyleName(value:String):void + { + super.customFooterStyleName = value; + } + + /** + * DEPRECATED: Replaced by customButtonGroupStyleName. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see #customButtonGroupStyleName + */ + public function get customButtonGroupName():String + { + return this.customButtonGroupStyleName; + } + + /** + * @private + */ + public function set customButtonGroupName(value:String):void + { + this.customButtonGroupStyleName = value; + } + + /** + * A set of key/value pairs to be passed down to the alert's button + * group sub-component. The button must be a + * feathers.core.ButtonGroup instance. + * + *

    If the subcomponent has its own subcomponents, their properties + * can be set too, using attribute @ notation. For example, + * to set the skin on the thumb which is in a SimpleScrollBar, + * which is in a List, you can use the following syntax:

    + *
    list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
    + * + *

    Setting properties in a buttonGroupFactory function + * instead of using buttonGroupProperties will result in better + * performance.

    + * + *

    In the following example, the button group properties are customized:

    + * + * + * alert.buttonGroupProperties.gap = 20; + * + * @default null + * + * @see #buttonGroupFactory + * @see feathers.controls.ButtonGroup + */ + public function get buttonGroupProperties():Object + { + return super.footerProperties; + } + + /** + * @private + */ + public function set buttonGroupProperties(value:Object):void + { + super.footerProperties = value; + } + + /** + * @private + */ + override protected function initialize():void + { + if(!this.layout) + { + var layout:VerticalLayout = new VerticalLayout(); + layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_JUSTIFY; + this.layout = layout; + } + super.initialize(); + } + + /** + * @private + */ + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES) + var textRendererInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_TEXT_RENDERER); + + if(textRendererInvalid) + { + this.createMessage(); + } + + if(textRendererInvalid || dataInvalid) + { + this.messageTextRenderer.text = this._message; + } + + if(textRendererInvalid || stylesInvalid) + { + this.refreshMessageStyles(); + } + + super.draw(); + + if(this._icon) + { + if(this._icon is IValidating) + { + IValidating(this._icon).validate(); + } + this._icon.x = this._paddingLeft; + this._icon.y = this._topViewPortOffset + (this._viewPort.height - this._icon.height) / 2; + } + } + + /** + * @private + */ + override protected function autoSizeIfNeeded():Boolean + { + var needsWidth:Boolean = this.explicitWidth !== this.explicitWidth; //isNaN + var needsHeight:Boolean = this.explicitHeight !== this.explicitHeight; //isNaN + if(!needsWidth && !needsHeight) + { + return false; + } + + if(this._icon is IValidating) + { + IValidating(this._icon).validate(); + } + + var oldIgnoreHeaderResizing:Boolean = this._ignoreHeaderResizing; + this._ignoreHeaderResizing = true; + var oldIgnoreFooterResizing:Boolean = this._ignoreFooterResizing; + this._ignoreFooterResizing = true; + + var oldHeaderWidth:Number = this.header.width; + var oldHeaderHeight:Number = this.header.height; + this.header.width = this.explicitWidth; + this.header.maxWidth = this._maxWidth; + this.header.height = NaN; + this.header.validate(); + + if(this.footer) + { + var oldFooterWidth:Number = this.footer.width; + var oldFooterHeight:Number = this.footer.height; + this.footer.width = this.explicitWidth; + this.footer.maxWidth = this._maxWidth; + this.footer.height = NaN; + this.footer.validate(); + } + + var newWidth:Number = this.explicitWidth; + var newHeight:Number = this.explicitHeight; + if(needsWidth) + { + newWidth = this._viewPort.width + this._rightViewPortOffset + this._leftViewPortOffset; + if(this._icon) + { + var iconWidth:Number = this._icon.width; + if(iconWidth === iconWidth) //!isNaN + { + newWidth += this._icon.width + this._gap; + } + } + newWidth = Math.max(newWidth, this.header.width); + if(this.footer) + { + newWidth = Math.max(newWidth, this.footer.width); + } + if(this.originalBackgroundWidth === this.originalBackgroundWidth && //!isNaN + this.originalBackgroundWidth > newWidth) + { + newWidth = this.originalBackgroundWidth; + } + } + if(needsHeight) + { + newHeight = this._viewPort.height; + if(this._icon) + { + var iconHeight:Number = this._icon.height; + if(iconHeight === iconHeight) //!isNaN + { + newHeight = Math.max(newHeight, this._icon.height); + } + } + newHeight += this._bottomViewPortOffset + this._topViewPortOffset; + if(this.originalBackgroundHeight === this.originalBackgroundHeight && //!isNaN + this.originalBackgroundHeight > newHeight) + { + newHeight = this.originalBackgroundHeight; + } + } + + this.header.width = oldHeaderWidth; + this.header.height = oldHeaderHeight; + if(this.footer) + { + this.footer.width = oldFooterWidth; + this.footer.height = oldFooterHeight; + } + this._ignoreHeaderResizing = oldIgnoreHeaderResizing; + this._ignoreFooterResizing = oldIgnoreFooterResizing; + + return this.setSizeInternal(newWidth, newHeight, false); + } + + /** + * Creates and adds the header sub-component and + * removes the old instance, if one exists. + * + *

    Meant for internal use, and subclasses may override this function + * with a custom implementation.

    + * + * @see #header + * @see #headerFactory + * @see #customHeaderStyleName + */ + override protected function createHeader():void + { + super.createHeader(); + this.headerHeader = Header(this.header); + } + + /** + * Creates and adds the buttonGroupFooter sub-component and + * removes the old instance, if one exists. + * + *

    Meant for internal use, and subclasses may override this function + * with a custom implementation.

    + * + * @see #buttonGroupFooter + * @see #buttonGroupFactory + * @see #customButtonGroupStyleName + */ + protected function createButtonGroup():void + { + if(this.buttonGroupFooter) + { + this.buttonGroupFooter.removeEventListener(Event.TRIGGERED, buttonsFooter_triggeredHandler); + } + super.createFooter(); + this.buttonGroupFooter = ButtonGroup(this.footer); + this.buttonGroupFooter.addEventListener(Event.TRIGGERED, buttonsFooter_triggeredHandler); + } + + /** + * @private + */ + override protected function createFooter():void + { + this.createButtonGroup(); + } + + /** + * Creates and adds the messageTextRenderer sub-component and + * removes the old instance, if one exists. + * + *

    Meant for internal use, and subclasses may override this function + * with a custom implementation.

    + * + * @see #message + * @see #messageTextRenderer + * @see #messageFactory + */ + protected function createMessage():void + { + if(this.messageTextRenderer) + { + this.removeChild(DisplayObject(this.messageTextRenderer), true); + this.messageTextRenderer = null; + } + + var factory:Function = this._messageFactory != null ? this._messageFactory : FeathersControl.defaultTextRendererFactory; + this.messageTextRenderer = ITextRenderer(factory()); + var uiTextRenderer:IFeathersControl = IFeathersControl(this.messageTextRenderer); + uiTextRenderer.styleNameList.add(this.messageName); + uiTextRenderer.touchable = false; + this.addChild(DisplayObject(this.messageTextRenderer)); + } + + /** + * @private + */ + override protected function refreshFooterStyles():void + { + super.refreshFooterStyles(); + this.buttonGroupFooter.dataProvider = this._buttonsDataProvider; + } + + /** + * @private + */ + protected function refreshMessageStyles():void + { + for(var propertyName:String in this._messageProperties) + { + var propertyValue:Object = this._messageProperties[propertyName]; + this.messageTextRenderer[propertyName] = propertyValue; + } + } + + /** + * @private + */ + override protected function calculateViewPortOffsets(forceScrollBars:Boolean = false, useActualBounds:Boolean = false):void + { + super.calculateViewPortOffsets(forceScrollBars, useActualBounds); + if(this._icon) + { + if(this._icon is IValidating) + { + IValidating(this._icon).validate(); + } + var iconWidth:Number = this._icon.width; + if(iconWidth == iconWidth) //!isNaN + { + this._leftViewPortOffset += this._icon.width + this._gap; + } + } + } + + /** + * @private + */ + protected function buttonsFooter_triggeredHandler(event:Event, data:Object):void + { + this.removeFromParent(); + this.dispatchEventWith(Event.CLOSE, false, data); + this.dispose(); + } + + } +} diff --git a/source/feathers/controls/AutoComplete.as b/source/feathers/controls/AutoComplete.as new file mode 100644 index 0000000000..c3f4ef6176 --- /dev/null +++ b/source/feathers/controls/AutoComplete.as @@ -0,0 +1,867 @@ +/* +Feathers +Copyright 2012-2014 Joshua Tynjala. All Rights Reserved. + +This program is free software. You can redistribute and/or modify it in +accordance with the terms of the accompanying license agreement. +*/ +package feathers.controls +{ + import feathers.data.IAutoCompleteSource; + import feathers.controls.popups.DropDownPopUpContentManager; + import feathers.controls.popups.IPopUpContentManager; + import feathers.controls.renderers.IListItemRenderer; + import feathers.core.PropertyProxy; + import feathers.data.ListCollection; + import feathers.events.FeathersEventType; + import feathers.skins.IStyleProvider; + + import flash.events.KeyboardEvent; + + import flash.ui.Keyboard; + import flash.utils.getTimer; + + import starling.core.Starling; + import starling.events.Event; + import starling.events.EventDispatcher; + import starling.events.KeyboardEvent; + + /** + * Dispatched when the pop-up list is opened. + * + *

    The properties of the event object have the following values:

    + * + * + * + * + * + * + *
    PropertyValue
    bubblesfalse
    currentTargetThe Object that defines the + * event listener that handles the event. For example, if you use + * myButton.addEventListener() to register an event listener, + * myButton is the value of the currentTarget.
    datanull
    targetThe Object that dispatched the event; + * it is not always the Object listening for the event. Use the + * currentTarget property to always access the Object + * listening for the event.
    + * + * @eventType starling.events.Event.OPEN + */ + [Event(name="open",type="starling.events.Event")] + + /** + * Dispatched when the pop-up list is closed. + * + *

    The properties of the event object have the following values:

    + * + * + * + * + * + * + *
    PropertyValue
    bubblesfalse
    currentTargetThe Object that defines the + * event listener that handles the event. For example, if you use + * myButton.addEventListener() to register an event listener, + * myButton is the value of the currentTarget.
    datanull
    targetThe Object that dispatched the event; + * it is not always the Object listening for the event. Use the + * currentTarget property to always access the Object + * listening for the event.
    + * + * @eventType starling.events.Event.CLOSE + */ + [Event(name="close",type="starling.events.Event")] + + /** + * A text input that provides a pop-up list with suggestions as you type. + * + * @see ../../../help/auto-complete.html How to use the Feathers AutoComplete component + * @see feathers.controls.TextInput + */ + public class AutoComplete extends TextInput + { + /** + * @private + */ + protected static const INVALIDATION_FLAG_LIST_FACTORY:String = "listFactory"; + + /** + * The default value added to the styleNameList of the pop-up + * list. + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const DEFAULT_CHILD_STYLE_NAME_LIST:String = "feathers-auto-complete-list"; + + /** + * The default IStyleProvider for all + * AutoComplete components. If null, falls + * back to using TextInput.globalStyleProvider instead. + * + * @default null + * @see feathers.core.FeathersControl#styleProvider + */ + public static var globalStyleProvider:IStyleProvider; + + /** + * @private + */ + protected static function defaultListFactory():List + { + return new List(); + } + + /** + * Constructor. + */ + public function AutoComplete() + { + this.addEventListener(Event.CHANGE, autoComplete_changeHandler); + } + + /** + * The default value added to the styleNameList of the + * pop-up list. This variable is protected so that + * sub-classes can customize the list style name in their constructors + * instead of using the default style name defined by + * DEFAULT_CHILD_STYLE_NAME_LIST. + * + *

    To customize the pop-up list name without subclassing, see + * customListStyleName.

    + * + * @see #customListStyleName + * @see feathers.core.FeathersControl#styleNameList + */ + protected var listStyleName:String = DEFAULT_CHILD_STYLE_NAME_LIST; + + /** + * The list sub-component. + * + *

    For internal use in subclasses.

    + * + * @see #listFactory + * @see #createList() + */ + protected var list:List; + + /** + * @private + */ + protected var _listCollection:ListCollection; + + /** + * @private + */ + override protected function get defaultStyleProvider():IStyleProvider + { + if(AutoComplete.globalStyleProvider) + { + return AutoComplete.globalStyleProvider; + } + return TextInput.globalStyleProvider; + } + + /** + * @private + */ + protected var _originalText:String; + + /** + * @private + */ + protected var _source:IAutoCompleteSource; + + /** + * The source of the suggestions that appear in the pop-up list. + */ + public function get source():IAutoCompleteSource + { + return this._source; + } + + /** + * @private + */ + public function set source(value:IAutoCompleteSource):void + { + if(this._source == value) + { + return; + } + if(this._source) + { + this._source.removeEventListener(Event.COMPLETE, dataProvider_completeHandler); + } + this._source = value; + if(this._source) + { + this._source.addEventListener(Event.COMPLETE, dataProvider_completeHandler); + } + } + + /** + * @private + */ + protected var _autoCompleteDelay:Number = 0.5; + + /** + * The time, in seconds, after the text has changed before requesting + * suggestions from the IAutoCompleteSource. + * + * @default 0.5 + * + * @see #source + */ + public function get autoCompleteDelay():Number + { + return this._autoCompleteDelay; + } + + /** + * @private + */ + public function set autoCompleteDelay(value:Number):void + { + this._autoCompleteDelay = value; + } + + /** + * @private + */ + protected var _minimumAutoCompleteLength:int = 2; + + /** + * The minimum number of entered characters required to request + * suggestions from the IAutoCompleteSource. + * + * @default 2 + * + * @see #source + */ + public function get minimumAutoCompleteLength():Number + { + return this._minimumAutoCompleteLength; + } + + /** + * @private + */ + public function set minimumAutoCompleteLength(value:Number):void + { + this._minimumAutoCompleteLength = value; + } + + /** + * @private + */ + protected var _popUpContentManager:IPopUpContentManager; + + /** + * A manager that handles the details of how to display the pop-up list. + * + *

    In the following example, a pop-up content manager is provided:

    + * + * + * list.popUpContentManager = new CalloutPopUpContentManager(); + * + * @default null + */ + public function get popUpContentManager():IPopUpContentManager + { + return this._popUpContentManager; + } + + /** + * @private + */ + public function set popUpContentManager(value:IPopUpContentManager):void + { + if(this._popUpContentManager == value) + { + return; + } + if(this._popUpContentManager is EventDispatcher) + { + var dispatcher:EventDispatcher = EventDispatcher(this._popUpContentManager); + dispatcher.removeEventListener(Event.OPEN, popUpContentManager_openHandler); + dispatcher.removeEventListener(Event.CLOSE, popUpContentManager_closeHandler); + } + this._popUpContentManager = value; + if(this._popUpContentManager is EventDispatcher) + { + dispatcher = EventDispatcher(this._popUpContentManager); + dispatcher.addEventListener(Event.OPEN, popUpContentManager_openHandler); + dispatcher.addEventListener(Event.CLOSE, popUpContentManager_closeHandler); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _listFactory:Function; + + /** + * A function used to generate the picker list's pop-up list + * sub-component. The list must be an instance of List. + * This factory can be used to change properties on the list when it is + * first created. For instance, if you are skinning Feathers components + * without a theme, you might use this factory to set skins and other + * styles on the list. + * + *

    The function should have the following signature:

    + *
    function():List
    + * + *

    In the following example, a custom list factory is passed to the + * picker list:

    + * + * + * list.listFactory = function():List + * { + * var popUpList:List = new List(); + * popUpList.backgroundSkin = new Image( texture ); + * return popUpList; + * }; + * + * @default null + * + * @see feathers.controls.List + * @see #listProperties + */ + public function get listFactory():Function + { + return this._listFactory; + } + + /** + * @private + */ + public function set listFactory(value:Function):void + { + if(this._listFactory == value) + { + return; + } + this._listFactory = value; + this.invalidate(INVALIDATION_FLAG_LIST_FACTORY); + } + + /** + * @private + */ + protected var _customListStyleName:String; + + /** + * A style name to add to the picker list's list sub-component. + * Typically used by a theme to provide different styles to different + * picker lists. + * + *

    In the following example, a custom list style name is passed to the + * picker list:

    + * + * + * list.customListStyleName = "my-custom-list"; + * + *

    In your theme, you can target this sub-component style name to provide + * different styles than the default:

    + * + * + * getStyleProviderForClass( List ).setFunctionForStyleName( "my-custom-list", setCustomListStyles ); + * + * @default null + * + * @see #DEFAULT_CHILD_STYLE_NAME_LIST + * @see feathers.core.FeathersControl#styleNameList + * @see #listFactory + * @see #listProperties + */ + public function get customListStyleName():String + { + return this._customListStyleName; + } + + /** + * @private + */ + public function set customListStyleName(value:String):void + { + if(this._customListStyleName == value) + { + return; + } + this._customListStyleName = value; + this.invalidate(INVALIDATION_FLAG_LIST_FACTORY); + } + + /** + * @private + */ + protected var _listProperties:PropertyProxy; + + /** + * A set of key/value pairs to be passed down to the picker's pop-up + * list sub-component. The pop-up list is a + * feathers.controls.List instance that is created by + * listFactory. + * + *

    If the subcomponent has its own subcomponents, their properties + * can be set too, using attribute @ notation. For example, + * to set the skin on the thumb which is in a SimpleScrollBar, + * which is in a List, you can use the following syntax:

    + *
    list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
    + * + *

    Setting properties in a listFactory function + * instead of using listProperties will result in better + * performance.

    + * + *

    In the following example, the list properties are passed to the + * auto complete:

    + * + * + * input.listProperties.backgroundSkin = new Image( texture ); + * + * @default null + * + * @see #listFactory + * @see feathers.controls.List + */ + public function get listProperties():Object + { + if(!this._listProperties) + { + this._listProperties = new PropertyProxy(childProperties_onChange); + } + return this._listProperties; + } + + /** + * @private + */ + public function set listProperties(value:Object):void + { + if(this._listProperties == value) + { + return; + } + if(!value) + { + value = new PropertyProxy(); + } + if(!(value is PropertyProxy)) + { + var newValue:PropertyProxy = new PropertyProxy(); + for(var propertyName:String in value) + { + newValue[propertyName] = value[propertyName]; + } + value = newValue; + } + if(this._listProperties) + { + this._listProperties.removeOnChangeCallback(childProperties_onChange); + } + this._listProperties = PropertyProxy(value); + if(this._listProperties) + { + this._listProperties.addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _ignoreAutoCompleteChanges:Boolean = false; + + /** + * @private + */ + protected var _lastChangeTime:int = 0; + + /** + * @private + */ + protected var _listHasFocus:Boolean = false; + + /** + * @private + */ + protected var _isOpenListPending:Boolean = false; + + /** + * @private + */ + protected var _isCloseListPending:Boolean = false; + + /** + * Opens the pop-up list, if it isn't already open. + */ + public function openList():void + { + this._isCloseListPending = false; + if(this._popUpContentManager.isOpen) + { + return; + } + if(!this._isValidating && this.isInvalid()) + { + this._isOpenListPending = true; + return; + } + this._isOpenListPending = false; + this._popUpContentManager.open(this.list, this); + this.list.validate(); + if(this._focusManager) + { + this.stage.addEventListener(starling.events.KeyboardEvent.KEY_UP, stage_keyUpHandler); + } + } + + /** + * Closes the pop-up list, if it is open. + */ + public function closeList():void + { + this._isOpenListPending = false; + if(!this._popUpContentManager.isOpen) + { + return; + } + if(!this._isValidating && this.isInvalid()) + { + this._isCloseListPending = true; + return; + } + if(this._listHasFocus) + { + this.list.dispatchEventWith(FeathersEventType.FOCUS_OUT); + } + this._isCloseListPending = false; + this.list.validate(); + //don't clean up anything from openList() in closeList(). The list + //may be closed by removing it from the PopUpManager, which would + //result in closeList() never being called. + //instead, clean up in the Event.REMOVED_FROM_STAGE listener. + this._popUpContentManager.close(); + } + + /** + * @inheritDoc + */ + override public function dispose():void + { + this.source = null; + if(this.list) + { + this.closeList(); + this.list.dispose(); + this.list = null; + } + if(this._popUpContentManager) + { + this._popUpContentManager.dispose(); + this._popUpContentManager = null; + } + super.dispose(); + } + + /** + * @private + */ + override protected function initialize():void + { + super.initialize(); + + this._listCollection = new ListCollection(); + if(!this._popUpContentManager) + { + this.popUpContentManager = new DropDownPopUpContentManager(); + } + } + + /** + * @private + */ + override protected function draw():void + { + var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES); + var listFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_LIST_FACTORY); + + super.draw(); + + if(listFactoryInvalid) + { + this.createList(); + } + + if(listFactoryInvalid || stylesInvalid) + { + this.refreshListProperties(); + } + + this.handlePendingActions(); + } + + /** + * Creates and adds the list sub-component and + * removes the old instance, if one exists. + * + *

    Meant for internal use, and subclasses may override this function + * with a custom implementation.

    + * + * @see #list + * @see #listFactory + * @see #customListStyleName + */ + protected function createList():void + { + if(this.list) + { + this.list.removeFromParent(false); + //disposing separately because the list may not have a parent + this.list.dispose(); + this.list = null; + } + + var factory:Function = this._listFactory != null ? this._listFactory : defaultListFactory; + var listStyleName:String = this._customListStyleName != null ? this._customListStyleName : this.listStyleName; + this.list = List(factory()); + this.list.focusOwner = this; + this.list.isFocusEnabled = false; + this.list.isChildFocusEnabled = false; + this.list.styleNameList.add(listStyleName); + this.list.addEventListener(Event.CHANGE, list_changeHandler); + this.list.addEventListener(Event.TRIGGERED, list_triggeredHandler); + this.list.addEventListener(Event.REMOVED_FROM_STAGE, list_removedFromStageHandler); + } + + /** + * @private + */ + protected function refreshListProperties():void + { + for(var propertyName:String in this._listProperties) + { + var propertyValue:Object = this._listProperties[propertyName]; + this.list[propertyName] = propertyValue; + } + } + + /** + * @private + */ + protected function handlePendingActions():void + { + if(this._isOpenListPending) + { + this.openList(); + } + if(this._isCloseListPending) + { + this.closeList(); + } + } + + /** + * @private + */ + override protected function focusInHandler(event:Event):void + { + //the priority here is 1 so that this listener is called before + //starling's listener. we want to know the list's selected index + //before the list changes it. + Starling.current.nativeStage.addEventListener(flash.events.KeyboardEvent.KEY_DOWN, nativeStage_keyDownHandler, false, 1, true); + super.focusInHandler(event); + } + + /** + * @private + */ + override protected function focusOutHandler(event:Event):void + { + Starling.current.nativeStage.removeEventListener(flash.events.KeyboardEvent.KEY_DOWN, nativeStage_keyDownHandler); + super.focusOutHandler(event); + } + + /** + * @private + */ + protected function nativeStage_keyDownHandler(event:flash.events.KeyboardEvent):void + { + if(!this._popUpContentManager.isOpen) + { + return; + } + var isDown:Boolean = event.keyCode == Keyboard.DOWN; + var isUp:Boolean = event.keyCode == Keyboard.UP; + if(!isDown && !isUp) + { + return; + } + var oldSelectedIndex:int = this.list.selectedIndex; + var lastIndex:int = this.list.dataProvider.length - 1; + if(oldSelectedIndex < 0) + { + event.stopImmediatePropagation(); + this._originalText = this._text; + if(isDown) + { + this.list.selectedIndex = 0; + } + else + { + this.list.selectedIndex = lastIndex; + } + this.list.scrollToDisplayIndex(this.list.selectedIndex, this.list.keyScrollDuration); + this._listHasFocus = true; + this.list.dispatchEventWith(FeathersEventType.FOCUS_IN); + } + else if((isDown && oldSelectedIndex == lastIndex) || + (isUp && oldSelectedIndex == 0)) + { + event.stopImmediatePropagation(); + var oldIgnoreAutoCompleteChanges:Boolean = this._ignoreAutoCompleteChanges; + this._ignoreAutoCompleteChanges = true; + this.text = this._originalText; + this._ignoreAutoCompleteChanges = oldIgnoreAutoCompleteChanges; + this.list.selectedIndex = -1; + this.selectRange(this.text.length, this.text.length); + this._listHasFocus = false; + this.list.dispatchEventWith(FeathersEventType.FOCUS_OUT); + } + } + + /** + * @private + */ + protected function autoComplete_changeHandler(event:Event):void + { + if(this._ignoreAutoCompleteChanges || !this._source || !this.hasFocus) + { + return; + } + if(this.text.length < this._minimumAutoCompleteLength) + { + this.removeEventListener(Event.ENTER_FRAME, autoComplete_enterFrameHandler); + this.closeList(); + return; + } + + if(this._autoCompleteDelay == 0) + { + //just in case the enter frame listener was added before + //sourceUpdateDelay was set to 0. + this.removeEventListener(Event.ENTER_FRAME, autoComplete_enterFrameHandler); + + this._source.load(this.text, this._listCollection); + } + else + { + this._lastChangeTime = getTimer(); + this.addEventListener(Event.ENTER_FRAME, autoComplete_enterFrameHandler); + } + } + + /** + * @private + */ + protected function autoComplete_enterFrameHandler():void + { + var currentTime:int = getTimer(); + var secondsSinceLastUpdate:Number = (currentTime - this._lastChangeTime) / 1000; + if(secondsSinceLastUpdate < this._autoCompleteDelay) + { + return; + } + this.removeEventListener(Event.ENTER_FRAME, autoComplete_enterFrameHandler); + this._source.load(this.text, this._listCollection); + } + + /** + * @private + */ + protected function dataProvider_completeHandler(event:Event, data:ListCollection):void + { + this.list.dataProvider = data; + if(data.length == 0) + { + if(this._popUpContentManager.isOpen) + { + this.closeList(); + } + return; + } + this.openList(); + } + + /** + * @private + */ + protected function list_changeHandler(event:Event):void + { + if(!this.list.selectedItem) + { + return; + } + var oldIgnoreAutoCompleteChanges:Boolean = this._ignoreAutoCompleteChanges; + this._ignoreAutoCompleteChanges = true; + this.text = this.list.selectedItem.toString(); + this.selectRange(this.text.length, this.text.length); + this._ignoreAutoCompleteChanges = oldIgnoreAutoCompleteChanges; + } + + /** + * @private + */ + protected function popUpContentManager_openHandler(event:Event):void + { + this.dispatchEventWith(Event.OPEN); + } + + /** + * @private + */ + protected function popUpContentManager_closeHandler(event:Event):void + { + this.dispatchEventWith(Event.CLOSE); + } + + /** + * @private + */ + protected function list_removedFromStageHandler(event:Event):void + { + if(this._focusManager) + { + this.list.stage.removeEventListener(starling.events.KeyboardEvent.KEY_UP, stage_keyUpHandler); + } + } + + /** + * @private + */ + protected function list_triggeredHandler(event:Event):void + { + if(!this._isEnabled) + { + return; + } + this.closeList(); + this.selectRange(this.text.length, this.text.length); + } + + /** + * @private + */ + protected function stage_keyUpHandler(event:starling.events.KeyboardEvent):void + { + if(!this._popUpContentManager.isOpen) + { + return; + } + if(event.keyCode == Keyboard.ENTER) + { + this.closeList(); + this.selectRange(this.text.length, this.text.length); + } + } + } +} diff --git a/source/feathers/controls/Button.as b/source/feathers/controls/Button.as new file mode 100644 index 0000000000..33e9084e62 --- /dev/null +++ b/source/feathers/controls/Button.as @@ -0,0 +1,2996 @@ +/* +Feathers +Copyright 2012-2014 Joshua Tynjala. All Rights Reserved. + +This program is free software. You can redistribute and/or modify it in +accordance with the terms of the accompanying license agreement. +*/ +package feathers.controls +{ + import feathers.core.FeathersControl; + import feathers.core.IFeathersControl; + import feathers.core.IFocusDisplayObject; + import feathers.core.ITextRenderer; + import feathers.core.IValidating; + import feathers.core.PropertyProxy; + import feathers.events.FeathersEventType; + import feathers.skins.IStyleProvider; + import feathers.skins.StateWithToggleValueSelector; + + import flash.geom.Point; + import flash.ui.Keyboard; + import flash.utils.getTimer; + + import starling.core.RenderSupport; + + import starling.display.DisplayObject; + import starling.events.Event; + import starling.events.KeyboardEvent; + import starling.events.Touch; + import starling.events.TouchEvent; + import starling.events.TouchPhase; + + /** + * Dispatched when the the user taps or clicks the button. The touch must + * remain within the bounds of the button on release to register as a tap + * or a click. If focus management is enabled, the button may also be + * triggered by pressing the spacebar while the button has focus. + * + *

    The properties of the event object have the following values:

    + * + * + * + * + * + * + *
    PropertyValue
    bubblesfalse
    currentTargetThe Object that defines the + * event listener that handles the event. For example, if you use + * myButton.addEventListener() to register an event listener, + * myButton is the value of the currentTarget.
    datanull
    targetThe Object that dispatched the event; + * it is not always the Object listening for the event. Use the + * currentTarget property to always access the Object + * listening for the event.
    + * + * @eventType starling.events.Event.TRIGGERED + */ + [Event(name="triggered",type="starling.events.Event")] + + /** + * Dispatched when the button is pressed for a long time. The property + * isLongPressEnabled must be set to true before + * this event will be dispatched. + * + *

    The following example enables long presses:

    + * + * + * button.isLongPressEnabled = true; + * button.addEventListener( FeathersEventType.LONG_PRESS, function( event:Event ):void + * { + * // long press + * }); + * + *

    The properties of the event object have the following values:

    + * + * + * + * + * + * + *
    PropertyValue
    bubblesfalse
    currentTargetThe Object that defines the + * event listener that handles the event. For example, if you use + * myButton.addEventListener() to register an event listener, + * myButton is the value of the currentTarget.
    datanull
    targetThe Object that dispatched the event; + * it is not always the Object listening for the event. Use the + * currentTarget property to always access the Object + * listening for the event.
    + * + * @eventType feathers.events.FeathersEventType.LONG_PRESS + * @see #isLongPressEnabled + * @see #longPressDuration + */ + [Event(name="longPress",type="starling.events.Event")] + + /** + * A push button control that may be triggered when pressed and released. + * + *

    The following example creates a button, gives it a label and listens + * for when the button is triggered:

    + * + * + * var button:Button = new Button(); + * button.label = "Click Me"; + * button.addEventListener( Event.TRIGGERED, button_triggeredHandler ); + * this.addChild( button ); + * + * @see ../../../help/button.html How to use the Feathers Button component + */ + public class Button extends FeathersControl implements IFocusDisplayObject + { + /** + * @private + */ + private static const HELPER_POINT:Point = new Point(); + + /** + * The default value added to the styleNameList of the label. + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const DEFAULT_CHILD_STYLE_NAME_LABEL:String = "feathers-button-label"; + + /** + * DEPRECATED: Replaced by Button.DEFAULT_CHILD_STYLE_NAME_LABEL. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Button#DEFAULT_CHILD_STYLE_NAME_LABEL + */ + public static const DEFAULT_CHILD_NAME_LABEL:String = DEFAULT_CHILD_STYLE_NAME_LABEL; + + /** + * An alternate style name to use with Button to allow a + * theme to give it a more prominent, "call-to-action" style. If a theme + * does not provide a style for a call-to-action button, the theme will + * automatically fall back to using the default button style. + * + *

    An alternate style name should always be added to a component's + * styleNameList before the component is initialized. If + * the style name is added later, it will be ignored.

    + * + *

    In the following example, the call-to-action style is applied to + * a button:

    + * + * + * var button:Button = new Button(); + * button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON ); + * this.addChild( button ); + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON:String = "feathers-call-to-action-button"; + + /** + * DEPRECATED: Replaced by Button.ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Button#ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON + */ + public static const ALTERNATE_NAME_CALL_TO_ACTION_BUTTON:String = ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON; + + /** + * An alternate style name to use with Button to allow a + * theme to give it a less prominent, "quiet" style. If a theme does not + * provide a style for a quiet button, the theme will automatically fall + * back to using the default button style. + * + *

    An alternate style name should always be added to a component's + * styleNameList before the component is initialized. If + * the style name is added later, it will be ignored.

    + * + *

    In the following example, the quiet button style is applied to + * a button:

    + * + * + * var button:Button = new Button(); + * button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_QUIET_BUTTON ); + * this.addChild( button ); + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const ALTERNATE_STYLE_NAME_QUIET_BUTTON:String = "feathers-quiet-button"; + + /** + * DEPRECATED: Replaced by Button.ALTERNATE_STYLE_NAME_QUIET_BUTTON. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Button#ALTERNATE_STYLE_NAME_QUIET_BUTTON + */ + public static const ALTERNATE_NAME_QUIET_BUTTON:String = ALTERNATE_STYLE_NAME_QUIET_BUTTON; + + /** + * An alternate style name to use with Button to allow a + * theme to give it a highly prominent, "danger" style. An example would + * be a delete button or some other button that has a destructive action + * that cannot be undone if the button is triggered. If a theme does not + * provide a style for the danger button, the theme will automatically + * fall back to using the default button style. + * + *

    An alternate style name should always be added to a component's + * styleNameList before the component is initialized. If + * the style name is added later, it will be ignored.

    + * + *

    In the following example, the danger button style is applied to + * a button:

    + * + * + * var button:Button = new Button(); + * button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_DANGER_BUTTON ); + * this.addChild( button ); + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const ALTERNATE_STYLE_NAME_DANGER_BUTTON:String = "feathers-danger-button"; + + /** + * DEPRECATED: Replaced by Button.ALTERNATE_STYLE_NAME_DANGER_BUTTON. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Button#ALTERNATE_STYLE_NAME_DANGER_BUTTON + */ + public static const ALTERNATE_NAME_DANGER_BUTTON:String = ALTERNATE_STYLE_NAME_DANGER_BUTTON; + + /** + * An alternate style name to use with Button to allow a + * theme to give it a "back button" style, perhaps with an arrow + * pointing backward. If a theme does not provide a style for a back + * button, the theme will automatically fall back to using the default + * button skin. + * + *

    An alternate style name should always be added to a component's + * styleNameList before the component is initialized. If + * the style name is added later, it will be ignored.

    + * + *

    In the following example, the back button style is applied to + * a button:

    + * + * + * var button:Button = new Button(); + * button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_BACK_BUTTON ); + * this.addChild( button ); + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const ALTERNATE_STYLE_NAME_BACK_BUTTON:String = "feathers-back-button"; + + /** + * DEPRECATED: Replaced by Button.ALTERNATE_STYLE_NAME_BACK_BUTTON. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Button#ALTERNATE_STYLE_NAME_BACK_BUTTON + */ + public static const ALTERNATE_NAME_BACK_BUTTON:String = ALTERNATE_STYLE_NAME_BACK_BUTTON; + + /** + * An alternate style name to use with Button to allow a + * theme to give it a "forward" button style, perhaps with an arrow + * pointing forward. If a theme does not provide a style for a forward + * button, the theme will automatically fall back to using the default + * button style. + * + *

    An alternate style name should always be added to a component's + * styleNameList before the component is initialized. If + * the style name is added later, it will be ignored.

    + * + *

    In the following example, the forward button style is applied to + * a button:

    + * + * + * var button:Button = new Button(); + * button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_FORWARD_BUTTON ); + * this.addChild( button ); + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const ALTERNATE_STYLE_NAME_FORWARD_BUTTON:String = "feathers-forward-button"; + + /** + * DEPRECATED: Replaced by Button.ALTERNATE_STYLE_NAME_FORWARD_BUTTON. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see Button#ALTERNATE_STYLE_NAME_FORWARD_BUTTON + */ + public static const ALTERNATE_NAME_FORWARD_BUTTON:String = ALTERNATE_STYLE_NAME_FORWARD_BUTTON; + + /** + * Identifier for the button's up state. Can be used for styling purposes. + * + * @see #stateToSkinFunction + * @see #stateToIconFunction + * @see #stateToLabelPropertiesFunction + */ + public static const STATE_UP:String = "up"; + + /** + * Identifier for the button's down state. Can be used for styling purposes. + * + * @see #stateToSkinFunction + * @see #stateToIconFunction + * @see #stateToLabelPropertiesFunction + */ + public static const STATE_DOWN:String = "down"; + + /** + * Identifier for the button's hover state. Can be used for styling purposes. + * + * @see #stateToSkinFunction + * @see #stateToIconFunction + * @see #stateToLabelPropertiesFunction + */ + public static const STATE_HOVER:String = "hover"; + + /** + * Identifier for the button's disabled state. Can be used for styling purposes. + * + * @see #stateToSkinFunction + * @see #stateToIconFunction + * @see #stateToLabelPropertiesFunction + */ + public static const STATE_DISABLED:String = "disabled"; + + /** + * The icon will be positioned above the label. + * + * @see #iconPosition + */ + public static const ICON_POSITION_TOP:String = "top"; + + /** + * The icon will be positioned to the right of the label. + * + * @see #iconPosition + */ + public static const ICON_POSITION_RIGHT:String = "right"; + + /** + * The icon will be positioned below the label. + * + * @see #iconPosition + */ + public static const ICON_POSITION_BOTTOM:String = "bottom"; + + /** + * The icon will be positioned to the left of the label. + * + * @see #iconPosition + */ + public static const ICON_POSITION_LEFT:String = "left"; + + /** + * The icon will be positioned manually with no relation to the position + * of the label. Use iconOffsetX and iconOffsetY + * to set the icon's position. + * + * @see #iconPosition + * @see #iconOffsetX + * @see #iconOffsetY + */ + public static const ICON_POSITION_MANUAL:String = "manual"; + + /** + * The icon will be positioned to the left the label, and the bottom of + * the icon will be aligned to the baseline of the label text. + * + * @see #iconPosition + */ + public static const ICON_POSITION_LEFT_BASELINE:String = "leftBaseline"; + + /** + * The icon will be positioned to the right the label, and the bottom of + * the icon will be aligned to the baseline of the label text. + * + * @see #iconPosition + */ + public static const ICON_POSITION_RIGHT_BASELINE:String = "rightBaseline"; + + /** + * The icon and label will be aligned horizontally to the left edge of the button. + * + * @see #horizontalAlign + */ + public static const HORIZONTAL_ALIGN_LEFT:String = "left"; + + /** + * The icon and label will be aligned horizontally to the center of the button. + * + * @see #horizontalAlign + */ + public static const HORIZONTAL_ALIGN_CENTER:String = "center"; + + /** + * The icon and label will be aligned horizontally to the right edge of the button. + * + * @see #horizontalAlign + */ + public static const HORIZONTAL_ALIGN_RIGHT:String = "right"; + + /** + * The icon and label will be aligned vertically to the top edge of the button. + * + * @see #verticalAlign + */ + public static const VERTICAL_ALIGN_TOP:String = "top"; + + /** + * The icon and label will be aligned vertically to the middle of the button. + * + * @see #verticalAlign + */ + public static const VERTICAL_ALIGN_MIDDLE:String = "middle"; + + /** + * The icon and label will be aligned vertically to the bottom edge of the button. + * + * @see #verticalAlign + */ + public static const VERTICAL_ALIGN_BOTTOM:String = "bottom"; + + /** + * The default IStyleProvider for all Button + * components. + * + * @default null + * @see feathers.core.FeathersControl#styleProvider + */ + public static var globalStyleProvider:IStyleProvider; + + /** + * Constructor. + */ + public function Button() + { + super(); + this.isQuickHitAreaEnabled = true; + this.addEventListener(TouchEvent.TOUCH, button_touchHandler); + this.addEventListener(Event.REMOVED_FROM_STAGE, button_removedFromStageHandler); + } + + /** + * The value added to the styleNameList of the label text + * renderer. This variable is protected so that sub-classes + * can customize the label text renderer style name in their + * constructors instead of using the default style name defined by + * DEFAULT_CHILD_STYLE_NAME_LABEL. + * + * @see feathers.core.FeathersControl#styleNameList + */ + protected var labelStyleName:String = DEFAULT_CHILD_STYLE_NAME_LABEL; + + /** + * DEPRECATED: Replaced by labelStyleName. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see #labelStyleName + */ + protected function get labelName():String + { + return this.labelStyleName; + } + + /** + * @private + */ + protected function set labelName(value:String):void + { + this.labelStyleName = value; + } + + /** + * The text renderer for the button's label. + * + *

    For internal use in subclasses.

    + * + * @see #label + * @see #labelFactory + * @see #createLabel() + */ + protected var labelTextRenderer:ITextRenderer; + + /** + * The currently visible skin. The value will be null if + * there is no currently visible skin. + * + *

    For internal use in subclasses.

    + */ + protected var currentSkin:DisplayObject; + + /** + * The currently visible icon. The value will be null if + * there is no currently visible icon. + * + *

    For internal use in subclasses.

    + */ + protected var currentIcon:DisplayObject; + + /** + * The saved ID of the currently active touch. The value will be + * -1 if there is no currently active touch. + * + *

    For internal use in subclasses.

    + */ + protected var touchPointID:int = -1; + + /** + * @private + */ + override protected function get defaultStyleProvider():IStyleProvider + { + return Button.globalStyleProvider; + } + + /** + * @private + */ + override public function set isEnabled(value:Boolean):void + { + if(this._isEnabled == value) + { + return; + } + super.isEnabled = value; + if(!this._isEnabled) + { + this.touchable = false; + this.currentState = STATE_DISABLED; + this.touchPointID = -1; + } + else + { + //might be in another state for some reason + //let's only change to up if needed + if(this.currentState == STATE_DISABLED) + { + this.currentState = STATE_UP; + } + this.touchable = true; + } + } + + /** + * @private + */ + protected var _currentState:String = STATE_UP; + + /** + * The current touch state of the button. + * + *

    For internal use in subclasses.

    + */ + protected function get currentState():String + { + return this._currentState; + } + + /** + * @private + */ + protected function set currentState(value:String):void + { + if(this._currentState == value) + { + return; + } + if(this.stateNames.indexOf(value) < 0) + { + throw new ArgumentError("Invalid state: " + value + "."); + } + this._currentState = value; + this.invalidate(INVALIDATION_FLAG_STATE); + } + + /** + * @private + */ + protected var _label:String = null; + + /** + * The text displayed on the button. + * + *

    The following example gives the button some label text:

    + * + * + * button.label = "Click Me"; + * + * @default null + */ + public function get label():String + { + return this._label; + } + + /** + * @private + */ + public function set label(value:String):void + { + if(this._label == value) + { + return; + } + this._label = value; + this.invalidate(INVALIDATION_FLAG_DATA); + } + + /** + * @private + */ + protected var _hasLabelTextRenderer:Boolean = true; + + /** + * Determines if the button's label text renderer is created or not. + * Useful for button sub-components that may not display text, like + * slider thumbs and tracks, or similar sub-components on scroll bars. + * + *

    The following example removed the label text renderer:

    + * + * + * button.hasLabelTextRenderer = false; + * + * @default true + */ + public function get hasLabelTextRenderer():Boolean + { + return this._hasLabelTextRenderer; + } + + /** + * @private + */ + public function set hasLabelTextRenderer(value:Boolean):void + { + if(this._hasLabelTextRenderer == value) + { + return; + } + this._hasLabelTextRenderer = value; + this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER); + } + + /** + * @private + */ + protected var _iconPosition:String = ICON_POSITION_LEFT; + + [Inspectable(type="String",enumeration="top,right,bottom,left,rightBaseline,leftBaseline,manual")] + /** + * The location of the icon, relative to the label. + * + *

    The following example positions the icon to the right of the + * label:

    + * + * + * button.label = "Click Me"; + * button.defaultIcon = new Image( texture ); + * button.iconPosition = Button.ICON_POSITION_RIGHT; + * + * @default Button.ICON_POSITION_LEFT + * + * @see #ICON_POSITION_TOP + * @see #ICON_POSITION_RIGHT + * @see #ICON_POSITION_BOTTOM + * @see #ICON_POSITION_LEFT + * @see #ICON_POSITION_RIGHT_BASELINE + * @see #ICON_POSITION_LEFT_BASELINE + * @see #ICON_POSITION_MANUAL + */ + public function get iconPosition():String + { + return this._iconPosition; + } + + /** + * @private + */ + public function set iconPosition(value:String):void + { + if(this._iconPosition == value) + { + return; + } + this._iconPosition = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _gap:Number = 0; + + /** + * The space, in pixels, between the icon and the label. Applies to + * either horizontal or vertical spacing, depending on the value of + * iconPosition. + * + *

    If gap is set to Number.POSITIVE_INFINITY, + * the label and icon will be positioned as far apart as possible. In + * other words, they will be positioned at the edges of the button, + * adjusted for padding.

    + * + *

    The following example creates a gap of 50 pixels between the label + * and the icon:

    + * + * + * button.label = "Click Me"; + * button.defaultIcon = new Image( texture ); + * button.gap = 50; + * + * @default 0 + * + * @see #iconPosition + * @see #minGap + */ + public function get gap():Number + { + return this._gap; + } + + /** + * @private + */ + public function set gap(value:Number):void + { + if(this._gap == value) + { + return; + } + this._gap = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _minGap:Number = 0; + + /** + * If the value of the gap property is + * Number.POSITIVE_INFINITY, meaning that the gap will + * fill as much space as possible, the final calculated value will not be + * smaller than the value of the minGap property. + * + *

    The following example ensures that the gap is never smaller than + * 20 pixels:

    + * + * + * button.gap = Number.POSITIVE_INFINITY; + * button.minGap = 20; + * + * @default 0 + * + * @see #gap + */ + public function get minGap():Number + { + return this._minGap; + } + + /** + * @private + */ + public function set minGap(value:Number):void + { + if(this._minGap == value) + { + return; + } + this._minGap = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _horizontalAlign:String = HORIZONTAL_ALIGN_CENTER; + + [Inspectable(type="String",enumeration="left,center,right")] + /** + * The location where the button's content is aligned horizontally (on + * the x-axis). + * + *

    The following example aligns the button's content to the left:

    + * + * + * button.horizontalAlign = Button.HORIZONTAL_ALIGN_LEFT; + * + * @default Button.HORIZONTAL_ALIGN_CENTER + * + * @see #HORIZONTAL_ALIGN_LEFT + * @see #HORIZONTAL_ALIGN_CENTER + * @see #HORIZONTAL_ALIGN_RIGHT + */ + public function get horizontalAlign():String + { + return this._horizontalAlign; + } + + /** + * @private + */ + public function set horizontalAlign(value:String):void + { + if(this._horizontalAlign == value) + { + return; + } + this._horizontalAlign = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _verticalAlign:String = VERTICAL_ALIGN_MIDDLE; + + [Inspectable(type="String",enumeration="top,middle,bottom")] + /** + * The location where the button's content is aligned vertically (on + * the y-axis). + * + *

    The following example aligns the button's content to the top:

    + * + * + * button.verticalAlign = Button.VERTICAL_ALIGN_TOP; + * + * @default Button.VERTICAL_ALIGN_MIDDLE + * + * @see #VERTICAL_ALIGN_TOP + * @see #VERTICAL_ALIGN_MIDDLE + * @see #VERTICAL_ALIGN_BOTTOM + */ + public function get verticalAlign():String + { + return _verticalAlign; + } + + /** + * @private + */ + public function set verticalAlign(value:String):void + { + if(this._verticalAlign == value) + { + return; + } + this._verticalAlign = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * Quickly sets all padding properties to the same value. The + * padding getter always returns the value of + * paddingTop, but the other padding values may be + * different. + * + *

    The following example gives the button 20 pixels of padding on all + * sides:

    + * + * + * button.padding = 20; + * + * @default 0 + * + * @see #paddingTop + * @see #paddingRight + * @see #paddingBottom + * @see #paddingLeft + */ + public function get padding():Number + { + return this._paddingTop; + } + + /** + * @private + */ + public function set padding(value:Number):void + { + this.paddingTop = value; + this.paddingRight = value; + this.paddingBottom = value; + this.paddingLeft = value; + } + + /** + * @private + */ + protected var _paddingTop:Number = 0; + + /** + * The minimum space, in pixels, between the button's top edge and the + * button's content. + * + *

    The following example gives the button 20 pixels of padding on the + * top edge only:

    + * + * + * button.paddingTop = 20; + * + * @default 0 + */ + public function get paddingTop():Number + { + return this._paddingTop; + } + + /** + * @private + */ + public function set paddingTop(value:Number):void + { + if(this._paddingTop == value) + { + return; + } + this._paddingTop = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _paddingRight:Number = 0; + + /** + * The minimum space, in pixels, between the button's right edge and the + * button's content. + * + *

    The following example gives the button 20 pixels of padding on the + * right edge only:

    + * + * + * button.paddingRight = 20; + * + * @default 0 + */ + public function get paddingRight():Number + { + return this._paddingRight; + } + + /** + * @private + */ + public function set paddingRight(value:Number):void + { + if(this._paddingRight == value) + { + return; + } + this._paddingRight = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _paddingBottom:Number = 0; + + /** + * The minimum space, in pixels, between the button's bottom edge and + * the button's content. + * + *

    The following example gives the button 20 pixels of padding on the + * bottom edge only:

    + * + * + * button.paddingBottom = 20; + * + * @default 0 + */ + public function get paddingBottom():Number + { + return this._paddingBottom; + } + + /** + * @private + */ + public function set paddingBottom(value:Number):void + { + if(this._paddingBottom == value) + { + return; + } + this._paddingBottom = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _paddingLeft:Number = 0; + + /** + * The minimum space, in pixels, between the button's left edge and the + * button's content. + * + *

    The following example gives the button 20 pixels of padding on the + * left edge only:

    + * + * + * button.paddingLeft = 20; + * + * @default 0 + */ + public function get paddingLeft():Number + { + return this._paddingLeft; + } + + /** + * @private + */ + public function set paddingLeft(value:Number):void + { + if(this._paddingLeft == value) + { + return; + } + this._paddingLeft = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _labelOffsetX:Number = 0; + + /** + * Offsets the x position of the label by a certain number of pixels. + * This does not affect the measurement of the button. The button will + * measure itself as if the label were not offset from its original + * position. + * + *

    The following example offsets the x position of the button's label + * by 20 pixels:

    + * + * + * button.labelOffsetX = 20; + * + * @default 0 + * + * @see #labelOffsetY + */ + public function get labelOffsetX():Number + { + return this._labelOffsetX; + } + + /** + * @private + */ + public function set labelOffsetX(value:Number):void + { + if(this._labelOffsetX == value) + { + return; + } + this._labelOffsetX = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _labelOffsetY:Number = 0; + + /** + * Offsets the y position of the label by a certain number of pixels. + * This does not affect the measurement of the button. The button will + * measure itself as if the label were not offset from its original + * position. + * + *

    The following example offsets the y position of the button's label + * by 20 pixels:

    + * + * + * button.labelOffsetY = 20; + * + * @default 0 + * + * @see #labelOffsetX + */ + public function get labelOffsetY():Number + { + return this._labelOffsetY; + } + + /** + * @private + */ + public function set labelOffsetY(value:Number):void + { + if(this._labelOffsetY == value) + { + return; + } + this._labelOffsetY = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _iconOffsetX:Number = 0; + + /** + * Offsets the x position of the icon by a certain number of pixels. + * This does not affect the measurement of the button. The button will + * measure itself as if the icon were not offset from its original + * position. + * + *

    The following example offsets the x position of the button's icon + * by 20 pixels:

    + * + * + * button.iconOffsetX = 20; + * + * @default 0 + * + * @see #iconOffsetY + */ + public function get iconOffsetX():Number + { + return this._iconOffsetX; + } + + /** + * @private + */ + public function set iconOffsetX(value:Number):void + { + if(this._iconOffsetX == value) + { + return; + } + this._iconOffsetX = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _iconOffsetY:Number = 0; + + /** + * Offsets the y position of the icon by a certain number of pixels. + * This does not affect the measurement of the button. The button will + * measure itself as if the icon were not offset from its original + * position. + * + *

    The following example offsets the y position of the button's icon + * by 20 pixels:

    + * + * + * button.iconOffsetY = 20; + * + * @default 0 + * + * @see #iconOffsetX + */ + public function get iconOffsetY():Number + { + return this._iconOffsetY; + } + + /** + * @private + */ + public function set iconOffsetY(value:Number):void + { + if(this._iconOffsetY == value) + { + return; + } + this._iconOffsetY = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * Determines if a pressed button should remain in the down state if a + * touch moves outside of the button's bounds. Useful for controls like + * Slider and ToggleSwitch to keep a thumb in + * the down state while it is dragged around. + * + *

    The following example ensures that the button's down state remains + * active when the button is pressed but the touch moves outside the + * button's bounds:

    + * + * + * button.keepDownStateOnRollOut = true; + */ + public var keepDownStateOnRollOut:Boolean = false; + + /** + * @private + */ + protected var _stateNames:Vector. = new + [ + STATE_UP, STATE_DOWN, STATE_HOVER, STATE_DISABLED + ]; + + /** + * A list of all valid touch state names for use with currentState. + * + *

    For internal use in subclasses.

    + * + * @see #currentState + */ + protected function get stateNames():Vector. + { + return this._stateNames; + } + + /** + * @private + */ + protected var _originalSkinWidth:Number = NaN; + + /** + * @private + */ + protected var _originalSkinHeight:Number = NaN; + + /** + * @private + */ + protected var _stateToSkinFunction:Function; + + /** + * Returns a skin for the current state. Can be used instead of + * individual skin properties for different states, like + * upSkin or hoverSkin, to reuse the same + * display object for all states. The function should simply change the + * display object's properties. For example, a function could reuse the + * the same starling.display.Image instance among all + * button states, and change its texture for each state. + * + *

    The following function signature is expected:

    + *
    function(target:Button, state:Object, oldSkin:DisplayObject = null):DisplayObject
    + * + * @default null + */ + public function get stateToSkinFunction():Function + { + return this._stateToSkinFunction; + } + + /** + * @private + */ + public function set stateToSkinFunction(value:Function):void + { + if(this._stateToSkinFunction == value) + { + return; + } + this._stateToSkinFunction = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _stateToIconFunction:Function; + + /** + * Returns an icon for the current state. Can be used instead of + * individual icon properties for different states, like + * upIcon or hoverIcon, to reuse the same + * display object for all states. the function should simply change the + * display object's properties. For example, a function could reuse the + * the same starling.display.Image instance among all + * button states, and change its texture for each state. + * + *

    The following function signature is expected:

    + *
    function(target:Button, state:Object, oldIcon:DisplayObject = null):DisplayObject
    + * + * @default null + */ + public function get stateToIconFunction():Function + { + return this._stateToIconFunction; + } + + /** + * @private + */ + public function set stateToIconFunction(value:Function):void + { + if(this._stateToIconFunction == value) + { + return; + } + this._stateToIconFunction = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _stateToLabelPropertiesFunction:Function; + + /** + * Returns a text format for the current state. + * + *

    The following function signature is expected:

    + *
    function(target:Button, state:Object):Object
    + * + * @default null + */ + public function get stateToLabelPropertiesFunction():Function + { + return this._stateToLabelPropertiesFunction; + } + + /** + * @private + */ + public function set stateToLabelPropertiesFunction(value:Function):void + { + if(this._stateToLabelPropertiesFunction == value) + { + return; + } + this._stateToLabelPropertiesFunction = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + * Chooses an appropriate skin based on the state and the selection. + */ + protected var _skinSelector:StateWithToggleValueSelector = new StateWithToggleValueSelector(); + + /** + * The skin used when no other skin is defined for the current state. + * Intended to be used when multiple states should share the same skin. + * + *

    This property will be ignored if a function is passed to the + * stateToSkinFunction property.

    + * + *

    The following example gives the button a default skin to use for + * all states when no specific skin is available:

    + * + * + * button.defaultSkin = new Image( texture ); + * + * @default null + * + * @see #stateToSkinFunction + * @see #upSkin + * @see #downSkin + * @see #hoverSkin + * @see #disabledSkin + */ + public function get defaultSkin():DisplayObject + { + return DisplayObject(this._skinSelector.defaultValue); + } + + /** + * @private + */ + public function set defaultSkin(value:DisplayObject):void + { + if(this._skinSelector.defaultValue == value) + { + return; + } + this._skinSelector.defaultValue = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The skin used for the button's up state. If null, then + * defaultSkin is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToSkinFunction property.

    + * + *

    The following example gives the button a skin for the up state:

    + * + * + * button.upSkin = new Image( texture ); + * + * @default null + * + * @see #defaultSkin + */ + public function get upSkin():DisplayObject + { + return DisplayObject(this._skinSelector.getValueForState(STATE_UP, false)); + } + + /** + * @private + */ + public function set upSkin(value:DisplayObject):void + { + if(this._skinSelector.getValueForState(STATE_UP, false) == value) + { + return; + } + this._skinSelector.setValueForState(value, STATE_UP, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The skin used for the button's down state. If null, then + * defaultSkin is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToSkinFunction property.

    + * + *

    The following example gives the button a skin for the down state:

    + * + * + * button.downSkin = new Image( texture ); + * + * @default null + * + * @see #defaultSkin + */ + public function get downSkin():DisplayObject + { + return DisplayObject(this._skinSelector.getValueForState(STATE_DOWN, false)); + } + + /** + * @private + */ + public function set downSkin(value:DisplayObject):void + { + if(this._skinSelector.getValueForState(STATE_DOWN, false) == value) + { + return; + } + this._skinSelector.setValueForState(value, STATE_DOWN, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The skin used for the button's hover state. If null, then + * defaultSkin is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToSkinFunction property.

    + * + *

    The following example gives the button a skin for the hover state:

    + * + * + * button.hoverSkin = new Image( texture ); + * + * @default null + * + * @see #defaultSkin + */ + public function get hoverSkin():DisplayObject + { + return DisplayObject(this._skinSelector.getValueForState(STATE_HOVER, false)); + } + + /** + * @private + */ + public function set hoverSkin(value:DisplayObject):void + { + if(this._skinSelector.getValueForState(STATE_HOVER, false) == value) + { + return; + } + this._skinSelector.setValueForState(value, STATE_HOVER, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The skin used for the button's disabled state. If null, + * then defaultSkin is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToSkinFunction property.

    + * + *

    The following example gives the button a skin for the disabled state:

    + * + * + * button.disabledSkin = new Image( texture ); + * + * @default null + * + * @see #defaultSkin + */ + public function get disabledSkin():DisplayObject + { + return DisplayObject(this._skinSelector.getValueForState(STATE_DISABLED, false)); + } + + /** + * @private + */ + public function set disabledSkin(value:DisplayObject):void + { + if(this._skinSelector.getValueForState(STATE_DISABLED, false) == value) + { + return; + } + this._skinSelector.setValueForState(value, STATE_DISABLED, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _labelFactory:Function; + + /** + * A function used to instantiate the button's label text renderer + * sub-component. By default, the button will use the global text + * renderer factory, FeathersControl.defaultTextRendererFactory(), + * to create the label text renderer. The label text renderer must be an + * instance of ITextRenderer. To change properties on the + * label text renderer, see defaultLabelProperties and the + * other "LabelProperties" properties for each button + * state. + * + *

    The factory should have the following function signature:

    + *
    function():ITextRenderer
    + * + *

    The following example gives the button a custom factory for the + * label text renderer:

    + * + * + * button.labelFactory = function():ITextRenderer + * { + * return new TextFieldTextRenderer(); + * } + * + * @default null + * + * @see feathers.core.ITextRenderer + * @see feathers.core.FeathersControl#defaultTextRendererFactory + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + */ + public function get labelFactory():Function + { + return this._labelFactory; + } + + /** + * @private + */ + public function set labelFactory(value:Function):void + { + if(this._labelFactory == value) + { + return; + } + this._labelFactory = value; + this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER); + } + + /** + * @private + */ + protected var _labelPropertiesSelector:StateWithToggleValueSelector = new StateWithToggleValueSelector(); + + /** + * The default label properties are a set of key/value pairs to be + * passed down to the button's label text renderer, and it is used when + * no specific properties are defined for the button's current state. + * Intended for use when multiple states should share the same + * properties. The label text renderer is an ITextRenderer + * instance. The available properties depend on which ITextRenderer + * implementation is returned by labelFactory. The most + * common implementations are BitmapFontTextRenderer and + * TextFieldTextRenderer. + * + *

    The following example gives the button default label properties to + * use for all states when no specific label properties are available + * (this example assumes that the label text renderer is a + * BitmapFontTextRenderer):

    + * + * + * button.defaultLabelProperties.textFormat = new BitmapFontTextFormat( bitmapFont ); + * button.defaultLabelProperties.wordWrap = true; + * + * @default null + * + * @see feathers.core.ITextRenderer + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + * @see #stateToLabelPropertiesFunction + */ + public function get defaultLabelProperties():Object + { + var value:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.defaultValue); + if(!value) + { + value = new PropertyProxy(childProperties_onChange); + this._labelPropertiesSelector.defaultValue = value; + } + return value; + } + + /** + * @private + */ + public function set defaultLabelProperties(value:Object):void + { + if(!(value is PropertyProxy)) + { + value = PropertyProxy.fromObject(value); + } + var oldValue:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.defaultValue); + if(oldValue) + { + oldValue.removeOnChangeCallback(childProperties_onChange); + } + this._labelPropertiesSelector.defaultValue = value; + if(value) + { + PropertyProxy(value).addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * A set of key/value pairs to be passed down ot the button's label + * text renderer when the button is in the up state. If null, + * then defaultLabelProperties is used instead. The label + * text renderer is an ITextRenderer instance. The + * available properties depend on which ITextRenderer + * implementation is returned by labelFactory. The most + * common implementations are BitmapFontTextRenderer and + * TextFieldTextRenderer. + * + *

    The following example gives the button label properties for the + * up state:

    + * + * + * button.upLabelProperties.textFormat = new BitmapFontTextFormat( bitmapFont ); + * + * @default null + * + * @see feathers.core.ITextRenderer + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + * @see #defaultLabelProperties + */ + public function get upLabelProperties():Object + { + var value:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_UP, false)); + if(!value) + { + value = new PropertyProxy(childProperties_onChange); + this._labelPropertiesSelector.setValueForState(value, STATE_UP, false); + } + return value; + } + + /** + * @private + */ + public function set upLabelProperties(value:Object):void + { + if(!(value is PropertyProxy)) + { + value = PropertyProxy.fromObject(value); + } + var oldValue:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_UP, false)); + if(oldValue) + { + oldValue.removeOnChangeCallback(childProperties_onChange); + } + this._labelPropertiesSelector.setValueForState(value, STATE_UP, false); + if(value) + { + PropertyProxy(value).addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * A set of key/value pairs to be passed down ot the button's label + * text renderer when the button is in the down state. If null, + * then defaultLabelProperties is used instead. The label + * text renderer is an ITextRenderer instance. The + * available properties depend on which ITextRenderer + * implementation is returned by labelFactory. The most + * common implementations are BitmapFontTextRenderer and + * TextFieldTextRenderer. + * + *

    The following example gives the button label properties for the + * down state:

    + * + * + * button.downLabelProperties.textFormat = new BitmapFontTextFormat( bitmapFont ); + * + * @default null + * + * @see feathers.core.ITextRenderer + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + * @see #defaultLabelProperties + */ + public function get downLabelProperties():Object + { + var value:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_DOWN, false)); + if(!value) + { + value = new PropertyProxy(childProperties_onChange); + this._labelPropertiesSelector.setValueForState(value, STATE_DOWN, false); + } + return value; + } + + /** + * @private + */ + public function set downLabelProperties(value:Object):void + { + if(!(value is PropertyProxy)) + { + value = PropertyProxy.fromObject(value); + } + var oldValue:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_DOWN, false)); + if(oldValue) + { + oldValue.removeOnChangeCallback(childProperties_onChange); + } + this._labelPropertiesSelector.setValueForState(value, STATE_DOWN, false); + if(value) + { + PropertyProxy(value).addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * A set of key/value pairs to be passed down ot the button's label + * text renderer when the button is in the hover state. If null, + * then defaultLabelProperties is used instead. The label + * text renderer is an ITextRenderer instance. The + * available properties depend on which ITextRenderer + * implementation is returned by labelFactory. The most + * common implementations are BitmapFontTextRenderer and + * TextFieldTextRenderer. + * + *

    The following example gives the button label properties for the + * hover state:

    + * + * + * button.hoverLabelProperties.textFormat = new BitmapFontTextFormat( bitmapFont ); + * + * @default null + * + * @see feathers.core.ITextRenderer + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + * @see #defaultLabelProperties + */ + public function get hoverLabelProperties():Object + { + var value:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_HOVER, false)); + if(!value) + { + value = new PropertyProxy(childProperties_onChange); + this._labelPropertiesSelector.setValueForState(value, STATE_HOVER, false); + } + return value; + } + + /** + * @private + */ + public function set hoverLabelProperties(value:Object):void + { + if(!(value is PropertyProxy)) + { + value = PropertyProxy.fromObject(value); + } + var oldValue:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_HOVER, false)); + if(oldValue) + { + oldValue.removeOnChangeCallback(childProperties_onChange); + } + this._labelPropertiesSelector.setValueForState(value, STATE_HOVER, false); + if(value) + { + PropertyProxy(value).addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * A set of key/value pairs to be passed down ot the button's label + * text renderer when the button is in the disabled state. If null, + * then defaultLabelProperties is used instead. The label + * text renderer is an ITextRenderer instance. The + * available properties depend on which ITextRenderer + * implementation is returned by labelFactory. The most + * common implementations are BitmapFontTextRenderer and + * TextFieldTextRenderer. + * + *

    The following example gives the button label properties for the + * disabled state:

    + * + * + * button.disabledLabelProperties.textFormat = new BitmapFontTextFormat( bitmapFont ); + * + * @default null + * + * @see feathers.core.ITextRenderer + * @see feathers.controls.text.BitmapFontTextRenderer + * @see feathers.controls.text.TextFieldTextRenderer + * @see #defaultLabelProperties + */ + public function get disabledLabelProperties():Object + { + var value:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_DISABLED, false)); + if(!value) + { + value = new PropertyProxy(childProperties_onChange); + this._labelPropertiesSelector.setValueForState(value, STATE_DISABLED, false); + } + return value; + } + + /** + * @private + */ + public function set disabledLabelProperties(value:Object):void + { + if(!(value is PropertyProxy)) + { + value = PropertyProxy.fromObject(value); + } + var oldValue:PropertyProxy = PropertyProxy(this._labelPropertiesSelector.getValueForState(STATE_DISABLED, false)); + if(oldValue) + { + oldValue.removeOnChangeCallback(childProperties_onChange); + } + this._labelPropertiesSelector.setValueForState(value, STATE_DISABLED, false); + if(value) + { + PropertyProxy(value).addOnChangeCallback(childProperties_onChange); + } + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + protected var _iconSelector:StateWithToggleValueSelector = new StateWithToggleValueSelector(); + + /** + * The icon used when no other icon is defined for the current state. + * Intended to be used when multiple states should share the same icon. + * + *

    This property will be ignored if a function is passed to the + * stateToIconFunction property.

    + * + *

    The following example gives the button a default icon to use for + * all states when no specific icon is available:

    + * + * + * button.defaultIcon = new Image( texture ); + * + * @default null + * + * @see #stateToIconFunction + * @see #upIcon + * @see #downIcon + * @see #hoverIcon + * @see #disabledIcon + */ + public function get defaultIcon():DisplayObject + { + return DisplayObject(this._iconSelector.defaultValue); + } + + /** + * @private + */ + public function set defaultIcon(value:DisplayObject):void + { + if(this._iconSelector.defaultValue == value) + { + return; + } + this._iconSelector.defaultValue = value; + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The icon used for the button's up state. If null, then + * defaultIcon is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToIconFunction property.

    + * + *

    The following example gives the button an icon for the up state:

    + * + * + * button.upIcon = new Image( texture ); + * + * @default null + * + * @see #defaultIcon + */ + public function get upIcon():DisplayObject + { + return DisplayObject(this._iconSelector.getValueForState(STATE_UP, false)); + } + + /** + * @private + */ + public function set upIcon(value:DisplayObject):void + { + if(this._iconSelector.getValueForState(STATE_UP, false) == value) + { + return; + } + this._iconSelector.setValueForState(value, STATE_UP, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The icon used for the button's down state. If null, then + * defaultIcon is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToIconFunction property.

    + * + *

    The following example gives the button an icon for the down state:

    + * + * + * button.downIcon = new Image( texture ); + * + * @default null + * + * @see #defaultIcon + */ + public function get downIcon():DisplayObject + { + return DisplayObject(this._iconSelector.getValueForState(STATE_DOWN, false)); + } + + /** + * @private + */ + public function set downIcon(value:DisplayObject):void + { + if(this._iconSelector.getValueForState(STATE_DOWN, false) == value) + { + return; + } + this._iconSelector.setValueForState(value, STATE_DOWN, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The icon used for the button's hover state. If null, then + * defaultIcon is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToIconFunction property.

    + * + *

    The following example gives the button an icon for the hover state:

    + * + * + * button.hoverIcon = new Image( texture ); + * + * @default null + * + * @see #defaultIcon + */ + public function get hoverIcon():DisplayObject + { + return DisplayObject(this._iconSelector.getValueForState(STATE_HOVER, false)); + } + + /** + * @private + */ + public function set hoverIcon(value:DisplayObject):void + { + if(this._iconSelector.getValueForState(STATE_HOVER, false) == value) + { + return; + } + this._iconSelector.setValueForState(value, STATE_HOVER, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * The icon used for the button's disabled state. If null, then + * defaultIcon is used instead. + * + *

    This property will be ignored if a function is passed to the + * stateToIconFunction property.

    + * + *

    The following example gives the button an icon for the disabled state:

    + * + * + * button.disabledIcon = new Image( texture ); + * + * @default null + * + * @see #defaultIcon + */ + public function get disabledIcon():DisplayObject + { + return DisplayObject(this._iconSelector.getValueForState(STATE_DISABLED, false)); + } + + /** + * @private + */ + public function set disabledIcon(value:DisplayObject):void + { + if(this._iconSelector.getValueForState(STATE_DISABLED, false) == value) + { + return; + } + this._iconSelector.setValueForState(value, STATE_DISABLED, false); + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + * Used for determining the duration of a long press. + */ + protected var _touchBeginTime:int; + + /** + * @private + */ + protected var _hasLongPressed:Boolean = false; + + /** + * @private + */ + protected var _longPressDuration:Number = 0.5; + + /** + * The duration, in seconds, of a long press. + * + *

    The following example changes the long press duration to one full second:

    + * + * + * button.longPressDuration = 1.0; + * + * @default 0.5 + * + * @see #event:longPress + * @see #isLongPressEnabled + */ + public function get longPressDuration():Number + { + return this._longPressDuration; + } + + /** + * @private + */ + public function set longPressDuration(value:Number):void + { + this._longPressDuration = value; + } + + /** + * @private + */ + protected var _isLongPressEnabled:Boolean = false; + + /** + * Determines if FeathersEventType.LONG_PRESS will be + * dispatched. + * + *

    The following example enables long presses:

    + * + * + * button.isLongPressEnabled = true; + * button.addEventListener( FeathersEventType.LONG_PRESS, function( event:Event ):void + * { + * // long press + * }); + * + * @default false + * + * @see #event:longPress + * @see #longPressDuration + */ + public function get isLongPressEnabled():Boolean + { + return this._isLongPressEnabled; + } + + /** + * @private + */ + public function set isLongPressEnabled(value:Boolean):void + { + this._isLongPressEnabled = value; + if(!value) + { + this.removeEventListener(Event.ENTER_FRAME, longPress_enterFrameHandler); + } + } + + /** + * @private + */ + protected var _scaleWhenDown:Number = 1; + + /** + * The button renders at this scale in the down state. + * + *

    The following example scales the button in the down state:

    + * + * + * button.scaleWhenDown = 0.9; + * + * @default 1 + */ + public function get scaleWhenDown():Number + { + return this._scaleWhenDown; + } + + /** + * @private + */ + public function set scaleWhenDown(value:Number):void + { + this._scaleWhenDown = value; + } + + /** + * @private + */ + protected var _scaleWhenHovering:Number = 1; + + /** + * The button renders at this scale in the hover state. + * + *

    The following example scales the button in the hover state:

    + * + * + * button.scaleWhenHovering = 0.9; + * + * @default 1 + */ + public function get scaleWhenHovering():Number + { + return this._scaleWhenHovering; + } + + /** + * @private + */ + public function set scaleWhenHovering(value:Number):void + { + this._scaleWhenHovering = value; + } + + /** + * @private + */ + override public function render(support:RenderSupport, parentAlpha:Number):void + { + var scale:Number = 1; + if(this._currentState == STATE_DOWN) + { + scale = this._scaleWhenDown; + } + else if(this._currentState == STATE_HOVER) + { + scale = this._scaleWhenHovering; + } + if(scale !== 1) + { + support.scaleMatrix(scale, scale); + support.translateMatrix(Math.round((1 - scale) / 2 * this.actualWidth), + Math.round((1 - scale) / 2 * this.actualHeight)); + } + super.render(support, parentAlpha); + } + + /** + * @private + */ + override protected function draw():void + { + var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); + var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES); + var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE); + var stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE); + var textRendererInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_TEXT_RENDERER); + var focusInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_FOCUS); + + if(textRendererInvalid) + { + this.createLabel(); + } + + if(textRendererInvalid || stateInvalid || dataInvalid) + { + this.refreshLabel(); + } + + if(stylesInvalid || stateInvalid) + { + this.refreshSkin(); + this.refreshIcon(); + } + + if(textRendererInvalid || stylesInvalid || stateInvalid) + { + this.refreshLabelStyles(); + } + + sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid; + + if(stylesInvalid || stateInvalid || sizeInvalid) + { + this.scaleSkin(); + } + + if(textRendererInvalid || stylesInvalid || stateInvalid || dataInvalid || sizeInvalid) + { + this.layoutContent(); + } + + if(sizeInvalid || focusInvalid) + { + this.refreshFocusIndicator(); + } + } + + /** + * If the component's dimensions have not been set explicitly, it will + * measure its content and determine an ideal size for itself. If the + * explicitWidth or explicitHeight member + * variables are set, those value will be used without additional + * measurement. If one is set, but not the other, the dimension with the + * explicit value will not be measured, but the other non-explicit + * dimension will still need measurement. + * + *

    Calls setSizeInternal() to set up the + * actualWidth and actualHeight member + * variables used for layout.

    + * + *

    Meant for internal use, and subclasses may override this function + * with a custom implementation.

    + */ + protected function autoSizeIfNeeded():Boolean + { + var needsWidth:Boolean = this.explicitWidth !== this.explicitWidth; //isNaN + var needsHeight:Boolean = this.explicitHeight !== this.explicitHeight; //isNaN + if(!needsWidth && !needsHeight) + { + return false; + } + this.refreshMaxLabelWidth(true); + if(this.labelTextRenderer) + { + this.labelTextRenderer.measureText(HELPER_POINT); + } + else + { + HELPER_POINT.setTo(0, 0); + } + var newWidth:Number = this.explicitWidth; + if(needsWidth) + { + if(this.currentIcon && this.label) + { + if(this._iconPosition != ICON_POSITION_TOP && this._iconPosition != ICON_POSITION_BOTTOM && + this._iconPosition != ICON_POSITION_MANUAL) + { + var adjustedGap:Number = this._gap; + if(adjustedGap == Number.POSITIVE_INFINITY) + { + adjustedGap = this._minGap; + } + newWidth = this.currentIcon.width + adjustedGap + HELPER_POINT.x; + } + else + { + newWidth = Math.max(this.currentIcon.width, HELPER_POINT.x); + } + } + else if(this.currentIcon) + { + newWidth = this.currentIcon.width; + } + else if(this.label) + { + newWidth = HELPER_POINT.x; + } + newWidth += this._paddingLeft + this._paddingRight; + if(newWidth !== newWidth) //isNaN + { + newWidth = this._originalSkinWidth; + if(newWidth != newWidth) + { + newWidth = 0; + } + } + else if(this._originalSkinWidth === this._originalSkinWidth) //!isNaN + { + if(this._originalSkinWidth > newWidth) + { + newWidth = this._originalSkinWidth; + } + } + } + + var newHeight:Number = this.explicitHeight; + if(needsHeight) + { + if(this.currentIcon && this.label) + { + if(this._iconPosition == ICON_POSITION_TOP || this._iconPosition == ICON_POSITION_BOTTOM) + { + adjustedGap = this._gap; + if(adjustedGap == Number.POSITIVE_INFINITY) + { + adjustedGap = this._minGap; + } + newHeight = this.currentIcon.height + adjustedGap + HELPER_POINT.y; + } + else + { + newHeight = Math.max(this.currentIcon.height, HELPER_POINT.y); + } + } + else if(this.currentIcon) + { + newHeight = this.currentIcon.height; + } + else if(this.label) + { + newHeight = HELPER_POINT.y; + } + newHeight += this._paddingTop + this._paddingBottom; + if(newHeight != newHeight) + { + newHeight = this._originalSkinHeight; + if(newHeight != newHeight) + { + newHeight = 0; + } + } + else if(this._originalSkinHeight === this._originalSkinHeight) //!isNaN + { + if(this._originalSkinHeight > newHeight) + { + newHeight = this._originalSkinHeight; + } + } + } + + return this.setSizeInternal(newWidth, newHeight, false); + } + + /** + * Creates the label text renderer sub-component and + * removes the old instance, if one exists. + * + *

    Meant for internal use, and subclasses may override this function + * with a custom implementation.

    + * + * @see #labelTextRenderer + * @see #labelFactory + */ + protected function createLabel():void + { + if(this.labelTextRenderer) + { + this.removeChild(DisplayObject(this.labelTextRenderer), true); + this.labelTextRenderer = null; + } + + if(this._hasLabelTextRenderer) + { + var factory:Function = this._labelFactory != null ? this._labelFactory : FeathersControl.defaultTextRendererFactory; + this.labelTextRenderer = ITextRenderer(factory()); + this.labelTextRenderer.styleNameList.add(this.labelName); + this.addChild(DisplayObject(this.labelTextRenderer)); + } + } + + /** + * @private + */ + protected function refreshLabel():void + { + if(!this.labelTextRenderer) + { + return; + } + this.labelTextRenderer.text = this._label; + this.labelTextRenderer.visible = this._label !== null && this._label.length > 0; + this.labelTextRenderer.isEnabled = this._isEnabled; + } + + /** + * Sets the currentSkin property. + * + *

    For internal use in subclasses.

    + */ + protected function refreshSkin():void + { + var oldSkin:DisplayObject = this.currentSkin; + if(this._stateToSkinFunction != null) + { + this.currentSkin = DisplayObject(this._stateToSkinFunction(this, this._currentState, oldSkin)); + } + else + { + this.currentSkin = DisplayObject(this._skinSelector.updateValue(this, this._currentState, this.currentSkin)); + } + if(this.currentSkin != oldSkin) + { + if(oldSkin) + { + this.removeChild(oldSkin, false); + } + if(this.currentSkin) + { + this.addChildAt(this.currentSkin, 0); + } + } + if(this.currentSkin && + (this._originalSkinWidth !== this._originalSkinWidth || //isNaN + this._originalSkinHeight !== this._originalSkinHeight)) + { + if(this.currentSkin is IValidating) + { + IValidating(this.currentSkin).validate(); + } + this._originalSkinWidth = this.currentSkin.width; + this._originalSkinHeight = this.currentSkin.height; + } + } + + /** + * Sets the currentIcon property. + * + *

    For internal use in subclasses.

    + */ + protected function refreshIcon():void + { + var oldIcon:DisplayObject = this.currentIcon; + if(this._stateToIconFunction != null) + { + this.currentIcon = DisplayObject(this._stateToIconFunction(this, this._currentState, oldIcon)); + } + else + { + this.currentIcon = DisplayObject(this._iconSelector.updateValue(this, this._currentState, this.currentIcon)); + } + if(this.currentIcon is IFeathersControl) + { + IFeathersControl(this.currentIcon).isEnabled = this._isEnabled; + } + if(this.currentIcon != oldIcon) + { + if(oldIcon) + { + this.removeChild(oldIcon, false); + } + if(this.currentIcon) + { + //we want the icon to appear below the label text renderer + var index:int = this.numChildren; + if(this.labelTextRenderer) + { + index = this.getChildIndex(DisplayObject(this.labelTextRenderer)); + } + this.addChildAt(this.currentIcon, index); + } + } + } + + /** + * @private + */ + protected function refreshLabelStyles():void + { + if(!this.labelTextRenderer) + { + return; + } + if(this._stateToLabelPropertiesFunction != null) + { + var properties:Object = this._stateToLabelPropertiesFunction(this, this._currentState); + } + else + { + properties = this._labelPropertiesSelector.updateValue(this, this._currentState); + } + for(var propertyName:String in properties) + { + var propertyValue:Object = properties[propertyName]; + this.labelTextRenderer[propertyName] = propertyValue; + } + } + + /** + * @private + */ + protected function scaleSkin():void + { + if(!this.currentSkin) + { + return; + } + this.currentSkin.x = 0; + this.currentSkin.y = 0; + if(this.currentSkin.width != this.actualWidth) + { + this.currentSkin.width = this.actualWidth; + } + if(this.currentSkin.height != this.actualHeight) + { + this.currentSkin.height = this.actualHeight; + } + if(this.currentSkin is IValidating) + { + IValidating(this.currentSkin).validate(); + } + } + + /** + * Positions and sizes the button's content. + * + *

    For internal use in subclasses.

    + */ + protected function layoutContent():void + { + this.refreshMaxLabelWidth(false); + if(this._label && this.labelTextRenderer && this.currentIcon) + { + this.labelTextRenderer.validate(); + this.positionSingleChild(DisplayObject(this.labelTextRenderer)); + if(this._iconPosition != ICON_POSITION_MANUAL) + { + this.positionLabelAndIcon(); + } + + } + else if(this._label && this.labelTextRenderer && !this.currentIcon) + { + this.labelTextRenderer.validate(); + this.positionSingleChild(DisplayObject(this.labelTextRenderer)); + } + else if((!this._label || !this.labelTextRenderer) && this.currentIcon && this._iconPosition != ICON_POSITION_MANUAL) + { + this.positionSingleChild(this.currentIcon); + } + + if(this.currentIcon) + { + if(this._iconPosition == ICON_POSITION_MANUAL) + { + this.currentIcon.x = this._paddingLeft; + this.currentIcon.y = this._paddingTop; + } + this.currentIcon.x += this._iconOffsetX; + this.currentIcon.y += this._iconOffsetY; + } + if(this._label && this.labelTextRenderer) + { + this.labelTextRenderer.x += this._labelOffsetX; + this.labelTextRenderer.y += this._labelOffsetY; + } + } + + /** + * @private + */ + protected function refreshMaxLabelWidth(forMeasurement:Boolean):void + { + if(this.currentIcon is IValidating) + { + IValidating(this.currentIcon).validate(); + } + var calculatedWidth:Number = this.actualWidth; + if(forMeasurement) + { + calculatedWidth = this.explicitWidth; + if(calculatedWidth !== calculatedWidth) //isNaN + { + calculatedWidth = this._maxWidth; + } + } + if(this._label && this.labelTextRenderer && this.currentIcon) + { + if(this._iconPosition == ICON_POSITION_LEFT || this._iconPosition == ICON_POSITION_LEFT_BASELINE || + this._iconPosition == ICON_POSITION_RIGHT || this._iconPosition == ICON_POSITION_RIGHT_BASELINE) + { + var adjustedGap:Number = this._gap; + if(adjustedGap == Number.POSITIVE_INFINITY) + { + adjustedGap = this._minGap; + } + this.labelTextRenderer.maxWidth = calculatedWidth - this._paddingLeft - this._paddingRight - this.currentIcon.width - adjustedGap; + } + else + { + this.labelTextRenderer.maxWidth = calculatedWidth - this._paddingLeft - this._paddingRight; + } + + } + else if(this._label && this.labelTextRenderer && !this.currentIcon) + { + this.labelTextRenderer.maxWidth = calculatedWidth - this._paddingLeft - this._paddingRight; + } + } + + /** + * @private + */ + protected function positionSingleChild(displayObject:DisplayObject):void + { + if(this._horizontalAlign == HORIZONTAL_ALIGN_LEFT) + { + displayObject.x = this._paddingLeft; + } + else if(this._horizontalAlign == HORIZONTAL_ALIGN_RIGHT) + { + displayObject.x = this.actualWidth - this._paddingRight - displayObject.width; + } + else //center + { + displayObject.x = this._paddingLeft + Math.round((this.actualWidth - this._paddingLeft - this._paddingRight - displayObject.width) / 2); + } + if(this._verticalAlign == VERTICAL_ALIGN_TOP) + { + displayObject.y = this._paddingTop; + } + else if(this._verticalAlign == VERTICAL_ALIGN_BOTTOM) + { + displayObject.y = this.actualHeight - this._paddingBottom - displayObject.height; + } + else //middle + { + displayObject.y = this._paddingTop + Math.round((this.actualHeight - this._paddingTop - this._paddingBottom - displayObject.height) / 2); + } + } + + /** + * @private + */ + protected function positionLabelAndIcon():void + { + if(this._iconPosition == ICON_POSITION_TOP) + { + if(this._gap == Number.POSITIVE_INFINITY) + { + this.currentIcon.y = this._paddingTop; + this.labelTextRenderer.y = this.actualHeight - this._paddingBottom - this.labelTextRenderer.height; + } + else + { + if(this._verticalAlign == VERTICAL_ALIGN_TOP) + { + this.labelTextRenderer.y += this.currentIcon.height + this._gap; + } + else if(this._verticalAlign == VERTICAL_ALIGN_MIDDLE) + { + this.labelTextRenderer.y += Math.round((this.currentIcon.height + this._gap) / 2); + } + this.currentIcon.y = this.labelTextRenderer.y - this.currentIcon.height - this._gap; + } + } + else if(this._iconPosition == ICON_POSITION_RIGHT || this._iconPosition == ICON_POSITION_RIGHT_BASELINE) + { + if(this._gap == Number.POSITIVE_INFINITY) + { + this.labelTextRenderer.x = this._paddingLeft; + this.currentIcon.x = this.actualWidth - this._paddingRight - this.currentIcon.width; + } + else + { + if(this._horizontalAlign == HORIZONTAL_ALIGN_RIGHT) + { + this.labelTextRenderer.x -= this.currentIcon.width + this._gap; + } + else if(this._horizontalAlign == HORIZONTAL_ALIGN_CENTER) + { + this.labelTextRenderer.x -= Math.round((this.currentIcon.width + this._gap) / 2); + } + this.currentIcon.x = this.labelTextRenderer.x + this.labelTextRenderer.width + this._gap; + } + } + else if(this._iconPosition == ICON_POSITION_BOTTOM) + { + if(this._gap == Number.POSITIVE_INFINITY) + { + this.labelTextRenderer.y = this._paddingTop; + this.currentIcon.y = this.actualHeight - this._paddingBottom - this.currentIcon.height; + } + else + { + if(this._verticalAlign == VERTICAL_ALIGN_BOTTOM) + { + this.labelTextRenderer.y -= this.currentIcon.height + this._gap; + } + else if(this._verticalAlign == VERTICAL_ALIGN_MIDDLE) + { + this.labelTextRenderer.y -= Math.round((this.currentIcon.height + this._gap) / 2); + } + this.currentIcon.y = this.labelTextRenderer.y + this.labelTextRenderer.height + this._gap; + } + } + else if(this._iconPosition == ICON_POSITION_LEFT || this._iconPosition == ICON_POSITION_LEFT_BASELINE) + { + if(this._gap == Number.POSITIVE_INFINITY) + { + this.currentIcon.x = this._paddingLeft; + this.labelTextRenderer.x = this.actualWidth - this._paddingRight - this.labelTextRenderer.width; + } + else + { + if(this._horizontalAlign == HORIZONTAL_ALIGN_LEFT) + { + this.labelTextRenderer.x += this._gap + this.currentIcon.width; + } + else if(this._horizontalAlign == HORIZONTAL_ALIGN_CENTER) + { + this.labelTextRenderer.x += Math.round((this._gap + this.currentIcon.width) / 2); + } + this.currentIcon.x = this.labelTextRenderer.x - this._gap - this.currentIcon.width; + } + } + + if(this._iconPosition == ICON_POSITION_LEFT || this._iconPosition == ICON_POSITION_RIGHT) + { + if(this._verticalAlign == VERTICAL_ALIGN_TOP) + { + this.currentIcon.y = this._paddingTop; + } + else if(this._verticalAlign == VERTICAL_ALIGN_BOTTOM) + { + this.currentIcon.y = this.actualHeight - this._paddingBottom - this.currentIcon.height; + } + else + { + this.currentIcon.y = this._paddingTop + Math.round((this.actualHeight - this._paddingTop - this._paddingBottom - this.currentIcon.height) / 2); + } + } + else if(this._iconPosition == ICON_POSITION_LEFT_BASELINE || this._iconPosition == ICON_POSITION_RIGHT_BASELINE) + { + this.currentIcon.y = this.labelTextRenderer.y + (this.labelTextRenderer.baseline) - this.currentIcon.height; + } + else //top or bottom + { + if(this._horizontalAlign == HORIZONTAL_ALIGN_LEFT) + { + this.currentIcon.x = this._paddingLeft; + } + else if(this._horizontalAlign == HORIZONTAL_ALIGN_RIGHT) + { + this.currentIcon.x = this.actualWidth - this._paddingRight - this.currentIcon.width; + } + else + { + this.currentIcon.x = this._paddingLeft + Math.round((this.actualWidth - this._paddingLeft - this._paddingRight - this.currentIcon.width) / 2); + } + } + } + + /** + * @private + */ + protected function resetTouchState(touch:Touch = null):void + { + this.touchPointID = -1; + this.removeEventListener(Event.ENTER_FRAME, longPress_enterFrameHandler); + if(this._isEnabled) + { + this.currentState = STATE_UP; + } + else + { + this.currentState = STATE_DISABLED; + } + } + + /** + * Triggers the button. + */ + protected function trigger():void + { + this.dispatchEventWith(Event.TRIGGERED); + } + + /** + * @private + */ + protected function childProperties_onChange(proxy:PropertyProxy, name:Object):void + { + this.invalidate(INVALIDATION_FLAG_STYLES); + } + + /** + * @private + */ + override protected function focusInHandler(event:Event):void + { + super.focusInHandler(event); + this.stage.addEventListener(KeyboardEvent.KEY_DOWN, stage_keyDownHandler); + this.stage.addEventListener(KeyboardEvent.KEY_UP, stage_keyUpHandler); + } + + /** + * @private + */ + override protected function focusOutHandler(event:Event):void + { + super.focusOutHandler(event); + this.stage.removeEventListener(KeyboardEvent.KEY_DOWN, stage_keyDownHandler); + this.stage.removeEventListener(KeyboardEvent.KEY_UP, stage_keyUpHandler); + + if(this.touchPointID >= 0) + { + this.touchPointID = -1; + if(this._isEnabled) + { + this.currentState = STATE_UP; + } + else + { + this.currentState = STATE_DISABLED; + } + } + } + + /** + * @private + */ + protected function button_removedFromStageHandler(event:Event):void + { + this.resetTouchState(); + } + + /** + * @private + */ + protected function button_touchHandler(event:TouchEvent):void + { + if(!this._isEnabled) + { + this.touchPointID = -1; + return; + } + + if(this.touchPointID >= 0) + { + var touch:Touch = event.getTouch(this, null, this.touchPointID); + if(!touch) + { + //this should never happen + return; + } + + touch.getLocation(this.stage, HELPER_POINT); + var isInBounds:Boolean = this.contains(this.stage.hitTest(HELPER_POINT, true)); + if(touch.phase == TouchPhase.MOVED) + { + if(isInBounds || this.keepDownStateOnRollOut) + { + this.currentState = STATE_DOWN; + } + else + { + this.currentState = STATE_UP; + } + } + else if(touch.phase == TouchPhase.ENDED) + { + this.resetTouchState(touch); + //we we dispatched a long press, then triggered and change + //won't be able to happen until the next touch begins + if(!this._hasLongPressed && isInBounds) + { + this.trigger(); + } + } + return; + } + else //if we get here, we don't have a saved touch ID yet + { + touch = event.getTouch(this, TouchPhase.BEGAN); + if(touch) + { + this.currentState = STATE_DOWN; + this.touchPointID = touch.id; + if(this._isLongPressEnabled) + { + this._touchBeginTime = getTimer(); + this._hasLongPressed = false; + this.addEventListener(Event.ENTER_FRAME, longPress_enterFrameHandler); + } + return; + } + touch = event.getTouch(this, TouchPhase.HOVER); + if(touch) + { + this.currentState = STATE_HOVER; + return; + } + + //end of hover + this.currentState = STATE_UP; + } + } + + /** + * @private + */ + protected function longPress_enterFrameHandler(event:Event):void + { + var accumulatedTime:Number = (getTimer() - this._touchBeginTime) / 1000; + if(accumulatedTime >= this._longPressDuration) + { + this.removeEventListener(Event.ENTER_FRAME, longPress_enterFrameHandler); + this._hasLongPressed = true; + this.dispatchEventWith(FeathersEventType.LONG_PRESS); + } + } + + /** + * @private + */ + protected function stage_keyDownHandler(event:KeyboardEvent):void + { + if(event.keyCode == Keyboard.ESCAPE) + { + this.touchPointID = -1; + this.currentState = STATE_UP; + } + if(this.touchPointID >= 0 || event.keyCode != Keyboard.SPACE) + { + return; + } + this.touchPointID = int.MAX_VALUE; + this.currentState = STATE_DOWN; + } + + /** + * @private + */ + protected function stage_keyUpHandler(event:KeyboardEvent):void + { + if(this.touchPointID != int.MAX_VALUE || event.keyCode != Keyboard.SPACE) + { + return; + } + this.resetTouchState(); + this.trigger(); + } + } +} \ No newline at end of file diff --git a/source/feathers/controls/ButtonGroup.as b/source/feathers/controls/ButtonGroup.as new file mode 100644 index 0000000000..db36e659ff --- /dev/null +++ b/source/feathers/controls/ButtonGroup.as @@ -0,0 +1,1906 @@ +/* +Feathers +Copyright 2012-2014 Joshua Tynjala. All Rights Reserved. + +This program is free software. You can redistribute and/or modify it in +accordance with the terms of the accompanying license agreement. +*/ +package feathers.controls +{ + import feathers.core.FeathersControl; + import feathers.core.PropertyProxy; + import feathers.data.ListCollection; + import feathers.layout.HorizontalLayout; + import feathers.layout.LayoutBoundsResult; + import feathers.layout.VerticalLayout; + import feathers.layout.ViewPortBounds; + import feathers.skins.IStyleProvider; + + import starling.display.DisplayObject; + import starling.events.Event; + + /** + * Dispatched when one of the buttons is triggered. The data + * property of the event contains the item from the data provider that is + * associated with the button that was triggered. + * + *

    The following example listens to Event.TRIGGERED on the + * button group instead of on individual buttons:

    + * + * + * group.dataProvider = new ListCollection( + * [ + * { label: "Yes" }, + * { label: "No" }, + * { label: "Cancel" }, + * ]); + * group.addEventListener( Event.TRIGGERED, function( event:Event, data:Object ):void + * { + * trace( "The button with label \"" + data.label + "\" was triggered." ); + * } + * + *

    The properties of the event object have the following values:

    + * + * + * + * + * + * + *
    PropertyValue
    bubblesfalse
    currentTargetThe Object that defines the + * event listener that handles the event. For example, if you use + * myButton.addEventListener() to register an event listener, + * myButton is the value of the currentTarget.
    dataThe item associated with the button + * that was triggered.
    targetThe Object that dispatched the event; + * it is not always the Object listening for the event. Use the + * currentTarget property to always access the Object + * listening for the event.
    + * + * @eventType starling.events.Event.TRIGGERED + */ + [Event(name="triggered", type="starling.events.Event")] + + [DefaultProperty("dataProvider")] + /** + * A set of related buttons with layout, customized using a data provider. + * + *

    The following example creates a button group with a few buttons:

    + * + * + * var group:ButtonGroup = new ButtonGroup(); + * group.dataProvider = new ListCollection( + * [ + * { label: "Yes", triggered: yesButton_triggeredHandler }, + * { label: "No", triggered: noButton_triggeredHandler }, + * { label: "Cancel", triggered: cancelButton_triggeredHandler }, + * ]); + * this.addChild( group ); + * + * @see ../../../help/button-group.html How to use the Feathers ButtonGroup component + * @see feathers.controls.TabBar + */ + public class ButtonGroup extends FeathersControl + { + /** + * The default IStyleProvider for all ButtonGroup + * components. + * + * @default null + * @see feathers.core.FeathersControl#styleProvider + */ + public static var globalStyleProvider:IStyleProvider; + + /** + * @private + */ + protected static const INVALIDATION_FLAG_BUTTON_FACTORY:String = "buttonFactory"; + + /** + * @private + */ + protected static const LABEL_FIELD:String = "label"; + + /** + * @private + */ + protected static const ENABLED_FIELD:String = "isEnabled"; + + /** + * @private + */ + private static const DEFAULT_BUTTON_FIELDS:Vector. = new + [ + "defaultIcon", + "upIcon", + "downIcon", + "hoverIcon", + "disabledIcon", + "defaultSelectedIcon", + "selectedUpIcon", + "selectedDownIcon", + "selectedHoverIcon", + "selectedDisabledIcon", + "isSelected", + "isToggle", + ]; + + /** + * @private + */ + private static const DEFAULT_BUTTON_EVENTS:Vector. = new + [ + Event.TRIGGERED, + Event.CHANGE, + ]; + + /** + * The buttons are displayed in order from left to right. + * + * @see #direction + */ + public static const DIRECTION_HORIZONTAL:String = "horizontal"; + + /** + * The buttons are displayed in order from top to bottom. + * + * @see #direction + */ + public static const DIRECTION_VERTICAL:String = "vertical"; + + /** + * The buttons will be aligned horizontally to the left edge of the + * button group. + * + * @see #horizontalAlign + */ + public static const HORIZONTAL_ALIGN_LEFT:String = "left"; + + /** + * The buttons will be aligned horizontally to the center of the + * button group. + * + * @see #horizontalAlign + */ + public static const HORIZONTAL_ALIGN_CENTER:String = "center"; + + /** + * The buttons will be aligned horizontally to the right edge of the + * button group. + * + * @see #horizontalAlign + */ + public static const HORIZONTAL_ALIGN_RIGHT:String = "right"; + + /** + * If the direction is vertical, each button will fill the entire + * width of the button group, and if the direction is horizontal, the + * alignment will behave the same as HORIZONTAL_ALIGN_LEFT. + * + * @see #horizontalAlign + * @see #direction + */ + public static const HORIZONTAL_ALIGN_JUSTIFY:String = "justify"; + + /** + * The buttons will be aligned vertically to the top edge of the + * button group. + */ + public static const VERTICAL_ALIGN_TOP:String = "top"; + + /** + * The buttons will be aligned vertically to the middle of the + * button group. + * + * @see #verticalAlign + */ + public static const VERTICAL_ALIGN_MIDDLE:String = "middle"; + + /** + * The buttons will be aligned vertically to the bottom edge of the + * button group. + * + * @see #verticalAlign + */ + public static const VERTICAL_ALIGN_BOTTOM:String = "bottom"; + + /** + * If the direction is horizontal, each button will fill the entire + * height of the button group, and if the direction is vertical, the + * alignment will behave the same as VERTICAL_ALIGN_TOP. + * + * @see #verticalAlign + * @see #direction + */ + public static const VERTICAL_ALIGN_JUSTIFY:String = "justify"; + + /** + * The default value added to the styleNameList of the buttons. + * + * @see feathers.core.FeathersControl#styleNameList + */ + public static const DEFAULT_CHILD_STYLE_NAME_BUTTON:String = "feathers-button-group-button"; + + /** + * DEPRECATED: Replaced by ButtonGroup.DEFAULT_CHILD_STYLE_NAME_BUTTON. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see ButtonGroup#DEFAULT_CHILD_STYLE_NAME_BUTTON + */ + public static const DEFAULT_CHILD_NAME_BUTTON:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; + + /** + * @private + */ + protected static function defaultButtonFactory():Button + { + return new Button(); + } + + /** + * Constructor. + */ + public function ButtonGroup() + { + super(); + } + + /** + * The value added to the styleNameList of the buttons. + * This variable is protected so that sub-classes can + * customize the button style name in their constructors instead of + * using the default style name defined by + * DEFAULT_CHILD_STYLE_NAME_BUTTON. + * + *

    To customize the button style name without subclassing, see + * customButtonStyleName.

    + * + * @see #customButtonStyleName + * @see feathers.core.FeathersControl#styleNameList + */ + protected var buttonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; + + /** + * DEPRECATED: Replaced by buttonStyleName. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see #buttonStyleName + */ + protected function get buttonName():String + { + return this.buttonStyleName; + } + + /** + * @private + */ + protected function set buttonName(value:String):void + { + this.buttonStyleName = value; + } + + /** + * The value added to the styleNameList of the first button. + * + *

    To customize the first button name without subclassing, see + * customFirstButtonStyleName.

    + * + * @see #customFirstButtonStyleName + * @see feathers.core.FeathersControl#styleNameList + */ + protected var firstButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; + + /** + * DEPRECATED: Replaced by firstButtonStyleName. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see #firstButtonStyleName + */ + protected function get firstButtonName():String + { + return this.firstButtonStyleName; + } + + /** + * @private + */ + protected function set firstButtonName(value:String):void + { + this.firstButtonStyleName = value; + } + + /** + * The value added to the styleNameList of the last button. + * + *

    To customize the last button style name without subclassing, see + * customLastButtonStyleName.

    + * + * @see #customLastButtonStyleName + * @see feathers.core.FeathersControl#styleNameList + */ + protected var lastButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; + + /** + * DEPRECATED: Replaced by lastButtonStyleName. + * + *

    DEPRECATION WARNING: This property is deprecated + * starting with Feathers 2.1. It will be removed in a future version of + * Feathers according to the standard + * Feathers deprecation policy.

    + * + * @see #lastButtonStyleName + */ + protected function get lastButtonName():String + { + return this.lastButtonStyleName; + } + + /** + * @private + */ + protected function set lastButtonName(value:String):void + { + this.lastButtonStyleName = value; + } + + /** + * @private + */ + protected var activeFirstButton:Button; + + /** + * @private + */ + protected var inactiveFirstButton:Button; + + /** + * @private + */ + protected var activeLastButton:Button; + + /** + * @private + */ + protected var inactiveLastButton:Button; + + /** + * @private + */ + protected var _layoutItems:Vector. = new []; + + /** + * @private + */ + protected var activeButtons:Vector.