Repository: BowlerHatLLC/feathers Branch: master Commit: 44fc2bff265c Files: 785 Total size: 9.6 MB Directory structure: gitextract_keik636y/ ├── .github/ │ ├── SUPPORT.md │ └── workflows/ │ └── package-feathersui.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── build.properties ├── build.xml ├── documentation/ │ ├── README.md │ └── api-reference/ │ ├── package-descriptions.xml │ └── templates/ │ ├── AC_OETags.js │ ├── ASDoc_Config_Base.xml │ ├── ASDoc_terms.xml │ ├── ClassHeader.xslt │ ├── Classes.xslt │ ├── Overviews_Base.xml │ ├── PostProcessing.xslt │ ├── all-classes.xslt │ ├── all-index.xslt │ ├── asdoc-util.xslt │ ├── asdoc.js │ ├── class-files.xslt │ ├── class-list.xslt │ ├── class-parts.xslt │ ├── class-summary.xslt │ ├── cookies.js │ ├── effectsSummary.xslt │ ├── eventsGeneratedSummary.xslt │ ├── fieldSummary.xslt │ ├── help.js │ ├── index-list.html │ ├── index.html │ ├── merge_dita_xml.xslt │ ├── methodSummary.xslt │ ├── mxml-tags.html │ ├── override.css │ ├── package-detail.xslt │ ├── package-frame.html │ ├── package-list.xslt │ ├── package-summary.xslt │ ├── package.xslt │ ├── print.css │ ├── processHTML.xslt │ ├── style.css │ ├── stylesSummary.xslt │ └── title-bar.html ├── examples/ │ ├── ComponentsExplorer/ │ │ ├── README.md │ │ ├── assets/ │ │ │ └── images/ │ │ │ └── icons-readme.txt │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── ComponentsExplorer-app.xml │ │ ├── ComponentsExplorer.as │ │ ├── ComponentsExplorerWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── componentsExplorer/ │ │ ├── Main.as │ │ ├── ScreenID.as │ │ ├── data/ │ │ │ ├── DataGridSettings.as │ │ │ ├── DateTimeSpinnerSettings.as │ │ │ ├── EmbeddedAssets.as │ │ │ ├── GroupedListSettings.as │ │ │ ├── ItemRendererSettings.as │ │ │ ├── ListSettings.as │ │ │ ├── NumericStepperSettings.as │ │ │ └── SliderSettings.as │ │ └── screens/ │ │ ├── AlertScreen.as │ │ ├── AutoCompleteScreen.as │ │ ├── ButtonGroupScreen.as │ │ ├── ButtonScreen.as │ │ ├── CalloutScreen.as │ │ ├── CheckScreen.as │ │ ├── DataGridScreen.as │ │ ├── DataGridSettingsScreen.as │ │ ├── DateTimeSpinnerScreen.as │ │ ├── DateTimeSpinnerSettingsScreen.as │ │ ├── GroupedListScreen.as │ │ ├── GroupedListSettingsScreen.as │ │ ├── ItemRendererScreen.as │ │ ├── ItemRendererSettingsScreen.as │ │ ├── LabelScreen.as │ │ ├── ListScreen.as │ │ ├── ListSettingsScreen.as │ │ ├── MainMenuScreen.as │ │ ├── NumericStepperScreen.as │ │ ├── NumericStepperSettingsScreen.as │ │ ├── PageIndicatorScreen.as │ │ ├── PanelComponentScreen.as │ │ ├── PickerListScreen.as │ │ ├── ProgressBarScreen.as │ │ ├── RadioScreen.as │ │ ├── ScrollTextScreen.as │ │ ├── SliderScreen.as │ │ ├── SliderSettingsScreen.as │ │ ├── SpinnerListScreen.as │ │ ├── TabBarScreen.as │ │ ├── TextCalloutScreen.as │ │ ├── TextInputScreen.as │ │ ├── ToastScreen.as │ │ ├── ToggleSwitchScreen.as │ │ ├── TreeScreen.as │ │ └── WebViewScreen.as │ ├── DragAndDrop/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── DragAndDrop.as │ │ └── feathers/ │ │ └── examples/ │ │ └── dragDrop/ │ │ ├── DragSource.as │ │ ├── DropTarget.as │ │ └── Main.as │ ├── DrawersExplorer/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── DrawersExplorer-app.xml │ │ ├── DrawersExplorer.as │ │ ├── DrawersExplorerWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── drawersExplorer/ │ │ ├── Main.as │ │ ├── skins/ │ │ │ └── DrawersExplorerTheme.as │ │ └── views/ │ │ ├── ContentView.as │ │ └── DrawerView.as │ ├── Gallery/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── Gallery-app.xml │ │ ├── Gallery.as │ │ └── feathers/ │ │ ├── examples/ │ │ │ └── gallery/ │ │ │ ├── Main.as │ │ │ ├── controls/ │ │ │ │ ├── GalleryItemRenderer.as │ │ │ │ └── ThumbItemRenderer.as │ │ │ ├── data/ │ │ │ │ └── GalleryItem.as │ │ │ └── layout/ │ │ │ └── GalleryItemRendererLayout.as │ │ └── utils/ │ │ └── touch/ │ │ └── TouchSheet.as │ ├── HelloWorld/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── HelloWorld-app.xml │ │ ├── HelloWorld.as │ │ ├── HelloWorldWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── helloWorld/ │ │ └── Main.as │ ├── LayoutExplorer/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── LayoutExplorer-app.xml │ │ ├── LayoutExplorer.as │ │ ├── LayoutExplorerWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── layoutExplorer/ │ │ ├── Main.as │ │ ├── data/ │ │ │ ├── FlowLayoutSettings.as │ │ │ ├── HorizontalLayoutSettings.as │ │ │ ├── SlideShowLayoutSettings.as │ │ │ ├── TiledColumnsLayoutSettings.as │ │ │ ├── TiledRowsLayoutSettings.as │ │ │ ├── VerticalLayoutSettings.as │ │ │ └── WaterfallLayoutSettings.as │ │ └── screens/ │ │ ├── AnchorLayoutScreen.as │ │ ├── FlowLayoutScreen.as │ │ ├── FlowLayoutSettingsScreen.as │ │ ├── HorizontalLayoutScreen.as │ │ ├── HorizontalLayoutSettingsScreen.as │ │ ├── MainMenuScreen.as │ │ ├── SlideShowLayoutScreen.as │ │ ├── SlideShowLayoutSettingsScreen.as │ │ ├── TiledColumnsLayoutScreen.as │ │ ├── TiledColumnsLayoutSettingsScreen.as │ │ ├── TiledRowsLayoutScreen.as │ │ ├── TiledRowsLayoutSettingsScreen.as │ │ ├── VerticalLayoutScreen.as │ │ ├── VerticalLayoutSettingsScreen.as │ │ ├── WaterfallLayoutScreen.as │ │ └── WaterfallLayoutSettingsScreen.as │ ├── Magic8Chat/ │ │ ├── README.md │ │ ├── assets/ │ │ │ └── images/ │ │ │ └── icons-readme.txt │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── Magic8Chat-app.xml │ │ ├── Magic8Chat.as │ │ ├── Magic8ChatWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── magic8/ │ │ ├── Main.as │ │ ├── data/ │ │ │ └── ChatMessage.as │ │ └── themes/ │ │ ├── Magic8ChatTheme.as │ │ └── StyleNames.as │ ├── PullToRefresh/ │ │ ├── README.md │ │ ├── assets/ │ │ │ └── images/ │ │ │ └── spinner.xml │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── PullToRefresh-app.xml │ │ ├── PullToRefresh.as │ │ ├── PullToRefreshWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── pullToRefresh/ │ │ └── Main.as │ ├── StackScreenNavigatorExplorer/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── StackScreenNavigatorExplorer-app.xml │ │ ├── StackScreenNavigatorExplorer.as │ │ ├── StackScreenNavigatorExplorerWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── navigator/ │ │ ├── Main.as │ │ └── screens/ │ │ ├── ScreenA.as │ │ ├── ScreenB1.as │ │ ├── ScreenB2.as │ │ └── ScreenC.as │ ├── Tabs/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── Tabs-app.xml │ │ ├── Tabs.as │ │ ├── TabsWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── tabs/ │ │ ├── Main.as │ │ ├── screens/ │ │ │ ├── ContactsScreen.as │ │ │ ├── MessagesScreen.as │ │ │ └── ProfileScreen.as │ │ └── themes/ │ │ ├── StyleNames.as │ │ └── TabsTheme.as │ ├── TileList/ │ │ ├── README.md │ │ ├── assets/ │ │ │ └── images/ │ │ │ ├── atlas@2x.tps │ │ │ └── atlas@2x.xml │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── TileList-app.xml │ │ ├── TileList.as │ │ ├── TileListWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── tileList/ │ │ └── Main.as │ ├── Todos/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── Todos-app.xml │ │ ├── Todos.as │ │ ├── TodosWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── todos/ │ │ ├── Main.as │ │ ├── TodoItem.as │ │ ├── TodosTheme.as │ │ └── controls/ │ │ └── TodoItemRenderer.as │ ├── TrainTimes/ │ │ ├── README.md │ │ ├── assets/ │ │ │ └── images/ │ │ │ ├── traintimes.tps │ │ │ └── traintimes.xml │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── TrainTimes-app.xml │ │ ├── TrainTimes.as │ │ ├── TrainTimesWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── trainTimes/ │ │ ├── Main.as │ │ ├── controls/ │ │ │ └── StationListItemRenderer.as │ │ ├── model/ │ │ │ ├── StationData.as │ │ │ └── TimeData.as │ │ ├── screens/ │ │ │ ├── StationScreen.as │ │ │ └── TimesScreen.as │ │ └── themes/ │ │ └── TrainTimesTheme.as │ ├── TransitionsExplorer/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── TransitionsExplorer-app.xml │ │ ├── TransitionsExplorer.as │ │ ├── TransitionsExplorerWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── transitionsExplorer/ │ │ ├── Main.as │ │ └── screens/ │ │ ├── AllTransitionsScreen.as │ │ ├── ColorFadeTransitionScreen.as │ │ ├── FadeTransitionScreen.as │ │ ├── FourWayTransitionScreen.as │ │ └── IrisTransitionScreen.as │ ├── Video/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── Video-app.xml │ │ ├── Video.as │ │ └── feathers/ │ │ └── examples/ │ │ └── video/ │ │ └── Main.as │ ├── YouTubeFeeds/ │ │ ├── README.md │ │ ├── build.properties │ │ ├── build.xml │ │ └── source/ │ │ ├── YouTubeFeeds-app.xml │ │ ├── YouTubeFeeds.as │ │ ├── YouTubeFeedsWeb.as │ │ └── feathers/ │ │ └── examples/ │ │ └── youtube/ │ │ ├── Main.as │ │ ├── models/ │ │ │ ├── VideoDetails.as │ │ │ ├── VideoFeed.as │ │ │ └── YouTubeModel.as │ │ └── screens/ │ │ ├── ListVideosScreen.as │ │ ├── MainMenuScreen.as │ │ └── VideoDetailsScreen.as │ └── build.xml ├── package-src.json ├── package-swc.json ├── sdk.properties ├── source/ │ └── feathers/ │ ├── FEATHERS_VERSION.as │ ├── controls/ │ │ ├── Alert.as │ │ ├── AutoComplete.as │ │ ├── AutoSizeMode.as │ │ ├── BasicButton.as │ │ ├── Button.as │ │ ├── ButtonGroup.as │ │ ├── ButtonState.as │ │ ├── Callout.as │ │ ├── Check.as │ │ ├── DataGrid.as │ │ ├── DataGridColumn.as │ │ ├── DateTimeMode.as │ │ ├── DateTimeSpinner.as │ │ ├── DecelerationRate.as │ │ ├── DragGesture.as │ │ ├── Drawers.as │ │ ├── GroupedList.as │ │ ├── Header.as │ │ ├── IDirectionalScrollBar.as │ │ ├── IRange.as │ │ ├── IScreen.as │ │ ├── IScrollBar.as │ │ ├── IScrollContainer.as │ │ ├── ImageLoader.as │ │ ├── ItemRendererLayoutOrder.as │ │ ├── Label.as │ │ ├── LayoutGroup.as │ │ ├── List.as │ │ ├── NumericStepper.as │ │ ├── PageIndicator.as │ │ ├── PageIndicatorInteractionMode.as │ │ ├── Panel.as │ │ ├── PanelScreen.as │ │ ├── PickerList.as │ │ ├── ProgressBar.as │ │ ├── PullViewDisplayMode.as │ │ ├── Radio.as │ │ ├── Screen.as │ │ ├── ScreenNavigator.as │ │ ├── ScreenNavigatorItem.as │ │ ├── ScrollBar.as │ │ ├── ScrollBarDisplayMode.as │ │ ├── ScrollContainer.as │ │ ├── ScrollInteractionMode.as │ │ ├── ScrollPolicy.as │ │ ├── ScrollScreen.as │ │ ├── ScrollText.as │ │ ├── Scroller.as │ │ ├── SimpleScrollBar.as │ │ ├── Slider.as │ │ ├── SpinnerList.as │ │ ├── StackScreenNavigator.as │ │ ├── StackScreenNavigatorItem.as │ │ ├── StepperButtonLayoutMode.as │ │ ├── TabBar.as │ │ ├── TabNavigator.as │ │ ├── TabNavigatorItem.as │ │ ├── TextArea.as │ │ ├── TextCallout.as │ │ ├── TextInput.as │ │ ├── TextInputState.as │ │ ├── Toast.as │ │ ├── ToastQueueMode.as │ │ ├── ToggleButton.as │ │ ├── ToggleState.as │ │ ├── ToggleSwitch.as │ │ ├── TrackInteractionMode.as │ │ ├── TrackLayoutMode.as │ │ ├── TrackScaleMode.as │ │ ├── Tree.as │ │ ├── WebView.as │ │ ├── popups/ │ │ │ ├── BottomDrawerPopUpContentManager.as │ │ │ ├── CalloutPopUpContentManager.as │ │ │ ├── DropDownPopUpContentManager.as │ │ │ ├── IPersistentPopUpContentManager.as │ │ │ ├── IPopUpContentManager.as │ │ │ ├── IPopUpContentManagerWithPrompt.as │ │ │ └── VerticalCenteredPopUpContentManager.as │ │ ├── renderers/ │ │ │ ├── BaseDefaultItemRenderer.as │ │ │ ├── DefaultDataGridCellRenderer.as │ │ │ ├── DefaultDataGridHeaderRenderer.as │ │ │ ├── DefaultGroupedListHeaderOrFooterRenderer.as │ │ │ ├── DefaultGroupedListItemRenderer.as │ │ │ ├── DefaultListItemRenderer.as │ │ │ ├── DefaultTreeItemRenderer.as │ │ │ ├── IDataGridCellRenderer.as │ │ │ ├── IDataGridHeaderRenderer.as │ │ │ ├── IDragAndDropItemRenderer.as │ │ │ ├── IGroupedListFooterRenderer.as │ │ │ ├── IGroupedListHeaderRenderer.as │ │ │ ├── IGroupedListItemRenderer.as │ │ │ ├── IListItemRenderer.as │ │ │ ├── ITreeItemRenderer.as │ │ │ ├── LayoutGroupDataGridCellRenderer.as │ │ │ ├── LayoutGroupGroupedListHeaderOrFooterRenderer.as │ │ │ ├── LayoutGroupGroupedListItemRenderer.as │ │ │ ├── LayoutGroupListItemRenderer.as │ │ │ └── LayoutGroupTreeItemRenderer.as │ │ ├── supportClasses/ │ │ │ ├── BaseScreenNavigator.as │ │ │ ├── DataGridDataViewPort.as │ │ │ ├── DataGridRowRenderer.as │ │ │ ├── GroupedListDataViewPort.as │ │ │ ├── IScreenNavigatorItem.as │ │ │ ├── IViewPort.as │ │ │ ├── LayoutViewPort.as │ │ │ ├── ListDataViewPort.as │ │ │ ├── TextFieldViewPort.as │ │ │ └── TreeDataViewPort.as │ │ └── text/ │ │ ├── BaseTextRenderer.as │ │ ├── BitmapFontTextEditor.as │ │ ├── BitmapFontTextRenderer.as │ │ ├── ITextEditorViewPort.as │ │ ├── MeasureTextResult.as │ │ ├── StageTextTextEditor.as │ │ ├── StageTextTextEditorViewPort.as │ │ ├── TextBlockTextEditor.as │ │ ├── TextBlockTextRenderer.as │ │ ├── TextFieldTextEditor.as │ │ ├── TextFieldTextEditorViewPort.as │ │ └── TextFieldTextRenderer.as │ ├── core/ │ │ ├── BaseTextEditor.as │ │ ├── DefaultFocusManager.as │ │ ├── DefaultPopUpManager.as │ │ ├── DefaultToolTipManager.as │ │ ├── FeathersControl.as │ │ ├── FocusManager.as │ │ ├── IAdvancedNativeFocusOwner.as │ │ ├── IFeathersControl.as │ │ ├── IFeathersDisplayObject.as │ │ ├── IFeathersEventDispatcher.as │ │ ├── IFocusContainer.as │ │ ├── IFocusDisplayObject.as │ │ ├── IFocusExtras.as │ │ ├── IFocusManager.as │ │ ├── IGroupedToggle.as │ │ ├── IIMETextEditor.as │ │ ├── IMeasureDisplayObject.as │ │ ├── IMultilineTextEditor.as │ │ ├── INativeFocusOwner.as │ │ ├── IPopUpManager.as │ │ ├── IStateContext.as │ │ ├── IStateObserver.as │ │ ├── ITextBaselineControl.as │ │ ├── ITextEditor.as │ │ ├── ITextRenderer.as │ │ ├── IToggle.as │ │ ├── IToolTip.as │ │ ├── IToolTipManager.as │ │ ├── IValidating.as │ │ ├── PopUpManager.as │ │ ├── PropertyProxy.as │ │ ├── ToggleGroup.as │ │ ├── TokenList.as │ │ ├── ToolTipManager.as │ │ └── ValidationQueue.as │ ├── data/ │ │ ├── ArrayChildrenHierarchicalCollectionDataDescriptor.as │ │ ├── ArrayCollection.as │ │ ├── ArrayHierarchicalCollection.as │ │ ├── ArrayListCollectionDataDescriptor.as │ │ ├── HierarchicalCollection.as │ │ ├── IAutoCompleteSource.as │ │ ├── IHierarchicalCollection.as │ │ ├── IHierarchicalCollectionDataDescriptor.as │ │ ├── IListCollection.as │ │ ├── IListCollectionDataDescriptor.as │ │ ├── ListCollection.as │ │ ├── LocalAutoCompleteSource.as │ │ ├── SortOrder.as │ │ ├── URLAutoCompleteSource.as │ │ ├── VectorCollection.as │ │ ├── VectorHierarchicalCollection.as │ │ ├── VectorIntListCollectionDataDescriptor.as │ │ ├── VectorListCollectionDataDescriptor.as │ │ ├── VectorNumberListCollectionDataDescriptor.as │ │ ├── VectorUintListCollectionDataDescriptor.as │ │ ├── XMLListCollection.as │ │ ├── XMLListHierarchicalCollection.as │ │ └── XMLListListCollectionDataDescriptor.as │ ├── display/ │ │ └── RenderDelegate.as │ ├── dragDrop/ │ │ ├── DragData.as │ │ ├── DragDropManager.as │ │ ├── IDragSource.as │ │ └── IDropTarget.as │ ├── events/ │ │ ├── CollectionEventType.as │ │ ├── DragDropEvent.as │ │ ├── ExclusiveTouch.as │ │ ├── FeathersEventType.as │ │ └── MediaPlayerEventType.as │ ├── layout/ │ │ ├── AnchorLayout.as │ │ ├── AnchorLayoutData.as │ │ ├── BaseLinearLayout.as │ │ ├── BaseTiledLayout.as │ │ ├── BaseVariableVirtualLayout.as │ │ ├── Direction.as │ │ ├── FlowLayout.as │ │ ├── HorizontalAlign.as │ │ ├── HorizontalLayout.as │ │ ├── HorizontalLayoutData.as │ │ ├── HorizontalSpinnerLayout.as │ │ ├── IDragDropLayout.as │ │ ├── IGroupedLayout.as │ │ ├── ILayout.as │ │ ├── ILayoutData.as │ │ ├── ILayoutDisplayObject.as │ │ ├── ISpinnerLayout.as │ │ ├── ITrimmedVirtualLayout.as │ │ ├── IVariableVirtualLayout.as │ │ ├── IVirtualLayout.as │ │ ├── LayoutBoundsResult.as │ │ ├── Orientation.as │ │ ├── RelativeDepth.as │ │ ├── RelativePosition.as │ │ ├── SlideShowLayout.as │ │ ├── TiledColumnsLayout.as │ │ ├── TiledRowsLayout.as │ │ ├── VerticalAlign.as │ │ ├── VerticalLayout.as │ │ ├── VerticalLayoutData.as │ │ ├── VerticalSpinnerLayout.as │ │ ├── ViewPortBounds.as │ │ └── WaterfallLayout.as │ ├── media/ │ │ ├── BaseMediaPlayer.as │ │ ├── BaseTimedMediaPlayer.as │ │ ├── FullScreenToggleButton.as │ │ ├── IAudioPlayer.as │ │ ├── IMediaPlayer.as │ │ ├── IMediaPlayerControl.as │ │ ├── IProgressiveMediaPlayer.as │ │ ├── ITimedMediaPlayer.as │ │ ├── IVideoPlayer.as │ │ ├── MediaTimeMode.as │ │ ├── MuteToggleButton.as │ │ ├── PlayPauseToggleButton.as │ │ ├── SeekSlider.as │ │ ├── SoundChannelPeakVisualizer.as │ │ ├── SoundPlayer.as │ │ ├── SpectrumBarGraphVisualizer.as │ │ ├── TimeLabel.as │ │ ├── VideoPlayer.as │ │ └── VolumeSlider.as │ ├── motion/ │ │ ├── ColorFade.as │ │ ├── Cover.as │ │ ├── Cube.as │ │ ├── EffectInterruptBehavior.as │ │ ├── Fade.as │ │ ├── Flip.as │ │ ├── Iris.as │ │ ├── Move.as │ │ ├── Parallel.as │ │ ├── Resize.as │ │ ├── Reveal.as │ │ ├── Sequence.as │ │ ├── Slide.as │ │ ├── Wipe.as │ │ └── effectClasses/ │ │ ├── BaseEffectContext.as │ │ ├── IEffectContext.as │ │ ├── IMoveEffectContext.as │ │ ├── IResizeEffectContext.as │ │ ├── ParallelEffectContext.as │ │ ├── SequenceEffectContext.as │ │ ├── TweenEffectContext.as │ │ ├── TweenMoveEffectContext.as │ │ └── TweenResizeEffectContext.as │ ├── skins/ │ │ ├── AddOnFunctionStyleProvider.as │ │ ├── ConditionalStyleProvider.as │ │ ├── FunctionStyleProvider.as │ │ ├── IStyleProvider.as │ │ ├── ImageSkin.as │ │ ├── StyleNameFunctionStyleProvider.as │ │ └── StyleProviderRegistry.as │ ├── system/ │ │ └── DeviceCapabilities.as │ ├── text/ │ │ ├── BitmapFontTextFormat.as │ │ ├── FontStylesSet.as │ │ └── StageTextField.as │ ├── themes/ │ │ ├── IAsyncTheme.as │ │ └── StyleNameFunctionTheme.as │ └── utils/ │ ├── ScreenDensityScaleFactorManager.as │ ├── display/ │ │ ├── ScreenDensityScaleCalculator.as │ │ ├── calculateScaleRatioToFill.as │ │ ├── calculateScaleRatioToFit.as │ │ ├── getDisplayObjectDepthFromStage.as │ │ ├── nativeToGlobal.as │ │ └── stageToStarling.as │ ├── focus/ │ │ ├── isBetterFocusForRelativePosition.as │ │ └── isBetterFocusForRelativePosition_LICENSE │ ├── geom/ │ │ ├── matrixToRotation.as │ │ ├── matrixToScaleX.as │ │ └── matrixToScaleY.as │ ├── keyboard/ │ │ ├── KeyToEvent.as │ │ ├── KeyToSelect.as │ │ ├── KeyToState.as │ │ └── KeyToTrigger.as │ ├── math/ │ │ ├── clamp.as │ │ ├── roundDownToNearest.as │ │ ├── roundToNearest.as │ │ ├── roundToPrecision.as │ │ └── roundUpToNearest.as │ ├── skins/ │ │ └── resetFluidChildDimensionsForMeasurement.as │ ├── text/ │ │ ├── TextEditorIMEClient.as │ │ ├── TextInputNavigation.as │ │ └── TextInputRestrict.as │ ├── textures/ │ │ ├── TextureCache.as │ │ └── calculateSnapshotTextureDimensions.as │ ├── touch/ │ │ ├── DelayedDownTouchToState.as │ │ ├── LongPress.as │ │ ├── TapToEvent.as │ │ ├── TapToSelect.as │ │ ├── TapToTrigger.as │ │ └── TouchToState.as │ └── xml/ │ └── xmlListInsertAt.as ├── test/ │ └── source/ │ ├── TestFeathers-app.xml │ ├── TestFeathers.as │ └── feathers/ │ └── tests/ │ ├── AddOnFunctionStyleProviderTests.as │ ├── AlertMeasurementTests.as │ ├── AnchorLayoutTests.as │ ├── ArrayCollectionTests.as │ ├── ArrayHierarchicalCollectionTests.as │ ├── BasicButtonInternalStateTests.as │ ├── BasicButtonMeasurementTests.as │ ├── BasicButtonTests.as │ ├── BitmapFontTextEditorFocusTests.as │ ├── BitmapFontTextRendererTests.as │ ├── BottomDrawerPopUpContentManagerTests.as │ ├── ButtonFocusTests.as │ ├── ButtonGroupDataProviderEventsTests.as │ ├── ButtonGroupMeasurementTests.as │ ├── ButtonGroupTests.as │ ├── ButtonInternalStateTests.as │ ├── ButtonMeasurementTests.as │ ├── ButtonTests.as │ ├── CalloutMeasurementTests.as │ ├── CalloutPopUpContentManagerTests.as │ ├── CalloutTests.as │ ├── ComponentLifecycleTests.as │ ├── ConditionalStyleProviderTests.as │ ├── DateTimeSpinnerTests.as │ ├── DefaultGroupedListHeaderOrFooterRendererMeasurementTests.as │ ├── DefaultListItemRendererInternalStateTests.as │ ├── DefaultListItemRendererMeasurementTests.as │ ├── DrawersMeasurementTests.as │ ├── DrawersTests.as │ ├── DropDownPopUpContentManagerTests.as │ ├── FlowLayoutTests.as │ ├── FocusIndicatorTests.as │ ├── FocusManagerEnabledTests.as │ ├── FocusManagerTests.as │ ├── FontStylesSetTests.as │ ├── FunctionStyleProviderTests.as │ ├── GroupedListDataProviderTests.as │ ├── GroupedListFactoryIDFunctionTests.as │ ├── GroupedListFocusTests.as │ ├── GroupedListRendererAddRemoveTests.as │ ├── GroupedListTests.as │ ├── HeaderInternalStateTests.as │ ├── HeaderMeasurementTests.as │ ├── HeaderTests.as │ ├── HierarchicalCollectionTests.as │ ├── HorizontalLayoutTests.as │ ├── HorizontalSpinnerLayoutTests.as │ ├── ImageLoaderInternalStateTests.as │ ├── ImageLoaderTests.as │ ├── ImageSkinTests.as │ ├── InvalidateTests.as │ ├── KeyToSelectTests.as │ ├── KeyToTriggerTests.as │ ├── LabelMeasurementTests.as │ ├── LabelTests.as │ ├── LayoutGroupHorizontalLayoutTests.as │ ├── LayoutGroupInternalStateTests.as │ ├── LayoutGroupMeasurementTests.as │ ├── LayoutGroupTests.as │ ├── LayoutGroupValidationTests.as │ ├── LayoutGroupVerticalLayoutTests.as │ ├── ListCollectionFilterTests.as │ ├── ListCollectionWithArrayTests.as │ ├── ListFactoryIDFunctionTests.as │ ├── ListFocusTests.as │ ├── ListRendererAddRemoveTests.as │ ├── ListTests.as │ ├── LongPressTests.as │ ├── MinAndMaxDimensionsTests.as │ ├── NumericStepperMeasurementTests.as │ ├── PageIndicatorMeasurementTests.as │ ├── PanelMeasurementTests.as │ ├── PickerListMeasurementTests.as │ ├── PickerListTests.as │ ├── PopUpManagerFocusManagerTests.as │ ├── PopUpManagerTests.as │ ├── ProgressBarMeasurementTests.as │ ├── ProgressBarTests.as │ ├── RadioTests.as │ ├── RestrictedStyleTests.as │ ├── ScaleTests.as │ ├── ScreenNavigatorMeasurementTests.as │ ├── ScreenNavigatorTests.as │ ├── ScrollBarHorizontalMeasurementTests.as │ ├── ScrollBarHorizontalTests.as │ ├── ScrollBarVerticalMeasurementTests.as │ ├── ScrollContainerMeasurementTests.as │ ├── ScrollContainerTests.as │ ├── ScrollContainerValidationTests.as │ ├── ScrollerMeasurementTests.as │ ├── ScrollerTests.as │ ├── SimpleScrollBarHorizontalTests.as │ ├── SimpleScrollBarMeasurementTests.as │ ├── SlideShowLayoutTests.as │ ├── SliderHorizontalMeasurementTests.as │ ├── SliderHorizontalTests.as │ ├── SliderVerticalMeasurementTests.as │ ├── SpinnerListTests.as │ ├── StackScreenNavigatorMeasurementTests.as │ ├── StackScreenNavigatorTests.as │ ├── StageTextTextEditorFocusTests.as │ ├── StyleNameFunctionStyleProviderTests.as │ ├── StyleProviderRegistryTests.as │ ├── StyleTests.as │ ├── TabBarEmptyDataProviderTests.as │ ├── TabBarMeasurementTests.as │ ├── TabBarTests.as │ ├── TabNavigatorTests.as │ ├── TapToSelectTests.as │ ├── TapToTriggerTests.as │ ├── TextAreaFocusTests.as │ ├── TextAreaInternalStateTests.as │ ├── TextAreaTests.as │ ├── TextBlockTextEditorFocusTests.as │ ├── TextBlockTextRendererTests.as │ ├── TextFieldTextEditorFocusTests.as │ ├── TextFieldTextEditorTests.as │ ├── TextFieldTextRendererTests.as │ ├── TextInputFocusTests.as │ ├── TextInputInternalStateTests.as │ ├── TextInputMeasurementTests.as │ ├── TextInputRestrictTests.as │ ├── TextInputTests.as │ ├── TextureCacheTests.as │ ├── TiledColumnsLayoutTests.as │ ├── TiledRowsLayoutTests.as │ ├── TimeLabelTests.as │ ├── ToggleButtonFocusTests.as │ ├── ToggleButtonInternalStateTests.as │ ├── ToggleButtonTests.as │ ├── ToggleGroupTests.as │ ├── ToggleSwitchMeasurementTests.as │ ├── ToggleSwitchTests.as │ ├── TokenListTests.as │ ├── TouchToStateTests.as │ ├── TreeFocusTests.as │ ├── TreeTests.as │ ├── VectorCollectionTests.as │ ├── VectorHierarchicalCollectionTests.as │ ├── VerticalCenteredPopUpContentManagerTests.as │ ├── VerticalLayoutTests.as │ ├── VerticalSpinnerLayoutTests.as │ ├── XMLListCollectionTests.as │ ├── XMLListHierarchicalCollectionTests.as │ ├── XMLListInsertAtTests.as │ └── supportClasses/ │ ├── AssertViewPortBoundsLayout.as │ ├── CustomMediaPlayer.as │ ├── CustomStateContext.as │ ├── CustomStyleProvider.as │ ├── CustomToggle.as │ ├── DisposeFlagQuad.as │ └── ScrollerViewPort.as └── themes/ ├── AeonDesktopTheme/ │ ├── README.md │ ├── assets/ │ │ └── images/ │ │ └── aeon_desktop.xml │ ├── package-src.json │ ├── package-swc.json │ └── source/ │ └── feathers/ │ └── themes/ │ ├── AeonDesktopTheme.as │ ├── AeonDesktopThemeWithAssetManager.as │ └── BaseAeonDesktopTheme.as ├── Export Theme PNGs.jsfl ├── MetalWorksDesktopTheme/ │ ├── README.md │ ├── assets/ │ │ └── images/ │ │ └── metalworks_desktop.xml │ ├── package-src.json │ ├── package-swc.json │ └── source/ │ └── feathers/ │ └── themes/ │ ├── BaseMetalWorksDesktopTheme.as │ ├── MetalWorksDesktopTheme.as │ └── MetalWorksDesktopThemeWithAssetManager.as ├── MetalWorksMobileTheme/ │ ├── README.md │ ├── assets/ │ │ └── images/ │ │ └── metalworks_mobile.xml │ ├── package-src.json │ ├── package-swc.json │ └── source/ │ └── feathers/ │ └── themes/ │ ├── BaseMetalWorksMobileTheme.as │ ├── MetalWorksMobileTheme.as │ └── MetalWorksMobileThemeWithAssetManager.as ├── MinimalDesktopTheme/ │ ├── README.md │ ├── assets/ │ │ ├── fonts/ │ │ │ └── pf_ronda_seven_desktop.fnt │ │ └── images/ │ │ └── minimal_desktop.xml │ ├── package-src.json │ ├── package-swc.json │ └── source/ │ └── feathers/ │ └── themes/ │ ├── BaseMinimalDesktopTheme.as │ ├── MinimalDesktopTheme.as │ └── MinimalDesktopThemeWithAssetManager.as ├── MinimalMobileTheme/ │ ├── README.md │ ├── assets/ │ │ ├── fonts/ │ │ │ └── pf_ronda_seven.fnt │ │ └── images/ │ │ └── minimal_mobile.xml │ ├── package-src.json │ ├── package-swc.json │ └── source/ │ └── feathers/ │ └── themes/ │ ├── BaseMinimalMobileTheme.as │ ├── MinimalMobileTheme.as │ └── MinimalMobileThemeWithAssetManager.as └── TopcoatLightMobileTheme/ ├── README.md ├── assets/ │ └── images/ │ └── topcoat_light_mobile.xml ├── package-src.json ├── package-swc.json └── source/ └── feathers/ └── themes/ ├── BaseTopcoatLightMobileTheme.as ├── TopcoatLightMobileTheme.as └── TopcoatLightMobileThemeWithAssetManager.as ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/SUPPORT.md ================================================ # Feathers Help & Support Looking for some help with [Feathers](https://feathersui.com/learn/as3-starling/)? Start by visiting the [the official Starling Framework forum](http://forum.starling-framework.org/) and create a thread in the [Feathers section](http://forum.starling-framework.org/forum/feathers). You'll get help from a community of experts, including [Josh Tynjala](https://joshblog.net/), the creator of Feathers! ## Additional Resources * [Feathers (Starling) Documentation](https://feathersui.com/learn/as3-starling/) * [Feathers (Starling) API Reference](https://feathersui.com/api-reference/) ================================================ FILE: .github/workflows/package-feathersui.yml ================================================ name: Package Feathers UI for Starling on: push: branches: - master pull_request: branches: - master jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: java-version: 11 distribution: "temurin" - uses: joshtynjala/setup-adobe-air-action@v2 with: air-version: "33.1" accept-license: true - uses: joshtynjala/setup-adobe-flash-player-action@v1 - name: Install dependencies run: | wget -O playerglobal.swc https://fpdownload.macromedia.com/get/flashplayer/updaters/32/playerglobal32_0.swc mkdir ${{ env.AIR_HOME }}/frameworks/libs/player/11.1/ cp -f playerglobal.swc ${{ env.AIR_HOME }}/frameworks/libs/player/11.1/ wget -O flexunit.zip http://mirrors.ibiblio.org/apache/flex/flexunit/4.2.0/binaries/apache-flex-flexunit-4.2.0-4.12.0-bin.zip unzip -q flexunit.zip rm flexunit/flexunit-4.2.0-20140410-flex_4.12.0.swc - name: Checkout Starling run: | git clone https://github.com/Gamua/Starling-Framework $GITHUB_WORKSPACE/starling --depth 1 - name: Ant Build run: | ant full -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" -Dflexunit.root="$GITHUB_WORKSPACE/flexunit" -Dflashplayer="/usr/local/bin/flashplayer" - name: Example Ant Build - ComponentsExplorer working-directory: examples/ComponentsExplorer run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - DragAndDrop working-directory: examples/DragAndDrop run: | ant build -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - DrawersExplorer working-directory: examples/DrawersExplorer run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - HelloWorld working-directory: examples/HelloWorld run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - LayoutExplorer working-directory: examples/LayoutExplorer run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - Magic8Chat working-directory: examples/Magic8Chat run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - PullToRefresh working-directory: examples/PullToRefresh run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - StackScreenNavigatorExplorer working-directory: examples/StackScreenNavigatorExplorer run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - Tabs working-directory: examples/Tabs run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - TileList working-directory: examples/TileList run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - Todos working-directory: examples/Todos run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - TrainTimes working-directory: examples/TrainTimes run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - TransitionsExplorer working-directory: examples/TransitionsExplorer run: | ant build-web -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - name: Example Ant Build - YouTubeFeeds working-directory: examples/YouTubeFeeds run: | ant build-web -Dyoutube.api.key=abc123 -Dflashsdk.root="${{ env.AIR_HOME }}" -Dstarling.root="$GITHUB_WORKSPACE/starling/starling/src" - uses: actions/upload-artifact@v4 with: name: feathersui-starling path: output if-no-files-found: error ================================================ FILE: .gitignore ================================================ .DS_Store Thumbs.db *.swc *.stackdump ._* *.local.properties *.p12 out/ output/ third-party/ signing/ .actionScriptProperties .flexLibProperties .project asconfig.json .settings/ bin-debug/ bin-release/ html-template/ .metadata/ *.iml .idea/ archive/ *.lnk .vscode/ *.code-workspace package-lock.json ================================================ FILE: CHANGELOG.md ================================================ # Feathers UI Release Notes Noteworthy changes in official, stable releases of [Feathers UI](https://feathersui.com/). ## 4.2.0 - 2021 ## 4.1.1 - May 2020 * FeathersControl: Fixed issue where super.visible was never set to false at the completion of a hideEffect. * Scroller: Fixed issue where scroller actualWidth was incorrectly passed to view port minVisibleWidth instead of actualMinWidth. ## 4.1.0 - February 2020 * Targets Starling 2.6. * DefaultTreeItemRenderer: Fixed issue where icons and other styles were not properly restricted, when set outside of a theme. * Effects: Fixed issue where tween delay was not included in total time. * FeathersControl: Fixed issue where a null reference error could be thrown when removing a component in the parent's Event.ADDED_TO_STAGE listener. * FeathersControl: Fixed issue where setting visible to the same value before showEffect or hideEffect completed would incorrectly interrupt the effect. * List: Fixed issue where accessories/icons would disappear when displaying the drag-and-drop avatar. * Scroller: Fixed issue where a null reference error could be thrown in the mouse wheel handler. * Toast: added openEffect, which is triggered after the parent container has run its layout code. Event.OPEN is dispatched when this effect is complete. * WebView: Fixed issue where the height incorrectly defaulted to the same value as the width. ## 4.0.0 - January 2019 See the [Feathers 4.0 Migration Guide](https://feathersui.com/help/migration-guide-4.0.html) for details about how to upgrade to Feathers 4.0 from previous versions. * Drag and drop: Added support for drag-and-drop in List and TabBar components. * Toast: New component for displaying in-app notifications. * Removed APIs that were deprecated in Feathers 3.x. * Button: Fixed issue where scaleWhenDown or scaleWhenHovering could get stuck when returning back to a scale of 1, if no other changes to the button state resulted in a call to setRequiresRedraw(). * DataGrid: Fixed issue where multiple cells could be incorrectly deselected when allowMultipleSelection is true. * DataGrid: Fixed issue where measurement did not account for total combined width of headers. * DefaultDataGridCellRenderer: If dataField is null, uses the data for the entire row instead. * FeathersEventType: Fixed typo in "stateChange" string. * HorizontalLayout: Fixed issue where distributeWidths did not properly use the largest item width when the container's explicit width was not set. * Header: Added detection for iPhone XS, XS Max, and XR to increase status bar height for notch. * ImageLoader: Added new style property to support a custom MeshStyle. * KeyToEvent, KeyToSelect, KeyToState: Fixed null reference error in KeyboardEvent.KEY_DOWN listener if target lost focus before listener was called. * Navigators: Fixed issue where transitionDElayEvent was ignored if it was dispatched before CREATION_COMPLETE. * SimpleScrollBar, ScrollBar: Added fixedThumbSize style to allow the thumb size to remain fixed, even when the scrolling range changes. * Scroller: Fixed issue where pressing left key on keyboard incorrectly jumped to maximum horizontal scroll position. * Scroller: Fixed issue where scrolling was possible with keyboard when using ScrollPolicy.OFF. * Scroller: Fixed null reference error caused by removing mask from leftPullView instead of topPullView when changing the topPullView. * Scroller: Fixed issue where touching a container with snapToPages set to true while it was animating might not continue the animation if needed after TouchPhase.ENDED. * Slider: Fixed issue where touching track with TrackInteractionMode.TO_VALUE would incorrectly limit the range if minimumPadding or maximumPadding is negative. * SpinnerList: Fixed issue where removing from stage before animation completed could change the selectedIndex unexpectedly. * StageTextTextEditor: Fixed issue where a very large width or height would cause the text editor to be positioned below the minimum allowed position. * TextArea: Added prompt property, similar to TextInput. * TextArea: Added innerPadding styles to add padding around both prompt and the text in the view port. Breaking change: You must inner padding on the TextArea instead of setting the padding property on TextFieldTextEditorViewPort. * TextBlockTextRenderer: Fixed issue where the measurement might be wrong if width of height set to negative values. * TextBlockTextRenderer: Fixed issue where height measurement might be wrong when using starling.text.TextFormat. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where texture was offset and cut off on context resture when using vertical align in starling.text.TextFormat. * TextBlockTextRenderer: fixed issue where measurement was wrong when using nativeFilters property. * Themes: Use new starling.assets.AssetManager. * Todos Example: Can reorder items with drag and drop. * Todos Example: Persists todos with SharedObject. * ToggleButton: Fixed issue where the scale for the current state was incorrect when selected. * ToolTipManager: Fixed cast that incorrectly required all custom tooltips to extend Label instead of implement the IToolTip interface. * VideoPlayer: Automatically calls setRequiresRedraw() during playback so that skipUnchangedFrames may remain enabled. ## 3.5.0 - June 2018 * AnchorLayout: fixed issue where measurement could be incorrect when using horizontalCenter or verticalCenter. * BitmapFontTextEditor, TextBlockTextEditor: added Shift+Home, Shift+End, Shift+Up, and Shift+Down keyboard shortcuts. * BitmapFontTextEditor, TextBlockTextEditor: when pasting text, new lines are removed because TextInput displays only a single line. * BitmapFontTextEditor, TextBlockTextEditor: fixed issue where soft keyboard incorrectly opened on mobile when not editable. * BitmapFontTextEditor, TextBlockTextEditor, TextFieldTextEditor: fixed issue where touching outside the text editor incorrectly cleared focus when the FocusManager was enabled (it should only do that without a FocusManager). * BottomDrawerPopUpContentManager: added panelFactory and closeButtonFactory to allow these components to be more easily customized. * DataGrid, List, TabBar: fixed issue where sorting the collection did not update the selected indices. * DateTimeSpinner: fixed issue where the 31st of a month that actually has fewer days could be selected when switching to that month from a different month that has 31 days. * DateTimeSpinner: fixed issue where Event.CHANGE could be dispatched when the selected date had not changed. * DeviceCapabilities: added isLargePhone() method to check for plus-sized phones (sometimes called "phablets"). * DeviceCapabilities: isPhone(), isTablet(), and isLargePhone() methods now use both portrait and landscape sizes to determine the correct classification for a device because it is more accurate. * Effects: Added new built-in animations that can be used by components. Includes Move, Resize, Fade, Iris, Wipe, Sequence, and Parallel. * FeathersControl: Listens for Event.CHANGE on IStyleProvider to allow themes to modify their style providers and have changes reflected automatically. * FeathersControl: added showEffect, hideEffect, moveEffect, resizeEffect, focusInEffect, focusOutEffect, addedEffect, and removeFromParentWithEffect(). * fontStyles: In addition to restricting this style when the property is set, also listens for Event.CHANGE. * GroupedList, Tree: fixed issue where using a data provider that returned XML could cause runtime errors because the item renderer could not be found. * Header: improved "extra" top padding for iPhone X when app is not full screen. * HorizontalLayout, VerticalLayout: fixed issue where scaleX and scaleY were not accounted for when an item uses pivotX or pivotY. * ImageLoader: added loaderContext property to support a custom flash.system.LoaderContext. * List: added addItemWithEffect() and removeItemWithEffect(). * LongPress: fixed issue where the Event.ENTER_FRAME listener was not removed if the target were set to null before the touch ended. * nativeToGlobal: utility function similar to localToGlobal(), except converting between native stage coordinates and global Starling coordinates. * ProgressBar: if the fill skin has a minimum size, and the progress bar's value is equal to its minimum value, the fill skin is hidden. * Scroller: fixed issue where a null reference error could be thrown in the TouchEvent.TOUCH listener under certain conditions. * Scroller: if thrown, a new touch automatically stops scrolling and once again requires dragging a minimum distance to start scrolling. This more closely matches native behavior to allow other containers to take over scrolling if dragged in a new direction. * Scroller: fixed issue where items in the view port might not be positioned correctly when snapScrollPositionsToPixels is true, causing jittery scrolling as items jump between pixels. * ScrollText: added outerPadding, outerPaddingTop, outerPaddingRight, outerPaddingBottom, and outerPaddingLeft properties. * Slider: fixed issue where thumb did not go into down state when using TrackInteractionMode.TO_VALUE. * SpinnerList: Fixed issue where performance could drop temporarily when transitioning from the end back to the beginning (or vice versa) when items repeat. * SpinnerList: fixed missing calls to processStyleRestriction() for showSelectionOverlay and hideSelectionOverlayUnlessFocused. * StackScreenNavigator: added isSwipeToPopEnabled property to activate a swipe gesture to navigate back in history. * StackScreenNavigator: fixed issue where Event.CHANGE was not dispatched again after a transition was cancelled. * StageTextTextEditor: fixed issue where focus was lost after touching an object with a focus owner, and the focus owner contains the TextInput. * TextFieldTextEditor: added softKeyboard property to allow the soft keyboard to be customized on mobile. * TextFieldTextEditor: added resetScrollOnFocusOut property, which is true by default. * TextFieldTextRenderer, TextFieldTextEditor: useGutter property is automatically forced to true if the border property is set to true so that the border is not clipped. * TextInput: fixed issue where a text editor might not receive focus if the TextInput moves between TouchPhase.BEGAN and TouchPhase.ENDED. * Themes: fixed issue where pivots in texture atlas caused some skins to appear at incorrect locations with Starling 2.3. * TiledColumnsLayout: fixed issue where the columns could be incorrectly aligned horizontally when alignment should not be possible. * TiledColumnsLayout: fixed issue where an incorrect number of visible columns was calculated when distributeHeights is true. * TiledColumnsLayout: if distributeWidths is set to true, useSquareTiles is changed to false automatically (or distributeWidths would have no effect). * TiledRowsLayout: if distributeHeights is set to true, useSquareTiles is changed to false automatically (or distributeHeights would have no effect). * Tree: added scrollToDisplayLocation() method. * ValidationQueue: reduced memory allocations to avoid unnecessary garbage collection. * VectorHierarchicalCollection: Fixed issue that caused compilation to fail with classic Adobe Flex SDK. * VerticalLayout: fixed issue where a sticky header might disappear too early if paddingTop is greater than zero. * VideoPlayer: added missing API documentation for FeathersEventType.ERROR. ## 3.4.1 - February 2018 * AnchorLayout: Fixed issue where x and y properties might not be accounted for in measurement if item had AnchorLayoutData, but didn't set left and top. * BitmapFontTextEditor: Fixed issue where the cursor and selection might be positioned incorrectly when alignment is center or right. * BitmapFontTextRenderer: Fixed issue where a new MeshStyle could be created too frequently when getDefaultMeshStyle() returns null. * DataGrid: Fixed issue where reordering the columns might not reorder the column headers if the columns were generated automatically. * DateTimeSpinner: Fixed issue where the default maximum date near the end of a year when using DateTimeMode.DATE_AND_TIME was not far enough into the future. * FDT: Fixed some valid, but unconventional, code that caused this IDE to display false-positive compiler errors. * Hierarchical Collections: Fixed some issues related to using null or empty locations that should have been considered invalid. * ImageLoader: Fixed issue where an IOError or SecurityError might be thrown for an old source that was replaced. * PopUpManager: Fixed issue where an error could be thrown by calling removeAllPopUps() when removing one pop-up might remove others automatically. * TextBlockTextEditor: Fixed issue where the cursor might be positioned incorrectly when alignment is center or right. * TextFieldTextEditor: Fixed issue where text editor would measure itself incorrectly when using embedded fonts because the measurement was based on device fonts instead. * ToggleGroup: Fixed issue where a flag to ignore changes might be disabled too early, causing the selection to change to the wrong value. * Tree: Fixed issue where changing the selected item programatically might not immediately update the appearance of the rendered component. ## 3.4.0 - December 2017 * New Component: DataGrid displays a list of data as a table. Each item is rendered as a row, divided into columns for each of the item's fields. Supports sorting columns, resizing columns, and drag-and-drop reordering of columns. * Support for Android TV. Refactored focus management API and keyboard interaction to support TV remotes. Support scaling to TV resolutions. * Collections: support for sorting. * Alert: fixed null reference error when buttonsDataProvider is null and the accept or cancel key is pressed. * ArrayHierarchicalCollection, VectorHierarchicalCollection: fixed issue where a runtime error could be thrown when checking if an item is a branch if the item is null. * AutoComplete: fixed issue where the list did not close if an item is triggered by a keyboard event. * BitmapFontTextRenderer: added breakLongWords property which can optionally break in the middle of long words if they extend beyond the width of the text renderer's bounds. * BitmapFontTextRenderer: fixed issue where distance field fonts would render blurry and fonts that shouldn't use smoothing would be blurry. * Button: added getScaleForState() and setScaleForState() to support different rendering scales in all states, in addition to the existing scaleWhenDown and scaleWhenHovering. * Button, ToggleButton, ToggleSwitch, List, GroupedList, Tree: Event.TRIGGERED and Event.CHANGE may also be dispatched for Keyboard.ENTER if the key location is KeyLocation.D_PAD. * Callout: added originGap property to optionally add extra spacing between the callout and its origin. * DateTimeSpinner: fixed issue where internal SpinnerLists were not disabled when isEnabled is set to false. * DeviceCapabilities: added simulateDPad property that allows regular keyboard arrow keys to interact with components similarly to a TV remote or another device that dispatches keyboard events with KeyLocation.D_PAD. * DeviceCapabilities: methods that accept a flash.display.Stage parameter now default to null and fall back to Starling.current.nativeStage. * DragDropManager: fixed issue where a null reference error could be thrown if the drag source's stage property was null during cleanup. * FocusManager: can change focus up, down, left, or right if the keyLocation property of the KeyboardEvent is KeyLocation.D_PAD. * FocusManager: supports TransformGestureEvent.GESTURE_DIRECTIONAL_TAP for focus navigation on Apple tvOS. * HorizontalSpinnerLayout: added horizontalAlign property to allow the selected item to be aligned to the left or right instead of the default center. * HorizontalSpinnerLayout: added paddingLeft and paddingRight to affect the position of the selected item, in addition to the horizontalAlign property. * IFocusDisplayObject, added nextUpFocus, nextDownFocus, nextLeftFocus, and nextRightFocus properties, similar to previousTabFocus and nextTabFocus. * IFocusDisplayObject: added isShowingFocus property to check if the focused object is showing its focus indicator. * IListCollection: added sortCompareFunction property to allow sorting of items in the collection. * ImageLoader: fixed issue where a texture that is too large for the current profile would result in a runtime error instead of being caught and turned into Event.IO_ERROR. * ImageSkin: the defaultColor property defaults to 0xffffff so that it behaves more like the defaultTexture. * ImageSkin: throws a runtime error if the color property from the Image superclass is set. Use defaultColor instead. * IScreenNavigatorItem: added transitionDelayEvent to optionally delay the start of the transition until the screen dispatches an event. This allows the screen extra time to initialize and do things like load assets from the web. * ISpinnerLayout: added selectionBounds getter to allow the layout to customize where the selectionOverlaySkin should be positioned. * KeyToEvent: new superclass for KeyToTrigger to allow other events to easily get dispatched on key press. * KeyToSelect, KeyToState, KeyToTrigger: added keyLocation property to optionally require a specific key location (like KeyLocation.D_PAD). * LayoutGroup: fixed issue where AutoSizeMode.STAGE could be ignored if children are positioned beyond stageWidth and stageHeight, which could have made the container larger than expected. * List, GroupedList, Scroller, SpinnerList, TextArea: uses native flash.events.KeyboardEvent.KEY_DOWN for keyboard interaction so that they can cancel focus changes, if necessary. * List, GroupedList, Tree: fixed issue where a layout could be broken if the typicalItem were null. * Mobile Themes: Now enable the FocusManager by default, just like desktop. * NumericStepper: added useLeftAndRightKeys property to optionally allow stepper to be changed with Keyboard.LEFT and Keyboard.RIGHT instead of Keyboard.UP and Keyboard.DOWN. * PickerList: fixed issue where the pop-up list may be given focus in the wrong focus manager when it uses a different focus manager than the PickerList. * ScreenDensityScaleFactorManager: added support for Android TV and Apple tvOS. * ScrollBar, SimpleScrollBar, Slider: fixed issue where the scroll bar could not reach the maximum scroll position with certain page or step values. * Scroller: fixed issue where a null reference error could be thrown if scrolling animation were manually removed just as it completed. * SpinnerList: added hideSelectionOverlayUnlessFocused to allow the selectionOverlaySkin to be hidden when the list is not focused if showSelectionOverlay is true. * SpinnerList: added showSelectionOverlay property to completely hide the selectionOverlaySkin skin when set to false. * SpinnerList: The selectedIndex and selectedItem is changed immediately when an item renderer is triggered or keyboard events change selection, instead of waiting for the animation to complete. * StageTextTextEditor: keyboard arrow keys and Keyboard.ENTER are re-dispatched if KeyLocation.D_PAD so that this text editor will support focus changes, similar to how Keyboard.TAB is already re-dispatched. * TapToEvent: new superclass for TapToTrigger to allow other events to easily get dispatched when tapping a display object. * TapToEvent, TapToTrigger: added new tapCount property to wait for a specific number of taps before dispatching the event. * TextBlockTextEditor: improved support for bidiLevel 1 and right-to-left languages. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where updateSnapshotOnScaleChange would result in incorrect texture dimensions if the scale was set after the component validated the first time but before it rendered. * TextInput: added iconPosition property and support for RelativePosition.RIGHT. * Todos Example: added a TabBar to filter items based on if they are completed or not. * ToggleButton: added scaleWhenSelected property. * TouchToState: if TouchPhase.HOVER is dispatched before TouchPhase.BEGAN, returns to hover state on TouchPhase.ENDED if hitTest() is successful. * Tree: fixed issue where hasVariableItemDimensions was incorrectly forced to true, if possible. Should now be set manually on the layout. * VerticalSpinnerLayout: added verticalAlign property to allow the selected item to be aligned to the top or bottom instead of the default middle. * VerticalSpinnerLayout: added paddingTop and paddingBottom to affect the position of the selected item, in addition to the verticalAlign property. * VideoPlayer: added netStreamFactory to customize how the flash.net.NetStream is created. ## 3.3.1 - October 2017 * BitmapFontTextRenderer: fixed issue where multiple text renderers with multiple custom mesh styles would incorrectly share a single style. * FeathersControl: fixed issue where focusIndicatorSkin was not always disposed. * FontStylesSet: fixed issue where properties from a new starling.text.TextFormat were incorrectly copied to the old TextFormat, which could cause other components to change font styles too. * ImageLoader: fixed issue where texture would not be reused when starling.textures.Texture.asyncBitmapUploadEnabled is false. * ImageLoader: fixed issue where error was thrown if using texture cache and the texture could not be reused in its current state on restoration. * ImageLoader: fixed issue where a runtime error could be thrown if the texture is disposed while the application is deactivated on mobile. * Scroller: fixed issue where top and bottom offsets were used instead of left and right when determining if the horizontal scroll bar should be displayed. * Scroller: fixed issue where pull views would not work sometimes if hasElasticEdges is false. * ScrollText: fixed issue where Event.TRIGGERED would not work if FocusManager is enabled because it didn't implement INativeFocusOwner to return its TextField. * StageTextTextEditor: fixed issue where setting the parent TextInput's visible property to false inside a FeathersEventType.FOCUS_OUT listener would hide the background, but not the StageText. * StageTextTextEditor: fixed issue where calling clearFocus() after setting the parent TextInput's visible property to false would hide the background, but not the StageText. * TabNavigator: fixed issue where the previous screen was incorrectly recreated if isSwipeEnabled is true and a swipe transition is cancelled. * TextInputRestrict: fixed issue where -, ^, and \ characters could not be escaped. Used by BitmapFontTextEditor and TextBlockTextEditor. ## 3.3.0 - July 2017 See the [Feathers 3.3 Migration Guide](https://feathersui.com/help/migration-guide-3.3.html) for details about how to upgrade to Feathers 3.3. * New Component: Tree is a List-like component designed for displaying nested hierarchical data, with branches that may be opened and closed. * New Layout: SlideShowLayout is designed for displaying one image at a time in a gallery. * BaseDefaultItemRenderer: fixed issue in skinSourceField where the wrong variable was checked to determine if the property has changed. * BaseDefaultItemRenderer: fixed issue where icon or accessory dimensions were not accounted for in measurement if item renderer does not have a label. * BaseLinearLayout: new abstract base class for HorizontalLayout and VerticalLayout that shares common code. * BaseTiledLayout: new abstract base class for TiledRowsLayout and TiledColumnsLayout that shares common code. * BottomDrawerPopUpContentManager: added customCloseButtonStyleName to customize the style name of the close button in the theme. * BottomDrawerPopUpContentManager, CalloutPopUpContentManager, DropDownPopUpContentManager, VerticalCenteredPopUpContentManager: fixed issue where the content was not scaled the same as the origin. * Callout: fixed issue where stage dimensions were not accounted for when calculating maximum dimensions of content. * Callout: fixed issue where moving origin when content is smaller than background skin could cause content to be rendered at incorrect size. * Cover, Reveal, Wipe: fixed issue where runtime error could be thrown if mask was unexpectedly removed from display objects. * DateTimeSpinner: fixed issue where you could not set the itemRendererFactory directly on the inner SpinnerLists when the DateTimeSpinner itemRendererFactory was null. * DefaultFocusManager: fixed issue where addEventListener() was called where removeEventListener() should have been called, potentially causing a memory leak. * DefaultFocusManager: fixed issue where maintainTouchFocus was incorrectly ignored. * Direction: added NONE constant that may be used in some situations. * DropDownPopUpContentManager: fixed issue where the delegate used for animation was not scaled by the same amount as the content it mirrored. * DropDownPopUpContentManager, VerticalCenteredPopUpContentManager: fixed issue where content was not positioned or resized correctly if PopUpManager.root is scaled. * FeathersControl: throws an error if validate() is called during initialize() because it was not clear that this previously returned without doing anything. * FeathersControl: fixed issue where setting minWidth or minHeight that is larger than the actualWidth and actualHeight might fail to invalidate the component. * FeathersControl: fixed issue where setting the validation queue before initialization could cause a navigator to trigger validation when showing a screen during initialization and validate something too early. * FocusManager: fixed issue where getFocusManagerForStage() threw a RangeError if stack size is 0 instead of returning null. * FontStylesSet: added dispose() method to make sure event listeners are removed (to be called by the parent of the text renderer/editor). * FontStylesSet: no longer calls clone() on starling.text.TextFormat because this prevents detection of changes to original TextFormat object. This reverts a change in Feathers 3.1.2 and goes back to previous behavior (while still fixing the memory leak that prompted the change). * GroupedList: fixed issue where first/last/single item renderer factories were not used as fallbacks when factoryIDFunction returns null. * GroupedList, List: fixed issue where mouse wheel did not work when useVirtualLayout is false in layout. * GroupedList: fixed issue where keyboard navigation failed after multiple groups. * HorizontalSpinnerLayout, VerticalSpinnerLayout: fixed issue where keyboard navigation did not loop when items are repeated. * ILayout: added calculateNavigationDestination() to allow custom behavior for keyboard navigation. * IListCollection: new interface to support custom collection implementations, and added ArrayCollection, VectorCollection, and XMLListCollection. * IHierarchicalCollection: new interface to support custom hierarchical collection implementations, and added ArrayHierarchicalCollection, VectorHierarchicalCollection, and XMLListHierarchicalCollection. * ImageLoader: fixed issue where originalSourceWidth and originalSourceHeight properties returned the wrong value in an Event.COMPLETE listener. * ImageLoader: fixed issue where scaleFactor getter returned incorrect value. * LayoutGroup, ScrollContainer: in a subclass that overrides draw(), if a child is resized or has changes to its layoutData before super.draw() is called, the container will not be invalidated to avoid the "returned to validation queue too many times during validation" error. * SoundPlayer: added soundLoaderContext property to allow a flash.media.SoundLoaderContext to be passed in for the internal load() call. * Scroller: added horizontalPageIndex and verticalPageIndex setters so that you can change pages without calling scrollToPageIndex() (which is meant for animation). * Scroller: fixed issue where scroll bar would fade out immediately when beyond the minimum or maximum scroll position instead of waiting until after the scroller snaps back into range. * Scroller: if hasElasticEdges is false, does not consider itself dragged if already at the minimum or maximum and can't be scrolled further. * Scroller: fixed issue with snapScrollPositionToPixels where the animation would appear to complete because it had already snapped to the final pixel, but there could still be more time left on the animation. * Scroller: fixed issue where measured view port dimensions (such as those from a layout) that are smaller than content dimensions would cause the full dimensions to exclude the scroll bars. This would sometimes cause both horizontal and vertical scroll bars to appear when only one should be required. * Scroller: fixed incorrect maximum page index calculation caused by floating point math error and Math.ceil. * Scroller: fixed issue where pull views with pivots were not masked correctly. * ScrollContainer: fixed issue where children positioned at negative coordinates did not affect the minimum scroll position. * ScrollContainer: fixed issue where pivotX and pivotY were not scaled when calculating item position. * SpinnerList: fixed issue where an item renderer that is disabled could be incorrectly selected. Returns to the previously selected index if the scroll position lands on a disabled item renderer. * SpinnerList: fixed issue where pageThrowDuration property was ignored when scrolling horizontally. * TabNavigator: fixed issue where isSwipeEnabled getter returned incorrect value. * TextArea: fixed issue where runtime error would be thrown in measureViewPort is true. * TextFieldTextEditor: fixed issue where state changes in the parent component would not always update the font styles when using starling.text.TextFormat. * Text Renderers/Editors: if they have a texture snapshot, optimized to avoid updating the snapshot until render() is called, in case it needs to validate() multiple times per frame (which is common in lists). * TiledColumnsLayout, TiledRowsLayout: deprecated PAGING_NONE, PAGING_HORIZONTAL, and PAGING_VERTICAL in favor of Direction.NONE, Direction.HORIZONTAL, and Direction.VERTICAL. * ToggleSwitch: now uses ExclusiveTouch so that parent containers cannot scroll while dragging thumb. * Gallery Example: replaced full size image with a List that uses SlideShowLayout, and the full size image may be resized with a gesture. ## 3.2.0 - April 2017 * PullToRefresh: new example that demonstrates how to support the popular "pull to refresh" gesture with Feathers lists and other scrolling containers. * TabNavigator: support for swiping between tabs. * ListCollection: added filterFunction property to support filtering items in data providers. * API Reference: All classes now specify the version of Feathers when they were first added. * Added [Deprecated] metadata to deprecated APIs. * Alert: added acceptButtonIndex and cancelButtonIndex to allow keyboard (or hardware back button) control over alert. * AnchorLayout: fixed issue where maxWidth and maxHeight were ignored when using top/right/bottom/left on AnchorLayoutData. * AutoComplete, PickerList: fixed issue where event listeners were not added to default popUpContentManager created in initialize(). * BitmapFontTextEditor, TextBlockTextEditor: added support for blinking cursor when focused. * BitmapFontTextEditor, TextBlockTextEditor: fixed issue where FeathersEventType.FOCUS_OUT would not be dispatched afte calling setFocus() when the FocusManager is not enabled. * BitmapFontTextRenderer: fixed an issue where extra whitespace would appear at the end of every line. * BitmapFontTextRenderer: added support for kerning and letterSpacing properties of starling.text.TextFormat. * Button, DefaultGroupedListHeaderOrFooterRenderer, Header: added wordWrap property. No longer needs to be set in text renderer factory, but existing code that sets it there will continue to work. * Button, DefaultGroupedListHeaderOrFooterRenderer, Header: added numLines getter to get the number of lines displayed in the text renderer. * Button: fixed issue where label text renderer measurement was incorrect if minWidth or minHeight is set explicitly. * CalloutPopUpContentManager: similar to Callout, the direction property is now deprecated and added supportedPositions as its replacement. * DateTimeSpinner: added backgroundSkin, backgroundDisabledSkin, and padding properties. * DateTimeSpinner: fixed issue where pending value of scrollToDate() was not cleared. * Drawers: content property may now be null when validating. However, it should not be null when opening a drawer. * FeathersControl; layoutData is set to null when disposed to avoid potential memory leaks. * FeathersControl: Removes event listeners on styleNameList when disposed so that they cannot be called for no reason. * FeathersControl; added ignoreNextStyleRestriction() to allow components to set defaults during initialization while still allowing a theme to replace styles later. * FeathersControl: fixed an issue where measured minimum dimensions were not affected by explicit maximum dimensions. * GroupedList: similar to items, an error is thrown if duplicate header or footer data appears in the data provider. * HorizontalLayout, VerticalLayout: fixed issue where includeInLayout was ignored when distributing item sizes. * HorizontalLayout, VerticalLayout: fixed issue where includeInLayout was ignored when using percent dimensions. * HorizontalLayout, VerticalLayout: fixed issue where the typicalItem could not resize after layout. * ImageLoader: supports asynchronous texture uploads to improve performance when uploading textures to the GPU. * ImageLoader: exposed sourceToTextureCacheKey() to allow subclasses to override the key used in the TextureCache for non-URL sources. * ImageLoader: createTextureOnRestore accepts sources that are non-URLs to allow subclasses to override this behavior. * IPopUpContentManager: now includes EventDispatcher APIs so that casting is not required. * Item Renderers: callbacks like labelFunction and iconFunction now support a second, optional parameter for the item's index. For example, labelFunction may now use either of the following signatures: function(item:Object):String or function(item:Object, index:int):String. * Item Renderers: will now display data when owner is null. * KeyToState: new utility class to change a component's state based on keyboard events. * KeyToTrigger, KeyToSelect: fixed issue where event listeners added to the stage would not be removed if the target was set to null before it was removed from stage. * List, GroupedList; when updateAll() is called on the data provider, items that were added or removed from source are now rendered. * List, GroupedList: fixed issue where event listeners were not added to default layout created in initialize(). * List, GroupedList: fixed issue where an item could not receive a new factoryID after its index changes. * ListCollection, HierarchicalCollection: removeAll() no longer results in CollectionEventType.RESET. This should not have been considered a drastic reset. CollectionEventType.REMOVE_ALL is dispatched instead. * PickerList: added itemRendererFactory and customItemRendererStyleName. They no longer need to be set in the listFactory. However, existing code that sets them in the listFactory will continue to work correctly. * Navigators: validates active screen when navigator validates to avoid flickering on next frame with delayed automatic validation. * ScrollContainer: renamed internal stage_resizeHandler to scrollContainer_stage_resizeHandler because ASC 1.0 might consider it a conflict. * Scroller: fixed issue where a state change would not cause the scroller to measure its new background skin. * Scroller: fixed issue where a layout change would not cause the scroller to measure its content again. * Scroller: added horizontalScrollBarPosition to allow the horizontal scroll bar to appear on top. * Scroller: added support for pull views on top, right, bottom, and left to support "pull to refresh" gesture. * Scroller: fixed issue where scrollToPageIndex() would not result in dispatch of FeathersEventType.SCROLL_START and FeathersEventType.SCROLL_COMPLETE. * SpinnerList: fixed issue where scroll position was not updated if layout snapInterval changed. * StageTextTextEditor: position of StageText can no longer be larger than 8191 or smaller than -8192 to avoid a runtime error. * StageTextTextEditor: added clearButtonMode property to support new StageText API. * StageTextTextEditor: does not call assignFocus() on StageText if StageText already has focus because this can cause soft keyboard to close and re-open on iOS. * TabBar: fixed issue where setSelectedIndexWithAnimation() and setSelectedItemWithAnimation() did not change the value of the selectedItem property. * TabBarSlideTransitionManager: moved to feathers-compat project. * TextBlockTextRenderer: fixed issue where a new line width would not be properly detected when using content property, and optimized for the standard text case. * TextBlockTextRenderer: added support for leading, kerning, and letterSpacing properties of starling.text.TextFormat. * TextBlockTextRenderer, TextFieldTextRenderer: fixed incorrect position of snapshots when using updateSnapshotOnScaleChange. * TextFieldTextRenderer: ensures that _text property is not null because flash.text.TextField does not support null values. * TextInput: no longer shows IBEAM cursor on TouchPhase.HOVER if isEditable and isSelectable are both false. * TouchToState: new utility class to change a component's state based on TouchPhase values. * VerticalCenteredPopUpContentManager: fixed margin setter that passed 0 to marginTop/marginRight/marginBottom/marginLeft instead of new value. * VerticalLayout: alignment of headers with getScrollPositionForIndex() defaults to VerticalAlign.TOP because that makes more sense for headers instead of VerticalAlign.MIDDLE. * VideoPlayer: fixed issue where display state was not properly updated when exiting full screen with the Escape key. ## 3.1.2 - January 2017 * FontStylesSet: Clones or copies properties from starling.text.TextFormat to avoid memory leak. ## 3.1.1 - November 2016 * AnchorLayout: fixed issue where using percentWidth would result in an error about maxWidth being NaN. * DefaultListItemRenderer: fixed issue where defaultSkin and defaultIcon properties were not treated correctly as styles. * FlowLayout: fixed issue where alignment to the center or right was not correct when container has explicit width. * Header: accounts for new Capabilities.os value on some recent iOS devices when calculating extra padding for status bar when not full screen. * HorizontalLayout, VerticalLayout fixed issue where using requestedColumnCount/requestedRowCount would result in incorrect view port dimensions if layout contained zero items. * TextBlockTextRenderer, TextBlockTextEditor: fixed issue where text would not be clipped sometimes if truncation is disabled. * TextBlockTextRenderer: fixed issue where center or bottom alignment was offset incorrectly. * ToggleButton: fixed issue where defaultLabelProperties, selectedUpLabelProperties, and other selected label properties were ignored. ## 3.1.0 - October 2016 See the [Feathers 3.1 Migration Guide](https://feathersui.com/help/migration-guide-3.1.html) for details about how to upgrade to Feathers 3.1. * New Component: TabNavigator to display a TabBar that switches between screens, similar to a ScreenNavigator. * Font Styles: all components support starling.text.TextFormat for font styling. For advanced needs, text renderers can still use low-level ElementFormat/TextFormat objects which take precedence. * Style Properties: some properties are now considered styles, and a theme cannot replace their values if they are set outside of the theme first. No more AddOnFunctionStyleProvider, validation, or extending the theme required. * Architecture: Attempts to use stage.starling instead of Starling.current, if possible. Brings better compatibility with multiple Starling instances. * Architecture: switched many places to use starling.utils.Pool instead of static helper objects. * AnchorLayout: fixed issue where maxWidth wasn't used when explicitWidth was not set. * AnchorLayout, HorizontalLayout, VerticalLayout: with percentWidth and percentHeight, explicitMinWidth and explicitMinHeight will be used as the final minimum bounds instead of calculated minimums sent to saveMeasurements(). * BitmapFontTextRenderer: fixed infinite loop when wordWrap is true and maxWidth is 0. * BitmapFontTextRenderer: added style property to support a custom MeshStyle. * BitmapFontTextRenderer: fixed issue where resizing larger would not change position of aligned text. * Button: fixed issue where header would invalidate too often if icon dimensions change. * Button: fixed alignment when using scaleWhenDown or scaleWhenHovering. * ButtonBar: implements ITextBaselineControl to expose button baseline. * Callout: is positioned in parent's coordinate space, instead of stage coordinate space. * ColorFade: fixed issue where Quad could be given a width or height of 0 in its constructor, which causes a runtime error. * Cube: fixed issue with culling that caused screen to overlap incorrectly during transition. * DateTimeSpinner: added customItemRendererStyleName. * Default Item Renderers: added customIconLoaderStyleName and customAccessoryLoaderStyleName for icon and accessory ImageLoaders. * Default Item Renderers: uses customHitTest on TapToTrigger, TapToSelect, and LongPress to exclude accessory from touches (instead of old custom implementation). * DropDownPopUpContentManager: fixed issue where Quad could be given a width or height of 0 in its constructor, which causes a runtime error. * FeathersControl: runtime error is thrown if a component is repeatedly added to validation queue in the same frame. * FeathersControl: instead of adding listeners for FeathersEventType.FOCUS_IN and FeathersEventType.FOCUS_OUT when focusManager is set, adds listeners automatically if component implements IFocusDisplayObject. * FlowLayout: fixed issue where horizontal alignment did not account for items larger than the width of the view port. * GroupedList, List: fixed issue where calling scrollToDisplayIndex() would result in a runtime error if dataProvider is null. * Header: uses ScreenDensityScaleCalculator to calculate extra padding on iOS when app is not full screen. * Header: fixed issue where header would invalidate too often if item dimensions change. * Header: fixed issue where extra status bar padding for iOS might not be calculated correctly if background skin height is large enough. * HorizontalLayout, VerticalLayout: fixed issue where distributeWidths and distributeHeights did not work correctly when useVirtualLayout is true. * HorizontalLayout, VerticalLayout: fixed issue where percentHeight or percentWidth might not be used during measurement. * HorizontalLayout, VerticalLayout: fixed issue where maxWidth or maxHeight would be incorrectly limited. * HorizontalLayout, VerticalLayout: fixed issue where requestedRowCount and requestedColumnCount did not work correctly when useVirtualLayout is false. * HorizontalLayout, VerticalLayout: added maxColumnCount and maxRowCount properties. * HorizontalSpinnerLayout, VerticalSpinnerLayout: fixed runtime error in snapInterval property when typicalItem is null. * ImageLoader: fixed issue where scale9Grid incorrectly allowed maintainAspectRatio to remain in effect. * ImageLoader: fixed issue where a layout with percentWidth and percentHeight might not work because minimum dimensions were not calculated correctly. * ImageLoader: does not call close() on flash.display.Loader because this can cause a memory leak when using ImageDecodingPolicy.ON_LOAD. Instead, switches to different Event.COMPLETE listener to dispose BitmapData and unload image. * ImageSkin: fixed issue where skin would not resize correctly after setting explicit dimensions and then clearing them. * ITextRenderer: added numLines getter that returns the number of lines of text that are wrapped. * ITextRenderer, ITextEditor: added fontStyles property that accepts a FontStylesSet. This is not meant to be used by application developers, but custom component authors. Application developers should set font styles on the parent component instead of text renderer/editor. * LayoutGroup Item Renderers: added backgroundSelectedSkin to optionally customize background when selected. * LayoutGroup, ScreenNavigator, ScrollContainer: StackScreenNavigator: fixed issue where AutoSizeMode.STAGE would be ignored if the navigator validated before being added to the stage. * LayoutGroup, ScrollContainer: the default layout (when the layout property is null) now accounts for pivotX and pivotY during measurement. * MultiStarlingStyleNameFunctionTheme: moved to feathers-compat. * Panel: fixed issue where header would invalidate too often if header dimensions changes. * PickerList: calls revealScrollBars() on pop-up list when opened to show whether scrolling is possible. * PickerList: implements ITextBaselineControl to expose button baseline. * PopUpManager: now accounts for pivotX and pivotY when centering a pop-up. * PopUpManager: added popUpCount property to indicate how many pop-ups are currently open. * PopUpManager: added removeAllPoUps() function to remove all open pop-ups. * ScreenDensityScaleCalculator: pulled out calculation of scale factor using DPI from ScreenDensityScaleFactorManager into separate class that can be used elsewhere. * ScreenNavigator, StackScreenNavigator: the default transition (which has no effect) now happens immediately instead of waiting for next frame the way that animated transitions are treated. * Scroller: fixed issue where final touch movement would not be included in drag on TouchPhase.ENDED. * Scroller: runtime error is thrown if measurement of view port gets into an infinite loop. Previously, it broke out of the loop, but performance would suffer. * Scroller: checks for drag start on TouchPhase.MOVED so that the Quad touch blocker appears faster and the view port does not receive invalid touches. Continues to update velocity on Event.ENTER_FRAME. * Scroller: fixed issue where a runtime error was thrown when a bubbling TouchEvent continued after removing the listener. * SpinnerList: fixed issue where pageThrowDuration property was ignored when scrolling horizontally. * SpinnerList: fixed issue where scroll position was not updated after removing or adding item before the selected item. * StackScreenNavigator: fixed issue where navigator could transition infinitely because state was not cleared correctly. * StageTextTextEditor, TextFieldTextEditor: fixed issue where the texture would be updated too frequently because the wrong texture dimensions were used for comparison. * StageTextTextEditor, TextFieldTextEditor: added maintainTouchFocus property that will keep the text editor in focus if something else is touched. On mobile, this will keep the soft keyboard open. Requires AIR 22. * StageTextTextEditor: fixed issue where StageText could not always be hidden when isEditable is false. * StyleNameFunctionTheme: has a property for the Starling instance it is associated with. * StyleNameFunctionTheme: automatically supports multiple Starling instances. Create a new instance of the theme when a new instance of Starling is current. * TabBar: dispatches Event.TRIGGERED when a tab is triggered. The event's data property references the item from the data provider. * TabBar: added selectedSkin property to display an animated overlay over the tabs to indicate selection. * TabBar: added setSelectedIndexWithAnimation() to animate the selectedSkin on programatic selection changes (always animated on user changes). * TabBar: added labelField, labelFunction, iconField, iconFunction, enabledField and enabledFunction. These are no longer controlled by tabInitializer property. * TabBar: icon from ListCollection is not disposed, and dispose() function on ListCollection should be used. * TabBar: implements ITextBaselineControl to expose tab baseline. * TapToTrigger, TapToSelect, LongPress: added customHitTest property to allow items to be excluded or other custom behavior. * TextArea: no longer changes selection range when given focus because Flex and HTML textarea element don't do that. * TextArea: exposed selectionBeginIndex and selectionEndIndex properties, similar to TextInput. * TextArea: fixed issue where calling selectRange() immediately after setFocus() would incorrectly change selection. * TextArea, TextInput: fixed issue where changing errorString while input has focus would not change visibility of TextCallout (such as when setting to null). * TextBlockTextRenderer, TextBlockTextEditor, TextFieldTextRenderer, TextFieldTextEditor: uses SystemUtil.isEmbeddedFont() to determine if font styles are embedded when using starling.text.TextFormat. * TextBlockTextRenderer, TextFieldTextRenderer: optimize render() function to avoid calling getTransformationMatrix() unless required. * TextBlockTextRenderer, TextFieldTextRenderer: uses smallest texture possible, even when dimensions are explicit to save memory and optimize performance (so that resizing larger doesn't cause a new texture to be required). * TextInput: calling setFocus() programatically will select all text, for consistency with Flex. * TextInput: fixed issue where incorrect selection range would be reported in FeathersEventType.FOCUS_IN listener. * TextInput: fixed issue where selection range would not be set if text editor did not exist yet. * Text Renderers, Text Editors: when using starling.text.TextFormat, supports vertical alignment. * TiledColumnsLayout, TiledRowsLayout: added distributeWidths and distributeHeights properties. * ToggleGroup: added numItems property and getItemAt() method. * ToggleSwitch: implemented IStateContext with states defined in feathers.controls.ToggleState class. * ValidationQueue: no longer keeps a delayed queue that will be validated a frame later because FeathersControl throws an error in the cases where it was used. * VerticalLayout: fixed issue where scroll position calculation did not account for sticky header on GroupedList. * VideoPlayer: added events for MediaPlayerEventType.CUE_POINT and MediaPlayerEventType.XMP_DATA for NetStream's onCuePoint and onXMPData. * VideoPlayer: invalidates layout after Event.READY so that it might resize, if needed. * WebView: added FeathersEventType.LOCATION_CHANGING. * New Example: Tabs, a demonstration of the new TabNavigator component. * New Example: Magic8Chat, a mobile chat application. ## 3.0.4 - September 2016 * Header: fixed issue where extra padding for status bar did not work on iOS 10. ## 3.0.3 - July 2016 * ImageLoader: Fixed issue where reusing the existing texture did not cause the rendered view to update when skipUnchangedFrames is true. * Text Renderers: Fixed issue where reusing the existing texture(s) did not cause the rendered view to update when skipUnchangedFrames is true. ## 3.0.2 - June 2016 * Scroller: Fixed issue where view port mask would not always be resized, such as when items are added to a List. ## 3.0.1 - June 2016 * List, GroupedList: fixed issue where ViewPortBounds minWidth and minHeight could be NaN (this broke percentWidth and percentHeight on some layouts). * HorizontalLayout, VerticalLayout: fixed issue where layout could invalidate every frame when using percentages. * FeathersControl: fixed issue where setting width or height, then scaleX or scaleY, then trying to set original width or height would fail. ## 3.0.0 - June 2016 See the [Feathers 3.0 Migration Guide](https://feathersui.com/help/migration-guide-3.0.html) for details about how to upgrade to Feathers 3.0. * Support for Starling Framework 2.0 * Minimum runtime version is now Flash Player 19 and AIR 19. * All Components: now automatically calculate minimum dimensions when they are not set explicitly. These values may be used by some layouts, such as when specifying percentWidth and percentHeight. * New Example: StackScreenNavigatorExplorer demonstrates various options for StackScreenNavigator. * Examples: updated to use ScreenDensityScaleFactorManager. * Examples: updated to use Starling's new skipUnchangedFrames property. * Example Themes: updated to scale based on contentScaleFactor instead of Capabilities.screenDPI. * Example Themes: Redesigned using Animate CC, and exported as sprite sheet. Find links to original FLA files in Feathers Help. * Migrated shared constants to a single class. Example: HORIZONTAL_ALIGN_LEFT, HORIZONTAL_ALIGN_CENTER, and HORIZONTAL_ALIGN_RIGHT are now available on the feathers.layout.HorizontalAlign class. See migration guide for details and regular expressions for Find/Replace. * AnchorLayout: optimized measurement of children by restricting dimensions before validation. * BasicButton: new superclass of Button that has only a background skin. Useful as for skinning components like a Slider's thumb or tracks that don't need an icon or label. * BitmapFontTextEditor: fixed issue where selectionAnchorIndex was not updated in certain situations. * BitmapFontTextRenderer: fixed issue where explicit dimensions were ignored in measurement. * BitmapFontTextRenderer: replaced snapToPixels property with pixelSnapping property to match Starling 2.0 naming convention. * BitmapFontTextRenderer: added support for offsetX and offsetY properties from starling.text.BitmapFont. * BitmapFontTextRenderer: optimized measurement of width by skipping calculations if maximum is larger than last width. * BottomDrawerPopUpContentManager: added overlayFactory property to customize the modal overlay. * Button: deprecated stateToSkinFunction. Replaced by feathers.skins.ImageSkin. * Button: deprecated upLabelProperties, hoverLabelProperties, downLabelProperties, disabledLabelProperties. Replaced by setting font styles on text renderer in labelFactory. Text renderers now support multiple font styles for different states. * Button: states are defined in feathers.controls.ButtonState. * Button: fixes issue where some icons or skins would not be disposed when button is disposed. * ButtonGroup: fixed issue where changing isEnabled in data provider to false and then true would not re-enable a button. * ButtonGroup: added buttonReleaser property that works similarly to buttonInitializer, but for cleaning up a tab. * Callout: deprecated supportedDirections property, and replaced it with supportedPositions property that accepts a Vector. of constants defined by the RelativePosition class. Allows more flexibility in the preferred order of callout positions. * Callout: added horizontalAlign and verticalAlign properties to customize alignment of callout relative to its origin. * CalloutPopUpContentManager: added overlayFactory property to customize the modal overlay. * ConditionalStyleProvider: new style provider where the result of a function selects between two style providers. * DateTimeSpinner: added itemRendererFactory property to allow the item renderer to be customized. Must return a DefaultListItemRenderer or a subclass. * DateTimeSpinner: improved measurement with DateTimeMode.DATE by using longest month name as typical item. * DateTimeSpinner: fixed issue where runtime error could be thrown if changing range or locale. * DateTimeSpinner: fixed issue where changing locale would not update displayed month names. * DateTimeSpinner: fixed issue where year range would be wrong after changing minimum. * DateTimeSpinner: now uses a typicalItem for the DateTimeMode.DATE_AND_TIME dates list so that it won't resize during scrolling. * DefaultListItemRenderer, DefaultGroupedListItemRenderer: itemToLabel() now strictly checks for null instead of a "truthy" value, and an empty string will have different behavior. * DisplayListWatcher: removed class. Please migrate to new themes, or find this class in feathers-compat library. * Drawers: fixed issue where drawer would jump open instead of opening smoothly when minimumDragDistance was too large. * Drawers: optimized measurement of drawers by setting explicit/max dimensions before validation. * Drawers: drawers must implement IFeathersControl, and Sprite is not allowed anymore. * Drawers: now enforces the assumption that multiple drawers cannot be opened at the same time (multiple drawers can still be docked). * FeathersControl: setSizeInternal() is deprecated and replaced by saveMeasurements(), which includes the ability to set the minimum width and minimum height. * FeathersControl: added toolTip property to display a tool-tip if the ToolTipManager is enabled. * FeathersControl: added explicitWidth, explicitHeight, explicitMinWidth, and explicitMinHeight. Will return a Number when set, or NaN if the component has auto-sized. * FeathersControl: if component implements IStateContext and focusIndicatorSkin is IStateObserver, passes self to stateContext property. * FeathersControl: added resetStyleProvider() function to allow a component's style provider to be set back to the default. Useful when changing to a different theme. * FeathersControl: fixed issue where setting width after scaleX (or height after scaleY) would result in incorrect final dimensions. Same for minWidth and minHeight. * FeathersControl: maxWidth and maxHeight can never be less than 0. * FeathersControl: optimization where the component will not invalidate if changing minWidth, minHeight, maxWidth, or maxHeight obviously won't affect the actual dimensions of the component. * FocusManager: fixed issue where focus would stop going forward when encountering an IFocusContainer. * FlowLayout: fixed issue where alignment could be wrong if maximum row width were smaller than max width. * GroupedList: added itemToItemRenderer(), headerDataToHeaderRenderer(), and footerDataToFooterRenderer() functions, to get a renderer for specific data (if one is available). * GroupedList: fixed issue where a runtime error could be thrown when the dataProvider property is null. * GroupedList: fixed issue where a runtime error could be thrown when adding or removing an item and using first, last, or single item renderer. * Header: improved calculation of status bar height when using useExtraPaddingForOSStatusBar. * Header: When horizontalAlign is HorizontalAlign.LEFT, and the header has leftItems, the title will appear to the right of the items instead of being hidden. Same for HorizontalAlign.RIGHT and rightItems. In these cases, the title will still be hidden if the header has centerItems. * HorizontalLayout: fixed issue where percentWidth/percentHeight values greater than 100 were not clamped. * HorizontalSpinnerLayout: added repeatItems property that may be set to false to disable repeating items with infinite scrolling. * HorizontalSpinnerLayout: fixed issue where items could disappear when using gap property. * ImageLoader: fixed issue where setting source to null when using a TextureCache would not release the texture from the cache. * ImageLoader: replaced snapToPixels property with pixelSnapping property to match Starling 2.0 naming convention. * ImageLoader: added scale9Grid and tileGrid properties. * ImageLoader: fixed issue where ScaleMode.NONE was not respected during auto-sizing. * ImageLoader: masks internal Image instead of itself when clipping a scaled texture so that the mask property can be used too. * ImageSkin: new display object that supports multiple textures and colors for different states. * IMeasureDisplayObject: new interface with explicit, minimum, and maximum dimensions for use when the full IFeathersControl is not necessary. * INativeFocusOwner: nativeFocus property is now typed as Object instead of InteractiveObject so that objects like StageText may be used, and added IAdvancedNativeFocusOwner to provide custom API for setting focus. * KeyToSelect: new utility class that allows selection with keyboard, similar to TapToSelect. * KeyToTrigger: new utility class that allows trigger event with keyboard, similar to TapToTrigger. * Label: added customTextRendererStyleName property. * LayoutGroup: if component is root when initialized, defaults to AutoSizeMode.STAGE. * List: added itemToItemRenderer() function, to get an item renderer for a specific item (if one is available). * List: fixed issue where a runtime error could be thrown when the dataProvider property is null. * NumericStepper: fixed issue where pressing increment or decrement button after editing TextInput would result in wrong value. * OldFadeNewSlideTransitionManager: removed class. Use StackScreenNavigator with push and pop transitions instead, or find this class in feathers-compat. * PickerList: itemToLabel() now strictly checks for null instead of a "truthy" value, and an empty string will have different behavior. * PickerList: fixed issue where button label would not be updated when calling updateItemAt() on data provider with selected index. * Scale3Image: removed class. Use starling.display.Image with scale9Grid. * Scale3Textures: removed class. Use starling.display.Image with scale9Grid, or find this class in feathers-compat library. * Scale9Image: removed class. Use starling.display.Image with scale9Grid. * Scale9Textures: removed class. Use starling.display.Image with scale9Grid, or find this class in feathers-compat library. * ScreenDensityScaleFactorManager: on desktop, screen density isn't used because native stage contentsScaleFactor has the proper behavior. However, it will DeviceCapabilities.dpi on desktop if the value has been customized. * ScreenFadeTransitionManager: removed class. Use StackScreenNavigator with push and pop transitions instead, or find this class in feathers-compat. * ScreenNavigator: fixed issue where an event with the same name as a member of the screen could result in a runtime error if as3-signals weren't available. * ScreenSlidingStackTransitionManager: removed class. Use StackScreenNavigator with push and pop transitions instead, or find this class in feathers-compat. * ScrollContainer: if component is root when initialized, defaults to AutoSizeMode.STAGE. * ScrollContainer: fixed issue where includeInLayout could be ignored when not using a layout. * Scroller: fixed issue where scrolling would still be active after removing from stage and adding again. * Scroller: fixed issue where the page index calculation would fail if the width or height of the component were not an integer. * Scroller: snapScrollPositionToPixels now accounts for contentScaleFactor so that pixel snapping is to view port dimensions instead of stage dimensions to make scrolling smoother. * ScrollText: switched back default value for cacheAsBitmap to false because it seems to have started hurting performance again. * Slider: TrackInteractionMode.TO_VALUE now allows dragging during TouchPhase.MOVED. * SpinnerList: fixed issue where the selectionOverlaySkin could be resized incorrectly if the page size is larger than the list's dimensions. * SpinnerList: can no longer be completely deselected if data provider is not empty. * StackScreenNavigator: fixed issue where an event with the same name as a member of the screen could result in a runtime error if as3-signals weren't available. * StackScreenNavigator: fixed runtime error in popAll() when root screen is visible. * StackScreenNavigator: fixed issue where a new screen with the same ID as the active screen could not be shown. * StackScreenNavigator: fixed issue where a new screen that has the same display object instance as the active screen would break navigation. The transition is now skipped. * StageTextTextEditor: better measurement on desktop and when testing a mobile app in ADL to account for the internal TextField gutter. More consistent across all platforms. * StageTextTextEditor: simplified font size calculation. * StandardIcons: removed class that was deprecated. Use DefaultListItemRenderer.ALTERNATE_STYLE_NAME_DRILL_DOWN to display a drill down accessory in an item renderer. * StateValueSelector: removed class. Use ImageSkin, or find this class in feathers-compat library. * StateToggleValueSelector: removed class. Use ImageSkin, or find this class in feathers-compat library. * StyleProviderRegistry: added hasStyleProvider() and getRegistredClasses(). * TabBar: fixed issue where changing isEnabled in data provider to false and then true would not re-enable a tab. * TabBar: added tabReleaser property that works similarly to tabInitializer, but for cleaning up a tab. * TapToSelect: fixed issue where runtime error could be thrown if removed from stage between TouchPhase.BEGAN and TouchPhase.ENDED. * TapToTrigger: fixed issue where runtime error could be thrown if removed from stage between TouchPhase.BEGAN and TouchPhase.ENDED. * TextArea: added errorString property to display an error in a TextCallout when the component is focused. * TextArea: added TextInputState.ERROR to allow skins to change appearance when the errorString is set. * TextArea: states are defined in feathers.controls.TextInputState. * TextArea: fixed issue where set focus on touch did not account for vertical scroll position. * TextBlockTextRenderer: better calculation of ascent and descent to avoid the issue where accents and other diacritical marks were being cut off at the top. Also, results in better vertical centering of the text. * TextBlockTextRenderer: optimized measurement of width by skipping calculations if maximum is larger than last width. * TextBlockTextRenderer: added support for input method editors (IMEs) to improve compatibility with more languages. * TextBlockTextRenderer: replaced snapToPixels property with pixelSnapping property to match Starling 2.0 naming convention. * TextBlockTextRenderer: fixed issue where runtime error could be thrown when attempting to create BitmapData with negative dimensions. * TextBlockTextRenderer: optimized performance of measurement calculation by avoiding unecessary alignment. * TextCallout: new component that conveniently displays a message in a callout. * TextFieldTextRenderer: replaced snapToPixels property with pixelSnapping property to match Starling 2.0 naming convention. * TextFieldTextRenderer: fixed issue where last line could sometimes be cut off due to floating point rounding errors. * TextInput: fixed issue where the position of the text editor when using VerticalAlign.MIDDLE was not rounded to the nearest pixel. * TextInput: added errorString property to display an error in a TextCallout when the component is focused. * TextInput: added TextInputState.ERROR to allow skins to change appearance when the errorString is set. * TextInput: states are defined in feathers.controls.TextInputState. * TextInput: fixed issue where some icons or skins would not be disposed when input is disposed. * TextInput: fixed issue where focus in and out events sometimes weren't dispatched. * TextInput: fixed issue where IBEAM mouse cursor would not always be cleared. * TextInput: will show focused state when focused, but text editor cannot have focus. * TiledImage: removed class. Use starling.display.Image with tileGrid. * TimeLabel: fixed issue where displayed text was incorrectly when time is greater than one hour. * ToggleButton: deprecated defaultSelectedLabelProperties, selectedUpLabelProperties, selectedHoverLabelProperties, selectedDownLabelProperties, selectedDisabledLabelProperties. Replaced by setting font styles on text renderer in labelFactory. Text renderers now support multiple font styles for different states. * ToggleSwitch: labelAlign is deprecated and behaves as LABEL_ALIGN_MIDDLE now that baseline issue in TextBlockTextRenderer is fixed. * TokenList: optimized value getter to avoid repeated calls to Vector join(). * ToolTipManager: added support for displaying tool tips on mouse hover. Must use desktop theme or opt-in using setEnabledForStage(). * ValidationQueue: optimized to avoid sorting queue of length is 1 because sorting allocates and object and will result in more frequent garbage collection. * VerticalCenteredPopUpContentManager: added overlayFactory property to customize the modal overlay. * VerticalLayout: fixed issue where percentWidth/percentHeight values greater than 100 were not clamped. * VerticalSpinnerLayout: added repeatItems property that may be set to false to disable repeating items with infinite scrolling. * VerticalSpinnerLayout: fixed issue where items could disappear when using gap property. * VideoPlayer: fixed issue where runtime error was thrown when setting netConnectionFactory. * VideoPlayer: improved support for streaming video from server. * VideoPlayer: dispatches FeathersEventType.ERROR when NetStream.Play.NoSupportedTrackFound is dispatched by NetStream. ### 3.0.0 API Changes Please see the [Feathers 3.0 Migration Guide](https://feathersui.com/help/migration-guide-3.0.html) for details about what has been deprecated or removed in Feathers 3.0. ## 2.3.0 - December 2015 * New Component: DateTimeSpinner combines a set of SpinnerList components to select the date, the time, or both. * New Theme: TopcoatLightMobileTheme. Thank you to Marcel Piestansky for your contributions. * List, GroupedList: added support for displaying more than one type of item renderer (plus multiple header and footer renderers on GroupedList). * TapToTrigger, TapToSelect, and LongPress: new utility classes that make it easy to implement Event.TRIGGERED, Event.CHANGE, and FeathersEventType.LONG_PRESS on custom item renderers. * TextureCache: utility class used to store textures loaded from URL by ImageLoader for quick reloading from memory instead of requesting URL again. * Text: Support changing between multiple font styles when parent component changes state. Makes it easier to set font styles for button and item renderer states with strict compile-time type checking (instead of using downLabelProperties, hoverLabelProperties, etc). * Alert: fixed issue where icon would not be positioned correctly when message needed to scroll. * Alert: fixed issue where layout would not be updated after icon resized. * BitmapFontTextRenderer: fixed issue where a line break could happen too early due to floating point inaccuracy. * BitmapFontTextRenderer: added support for leading property on BitmapFontTextFormat to add extra space between lines. Thanks, matyasatfp! * BottomDrawerPopUpContentManager: New IPopUpContentManager for PickerList that opens a drawer at the bottom of the stage. * Button: added setSkinForState() and setIconForState() methods. Recommended instead of separate properties like downSkin and hoverSkin. * Button: fixed issue where skin was positioned incorrectly when using scaleWhenDown. Thanks, zongjingyao! * Button: added customLabelStyleName property. * ToggleButton: fixed issue where the button could get stuck in a disabled state if selected and re-enabled. * Button, ToggleButton, LayoutGroup, Scroller, TextInput, TextArea: ensures that all skins are disposed when disposing the parent component (some may not be on the display list at the time, so they need to be disposed manually). * Button, Item Renderers: when skin, icon, or accessory is IStateObserver, sets the stateContext property. * ButtonGroup: when distributeButtonSizes is false, and the direction is horizontal, will display buttons in multiple rows if they will not fit into one row. * ButtonGroup: added support for passing the item from the data provider as an optional third parameter to event listeners added in the data provider. * ButtonGroup: added support for listening to FeathersEventType.LONG_PRESS on buttons. * ButtonGroup: added support for calling updateItemAt() and updateAll() on data provider. * Callout: adjusts minimum and maximum dimensions of content instead of setting width and height directly, if possible, to allow resizing. * DefaultFocusManager: fixed issue where focus could be restored to an object that was no longer on stage, causing a runtime error. * DefaultFocusManager: fixed issue where a component added under a modal pop-up doesn't have a focus manager. * DefaultListItemRenderer, DefaultGroupedListItemRenderer: added defaultAccessory property and setAccessoryForState() method. As long as itemHasAccessory property is false, accessory does not need to be set with data provider. * DefaultGroupedListHeaderOrFooterRenderer: added customContentLabelStyleName. * Drawers: added openMode property to control whether drawers are opened above or below the content. For backwards compatibility, defaults to below. * Drawers: fixed issue where setting drawer to null while open would leave overlay skin visible, making it impossible to interact with the content. * Drawers: fixed issue where opening or closing a drawer without animation wouldn't always work. * Drawers: added support for dividers between docked drawers and content. * FlowLayout: added firstHorizontalGap and lastHorizontalGap properties to allow a different gap after the first item and before the last item. * FlowLayout: fixed contentWidth result from layout() when content is larger than view port. * FlowLayout: fixed result from measureViewPort() when using multiple rows. * FlowLayout, TiledRowsLayout, TiledColumnsLayout: fixed issue where the calculated view port dimensions were too large when using maxWidth/maxHeight and the rows or columns were smaller than the maximum dimensions. * GroupedList, List: dispatches FeathersEventType.RENDERER_REMOVE for all item renderers on dispose. * GroupedList: default layout now uses stickyHeader property of VerticalLayout. * Header: extra padding for iOS status bar now supports 3x devices. * Header: added customTitleStyleName property. * HierarchicalCollection, ListCollection: added updateAll() method, similar to updateItemItem(), that tells the List that all items have been updated. * HorizontalLayout, VerticalLayout: fixed issue where percentWidth and percentHeight values were ignored when measuring the typical item in a virtual layout. * HorizontalSpinnerLayout, VerticalSpinnerLayout: fixed issue where a "renderer map contains bad data" runtime error could be thrown after duplicate indices were requested by getVisibleIndicesAtScrollPosition(). * IAsyncTheme: new interface available to themes that need to load assets asynchronously. Used by Feathers SDK to delay app initialization until the theme is ready. * IGroupedLayout: new interface for layouts that support special modifiers for GroupedList, like headers that stick to the top. * IGroupedListHeaderOrFooterRenderer: interface is deprecated, and it replaced by two separate interfaces, IGroupedListHeaderRenderer and IGroupedListFooterRenderer. * IListItemRenderer, IGroupedListItemRenderer: added factoryID property that allows List to determine which item renderer factory was used to create the renderer. * IStateContext, IStateObserver: new relationship between components that have state and sub-components that want to know their parent's state. * ImageLoader: immediately stops loading when changing source property, instead of waiting for validation. * Layouts: fixed issue where the wrong dimensions would be calculated when the layout contained zero items. * LayoutGroup: fixed issue where background skin dimensions did not affect min dimensions of layout. * LayoutGroup: fixed issue where removing a child in an Event.REMOVED_FROM_STAGE listener could cause the internal state to get out of sync with the display list. * List: fixed issue where FeathersEventType.RENDERER_REMOVE would be dispatched for item renderers that were kept in memory to improve performance, but they didn't have an item, so the event would make no sense. * PickerList: defaults to using BottomDrawerPopUpContentManager and SpinnerList on devices detected as phones. * PickerList: defaults to DropDownPopUpContentManager on devices detected as desktop computers. * PickerList: fixed issue where pop-up List may incorrectly create an item renderer for every item in the data provider before the list is opened. * Scale3Image: removed duplicate code that had no effect. * SeekSlider: added progressSkin property to display loading progress from media player. * SoundPlayer: fixed issue where passing Sound instance to soundSource property would not update totalTime property and the sound would not play. * SoundPlayer: added MediaPlayerEventType.METADATA_RECEIVED event for Sound Event.ID3. * SoundPlayer, VideoPlayer: implement new IProgressiveMediaPlayer interface with bytesLoaded and bytesTotal properties. * SoundPlayer: fixed issue where sound might not stop playing or might not be cleaned up properly on dispose. * SpinnerList: fixed issue where setting data provider to same object would reset selection. * SpinnerList: default layouts requested four rows instead of five because it will be more visually obvious that it can scroll because some items will be only partially visible * StandardIcons: this class is considered deprecated because List now supports multiple item renderer factories. Drill down icon should be passed to item renderer during skinning. * StackScreenNavigator: added stackCount property. * StackScreenNavigator: added replaceScreen(), popAll(), and popToRootAndReplace() functions. * StackScreenNavigatorItem: added setScreenIDForReplaceEvent() and clearReplaceEvent() methods and replaceEvents property. * StackScreenNavigator, ScreenNavigator: fixed issue where loading new screen in a FeathersEventType.TRANSITION_COMPLETE listener could cause old screen to remain on display list. * StageTextTextEditor: added support for FocusManager. * TabBar: implements IFocusDisplayObject, and the selected tab may be changed with keyboard. * TextArea: added customTextEditorStyleName property. * Text Editors: added global style providers. * Text Editors: fixed issue where calling clearFocus() on Android would remove focus, but keep the soft keyboard open. * TextBlockTextEditor: fixed issue where selection skin could incorrectly appear outside bounds of TextInput. * Text Renderers: added text styles for selected state. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where textures were uploaded too frequently with certain Starling scale factors. * TextFieldTextRenderer: fixed issue where snapshot was not updated when Starling scale factor changes at runtime. * TextInput: added isSelectable property, to go with isEditable property, to allow selection and editing to be controlled separately. * TextInput: added customTextEditorStyleName and customPromptStyleName properties. * TiledRowsLayout, TiledColumnsLayout: fixed issue where wrong number of rows or columns were calculated when using maxWidth or maxHeight. * TiledRowsLayout, TiledColumnsLayout: fixed issues with measurement and item positioning when using requested row or column counts. * ToggleButton: added toggleGroup property, similar to Radio, and implemented IGroupedToggle interface. * ToggleButton: added some missing constants inherited from Button. * ToggleSwitch: added customOnLabelStyleName and customOffLabelStyleName. * Todos: Example updated with modernized coding practices and changed design a bit. * ValidationQueue: uses Vector insertAt() when available in runtime to improve performance by avoiding extra garbage collection. * VideoPlayer: added netConnectionFactory to allow creation of NetConnection and the call to connect() to be customized. * VideoPlayer: added MediaPlayerEventType.METADATA_RECEIVED event for NetStream onMetaData callback. * VideoPlayer: fixed issue where Event.COMPLETE was not dispatched on iOS because NetStream.Play.Complete event was not dispatched on this platform only. * VideoPlayer: fixed issue where restoring context would cause video to start playing if paused before context was lost. * VideoPlayer: fixed issue where only audio would play on iOS if played a second time. * VideoPlayer: fixed issue where video might not stop playing or might not be cleaned up properly on dispose. * VideoPlayer: dispatches FeathersEventType.CLEAR when texture is disposed, similar to Event.READY when texture is ready to be rendered. ImageLoader should clear its source when this is dispatched. * More than doubled the number of unit tests! ### 2.3.0 Deprecated APIs All deprecated APIs are subject to the [Feathers deprecation policy](https://feathersui.com/help/deprecation-policy.html). Please migrate to the new APIs as soon as possible because the deprecated APIs **will** be removed in a future version of Feathers. The `StandardIcons` class is deprecated. It was used to provide a drill-down icon for item renderers, but since lists now support multiple item renderer types, it is no longer needed. Additionally, the `StandardIcons` didn't work properly with multiple Starling instances, so it was ultimately a poor design choice. The `IGroupedListHeaderOrFooterRenderer` interface is deprecated. The `GroupedList` component used this interface, but it now supports separate `IGroupedListHeaderRenderer` and `IGroupedListFooterRenderer` interfaces. The `FeathersEventType.ERROR` constant was originally deprecated in Feathers 2.2.0 and remains deprecated in Feathers 2.3. The `ImageLoader` component used this constant, and it now dispatches separate `Event.IO_ERROR` and `Event.SECURITY_ERROR` events. All properties and constants where "name" was replaced by "style name" were originally deprecated in Feathers 2.1.0, and they have now been removed. * `custom*Name` => `custom*StyleName` * `DEFAULT_CHILD_NAME_*` => `DEFAULT_CHILD_STYLE_NAME_*` * `ALTERNATE_NAME_*` => `ALTERNATE_STYLE_NAME_*` * `itemRendererName` => `customItemRendererStyleName` * `firstItemRendererName` => `customFirstItemRendererStyleName` * `lastItemRendererName` => `customFirstItemRendererStyleName` * `singleItemRendererName` => `customSingleItemRendererStyleName` * `headerRendererName` => `customHeaderRendererStyleName` * `footerRendererName` => `customFooterRendererStyleName` ## 2.2.0 - August 2015 * New Component: SoundPlayer. Plays audio using a Sound object. * New Component: VideoPlayer. Plays video using a NetStream object. * New Layout: Flow. Displays items of differing dimensions in multiple rows. * New Layout: WaterfallLayout. Displays items optimally in columns of equal width. * New Layout: HorizontalSpinnerLayout. Similar to VerticalSpinnerLayout, but displays items in a horizontal row. * New Transition: Iris. Scales a circular mask to animate between two screens. * New Transition: Wipe. Resizes a clipRect to animate between two screens. * New Example: Video. A desktop AIR app that can play videos from the file system. * AddOnFunctionStyleProvider: added callBeforeOriginalStyleProvider property to allow the add-on function to be called first. * Alert: added customMessageStyleName property. * BitmapFontTextEditor, TextBlockTextEditor: fixed an issue where they didn't accept non-Latin characters and ignored characters when Alt key was pressed. * BitmapFontTextEditor, TextBlockTextEditor: uses needsSoftKeyboard and requestSoftKeyboard() to show soft keyboard on Android. Vote on [Adobe Bug #3962712](https://bugbase.adobe.com/index.cfm?event=bug&id=3962712) to add iOS support. * BitmapFontTextEditor, TextBlockTextEditor: fixed issue where the selection anchor index wasn't properly updated, making the keyboard selection change on the wrong side. * BitmapFontTextEditor, TextBlockTextEditor: fixed issue where setting TextInput's parent visible property to false wouldn't clear focus. * BitmapFontTextEditor, TextBlockTextEditor: fixed an issue where pasting something other than text would cause a runtime error. * BitmapFontTextEditor, TextBlockTextEditor: fixed an issue where changing the text property in an Event.CHANGE listener could cause the cursorSkin to be positioned incorrectly. * Button: fixed issue where the label text renderer wasn't given an maxHeight that accounted for the button's height and padding. * ColorFade: fixed name of createBlackFadeTransition(). * Default Item Renderers: fixed issue where children above or below label text renderer couldn't sometimes affect the label's width. * DropDownPopUpContentManager: fixed issue where pop-up wasn't repositioned if the source moved to a new location. * DropDownPopUpContentManager: added primaryDirection property to support trying to display the pop-up above the source first, instead of below. * DropDownPopUpContentManager: added fitContentMinWidthToOrigin property to allow the content to be smaller than the origin. * DropDownPopUpContentManager: fixed horizontal position of pop-up above origin. * DropDownPopUpContentManager: fixed issues caused by multiple Starling instances. * DropDownPopUpContentManager: added isModal and overlayFactory properties to affect how pop-up is displayed. * FeathersControl: fixed issue where initialize() could be called during initialization. * FocusManager: added support for new INativeFocusOwner interface, which allows components to be associated with a specific focusable native display object (like text editors!). * GroupedList: the itemIndex parameter on scrollToDisplayIndex() is now optional so that you can scroll to a group header. * Header: fixed issue where useExtraPaddingForOSStatusBar property didn't account for contentScaleFactor. * HorizontalLayout, VerticalLayout: fixed issue where a scrollToDisplayIndex() on a List wouldn't work. * HorizontalLayout, VerticalLayout: fixed issue where center/middle alignment wasn't properly ignored if total content size was larger than the container bounds (thanks kavolorn!) * HorizontalLayout, VerticalLayout: fixed issue with alignment when scrolling is required in perpendicular direction. * HorizontalLayout: fixed issue where items weren't measured correctly sometimes when using percentage dimensions. * ImageLoader: now accounts for minimum and maximum dimensions when maintaining aspect ratio. * ImageLoader: now dispatches separate Event.IO_ERROR and Event.SECURITY_ERROR constants instead of FeathersEventType.ERROR. * ImageLoader: fixed issue where appending variable to ATF URL would break the check for the file extension. * ImageLoader: added scaleContent, horizontalAlign, and verticalAlign properties. * ImageLoader: added scaleMode property that uses values from starling.utils.ScaleMode. * LayoutGroup: fixed issue where the background skin wasn't clipped by the clipRect. * MultiStarlingStyleNameFunctionTheme: a variation of StyleNameFunctionTheme that supports multiple Starling instances. * LayoutGroup, Scroller (and subclasses), ScreenNavigator, StackScreenNavigator: setting clipContent to false will clear the clipRect only once so that clipRect may be used externally. * LayoutGroupListItemRenderer, LayoutGroupGroupedListItemRenderer: fixed issue where changing the data would hurt performance because the item renderer would need to validate more than once. * List: sometimes keeps around an extra item renderer to avoid garbage collection and improve performance. When the typical item is from the data provider, the number of renderered items would fluctuate when scrolling. * NumericStepper: fixed issue where selection might be changed in TextInput when using arrow keys to step. * Panel: fixed issue where autoSizeMode property was ignored. * PopUpManager: fixed issue where adding a pop-up that already had a parent would cause the Event.REMOVED_FROM_STAGE listener to be called early. * ProgressBar, Slider: fixed issue where the layout would be broken if the minimum equals the maximum. * RenderDelegate: a display object that passes rendering to another display object that has its own transformations. Useful for custom transitions. * Scroller: fixed issue where scrollToPageIndex() would not accept negative page indicies. * Scroller: fixed issue where the container didn't detect major changes to the maximum scroll position, causing it to scroll far beyond the end of the content. * Scroller: added SCROLL_BAR_DISPLAY_MODE_FIXED_FLOAT to allow the scroll bar floats above the content, but it won't fade out. * Scroller: fixed issue where INTERACTION_MODE_TOUCH_AND_SCROLL_BARS didn't work in nested scrollers because scroll bars could overlap and stop touches even when scrolling was not possible. * Scroller: fixed issue where touching the scroll bar thumb wouldn't stop a throw. * Scroller: fixed issue where a floating scroll bar would be hidden after hover out instead of waiting for the throw animation to finish. * Scroller: fixed issue where clipping was no properly updated when using INTERACTION_MODE_MOUSE and the view port was resized small enough that scrolling was no longer needed. * Scroller: fixed issue where Scroller couldn't properly calculate its dimensions when it has a background skin but no view port content, causing an infinite loop. * Scroller: fixed issue where floating point errors sometimes caused it to snap to the wrong page. * Scroller: fixed issue where maximum page indices might be one larger than they should be if a floating point error occurs. * Scroller: snapScrollPositionToPixels now defaults to true. * Scroller: switched to a different throwEase that is more natural. * ScrollBar, SimpleScrollBar, Slider: on initialize, clamps value to minimum and maximum because value may not have been set, and it may be outside the range. * ScrollContainer: fixed issue where getRawChildIndex() didn't reset the displayListBypassEnabled flag before returning the result. * ScrollContainer: fixed issue where view port resizing wasn't ignored when using AUTO_SIZE_MODE_STAGE, potentially hurting performance. * ScrollText: uses cacheAsBitmap to improve scrolling performance. A property has been exposed to disable this, if desired. * ScreenDensityScaleFactorManager: manages the Starling view port and stage dimensions to automatically generate an appropriate contentScaleFactor value based on the screen DPI. * ScrollContainer: fixed issue where addChild() stopped working with Starling 1.7. * Slider: thumb position is now rounded to the nearest pixel. * Slider: added thumbOffset property to allow the thumb to be repositioned in the direction perpendicular to the track. * SpinnerList: by default, the scroll bar is hidden. * StackScreenNavigator: fixed issue where setting rootScreenID before screens were added could throw a runtime error. * StageTextTextEditor: fixed issue where text color wouldn't change when disabled while StageText didn't have focus. * StageTextTextEditor: fixed an issue where where the text editor would try to change the font size property every frame, but it wasn't rounding to an integer, causing the check to fail. * StageTextTextEditor, TextFieldTextEditor: improved positioning of StageText or TextField overlay when added to Sprite3D. * StyleNameFunctionTheme: added a createRegistry() function that can be overridden in a subclass to customize the style provider registry. * TabBar: now supports isEnabled in data provider, similar to ButtonGroup. * TextArea, TextInput: fixed issue where the backgroundFocusedSkin wasn't displayed when the FocusManager was disabled (thanks tcfraser!) * TextArea: fixed issue where setting the height of the TextArea larger than the text may result in the TextArea not receiving focus. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where the texture would sometimes restore with the wrong font size and clipping. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where snapshot dimensions were rounded down to the nearest pixel, which could cut off a small part of the text. * TextBlockTextRenderer, TextFieldTextRenderer: uses Texture.empty() and uploads BitmapData manually instead of Texture.fromBitmapData() to avoid the creation of an onRestore function that will be immediately replaced. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where the texture snapshot could be blurry when scaled up from 0. * Text Renderers: added updateSnapshotOnScaleChange property to allow the snapshot to always be crisp, even when scaled up or down. Use with caution as it needs to check the scale every frame. * TextBlockTextRenderer: fixed issue where texture snapshot remained visible when the text renderer's width or height was supposed to be 0. * TextBlockTextRenderer: fixed issue where the cursorSkin wasn't properly positioned and sized when calling setFocus() manually. * TextBlockTextEditor: fixed an issue where scrolling wasn't working properly on HiDPI displays. * TextFieldTextEditor: fixed issue where the font displayed at the wrong scale the first time that the text editor received focus on some mobile devices. * TextFieldTextEditor: fixed issue where accessing the baseline property might throw a runtime error because textSnapshot was null. * TextFieldTextEditor: exposed some more TextField property that control rendering. * TextFieldTextRenderer: added useSnapshotDelayWorkaround property and disabled this workaround by default. * Text Editors: detects changes in contentScaleFactor (such as when switching between HiDPI and normal screens) and recreates snapshots. * TextInput: can now receive focus when isEditable is false. * TiledRowsLayout, TiledColumnsCount: The requestedColumnCount property may now be used to calculate an ideal width for that number of columns, if the container doesn't have an explicitWidth. (TiledColumnsLayout uses the requestedRowCount property). * ValidationQueue: skips components in queue that are no longer on the display list. * ValidationQueue: will not proceed if Starling's context is invalid. This may happen if a TouchEvent.TOUCH listener causes a lost context. * VerticalSpinnerLayout: fixed issue where item heights weren't forced to the same size, which could cause large gaps or overlapping items. * WebView: added missing FeathersEventType.LOCATION_CHANGE constant for event. * YouTubeFeeds: example updated to use newer YouTube API since the old one was shut down. * Transitions: changed some to use RenderDelegate to avoid removing screens from display list. * Examples: use Context3DProfile.BASELINE for mobile examples, since it is widely supported on mobile. * Examples: enabled supportHighResolution flag for mobile apps so that they look better on HiDPI screens. This has no effect on a real mobile device. It just improves the development experience. * Themes: when disposing, unregisters bitmap fonts, clears texture onRestore function, and clears StandardIcons class. * Themes: desktop themes now use HiDPI textures. ### 2.2.0 Deprecated APIs All deprecated APIs are subject to the [Feathers deprecation policy](https://feathersui.com/help/deprecation-policy.html). Please migrate to the new APIs as soon as possible because the deprecated APIs **will** be removed in a future version of Feathers. The `FeathersEventType.ERROR` constant is deprecated. The `ImageLoader` component used this constant, and it now dispatches separate `Event.IO_ERROR` and `Event.SECURITY_ERROR` events. Error events should always be specific. The `nameList` property on the `IFeathersControl` interface was originally deprecated in Feathers 2.0.0, and it has now been removed. It is replaced by the `styleNameList` property. The `manageVisibility` property on layouts was originally deprecated in Feathers 2.0.0, and it has now been removed. This property no longer provided the performance improvements that it was originally intended for. Properties such as `customThumbName` on the `Slider` component have have been renamed. In this case, `customThumbName` is deprecated and replaced by `customThumbStyleName`. Similarly, the static constant `Slider.DEFAULT_CHILD_NAME_THUMB` has been deprecated and renamed `Slider.DEFAULT_CHILD_STYLE_NAME_THUMB`. Similarly, the static constant `Button.ALTERNATE_NAME_BACK_BUTTON` has been deprecated and renamed `Button.ALTERNATE_STYLE_NAME_BACK_BUTTON`. On all components, APIs that refer to the *name* of sub-components have been deprecated and they have been replaced by a similar API that refers to the *style name* instead. For brevity, the list below shows the mapping between the old naming conventions and the new naming conventions instead of listing each renamed property individually. * `custom*Name` => `custom*StyleName` * `DEFAULT_CHILD_NAME_*` => `DEFAULT_CHILD_STYLE_NAME_*` * `ALTERNATE_NAME_*` => `ALTERNATE_STYLE_NAME_*` The `List` and `GroupedList` components had some properties that didn't follow the original `custom*Name` naming convention. In both classes, the `itemRendererName` property has been deprecated and replaced by `customItemRendererStyleName`. In `GroupedList`, `firstItemRendererName`, `lastItemRendererName` and `singleItemRendererName` have been deprecated and replaced by `customFirstItemRendererStyleName`, `customLastItemRendererStyleName`, and `customSingleItemRendererStyleName` respectively. Similarly, `headerRendererName` and `footerRendererName` have been deprecated and replaced by `customHeaderRendererStyleName` and `customFooterRendererStyleName` respectively. With this change, these properties no longer diverge from the naming convention used for similar properties on other components. All of the above renamed APIs were deprecated in Feathers 2.1.0, and they remain deprecated in Feathers 2.2.0. ### 2.2.0 API Changes The `scrollToPageIndex()` function in the `Scroller` class, and its subclasses, no longer accepts `-1` as a valid way of specifying that the horizontal or vertical page index should not change. You must pass in the current value of the `horizontalPageIndex` or `verticalPageIndex` property instead. With the ability to have negative page indices, `-1` must now be available as a valid page index. In the following code, the vertical page index is not meant to be changed: ``` list.scrollToPageIndex( 2, -1 ); ``` The code would need to be modified, like this: ``` list.scrollToPageIndex( 2, list.verticalPageIndex ); ``` ## 2.1.2 - July 2015 * ScrollContainer: overrides addChild() to fix "RangeError: Invalid child index" issue when using Starling 1.7. ## 2.1.1 - March 2015 * BitmapFontTextRenderer, ScrollContainer: added workarounds for compiler bugs in Adobe Flex SDK 4.6. * ButtonGroup, TabBar: fixed issue where buttons or tabs would flicker and resize for a frame when the container resizes. * HorizontalLayout, VerticalLayout: fixed an issue that resulted in no scrolling when the scrollToDisplayIndex() function is called on a List. * ScrollContainer: fixed issue where setting autoSizeMode to AUTO_SIZE_MODE_STAGE resulted in being unable to scroll. * SpinnerList: fixed issue where setting the selected index programmatically didn't always update the scroll position. * TextBlockTextRenderer, TextFieldTextRenderer: fixed issue where text would appear blurry because snapToPixels incorrectly snapped on the y-axis. ## 2.1.0 - February 2015 * New Component: AutoComplete, a TextInput that provides a pop-up list of suggestions. * New Component: SpinnerList, a list that changes selection when scrolling to an item. * New Component: StackScreenNavigator, a variation of ScreenNavigator with a history stack that you can push and pop. * New Component: WebView, displays a native web browser using StageWebView, but may be positioned in local coordinates. Available in AIR only. * New Layout: VerticalSpinnerLayout, the default layout for the new SpinnerList component. * New Transitions: ColorFade, Cover, Cube, Fade, Flip, Reveal, Slide. * New Example: TransitionsExplorer demonstrates each transition. * Unit tests: created unit tests for a number of Feathers components. * Help: help files are now distributed with Feathers for offline use. * AnchorLayout: fixed issue where items positioned relative to horizontalCenterAnchorDisplayObject or verticalCenterAnchorDisplayObject were not positioned correctly whent he anchor was at a higher depth. * Button: added scaleWhenDown and scaleWhenHovering properties to scale the button in these states. * BaseDefaultItemRenderer: fixed issue where data that is == null would be ignored in some cases by changing to stricter === null check. * BitmapFontTextRenderer: fixed issue where a runtime error could be thrown if a character in the bitmap font had a width or height of 0. * BitmapFontTextEditor, TextBlockTextEditor: fixed issue where clearing the text on focus would cause the selection range to be invalid. * BitmapFontTextEditor, TextBlockTextEditor: listens for flash.events.Event.SELECT_ALL instead of Ctrl/Command+A with a keyboard event because it didn't work properly on Mac. * BitmapFontTextRenderer: fixed issue where the last word of a line would sometimes appear on the next line. * CalloutPopUpContentManager, DropDownPopUpContentManager, VerticalCenteredPopUpContentManager: detects if pop-up is removed from stage externally so that Event.CLOSE is properly dispatched. * DropDownPopUpContentManager: fixed issue where the source would close the pop-up while validating, but the pop-up was being positioned, causing a runtime error, so now checks if open after source is validated. * FeathersControl: added move() convenience function to set x and y properties, similar to how setSize() sets width and height. * FeathersControl: the styleProvider property may be changed after initialization. * FeathersControl: changes to styleNameList after initialization now causes the styleProvider to be re-applied. * FeathersControl: may now flatten even when not initialized or on stage. * FEATHERS_VERSION: new constant that can be used to see the version of Feathers being used. * FocusManager: both containers and their children may receive focus separately (to allow the container to scroll with the keyboard), thanks to the new IFocusContainer interface. * HierarchicalCollection: added removeAll() function, similar to ListCollection. * HorizontalLayout, VerticalLayout: when alignment is justified, the size of the item renderer is reset so that an accurate measurement can be taken instead of using the old justified size. * HorizontalLayout: added requestColumnCount property for more control over width auto-measurement. * HorizontalLayout, VerticalLayout: fixed issue where the number of item renderers didn't remain constant when using hasVariableItemDimensions when all item renderers were the same size. * ILayout: added getNearestScrollPositionForIndex() function to support scrolling when changing selected index in components like List. * Label: added backgroundSkin, backgroundDisabledSkin, and padding properties. * LayoutGroup: added LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR. * LayoutGroup: added autoSizeMode property to specify that it should fill the stage. * List, GroupedList: fixed issue where scrolling backwards would sometimes cause item renderers to jump around instead of scrolling smoothly with a virtual layout with variable item dimensions where an item resized. Layout may adjust scroll position, if needed. * List, GroupedList: updates scroll position, if needed, when using arrow keys to change selection. * List, GroupedList: dispatches Event.TRIGGERED when an item renderer is triggered. The event data is the item from the data provider. * List, GroupedList: added stricter === null check when checking if a typicalItem has been set because values like 0 could match == null. * List, GroupedList: fixed issue where layout didn't update after an item renderer resized while the list wasn't validating. * List, GroupedList: fixed issue where the typical item renderer resized, but the layout wasn't updated. * List, GroupedList: fixed issue where changing the index of a typical item chosen from the data provider would not update the index of its item renderer. * ListCollection: setting data property to null keeps null instead of removing all items from existing data. * NumericStepper: added valueFormatFunction and valueParseFunction properties to support custom formatting. * Panel: added new title and headerTitleField properties to use instead of going through headerProperties. * Panel: fixed issue where outerPaddingBottom was ignored if the panel didn't have a footer. * PanelScreen: added missing DEFAULT_CHILD_STYLE_NAME_FOOTER constant for use in themes. * PickerList: dispatches Event.OPEN and Event.CLOSE when the pop-up list opens and closes. * PickerList, TabBar: fixes issue where Event.CHANGE was incorrectly dispatched on disposal because dataProvider was set to null. * Scale3Textures, Scale9Textures: fixed validation of region sizes when using a scaled texture that doesn't match Starling.contentScaleFactor. * ScreenNavigator: fixes issue where new screen wasn't resized properly by validating self if validation queue is currently busy. * ScreenNavigator: adds a delay of two frames before starting a transition animation because it significantly improves the performance of the transition. * ScreenNavigator: added isTransition active property to indicate if a transition is currently in progress. * ScreenNavigator: fixed issue where clearing a screen didn't dispatch FeathersEventType.TRANSITION_START. * ScreenNavigator: added support for transitions that may cancel themselves. * ScreenNavigator: added optional transition function argument to showScreen() and clearScreen(). * ScreenNavigator: fixes issue where active screen wasn't properly cleared if removed with removeScreen() or removeAllScreens(). * ScreenNavigator: dispatches FeathersEventType.TRANSITION_IN_START, FeathersEventType.TRANSITION_IN_COMPLETE, FeathersEventType.TRANSITION_OUT_START, and FeathersEventType.TRANSITION_OUT_COMPLETE on screens (not on self). Screens may listen for these events instead of the events dispatched by ScreenNavigator. * ScreenNavigatorItem: added setFunctionForEvent() and setScreenIDForEvent(). * ScreenNavigatorItem: The properties getter will always be a valid object. It won't return null. * ScrollBar: hides thumb when ranging is infinite. * ScrollBar: sets touchable to false on tracks when range is 0 or infinite. * Scroller: performance improvements from less garbage collection. * Scroller: added support for scrolling horizontally with vertical scroll wheel. * Scroller: can receive focus to control scroll position with keyboard. * Scroller: fixed issue where snapToPages was ignored when using mouse wheel or throwing. * Scroller: fixed issue where animation for elastic snapping would restart on every touch when the distance was less than 1 pixel, causing it to appear that the item renderers could not be touched. * ScrollContainer: added autoSizeMode property to specify that it should fill the stage. * ScrollContainer: fixed issue where outer container didn't invalidate when adding or removing children, or when children are resized, causing validate() to have no effect. * StageTextTextEditor, TextFieldTextEditor: fixes issue where focus remained when parent was set invisible. * StyleNameFunctionTheme: the getStyleProviderForClass() function is now public. * TabBar, ToggleGroup, List, GroupedList, PickerList: fixed issue where Event.CHANGE was not dispatched when removing an item and the selectedIndex remains the same, but the selectedItem is different. * TabBar: default selectedIndex is -1 until the data provider is set. * TabBar: Event.CHANGE is dispatched immediately when selectedIndex property changes instead of waiting for validation. Makes it more consistent with other components, like List. * TextFieldTextEditor: fixed issue where HTML formatting is lost if edited when isHTML is true. * TextFieldTextEditor: fixed issue where snapshot wasn't updated when size changed, but data or styles did not. * TextFieldTextEditorViewPort: added padding properties. * TextFieldTextEditorViewPort: fixed issue where the selection index was wrong from touch. * TextFieldTextRenderer, TextBlockTextRenderer: fixed issue where native filters could cause the text renderer to create a texture that is larger than the maximum dimensions allowed. * TextFieldTextRenderer, TextBlockTextRenderer: fixed issue where only the first texture (if multiple textures were required) was positioned properly when using native filters. * TextFieldTextRenderer, TextBlockTextRenderer: fixed issue where texture snapshots could be clipped too small when using native filters. * VerticalLayout: added requestRowCount property for more control over height auto-measurement. ### 2.1.0 Deprecated APIs All deprecated APIs are subject to the [Feathers deprecation policy](https://feathersui.com/help/deprecation-policy.html). 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 on the `IFeathersControl` interface 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 `nameList` property was deprecated in Feathers 2.0.0, and it remains deprecated in Feathers 2.1.0. 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. The `manageVisibility` property was deprecated in Feathers 2.0.0, and it remains deprecated in Feathers 2.1.0. Similar to how the `nameList` property was renamed `styleNameList` in Feathers 2.0.0, properties such as `customThumbName` on the `Slider` component have have been renamed too. In this case, `customThumbName` is deprecated and replaced by `customThumbStyleName`. Similarly, the static constant `Slider.DEFAULT_CHILD_NAME_THUMB` has been deprecated and renamed `Slider.DEFAULT_CHILD_STYLE_NAME_THUMB`. Similarly, the static constant `Button.ALTERNATE_NAME_BACK_BUTTON` has been deprecated and renamed `Button.ALTERNATE_STYLE_NAME_BACK_BUTTON`. On all components, APIs that refer to the *name* of sub-components have been deprecated and they have been replaced by a similar API that refers to the *style name* instead. For brevity, the list below shows the mapping between the old naming conventions and the new naming conventions instead of listing each renamed property individually. * `custom*Name` => `custom*StyleName` * `DEFAULT_CHILD_NAME_*` => `DEFAULT_CHILD_STYLE_NAME_*` * `ALTERNATE_NAME_*` => `ALTERNATE_STYLE_NAME_*` The `List` and `GroupedList` components had some properties that didn't follow the original `custom*Name` naming convention. In both classes, the `itemRendererName` property has been deprecated and replaced by `customItemRendererStyleName`. In `GroupedList`, `firstItemRendererName`, `lastItemRendererName` and `singleItemRendererName` have been deprecated and replaced by `customFirstItemRendererStyleName`, `customLastItemRendererStyleName`, and `customSingleItemRendererStyleName` respectively. Similarly, `headerRendererName` and `footerRendererName` have been deprecated and replaced by `customHeaderRendererStyleName` and `customFooterRendererStyleName` respectively. With this change, these properties no longer diverge from the naming convention used for similar properties on other components. ### 2.1.0 API Changes #### ILayout The `getNearestScrollPositionForIndex()` method has been added to the `ILayout` interface. Custom implementations of `ILayout` created before Feathers 2.1.0 will have compiler errors until the required changes are made. This method is meant to calculate an updated scroll position for a specific index that requires the minimum amount of scrolling to fully display the specified index within the container's view port. It was added so that components like `List` could update the scroll position when changing the selected index with the keyboard when the component has focus. To maintain the existing behavior (where the container doesn't scroll at all) to simply bypass the compiler error, the following implementation will return the existing scroll position: public function getNearestScrollPositionForIndex(index:int, scrollX:Number, scrollY:Number, items:Vector., x:Number, y:Number, width:Number, height:Number, result:Point = null):Point { if(!result) { return new Point(scrollX, scrollY); } result.setTo(scrollX, scrollY); return result; } #### Scroller now implements IFocusDisplayObject With the addition of the new `IFocusContainer` interface, it is now possible for a container and its children to both appear in the tab focus chain when the `FocusManager` is enabled. Previously, subclasses of `Scroller`, like `List` or `ScrollContainer`, could not receive focus to allow the user to control the scroll position with the keyboard because the children wouldn't be able to receive focus too. Now, with the new interface and an updated focus manager, that restriction is lifted, and `Scroller` implements `IFocusDisplayObject` to support keyboard scrolling. Subclasses of `Scroller` that need to support passing focus to children must now implement `IFocusContainer`. `List`, `ScrollContainer`, `GroupedList` have been updated, obviously, but custom subclasses of `Scroller` may need to be updated to support focus. `IFocusContainer` requires one property, `isChildFocusEnabled`. For convenience, you may copy following implementation of `isChildFocusEnabled` into a subclass of `Scroller`: protected var _isChildFocusEnabled:Boolean = true; public function get isChildFocusEnabled():Boolean { return this._isEnabled && this._isChildFocusEnabled; } public function set isChildFocusEnabled(value:Boolean):void { this._isChildFocusEnabled = value; } ## 2.0.1 - November 2014 * 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 - October 2014 * 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](https://feathersui.com/help/deprecation-policy.html). 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 - July 2014 * 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 - April 2014 * 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](https://feathersui.com/help/deprecation-policy.html). 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](https://feathersui.com/help/deprecation-policy.html#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 - November 2013 * 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](https://feathersui.com/help/deprecation-policy.html). 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](https://feathersui.com/help/deprecation-policy.html#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 - September 2013 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 - June 2013 * 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](https://feathersui.com/help/deprecation-policy.html). 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](https://feathersui.com/help/deprecation-policy.html#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 - February 2013 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 - January 2013 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 - December 2012 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`. ================================================ FILE: LICENSE.md ================================================ Simplified BSD License ====================== Copyright 2012-2021 Bowler Hat LLC. 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. ================================================ FILE: README.md ================================================ # Feathers (AS3/Starling) 4.2.0 Say hello to [Feathers UI (AS3/Starling)](https://feathersui.com/learn/as3-starling), a library of light-weight, skinnable, and extensible UI controls for mobile and desktop. The components run on [Starling Framework](https://gamua.com/starling/) and [Adobe AIR](http://airsdk.dev) — offering blazing fast GPU powered graphics to create a smooth and responsive experience. Build completely standalone, native applications on iOS, Android, Windows, and macOS, or target Adobe Flash Player in desktop browsers. Created by [Josh Tynjala](https://joshblog.net) from Bowler Hat LLC, Feathers UI is free and open source. ## Quick Links * [Website](https://feathersui.com/learn/as3-starling/) * [Help](https://feathersui.com/learn/as3-starling/getting-started) * [API Reference](https://feathersui.com/api-reference/) * [Discussion Forum](https://forum.starling-framework.org/t/feathers) * [Github Project](https://github.com/feathersui/feathersui-starling) ## Minimum Requirements * Adobe AIR 50 * Starling Framework 2.7 ## Downloads Visit [Feathers Installation (AS3/Starling version)](https://feathersui.com/learn/as3-starling/installation/) to download the latest stable version of Feathers for ActionScript 3.0 and Starling Framework. ================================================ FILE: build.properties ================================================ #this folder should contain the contents of starling.zip/starling/src starling.root = ${basedir}/third-party/starling #this folder should contain the SWC files for flexunit, as described here: #https://github.com/Gamua/Starling-Framework/blob/v1.7/tests/README.md #additionally, it should contain the JAR files for the flexunit ant tasks flexunit.root = ${basedir}/third-party/flexunit # The location of the flexunit jar flexunit.tasks = ${flexunit.root}/flexUnitTasks-4.2.0-20140410.jar source.root = ${basedir}/source examples.root = ${basedir}/examples themes.root = ${basedir}/themes api.root = ${basedir}/documentation/api-reference help.root = ${basedir}/documentation/help test.root = ${basedir}/test output.path = ${basedir}/output dependency.output = ${output.path}/dependencies 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 swc.file = feathers.swc swf.version = 30 feathers.version = 4.2.0 apm.lib.file = feathersui_${feathers.version}.airpackage apm.src.file = feathersui-source_${feathers.version}.airpackage footer.text = Feathers | Github Project | Support Forum ================================================ FILE: build.xml ================================================ ================================================ FILE: documentation/README.md ================================================ # Documentation The *api-reference* folder contains a custom template for the [API reference](https://feathersui.com/api-reference/). The Markdown help files that were previously in the *help* folder have been moved to the [feathersui-website](https://github.com/BowlerHatLLC/feathersui-website/tree/master/docs/as3-starling) repository. ================================================ FILE: documentation/api-reference/package-descriptions.xml ================================================ ================================================ FILE: documentation/api-reference/templates/AC_OETags.js ================================================ //////////////////////////////////////////////////////////////////////////////// // // 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
================================================ FILE: documentation/api-reference/templates/ASDoc_terms.xml ================================================ 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

StyleStyle

Style

text for style

StyleDetail

Style Detail

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.

================================================ FILE: documentation/api-reference/templates/ClassHeader.xslt ================================================ globalClassifier: ================================================ FILE: documentation/api-reference/templates/Classes.xslt ================================================ , , , , , , . false :public :internal . . ================================================ FILE: documentation/api-reference/templates/Overviews_Base.xml ================================================ ================================================ FILE: documentation/api-reference/templates/PostProcessing.xslt ================================================ WARNING : Short Description not present for WARNING : api Description not present for WARNING : Short Description not present for WARNING : api Description not present for ================================================ FILE: documentation/api-reference/templates/all-classes.xslt ================================================ <xsl:choose> <xsl:when test="$prog_language_name='javascript'" /> <xsl:otherwise> <xsl:value-of select="$title"/> </xsl:otherwise> </xsl:choose>

================================================ FILE: documentation/api-reference/templates/all-index.xslt ================================================ +,:!?/.^~*=%|&<>()[]{}" 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
 
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');
================================================ FILE: documentation/api-reference/templates/asdoc-util.xslt ================================================ <!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 ================================================ FILE: documentation/api-reference/templates/asdoc.js ================================================ //////////////////////////////////////////////////////////////////////////////// // // 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) { var borderStyle = "solid 1px #333"; findTitleTableObject("propertiesLink").style.display = showProperties ? "inline" : "none"; findTitleTableObject("propertiesLink").style.borderRight = (showProperties && (showPackageProperties || showConstructor || showMethods || showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("packagePropertiesLink").style.borderRight = (showPackageProperties && (showConstructor || showMethods || showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showConstants || showEffects || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("constructorLink").style.borderRight = (showConstructor && (showMethods || showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("methodsLink").style.borderRight = (showMethods && (showPackageFunctions || showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("packageFunctionsLink").style.borderRight = (showPackageFunctions && (showEvents || showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("eventsLink").style.borderRight = (showEvents && (showStyles || showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("stylesLink").style.borderRight = (showStyles && (showSkinPart || showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "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("SkinPartLink").style.borderRight = (showSkinPart && (showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("SkinPartBar").style.display = (showSkinPart && (showSkinState || showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("SkinStateLink").style.display = showSkinState ? "inline" : "none"; findTitleTableObject("SkinStateLink").style.borderRight = (showSkinState && (showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("SkinStateBar").style.display = (showSkinState && (showEffects || showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("effectsLink").style.display = showEffects ? "inline" : "none"; findTitleTableObject("effectsLink").style.borderRight = (showEffects && (showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("effectsBar").style.display = (showEffects && (showConstants || showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("constantsLink").style.display = showConstants ? "inline" : "none"; findTitleTableObject("constantsLink").style.borderRight = (showConstants && (showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("constantsBar").style.display = (showConstants && (showPackageConstants || showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("packageConstantsLink").style.display = showPackageConstants ? "inline" : "none"; findTitleTableObject("packageConstantsLink").style.borderRight = (showPackageConstants && (showInterfaces || showClasses || showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("packageConstantsBar").style.display = (showPackageConstants && (showInterfaces || showClasses || showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("interfacesLink").style.display = showInterfaces ? "inline" : "none"; findTitleTableObject("interfacesLink").style.borderRight = (showInterfaces && (showClasses || showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("interfacesBar").style.display = (showInterfaces && (showClasses || showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("classesLink").style.display = showClasses ? "inline" : "none"; findTitleTableObject("classesLink").style.borderRight = (showClasses && (showPackageUse || showExamples)) ? borderStyle : "none"; // findTitleTableObject("classesBar").style.display = (showClasses && (showPackageUse || showExamples)) ? "inline" : "none"; findTitleTableObject("packageUseLink").style.display = showPackageUse ? "inline" : "none"; findTitleTableObject("packageUseLink").style.borderRight = (showPackageUse && showExamples) ? borderStyle : "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" : ""; if (rules[i].selectorText == "table.hideInherited" + selectorText) rules[i].style.display = show ? "block" : "none"; if (rules[i].selectorText == "table.showInherited" + selectorText) rules[i].style.display = show ? "none" : "block"; } } else { document.styleSheets[0].addRule(".hideInherited" + selectorText, show ? "display:inline" : "display:none"); document.styleSheets[0].addRule(".showInherited" + selectorText, show ? "display:none" : "display:inline"); document.styleSheets[0].addRule("table.hideInherited" + selectorText, show ? "display:block" : "display:none"); document.styleSheets[0].addRule("table.showInherited" + selectorText, show ? "display:none" : "display:block"); } 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); } } ================================================ FILE: documentation/api-reference/templates/class-files.xslt ================================================ 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

. ================================================ FILE: documentation/api-reference/templates/class-list.xslt ================================================ class-list.html /class-list.html <xsl:value-of select="$title"/>

&nbsp;
&nbsp;
()
&nbsp;
&nbsp;
================================================ FILE: documentation/api-reference/templates/class-parts.xslt ================================================

Class Interface 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/>
: : ,
: : ,
================================================ FILE: documentation/api-reference/templates/class-summary.xslt ================================================ <xsl:value-of select="$asdoc_terms/row[entry[1][p/text() = $localTitle]]/entry[2]/p"/> <xsl:call-template name="getPageTitlePostFix"/> eclipseBody ================================================ FILE: documentation/api-reference/templates/cookies.js ================================================ //////////////////////////////////////////////////////////////////////////////// // // 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"; } } ================================================ FILE: documentation/api-reference/templates/effectsSummary.xslt ================================================ ================================================ FILE: documentation/api-reference/templates/eventsGeneratedSummary.xslt ================================================ ================================================ FILE: documentation/api-reference/templates/fieldSummary.xslt ================================================

================================================ FILE: documentation/api-reference/templates/help.js ================================================ //////////////////////////////////////////////////////////////////////////////// // // 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; } } ================================================ FILE: documentation/api-reference/templates/index-list.html ================================================ ActionScript 3.0 Language and Components Reference

    Index

    A N
    B O
    C P
    D Q
    E R
    F S
    G T
    H U
    I V
    J W
    K X
    L Y
    M Z
    ================================================ FILE: documentation/api-reference/templates/index.html ================================================ 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> ================================================ FILE: documentation/api-reference/templates/merge_dita_xml.xslt ================================================ ================================================ FILE: documentation/api-reference/templates/methodSummary.xslt ================================================

    ================================================ FILE: documentation/api-reference/templates/mxml-tags.html ================================================ 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>
    ================================================ FILE: documentation/api-reference/templates/override.css ================================================ /* //////////////////////////////////////////////////////////////////////////////// // // 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. // //////////////////////////////////////////////////////////////////////////////// */ ================================================ FILE: documentation/api-reference/templates/package-detail.xslt ================================================ 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"
    ================================================ FILE: documentation/api-reference/templates/package-frame.html ================================================ 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> ================================================ FILE: documentation/api-reference/templates/package-list.xslt ================================================ <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%
    ================================================ FILE: documentation/api-reference/templates/style.css ================================================ /* //////////////////////////////////////////////////////////////////////////////// // // 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; } /****** start mobile tweaks ******/ .titleTable tr td.titleTableTopNav a, .titleTable tr td.titleTableSubNav a { padding-right: 6px; padding-left: 6px; border-right: solid 1px #333; } .titleTable tr td.titleTableTopNav a:last-of-type, .titleTable tr td.titleTableSubNav a:last-of-type, .titleTable tr td.titleTableTopNav a#framesLink1, .titleTable tr td.titleTableTopNav a#noFramesLink11 { border-right: none; } @media only screen and (max-width: 600px) { .titleTable tr { display: flex; align-items: center; flex-wrap: wrap; } .titleTable tr.titleTableRow2 { height: auto; background-size: contain; } .titleTable tr td { display: flex; align-items: center; background-size: contain; align-self: stretch; min-height: 32px; flex-grow: 1; padding-left: 10px; padding-right: 10px; } .titleTable tr td.titleTableTitle { white-space: normal; flex-grow: 2; } .titleTable tr td.titleTableLogo { display: none; } .titleTable tr td.titleTableSubTitle { flex-grow: 2; } .titleTable tr td.titleTableTopNav { justify-content: end; } .titleTable tr td.titleTableSubNav { justify-content: end; } .MainContent, .summarySection, .detailHeader, .detailBody { margin-left: 8px; margin-right: 8px; } .summaryTable { overflow-x: auto; display: block; } .detailHeader tr { display: flex; align-items: baseline; flex-wrap: wrap; } .detailHeaderName { word-break: break-word; white-space: normal; } .allIndexTable { overflow-x: auto; display: block; } .idxrow, .seeAlso a, .detailBody code { /* word-break: normal; */ overflow-wrap: anywhere; word-break: break-word; } .titleTable tr td.titleTableSearch { display: none; } /* title bar in a frame */ .titleTable.titleTableFrame tr { flex-wrap: unset; } .titleTable.titleTableFrame tr td.titleTableTopNav { flex-grow: 3; } .titleTable.titleTableFrame tr td.titleTableTitle { flex-grow: 1; } } @media only screen and (max-width: 450px) { .titleTable.titleTableFrame tr td.titleTableTopNav a:not(#noFramesLink1), .titleTable.titleTableFrame tr td.titleTableSubNav a { display: none !important; } } table.hideInheritedConstant { display: none; } table.showInheritedConstant { display: block; } table.hideInheritedProtectedConstant { display: none; } table.showInheritedProtectedConstant { display: block; } table.hideInheritedProperty { display: none; } table.showInheritedProperty { display: block; } table.hideInheritedProtectedProperty { display: none; } table.showInheritedProtectedProperty { display: block; } table.hideInheritedMethod { display: none; } table.showInheritedMethod { display: block; } table.hideInheritedProtectedMethod { display: none; } table.showInheritedProtectedMethod { display: block; } table.hideInheritedEvent { display: none; } table.showInheritedEvent { display: block; } table.hideInheritedStyle { display: none; } table.showInheritedStyle { display: block; } table.hideInheritedEffect { display: none; } table.showInheritedEffect { display: block; } ================================================ FILE: documentation/api-reference/templates/stylesSummary.xslt ================================================ ================================================ FILE: documentation/api-reference/templates/title-bar.html ================================================ ActionScript 3.0 Language Reference
    ActionScript 3.0 Language and Components Reference All Packages All Classes Index No Frames
     
     
    ================================================ FILE: examples/ComponentsExplorer/README.md ================================================ # 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 Framework 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. ================================================ FILE: examples/ComponentsExplorer/assets/images/icons-readme.txt ================================================ Icons by Glyphish - glyphish.com ================================================ FILE: examples/ComponentsExplorer/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed advanced.telemetry=false swf.version = 30 ================================================ FILE: examples/ComponentsExplorer/build.xml ================================================ ================================================ FILE: examples/ComponentsExplorer/source/ComponentsExplorer-app.xml ================================================ com.feathersui.examples.ComponentsExplorer Components Components 4.2.0 Components Explorer example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC ComponentsExplorer.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent NSAppTransportSecurity NSAllowsArbitraryLoads ]]> high ================================================ FILE: examples/ComponentsExplorer/source/ComponentsExplorer.as ================================================ package { import feathers.examples.componentsExplorer.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/ComponentsExplorerWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.componentsExplorer.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/Main.as ================================================ package feathers.examples.componentsExplorer { import feathers.controls.Drawers; import feathers.controls.StackScreenNavigator; import feathers.controls.StackScreenNavigatorItem; import feathers.examples.componentsExplorer.data.DataGridSettings; import feathers.examples.componentsExplorer.data.DateTimeSpinnerSettings; 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.AutoCompleteScreen; import feathers.examples.componentsExplorer.screens.ButtonGroupScreen; import feathers.examples.componentsExplorer.screens.ButtonScreen; import feathers.examples.componentsExplorer.screens.CalloutScreen; import feathers.examples.componentsExplorer.screens.CheckScreen; import feathers.examples.componentsExplorer.screens.DataGridScreen; import feathers.examples.componentsExplorer.screens.DataGridSettingsScreen; import feathers.examples.componentsExplorer.screens.DateTimeSpinnerScreen; import feathers.examples.componentsExplorer.screens.DateTimeSpinnerSettingsScreen; 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.PanelComponentScreen; import feathers.examples.componentsExplorer.screens.PickerListScreen; import feathers.examples.componentsExplorer.screens.ProgressBarScreen; import feathers.examples.componentsExplorer.screens.RadioScreen; import feathers.examples.componentsExplorer.screens.ScrollTextScreen; import feathers.examples.componentsExplorer.screens.SliderScreen; import feathers.examples.componentsExplorer.screens.SliderSettingsScreen; import feathers.examples.componentsExplorer.screens.SpinnerListScreen; import feathers.examples.componentsExplorer.screens.TabBarScreen; import feathers.examples.componentsExplorer.screens.TextCalloutScreen; import feathers.examples.componentsExplorer.screens.TextInputScreen; import feathers.examples.componentsExplorer.screens.ToggleSwitchScreen; import feathers.examples.componentsExplorer.screens.TreeScreen; import feathers.examples.componentsExplorer.screens.WebViewScreen; import feathers.layout.Orientation; import feathers.motion.Cover; import feathers.motion.Reveal; import feathers.motion.Slide; import feathers.system.DeviceCapabilities; import feathers.themes.MetalWorksMobileTheme; import flash.system.Capabilities; import starling.core.Starling; import starling.events.Event; import feathers.examples.componentsExplorer.screens.ToastScreen; public class Main extends Drawers { public function Main() { //set up the theme right away! new MetalWorksMobileTheme(); super(); } private var _navigator:StackScreenNavigator; private var _menu:MainMenuScreen; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); EmbeddedAssets.initialize(); this._navigator = new StackScreenNavigator(); this.content = this._navigator; var alertItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(AlertScreen); alertItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.ALERT, alertItem); var autoCompleteItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(AutoCompleteScreen); autoCompleteItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.AUTO_COMPLETE, autoCompleteItem); var buttonItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ButtonScreen); buttonItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.BUTTON, buttonItem); var buttonGroupItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ButtonGroupScreen); buttonGroupItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.BUTTON_GROUP, buttonGroupItem); var calloutItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(CalloutScreen); calloutItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.CALLOUT, calloutItem); var checkItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(CheckScreen); checkItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.CHECK, checkItem); var dataGridSettings:DataGridSettings = new DataGridSettings(); var dataGridItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(DataGridScreen); dataGridItem.setScreenIDForPushEvent(DataGridScreen.SHOW_SETTINGS, ScreenID.DATA_GRID_SETTINGS); dataGridItem.addPopEvent(Event.COMPLETE); dataGridItem.properties.settings = dataGridSettings; this._navigator.addScreen(ScreenID.DATA_GRID, dataGridItem); var dataGridSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(DataGridSettingsScreen); dataGridSettingsItem.addPopEvent(Event.COMPLETE); dataGridSettingsItem.properties.settings = dataGridSettings; //custom push and pop transitions for this settings screen dataGridSettingsItem.pushTransition = Cover.createCoverUpTransition(); dataGridSettingsItem.popTransition = Reveal.createRevealDownTransition(); this._navigator.addScreen(ScreenID.DATA_GRID_SETTINGS, dataGridSettingsItem); var dateTimeSpinnerSettings:DateTimeSpinnerSettings = new DateTimeSpinnerSettings(); var dateTimeSpinnerItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(DateTimeSpinnerScreen); dateTimeSpinnerItem.setScreenIDForPushEvent(DateTimeSpinnerScreen.SHOW_SETTINGS, ScreenID.DATE_TIME_SPINNER_SETTINGS); dateTimeSpinnerItem.addPopEvent(Event.COMPLETE); dateTimeSpinnerItem.properties.settings = dateTimeSpinnerSettings; this._navigator.addScreen(ScreenID.DATE_TIME_SPINNER, dateTimeSpinnerItem); var dateTimeSpinnerSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(DateTimeSpinnerSettingsScreen); dateTimeSpinnerSettingsItem.addPopEvent(Event.COMPLETE); dateTimeSpinnerSettingsItem.properties.settings = dateTimeSpinnerSettings; //custom push and pop transitions for this settings screen dateTimeSpinnerSettingsItem.pushTransition = Cover.createCoverUpTransition(); dateTimeSpinnerSettingsItem.popTransition = Reveal.createRevealDownTransition(); this._navigator.addScreen(ScreenID.DATE_TIME_SPINNER_SETTINGS, dateTimeSpinnerSettingsItem); var groupedListSettings:GroupedListSettings = new GroupedListSettings(); var groupedListItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(GroupedListScreen); groupedListItem.setScreenIDForPushEvent(GroupedListScreen.SHOW_SETTINGS, ScreenID.GROUPED_LIST_SETTINGS); groupedListItem.addPopEvent(Event.COMPLETE); groupedListItem.properties.settings = groupedListSettings; this._navigator.addScreen(ScreenID.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(ScreenID.GROUPED_LIST_SETTINGS, groupedListSettingsItem); var itemRendererSettings:ItemRendererSettings = new ItemRendererSettings(); var itemRendererItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ItemRendererScreen); itemRendererItem.setScreenIDForPushEvent(ItemRendererScreen.SHOW_SETTINGS, ScreenID.ITEM_RENDERER_SETTINGS); itemRendererItem.addPopEvent(Event.COMPLETE); itemRendererItem.properties.settings = itemRendererSettings; this._navigator.addScreen(ScreenID.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(ScreenID.ITEM_RENDERER_SETTINGS, itemRendererSettingsItem); var labelItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(LabelScreen); labelItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.LABEL, labelItem); var listSettings:ListSettings = new ListSettings(); var listItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ListScreen); listItem.setScreenIDForPushEvent(ListScreen.SHOW_SETTINGS, ScreenID.LIST_SETTINGS); listItem.addPopEvent(Event.COMPLETE); listItem.properties.settings = listSettings; this._navigator.addScreen(ScreenID.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(ScreenID.LIST_SETTINGS, listSettingsItem); var numericStepperSettings:NumericStepperSettings = new NumericStepperSettings(); var numericStepperItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(NumericStepperScreen); numericStepperItem.setScreenIDForPushEvent(NumericStepperScreen.SHOW_SETTINGS, ScreenID.NUMERIC_STEPPER_SETTINGS); numericStepperItem.addPopEvent(Event.COMPLETE); numericStepperItem.properties.settings = numericStepperSettings; this._navigator.addScreen(ScreenID.NUMERIC_STEPPER, numericStepperItem); var panelItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(PanelComponentScreen); panelItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.PANEL, panelItem); 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(ScreenID.NUMERIC_STEPPER_SETTINGS, numericStepperSettingsItem); var pageIndicatorItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(PageIndicatorScreen); pageIndicatorItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.PAGE_INDICATOR, pageIndicatorItem); var pickerListItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(PickerListScreen); pickerListItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.PICKER_LIST, pickerListItem); var progressBarItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ProgressBarScreen); progressBarItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.PROGRESS_BAR, progressBarItem); var radioItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(RadioScreen); radioItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.RADIO, radioItem); var scrollTextItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ScrollTextScreen); scrollTextItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.SCROLL_TEXT, scrollTextItem); var sliderSettings:SliderSettings = new SliderSettings(); var sliderItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(SliderScreen); sliderItem.setScreenIDForPushEvent(SliderScreen.SHOW_SETTINGS, ScreenID.SLIDER_SETTINGS); sliderItem.addPopEvent(Event.COMPLETE); sliderItem.properties.settings = sliderSettings; this._navigator.addScreen(ScreenID.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(ScreenID.SLIDER_SETTINGS, sliderSettingsItem); var spinnerListItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(SpinnerListScreen); spinnerListItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.SPINNER_LIST, spinnerListItem); var tabBarItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TabBarScreen); tabBarItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.TAB_BAR, tabBarItem); var textCalloutItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TextCalloutScreen); textCalloutItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.TEXT_CALLOUT, textCalloutItem); var textInputItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TextInputScreen); textInputItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.TEXT_INPUT, textInputItem); var toastItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ToastScreen); toastItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.TOAST, toastItem); var togglesItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ToggleSwitchScreen); togglesItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.TOGGLES, togglesItem); var treeItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(TreeScreen); treeItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.TREE, treeItem); if(Capabilities.playerType == "Desktop") //this means AIR, even for mobile { var webViewItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(WebViewScreen); webViewItem.addPopEvent(Event.COMPLETE); this._navigator.addScreen(ScreenID.WEB_VIEW, webViewItem); } 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(); this._menu.addEventListener(Event.CHANGE, mainMenu_tabletChangeHandler); this._menu.height = 200; this.leftDrawer = this._menu; this.leftDrawerDockMode = Orientation.BOTH; } else { var mainMenuItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(MainMenuScreen); mainMenuItem.setFunctionForPushEvent(Event.CHANGE, mainMenu_phoneChangeHandler); this._navigator.addScreen(ScreenID.MAIN_MENU, mainMenuItem); this._navigator.rootScreenID = ScreenID.MAIN_MENU; } this._navigator.pushTransition = Slide.createSlideLeftTransition(); this._navigator.popTransition = Slide.createSlideRightTransition(); } private function mainMenu_phoneChangeHandler(event:Event):void { //when MainMenuScreen dispatches Event.CHANGE, its selectedScreenID //property has been updated. use that to show the correct screen. var screen:MainMenuScreen = MainMenuScreen(event.currentTarget); this._navigator.pushScreen(screen.selectedScreenID, event.data); //pass the data from the event to save it for when we pop back. } private function mainMenu_tabletChangeHandler(event:Event):void { //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. var screen:MainMenuScreen = MainMenuScreen(event.currentTarget); this._navigator.rootScreenID = screen.selectedScreenID; } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/ScreenID.as ================================================ package feathers.examples.componentsExplorer { public class ScreenID { public static const MAIN_MENU:String = "mainMenu"; public static const ALERT:String = "alert"; public static const AUTO_COMPLETE:String = "autoComplete"; public static const BUTTON:String = "button"; public static const BUTTON_GROUP:String = "buttonGroup"; public static const CALLOUT:String = "callout"; public static const CHECK:String = "check"; public static const DATA_GRID:String = "dataGrid"; public static const DATA_GRID_SETTINGS:String = "dataGridSettings"; public static const DATE_TIME_SPINNER:String = "dateTimeSpinner"; public static const DATE_TIME_SPINNER_SETTINGS:String = "dateTimeSpinnerSettings"; public static const GROUPED_LIST:String = "groupedList"; public static const GROUPED_LIST_SETTINGS:String = "groupedListSettings"; public static const ITEM_RENDERER:String = "itemRenderer"; public static const ITEM_RENDERER_SETTINGS:String = "itemRendererSettings"; public static const LABEL:String = "label"; public static const LIST:String = "list"; public static const LIST_SETTINGS:String = "listSettings"; public static const NUMERIC_STEPPER:String = "numericStepper"; public static const NUMERIC_STEPPER_SETTINGS:String = "numericStepperSettings"; public static const PAGE_INDICATOR:String = "pageIndicator"; public static const PANEL:String = "panel"; public static const PICKER_LIST:String = "pickerList"; public static const PROGRESS_BAR:String = "progressBar"; public static const RADIO:String = "radio"; public static const SCROLL_TEXT:String = "scrollText"; public static const SLIDER:String = "slider"; public static const SPINNER_LIST:String = "spinnerList"; public static const SLIDER_SETTINGS:String = "sliderSettings"; public static const TAB_BAR:String = "tabBar"; public static const TEXT_CALLOUT:String = "textCallout"; public static const TEXT_INPUT:String = "textInput"; public static const TOAST:String = "toast"; public static const TOGGLES:String = "toggles"; public static const TREE:String = "tree"; public static const WEB_VIEW:String = "webView"; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/DataGridSettings.as ================================================ package feathers.examples.componentsExplorer.data { import feathers.controls.ItemRendererLayoutOrder; import feathers.layout.HorizontalAlign; import feathers.layout.RelativePosition; import feathers.layout.VerticalAlign; public class DataGridSettings { public function DataGridSettings() { } public var reorderColumns:Boolean = false; public var sortableColumns:Boolean = false; public var resizableColumns:Boolean = false; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/DateTimeSpinnerSettings.as ================================================ package feathers.examples.componentsExplorer.data { import feathers.controls.DateTimeMode; public class DateTimeSpinnerSettings { public function DateTimeSpinnerSettings() { } public var editingMode:String = DateTimeMode.DATE_AND_TIME; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/EmbeddedAssets.as ================================================ 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.fromEmbeddedAsset(SKULL_ICON_DARK_EMBEDDED, false, false, 2); SKULL_ICON_LIGHT = Texture.fromEmbeddedAsset(SKULL_ICON_LIGHT_EMBEDDED, false, false, 2); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/GroupedListSettings.as ================================================ 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; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ItemRendererSettings.as ================================================ package feathers.examples.componentsExplorer.data { import feathers.controls.ItemRendererLayoutOrder; import feathers.layout.HorizontalAlign; import feathers.layout.RelativePosition; import feathers.layout.VerticalAlign; 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 = ItemRendererLayoutOrder.LABEL_ICON_ACCESSORY; public var iconType:String = ICON_ACCESSORY_TYPE_TEXTURE; public var iconPosition:String = RelativePosition.LEFT; public var useInfiniteGap:Boolean = false; public var accessoryPosition:String = RelativePosition.RIGHT; public var accessoryType:String = ICON_ACCESSORY_TYPE_DISPLAY_OBJECT; public var useInfiniteAccessoryGap:Boolean = true; public var horizontalAlign:String = HorizontalAlign.LEFT; public var verticalAlign:String = VerticalAlign.MIDDLE; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/ListSettings.as ================================================ 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; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/NumericStepperSettings.as ================================================ package feathers.examples.componentsExplorer.data { public class NumericStepperSettings { public function NumericStepperSettings() { } public var step:Number = 1; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/data/SliderSettings.as ================================================ package feathers.examples.componentsExplorer.data { import feathers.controls.TrackInteractionMode; public class SliderSettings { public function SliderSettings() { } public var step:Number = 1; public var page:Number = 10; public var liveDragging:Boolean = true; public var trackInteractionMode:String = TrackInteractionMode.TO_VALUE; } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/AlertScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Alert; import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.data.ArrayCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import starling.events.Event; import feathers.system.DeviceCapabilities; import starling.core.Starling; import starling.display.DisplayObject; 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 buttonLayoutData:AnchorLayoutData = new AnchorLayoutData(); buttonLayoutData.horizontalCenter = 0; buttonLayoutData.verticalCenter = 0; this._showAlertButton.layoutData = buttonLayoutData; 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 ArrayCollection( [ { label: "OK" }, { label: "Cancel" } ])); //when the enter key is pressed, treat it as OK alert.acceptButtonIndex = 0; //when the back or escape key is pressed, treat it as cancel alert.cancelButtonIndex = 1; alert.addEventListener(Event.CLOSE, alert_closeHandler); } private function alert_closeHandler(event:Event, data:Object):void { if(data) { trace("alert closed with item:", data.label); } else { trace("alert closed without item"); } } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/AutoCompleteScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.AutoComplete; import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; import feathers.data.LocalAutoCompleteSource; import feathers.data.VectorCollection; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 AutoCompleteScreen extends PanelScreen { public function AutoCompleteScreen() { } private var _input:AutoComplete; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Auto-complete"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.CENTER; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; this._input = new AutoComplete(); this._input.prompt = "Fruits. Type 'ap' to see suggestions"; this._input.source = new LocalAutoCompleteSource(new VectorCollection(new [ "Apple", "Apricot", "Banana", "Cantaloupe", "Cherry", "Grape", "Lemon", "Lime", "Mango", "Orange", "Peach", "Pineapple", "Plum", "Pomegranate", "Raspberry", "Strawberry", "Watermelon" ])); this.addChild(this._input); 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonGroupScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.ButtonGroup; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.data.ArrayCollection; 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 ArrayCollection( [ { 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."); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ButtonScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.ImageLoader; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; import feathers.controls.ToggleButton; import feathers.examples.componentsExplorer.data.EmbeddedAssets; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 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; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Button"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.CENTER; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; 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(); this._iconButton.label = "Icon Button"; var icon:ImageLoader = new ImageLoader(); //the source can be either a texture or a URL icon.source = EmbeddedAssets.SKULL_ICON_DARK; this._iconButton.defaultIcon = 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/CalloutScreen.as ================================================ 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.controls.ScrollPolicy; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 { public function CalloutScreen() { super(); } private var _showCalloutButton:Button; private var _content:PanelScreen; override public function dispose():void { //the content won't be on the display list when the screen is //disposed, so dispose it manually if(this._content) { this._content.dispose(); this._content = null; } super.dispose(); } override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Callout"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.CENTER; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; //this is what we're going to display in the callout this._content = new PanelScreen(); this._content.headerFactory = function():Header { var header:Header = new Header(); //don't add extra padding on iOS header.useExtraPaddingForOSStatusBar = false; header.paddingTop = 2; header.paddingBottom = 8; header.gap = 8; header.titleGap = 8; header.backgroundSkin = null; //we want to use the theme's font styles, with a slightly smaller font size header.initializeNow(); header.fontStyles.size = 14; return header; }; this._content.title = "Callout Content"; this._content.width = 200; this._content.layout = new AnchorLayout(); var description:Label = new Label(); description.layoutData = new AnchorLayoutData(0, 0, 0, 0); description.wordWrap = true; description.text = "A callout displays content in a pop-up container, with an arrow that points to its origin.\n\nTap anywhere outside of the callout to close it."; this._content.addChild(description); //the content will be shown in the callout, so we don't add it to a //parent yet. this._showCalloutButton = new Button(); this._showCalloutButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON); this._showCalloutButton.label = "Show Callout"; this._showCalloutButton.addEventListener(Event.TRIGGERED, showCalloutButton_triggeredHandler); this.addChild(this._showCalloutButton); 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 showCalloutButton_triggeredHandler(event:Event):void { var callout:Callout = Callout.show(this._content, this._showCalloutButton); //we're reusing the content every time that it is shown, so we don't //want the content to be disposed. we'll dispose of it manually //later when the screen is disposed. callout.disposeContent = false; } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/CheckScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Check; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 CheckScreen extends PanelScreen { public function CheckScreen() { super(); } private var _check:Check; private var _checked:Check; private var _disabled:Check; private var _selectedDisabled:Check; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Check"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.LEFT; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; this._check = new Check(); this._check.label = "Default"; this._check.addEventListener(Event.CHANGE, check_changeHandler); this.addChild(this._check); this._checked = new Check(); this._checked.label = "Selected"; this._checked.isSelected = true; this.addChild(this._checked); this._disabled = new Check(); this._disabled.label = "Disabled"; this._disabled.isEnabled = false; this.addChild(this._disabled); this._selectedDisabled = new Check(); this._selectedDisabled.label = "Selected and Disabled"; this._selectedDisabled.isSelected = true; this._selectedDisabled.isEnabled = false; this.addChild(this._selectedDisabled); 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 check_changeHandler(event:Event):void { trace("check changed:", this._check.isSelected); } private function backButton_triggeredHandler(event:Event):void { this.onBackButton(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/DataGridScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.DataGrid; import feathers.controls.DataGridColumn; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.data.ArrayCollection; import feathers.events.FeathersEventType; import feathers.examples.componentsExplorer.data.DataGridSettings; 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 DataGridScreen extends PanelScreen { public static const SHOW_SETTINGS:String = "showSettings"; public function DataGridScreen() { super(); } public var settings:DataGridSettings; private var _grid:DataGrid; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Data Grid"; this.layout = new AnchorLayout(); var items:Array = [ { item: "Chicken breast", dept: "Meat", price: "5.90" }, { item: "Bacon", dept: "Meat", price: "4.49" }, { item: "2% Milk", dept: "Dairy", price: "2.49" }, { item: "Butter", dept: "Dairy", price: "4.69" }, { item: "Lettuce", dept: "Produce", price: "1.29" }, { item: "Broccoli", dept: "Produce", price: "2.99" }, { item: "Whole Wheat Bread", dept: "Bakery", price: "2.49" }, { item: "English Muffins", dept: "Bakery", price: "2.99" }, ]; var columns:Array = [ new DataGridColumn("item", "Item"), new DataGridColumn("dept", "Department"), new DataGridColumn("price", "Unit Price"), ]; this._grid = new DataGrid(); this._grid.dataProvider = new ArrayCollection(items); this._grid.columns = new ArrayCollection(columns); this._grid.sortableColumns = this.settings.sortableColumns; this._grid.resizableColumns = this.settings.resizableColumns; this._grid.reorderColumns = this.settings.reorderColumns; //optimization: since this grid fills the entire screen, there's no //need for clipping. clipping should not be disabled if there's a //chance that item renderers could be visible if they appear outside //the list's bounds this._grid.clipContent = false; //optimization: when the background is covered by all item //renderers, don't render it this._grid.autoHideBackground = true; this._grid.addEventListener(Event.CHANGE, list_changeHandler); this._grid.layoutData = new AnchorLayoutData(0, 0, 0, 0); this.addChild(this._grid); 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._grid.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._grid.selectedIndices; trace("List change:", selectedIndices.length > 0 ? selectedIndices : this._grid.selectedIndex); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/DataGridSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.examples.componentsExplorer.data.DataGridSettings; 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 DataGridSettingsScreen extends PanelScreen { public function DataGridSettingsScreen() { super(); } public var settings:DataGridSettings; private var _list:List; private var _sortableColumnsToggle:ToggleSwitch; private var _resizableColumnsToggle:ToggleSwitch; private var _reorderColumnsToggle: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 = "Data Grid Settings"; this.layout = new AnchorLayout(); this._sortableColumnsToggle = new ToggleSwitch(); this._sortableColumnsToggle.isSelected = this.settings.sortableColumns; this._sortableColumnsToggle.addEventListener(Event.CHANGE, sortableColumnsToggle_changeHandler); this._resizableColumnsToggle = new ToggleSwitch(); this._resizableColumnsToggle.isSelected = this.settings.resizableColumns; this._resizableColumnsToggle.addEventListener(Event.CHANGE, resizableColumnsToggle_changeHandler); this._reorderColumnsToggle = new ToggleSwitch(); this._reorderColumnsToggle.isSelected = this.settings.reorderColumns; this._reorderColumnsToggle.addEventListener(Event.CHANGE, reorderColumnsToggle_changeHandler); this._list = new List(); this._list.isSelectable = false; this._list.dataProvider = new ArrayCollection( [ { label: "Sortable Columns", accessory: this._sortableColumnsToggle }, { label: "Resizable Columns", accessory: this._resizableColumnsToggle }, { label: "Reorder Columns", accessory: this._reorderColumnsToggle }, ]); 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 reorderColumnsToggle_changeHandler(event:Event):void { this.settings.reorderColumns = this._reorderColumnsToggle.isSelected; } private function resizableColumnsToggle_changeHandler(event:Event):void { this.settings.resizableColumns = this._resizableColumnsToggle.isSelected; } private function sortableColumnsToggle_changeHandler(event:Event):void { this.settings.sortableColumns = this._sortableColumnsToggle.isSelected; } private function doneButton_triggeredHandler(event:Event):void { this.onBackButton(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/DateTimeSpinnerScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.DateTimeSpinner; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.examples.componentsExplorer.data.DateTimeSpinnerSettings; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 DateTimeSpinnerScreen extends PanelScreen { public static const SHOW_SETTINGS:String = "showSettings"; public function DateTimeSpinnerScreen() { } public var settings:DateTimeSpinnerSettings; private var _dateTimeSpinner:DateTimeSpinner; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Date Time Spinner"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.CENTER; verticalLayout.verticalAlign = VerticalAlign.MIDDLE; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this._dateTimeSpinner = new DateTimeSpinner(); this._dateTimeSpinner.editingMode = this.settings.editingMode; this._dateTimeSpinner.addEventListener(Event.CHANGE, dateTimeSpinner_changeHandler); this.addChild(this._dateTimeSpinner); 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 backButton_triggeredHandler(event:Event):void { this.onBackButton(); } private function settingsButton_triggeredHandler(event:Event):void { this.dispatchEventWith(SHOW_SETTINGS); } private function dateTimeSpinner_changeHandler(event:Event):void { trace("DateTimeSpinner change:", this._dateTimeSpinner.value); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/DateTimeSpinnerSettingsScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.DateTimeMode; import feathers.controls.Header; import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.PickerList; import feathers.data.ArrayCollection; import feathers.data.VectorCollection; import feathers.examples.componentsExplorer.data.DateTimeSpinnerSettings; 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 DateTimeSpinnerSettingsScreen extends PanelScreen { public function DateTimeSpinnerSettingsScreen() { super(); } public var settings:DateTimeSpinnerSettings; private var _list:List; private var _editingModePicker: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 = "Date Time Spinner Settings"; this.layout = new AnchorLayout(); this._editingModePicker = new PickerList(); this._editingModePicker.dataProvider = new VectorCollection(new [ DateTimeMode.DATE_AND_TIME, DateTimeMode.DATE, DateTimeMode.TIME, ]); this._editingModePicker.selectedItem = this.settings.editingMode; this._editingModePicker.addEventListener(Event.CHANGE, editingModePicker_changeHandler); this._list = new List(); this._list.isSelectable = false; this._list.dataProvider = new ArrayCollection( [ { label: "editingMode", accessory: this._editingModePicker }, ]); 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 editingModePicker_changeHandler(event:Event):void { this.settings.editingMode = this._editingModePicker.selectedItem as String; } private function doneButton_triggeredHandler(event:Event):void { this.onBackButton(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListScreen.as ================================================ 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.ArrayHierarchicalCollection; 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" }, ] } ]; 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 ArrayHierarchicalCollection(groups); this._list.typicalItem = { text: "Item 1000" }; this._list.isSelectable = this.settings.isSelectable; this._list.hasElasticEdges = this.settings.hasElasticEdges; //optimization: since this list fills the entire screen, there's no //need for clipping. clipping should not be disabled if there's a //chance that item renderers could be visible if they appear outside //the list's bounds this._list.clipContent = false; //optimization: when the background is covered by all item //renderers, don't render it 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 change:", this._list.selectedGroupIndex, this._list.selectedItemIndex); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/GroupedListSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.VectorCollection; 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 VectorCollection(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 ArrayCollection( [ { 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; } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererScreen.as ================================================ 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.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.examples.componentsExplorer.data.EmbeddedAssets; import feathers.examples.componentsExplorer.data.ItemRendererSettings; 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 ItemRendererScreen extends PanelScreen { public static const SHOW_SETTINGS:String = "showSettings"; public function ItemRendererScreen() { super(); } private var _list:List; private var _listItem:Object; 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 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.itemRendererFactory = this.customItemRendererFactory; this._list.dataProvider = new ArrayCollection([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; } } private function customItemRendererFactory():IListItemRenderer { var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); itemRenderer.labelField = "text"; if(this.settings.hasIcon) { switch(this.settings.iconType) { case ItemRendererSettings.ICON_ACCESSORY_TYPE_LABEL: { this._listItem.iconText = "Icon Text"; itemRenderer.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; itemRenderer.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(); itemRenderer.iconField = "icon"; //clear these in case this setting has changed delete this._listItem.iconText; delete this._listItem.iconTexture; } } itemRenderer.iconPosition = this.settings.iconPosition; } if(this.settings.hasAccessory) { switch(this.settings.accessoryType) { case ItemRendererSettings.ICON_ACCESSORY_TYPE_LABEL: { this._listItem.accessoryText = "Accessory Text"; itemRenderer.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; itemRenderer.accessorySourceField = "accessoryTexture"; break; } default: { this._listItem.accessory = new ToggleSwitch(); itemRenderer.accessoryField = "accessory"; //clear these in case this setting has changed delete this._listItem.accessoryText; delete this._listItem.accessoryTexture; } } itemRenderer.accessoryPosition = this.settings.accessoryPosition; } if(this.settings.useInfiniteGap) { itemRenderer.gap = Number.POSITIVE_INFINITY; } else { itemRenderer.gap = 12; } if(this.settings.useInfiniteAccessoryGap) { itemRenderer.accessoryGap = Number.POSITIVE_INFINITY; } else { itemRenderer.accessoryGap = 12; } itemRenderer.horizontalAlign = this.settings.horizontalAlign; itemRenderer.verticalAlign = this.settings.verticalAlign; itemRenderer.layoutOrder = this.settings.layoutOrder; return itemRenderer; } 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); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ItemRendererSettingsScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.GroupedList; import feathers.controls.Header; import feathers.controls.ItemRendererLayoutOrder; import feathers.controls.PanelScreen; import feathers.controls.PickerList; import feathers.controls.ToggleSwitch; import feathers.data.ArrayCollection; import feathers.data.ArrayHierarchicalCollection; import feathers.data.VectorCollection; import feathers.examples.componentsExplorer.data.ItemRendererSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.RelativePosition; import feathers.layout.VerticalAlign; 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 VectorCollection(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 = RelativePosition.RIGHT_BASELINE; this._iconPositionPicker.dataProvider = new VectorCollection(new [ RelativePosition.TOP, RelativePosition.RIGHT, RelativePosition.BOTTOM, RelativePosition.LEFT, RelativePosition.LEFT_BASELINE, RelativePosition.RIGHT_BASELINE, //RelativePosition.MANUAL, ]); this._iconPositionPicker.listProperties.typicalItem = RelativePosition.RIGHT_BASELINE; this._iconPositionPicker.selectedItem = this.settings.iconPosition; this._iconPositionPicker.addEventListener(Event.CHANGE, iconPositionPicker_changeHandler); this._gapPicker = new PickerList(); this._gapPicker.dataProvider = new ArrayCollection( [ { 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 VectorCollection(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 = RelativePosition.BOTTOM; this._accessoryPositionPicker.dataProvider = new VectorCollection(new [ RelativePosition.TOP, RelativePosition.RIGHT, RelativePosition.BOTTOM, RelativePosition.LEFT, //RelativePosition.MANUAL, ]); this._accessoryPositionPicker.listProperties.typicalItem = RelativePosition.BOTTOM; this._accessoryPositionPicker.selectedItem = this.settings.accessoryPosition; this._accessoryPositionPicker.addEventListener(Event.CHANGE, accessoryPositionPicker_changeHandler); this._accessoryGapPicker = new PickerList(); this._accessoryGapPicker.dataProvider = new ArrayCollection( [ { 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 = ItemRendererLayoutOrder.LABEL_ACCESSORY_ICON; this._layoutOrderPicker.dataProvider = new VectorCollection(new [ ItemRendererLayoutOrder.LABEL_ICON_ACCESSORY, ItemRendererLayoutOrder.LABEL_ACCESSORY_ICON, ]); this._layoutOrderPicker.listProperties.typicalItem = ItemRendererLayoutOrder.LABEL_ACCESSORY_ICON; this._layoutOrderPicker.selectedItem = this.settings.layoutOrder; this._layoutOrderPicker.addEventListener(Event.CHANGE, layoutOrderPicker_changeHandler); this._horizontalAlignPicker = new PickerList(); this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT, ]); this._horizontalAlignPicker.typicalItem = HorizontalAlign.CENTER; this._horizontalAlignPicker.listProperties.typicalItem = HorizontalAlign.CENTER; this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, ]); this._verticalAlignPicker.typicalItem = VerticalAlign.MIDDLE; this._verticalAlignPicker.listProperties.typicalItem = VerticalAlign.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 ArrayHierarchicalCollection( [ { 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/LabelScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.Label; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 function LabelScreen() { super(); } private var _normalLabel:Label; private var _disabledLabel:Label; private var _headingLabel:Label; private var _detailLabel:Label; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Label"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.JUSTIFY; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; 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._headingLabel.wordWrap = true; 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._detailLabel.wordWrap = true; 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListScreen.as ================================================ 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.ArrayCollection; 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 ArrayCollection(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: since this list fills the entire screen, there's no //need for clipping. clipping should not be disabled if there's a //chance that item renderers could be visible if they appear outside //the list's bounds this._list.clipContent = false; //optimization: when the background is covered by all item //renderers, don't render it 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 change:", selectedIndices.length > 0 ? selectedIndices : this._list.selectedIndex); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ListSettingsScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Header; import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.ToggleSwitch; import feathers.data.ArrayCollection; import feathers.examples.componentsExplorer.data.ListSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import starling.events.Event; import feathers.controls.Button; import starling.display.DisplayObject; [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 ArrayCollection( [ { 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; } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/MainMenuScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.events.FeathersEventType; import feathers.examples.componentsExplorer.ScreenID; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.system.DeviceCapabilities; import flash.system.Capabilities; import starling.core.Starling; import starling.events.Event; [Event(name="complete",type="starling.events.Event")] [Event(name="change",type="starling.events.Event")] public class MainMenuScreen extends PanelScreen { public function MainMenuScreen() { super(); } private var _list:List; public var savedVerticalScrollPosition:Number = 0; public var savedSelectedIndex:int = -1; private var _selectedScreenID:String = null; public function get selectedScreenID():String { return this._selectedScreenID; } 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 ArrayCollection( [ { label: "Alert", screen: ScreenID.ALERT }, { label: "Auto-complete", screen: ScreenID.AUTO_COMPLETE }, { label: "Button", screen: ScreenID.BUTTON }, { label: "Button Group", screen: ScreenID.BUTTON_GROUP }, { label: "Callout", screen: ScreenID.CALLOUT }, { label: "Check", screen: ScreenID.CHECK }, { label: "Data Grid", screen: ScreenID.DATA_GRID }, { label: "Date Time Spinner", screen: ScreenID.DATE_TIME_SPINNER }, { label: "Grouped List", screen: ScreenID.GROUPED_LIST }, { label: "Item Renderer", screen: ScreenID.ITEM_RENDERER }, { label: "Label", screen: ScreenID.LABEL }, { label: "List", screen: ScreenID.LIST }, { label: "Numeric Stepper", screen: ScreenID.NUMERIC_STEPPER }, { label: "Page Indicator", screen: ScreenID.PAGE_INDICATOR }, { label: "Panel", screen: ScreenID.PANEL }, { label: "Picker List", screen: ScreenID.PICKER_LIST }, { label: "Progress Bar", screen: ScreenID.PROGRESS_BAR }, { label: "Radio", screen: ScreenID.RADIO }, { label: "Scroll Text", screen: ScreenID.SCROLL_TEXT }, { label: "Slider", screen: ScreenID.SLIDER}, { label: "Spinner List", screen: ScreenID.SPINNER_LIST }, { label: "Tab Bar", screen: ScreenID.TAB_BAR }, { label: "Text Callout", screen: ScreenID.TEXT_CALLOUT }, { label: "Text Input and Text Area", screen: ScreenID.TEXT_INPUT }, { label: "Toast", screen: ScreenID.TOAST }, { label: "Toggle Switch", screen: ScreenID.TOGGLES }, { label: "Tree", screen: ScreenID.TREE }, ]); if(Capabilities.playerType == "Desktop") //this means AIR, even for mobile { this._list.dataProvider.addItem( { label: "Web View", screen: ScreenID.WEB_VIEW } ); } this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); this._list.clipContent = false; this._list.autoHideBackground = true; this._list.verticalScrollPosition = this.savedVerticalScrollPosition; this._list.itemRendererFactory = this.createItemRenderer; var isTablet:Boolean = DeviceCapabilities.isTablet(Starling.current.nativeStage); 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 createItemRenderer():IListItemRenderer { var isTablet:Boolean = DeviceCapabilities.isTablet(Starling.current.nativeStage); var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); if(!isTablet) { renderer.styleNameList.add(DefaultListItemRenderer.ALTERNATE_STYLE_NAME_DRILL_DOWN); } //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; } 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 { this._selectedScreenID = this._list.selectedItem.screen as String; if(DeviceCapabilities.isTablet(Starling.current.nativeStage)) { this.dispatchEventWith(Event.CHANGE); 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(Event.CHANGE, false, { savedVerticalScrollPosition: this._list.verticalScrollPosition, savedSelectedIndex: this._list.selectedIndex }); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperScreen.as ================================================ 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); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/NumericStepperSettingsScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Header; import feathers.controls.List; import feathers.controls.NumericStepper; import feathers.controls.PanelScreen; import feathers.data.ArrayCollection; import feathers.examples.componentsExplorer.data.NumericStepperSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import starling.events.Event; import feathers.controls.Button; import starling.display.DisplayObject; [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 ArrayCollection( [ { 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PageIndicatorScreen.as ================================================ 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PanelComponentScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.Label; import feathers.controls.Panel; import feathers.controls.PanelScreen; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 PanelComponentScreen extends PanelScreen { public function PanelComponentScreen() { super(); } private var _panel:Panel; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Panel"; this.layout = new AnchorLayout(); this._panel = new Panel(); this._panel.title = "Title"; this._panel.width = 200; this._panel.height = 150; //how the component is positioned in its parent's layout var panelLayoutData:AnchorLayoutData = new AnchorLayoutData(); panelLayoutData.horizontalCenter = 0; panelLayoutData.verticalCenter = 0; this._panel.layoutData = panelLayoutData; //the panel's own internal layout var panelLayout:VerticalLayout = new VerticalLayout(); panelLayout.horizontalAlign = HorizontalAlign.CENTER; panelLayout.verticalAlign = VerticalAlign.MIDDLE; this._panel.layout = panelLayout; this.addChild(this._panel); var content:Label = new Label(); content.text = "This is the Panel's content."; content.wordWrap = true; this._panel.addChild(content); 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/PickerListScreen.as ================================================ 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.SpinnerList; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; 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 ArrayCollection(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._list.addEventListener(Event.CHANGE, pickerList_changeHandler); 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; if(DeviceCapabilities.isPhone(Starling.current.nativeStage)) { list = new SpinnerList(); } else { 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(); } private function pickerList_changeHandler(event:Event):void { trace("PickerList change:", this._list.selectedIndex); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ProgressBarScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ProgressBar; import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.VerticalAlign; 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 function ProgressBarScreen() { super(); } private var _horizontalProgress:ProgressBar; private var _verticalProgress:ProgressBar; private var _horizontalProgressTween:Tween; private var _verticalProgressTween:Tween; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Progress Bar"; var layout:HorizontalLayout = new HorizontalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.padding = 12; layout.gap = 12; this.layout = layout; this._horizontalProgress = new ProgressBar(); this._horizontalProgress.direction = 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 = 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/RadioScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.Label; import feathers.controls.PanelScreen; import feathers.controls.Radio; import feathers.controls.ScrollPolicy; import feathers.core.ToggleGroup; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 RadioScreen extends PanelScreen { public function RadioScreen() { super(); } private var _group1:ToggleGroup; private var _title1:Label; private var _radio1:Radio; private var _radio2:Radio; private var _radio3:Radio; private var _radio4:Radio; private var _group2:ToggleGroup; private var _title2:Label; private var _radioA:Radio; private var _radioB:Radio; private var _radioC:Radio; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Radio"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.LEFT; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; this._group1 = new ToggleGroup(); this._title1 = new Label(); this._title1.styleNameList.add(Label.ALTERNATE_STYLE_NAME_HEADING); this._title1.text = "Group 1"; this.addChild(this._title1); this._radio1 = new Radio(); this._radio1.label = "Option 1"; this._radio1.toggleGroup = this._group1; this.addChild(this._radio1); this._radio2 = new Radio(); this._radio2.label = "Option 2"; this._radio2.isSelected = true; this._radio2.toggleGroup = this._group1; this.addChild(this._radio2); this._radio3 = new Radio(); this._radio3.label = "Option 3"; this._radio3.toggleGroup = this._group1; this.addChild(this._radio3); this._radio4 = new Radio(); this._radio4.label = "Option 4 (Disabled)"; this._radio4.isEnabled = false; this._radio4.toggleGroup = this._group1; this.addChild(this._radio4); this._group1.addEventListener(Event.CHANGE, group1_changeHandler); //radios may be added to different groups this._group2 = new ToggleGroup(); this._title2 = new Label(); this._title2.styleNameList.add(Label.ALTERNATE_STYLE_NAME_HEADING); this._title2.text = "Group 2"; this.addChild(this._title2); this._radioA = new Radio(); this._radioA.label = "Option A"; this.addChild(this._radioA); this._radioB = new Radio(); this._radioB.label = "Option B"; this.addChild(this._radioB); this._radioC = new Radio(); this._radioC.label = "Option C"; this.addChild(this._radioC); this._group2.selectedItem = this._radioA; 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 group1_changeHandler(event:Event):void { trace("radio group changed:", this._group1.selectedIndex); } private function backButton_triggeredHandler(event:Event):void { this.onBackButton(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ScrollTextScreen.as ================================================ 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.\n\nDonec ultricies nibh non metus volutpat, ac gravida tellus accumsan. Sed in urna quis ante ultrices tristique non non felis. Etiam accumsan molestie felis id auctor. Aliquam suscipit finibus mollis. Etiam euismod odio massa, eu tempus neque consequat ullamcorper. Donec non dignissim metus, ut dictum erat. Sed vestibulum ut sapien vitae laoreet. Integer sollicitudin tellus vitae scelerisque aliquam. Praesent gravida, leo imperdiet vestibulum congue, felis arcu eleifend sem, nec cursus enim massa sit amet risus. Sed cursus pulvinar bibendum.\n\nVivamus nec posuere nunc. Quisque consequat nisi sem, a mattis nisi sagittis ac. Donec efficitur, dui in tincidunt mollis, sapien eros pharetra nibh, quis malesuada mauris velit quis mauris. Nunc eget fermentum tellus. Integer a mi neque. Suspendisse ut cursus mi. Nam tempus interdum felis vel rutrum. Sed quis pharetra mauris, id faucibus quam. Nunc vehicula ullamcorper nisl, non interdum massa scelerisque nec. Proin suscipit rhoncus enim sed tristique.\n\nProin id erat nunc. Sed rutrum tortor in tempor vehicula. Integer et imperdiet odio, sed viverra diam. Pellentesque et commodo lectus, vitae tempus tortor. Quisque purus justo, pharetra ac est molestie, finibus aliquam dui. Vestibulum sodales hendrerit nibh, quis venenatis lorem dictum in. Sed volutpat bibendum eros id vulputate. Curabitur lobortis, tellus a aliquet aliquet, nunc risus aliquet arcu, at ullamcorper ligula tortor vel nulla. Duis sit amet odio pharetra, sodales magna ac, eleifend magna. Curabitur fringilla nec urna vel ultricies.\n\nNunc vel consequat dolor. Quisque nec pretium arcu, faucibus efficitur tortor. Etiam sapien dui, vulputate et libero sollicitudin, consectetur iaculis quam. Nulla eget odio vehicula, vehicula libero sed, tristique lectus. Aliquam in mollis ante, ac molestie risus. Nam faucibus urna at dui varius, sed elementum diam convallis. Nullam ut suscipit diam.\n\nCras tempus faucibus dolor id accumsan. Integer lobortis rutrum vulputate. Nullam porttitor nisi dapibus, tincidunt ante eu, gravida mi. Cras efficitur, magna vitae pulvinar dictum, mauris libero laoreet est, quis volutpat nibh libero a felis. Nunc fringilla dignissim mauris, et aliquam elit molestie ac. Nunc sit amet dignissim nunc. Cras accumsan mauris augue, eget laoreet erat tincidunt in. Phasellus rutrum turpis eget ligula tristique consequat. Maecenas volutpat consectetur purus a ultricies. Sed auctor pulvinar sem, eget fringilla purus consequat sit amet. In hac habitasse platea dictumst. Fusce lobortis vehicula aliquam. Phasellus ornare, est at condimentum consequat, elit ipsum hendrerit est, in rhoncus mauris dui nec quam."; 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderScreen.as ================================================ 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.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.VerticalAlign; 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 function SliderScreen() { super(); } public var settings:SliderSettings; private var _horizontalSlider:Slider; private var _verticalSlider:Slider; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Slider"; var layout:HorizontalLayout = new HorizontalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.padding = 12; layout.gap = 12; this.layout = layout; this._horizontalSlider = new Slider(); this._horizontalSlider.direction = 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.trackInteractionMode = this.settings.trackInteractionMode; this._horizontalSlider.addEventListener(Event.CHANGE, horizontalSlider_changeHandler); this.addChild(this._horizontalSlider); this._verticalSlider = new Slider(); this._verticalSlider.direction = 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.trackInteractionMode = this.settings.trackInteractionMode; 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("horizontal 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); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SliderSettingsScreen.as ================================================ 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.PickerList; import feathers.controls.ToggleSwitch; import feathers.controls.TrackInteractionMode; import feathers.data.ArrayCollection; 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; private var _trackInteractionModePicker: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 = "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._trackInteractionModePicker = new PickerList(); this._trackInteractionModePicker.typicalItem = TrackInteractionMode.TO_VALUE; this._trackInteractionModePicker.dataProvider = new ArrayCollection( [ TrackInteractionMode.TO_VALUE, TrackInteractionMode.BY_PAGE, ]); this._trackInteractionModePicker.selectedItem = this.settings.trackInteractionMode; this._trackInteractionModePicker.addEventListener(Event.CHANGE, trackInteractionModePicker_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 ArrayCollection( [ { label: "liveDragging", accessory: this._liveDraggingToggle }, { label: "step", accessory: this._stepStepper }, { label: "trackInteractionMode", accessory: this._trackInteractionModePicker }, { 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 trackInteractionModePicker_changeHandler(event:Event):void { this.settings.trackInteractionMode = this._trackInteractionModePicker.selectedItem as String; } private function doneButton_triggeredHandler(event:Event):void { this.onBackButton(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/SpinnerListScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.SpinnerList; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.events.FeathersEventType; 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 SpinnerListScreen extends PanelScreen { public function SpinnerListScreen() { super(); } private var _list:SpinnerList; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Spinner List"; this.layout = new AnchorLayout(); this._list = new SpinnerList(); this._list.dataProvider = new ArrayCollection( [ { text: "Aardvark" }, { text: "Alligator" }, { text: "Alpaca" }, { text: "Anteater" }, { text: "Baboon" }, { text: "Bear" }, { text: "Beaver" }, { text: "Canary" }, { text: "Cat" }, { text: "Deer" }, { text: "Dingo" }, { text: "Dog" }, { text: "Dolphin" }, { text: "Donkey" }, { text: "Dragonfly" }, { text: "Duck" }, { text: "Dung Beetle" }, { text: "Eagle" }, { text: "Earthworm" }, { text: "Eel" }, { text: "Elk" }, { text: "Fox" }, ]); this._list.typicalItem = {text: "Item 1000"}; 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); var listLayoutData:AnchorLayoutData = new AnchorLayoutData(); listLayoutData.left = 0; listLayoutData.right = 0; listLayoutData.verticalCenter = 0; this._list.layoutData = listLayoutData; 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 ]; } 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 list_changeHandler(event:Event):void { trace("SpinnerList change:", this._list.selectedIndex); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TabBarScreen.as ================================================ 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.ArrayCollection; 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 ArrayCollection( [ { label: "One" }, { label: "Two" }, { label: "Three" }, { label: "Disabled", isEnabled: false }, ]); 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TextCalloutScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.TextCallout; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.RelativePosition; 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 TextCalloutScreen extends PanelScreen { private static const MESSAGE:String = "Thank you for trying Feathers.\nHappy coding."; public function TextCalloutScreen() { super(); } private var _rightButton:Button; private var _bottomButton:Button; private var _topButton:Button; private var _leftButton:Button; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = " Text Callout"; this.layout = new AnchorLayout(); this._rightButton = new Button(); this._rightButton.label = "Right"; this._rightButton.addEventListener(Event.TRIGGERED, rightButton_triggeredHandler); var rightButtonLayoutData:AnchorLayoutData = new AnchorLayoutData(); rightButtonLayoutData.top = 12; rightButtonLayoutData.left = 12; this._rightButton.layoutData = rightButtonLayoutData; this.addChild(this._rightButton); this._bottomButton = new Button(); this._bottomButton.label = "Bottom"; this._bottomButton.addEventListener(Event.TRIGGERED, bottomButton_triggeredHandler); var bottomButtonLayoutData:AnchorLayoutData = new AnchorLayoutData(); bottomButtonLayoutData.top = 12; bottomButtonLayoutData.right = 12; this._bottomButton.layoutData = bottomButtonLayoutData; this.addChild(this._bottomButton); this._topButton = new Button(); this._topButton.label = "Top"; this._topButton.addEventListener(Event.TRIGGERED, topButton_triggeredHandler); var topButtonLayoutData:AnchorLayoutData = new AnchorLayoutData(); topButtonLayoutData.bottom = 12; topButtonLayoutData.left = 12; this._topButton.layoutData = topButtonLayoutData; this.addChild(this._topButton); this._leftButton = new Button(); this._leftButton.label = "Left"; this._leftButton.addEventListener(Event.TRIGGERED, leftButton_triggeredHandler); var leftButtonLayoutData:AnchorLayoutData = new AnchorLayoutData(); leftButtonLayoutData.bottom = 12; leftButtonLayoutData.right = 12; this._leftButton.layoutData = leftButtonLayoutData; 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; } private function onBackButton():void { this.dispatchEventWith(Event.COMPLETE); } private function backButton_triggeredHandler(event:Event):void { this.onBackButton(); } private function rightButton_triggeredHandler(event:Event):void { TextCallout.show(MESSAGE, this._rightButton, new [RelativePosition.RIGHT]); } private function bottomButton_triggeredHandler(event:Event):void { TextCallout.show(MESSAGE, this._bottomButton, new [RelativePosition.BOTTOM]); } private function topButton_triggeredHandler(event:Event):void { TextCallout.show(MESSAGE, this._topButton, new [RelativePosition.TOP]); } private function leftButton_triggeredHandler(event:Event):void { TextCallout.show(MESSAGE, this._leftButton, new [RelativePosition.LEFT]); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TextInputScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; import feathers.controls.TextArea; import feathers.controls.TextInput; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; 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 function TextInputScreen() { } private var _input:TextInput; private var _disabledInput:TextInput; private var _passwordInput:TextInput; private var _errorInput:TextInput; private var _notEditableInput:TextInput; private var _searchInput:TextInput; private var _textArea:TextArea; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Text Input"; var verticalLayout:VerticalLayout = new VerticalLayout(); verticalLayout.horizontalAlign = HorizontalAlign.CENTER; verticalLayout.verticalAlign = VerticalAlign.TOP; verticalLayout.padding = 12; verticalLayout.gap = 8; this.layout = verticalLayout; this.verticalScrollPolicy = ScrollPolicy.ON; 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._errorInput = new TextInput(); this._errorInput.prompt = "Error Input"; this._errorInput.errorString = "Oh, no! It's an error!"; this.addChild(this._errorInput); this._notEditableInput = new TextInput(); this._notEditableInput.text = "Not Editable"; this._notEditableInput.isEditable = false; this.addChild(this._notEditableInput); //note: using TextArea on mobile generally isn't recommended. //consider TextInput with a multiline StageTextTextEditor instead. this._textArea = new TextArea(); this.addChild(this._textArea); 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(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ToastScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Alert; import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.data.ArrayCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import starling.events.Event; import feathers.system.DeviceCapabilities; import starling.core.Starling; import starling.display.DisplayObject; import feathers.controls.Toast; import feathers.controls.ButtonGroup; public class ToastScreen extends PanelScreen { public function ToastScreen() { super(); } private var _showToastButtons:ButtonGroup; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Toast"; this.layout = new AnchorLayout(); this._showToastButtons = new ButtonGroup(); this._showToastButtons.dataProvider = new ArrayCollection( [ { label: "Show Toast with Message", triggered: showMessageButton_triggeredHandler }, { label: "Show Toast with Actions", triggered: showActionsButton_triggeredHandler }, ]) var buttonGroupLayoutData:AnchorLayoutData = new AnchorLayoutData(); buttonGroupLayoutData.horizontalCenter = 0; buttonGroupLayoutData.verticalCenter = 0; this._showToastButtons.layoutData = buttonGroupLayoutData; this.addChild(this._showToastButtons); 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 showMessageButton_triggeredHandler(event:Event):void { Toast.showMessage("Hi, there!"); } private function showActionsButton_triggeredHandler(event:Event):void { Toast.showMessageWithActions("I have an action", new ArrayCollection( [ { label: "Neat!" } ])); } private function alert_closeHandler(event:Event, data:Object):void { if(data) { trace("alert closed with item:", data.label); } else { trace("alert closed without item"); } } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/ToggleSwitchScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ToggleSwitch; import feathers.layout.HorizontalAlign; import feathers.layout.TiledRowsLayout; import feathers.layout.VerticalAlign; 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 ToggleSwitchScreen extends PanelScreen { public function ToggleSwitchScreen() { super(); } private var _toggle:ToggleSwitch; private var _selected:ToggleSwitch; private var _disabled:ToggleSwitch; private var _selectedDisabled:ToggleSwitch; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Toggle Switch"; var layout:TiledRowsLayout = new TiledRowsLayout(); layout.requestedColumnCount = 2; layout.useSquareTiles = false; layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.TOP; layout.tileHorizontalAlign = HorizontalAlign.CENTER; layout.tileVerticalAlign = VerticalAlign.TOP; layout.padding = 12; layout.horizontalGap = 12; layout.verticalGap = 44; this.layout = layout; this._toggle = new ToggleSwitch(); this._toggle.addEventListener(Event.CHANGE, toggleSwitch_changeHandler); this.addChild(this._toggle); this._selected = new ToggleSwitch(); this._selected.isSelected = true; this.addChild(this._selected); this._disabled = new ToggleSwitch(); this._disabled.isEnabled = false; this.addChild(this._disabled); this._selectedDisabled = new ToggleSwitch(); this._selectedDisabled.isSelected = true; this._selectedDisabled.isEnabled = false; this.addChild(this._selectedDisabled); 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 toggleSwitch_changeHandler(event:Event):void { trace("toggle switch changed:", this._toggle.isSelected); } private function backButton_triggeredHandler(event:Event):void { this.onBackButton(); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/TreeScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.Tree; import feathers.controls.renderers.DefaultTreeItemRenderer; import feathers.controls.renderers.ITreeItemRenderer; import feathers.data.ArrayHierarchicalCollection; import feathers.events.FeathersEventType; 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 TreeScreen extends PanelScreen { public function TreeScreen() { super(); } private var _tree:Tree; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Tree"; this.layout = new AnchorLayout(); var data:Array = [ { text: "Node 1", children: [ { text: "Node 1A", children: [ { text: "Node 1A-I" }, { text: "Node 1A-II" }, { text: "Node 1A-III" }, { text: "Node 1A-IV" }, ] }, { text: "Node 1B" }, { text: "Node 1C" }, ] }, { text: "Node 2", children: [ { text: "Node 2A" }, { text: "Node 2B" }, { text: "Node 2C" }, ] }, { text: "Node 3" }, { text: "Node 4", children: [ { text: "Node 4A" }, { text: "Node 4B" }, { text: "Node 4C" }, { text: "Node 4D" }, { text: "Node 4E" }, ] } ]; this._tree = new Tree(); this._tree.dataProvider = new ArrayHierarchicalCollection(data); this._tree.typicalItem = { text: "Item 1000" }; //optimization: since this tree fills the entire screen, there's no //need for clipping. clipping should not be disabled if there's a //chance that item renderers could be visible if they appear outside //the tree's bounds this._tree.clipContent = false; //optimization: when the background is covered by all item //renderers, don't render it this._tree.autoHideBackground = true; this._tree.itemRendererFactory = function():ITreeItemRenderer { var renderer:DefaultTreeItemRenderer = new DefaultTreeItemRenderer(); renderer.labelField = "text"; return renderer; }; this._tree.addEventListener(Event.CHANGE, tree_changeHandler); this._tree.layoutData = new AnchorLayoutData(0, 0, 0, 0); this.addChildAt(this._tree, 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 ]; } return header; } private function onBackButton():void { this.dispatchEventWith(Event.COMPLETE); } private function transitionInCompleteHandler(event:Event):void { this._tree.revealScrollBars(); } private function backButton_triggeredHandler(event:Event):void { this.onBackButton(); } private function tree_changeHandler(event:Event):void { trace("Tree change:", this._tree.dataProvider.getItemLocation(this._tree.selectedItem)); } } } ================================================ FILE: examples/ComponentsExplorer/source/feathers/examples/componentsExplorer/screens/WebViewScreen.as ================================================ package feathers.examples.componentsExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.LayoutGroup; import feathers.controls.PanelScreen; import feathers.controls.TextInput; import feathers.controls.WebView; import feathers.events.FeathersEventType; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalLayoutData; 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 WebViewScreen extends PanelScreen { public function WebViewScreen() { super(); } private var _browser:WebView; private var _locationInput:TextInput; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Web View"; 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._browser = new WebView(); this._browser.layoutData = new AnchorLayoutData(0, 0, 0, 0); this._browser.addEventListener(FeathersEventType.LOCATION_CHANGE, webView_locationChangeHandler); this.addChild(this._browser); this.headerFactory = this.customHeaderFactory; this.footerFactory = this.customFooterFactory; //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; } //with skipUnchangedFrames, we need to call setRequiresRedraw() //every frame this.addEventListener(Event.ENTER_FRAME, enterFrameHandler); } 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 customFooterFactory():LayoutGroup { var footer:LayoutGroup = new LayoutGroup(); footer.styleNameList.add(LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR); this._locationInput = new TextInput(); this._locationInput.prompt = "Enter a website address"; this._locationInput.layoutData = new HorizontalLayoutData(100); this._locationInput.addEventListener(FeathersEventType.ENTER, locationInput_enterHandler); footer.addChild(this._locationInput); var goButton:Button = new Button(); goButton.label = "Go"; goButton.addEventListener(Event.TRIGGERED, goButton_triggeredHandler); footer.addChild(goButton); return footer; } private function loadLocation():void { if(this._locationInput.text.length == 0) { return; } this._locationInput.clearFocus(); var url:String = this._locationInput.text; //make sure that there's a protocol. otherwise, AIR will add app:/, //which probably isn't what you want. if(!url.match(/^\w+:\//)) { url = "http://" + url; } url = encodeURI(url); this._browser.loadURL(url); } private function onBackButton():void { this.dispatchEventWith(Event.COMPLETE); } private function enterFrameHandler(event:Event):void { this._browser.setRequiresRedraw(); } private function backButton_triggeredHandler(event:Event):void { this.onBackButton(); } private function webView_locationChangeHandler(event:Event):void { this._locationInput.text = this._browser.location; } private function locationInput_enterHandler(event:Event):void { this.loadLocation(); } private function goButton_triggeredHandler(event:Event):void { this.loadLocation(); } } } ================================================ FILE: examples/DragAndDrop/README.md ================================================ # 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 Framework and Feathers, this example project requires the `MetalWorksDesktopTheme` example theme. You can find the SWC file for this theme at the following location in the Feathers release build: themes/MetalWorksDesktopTheme/swc/MetalWorksDesktopTheme.swc ## Web Demo View the [Drag and Drop Example](http://feathersui.com/examples/drag-and-drop/) in your web browser. ================================================ FILE: examples/DragAndDrop/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksDesktopTheme/source output.path = ${basedir}/output swf.version = 30 ================================================ FILE: examples/DragAndDrop/build.xml ================================================ ================================================ FILE: examples/DragAndDrop/source/DragAndDrop.as ================================================ 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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = 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) {} } private function stage_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/DragAndDrop/source/feathers/examples/dragDrop/DragSource.as ================================================ 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 _touchID:int = -1; private var _draggedObject:DisplayObject; private var _dragFormat:String; override protected function initialize():void { this.backgroundSkin = new Quad(1, 1, 0x36322e); } 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.backgroundSkin) { 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 } } } } ================================================ FILE: examples/DragAndDrop/source/feathers/examples/dragDrop/DropTarget.as ================================================ 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 _dragFormat:String; private var _backgroundQuad:Quad; override protected function initialize():void { this._backgroundQuad = new Quad(1, 1, DEFAULT_COLOR); this.backgroundSkin = this._backgroundQuad; } private function dragEnterHandler(event:DragDropEvent, dragData:DragData):void { if(!dragData.hasDataForFormat(this._dragFormat)) { return; } DragDropManager.acceptDrag(this); this._backgroundQuad.color = HOVER_COLOR; } private function dragExitHandler(event:DragDropEvent, dragData:DragData):void { this._backgroundQuad.color = DEFAULT_COLOR; } private function dragDropHandler(event:DragDropEvent, dragData:DragData):void { var droppedObject:DisplayObject = DisplayObject(dragData.getDataForFormat(this._dragFormat)) droppedObject.x = Math.min(Math.max(event.localX - droppedObject.width / 2, 0), this.actualWidth - droppedObject.width); //keep within the bounds of the target droppedObject.y = Math.min(Math.max(event.localY - droppedObject.height / 2, 0), this.actualHeight - droppedObject.height); //keep within the bounds of the target this.addChild(droppedObject); this._backgroundQuad.color = DEFAULT_COLOR; } } } ================================================ FILE: examples/DragAndDrop/source/feathers/examples/dragDrop/Main.as ================================================ 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() { //set up the theme right away! new MetalWorksDesktopTheme(); 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 { 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(); } } } ================================================ FILE: examples/DrawersExplorer/README.md ================================================ # 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 Framework 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. ================================================ FILE: examples/DrawersExplorer/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-full-screen swf.version = 30 ================================================ FILE: examples/DrawersExplorer/build.xml ================================================ ================================================ FILE: examples/DrawersExplorer/source/DrawersExplorer-app.xml ================================================ com.feathersui.examples.DrawersExplorer Drawers Drawers 4.2.0 Drawers Explorer example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC DrawersExplorer.swf true true true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon ]]> high ================================================ FILE: examples/DrawersExplorer/source/DrawersExplorer.as ================================================ package { import feathers.examples.drawersExplorer.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/DrawersExplorer/source/DrawersExplorerWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.drawersExplorer.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/DrawersExplorer/source/feathers/examples/drawersExplorer/Main.as ================================================ package feathers.examples.drawersExplorer { import feathers.controls.DragGesture; import feathers.controls.Drawers; import feathers.examples.drawersExplorer.skins.DrawersExplorerTheme; import feathers.examples.drawersExplorer.views.ContentView; import feathers.examples.drawersExplorer.views.DrawerView; import feathers.layout.Orientation; import starling.display.Sprite; import starling.events.Event; public class Main extends Sprite { public function Main() { //set up the theme right away! new DrawersExplorerTheme(); 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 { 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 = DragGesture.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; this._drawers.content.addEventListener(ContentView.OPEN_MODE_CHANGE, contentView_openDrawerChangeHandler); 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 = Orientation.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 = Orientation.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 = Orientation.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 = Orientation.NONE; this.addChild(this._drawers); } private function drawer_dockNoneHandler(event:Event):void { var drawer:DrawerView = DrawerView(event.currentTarget); this.changeDockMode(drawer, Orientation.NONE); } private function drawer_dockBothHandler(event:Event):void { var drawer:DrawerView = DrawerView(event.currentTarget); this.changeDockMode(drawer, Orientation.BOTH); } private function contentView_openDrawerChangeHandler(event:Event):void { var content:ContentView = ContentView(event.currentTarget); this._drawers.openMode = content.openMode; } } } ================================================ FILE: examples/DrawersExplorer/source/feathers/examples/drawersExplorer/skins/DrawersExplorerTheme.as ================================================ package feathers.examples.drawersExplorer.skins { import feathers.examples.drawersExplorer.views.ContentView; import feathers.examples.drawersExplorer.views.DrawerView; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.VerticalAlign; 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 { //don't forget to set styles from the super class, if required this.setScrollerStyles(view); var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.padding = this.gutterSize; layout.gap = this.gutterSize; view.layout = layout; } protected function setLeftAndRightDrawerViewStyles(view:DrawerView):void { //don't forget to set styles from the super class, if required this.setScrollerStyles(view); view.backgroundSkin = new Quad(10, 10, LIST_BACKGROUND_COLOR); var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.padding = this.smallGutterSize; layout.gap = this.smallGutterSize; view.layout = layout; } protected function setTopAndBottomDrawerViewStyles(view:DrawerView):void { //don't forget to set styles from the super class, if required this.setScrollerStyles(view); view.backgroundSkin = new Quad(10, 10, GROUPED_LIST_HEADER_BACKGROUND_COLOR); var layout:HorizontalLayout = new HorizontalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.padding = this.smallGutterSize; layout.gap = this.smallGutterSize; view.layout = layout; } } } ================================================ FILE: examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/ContentView.as ================================================ package feathers.examples.drawersExplorer.views { import feathers.controls.Button; import feathers.controls.List; import feathers.controls.Panel; import feathers.controls.PickerList; import feathers.controls.ScrollContainer; import feathers.data.ArrayCollection; import feathers.data.ListCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.RelativeDepth; import feathers.layout.VerticalLayout; 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 static const OPEN_MODE_CHANGE:String = "openModeChange"; public function ContentView() { } private var _topButton:Button; private var _rightButton:Button; private var _bottomButton:Button; private var _leftButton:Button; private var _openModePicker:PickerList; override protected function get defaultStyleProvider():IStyleProvider { return ContentView.globalStyleProvider; } private var _openMode:String = RelativeDepth.BELOW; public function get openMode():String { return this._openMode; } override protected function initialize():void { var openControlsPanel:Panel = new Panel(); openControlsPanel.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; var optionsPanel:Panel = new Panel(); optionsPanel.title = "Options"; optionsPanel.layout = new VerticalLayout(); this.addChild(optionsPanel); this._openModePicker = new PickerList(); this._openModePicker.dataProvider = new ArrayCollection( [ { label: "Below", data: RelativeDepth.BELOW }, { label: "Above", data: RelativeDepth.ABOVE }, ]); this._openModePicker.addEventListener(Event.CHANGE, openModePicker_changeHandler); var optionsList:List = new List(); optionsList.dataProvider = new ArrayCollection( [ { label: "Open Mode", accessory: this._openModePicker }, ]); optionsPanel.addChild(optionsList); } 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); } private function openModePicker_changeHandler(event:Event):void { this._openMode = this._openModePicker.selectedItem.data as String; this.dispatchEventWith(OPEN_MODE_CHANGE); } } } ================================================ FILE: examples/DrawersExplorer/source/feathers/examples/drawersExplorer/views/DrawerView.as ================================================ 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); } } } } ================================================ FILE: examples/Gallery/README.md ================================================ # 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 create lists with `SlideShowLayout` and `HorizontalLayout` with custom item renderers. ## Requirements In addition to Starling Framework 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' ================================================ FILE: examples/Gallery/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/Gallery/build.xml ================================================ ================================================ FILE: examples/Gallery/source/Gallery-app.xml ================================================ com.feathersui.examples.Gallery Gallery Gallery 4.2.0 Gallery example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC Gallery.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/Gallery/source/Gallery.as ================================================ package { import feathers.examples.gallery.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.simulateMultitouch = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/Gallery/source/feathers/examples/gallery/Main.as ================================================ package feathers.examples.gallery { import feathers.controls.DecelerationRate; import feathers.controls.Label; import feathers.controls.LayoutGroup; import feathers.controls.List; import feathers.controls.ScrollBarDisplayMode; import feathers.controls.ScrollPolicy; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.VectorCollection; import feathers.events.FeathersEventType; import feathers.examples.gallery.controls.GalleryItemRenderer; import feathers.examples.gallery.controls.ThumbItemRenderer; import feathers.examples.gallery.data.GalleryItem; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.SlideShowLayout; import feathers.layout.VerticalAlign; import feathers.themes.MetalWorksMobileTheme; import feathers.utils.textures.TextureCache; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.net.URLLoader; import flash.net.URLRequest; import starling.animation.Transitions; import starling.animation.Tween; import starling.core.Starling; import starling.events.Event; public class Main extends LayoutGroup { 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() { //set up the theme right away! //this is an *extended* version of MetalWorksMobileTheme new MetalWorksMobileTheme(); super(); } protected var fullSizeList:List; protected var thumbnailList:List; protected var message:Label; protected var apiLoader:URLLoader; protected var thumbnailTextureCache:TextureCache; override public function dispose():void { if(this.thumbnailTextureCache) { this.thumbnailTextureCache.dispose(); this.thumbnailTextureCache = null; } super.dispose(); } override protected function initialize():void { //don't forget to call super.initialize() when you override it! super.initialize(); this.layout = new AnchorLayout(); //keep some thumbnails in memory so that they don't need to be //reloaded from the web this.thumbnailTextureCache = new TextureCache(30); 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)); //the thumbnail list is positioned on the bottom edge of the app //and fills the entire width var thumbnailListLayoutData:AnchorLayoutData = new AnchorLayoutData(); thumbnailListLayoutData.left = 0; thumbnailListLayoutData.right = 0; thumbnailListLayoutData.bottom = 0; var thumbnailListLayout:HorizontalLayout = new HorizontalLayout(); thumbnailListLayout.verticalAlign = VerticalAlign.JUSTIFY; thumbnailListLayout.hasVariableItemDimensions = true; this.thumbnailList = new List(); this.thumbnailList.layout = thumbnailListLayout; //make sure that we have elastic edges horizontally this.thumbnailList.horizontalScrollPolicy = ScrollPolicy.ON; //we're not displaying scroll bars this.thumbnailList.scrollBarDisplayMode = ScrollBarDisplayMode.NONE; //make a swipe scroll a shorter distance this.thumbnailList.decelerationRate = DecelerationRate.FAST; this.thumbnailList.itemRendererFactory = thumbnailItemRendererFactory; this.thumbnailList.addEventListener(starling.events.Event.CHANGE, thumbnailList_changeHandler); this.thumbnailList.height = 100; this.thumbnailList.layoutData = thumbnailListLayoutData; this.addChild(this.thumbnailList); //the full size list fills the remaining space above the thumbnails var fullSizeListLayoutData:AnchorLayoutData = new AnchorLayoutData(0, 0, 0, 0); fullSizeListLayoutData.bottomAnchorDisplayObject = this.thumbnailList; //show a single item per page var fullSizeListLayout:SlideShowLayout = new SlideShowLayout(); fullSizeListLayout.horizontalAlign = HorizontalAlign.JUSTIFY; fullSizeListLayout.verticalAlign = VerticalAlign.JUSTIFY; //load the previous and next items so that they are already visible //if images use a lot of memory, this might not be possible for //some galleries! fullSizeListLayout.minimumItemCount = 3; this.fullSizeList = new List(); //snap to the nearest page when scrolling this.fullSizeList.snapToPages = true; //there is nothing to select in this list this.fullSizeList.isSelectable = false; //no need to display scroll bars in this list this.fullSizeList.scrollBarDisplayMode = ScrollBarDisplayMode.NONE; //make sure that we have elastic edges horizontally this.fullSizeList.horizontalScrollPolicy = ScrollPolicy.ON; this.fullSizeList.layout = fullSizeListLayout; this.fullSizeList.layoutData = fullSizeListLayoutData; this.fullSizeList.itemRendererFactory = fullSizeItemRendererFactory; this.addChild(this.fullSizeList); //display at the center of the list of full size images var messageLayoutData:AnchorLayoutData = new AnchorLayoutData(); messageLayoutData.horizontalCenter = 0; messageLayoutData.verticalCenter = 0; messageLayoutData.verticalCenterAnchorDisplayObject = this.fullSizeList; this.message = new Label(); this.message.text = "Loading..."; this.message.layoutData = messageLayoutData; this.addChild(this.message); } protected function fullSizeItemRendererFactory():IListItemRenderer { return new GalleryItemRenderer(); } protected function thumbnailItemRendererFactory():IListItemRenderer { var itemRenderer:ThumbItemRenderer = new ThumbItemRenderer(); //cache the textures so that they don't need to be reloaded from URLs itemRenderer.textureCache = this.thumbnailTextureCache; //limit how large these item renderers can be itemRenderer.maxWidth = 100; itemRenderer.maxHeight = 100; return itemRenderer; } protected function thumbnailList_changeHandler(event:starling.events.Event):void { var item:GalleryItem = GalleryItem(this.thumbnailList.selectedItem); if(!item) { return; } this.fullSizeList.scrollToDisplayIndex(this.thumbnailList.selectedIndex, 0.5); } 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."; 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 = ""; var collection:VectorCollection = new VectorCollection(items); this.thumbnailList.dataProvider = collection; this.fullSizeList.dataProvider = collection; } protected function apiLoader_errorListener(event:flash.events.Event):void { this.message.text = "Error loading images."; } } } ================================================ FILE: examples/Gallery/source/feathers/examples/gallery/controls/GalleryItemRenderer.as ================================================ package feathers.examples.gallery.controls { import feathers.controls.ImageLoader; import feathers.controls.List; import feathers.controls.ScrollBarDisplayMode; import feathers.controls.ScrollContainer; import feathers.controls.ScrollPolicy; import feathers.controls.renderers.IListItemRenderer; import feathers.core.FeathersControl; import feathers.events.FeathersEventType; import feathers.examples.gallery.data.GalleryItem; import feathers.examples.gallery.layout.GalleryItemRendererLayout; import feathers.layout.ILayout; import feathers.utils.display.calculateScaleRatioToFit; import feathers.utils.touch.TapToSelect; import feathers.utils.touch.TouchSheet; import flash.geom.Point; import flash.utils.Dictionary; import starling.animation.Transitions; import starling.animation.Tween; import starling.core.Starling; import starling.display.DisplayObject; import starling.events.Event; import starling.events.Touch; import starling.events.TouchEvent; import starling.events.TouchPhase; /** * A list item renderer that displays an image that may be zoomed. */ public class GalleryItemRenderer extends ScrollContainer implements IListItemRenderer { /** * Constructor. */ public function GalleryItemRenderer() { super(); //the default layout for a scroll container doesn't work well when //TouchSheet gestures move it into negative coordinates. this.layout = new GalleryItemRendererLayout(); //when we reach the edge, we want to stop without elasticity this.hasElasticEdges = false; } /** * @private */ protected var touchSheet:TouchSheet = null; /** * @private */ protected var image:ImageLoader = null; /** * @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 */ private var _factoryID:String = null; /** * @inheritDoc */ public function get factoryID():String { return this._factoryID; } /** * @private */ public function set factoryID(value:String):void { this._factoryID = value; } /** * @private */ protected var _owner:List = null; /** * @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 !== null) { this._owner.removeEventListener(FeathersEventType.SCROLL_COMPLETE, owner_scrollCompleteHandler); } this._owner = value; if(this._owner !== null) { this._owner.addEventListener(FeathersEventType.SCROLL_COMPLETE, owner_scrollCompleteHandler); } this.invalidate(INVALIDATION_FLAG_DATA); } /** * @private */ private var _data:GalleryItem = null; /** * @inheritDoc */ public function get data():Object { return this._data; } /** * @private */ public function set data(value:Object):void { if(this._data == value) { return; } 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 * If the scale value is less than this after a zoom gesture ends, the * scale will be animated back to this value. The default scale may be * updated when a new texture is loaded. */ protected var _defaultScale:Number = 1; /** * @private */ protected var _gestureCompleteTween:Tween = null; /** * @private */ override public function hitTest(localPoint:Point):DisplayObject { var target:DisplayObject = super.hitTest(localPoint); if(target === this) { //the TouchSheet may not fill the entire width and height of //the item renderer, but we want the gestures to work from //anywhere within the item renderer's bounds. return this.touchSheet; } return target; } /** * @private */ override protected function initialize():void { super.initialize(); this.image = new ImageLoader(); this.image.addEventListener(Event.COMPLETE, image_completeHandler); this.image.addEventListener(FeathersEventType.ERROR, image_errorHandler); //this is a custom version of TouchSheet designed to work better //with Feathers scrolling containers this.touchSheet = new TouchSheet(this.image); //you can disable certain features of this TouchSheet this.touchSheet.zoomEnabled = true; this.touchSheet.rotateEnabled = false; this.touchSheet.moveEnabled = false; //and events are dispatched when any of the gestures are performed this.touchSheet.addEventListener(TouchSheet.MOVE, touchSheet_gestureHandler); this.touchSheet.addEventListener(TouchSheet.ROTATE, touchSheet_gestureHandler); this.touchSheet.addEventListener(TouchSheet.ZOOM, touchSheet_gestureHandler); //on TouchPhase.ENDED, any gestures performed are complete this.touchSheet.addEventListener(TouchEvent.TOUCH, touchSheet_touchHandler); this.addChild(this.touchSheet); } /** * @private */ override protected function draw():void { var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); if(dataInvalid) { if(this._data !== null) { if(this.image.source !== this._data.url) { //hide until the image finishes loading this.touchSheet.visible = false; } this.image.source = this._data.url; } else { this.image.source = null; } //stop any active animations because it's a new image if(this._gestureCompleteTween !== null) { this.stage.starling.juggler.remove(this._gestureCompleteTween); this._gestureCompleteTween = null; } //reset all of the transformations because it's a new image this._defaultScale = 1; this.resetTransformation(); } super.draw(); } /** * @private */ protected function resetTransformation():void { this.touchSheet.rotation = 0; this.touchSheet.scale = this._defaultScale; this.touchSheet.pivotX = 0; this.touchSheet.pivotY = 0; this.touchSheet.x = 0; this.touchSheet.y = 0; } /** * @private */ protected function image_completeHandler(event:Event):void { //when an image first loads, we want it to fill the width and height //of the item renderer, without being larger than the item renderer this._defaultScale = calculateScaleRatioToFit( this.image.originalSourceWidth, this.image.originalSourceHeight, this.viewPort.visibleWidth, this.viewPort.visibleHeight); if(this._defaultScale > 1) { //however, we only want to make large images smaller. small //images should not be made larger because they'll get blurry. //the user can zoom in, if desired. this._defaultScale = 1; } this.touchSheet.scale = this._defaultScale; this.touchSheet.visible = true; } /** * @private */ protected function image_errorHandler(event:Event):void { this.invalidate(INVALIDATION_FLAG_SIZE); } /** * @private */ protected function touchSheet_touchHandler(event:TouchEvent):void { //the current gesture is complete on TouchPhase.ENDED var touch:Touch = event.getTouch(this.touchSheet, TouchPhase.ENDED); if(touch === null) { return; } //if the scale is smaller than the default, animate it back var targetScale:Number = this.touchSheet.scale; if(targetScale < this._defaultScale) { targetScale = this._defaultScale; } if(this.touchSheet.scale !== targetScale) { this._gestureCompleteTween = new Tween(this.touchSheet, 0.15, Transitions.EASE_OUT); this._gestureCompleteTween.scaleTo(targetScale); this._gestureCompleteTween.onComplete = this.gestureCompleteTween_onComplete; this.stage.starling.juggler.add(this._gestureCompleteTween); } } /** * @private */ protected function touchSheet_gestureHandler(event:Event):void { //if the animation from the previous gesture is still active, stop //it immediately when a new gesture starts if(this._gestureCompleteTween !== null) { this.stage.starling.juggler.remove(this._gestureCompleteTween); this._gestureCompleteTween = null; } } /** * @private */ protected function gestureCompleteTween_onComplete():void { this._gestureCompleteTween = null; } /** * @private */ protected function owner_scrollCompleteHandler(event:Event):void { if(this._owner.horizontalPageIndex === this._index) { return; } this.resetTransformation(); } } } ================================================ FILE: examples/Gallery/source/feathers/examples/gallery/controls/ThumbItemRenderer.as ================================================ package feathers.examples.gallery.controls { import feathers.controls.ImageLoader; import feathers.controls.List; import feathers.controls.renderers.IListItemRenderer; import feathers.core.FeathersControl; import feathers.events.FeathersEventType; import feathers.examples.gallery.data.GalleryItem; import feathers.utils.textures.TextureCache; import feathers.utils.touch.TapToSelect; import flash.geom.Point; import flash.utils.Dictionary; import starling.animation.Transitions; import starling.animation.Tween; import starling.core.Starling; import starling.events.Event; /** * Renders a simple thumbnail image with animation to fade in when it * completes loading. */ public class ThumbItemRenderer extends FeathersControl implements IListItemRenderer { /** * @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 ThumbItemRenderer() { //optimization: this item renderer doesn't have interactive children this.isQuickHitAreaEnabled = true; } /** * @private */ protected var image:ImageLoader; /** * @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 */ private var _factoryID:String; /** * @inheritDoc */ public function get factoryID():String { return this._factoryID; } /** * @private */ public function set factoryID(value:String):void { this._factoryID = value; } /** * @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 _tapToSelect:TapToSelect; /** * @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._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 */ private var _textureCache:TextureCache; /** * @inheritDoc */ public function get textureCache():TextureCache { return this._textureCache; } /** * @private */ public function set textureCache(value:TextureCache):void { if(this._textureCache == value) { return; } this._textureCache = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ override protected function initialize():void { super.initialize(); 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); this._tapToSelect = new TapToSelect(this); } /** * @private */ override protected function draw():void { var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); this.image.textureCache = this._textureCache; 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; } } this.autoSizeIfNeeded(); this.layoutChildren(); } /** * @private */ protected function autoSizeIfNeeded():Boolean { var needsWidth:Boolean = isNaN(this._explicitWidth); var needsHeight:Boolean = isNaN(this._explicitHeight); var needsMinWidth:Boolean = isNaN(this._explicitMinWidth); var needsMinHeight:Boolean = isNaN(this._explicitMinHeight); if(!needsWidth && !needsHeight && !needsMinWidth && !needsMinHeight) { return false; } //pass all of these values down to the ImageLoader //because they can affect its measured dimensions this.image.width = this._explicitWidth; this.image.height = this._explicitHeight; this.image.minWidth = this._explicitMinWidth; this.image.minHeight = this._explicitMinHeight; this.image.maxWidth = this._explicitMaxWidth; this.image.maxHeight = this._explicitMaxHeight; 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.saveMeasurements(newWidth, newHeight, newWidth, newHeight); } /** * @private */ protected function layoutChildren():void { this.image.width = this.actualWidth; this.image.height = this.actualHeight; this.image.validate(); } /** * @private */ protected function fadeTween_onComplete():void { this.fadeTween = null; } /** * @private */ protected function owner_scrollStartHandler(event:Event):void { 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); } } } ================================================ FILE: examples/Gallery/source/feathers/examples/gallery/data/GalleryItem.as ================================================ package feathers.examples.gallery.data { 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; } } ================================================ FILE: examples/Gallery/source/feathers/examples/gallery/layout/GalleryItemRendererLayout.as ================================================ package feathers.examples.gallery.layout { import feathers.layout.ILayout; import feathers.layout.LayoutBoundsResult; import feathers.layout.ViewPortBounds; import flash.errors.IllegalOperationError; import flash.geom.Point; import flash.geom.Rectangle; import starling.display.DisplayObject; import starling.events.EventDispatcher; import starling.utils.Pool; public class GalleryItemRendererLayout extends EventDispatcher implements ILayout { public function GalleryItemRendererLayout() { super(); } public function get requiresLayoutOnScroll():Boolean { return false; } public function layout(items:Vector., viewPortBounds:ViewPortBounds = null, result:LayoutBoundsResult = null):LayoutBoundsResult { var itemCount:int = items.length; if(itemCount > 1) { throw new IllegalOperationError("GalleryItemLayout may not have more than one item."); } if(!result) { result = new LayoutBoundsResult(); } var minX:Number = Number.POSITIVE_INFINITY; var minY:Number = Number.POSITIVE_INFINITY; var maxX:Number = Number.NEGATIVE_INFINITY; var maxY:Number = Number.NEGATIVE_INFINITY; if(itemCount > 0) { var item:DisplayObject = items[0]; var itemBounds:Rectangle = item.getBounds(item.parent, Pool.getRectangle()); if(itemBounds.x < minX) { minX = itemBounds.x; } if(itemBounds.y < minY) { minY = itemBounds.y; } var itemMaxX:Number = itemBounds.x + itemBounds.width; if(itemMaxX > maxX) { maxX = itemMaxX; } var itemMaxY:Number = itemBounds.y + itemBounds.height; if(itemMaxY > maxY) { maxY = itemMaxY; } Pool.putRectangle(itemBounds); } if(minX == Number.POSITIVE_INFINITY) { minX = 0; } if(minY == Number.POSITIVE_INFINITY) { minY = 0; } if(maxX == Number.NEGATIVE_INFINITY) { maxX = 0; } if(maxY == Number.NEGATIVE_INFINITY) { maxY = 0; } var contentX:Number = minX; var contentY:Number = minY; var contentWidth:Number = maxX - minX; var contentHeight:Number = maxY - minY; var viewPortWidth:Number = contentWidth; var viewPortHeight:Number = contentHeight; if(viewPortBounds && viewPortBounds.explicitWidth === viewPortBounds.explicitWidth) { viewPortWidth = viewPortBounds.explicitWidth; } if(viewPortBounds && viewPortBounds.explicitHeight === viewPortBounds.explicitHeight) { viewPortHeight = viewPortBounds.explicitHeight; } if(contentWidth <= viewPortWidth) { contentX -= (viewPortWidth - contentWidth) / 2; contentWidth = viewPortWidth; } if(contentHeight <= viewPortHeight) { contentY -= (viewPortHeight - contentHeight) / 2; contentHeight = viewPortHeight; } result.contentX = contentX; result.contentY = contentY; result.contentWidth = contentWidth; result.contentHeight = contentHeight; result.viewPortWidth = viewPortWidth; result.viewPortHeight = viewPortHeight; return result; } public function calculateNavigationDestination(items:Vector., index:int, keyCode:uint, bounds:LayoutBoundsResult):int { return 0; } public function getScrollPositionForIndex(index:int, items:Vector., x:Number, y:Number, width:Number, height:Number, result:Point = null):Point { if(!result) { return new Point(0, 0); } result.setTo(0, 0); return result; } public function getNearestScrollPositionForIndex(index:int, scrollX:Number, scrollY:Number, items:Vector., x:Number, y:Number, width:Number, height:Number, result:Point = null):Point { return getScrollPositionForIndex(index, items, x, y, width, height, result); } } } ================================================ FILE: examples/Gallery/source/feathers/utils/touch/TouchSheet.as ================================================ package feathers.utils.touch { import feathers.controls.LayoutGroup; import feathers.events.ExclusiveTouch; import flash.geom.Point; import starling.display.DisplayObject; import starling.display.Sprite; import starling.events.Touch; import starling.events.TouchEvent; import starling.events.TouchPhase; import starling.utils.Pool; /** * A modified version of TouchSheet for Feathers. */ public class TouchSheet extends LayoutGroup { public static const MOVE:String = "move"; public static const ZOOM:String = "zoom"; public static const ROTATE:String = "rotate"; public function TouchSheet(contents:DisplayObject=null) { addEventListener(TouchEvent.TOUCH, onTouch); useHandCursor = true; if (contents) { contents.x = int(contents.width / -2); contents.y = int(contents.height / -2); addChild(contents); } } public var moveEnabled:Boolean = true; public var rotateEnabled:Boolean = true; public var zoomEnabled:Boolean = true; public var bringToFrontEnabled:Boolean = true; protected var touchAID:int = -1; protected var touchBID:int = -1; private function onTouch(event:TouchEvent):void { var exclusiveTouch:ExclusiveTouch = ExclusiveTouch.forStage(this.stage); //first check if the existing touches ended if(touchBID != -1) { var touchB:Touch = event.getTouch(this, null, touchBID); if(touchB !== null) { if(touchB.phase === TouchPhase.ENDED) { touchBID = -1; } else { //if the touch has been claimed since we first started //watching it, we can no longer use it var claim:DisplayObject = exclusiveTouch.getClaim(touchBID); if(claim !== null && claim !== this) { touchBID = -1; } } } } //we checeked touch b first because a might be replaced by b if(touchAID != -1) { var touchA:Touch = event.getTouch(this, null, touchAID); if(touchA !== null) { if(touchA.phase === TouchPhase.ENDED) { touchAID = touchBID; touchBID = -1; } else { claim = exclusiveTouch.getClaim(touchAID); if(claim !== null && claim !== this) { touchAID = touchBID; touchBID = -1; } } } } //then, check for new touches, if necessary if(touchAID == -1 || touchBID == -1) { var touches:Vector. = event.getTouches(this, TouchPhase.BEGAN); var touchCount:int = touches.length; for(var i:int = 0; i < touchCount; i++) { var touch:Touch = touches[i]; claim = exclusiveTouch.getClaim(touch.id); if(claim !== null) { //this touch is claimed, so we can't use it continue; } if(touchAID == -1) { touchAID = touch.id; if(this.moveEnabled) { exclusiveTouch.claimTouch(touchAID, this); } } else if(touchBID == -1) { touchBID = touch.id; //if we've found both touches, claim them to stop containers //from scrolling exclusiveTouch.claimTouch(touchAID, this); exclusiveTouch.claimTouch(touchBID, this); } } } //do a multi-touch gesture if we have enough touches if(touchAID != -1 && touchBID != -1) { // two fingers touching -> rotate and scale touchA = event.getTouch(this, null, touchAID); touchB = event.getTouch(this, null, touchBID); if(touchA.phase !== TouchPhase.MOVED && touchB.phase !== TouchPhase.MOVED) { //neither touch moved, so nothing has changed return; } // updated to use stage instead of parent because the // parent might move, but the stage never will. -JT var currentPosA:Point = touchA.getLocation(stage, Pool.getPoint()); var previousPosA:Point = touchA.getPreviousLocation(stage, Pool.getPoint()); var currentPosB:Point = touchB.getLocation(stage, Pool.getPoint()); var previousPosB:Point = touchB.getPreviousLocation(stage, Pool.getPoint()); var currentVector:Point = currentPosA.subtract(currentPosB); var previousVector:Point = previousPosA.subtract(previousPosB); var currentAngle:Number = Math.atan2(currentVector.y, currentVector.x); var previousAngle:Number = Math.atan2(previousVector.y, previousVector.x); var deltaAngle:Number = currentAngle - previousAngle; // update pivot point based on previous center var point:Point = Pool.getPoint( (previousPosA.x + previousPosB.x) * 0.5, (previousPosA.y + previousPosB.y) * 0.5); globalToLocal(point, point); pivotX = point.x; pivotY = point.y; // update location based on the current center point.setTo( (currentPosA.x + currentPosB.x) * 0.5, (currentPosA.y + currentPosB.y) * 0.5); parent.globalToLocal(point, point); x = point.x; y = point.y; Pool.putPoint(point); Pool.putPoint(currentPosA); Pool.putPoint(previousPosA); Pool.putPoint(currentPosB); Pool.putPoint(previousPosB); if (rotateEnabled && deltaAngle != 0) { rotation += deltaAngle; dispatchEventWith(ROTATE); } var sizeDiff:Number = currentVector.length / previousVector.length; if (zoomEnabled && sizeDiff !== 1) { var zoomed:Boolean = false; var newScaleX:Number = scaleX * sizeDiff; if(scaleX !== newScaleX) { scaleX = newScaleX; zoomed = true; } var newScaleY:Number = scaleY * sizeDiff; if(scaleY !== newScaleY) { scaleY = newScaleY; zoomed = true; } if(zoomed) { dispatchEventWith(ZOOM); } } } else if(touchAID != -1) //single touch gesture { touchA = event.getTouch(this, null, touchAID); if (moveEnabled) { // one finger touching -> move // updated to use stage instead of parent because the // parent might move, but the stage won't -JT var delta:Point = touchA.getMovement(stage, Pool.getPoint()); if(delta.length != 0) { x += delta.x; y += delta.y; dispatchEventWith(MOVE); } Pool.putPoint(delta); } } var touchEnded:Touch = event.getTouch(this, TouchPhase.ENDED); if (touchEnded) { if (bringToFrontEnabled && touchEnded.tapCount == 2) { parent.addChild(this); // bring self to front } } } } } ================================================ FILE: examples/HelloWorld/README.md ================================================ # 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 Framework 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. ================================================ FILE: examples/HelloWorld/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/HelloWorld/build.xml ================================================ ================================================ FILE: examples/HelloWorld/source/HelloWorld-app.xml ================================================ com.feathersui.examples.HelloWorld Hello World Hello World 4.2.0 Hello World example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC HelloWorld.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/HelloWorld/source/HelloWorld.as ================================================ package { import feathers.examples.helloWorld.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/HelloWorld/source/HelloWorldWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.helloWorld.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/HelloWorld/source/feathers/examples/helloWorld/Main.as ================================================ package feathers.examples.helloWorld { import feathers.controls.Button; import feathers.controls.TextCallout; 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 { TextCallout.show("Hi, I'm Feathers!\nHave a nice day.", this.button); } } } ================================================ FILE: examples/LayoutExplorer/README.md ================================================ # 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 Framework 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. ================================================ FILE: examples/LayoutExplorer/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/LayoutExplorer/build.xml ================================================ ================================================ FILE: examples/LayoutExplorer/source/LayoutExplorer-app.xml ================================================ com.feathersui.examples.LayoutExplorer Layouts Layouts 4.2.0 Layout Explorer example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC LayoutExplorer.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/LayoutExplorer/source/LayoutExplorer.as ================================================ package { import feathers.examples.layoutExplorer.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/LayoutExplorer/source/LayoutExplorerWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.layoutExplorer.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/Main.as ================================================ package feathers.examples.layoutExplorer { import feathers.controls.Drawers; import feathers.controls.StackScreenNavigator; import feathers.controls.StackScreenNavigatorItem; import feathers.examples.layoutExplorer.data.FlowLayoutSettings; import feathers.examples.layoutExplorer.data.HorizontalLayoutSettings; import feathers.examples.layoutExplorer.data.SlideShowLayoutSettings; import feathers.examples.layoutExplorer.data.TiledColumnsLayoutSettings; import feathers.examples.layoutExplorer.data.TiledRowsLayoutSettings; import feathers.examples.layoutExplorer.data.VerticalLayoutSettings; import feathers.examples.layoutExplorer.data.WaterfallLayoutSettings; import feathers.examples.layoutExplorer.screens.AnchorLayoutScreen; import feathers.examples.layoutExplorer.screens.FlowLayoutScreen; import feathers.examples.layoutExplorer.screens.FlowLayoutSettingsScreen; import feathers.examples.layoutExplorer.screens.HorizontalLayoutScreen; import feathers.examples.layoutExplorer.screens.HorizontalLayoutSettingsScreen; import feathers.examples.layoutExplorer.screens.MainMenuScreen; import feathers.examples.layoutExplorer.screens.SlideShowLayoutScreen; import feathers.examples.layoutExplorer.screens.SlideShowLayoutSettingsScreen; 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.examples.layoutExplorer.screens.WaterfallLayoutScreen; import feathers.examples.layoutExplorer.screens.WaterfallLayoutSettingsScreen; import feathers.layout.Orientation; import feathers.motion.Cover; import feathers.motion.Reveal; import feathers.motion.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 FLOW:String = "flow"; 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 WATERFALL:String = "waterfall"; private static const SLIDE_SHOW:String = "slideShow"; private static const FLOW_SETTINGS:String = "flowSettings"; 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 WATERFALL_SETTINGS:String = "waterfallSettings"; private static const SLIDE_SHOW_SETTINGS:String = "slideShowSettings"; private static const MAIN_MENU_EVENTS:Object = { showAnchor: ANCHOR, showFlow: FLOW, showHorizontal: HORIZONTAL, showVertical: VERTICAL, showTiledRows: TILED_ROWS, showTiledColumns: TILED_COLUMNS, showWaterfall: WATERFALL, showSlideShow: SLIDE_SHOW }; public function Main() { //set up the theme right away! new MetalWorksMobileTheme(); super(); } private var _navigator:StackScreenNavigator; private var _menu:MainMenuScreen; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); 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 flowLayoutSettings:FlowLayoutSettings = new FlowLayoutSettings(); var flowItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FlowLayoutScreen); flowItem.setScreenIDForPushEvent(FlowLayoutScreen.SHOW_SETTINGS, FLOW_SETTINGS); flowItem.addPopEvent(Event.COMPLETE); flowItem.properties.settings = flowLayoutSettings; this._navigator.addScreen(FLOW, flowItem); var flowSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FlowLayoutSettingsScreen); flowSettingsItem.addPopEvent(Event.COMPLETE); flowSettingsItem.properties.settings = flowLayoutSettings; flowSettingsItem.pushTransition = Cover.createCoverUpTransition(); flowSettingsItem.popTransition = Reveal.createRevealDownTransition(); this._navigator.addScreen(FLOW_SETTINGS, flowSettingsItem); 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); var waterfallLayoutSettings:WaterfallLayoutSettings = new WaterfallLayoutSettings(); var waterfallItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(WaterfallLayoutScreen); waterfallItem.setScreenIDForPushEvent(TiledColumnsLayoutScreen.SHOW_SETTINGS, WATERFALL_SETTINGS); waterfallItem.addPopEvent(Event.COMPLETE); waterfallItem.properties.settings = waterfallLayoutSettings; this._navigator.addScreen(WATERFALL, waterfallItem); var waterfallSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(WaterfallLayoutSettingsScreen); waterfallSettingsItem.addPopEvent(Event.COMPLETE); waterfallSettingsItem.properties.settings = waterfallLayoutSettings; waterfallSettingsItem.pushTransition = Cover.createCoverUpTransition(); waterfallSettingsItem.popTransition = Reveal.createRevealDownTransition(); this._navigator.addScreen(WATERFALL_SETTINGS, waterfallSettingsItem); var slideShowSettings:SlideShowLayoutSettings = new SlideShowLayoutSettings(); var slideShowItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(SlideShowLayoutScreen); slideShowItem.setScreenIDForPushEvent(SlideShowLayoutScreen.SHOW_SETTINGS, SLIDE_SHOW_SETTINGS); slideShowItem.addPopEvent(Event.COMPLETE); slideShowItem.properties.settings = slideShowSettings; this._navigator.addScreen(SLIDE_SHOW, slideShowItem); var slideShowSettingsItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(SlideShowLayoutSettingsScreen); slideShowSettingsItem.addPopEvent(Event.COMPLETE); slideShowSettingsItem.properties.settings = slideShowSettings; slideShowSettingsItem.pushTransition = Cover.createCoverUpTransition(); slideShowSettingsItem.popTransition = Reveal.createRevealDownTransition(); this._navigator.addScreen(SLIDE_SHOW_SETTINGS, slideShowSettingsItem); 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 = Orientation.BOTH; } else { var mainMenuItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(MainMenuScreen); for(eventType in MAIN_MENU_EVENTS) { mainMenuItem.setScreenIDForPushEvent(eventType, MAIN_MENU_EVENTS[eventType] as String); } 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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/FlowLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; public class FlowLayoutSettings { public function FlowLayoutSettings() { } public var itemCount:int = 75; public var horizontalAlign:String = HorizontalAlign.LEFT; public var verticalAlign:String = VerticalAlign.TOP; public var rowVerticalAlign:String = VerticalAlign.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; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/HorizontalLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; public class HorizontalLayoutSettings { public function HorizontalLayoutSettings() { } public var itemCount:int = 75; public var horizontalAlign:String = HorizontalAlign.LEFT; public var verticalAlign:String = VerticalAlign.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; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/SlideShowLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; public class SlideShowLayoutSettings { public function SlideShowLayoutSettings() { } public var itemCount:int = 5; public var horizontalAlign:String = HorizontalAlign.CENTER; public var verticalAlign:String = VerticalAlign.MIDDLE; public var paddingTop:Number = 0; public var paddingRight:Number = 0; public var paddingBottom:Number = 0; public var paddingLeft:Number = 0; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledColumnsLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.TiledColumnsLayout; import feathers.layout.VerticalAlign; public class TiledColumnsLayoutSettings { public function TiledColumnsLayoutSettings() { } public var itemCount:int = 75; public var requestedRowCount:int = 0; public var paging:String = Direction.NONE; public var horizontalAlign:String = HorizontalAlign.LEFT; public var verticalAlign:String = VerticalAlign.TOP; public var tileHorizontalAlign:String = HorizontalAlign.LEFT; public var tileVerticalAlign:String = VerticalAlign.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; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/TiledRowsLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.TiledRowsLayout; import feathers.layout.VerticalAlign; public class TiledRowsLayoutSettings { public function TiledRowsLayoutSettings() { } public var paging:String = Direction.NONE; public var itemCount:int = 75; public var requestedColumnCount:int = 0; public var horizontalAlign:String = HorizontalAlign.LEFT; public var verticalAlign:String = VerticalAlign.TOP; public var tileHorizontalAlign:String = HorizontalAlign.LEFT; public var tileVerticalAlign:String = VerticalAlign.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; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/VerticalLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; public class VerticalLayoutSettings { public function VerticalLayoutSettings() { } public var itemCount:int = 75; public var horizontalAlign:String = HorizontalAlign.LEFT; public var verticalAlign:String = VerticalAlign.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; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/data/WaterfallLayoutSettings.as ================================================ package feathers.examples.layoutExplorer.data { import feathers.layout.HorizontalAlign; public class WaterfallLayoutSettings { public function WaterfallLayoutSettings() { } public var itemCount:int = 75; public var requestedColumnCount:int = 0; public var horizontalAlign:String = HorizontalAlign.CENTER; 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; } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/AnchorLayoutScreen.as ================================================ 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(); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/FlowLayoutScreen.as ================================================ 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.FlowLayoutSettings; import feathers.layout.FlowLayout; 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 FlowLayoutScreen extends PanelScreen { public static const SHOW_SETTINGS:String = "showSettings"; public function FlowLayoutScreen() { super(); } public var settings:FlowLayoutSettings; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Flow Layout"; var layout:FlowLayout = new FlowLayout(); 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.rowVerticalAlign = this.settings.rowVerticalAlign; this.layout = layout; 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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/FlowLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.FlowLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import starling.display.DisplayObject; import starling.events.Event; [Event(name="complete",type="starling.events.Event")] public class FlowLayoutSettingsScreen extends PanelScreen { public function FlowLayoutSettingsScreen() { super(); } public var settings:FlowLayoutSettings; private var _list:List; private var _itemCountStepper:NumericStepper; 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 _rowVerticalAlignPicker: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 = "Flow 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 = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, ]); this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); this._rowVerticalAlignPicker = new PickerList(); this._rowVerticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._rowVerticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, ]); this._rowVerticalAlignPicker.selectedItem = this.settings.rowVerticalAlign; this._rowVerticalAlignPicker.addEventListener(Event.CHANGE, rowVerticalAlignPicker_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 ArrayCollection( [ { label: "Item Count", accessory: this._itemCountStepper }, { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, { label: "verticalAlign", accessory: this._verticalAlignPicker }, { label: "rowVerticalAlign", accessory: this._rowVerticalAlignPicker }, { 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 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 rowVerticalAlignPicker_changeHandler(event:Event):void { this.settings.rowVerticalAlign = this._rowVerticalAlignPicker.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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutScreen.as ================================================ package feathers.examples.layoutExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; 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 = ScrollPolicy.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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/HorizontalLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.HorizontalLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; 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 = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, VerticalAlign.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 ArrayCollection( [ { 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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/MainMenuScreen.as ================================================ package feathers.examples.layoutExplorer.screens { import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.data.ListCollection; import feathers.events.FeathersEventType; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.system.DeviceCapabilities; import starling.core.Starling; import starling.events.Event; [Event(name="showAnchor",type="starling.events.Event")] [Event(name="showFlow",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")] [Event(name="showWaterfall",type="starling.events.Event")] public class MainMenuScreen extends PanelScreen { public static const SHOW_ANCHOR:String = "showAnchor"; public static const SHOW_FLOW:String = "showFlow"; 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 static const SHOW_WATERFALL:String = "showWaterfall"; public static const SHOW_SLIDE_SHOW:String = "showSlideShow"; 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 ArrayCollection( [ { text: "Anchor", event: SHOW_ANCHOR }, { text: "Flow", event: SHOW_FLOW }, { text: "Horizontal", event: SHOW_HORIZONTAL }, { text: "Vertical", event: SHOW_VERTICAL }, { text: "Tiled Rows", event: SHOW_TILED_ROWS }, { text: "Tiled Columns", event: SHOW_TILED_COLUMNS }, { text: "Waterfall", event: SHOW_WATERFALL }, { text: "Slide Show", event: SHOW_SLIDE_SHOW }, ]); this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); this._list.verticalScrollPosition = this.savedVerticalScrollPosition; this._list.itemRendererFactory = this.createItemRenderer; 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 createItemRenderer():IListItemRenderer { var isTablet:Boolean = DeviceCapabilities.isTablet(Starling.current.nativeStage); var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); if(!isTablet) { renderer.styleNameList.add(DefaultListItemRenderer.ALTERNATE_STYLE_NAME_DRILL_DOWN); } //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; } 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 }); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/SlideShowLayoutScreen.as ================================================ package feathers.examples.layoutExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.Label; import feathers.controls.PanelScreen; import feathers.events.FeathersEventType; import feathers.examples.layoutExplorer.data.SlideShowLayoutSettings; import feathers.layout.SlideShowLayout; 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 SlideShowLayoutScreen extends PanelScreen { public static const SHOW_SETTINGS:String = "showSettings"; public function SlideShowLayoutScreen() { super(); } public var settings:SlideShowLayoutSettings; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Slide Show Layout"; this.layout = new SlideShowLayout(); //with this layout, you should always snap to pages this.snapToPages = true; var layout:SlideShowLayout = new SlideShowLayout(); 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; var minQuadSize:Number = Math.min(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight) / 2; for(var i:int = 0; i < this.settings.itemCount; i++) { var size:Number = (minQuadSize + minQuadSize * 0.5 * Math.random()); var quad:Quad = new Quad(size, size, 0xff8800); this.addChild(quad); } this.layout = layout; 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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/SlideShowLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.SlideShowLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import starling.display.DisplayObject; import starling.events.Event; [Event(name="complete",type="starling.events.Event")] public class SlideShowLayoutSettingsScreen extends PanelScreen { public function SlideShowLayoutSettingsScreen() { super(); } public var settings:SlideShowLayoutSettings; private var _list:List; private var _itemCountStepper: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 = "Slide Show 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 = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT, HorizontalAlign.JUSTIFY ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, VerticalAlign.JUSTIFY ]); this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_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 ArrayCollection( [ { label: "Item Count", accessory: this._itemCountStepper }, { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, { label: "verticalAlign", accessory: this._verticalAlignPicker }, { 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 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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutScreen.as ================================================ 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.Direction; 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.requestedRowCount = this.settings.requestedRowCount; 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 != Direction.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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledColumnsLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.TiledColumnsLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; 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 _requestedRowCountStepper: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._requestedRowCountStepper = new NumericStepper(); this._requestedRowCountStepper.minimum = 0; //the layout can certainly handle more. this value is arbitrary. this._requestedRowCountStepper.maximum = 10; this._requestedRowCountStepper.step = 1; this._requestedRowCountStepper.value = this.settings.requestedRowCount; this._requestedRowCountStepper.addEventListener(Event.CHANGE, requestedRowCountStepper_changeHandler); this._pagingPicker = new PickerList(); this._pagingPicker.typicalItem = Direction.HORIZONTAL; this._pagingPicker.dataProvider = new VectorCollection(new [ Direction.NONE, Direction.HORIZONTAL, Direction.VERTICAL ]); this._pagingPicker.selectedItem = this.settings.paging; this._pagingPicker.addEventListener(Event.CHANGE, pagingPicker_changeHandler); this._horizontalAlignPicker = new PickerList(); this._horizontalAlignPicker.typicalItem = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM ]); this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); this._tileHorizontalAlignPicker = new PickerList(); this._tileHorizontalAlignPicker.typicalItem = HorizontalAlign.CENTER; this._tileHorizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT, HorizontalAlign.JUSTIFY ]); this._tileHorizontalAlignPicker.selectedItem = this.settings.tileHorizontalAlign; this._tileHorizontalAlignPicker.addEventListener(Event.CHANGE, tileHorizontalAlignPicker_changeHandler); this._tileVerticalAlignPicker = new PickerList(); this._tileVerticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._tileVerticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, VerticalAlign.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 ArrayCollection( [ { label: "Item Count", accessory: this._itemCountStepper }, { label: "Requested Row Count", accessory: this._requestedRowCountStepper }, { 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 requestedRowCountStepper_changeHandler(event:Event):void { this.settings.requestedRowCount = this._requestedRowCountStepper.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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutScreen.as ================================================ 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.Direction; 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.requestedColumnCount = this.settings.requestedColumnCount; 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 != Direction.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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/TiledRowsLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.TiledRowsLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; 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 _requestedColumnCountStepper: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._requestedColumnCountStepper = new NumericStepper(); this._requestedColumnCountStepper.minimum = 0; //the layout can certainly handle more. this value is arbitrary. this._requestedColumnCountStepper.maximum = 10; this._requestedColumnCountStepper.step = 1; this._requestedColumnCountStepper.value = this.settings.requestedColumnCount; this._requestedColumnCountStepper.addEventListener(Event.CHANGE, requestedColumnCountStepper_changeHandler); this._pagingPicker = new PickerList(); this._pagingPicker.typicalItem = Direction.HORIZONTAL; this._pagingPicker.dataProvider = new VectorCollection(new [ Direction.NONE, Direction.HORIZONTAL, Direction.VERTICAL ]); this._pagingPicker.selectedItem = this.settings.paging; this._pagingPicker.addEventListener(Event.CHANGE, pagingPicker_changeHandler); this._horizontalAlignPicker = new PickerList(); this._horizontalAlignPicker.typicalItem = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM ]); this._verticalAlignPicker.selectedItem = this.settings.verticalAlign; this._verticalAlignPicker.addEventListener(Event.CHANGE, verticalAlignPicker_changeHandler); this._tileHorizontalAlignPicker = new PickerList(); this._tileHorizontalAlignPicker.typicalItem = HorizontalAlign.CENTER; this._tileHorizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT, HorizontalAlign.JUSTIFY ]); this._tileHorizontalAlignPicker.selectedItem = this.settings.tileHorizontalAlign; this._tileHorizontalAlignPicker.addEventListener(Event.CHANGE, tileHorizontalAlignPicker_changeHandler); this._tileVerticalAlignPicker = new PickerList(); this._tileVerticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._tileVerticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.BOTTOM, VerticalAlign.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 ArrayCollection( [ { label: "Item Count", accessory: this._itemCountStepper }, { label: "Requested Column Count", accessory: this._requestedColumnCountStepper }, { 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 requestedColumnCountStepper_changeHandler(event:Event):void { this.settings.requestedColumnCount = this._requestedColumnCountStepper.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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutScreen.as ================================================ package feathers.examples.layoutExplorer.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; 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 = ScrollPolicy.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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/VerticalLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.VerticalLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; 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 = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT, HorizontalAlign.JUSTIFY ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_changeHandler); this._verticalAlignPicker = new PickerList(); this._verticalAlignPicker.typicalItem = VerticalAlign.BOTTOM; this._verticalAlignPicker.dataProvider = new VectorCollection(new [ VerticalAlign.TOP, VerticalAlign.MIDDLE, VerticalAlign.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 ArrayCollection( [ { 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; } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/WaterfallLayoutScreen.as ================================================ 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.WaterfallLayoutSettings; import feathers.layout.WaterfallLayout; 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 WaterfallLayoutScreen extends PanelScreen { public static const SHOW_SETTINGS:String = "showSettings"; public function WaterfallLayoutScreen() { super(); } public var settings:WaterfallLayoutSettings; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Waterfall Layout"; var layout:WaterfallLayout = new WaterfallLayout(); layout.requestedColumnCount = this.settings.requestedColumnCount; 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; this.layout = layout; this.snapScrollPositionsToPixels = true; var minQuadSize:Number = Math.round(Math.min(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight) / 5); for(var i:int = 0; i < this.settings.itemCount; i++) { var height:Number = Math.round((minQuadSize + minQuadSize * Math.random())); var quad:Quad = new Quad(minQuadSize, height, 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); } } } ================================================ FILE: examples/LayoutExplorer/source/feathers/examples/layoutExplorer/screens/WaterfallLayoutSettingsScreen.as ================================================ 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.ArrayCollection; import feathers.data.VectorCollection; import feathers.examples.layoutExplorer.data.WaterfallLayoutSettings; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import starling.display.DisplayObject; import starling.events.Event; [Event(name="complete",type="starling.events.Event")] public class WaterfallLayoutSettingsScreen extends PanelScreen { public function WaterfallLayoutSettingsScreen() { super(); } public var settings:WaterfallLayoutSettings; private var _list:List; private var _itemCountStepper:NumericStepper; private var _requestedColumnCountStepper:NumericStepper; 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; 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 = "Waterfall 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._requestedColumnCountStepper = new NumericStepper(); this._requestedColumnCountStepper.minimum = 0; //the layout can certainly handle more. this value is arbitrary. this._requestedColumnCountStepper.maximum = 10; this._requestedColumnCountStepper.step = 1; this._requestedColumnCountStepper.value = this.settings.requestedColumnCount; this._requestedColumnCountStepper.addEventListener(Event.CHANGE, requestedColumnCountStepper_changeHandler); this._horizontalAlignPicker = new PickerList(); this._horizontalAlignPicker.typicalItem = HorizontalAlign.CENTER; this._horizontalAlignPicker.dataProvider = new VectorCollection(new [ HorizontalAlign.LEFT, HorizontalAlign.CENTER, HorizontalAlign.RIGHT ]); this._horizontalAlignPicker.selectedItem = this.settings.horizontalAlign; this._horizontalAlignPicker.addEventListener(Event.CHANGE, horizontalAlignPicker_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 ArrayCollection( [ { label: "Item Count", accessory: this._itemCountStepper }, { label: "Requested Column Count", accessory: this._requestedColumnCountStepper }, { label: "horizontalAlign", accessory: this._horizontalAlignPicker }, { 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 requestedColumnCountStepper_changeHandler(event:Event):void { this.settings.requestedColumnCount = this._requestedColumnCountStepper.value; } private function horizontalAlignPicker_changeHandler(event:Event):void { this.settings.horizontalAlign = this._horizontalAlignPicker.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; } } } ================================================ FILE: examples/Magic8Chat/README.md ================================================ # Feathers Magic 8 Chat Demonstrates how to create a mobile chat app using [Feathers](http://feathersui.com/). ## Requirements In addition to Starling Framework 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 [Magic8Chat example](http://feathersui.com/examples/magic-8-chat/) in your browser. ================================================ FILE: examples/Magic8Chat/assets/images/icons-readme.txt ================================================ Icons by Glyphish - glyphish.com ================================================ FILE: examples/Magic8Chat/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 34 ================================================ FILE: examples/Magic8Chat/build.xml ================================================ ================================================ FILE: examples/Magic8Chat/source/Magic8Chat-app.xml ================================================ com.feathersui.examples.Magic8Chat Magic8Chat Magic8Chat 4.2.0 Magic8Chat example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC Magic8Chat.swf true false true direct true en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/Magic8Chat/source/Magic8Chat.as ================================================ package { import feathers.examples.magic8.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.system.Capabilities; import flash.utils.ByteArray; import starling.core.Starling; [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] public class Magic8Chat extends Sprite { public function Magic8Chat() { 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/Magic8Chat/source/Magic8ChatWeb.as ================================================ 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 Magic8ChatWeb extends MovieClip { public function Magic8ChatWeb() { 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.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.magic8.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/Magic8Chat/source/feathers/examples/magic8/Main.as ================================================ package feathers.examples.magic8 { import feathers.controls.Button; import feathers.controls.LayoutGroup; import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.TextInput; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.controls.text.StageTextTextEditor; import feathers.core.ITextEditor; import feathers.data.ArrayCollection; import feathers.data.ListCollection; import feathers.events.FeathersEventType; import feathers.examples.magic8.data.ChatMessage; import feathers.examples.magic8.themes.Magic8ChatTheme; import feathers.examples.magic8.themes.StyleNames; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayoutData; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; import starling.events.Event; public class Main extends PanelScreen { private static const MESSAGES:Vector. = new [ "It is certain", "It is decidedly so", "Without a doubt", "Yes, definitely", "You may rely on it", "As I see it, yes", "Most likely", "Outlook good", "Yes", "Signs point to yes", "Reply hazy try again", "Ask again later", "Better not tell you now", "Cannot predict now", "Concentrate and ask again", "Don't count on it", "My reply is no", "My sources say no", "Outlook not so good", "Very doubtful", ]; private static const USER_ITEM:String = "user"; private static const EIGHT_BALL_ITEM:String = "8ball"; public function Main() { new Magic8ChatTheme(); super(); this.title = "Magic 8-Ball"; } private var _list:List; private var _input:TextInput; private var _sendButton:Button; override protected function initialize():void { super.initialize(); this.layout = new AnchorLayout(); this._list = new List(); this._list.dataProvider = new ArrayCollection(); this._list.isSelectable = false; this._list.setItemRendererFactoryWithID(USER_ITEM, function():IListItemRenderer { var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); itemRenderer.styleNameList.add(StyleNames.USER_MESSAGE_ITEM_RENDERER); itemRenderer.labelField = "message"; itemRenderer.wordWrap = true; return itemRenderer; }); this._list.setItemRendererFactoryWithID(EIGHT_BALL_ITEM, function():IListItemRenderer { var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); itemRenderer.styleNameList.add(StyleNames.EIGHT_BALL_MESSAGE_ITEM_RENDERER); itemRenderer.labelField = "message"; itemRenderer.wordWrap = true; return itemRenderer; }); this._list.factoryIDFunction = function(item:ChatMessage):String { if(item.type === ChatMessage.TYPE_MAGIC_8BALL) { return EIGHT_BALL_ITEM; } return USER_ITEM; }; var listLayout:VerticalLayout = new VerticalLayout(); listLayout.hasVariableItemDimensions = true; listLayout.horizontalAlign = HorizontalAlign.JUSTIFY; listLayout.verticalAlign = VerticalAlign.BOTTOM; this._list.layout = listLayout; this.addChild(this._list); var controls:LayoutGroup = new LayoutGroup(); controls.styleNameList.add(LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR); this.addChild(controls); this._input = new TextInput(); this._input.prompt = "Ask a yes or no question..."; this._input.layoutData = new HorizontalLayoutData(100); this._input.textEditorFactory = function():ITextEditor { var textEditor:StageTextTextEditor = new StageTextTextEditor(); textEditor.maintainTouchFocus = true; //flash.text.ReturnKeyLabel doesn't exist in Flash Player, so //we can't use the constant here. //we use ReturnKeyLabel.GO because the default label doesn't //dispatch an event for Keyboard.ENTER on all platforms. textEditor.returnKeyLabel = "go"; return textEditor; }; this._input.addEventListener(FeathersEventType.ENTER, input_enterHandler); this._input.addEventListener(Event.CHANGE, input_changeHandler); controls.addChild(this._input); this._sendButton = new Button(); this._sendButton.label = "Send"; this._sendButton.addEventListener(Event.TRIGGERED, sendButton_triggeredHandler); controls.addChild(this._sendButton); controls.layoutData = new AnchorLayoutData(NaN, 0, 0, 0); var listLayoutData:AnchorLayoutData = new AnchorLayoutData(0, 0, 0, 0); listLayoutData.bottomAnchorDisplayObject = controls; this._list.layoutData = listLayoutData; } private function sendMessage():void { var message:String = this._input.text; if(message.length == 0) { this._input.errorString = "Please ask a question!"; return; } this._input.text = ""; this._list.dataProvider.addItem(new ChatMessage(ChatMessage.TYPE_USER, message)); var index:int = Math.floor(Math.random() * MESSAGES.length); var response:String = MESSAGES[index]; this._list.dataProvider.addItem(new ChatMessage(ChatMessage.TYPE_MAGIC_8BALL, response)); this._list.validate(); this._list.scrollToPosition(0, this._list.maxVerticalScrollPosition, 0.5); } private function input_changeHandler(event:Event):void { if(this._input.text.length > 0) { this._input.errorString = null; } } private function input_enterHandler(event:Event):void { this.sendMessage(); } private function sendButton_triggeredHandler(event:Event):void { this.sendMessage(); } } } ================================================ FILE: examples/Magic8Chat/source/feathers/examples/magic8/data/ChatMessage.as ================================================ package feathers.examples.magic8.data { public class ChatMessage { public static const TYPE_USER:String = "user"; public static const TYPE_MAGIC_8BALL:String = "magic8Ball"; public function ChatMessage(type:String, message:String) { this.type = type; this.message = message; } public var type:String; public var message:String; } } ================================================ FILE: examples/Magic8Chat/source/feathers/examples/magic8/themes/Magic8ChatTheme.as ================================================ package feathers.examples.magic8.themes { import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.text.TextBlockTextRenderer; import feathers.layout.HorizontalAlign; import feathers.layout.RelativePosition; import feathers.themes.MetalWorksMobileTheme; import starling.display.Image; import starling.textures.Texture; public class Magic8ChatTheme extends MetalWorksMobileTheme { [Embed(source="/../assets/images/8ball@2x.png")] private static const EIGHT_BALL_ICON:Class; [Embed(source="/../assets/images/question@2x.png")] private static const QUESTION_ICON:Class; private static const THEME_STYLE_NAME_MESSAGE_ITEM_RENDERER_LABEL:String = "magic8Ball-message-item-renderer-label"; public function Magic8ChatTheme() { super(); } private var eightBallTexture:Texture; private var questionTexture:Texture; override protected function initializeTextures():void { super.initializeTextures(); this.eightBallTexture = Texture.fromEmbeddedAsset(EIGHT_BALL_ICON, false, false, 2); this.questionTexture = Texture.fromEmbeddedAsset(QUESTION_ICON, false, false, 2); } override protected function initializeStyleProviders():void { super.initializeStyleProviders(); this.getStyleProviderForClass(DefaultListItemRenderer) .setFunctionForStyleName(StyleNames.USER_MESSAGE_ITEM_RENDERER, this.setUserMessageItemRendererStyles); this.getStyleProviderForClass(DefaultListItemRenderer) .setFunctionForStyleName(StyleNames.EIGHT_BALL_MESSAGE_ITEM_RENDERER, this.setEightBallMessageItemRendererStyles); this.getStyleProviderForClass(TextBlockTextRenderer) .setFunctionForStyleName(THEME_STYLE_NAME_MESSAGE_ITEM_RENDERER_LABEL, this.setMessageItemRendererLabelStyles); } private function setUserMessageItemRendererStyles(itemRenderer:DefaultListItemRenderer):void { this.setItemRendererStyles(itemRenderer); itemRenderer.customLabelStyleName = THEME_STYLE_NAME_MESSAGE_ITEM_RENDERER_LABEL; itemRenderer.horizontalAlign = HorizontalAlign.RIGHT; itemRenderer.iconPosition = RelativePosition.RIGHT; itemRenderer.itemHasIcon = false; itemRenderer.defaultIcon = new Image(this.questionTexture); } private function setEightBallMessageItemRendererStyles(itemRenderer:DefaultListItemRenderer):void { this.setItemRendererStyles(itemRenderer); itemRenderer.customLabelStyleName = THEME_STYLE_NAME_MESSAGE_ITEM_RENDERER_LABEL; itemRenderer.itemHasIcon = false; itemRenderer.defaultIcon = new Image(this.eightBallTexture); } private function setMessageItemRendererLabelStyles(text:TextBlockTextRenderer):void { text.wordWrap = true; } } } ================================================ FILE: examples/Magic8Chat/source/feathers/examples/magic8/themes/StyleNames.as ================================================ package feathers.examples.magic8.themes { public class StyleNames { public static const USER_MESSAGE_ITEM_RENDERER:String = "magic8Ball-user-message-item-renderer"; public static const EIGHT_BALL_MESSAGE_ITEM_RENDERER:String = "magic8Ball-eight-ball-message-item-renderer"; } } ================================================ FILE: examples/PullToRefresh/README.md ================================================ # Feathers Pull to Refresh A demonstration of a [Feathers](http://feathersui.com/) list component containing a pull view that refreshes the data provider. ## Requirements In addition to Starling Framework 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 [Pull to Refresh](http://feathersui.com/examples/pull-to-refresh/) example in your browser. ================================================ FILE: examples/PullToRefresh/assets/images/spinner.xml ================================================  ================================================ FILE: examples/PullToRefresh/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed advanced.telemetry=false swf.version = 30 ================================================ FILE: examples/PullToRefresh/build.xml ================================================ ================================================ FILE: examples/PullToRefresh/source/PullToRefresh-app.xml ================================================ com.feathersui.examples.PullToRefresh PullToRefresh Pull to Refresh 4.2.0 Pull to Refresh example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC PullToRefresh.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent NSAppTransportSecurity NSAllowsArbitraryLoads ]]> high ================================================ FILE: examples/PullToRefresh/source/PullToRefresh.as ================================================ package { import feathers.examples.pullToRefresh.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.system.Capabilities; import flash.utils.ByteArray; import starling.core.Starling; [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] public class PullToRefresh extends Sprite { public function PullToRefresh() { 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/PullToRefresh/source/PullToRefreshWeb.as ================================================ 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 PullToRefreshWeb extends MovieClip { public function PullToRefreshWeb() { 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.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.pullToRefresh.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/PullToRefresh/source/feathers/examples/pullToRefresh/Main.as ================================================ package feathers.examples.pullToRefresh { import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.data.ArrayCollection; import feathers.data.IListCollection; import feathers.events.FeathersEventType; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.themes.MetalWorksMobileTheme; import flash.events.TimerEvent; import flash.utils.Timer; import starling.core.Starling; import starling.display.MovieClip; import starling.events.Event; import starling.textures.Texture; import starling.textures.TextureAtlas; public class Main extends PanelScreen { [Embed(source="/../assets/images/spinner.png")] private static const SPINNER_ATLAS_IMAGE_EMBEDDED:Class; [Embed(source="/../assets/images/spinner.xml",mimeType="application/octet-stream")] private static const SPINNER_ATLAS_XML_EMBEDDED:Class; public function Main() { new MetalWorksMobileTheme(); } private var _list:List; private var _pullView:MovieClip; private var _timer:Timer; private var _nextItemIndex:int = 1; override protected function initialize():void { super.initialize(); //don't forget this! this.title = "Pull to Refresh"; this.layout = new AnchorLayout(); //any Starling display object may be used as a pull view. //we'll use an animated MovieClip in this example. var texture:Texture = Texture.fromEmbeddedAsset(SPINNER_ATLAS_IMAGE_EMBEDDED, false, false, 2); var atlas:TextureAtlas = new TextureAtlas(texture, XML(new SPINNER_ATLAS_XML_EMBEDDED())); this._pullView = new MovieClip(atlas.getTextures()); //FeathersEventType.PULLING will be dispatched on the pull view as //it is pulled down so that we can change its appearance. this._pullView.addEventListener(FeathersEventType.PULLING, pullView_pullingHandler); this._list = new List(); //pull views may appear on any of the four sides. //we'll put one on the top. this._list.topPullView = this._pullView; //when the user pulls the topPullView down by its full height then //releases, the list will dispatch Event.UPDATE this._list.addEventListener(Event.UPDATE, list_updateHandler); this._list.dataProvider = new ArrayCollection(); this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); this.addChild(this._list); this.loadData(); } private function loadData():void { if(this._timer) { //if we're already loading data, cancel it this._timer.stop(); this._timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler); this._timer = null; } //if we aren't showing the pull view (such as the first time we load //the data), we can force it to display this._list.isTopPullViewActive = true; //start the pull view animation Starling.juggler.add(this._pullView); //we're not going to load real data for this example. we'll just //wait a couple of seconds and generate some new items dynamically. //using an AssetManager or URLLoader would look pretty similar. this._timer = new Timer(2000, 1); this._timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler); this._timer.start(); } private function timerCompleteHandler(event:TimerEvent):void { this._timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler); this._timer = null; var collection:IListCollection = this._list.dataProvider; //we don't need to remove all of the old items. we could simply add //the new ones to the beginning instead. //if not removing all items, be aware that the new data might //contain duplicate items, depending on how it was loaded, so it's //a good idea to check if an item already exists in the collection //before adding it. collection.removeAll(); for(var i:int = 0; i < 25; i++) { var newItem:Object = { label: "Item " + this._nextItemIndex }; collection.unshift(newItem); this._nextItemIndex++; } //when the data has finished loading, tell the list to deactivate //its pull view: this._list.isTopPullViewActive = false; //and stop the pull view animation Starling.juggler.remove(this._pullView); } private function pullView_pullingHandler(event:Event, ratio:Number):void { var totalFrames:int = this._pullView.numFrames; //to provide some extra feedback to the user while they're pulling, //change the currentFrame of the MovieClip based on how far they've //pulled var frameIndex:int = Math.round(ratio * totalFrames); //the ratio could be greater than 1, which could result in a frame //index greater than the number of frames in the MovieClip while(frameIndex >= totalFrames) { frameIndex -= totalFrames; } this._pullView.currentFrame = frameIndex; } private function list_updateHandler(event:Event):void { //load the new data when the List dispatches Event.UPDATE this.loadData(); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/README.md ================================================ # Feathers StackScreenNavigator Explorer Demonstrates how to navigate between screens using the [Feathers](http://feathersui.com/) `StackScreenNavigator` component, presented as a mobile app. ## Requirements In addition to Starling Framework 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 [StackScreenNavigator Explorer](http://feathersui.com/examples/stack-screen-navigator-explorer/) in your browser. ================================================ FILE: examples/StackScreenNavigatorExplorer/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/StackScreenNavigatorExplorer/build.xml ================================================ ================================================ FILE: examples/StackScreenNavigatorExplorer/source/StackScreenNavigatorExplorer-app.xml ================================================ com.feathersui.examples.StackScreenNavigatorExplorer StackScreenNavigator StackScreenNavigator 4.2.0 StackScreenNavigator Explorer example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC StackScreenNavigatorExplorer.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/StackScreenNavigatorExplorer/source/StackScreenNavigatorExplorer.as ================================================ package { import feathers.examples.navigator.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.system.Capabilities; import flash.utils.ByteArray; import starling.core.Starling; [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] public class StackScreenNavigatorExplorer extends Sprite { public function StackScreenNavigatorExplorer() { 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/source/StackScreenNavigatorExplorerWeb.as ================================================ 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 StackScreenNavigatorExplorerWeb extends MovieClip { public function StackScreenNavigatorExplorerWeb() { 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.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.navigator.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/source/feathers/examples/navigator/Main.as ================================================ package feathers.examples.navigator { import feathers.controls.LayoutGroup; import feathers.controls.StackScreenNavigator; import feathers.controls.StackScreenNavigatorItem; import feathers.examples.navigator.screens.ScreenA; import feathers.examples.navigator.screens.ScreenB1; import feathers.examples.navigator.screens.ScreenB2; import feathers.examples.navigator.screens.ScreenC; import feathers.motion.Fade; import feathers.motion.Slide; import feathers.themes.MetalWorksMobileTheme; import starling.events.Event; public class Main extends LayoutGroup { private static const SCREEN_A:String = "a"; private static const SCREEN_B1:String = "b1"; private static const SCREEN_B2:String = "b2"; private static const SCREEN_C:String = "c"; public function Main() { new MetalWorksMobileTheme(); super(); } private var _navigator:StackScreenNavigator; override protected function initialize():void { this._navigator = new StackScreenNavigator(); this._navigator.pushTransition = Slide.createSlideLeftTransition(); this._navigator.popTransition = Slide.createSlideRightTransition(); var itemA:StackScreenNavigatorItem = new StackScreenNavigatorItem(ScreenA); itemA.setScreenIDForPushEvent(Event.COMPLETE, SCREEN_B1); this._navigator.addScreen(SCREEN_A, itemA); var itemB1:StackScreenNavigatorItem = new StackScreenNavigatorItem(ScreenB1); itemB1.setScreenIDForPushEvent(Event.COMPLETE, SCREEN_C); itemB1.setScreenIDForReplaceEvent(Event.CHANGE, SCREEN_B2); itemB1.addPopEvent(Event.CANCEL); this._navigator.addScreen(SCREEN_B1, itemB1); var itemB2:StackScreenNavigatorItem = new StackScreenNavigatorItem(ScreenB2); itemB2.pushTransition = Fade.createFadeInTransition(); itemB2.addPopEvent(Event.CANCEL); this._navigator.addScreen(SCREEN_B2, itemB2); var itemC:StackScreenNavigatorItem = new StackScreenNavigatorItem(ScreenC); itemC.addPopToRootEvent(Event.CLOSE); itemC.addPopEvent(Event.CANCEL); this._navigator.addScreen(SCREEN_C, itemC); this._navigator.rootScreenID = SCREEN_A; this.addChild(this._navigator); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/source/feathers/examples/navigator/screens/ScreenA.as ================================================ package feathers.examples.navigator.screens { import feathers.controls.Button; import feathers.controls.PanelScreen; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; import feathers.layout.VerticalLayoutData; import starling.events.Event; /** * Pushes another screen onto the stack. An event is mapped to the push * action by calling setScreenIDForPushEvent() on the * StackScreenNavigatorItem. * * item.setScreenIDForPushEvent(Event.COMPLETE, otherScreenID); */ [Event(name="complete",type="starling.events.Event")] public class ScreenA extends PanelScreen { public function ScreenA() { super(); this.title = "Screen A"; } override protected function initialize():void { super.initialize(); var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.gap = 10; this.layout = layout; var pushB1Button:Button = new Button(); pushB1Button.label = "Push Screen B1"; pushB1Button.layoutData = new VerticalLayoutData(50); pushB1Button.addEventListener(Event.TRIGGERED, pushB1Button_triggeredHandler); this.addChild(pushB1Button); } protected function pushB1Button_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.COMPLETE); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/source/feathers/examples/navigator/screens/ScreenB1.as ================================================ package feathers.examples.navigator.screens { import feathers.controls.Button; import feathers.controls.PanelScreen; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; import feathers.layout.VerticalLayoutData; import starling.events.Event; /** * Pops this screen from the stack to return to the previous screen. An * event is mapped to the pop action by calling addPopEvent() on the * StackScreenNavigatorItem. * * item.addPopEvent(Event.CANCEL); */ [Event(name="cancel",type="starling.events.Event")] /** * Replaces this screen with another screen at the same position in the * stack. An event is mapped to the replace action by calling * setScreenIDForReplaceEvent() on the StackScreenNavigatorItem. * * item.setScreenIDForReplaceEvent(Event.CHANGE, otherScreenID); */ [Event(name="change",type="starling.events.Event")] /** * Pushes another screen onto the stack. An event is mapped to the push * action by calling setScreenIDForPushEvent() on the * StackScreenNavigatorItem. * * item.setScreenIDForPushEvent(Event.COMPLETE, otherScreenID); */ [Event(name="complete",type="starling.events.Event")] public class ScreenB1 extends PanelScreen { public function ScreenB1() { super(); this.title = "Screen B1"; } override protected function initialize():void { super.initialize(); var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.gap = 10; this.layout = layout; var popToAButton:Button = new Button(); popToAButton.label = "Pop to Screen A"; popToAButton.layoutData = new VerticalLayoutData(50); popToAButton.addEventListener(Event.TRIGGERED, popToAButton_triggeredHandler); this.addChild(popToAButton); var pushCButton:Button = new Button(); pushCButton.label = "Push Screen C"; pushCButton.layoutData = new VerticalLayoutData(50); pushCButton.addEventListener(Event.TRIGGERED, pushCButton_triggeredHandler); this.addChild(pushCButton); var replaceWithB2Button:Button = new Button(); replaceWithB2Button.label = "Replace With Screen B2"; replaceWithB2Button.layoutData = new VerticalLayoutData(50); replaceWithB2Button.addEventListener(Event.TRIGGERED, replaceWithB2Button_triggeredHandler); this.addChild(replaceWithB2Button); } protected function popToAButton_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.CANCEL); } protected function pushCButton_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.COMPLETE); } protected function replaceWithB2Button_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.CHANGE); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/source/feathers/examples/navigator/screens/ScreenB2.as ================================================ package feathers.examples.navigator.screens { import feathers.controls.Button; import feathers.controls.PanelScreen; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; import feathers.layout.VerticalLayoutData; import starling.events.Event; /** * Pops this screen from the stack to return to the previous screen. An * event is mapped to the pop action by calling addPopEvent() on the * StackScreenNavigatorItem. * * item.addPopEvent(Event.CANCEL); */ [Event(name="cancel",type="starling.events.Event")] public class ScreenB2 extends PanelScreen { public function ScreenB2() { super(); this.title = "Screen B2"; } override protected function initialize():void { super.initialize(); var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.gap = 10; this.layout = layout; var popToAButton:Button = new Button(); popToAButton.label = "Pop to Screen A"; popToAButton.layoutData = new VerticalLayoutData(50); popToAButton.addEventListener(Event.TRIGGERED, popToAButton_triggeredHandler); this.addChild(popToAButton); } protected function popToAButton_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.CANCEL); } } } ================================================ FILE: examples/StackScreenNavigatorExplorer/source/feathers/examples/navigator/screens/ScreenC.as ================================================ package feathers.examples.navigator.screens { import feathers.controls.Button; import feathers.controls.PanelScreen; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; import feathers.layout.VerticalLayoutData; import starling.events.Event; /** * Pops all screens from the stack to return to the root screen. An event * is mapped to the pop to root action by calling addPopToRootEvent() on the * StackScreenNavigatorItem. * * item.addPopToRootEvent(Event.CLOSE); */ [Event(name="close",type="starling.events.Event")] /** * Pops this screen from the stack to return to the previous screen. An * event is mapped to the pop action by calling addPopEvent() on the * StackScreenNavigatorItem. * * item.addPopEvent(Event.CANCEL); */ [Event(name="cancel",type="starling.events.Event")] public class ScreenC extends PanelScreen { public function ScreenC() { super(); this.title = "Screen C"; } override protected function initialize():void { super.initialize(); var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; layout.gap = 10; this.layout = layout; var popToB1Button:Button = new Button(); popToB1Button.label = "Pop to Screen B"; popToB1Button.layoutData = new VerticalLayoutData(50); popToB1Button.addEventListener(Event.TRIGGERED, popToB1Button_triggeredHandler); this.addChild(popToB1Button); var popToRootButton:Button = new Button(); popToRootButton.label = "Pop to Root"; popToRootButton.layoutData = new VerticalLayoutData(50); popToRootButton.addEventListener(Event.TRIGGERED, popToRootButton_triggeredHandler); this.addChild(popToRootButton); } protected function popToB1Button_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.CANCEL); } protected function popToRootButton_triggeredHandler(event:Event):void { this.dispatchEventWith(Event.CLOSE); } } } ================================================ FILE: examples/Tabs/README.md ================================================ # Feathers Tabs Demonstrates how to navigate between tabs using the [Feathers](http://feathersui.com/) `TabNavigator` component, presented as a mobile app. ## Requirements In addition to Starling Framework 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 [Tabs example](http://feathersui.com/examples/tabs/) in your browser. ## Credits User data randomly generated with [randomuser.me](https://randomuser.me/). ================================================ FILE: examples/Tabs/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/Tabs/build.xml ================================================ ================================================ FILE: examples/Tabs/source/Tabs-app.xml ================================================ com.feathersui.examples.Tabs Tabs Tabs 4.2.0 Tabs example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC Tabs.swf true false true direct true en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent NSAppTransportSecurity NSExceptionDomains feathersui.com NSTemporaryExceptionAllowsInsecureHTTPLoads ]]> high ================================================ FILE: examples/Tabs/source/Tabs.as ================================================ package { import feathers.examples.tabs.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.system.Capabilities; import flash.utils.ByteArray; import starling.core.Starling; [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] public class Tabs extends Sprite { public function Tabs() { 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/Tabs/source/TabsWeb.as ================================================ 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 TabsWeb extends MovieClip { public function TabsWeb() { 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.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.tabs.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/Tabs/source/feathers/examples/tabs/Main.as ================================================ package feathers.examples.tabs { import feathers.controls.TabNavigator; import feathers.controls.TabNavigatorItem; import feathers.examples.tabs.screens.ContactsScreen; import feathers.examples.tabs.screens.MessagesScreen; import feathers.examples.tabs.screens.ProfileScreen; import feathers.examples.tabs.themes.TabsTheme; import starling.display.Sprite; import starling.events.Event; public class Main extends Sprite { private static const MESSAGES:String = "messages"; private static const CONTACTS:String = "contacts"; private static const PROFILE:String = "profile"; public function Main() { new TabsTheme(); super(); this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); } protected var navigator:TabNavigator; protected function addedToStageHandler(event:Event):void { this.navigator = new TabNavigator(); this.addMessagesTab(); this.addContactsTab(); this.addProfileTab(); this.addChild(this.navigator); } private function addMessagesTab():void { var screen:MessagesScreen = new MessagesScreen(); var item:TabNavigatorItem = new TabNavigatorItem(screen, "Messages"); this.navigator.addScreen(MESSAGES, item); } private function addContactsTab():void { var screen:ContactsScreen = new ContactsScreen(); var item:TabNavigatorItem = new TabNavigatorItem(screen, "Contacts"); this.navigator.addScreen(CONTACTS, item); } private function addProfileTab():void { var screen:ProfileScreen = new ProfileScreen(); var item:TabNavigatorItem = new TabNavigatorItem(screen, "Profile"); this.navigator.addScreen(PROFILE, item); } } } ================================================ FILE: examples/Tabs/source/feathers/examples/tabs/screens/ContactsScreen.as ================================================ package feathers.examples.tabs.screens { import feathers.controls.GroupedList; import feathers.controls.ImageLoader; import feathers.controls.PanelScreen; import feathers.controls.renderers.DefaultGroupedListItemRenderer; import feathers.controls.renderers.IGroupedListItemRenderer; import feathers.data.ArrayHierarchicalCollection; import feathers.examples.tabs.themes.StyleNames; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.utils.textures.TextureCache; public class ContactsScreen extends PanelScreen { public function ContactsScreen() { this.title = "Contacts"; } private var _list:GroupedList; private var _cache:TextureCache; override public function dispose():void { if(this._cache !== null) { this._cache.dispose(); this._cache = null; } super.dispose(); } override protected function initialize():void { super.initialize(); this._cache = new TextureCache(10); this.layout = new AnchorLayout(); this._list = new GroupedList(); this._list.isSelectable = false; this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); this._list.customItemRendererStyleName = StyleNames.MESSAGE_LIST_ITEM_RENDERER; this._list.itemRendererFactory = this.createContactItemRenderer; this.addChild(this._list); this._list.dataProvider = new ArrayHierarchicalCollection( [ { header: "A", children: [ { name: "Andy Johnston", email: "itsandy1981@example.com", photo: "http://feathersui.com/examples/tabs/images/men92.jpg" }, ] }, { header: "D", children: [ { name: "Denise Kim", email: "kim.denise@example.com", photo: "http://feathersui.com/examples/tabs/images/women83.jpg" }, { name: "Dylan Curtis", email: "curtis1987@example.com", photo: "http://feathersui.com/examples/tabs/images/men87.jpg" }, ] }, { header: "P", children: [ { name: "Pat Brewer", email: "pbrewer19@example.com", photo: "http://feathersui.com/examples/tabs/images/women79.jpg" }, { name: "Pearl Boyd", email: "pearl.boyd@example.com", photo: "http://feathersui.com/examples/tabs/images/women69.jpg" }, ] }, { header: "R", children: [ { name: "Robin Taylor", email: "robintaylor@example.com", photo: "http://feathersui.com/examples/tabs/images/women89.jpg" }, ] }, { header: "S", children: [ { name: "Savannah Flores", email: "saflo79@example.com", photo: "http://feathersui.com/examples/tabs/images/women53.jpg" }, ] }, { header: "W", children: [ { name: "Wayne Adams", email: "superwayne@example.com", photo: "http://feathersui.com/examples/tabs/images/men36.jpg" }, ] }, ]); } private function createContactItemRenderer():IGroupedListItemRenderer { var itemRenderer:DefaultGroupedListItemRenderer = new DefaultGroupedListItemRenderer(); itemRenderer.labelField = "name"; itemRenderer.accessoryLabelField = "email"; itemRenderer.iconSourceField = "photo"; itemRenderer.iconLoaderFactory = this.createPhotoLoader; return itemRenderer; } private function createPhotoLoader():ImageLoader { var loader:ImageLoader = new ImageLoader(); loader.textureCache = this._cache; return loader; } } } ================================================ FILE: examples/Tabs/source/feathers/examples/tabs/screens/MessagesScreen.as ================================================ package feathers.examples.tabs.screens { import feathers.controls.ImageLoader; import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.data.ListCollection; import feathers.examples.tabs.themes.StyleNames; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.utils.textures.TextureCache; public class MessagesScreen extends PanelScreen { public function MessagesScreen() { this.title = "Messages"; } private var _list:List; private var _cache:TextureCache; override public function dispose():void { if(this._cache !== null) { this._cache.dispose(); this._cache = null; } super.dispose(); } override protected function initialize():void { super.initialize(); this._cache = new TextureCache(10); this.layout = new AnchorLayout(); this._list = new List(); this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); this._list.customItemRendererStyleName = StyleNames.MESSAGE_LIST_ITEM_RENDERER; this._list.itemRendererFactory = this.createMessageItemRenderer; this.addChild(this._list); this._list.dataProvider = new ArrayCollection( [ { name: "Patsy Brewer", message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", photo: "http://feathersui.com/examples/tabs/images/women79.jpg" }, { name: "Wayne Adams", message: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", photo: "http://feathersui.com/examples/tabs/images/men36.jpg" }, { name: "Andy Johnston", message: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", photo: "http://feathersui.com/examples/tabs/images/men92.jpg" }, { name: "Pearl Boyd", message: "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", photo: "http://feathersui.com/examples/tabs/images/women69.jpg" }, ]); } private function createMessageItemRenderer():IListItemRenderer { var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); itemRenderer.labelField = "name"; itemRenderer.accessoryLabelField = "message"; itemRenderer.iconSourceField = "photo"; itemRenderer.iconLoaderFactory = this.createPhotoLoader; return itemRenderer; } private function createPhotoLoader():ImageLoader { var loader:ImageLoader = new ImageLoader(); loader.textureCache = this._cache; return loader; } } } ================================================ FILE: examples/Tabs/source/feathers/examples/tabs/screens/ProfileScreen.as ================================================ package feathers.examples.tabs.screens { import feathers.controls.ImageLoader; import feathers.controls.Label; import feathers.controls.LayoutGroup; import feathers.controls.Screen; import feathers.examples.tabs.themes.StyleNames; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; public class ProfileScreen extends Screen { public function ProfileScreen() { super(); } private var _image:ImageLoader; private var _nameLabel:Label; private var _emailLabel:Label; override protected function initialize():void { super.initialize(); var mainLayout:VerticalLayout = new VerticalLayout(); mainLayout.horizontalAlign = HorizontalAlign.CENTER; mainLayout.verticalAlign = VerticalAlign.MIDDLE; mainLayout.padding = 10; this.layout = mainLayout; var header:LayoutGroup = new LayoutGroup(); var headerLayout:VerticalLayout = new VerticalLayout(); headerLayout.gap = 4; headerLayout.horizontalAlign = HorizontalAlign.CENTER; header.layout = headerLayout; this.addChild(header); this._image = new ImageLoader(); this._image.styleNameList.add(StyleNames.LARGE_PROFILE_IMAGE); this._image.source = "http://feathersui.com/examples/tabs/images/men67.jpg"; header.addChild(this._image); this._nameLabel = new Label(); this._nameLabel.styleNameList.add(Label.ALTERNATE_STYLE_NAME_HEADING); this._nameLabel.text = "Flynn Reynolds"; header.addChild(this._nameLabel); this._emailLabel = new Label(); this._emailLabel.text = "flynn.reynolds84@example.com"; this.addChild(this._emailLabel); } } } ================================================ FILE: examples/Tabs/source/feathers/examples/tabs/themes/StyleNames.as ================================================ package feathers.examples.tabs.themes { public class StyleNames { public static const MESSAGE_LIST_ITEM_RENDERER:String = "message-list-item-renderer"; public static const SMALL_PROFILE_IMAGE:String = "small-profile-image"; public static const LARGE_PROFILE_IMAGE:String = "large-profile-image"; } } ================================================ FILE: examples/Tabs/source/feathers/examples/tabs/themes/TabsTheme.as ================================================ package feathers.examples.tabs.themes { import feathers.controls.ImageLoader; import feathers.controls.ItemRendererLayoutOrder; import feathers.controls.renderers.BaseDefaultItemRenderer; import feathers.controls.renderers.DefaultGroupedListItemRenderer; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.layout.RelativePosition; import feathers.themes.MetalWorksMobileTheme; import starling.display.Canvas; public class TabsTheme extends MetalWorksMobileTheme { public function TabsTheme() { super(); } override protected function initializeStyleProviders():void { super.initializeStyleProviders(); this.getStyleProviderForClass(DefaultListItemRenderer).setFunctionForStyleName( StyleNames.MESSAGE_LIST_ITEM_RENDERER, this.setMessageListItemRendererStyles); this.getStyleProviderForClass(DefaultGroupedListItemRenderer).setFunctionForStyleName( StyleNames.MESSAGE_LIST_ITEM_RENDERER, this.setMessageListItemRendererStyles); this.getStyleProviderForClass(ImageLoader).setFunctionForStyleName( StyleNames.SMALL_PROFILE_IMAGE, this.setSmallProfileImageStyles); this.getStyleProviderForClass(ImageLoader).setFunctionForStyleName( StyleNames.LARGE_PROFILE_IMAGE, this.setLargeProfileImageStyles); } private function setMessageListItemRendererStyles(itemRenderer:BaseDefaultItemRenderer):void { this.setItemRendererStyles(itemRenderer); itemRenderer.accessoryPosition = RelativePosition.BOTTOM; itemRenderer.accessoryGap = 4; itemRenderer.layoutOrder = ItemRendererLayoutOrder.LABEL_ACCESSORY_ICON; itemRenderer.customIconLoaderStyleName = StyleNames.SMALL_PROFILE_IMAGE; } private function setProfileImageStyles(image:ImageLoader, size:Number):void { var halfSize:Number = size / 2; image.setSize(size, size); var mask:Canvas = new Canvas(); mask.beginFill(0xff00ff, 1); mask.drawCircle(halfSize, halfSize, halfSize); mask.endFill(); image.mask = mask; image.addChild(mask); } private function setSmallProfileImageStyles(image:ImageLoader):void { this.setProfileImageStyles(image, 48); } private function setLargeProfileImageStyles(image:ImageLoader):void { this.setProfileImageStyles(image, 100); } } } ================================================ FILE: examples/TileList/README.md ================================================ # 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 [Picons social media icon set](https://picons.me/download-social.php). ================================================ FILE: examples/TileList/assets/images/atlas@2x.tps ================================================ fileFormatVersion 3 texturePackerVersion 4.0.1 fileName /Users/joshtynjala/Development/feathers/feathers/examples/TileList/assets/images/atlas@2x.tps autoSDSettings scale 1 extension spriteFilter acceptFractionalValues maxTextureSize width -1 height -1 allowRotation premultiplyAlpha shapeDebug dpi 72 dataFormat sparrow textureFileName atlas@2x.png flipPVR pvrCompressionQuality PVR_QUALITY_BEST atfCompressData mipMapMinSize 32768 etc1CompressionQuality ETC1_QUALITY_LOW_PERCEPTUAL dxtCompressionMode DXT_PERCEPTUAL jxrColorFormat JXR_YUV444 jxrTrimFlexBits 0 jxrCompressionLevel 0 ditherType NearestNeighbour backgroundColor 0 libGdx filtering x Linear y Linear shapePadding 2 jpgQuality 80 pngOptimizationLevel 1 webpQualityLevel 101 textureSubPath textureFormat png borderPadding 2 maxTextureSize width 2048 height 2048 fixedTextureSize width -1 height -1 reduceBorderArtifacts algorithmSettings algorithm MaxRects freeSizeMode Best sizeConstraints AnySize forceSquared forceWordAligned maxRects heuristic Best basic sortBy Best order Ascending andEngine minFilter Linear packageName Texture wrap s Clamp t Clamp magFilter MagLinear dataFileNames data name atlas@2x.xml java name icons.java multiPack forceIdenticalLayout outputFormat RGBA8888 contentProtection key autoAliasEnabled trimSpriteNames prependSmartFolderName cleanTransparentPixels globalSpriteSettings scale 1 scaleMode Smooth extrude 1 trimThreshold 1 trimMargin 1 trimMode Trim tracerTolerance 200 heuristicMask pivotPoint Center fileList atlas@2x ignoreFileList replaceList ignoredWarnings commonDivisorX 1 commonDivisorY 1 packNormalMaps autodetectNormalMaps normalMapFilter normalMapSuffix normalMapSheetFileName ================================================ FILE: examples/TileList/assets/images/atlas@2x.xml ================================================ ================================================ FILE: examples/TileList/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MinimalMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons assets.path = ${basedir}/assets launch.image.path = ${assets.path}/launch-images swf.version = 30 ================================================ FILE: examples/TileList/build.xml ================================================ ================================================ FILE: examples/TileList/source/TileList-app.xml ================================================ com.feathersui.examples.TileList Tile List Tile List 4.2.0 TileList example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC TileList.swf true true true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon ]]> high ================================================ FILE: examples/TileList/source/TileList.as ================================================ package { import feathers.examples.tileList.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/TileList/source/TileListWeb.as ================================================ 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="#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.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); //simulating iPhone Retina DeviceCapabilities.dpi = 326; var MainType:Class = getDefinitionByName("feathers.examples.tileList.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/TileList/source/feathers/examples/tileList/Main.as ================================================ package feathers.examples.tileList { import feathers.controls.LayoutGroup; import feathers.controls.List; import feathers.controls.PageIndicator; import feathers.controls.ScrollBarDisplayMode; import feathers.controls.ScrollPolicy; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.RelativePosition; import feathers.layout.TiledRowsLayout; import feathers.layout.VerticalAlign; import feathers.themes.MinimalMobileTheme; import starling.events.Event; import starling.textures.TextureAtlas; import starling.utils.AssetManager; public class Main extends LayoutGroup { public function Main() { new MinimalMobileTheme(); super(); } private var _assetManager:AssetManager; private var _list:List; private var _pageIndicator:PageIndicator; override public function dispose():void { //don't forget to clean up textures and things! if(this._assetManager) { this._assetManager.dispose(); this._assetManager = null; } super.dispose(); } override protected function initialize():void { //don't forget to call super.initialize() super.initialize(); //a nice, fluid layout this.layout = new AnchorLayout(); //the page indicator can be used to scroll the list this._pageIndicator = new PageIndicator(); this._pageIndicator.direction = Direction.HORIZONTAL; this._pageIndicator.pageCount = 1; //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); this._list = new List(); this._list.itemRendererFactory = tileListItemRendererFactory; this._list.snapToPages = true; this._list.scrollBarDisplayMode = ScrollBarDisplayMode.NONE; this._list.horizontalScrollPolicy = ScrollPolicy.ON; this._list.verticalScrollPolicy = ScrollPolicy.OFF; var listLayout:TiledRowsLayout = new TiledRowsLayout(); listLayout.paging = Direction.HORIZONTAL; listLayout.useSquareTiles = false; listLayout.tileHorizontalAlign = HorizontalAlign.JUSTIFY; listLayout.tileVerticalAlign = HorizontalAlign.JUSTIFY; listLayout.horizontalAlign = HorizontalAlign.JUSTIFY; listLayout.verticalAlign = VerticalAlign.TOP; listLayout.requestedColumnCount = 4; listLayout.distributeWidths = true; this._list.layout = listLayout; //we listen to the scroll event to update the page indicator this._list.addEventListener(Event.SCROLL, list_scrollHandler); //the list fills the container's width and the remaining height //above the page indicator var listLayoutData:AnchorLayoutData = new AnchorLayoutData(); listLayoutData.top = 0; listLayoutData.right = 0; listLayoutData.bottom = 0; listLayoutData.bottomAnchorDisplayObject = this._pageIndicator; listLayoutData.left = 0; this._list.layoutData = listLayoutData; this.addChild(this._list); this.loadIcons(); } protected function loadIcons():void { this._assetManager = new AssetManager(2); this._assetManager.enqueue("images/atlas@2x.png"); this._assetManager.enqueue("images/atlas@2x.xml"); this._assetManager.loadQueue(assetManager_onProgress); } protected function tileListItemRendererFactory():IListItemRenderer { var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); itemRenderer.labelField = "label"; itemRenderer.iconSourceField = "texture"; itemRenderer.iconPosition = RelativePosition.TOP; itemRenderer.horizontalAlign = HorizontalAlign.CENTER; itemRenderer.verticalAlign = VerticalAlign.BOTTOM; itemRenderer.maxWidth = 80; itemRenderer.gap = 2; return itemRenderer; } 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); } protected function assetManager_onProgress(ratio:Number):void { if(ratio < 1) { return; } //get the texture atlas from the asset manager var atlas:TextureAtlas = this._assetManager.getTextureAtlas("atlas@2x"); //populate the list using the textures this._list.dataProvider = new ArrayCollection( [ { label: "Behance", texture: atlas.getTexture("behance") }, { label: "Blogger", texture: atlas.getTexture("blogger") }, { label: "Delicious", texture: atlas.getTexture("delicious") }, { label: "DeviantArt", texture: atlas.getTexture("deviantart") }, { label: "Digg", texture: atlas.getTexture("digg") }, { label: "Dribbble", texture: atlas.getTexture("dribbble") }, { label: "Facebook", texture: atlas.getTexture("facebook") }, { label: "Flickr", texture: atlas.getTexture("flickr") }, { label: "Github", texture: atlas.getTexture("github") }, { label: "Google", texture: atlas.getTexture("google") }, { label: "Instagram", texture: atlas.getTexture("instagram") }, { label: "LinkedIn", texture: atlas.getTexture("linkedin") }, { label: "Pinterest", texture: atlas.getTexture("pinterest") }, { label: "Snapchat", texture: atlas.getTexture("snapchat") }, { label: "SoundCloud", texture: atlas.getTexture("soundcloud") }, { label: "StackOverflow", texture: atlas.getTexture("stackoverflow") }, { label: "StumbleUpon", texture: atlas.getTexture("stumbleupon") }, { label: "Tumblr", texture: atlas.getTexture("tumblr") }, { label: "Twitter", texture: atlas.getTexture("twitter") }, { label: "Vimeo", texture: atlas.getTexture("vimeo") }, { label: "Vine", texture: atlas.getTexture("vine") }, { label: "WordPress", texture: atlas.getTexture("wordpress") }, { label: "Yahoo!", texture: atlas.getTexture("yahoo") }, { label: "Yelp", texture: atlas.getTexture("yelp") }, { label: "YouTube", texture: atlas.getTexture("youtube") }, ]); } } } ================================================ FILE: examples/Todos/README.md ================================================ # Todos Example for Feathers This [Feathers UI](http://feathersui.com/) example mocks up a simple application to track things that need to get done. The app can add and remove todo items, mark them as completed, and it even supports drag and drop to change the order of items. A custom list item renderer based on the `LayoutGroup` component is used, and it can switch between a normal checkbox and label and an editable mode that adds a drag handle and a delete button. ## Requirements In addition to Starling Framework 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. ================================================ FILE: examples/Todos/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/Todos/build.xml ================================================ ================================================ FILE: examples/Todos/source/Todos-app.xml ================================================ com.feathersui.examples.Todos Todos Todos 4.2.0 Todos example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC Todos.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/Todos/source/Todos.as ================================================ package { import feathers.examples.todos.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/Todos/source/TodosWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.todos.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/Todos/source/feathers/examples/todos/Main.as ================================================ package feathers.examples.todos { import feathers.controls.Alert; import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.LayoutGroup; import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.TabBar; import feathers.controls.TextInput; import feathers.controls.ToggleButton; import feathers.controls.text.StageTextTextEditor; import feathers.core.FeathersControl; import feathers.core.IFeathersControl; import feathers.core.ITextEditor; import feathers.data.ArrayCollection; import feathers.data.VectorCollection; import feathers.events.FeathersEventType; import feathers.examples.todos.TodoItem; import feathers.examples.todos.controls.TodoItemRenderer; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalLayoutData; import starling.display.DisplayObject; import starling.events.Event; import flash.net.SharedObject; import feathers.controls.renderers.IListItemRenderer; import flash.net.registerClassAlias; public class Main extends PanelScreen { public function Main() { //set up the theme right away! new TodosTheme(); super(); registerClassAlias("feathers.examples.todos.TodoItem", TodoItem); this._sharedObject = SharedObject.getLocal("todos"); this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); } private var _list:List; private var _tabs:TabBar; private var _toolbar:LayoutGroup; private var _input:TextInput; private var _clearButton:Button; private var _editButton:ToggleButton; private var _items:VectorCollection; private var _sharedObject:SharedObject; private function customHeaderFactory():IFeathersControl { var header:Header = new Header(); if(!this._editButton) { this._editButton = new ToggleButton(); this._editButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_QUIET_BUTTON); this._editButton.label = "Edit"; this._editButton.addEventListener(Event.CHANGE, editButton_changeHandler); } header.rightItems = new [ this._editButton ]; return header; } override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "TODOS"; this.width = this.stage.stageWidth; this.height = this.stage.stageHeight; this.layout = new AnchorLayout(); this.headerFactory = this.customHeaderFactory; this._tabs = new TabBar(); this._tabs.dataProvider = new ArrayCollection( [ {label: "All"}, {label: "Active"}, {label: "Completed"}, ]); this._tabs.addEventListener(Event.CHANGE, tabs_changeHandler); this.addChild(this._tabs); var itemsToRestore:Vector. = this._sharedObject.data.items; if(!itemsToRestore) { //if the shared object is empty, create a new vector itemsToRestore = new []; } this._items = new VectorCollection(itemsToRestore); this._list = new List(); this._list.isSelectable = false; this._list.dataProvider = this._items; this._list.itemRendererFactory = function():IListItemRenderer { var itemRenderer:TodoItemRenderer = new TodoItemRenderer(); itemRenderer.addEventListener(Event.CHANGE, itemRenderer_changeHandler); itemRenderer.addEventListener(TodoItemRenderer.EVENT_DELETE_ITEM, itemRenderer_deleteItemHandler); return itemRenderer; }; this.addChild(this._list); this._toolbar = new LayoutGroup(); this._toolbar.styleNameList.add(LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR); this.addChild(this._toolbar); this._clearButton = new Button(); this._clearButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_DANGER_BUTTON); this._clearButton.label = "Clear All Completed Items"; this._clearButton.includeInLayout = false; this._clearButton.visible = false; this._clearButton.addEventListener(Event.TRIGGERED, clearButton_triggeredHandler); this._toolbar.addChild(this._clearButton); this._input = new TextInput(); this._input.prompt = "What needs to be done?"; this._input.textEditorFactory = function():ITextEditor { var textEditor:StageTextTextEditor = FeathersControl.defaultTextEditorFactory() as StageTextTextEditor; if(textEditor) { //we can't get an enter key event without changing the value //of returnKeyLabel. //we didn't use using ReturnKeyLabel.GO here so that it will //build the demo for Flash Player. That class is AIR only. textEditor.returnKeyLabel = "go"; } return textEditor; }; this._input.layoutData = new HorizontalLayoutData(100); this._input.addEventListener(FeathersEventType.ENTER, input_enterHandler); this._toolbar.addChild(this._input); var toolbarLayoutData:AnchorLayoutData = new AnchorLayoutData(); toolbarLayoutData.top = 0; toolbarLayoutData.right = 0; toolbarLayoutData.left = 0; this._toolbar.layoutData = toolbarLayoutData; var tabsLayoutData:AnchorLayoutData = new AnchorLayoutData(); tabsLayoutData.bottom = 0; tabsLayoutData.right = 0; tabsLayoutData.left = 0; this._tabs.layoutData = tabsLayoutData; var listLayoutData:AnchorLayoutData = new AnchorLayoutData(); listLayoutData.top = 0; listLayoutData.topAnchorDisplayObject = this._toolbar; listLayoutData.right = 0; listLayoutData.bottom = 0; listLayoutData.bottomAnchorDisplayObject = this._tabs; listLayoutData.left = 0; this._list.layoutData = listLayoutData; } private function includeActiveItems(item:TodoItem):Boolean { return !item.isCompleted; } private function includeCompletedItems(item:TodoItem):Boolean { return item.isCompleted; } private function refreshFilterFunction():void { if(this._tabs.selectedIndex === 1) { this._items.filterFunction = this.includeActiveItems; } else if(this._tabs.selectedIndex === 2) { this._items.filterFunction = this.includeCompletedItems; } else { this._items.filterFunction = null; } } private function saveItems():void { this._sharedObject.data.items = this._items.vectorData; this._sharedObject.flush(); } 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._items.addItem(new TodoItem(this._input.text)); this._input.text = ""; this.saveItems(); } private function editButton_changeHandler(event:Event):void { var isEditing:Boolean = this._editButton.isSelected; this._list.dragEnabled = isEditing; this._list.dropEnabled = isEditing; this._clearButton.visible = isEditing; this._clearButton.includeInLayout = isEditing; this._input.visible = !isEditing; this._input.includeInLayout = !isEditing; } private function clearButton_triggeredHandler(event:Event):void { //the completed items may currently be filtered, so temporarily //disable the filter. this._items.filterFunction = null; var hasCompletedItem:Boolean = false; var itemCount:int = this._items.length; for(var i:int = itemCount - 1; i >= 0; i--) { var item:TodoItem = TodoItem(this._items.getItemAt(i)); if(item.isCompleted) { hasCompletedItem = true; break; } } //be sure to restore the filter this.refreshFilterFunction(); if(!hasCompletedItem) { return; } Alert.show("Are you sure that you want to delete all completed items? This action cannot be undone.", "Confirm delete", new ArrayCollection( [ { label: "Cancel" }, { label: "Delete", triggered: confirmButton_triggeredHandler }, ])); } private function confirmButton_triggeredHandler(event:Event):void { //the completed items may currently be filtered, so temporarily //disable the filter. this._items.filterFunction = null; var itemCount:int = this._items.length; for(var i:int = itemCount - 1; i >= 0; i--) { var item:TodoItem = TodoItem(this._items.getItemAt(i)); if(item.isCompleted) { this._items.removeItemAt(i); } } //be sure to restore the filter this.refreshFilterFunction(); this.saveItems(); } private function itemRenderer_changeHandler(event:Event):void { this.saveItems(); } private function itemRenderer_deleteItemHandler(event:Event, item:Object):void { this._items.removeItem(item); this.saveItems(); } private function stage_resizeHandler():void { this.width = this.stage.stageWidth; this.height = this.stage.stageHeight; } private function tabs_changeHandler(event:Event):void { this.refreshFilterFunction(); } } } ================================================ FILE: examples/Todos/source/feathers/examples/todos/TodoItem.as ================================================ package feathers.examples.todos { import flash.utils.IExternalizable; import flash.utils.IDataInput; import flash.utils.IDataOutput; public class TodoItem implements IExternalizable { public function TodoItem(description:String = null, isCompleted:Boolean = false) { this.description = description; this.isCompleted = isCompleted; } public var description:String; public var isCompleted:Boolean; public function writeExternal(output:IDataOutput):void { output.writeBoolean(this.isCompleted); output.writeUTF(this.description); } public function readExternal(input:IDataInput):void { this.isCompleted = input.readBoolean(); this.description = input.readUTF(); } } } ================================================ FILE: examples/Todos/source/feathers/examples/todos/TodosTheme.as ================================================ package feathers.examples.todos { import feathers.controls.Check; import feathers.controls.LayoutGroup; import feathers.examples.todos.controls.TodoItemRenderer; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.VerticalAlign; import feathers.skins.ImageSkin; import feathers.themes.MetalWorksMobileTheme; public class TodosTheme extends MetalWorksMobileTheme { public function TodosTheme() { super(); } override protected function initializeStyleProviders():void { super.initializeStyleProviders(); this.getStyleProviderForClass(TodoItemRenderer).defaultStyleFunction = this.setTodoItemRendererStyles; } override protected function setCheckStyles(check:Check):void { super.setCheckStyles(check); check.hasLabelTextRenderer = false; check.horizontalAlign = HorizontalAlign.CENTER; } override protected function setToolbarLayoutGroupStyles(group:LayoutGroup):void { super.setToolbarLayoutGroupStyles(group); var layout:HorizontalLayout = new HorizontalLayout(); layout.gap = this.smallGutterSize; layout.padding = this.gutterSize; layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; group.layout = layout; } protected function setTodoItemRendererStyles(itemRenderer:TodoItemRenderer):void { var backgroundSkin:ImageSkin = new ImageSkin(this.itemRendererUpSkinTexture); backgroundSkin.scale9Grid = ITEM_RENDERER_SCALE9_GRID; itemRenderer.backgroundSkin = backgroundSkin; var layout:HorizontalLayout = new HorizontalLayout(); layout.gap = this.smallGutterSize; layout.padding = this.smallGutterSize; layout.verticalAlign = VerticalAlign.MIDDLE; itemRenderer.layout = layout; var dragIcon:ImageSkin = new ImageSkin(this.dragHandleIcon); itemRenderer.dragIcon = dragIcon; } } } ================================================ FILE: examples/Todos/source/feathers/examples/todos/controls/TodoItemRenderer.as ================================================ package feathers.examples.todos.controls { import feathers.controls.Alert; import feathers.controls.Button; import feathers.controls.Check; import feathers.controls.Label; import feathers.controls.List; import feathers.controls.renderers.LayoutGroupListItemRenderer; import feathers.data.ArrayCollection; import feathers.examples.todos.TodoItem; import feathers.layout.HorizontalLayoutData; import feathers.skins.IStyleProvider; import starling.events.Event; import starling.display.DisplayObject; import feathers.controls.renderers.IDragAndDropItemRenderer; import feathers.controls.LayoutGroup; import feathers.layout.HorizontalLayout; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalAlign; public class TodoItemRenderer extends LayoutGroupListItemRenderer implements IDragAndDropItemRenderer { public static const EVENT_DELETE_ITEM:String = "deleteItem"; public static var globalStyleProvider:IStyleProvider; public function TodoItemRenderer() { super(); } protected var check:Check; protected var deleteButton:Button; protected var label:Label; override protected function get defaultStyleProvider():IStyleProvider { return globalStyleProvider; } private var _dragEnabled:Boolean = false; public function get dragEnabled():Boolean { return this._dragEnabled; } public function set dragEnabled(value:Boolean):void { if(this._dragEnabled == value) { return; } this._dragEnabled = value; this.invalidate(INVALIDATION_FLAG_DATA); } public function get dragProxy():DisplayObject { return this._dragIcon; } private var _dragIconContainer:LayoutGroup; private var _dragIcon:DisplayObject; public function get dragIcon():DisplayObject { return this._dragIcon; } public function set dragIcon(value:DisplayObject):void { if(this._dragIcon == value) { return; } if(this._dragIcon && this._dragIcon.parent == this._dragIconContainer) { this._dragIcon.removeFromParent(false); } this._dragIcon = value; if(this._dragIcon) { if(!this._dragIconContainer) { this._dragIconContainer = new LayoutGroup(); var layout:HorizontalLayout = new HorizontalLayout(); layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; this._dragIconContainer.layout = layout; this.addChildAt(this._dragIconContainer, 0); } this._dragIconContainer.addChild(this._dragIcon) } this.invalidate(INVALIDATION_FLAG_STYLES); } 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 initialize():void { if(!this.check) { this.check = new Check(); this.check.addEventListener(Event.CHANGE, check_changeHandler); this.addChild(this.check); } if(!this.label) { this.label = new Label(); this.label.layoutData = new HorizontalLayoutData(100); this.addChild(this.label); } if(!this.deleteButton) { this.deleteButton = new Button(); this.deleteButton.styleNameList.add(Button.ALTERNATE_STYLE_NAME_DANGER_BUTTON); this.deleteButton.label = "Delete"; this.deleteButton.addEventListener(Event.TRIGGERED, deleteButton_triggeredHandler); this.addChild(this.deleteButton); } } override protected function preLayout():void { if(this._dragIconContainer) { this.check.validate(); this._dragIconContainer.width = this.check.width; this._dragIconContainer.height = this.check.height; this.setChildIndex(this._dragIconContainer, 0); } } override protected function commitData():void { super.commitData(); var item:TodoItem = this._data as TodoItem; if(!item) { return; } this.label.text = item.description; this.check.isSelected = item.isCompleted; this.check.isEnabled = this._isEnabled; this.check.includeInLayout = !this._dragEnabled; this.check.visible = !this._dragEnabled; this.deleteButton.includeInLayout = this._dragEnabled; this.deleteButton.visible = this._dragEnabled; if(this._dragIconContainer) { this._dragIconContainer.includeInLayout = this._dragEnabled; this._dragIconContainer.visible = this._dragEnabled; } } protected function check_changeHandler(event:Event):void { var item:TodoItem = this._data as TodoItem; if(!item) { return; } var isCompleted:Boolean = this.check.isSelected; if(item.isCompleted == isCompleted) { return; } item.isCompleted = isCompleted; this.dispatchEventWith(Event.CHANGE); } protected function deleteButton_triggeredHandler(event:Event):void { Alert.show("Are you sure that you want to delete this item? This action cannot be undone.", "Confirm delete", new ArrayCollection( [ { label: "Cancel" }, { label: "Delete", triggered: confirmButton_triggeredHandler }, ])); } private function confirmButton_triggeredHandler(event:Event):void { this.dispatchEventWith(EVENT_DELETE_ITEM, false, this._data); } } } ================================================ FILE: examples/TrainTimes/README.md ================================================ # 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. ================================================ FILE: examples/TrainTimes/assets/images/traintimes.tps ================================================ 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 ================================================ FILE: examples/TrainTimes/assets/images/traintimes.xml ================================================ ================================================ FILE: examples/TrainTimes/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/assets/launch-images swf.version = 30 ================================================ FILE: examples/TrainTimes/build.xml ================================================ ================================================ FILE: examples/TrainTimes/source/TrainTimes-app.xml ================================================ com.feathersui.examples.TrainTimes Train Times Train Times 4.2.0 Train Times example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC TrainTimes.swf true false true direct high en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/TrainTimes/source/TrainTimes.as ================================================ package { import feathers.examples.trainTimes.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.system.Capabilities; import flash.utils.ByteArray; 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.showLaunchImage(); this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private var _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/TrainTimes/source/TrainTimesWeb.as ================================================ 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="#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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.trainTimes.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/Main.as ================================================ 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.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(); } } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/controls/StationListItemRenderer.as ================================================ package feathers.examples.trainTimes.controls { import feathers.controls.Button; import feathers.controls.ImageLoader; import feathers.controls.Label; import feathers.controls.LayoutGroup; import feathers.controls.List; 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:LayoutGroup; 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; } /** * @private */ private var _factoryID:String; /** * @inheritDoc */ public function get factoryID():String { return this._factoryID; } /** * @private */ public function set factoryID(value:String):void { this._factoryID = value; } 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); } 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 _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 _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 LayoutGroup(); this.actionContainer.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_ACTION_CONTAINER); 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; this.layout(); } protected function autoSizeIfNeeded():Boolean { var needsWidth:Boolean = isNaN(this._explicitWidth); var needsHeight:Boolean = isNaN(this._explicitHeight); var needsMinWidth:Boolean = isNaN(this._explicitMinWidth); var needsMinHeight:Boolean = isNaN(this._explicitMinHeight); if(!needsWidth && !needsHeight && !needsMinWidth && !needsMinHeight) { 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; } var newMinWidth:Number = this._explicitMinWidth; if(needsMinWidth) { newMinWidth = this.icon.width; newMinWidth += this._paddingLeft + this._paddingRight; } var newMinHeight:Number = this._explicitMinHeight; if(needsMinHeight) { newMinHeight = this.icon.height; } return this.saveMeasurements(newWidth, newHeight, newMinWidth, newMinHeight); } 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 && this._data) { var nameLabelText:String = this._data.name; if(this._isSelected) { nameLabelText += QUESTION_MARK; } this.nameLabel.text = nameLabelText; var displayAsSelected:Boolean = this._isSelected || this._data.isDepartingFromHere; 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 && 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 && 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 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) !== 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; } } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/model/StationData.as ================================================ 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; } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/model/TimeData.as ================================================ 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; } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/screens/StationScreen.as ================================================ 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.data.VectorCollection; import feathers.examples.trainTimes.controls.StationListItemRenderer; 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 static const CHILD_STYLE_NAME_STATION_LIST_ITEM_RENDERER:String = "stationListItemRenderer"; public static const CHILD_STYLE_NAME_STATION_LIST_FIRST_ITEM_RENDERER:String = "stationListFirstItemRenderer"; public static const CHILD_STYLE_NAME_STATION_LIST_LAST_ITEM_RENDERER:String = "stationListLastItemRenderer"; private static const FIRST_ITEM_RENDERER_ID:String = "station-list-first-item-renderer"; private static const LAST_ITEM_RENDERER_ID:String = "station-list-last-item-renderer"; 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 VectorCollection(new [ 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.itemRendererFactory = this.createItemRenderer; this._stationList.setItemRendererFactoryWithID(FIRST_ITEM_RENDERER_ID, this.createFirstItemRenderer); this._stationList.setItemRendererFactoryWithID(LAST_ITEM_RENDERER_ID, this.createLastItemRenderer); this._stationList.factoryIDFunction = this.factoryIDFunction; 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 factoryIDFunction(item:Object, index:int):String { if(index == 0) { return FIRST_ITEM_RENDERER_ID; } else if(index == this._stationList.dataProvider.length - 1) { return LAST_ITEM_RENDERER_ID; } return null; } private function createItemRenderer():StationListItemRenderer { var itemRenderer:StationListItemRenderer = new StationListItemRenderer(); itemRenderer.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_ITEM_RENDERER); itemRenderer.confirmCallback = this.stationList_onConfirm; itemRenderer.isInDestinationPhase = false; return itemRenderer; } private function createFirstItemRenderer():StationListItemRenderer { var itemRenderer:StationListItemRenderer = new StationListItemRenderer(); itemRenderer.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_FIRST_ITEM_RENDERER); itemRenderer.confirmCallback = this.stationList_onConfirm; itemRenderer.isInDestinationPhase = false; return itemRenderer; } private function createLastItemRenderer():StationListItemRenderer { var itemRenderer:StationListItemRenderer = new StationListItemRenderer(); itemRenderer.styleNameList.add(CHILD_STYLE_NAME_STATION_LIST_LAST_ITEM_RENDERER); itemRenderer.confirmCallback = this.stationList_onConfirm; itemRenderer.isInDestinationPhase = false; return itemRenderer; } 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(); } } } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/screens/TimesScreen.as ================================================ package feathers.examples.trainTimes.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.data.VectorCollection; 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 VectorCollection(NORTH_TIMES); this._list.layoutData = new AnchorLayoutData(0, 0, 0, 0); this._list.itemRendererFactory = this.customItemRendererFactory; this.addChild(this._list); this.headerFactory = this.customHeaderFactory; this.backButtonHandler = this.onBackButton; } private function customItemRendererFactory():IListItemRenderer { var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer(); itemRenderer.labelFunction = list_labelFunction; return itemRenderer; } 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(); } } } ================================================ FILE: examples/TrainTimes/source/feathers/examples/trainTimes/themes/TrainTimesTheme.as ================================================ package feathers.examples.trainTimes.themes { import feathers.controls.Button; import feathers.controls.Callout; import feathers.controls.Header; import feathers.controls.Label; import feathers.controls.LayoutGroup; import feathers.controls.List; 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.examples.trainTimes.controls.StationListItemRenderer; import feathers.examples.trainTimes.screens.StationScreen; import feathers.examples.trainTimes.screens.TimesScreen; import feathers.layout.Direction; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.VerticalAlign; import feathers.themes.StyleNameFunctionTheme; import flash.geom.Rectangle; import starling.core.Starling; import starling.display.DisplayObject; import starling.display.Image; import starling.display.Quad; import starling.events.ResizeEvent; import starling.text.TextFormat; import starling.textures.Texture; import starling.textures.TextureAtlas; import starling.utils.Align; 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 HEADER_SCALE9_GRID:Rectangle = new Rectangle(1, 1, 1, 1); protected static const HORIZONTAL_SCROLL_BAR_THUMB_SCALE9_GRID:Rectangle = new Rectangle(3, 0, 7, 4); protected static const VERTICAL_SCROLL_BAR_THUMB_SCALE9_GRID:Rectangle = new Rectangle(0, 3, 4, 7); 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 primaryBackground:Image; 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 mainBackgroundTexture:Texture; protected var headerBackgroundTexture:Texture; 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 horizontalScrollBarThumbSkinTexture:Texture; protected var verticalScrollBarThumbSkinTexture:Texture; 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; } super.dispose(); } protected function initialize():void { this.initializeGlobals(); this.initializeTextures(); this.initializeStage(); this.initializeStyleProviders(); } protected function initializeStage():void { this.primaryBackground = new Image(this.mainBackgroundTexture); this.primaryBackground.tileGrid = new Rectangle(); 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 initializeGlobals():void { FeathersControl.defaultTextRendererFactory = textRendererFactory; FeathersControl.defaultTextEditorFactory = textEditorFactory; PopUpManager.overlayFactory = popUpOverlayFactory; Callout.stagePaddingTop = Callout.stagePaddingRight = Callout.stagePaddingBottom = Callout.stagePaddingLeft = 8; } protected function initializeTextures():void { var atlasTexture:Texture = Texture.fromEmbeddedAsset(ATLAS_IMAGE, false, false, 2); this.atlas = new TextureAtlas(atlasTexture, XML(new ATLAS_XML())); this.mainBackgroundTexture = this.atlas.getTexture("main-background"); this.headerBackgroundTexture = this.atlas.getTexture("header-background"); 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.horizontalScrollBarThumbSkinTexture = this.atlas.getTexture("horizontal-scroll-bar-thumb-skin"); this.verticalScrollBarThumbSkinTexture = this.atlas.getTexture("vertical-scroll-bar-thumb-skin"); //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, 18, PRIMARY_TEXT_COLOR, Align.LEFT, Align.TOP); this.selectedTextFormat = new TextFormat(boldFontName, 18, PRIMARY_TEXT_COLOR, Align.LEFT, Align.TOP); this.selectedTextFormat.bold = true; this.headerTitleTextFormat = new TextFormat(regularFontName, 18, PRIMARY_TEXT_COLOR, Align.LEFT, Align.TOP); this.stationListNameTextFormat = new TextFormat(boldItalicFontName, 24, PRIMARY_TEXT_COLOR, Align.LEFT, Align.TOP); this.stationListNameTextFormat.bold = true; this.stationListNameTextFormat.italic = true; this.stationListDetailTextFormat = new TextFormat(boldFontName, 12, DETAIL_TEXT_COLOR, Align.LEFT, Align.TOP); this.stationListDetailTextFormat.bold = true; this.stationListDetailTextFormat.letterSpacing = 3; } 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).setFunctionForStyleName(StationScreen.CHILD_STYLE_NAME_STATION_LIST_ITEM_RENDERER, setStationListItemRendererStyles); this.getStyleProviderForClass(StationListItemRenderer).setFunctionForStyleName(StationScreen.CHILD_STYLE_NAME_STATION_LIST_FIRST_ITEM_RENDERER, setStationListFirstItemRendererStyles); this.getStyleProviderForClass(StationListItemRenderer).setFunctionForStyleName(StationScreen.CHILD_STYLE_NAME_STATION_LIST_LAST_ITEM_RENDERER, setStationListLastItemRendererStyles); this.getStyleProviderForClass(LayoutGroup).setFunctionForStyleName(StationListItemRenderer.CHILD_STYLE_NAME_STATION_LIST_ACTION_CONTAINER, setActionContainerStyles); } protected function horizontalScrollBarFactory():SimpleScrollBar { var scrollBar:SimpleScrollBar = new SimpleScrollBar(); scrollBar.direction = Direction.HORIZONTAL; var defaultSkin:Image = new Image(this.horizontalScrollBarThumbSkinTexture); defaultSkin.scale9Grid = HORIZONTAL_SCROLL_BAR_THUMB_SCALE9_GRID; defaultSkin.width = 5; scrollBar.thumbProperties.defaultSkin = defaultSkin; scrollBar.paddingRight = scrollBar.paddingBottom = scrollBar.paddingLeft = 2; return scrollBar; } protected function verticalScrollBarFactory():SimpleScrollBar { var scrollBar:SimpleScrollBar = new SimpleScrollBar(); scrollBar.direction = Direction.VERTICAL; var defaultSkin:Image = new Image(this.verticalScrollBarThumbSkinTexture); defaultSkin.scale9Grid = VERTICAL_SCROLL_BAR_THUMB_SCALE9_GRID; defaultSkin.height = 5; scrollBar.thumbProperties.defaultSkin = defaultSkin; scrollBar.paddingTop = scrollBar.paddingRight = scrollBar.paddingBottom = 2; return scrollBar; } protected function setNoStyles(target:DisplayObject):void {} protected function setLabelStyles(label:Label):void { label.fontStyles = this.defaultTextFormat; } protected function setStationListNameLabelStyles(label:Label):void { label.fontStyles = this.stationListNameTextFormat; } protected function setStationListDetailLabelStyles(label:Label):void { label.fontStyles = this.stationListDetailTextFormat; } protected function setButtonStyles(button:Button):void { var defaultIcon:Image = new Image(this.backIconTexture); button.defaultIcon = defaultIcon; button.minWidth = button.minHeight = 22; button.minTouchWidth = button.minTouchHeight = 44; } protected function setConfirmButtonStyles(button:Button):void { var defaultIcon:Image = new Image(this.confirmIconTexture); button.defaultIcon = defaultIcon; button.minWidth = button.minHeight = 22; button.minTouchWidth = button.minTouchHeight = 44; } protected function setCancelButtonStyles(button:Button):void { var defaultIcon:Image = new Image(this.cancelIconTexture); button.defaultIcon = defaultIcon; button.minWidth = button.minHeight = 22; button.minTouchWidth = button.minTouchHeight = 44; } protected function setHeaderStyles(header:Header):void { header.useExtraPaddingForOSStatusBar = true; header.minWidth = 44; header.minHeight = 44; header.padding = 7; header.titleAlign = HorizontalAlign.RIGHT; var backgroundSkin:Image = new Image(this.headerBackgroundTexture); backgroundSkin.scale9Grid = HEADER_SCALE9_GRID; header.backgroundSkin = backgroundSkin; header.fontStyles = this.headerTitleTextFormat; } protected function setStationListStyles(list:List):void { list.horizontalScrollBarFactory = this.horizontalScrollBarFactory; list.verticalScrollBarFactory = this.verticalScrollBarFactory; } protected function setTimesListStyles(list:List):void { list.horizontalScrollBarFactory = this.horizontalScrollBarFactory; list.verticalScrollBarFactory = this.verticalScrollBarFactory; list.customItemRendererStyleName = TIMES_LIST_ITEM_RENDERER_NAME; } protected function setTimesListItemRendererStyles(renderer:DefaultListItemRenderer):void { var defaultSkin:Quad = new Quad(44, 44, 0xff00ff); defaultSkin.alpha = 0; renderer.defaultSkin = defaultSkin; var defaultSelectedSkin:Quad = new Quad(44, 44, 0xcc2a41); renderer.defaultSelectedSkin = defaultSelectedSkin; renderer.fontStyles = this.defaultTextFormat; renderer.selectedFontStyles = this.selectedTextFormat; renderer.paddingLeft = 4; renderer.paddingRight = 8; } protected function setStationListItemRendererStyles(renderer:StationListItemRenderer):void { renderer.paddingLeft = 22; renderer.paddingRight = 16; renderer.normalIconTexture = this.stationListNormalIconTexture; renderer.selectedIconTexture = this.stationListSelectedIconTexture; } protected function setStationListFirstItemRendererStyles(renderer:StationListItemRenderer):void { renderer.paddingLeft = 22; renderer.paddingRight = 16; renderer.normalIconTexture = this.stationListFirstNormalIconTexture; renderer.selectedIconTexture = this.stationListFirstSelectedIconTexture; } protected function setStationListLastItemRendererStyles(renderer:StationListItemRenderer):void { renderer.paddingLeft = 22; renderer.paddingRight = 16; renderer.normalIconTexture = this.stationListLastNormalIconTexture; renderer.selectedIconTexture = this.stationListLastSelectedIconTexture; } protected function setActionContainerStyles(container:LayoutGroup):void { var backgroundSkin:Quad = new Quad(24, 24, 0xcc2a41); container.backgroundSkin = backgroundSkin; var layout:HorizontalLayout = new HorizontalLayout(); layout.paddingRight = 16; layout.gap = 24; layout.horizontalAlign = HorizontalAlign.CENTER; layout.verticalAlign = VerticalAlign.MIDDLE; container.layout = layout; } protected function stage_resizeHandler(event:ResizeEvent):void { this.primaryBackground.width = event.width; this.primaryBackground.height = event.height; } } } ================================================ FILE: examples/TransitionsExplorer/README.md ================================================ # Feathers Transitions Explorer Each of the animated transitions available for the [Feathers](http://feathersui.com/) [`StackScreenNavigator`](http://feathersui.com/help/stack-screen-navigator.html) and [`ScreenNavigator`](http://feathersui.com/help/screen-navigator.html)components, presented as a mobile app. ## Requirements In addition to Starling Framework 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 [Transitions Explorer](http://feathersui.com/examples/transitions-explorer/) in your browser. ================================================ FILE: examples/TransitionsExplorer/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/assets/launch-images swf.version = 30 ================================================ FILE: examples/TransitionsExplorer/build.xml ================================================ ================================================ FILE: examples/TransitionsExplorer/source/TransitionsExplorer-app.xml ================================================ com.feathersui.examples.TransitionsExplorer Transitions Transitions 4.2.0 Transitions Explorer example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC TransitionsExplorer.swf landscape true true direct true en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/TransitionsExplorer/source/TransitionsExplorer.as ================================================ package { import feathers.examples.transitionsExplorer.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private function showLaunchImage():void { var filePath:String; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6 plus filePath = "Default-414w-736h-Landscape@3x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad retina filePath = "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad classic filePath = "Default-Landscape.png"; } else if(Capabilities.screenResolutionX == 750) { //iphone 6 isPortraitOnly = true; filePath = "Default-375w-667h@2x.png"; } else if(Capabilities.screenResolutionX == 640) { //iphone retina isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { filePath = "Default-568h@2x.png"; } else { filePath = "Default@2x.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone classic 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); if(isPortraitOnly) { this._launchImage.rotation = -90; this._launchImage.y = Capabilities.screenResolutionX; } this.addChild(this._launchImage); } } } private function loaderInfo_completeHandler(event:Event):void { Starling.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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; } } private function stage_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/TransitionsExplorer/source/TransitionsExplorerWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.transitionsExplorer.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/Main.as ================================================ package feathers.examples.transitionsExplorer { import feathers.controls.AutoSizeMode; 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.examples.transitionsExplorer.screens.IrisTransitionScreen; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.motion.Cover; import feathers.motion.Cube; import feathers.motion.Flip; import feathers.motion.Reveal; import feathers.motion.Slide; import feathers.motion.Wipe; 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_IRIS:String = "iris"; private static const MENU_SCREEN_ID_REVEAL:String = "reveal"; private static const MENU_SCREEN_ID_SLIDE:String = "slide"; private static const MENU_SCREEN_ID_WIPE:String = "wipe"; private static const CONTENT_SCREEN_ID_ONE:String = "one"; private static const CONTENT_SCREEN_ID_TWO:String = "two"; public function Main() { //set up the theme right away! new MetalWorksMobileTheme(); super(); this.autoSizeMode = AutoSizeMode.STAGE; } private var _menu:StackScreenNavigator; private var _content:ScreenNavigator; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.layout = new AnchorLayout(); this._menu = new StackScreenNavigator(); this._menu.autoSizeMode = AutoSizeMode.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.IRIS, MENU_SCREEN_ID_IRIS); allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.REVEAL, MENU_SCREEN_ID_REVEAL); allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.SLIDE, MENU_SCREEN_ID_SLIDE); allTransitionsItem.setScreenIDForPushEvent(AllTransitionsScreen.WIPE, MENU_SCREEN_ID_WIPE); this._menu.addScreen(MENU_SCREEN_ID_ALL_TRANSITIONS, allTransitionsItem); var colorFadeItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(ColorFadeTransitionScreen); colorFadeItem.setFunctionForPushEvent(ColorFadeTransitionScreen.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 irisItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(IrisTransitionScreen); irisItem.setFunctionForPushEvent(IrisTransitionScreen.TRANSITION, transitionHandler); irisItem.addPopEvent(Event.COMPLETE); this._menu.addScreen(MENU_SCREEN_ID_IRIS, irisItem); 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); var wipeItem:StackScreenNavigatorItem = new StackScreenNavigatorItem(FourWayTransitionScreen); wipeItem.properties.transitionName = "Wipe"; wipeItem.properties.leftTransition = Wipe.createWipeLeftTransition(); wipeItem.properties.rightTransition = Wipe.createWipeRightTransition(); wipeItem.properties.upTransition = Wipe.createWipeUpTransition(); wipeItem.properties.downTransition = Wipe.createWipeDownTransition(); wipeItem.setFunctionForPushEvent(FourWayTransitionScreen.TRANSITION, transitionHandler); wipeItem.addPopEvent(Event.COMPLETE); this._menu.addScreen(MENU_SCREEN_ID_WIPE, wipeItem); 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); } } } ================================================ FILE: examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/AllTransitionsScreen.as ================================================ package feathers.examples.transitionsExplorer.screens { import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.ArrayCollection; import feathers.data.ListCollection; import feathers.events.FeathersEventType; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import starling.events.Event; 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 IRIS:String = "iris"; public static const REVEAL:String = "reveal"; public static const SLIDE:String = "slide"; public static const WIPE:String = "wipe"; 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 ArrayCollection( [ { label: "Color Fade", event: COLOR_FADE }, { label: "Cover", event: COVER }, { label: "Fade", event: FADE }, { label: "Cube", event: CUBE }, { label: "Flip", event: FLIP }, { label: "Iris", event: IRIS }, { label: "Reveal", event: REVEAL }, { label: "Slide", event: SLIDE }, { label: "Wipe", event: WIPE }, ]); 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 = this.createItemRenderer; this._list.addEventListener(Event.TRIGGERED, list_triggeredHandler); this.addChild(this._list); this.addEventListener(FeathersEventType.TRANSITION_IN_COMPLETE, transitionInCompleteHandler); } private function createItemRenderer():IListItemRenderer { var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); renderer.styleNameList.add(DefaultListItemRenderer.ALTERNATE_STYLE_NAME_DRILL_DOWN); //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; }; 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 }); } } } ================================================ FILE: examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/ColorFadeTransitionScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.motion.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 ArrayCollection( [ { label: "Black", transition: ColorFade.createBlackFadeTransition() }, { 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); } } } ================================================ FILE: examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FadeTransitionScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.motion.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 ArrayCollection( [ { 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); } } } ================================================ FILE: examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/FourWayTransitionScreen.as ================================================ 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.ArrayCollection; 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 ArrayCollection( [ { 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); } } } ================================================ FILE: examples/TransitionsExplorer/source/feathers/examples/transitionsExplorer/screens/IrisTransitionScreen.as ================================================ 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.ArrayCollection; import feathers.data.ListCollection; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.motion.Iris; import starling.display.DisplayObject; import starling.events.Event; public class IrisTransitionScreen extends PanelScreen { private static function irisCloseAtRandomPosition(oldScreen:DisplayObject, newScreen:DisplayObject, completeCallback:Function):void { var randomX:Number = Math.random() * (oldScreen ? oldScreen.width : newScreen.width); var randomY:Number = Math.random() * (oldScreen ? oldScreen.height : newScreen.height); Iris.createIrisCloseTransitionAt(randomX, randomY)(oldScreen, newScreen, completeCallback); } private static function irisOpenAtRandomPosition(oldScreen:DisplayObject, newScreen:DisplayObject, completeCallback:Function):void { var randomX:Number = Math.random() * (oldScreen ? oldScreen.width : newScreen.width); var randomY:Number = Math.random() * (oldScreen ? oldScreen.height : newScreen.height); Iris.createIrisOpenTransitionAt(randomX, randomY)(oldScreen, newScreen, completeCallback); } public static const TRANSITION:String = "transition"; public function IrisTransitionScreen() { super(); } private var _list:List; private var _backButton:Button; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); this.title = "Iris"; this.layout = new AnchorLayout(); this._list = new List(); this._list.dataProvider = new ArrayCollection( [ { label: "Iris Open", transition: Iris.createIrisOpenTransition() }, { label: "Iris Close", transition: Iris.createIrisCloseTransition() }, { label: "Iris Open At", transition: irisOpenAtRandomPosition }, { label: "Iris Close At", transition: irisCloseAtRandomPosition }, ]); 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); } } } ================================================ FILE: examples/Video/README.md ================================================ # Feathers Video Example A simple example of the [`VideoPlayer`](http://feathersui.com/help/video-player.html) component from [Feathers](http://feathersui.com/), presented as a desktop application. ## Requirements In addition to Starling Framework and Feathers, this example project requires the `MetalWorksDesktopTheme` example theme. You can find the SWC file for this theme at the following location in the Feathers release build: themes/MetalWorksDesktopTheme/swc/MetalWorksDesktopTheme.swc ================================================ FILE: examples/Video/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksDesktopTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons swf.version = 30 ================================================ FILE: examples/Video/build.xml ================================================ ================================================ FILE: examples/Video/source/Video-app.xml ================================================ com.feathersui.examples.Video Feathers Video Feathers Video 4.2.0 Video example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC Video.swf true true true true direct 480 320 480 320 high en icon48.png icon128.png ================================================ FILE: examples/Video/source/Video.as ================================================ package { import feathers.examples.video.Main; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.geom.Rectangle; import starling.core.Starling; [SWF(width="960",height="640",frameRate="60",backgroundColor="#4a4137")] public class Video extends Sprite { public function Video() { 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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.start(); this.stage.addEventListener(Event.RESIZE, stage_resizeHandler, false, int.MAX_VALUE, 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) {} } } } ================================================ FILE: examples/Video/source/feathers/examples/video/Main.as ================================================ package feathers.examples.video { import feathers.controls.Alert; import feathers.controls.AutoSizeMode; import feathers.controls.ImageLoader; import feathers.controls.LayoutGroup; import feathers.data.ArrayCollection; import feathers.data.ListCollection; import feathers.events.FeathersEventType; import feathers.events.MediaPlayerEventType; import feathers.layout.AnchorLayout; import feathers.layout.AnchorLayoutData; import feathers.layout.HorizontalLayoutData; import feathers.media.FullScreenToggleButton; import feathers.media.MuteToggleButton; import feathers.media.PlayPauseToggleButton; import feathers.media.SeekSlider; import feathers.media.VideoPlayer; import feathers.themes.MetalWorksDesktopTheme; import flash.desktop.NativeApplication; import flash.display.NativeMenu; import flash.display.NativeMenuItem; import flash.events.ContextMenuEvent; import flash.filesystem.File; import flash.net.FileFilter; import starling.core.Starling; import starling.display.Sprite; import starling.events.Event; public class Main extends Sprite { public function Main() { new MetalWorksDesktopTheme(); super(); this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); } protected var _videoPlayer:VideoPlayer protected var _controls:LayoutGroup; protected var _playPauseButton:PlayPauseToggleButton; protected var _seekSlider:SeekSlider; protected var _muteButton:MuteToggleButton; protected var _fullScreenButton:FullScreenToggleButton; protected var _view:ImageLoader; protected var _fullScreenItem:NativeMenuItem; protected var _fileToOpen:File; private function addedToStageHandler(event:Event):void { this.createMenu(); this._videoPlayer = new VideoPlayer(); this._videoPlayer.autoSizeMode = AutoSizeMode.STAGE; this._videoPlayer.layout = new AnchorLayout(); this._videoPlayer.addEventListener(Event.READY, videoPlayer_readyHandler); this._videoPlayer.addEventListener(FeathersEventType.CLEAR, videoPlayer_clearHandler); this._videoPlayer.addEventListener(MediaPlayerEventType.DISPLAY_STATE_CHANGE, videoPlayer_displayStateChangeHandler); this._videoPlayer.addEventListener(Event.IO_ERROR, videoPlayer_errorHandler); this._videoPlayer.addEventListener(FeathersEventType.ERROR, videoPlayer_errorHandler); this.addChild(this._videoPlayer); this._view = new ImageLoader(); this._videoPlayer.addChild(this._view); this._controls = new LayoutGroup(); this._controls.touchable = false; this._controls.styleNameList.add(LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR); this._videoPlayer.addChild(this._controls); this._playPauseButton = new PlayPauseToggleButton(); this._controls.addChild(this._playPauseButton); this._seekSlider = new SeekSlider(); this._seekSlider.layoutData = new HorizontalLayoutData(100); this._controls.addChild(this._seekSlider); this._muteButton = new MuteToggleButton(); this._controls.addChild(this._muteButton); this._fullScreenButton = new FullScreenToggleButton(); this._controls.addChild(this._fullScreenButton); var controlsLayoutData:AnchorLayoutData = new AnchorLayoutData(); controlsLayoutData.left = 0; controlsLayoutData.right = 0; controlsLayoutData.bottom = 0; this._controls.layoutData = controlsLayoutData; var viewLayoutData:AnchorLayoutData = new AnchorLayoutData(0, 0, 0, 0); viewLayoutData.bottomAnchorDisplayObject = this._controls; this._view.layoutData = viewLayoutData; } protected function createMenu():void { var menu:NativeMenu; if(NativeApplication.supportsMenu) { menu = NativeApplication.nativeApplication.menu; var applicationMenuItem:NativeMenuItem = menu.getItemAt(0); menu.removeAllItems(); menu.addItem(applicationMenuItem); } else { menu = new NativeMenu(); Starling.current.nativeStage.nativeWindow.menu = menu; } var fileMenuItem:NativeMenuItem = new NativeMenuItem("File"); var fileMenu:NativeMenu = new NativeMenu(); fileMenuItem.submenu = fileMenu; menu.addItem(fileMenuItem); var openItem:NativeMenuItem = new NativeMenuItem("Open"); openItem.keyEquivalent = "o"; openItem.addEventListener(flash.events.Event.SELECT, openItem_selectHandler); fileMenu.addItem(openItem); var closeItem:NativeMenuItem = new NativeMenuItem("Close"); closeItem.keyEquivalent = "w"; closeItem.addEventListener(flash.events.Event.SELECT, closeItem_selectHandler); fileMenu.addItem(closeItem); var viewMenuItem:NativeMenuItem = new NativeMenuItem("View"); var viewMenu:NativeMenu = new NativeMenu(); viewMenuItem.submenu = viewMenu; menu.addItem(viewMenuItem); this._fullScreenItem = new NativeMenuItem("Enter Full Screen"); this._fullScreenItem.keyEquivalent = "f"; this._fullScreenItem.addEventListener(flash.events.Event.SELECT, fullScreenItem_selectHandler); viewMenu.addItem(this._fullScreenItem); if(NativeApplication.supportsMenu) { var windowMenuItem:NativeMenuItem = new NativeMenuItem("Window"); var windowMenu:NativeMenu = new NativeMenu(); windowMenuItem.submenu = windowMenu; menu.addItem(windowMenuItem); var minimizeItem:NativeMenuItem = new NativeMenuItem("Minimize"); minimizeItem.keyEquivalent = "m"; minimizeItem.addEventListener(flash.events.Event.SELECT, minimizeItem_selectHandler); windowMenu.addItem(minimizeItem); var zoomItem:NativeMenuItem = new NativeMenuItem("Zoom"); zoomItem.addEventListener(flash.events.Event.SELECT, zoomItem_selectHandler); windowMenu.addItem(zoomItem); } } protected function videoPlayer_readyHandler(event:Event):void { this._view.source = this._videoPlayer.texture; this._controls.touchable = true; } protected function videoPlayer_clearHandler(event:Event):void { this._view.source = null; this._controls.touchable = false; } protected function videoPlayer_displayStateChangeHandler(event:Event):void { this._fullScreenItem.label = this._videoPlayer.isFullScreen ? "Exit Full Screen" : "Enter Full Screen"; } protected function videoPlayer_errorHandler(event:Event):void { Alert.show("Cannot play selected video.", "Video Error", new ArrayCollection([{ label: "OK" }])); trace("VideoPlayer Error: " + event.data); } protected function openItem_selectHandler(event:flash.events.Event):void { this._fileToOpen = new File(); this._fileToOpen.addEventListener(flash.events.Event.SELECT, fileToOpen_selectHandler); this._fileToOpen.addEventListener(flash.events.Event.CANCEL, fileToOpen_cancelHandler); this._fileToOpen.browseForOpen("Select video file", [ new FileFilter("Video files", "*.m4v;*.mp4;*.f4v;*.flv;*.mov") ]); } protected function closeItem_selectHandler(event:flash.events.Event):void { //we don't need to dispose the texture here. the VideoPlayer will //do it automatically when videoSource is changed. this._view.source = null; this._videoPlayer.videoSource = null; this._controls.touchable = false; } protected function fileToOpen_cancelHandler(event:flash.events.Event):void { this._fileToOpen.removeEventListener(flash.events.Event.SELECT, fileToOpen_selectHandler); this._fileToOpen.removeEventListener(flash.events.Event.CANCEL, fileToOpen_cancelHandler); this._fileToOpen = null; } protected function fileToOpen_selectHandler(event:flash.events.Event):void { if(this._videoPlayer.videoSource === this._fileToOpen.url) { //it's the same file, so just start it over instead of trying //to load it again! this._videoPlayer.stop(); this._videoPlayer.play(); return; } this._controls.touchable = false; this._videoPlayer.videoSource = this._fileToOpen.url; this._fileToOpen.removeEventListener(flash.events.Event.SELECT, fileToOpen_selectHandler); this._fileToOpen.removeEventListener(flash.events.Event.CANCEL, fileToOpen_cancelHandler); this._fileToOpen = null; } protected function fullScreenItem_selectHandler(event:flash.events.Event):void { this._videoPlayer.toggleFullScreen(); } protected function minimizeItem_selectHandler(event:flash.events.Event):void { Starling.current.nativeStage.nativeWindow.minimize(); } protected function zoomItem_selectHandler(event:flash.events.Event):void { Starling.current.nativeStage.nativeWindow.maximize(); } } } ================================================ FILE: examples/YouTubeFeeds/README.md ================================================ # 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 Framework 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. ================================================ FILE: examples/YouTubeFeeds/build.properties ================================================ feathers.root = ${basedir}/../../source starling.root = ${basedir}/../../third-party/starling theme.root = ${basedir}/../../themes/MetalWorksMobileTheme/source output.path = ${basedir}/output icon.path = ${basedir}/../shared-assets/icons launch.image.path = ${basedir}/../shared-assets/launch-images-windowed swf.version = 30 ================================================ FILE: examples/YouTubeFeeds/build.xml ================================================ ================================================ FILE: examples/YouTubeFeeds/source/YouTubeFeeds-app.xml ================================================ com.feathersui.examples.YouTubeFeeds YouTube Feeds YouTube Feeds 4.2.0 YouTube Feeds example application built with Feathers UI controls for Starling 2021 Bowler Hat LLC YouTubeFeeds.swf true false true direct en icon29.png icon48.png icon50.png icon57.png icon58.png icon72.png icon87.png icon96.png icon100.png icon114.png icon128.png icon144.png icon180.png 16bit ]]> UIDeviceFamily 1 2 UIPrerenderedIcon UIStatusBarStyle UIStatusBarStyleLightContent ]]> high ================================================ FILE: examples/YouTubeFeeds/source/YouTubeFeeds.as ================================================ package { import feathers.examples.youtube.Main; import feathers.utils.ScreenDensityScaleFactorManager; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageOrientation; import flash.display.StageScaleMode; import flash.display3D.Context3DProfile; import flash.display3D.Context3DRenderMode; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; 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 _scaler:ScreenDensityScaleFactorManager; private var _launchImage:Loader; private var _savedAutoOrients:Boolean; /** * On iOS, add the native launch image to the classic display list to * avoid displaying only the stage background color between when the * AIR app finishes launching and Starling starts rendering. * * Launch image names: https://forums.adobe.com/message/9986239#9986239 */ private function showLaunchImage():void { var filePath:String = null; var isPortraitOnly:Boolean = false; if(Capabilities.manufacturer.indexOf("iOS") >= 0) { var isPortraitUpsideDown:Boolean = this.stage.orientation == StageOrientation.UPSIDE_DOWN; var isPortrait:Boolean = this.stage.orientation == StageOrientation.DEFAULT || isPortraitUpsideDown; var isLandscapeRight:Boolean = this.stage.orientation == StageOrientation.ROTATED_RIGHT; if(Capabilities.screenResolutionX == 1242 && Capabilities.screenResolutionY == 2208) { //iphone 6/7/8 plus filePath = isPortrait ? "Default-414w-736h@3x~iphone.png" : "Default-Landscape-414w-736h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 1125 && Capabilities.screenResolutionY == 2436) { //iphone x filePath = isPortrait ? "Default-812h@3x~iphone.png" : "Default-Landscape-812h@3x~iphone.png"; } else if(Capabilities.screenResolutionX == 2048 && Capabilities.screenResolutionY == 2732) { //ipad pro filePath = isPortrait ? "Default-Portrait@2x.png" : "Default-Landscape@2x.png"; } else if(Capabilities.screenResolutionX == 1536 && Capabilities.screenResolutionY == 2048) { //ipad 3/air if(isPortraitUpsideDown) { filePath = "Default-Portrait@2x~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown@2x~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight@2x~ipad.png"; } else { filePath = "Default-LandscapeLeft@2x~ipad.png"; } } else if(Capabilities.screenResolutionX == 768 && Capabilities.screenResolutionY == 1024) { //ipad 1/2 if(isPortraitUpsideDown) { filePath = "Default-Portrait~ipad.png"; } else if(isPortrait) { filePath = "Default-PortraitUpsideDown~ipad.png"; } else if(isLandscapeRight) { filePath = "Default-LandscapeRight~ipad.png"; } else { filePath = "Default-Landscape~ipad.png"; } } else if(Capabilities.screenResolutionX == 750) { //iphone 6/7/8 isPortraitOnly = true; filePath = "Default-375w-667h@2x~iphone.png"; } else if(Capabilities.screenResolutionX == 640) { isPortraitOnly = true; if(Capabilities.screenResolutionY == 1136) { //iphone 5/5c/5s filePath = "Default-568h@2x~iphone.png"; } else { //iphone 4/4s filePath = "Default@2x~iphone.png"; } } else if(Capabilities.screenResolutionX == 320) { //iphone 3gs isPortraitOnly = true; filePath = "Default~iphone.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.multitouchEnabled = true; this._starling = new Starling(Main, this.stage, null, null, Context3DRenderMode.AUTO, Context3DProfile.BASELINE); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.start(); if(this._launchImage) { this._starling.addEventListener("rootCreated", starling_rootCreatedHandler); } this._scaler = new ScreenDensityScaleFactorManager(this._starling); 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_deactivateHandler(event:Event):void { this._starling.stop(true); 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(); } } } ================================================ FILE: examples/YouTubeFeeds/source/YouTubeFeedsWeb.as ================================================ 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 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; } this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler); } private var _starling:Starling; private function start():void { this.gotoAndStop(2); this.graphics.clear(); //simulating iPhone Retina DeviceCapabilities.dpi = 326; Starling.multitouchEnabled = true; var MainType:Class = getDefinitionByName("feathers.examples.youtube.Main") as Class; this._starling = new Starling(MainType, this.stage, new Rectangle(0, 0, 960, 640)); this._starling.supportHighResolutions = true; this._starling.skipUnchangedFrames = true; this._starling.stage.stageWidth = 480; this._starling.stage.stageHeight = 320; this._starling.start(); } private function loaderInfo_completeHandler(event:Event):void { this.start(); } } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/Main.as ================================================ package feathers.examples.youtube { import feathers.controls.StackScreenNavigator; import feathers.controls.StackScreenNavigatorItem; 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.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() { //set up the theme right away! new MetalWorksMobileTheme(); super(); } private var _model:YouTubeModel; override protected function initialize():void { //never forget to call super.initialize() super.initialize(); 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); } } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoDetails.as ================================================ package feathers.examples.youtube.models { public class VideoDetails { public function VideoDetails(title:String = null, author:String = null, url:String = null, description:String = null, thumbnailURL:String = null) { this.title = title; this.author = author; this.url = url; this.description = description; this.thumbnailURL = thumbnailURL; } public var title:String; public var author:String; public var url:String; public var description:String; public var thumbnailURL:String; } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/models/VideoFeed.as ================================================ 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; } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/models/YouTubeModel.as ================================================ package feathers.examples.youtube.models { public class YouTubeModel { public var selectedList:VideoFeed; public var selectedVideo:VideoDetails; public var cachedLists:Object = {}; } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/screens/ListVideosScreen.as ================================================ 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.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.VectorCollection; 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.URLLoaderDataFormat; import flash.net.URLRequest; import flash.system.Capabilities; import starling.core.Starling; import starling.display.DisplayObject; import starling.display.Stage; 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"; private static const YOUTUBE_VIDEO_URL:String = "https://www.youtube.com/watch?v="; 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:VectorCollection; private var _loader:URLLoader; private var _savedResult:Object; 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 = VectorCollection(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.dataFormat = URLLoaderDataFormat.TEXT; 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 parseListVideosResult(result:Object):void { this._message.visible = false; var stage:Stage = Starling.current.stage; var useHighQualityThumbnail:Boolean = Math.min(stage.stageWidth, stage.stageHeight) > 350; var useHTTP:Boolean = Capabilities.playerType !== "Desktop"; var items:Vector. = new []; var videos:Array = result.items as Array; var videoCount:int = videos.length; for(var i:int = 0; i < videoCount; i++) { var video:Object = videos[i]; var item:VideoDetails = new VideoDetails(); item.title = video.snippet.title as String; item.author = video.snippet.channelTitle as String; item.url = YOUTUBE_VIDEO_URL + video.id as String; item.description = video.snippet.description as String; if("thumbnails" in video.snippet) { if(useHighQualityThumbnail) { item.thumbnailURL = video.snippet.thumbnails.high.url as String; } else { item.thumbnailURL = video.snippet.thumbnails.medium.url as String; } //switch from https to http if we're not running in AIR if(useHTTP && item.thumbnailURL.indexOf("https") == 0) { item.thumbnailURL = "http" + item.thumbnailURL.substr(5); } } items.push(item); } var collection:VectorCollection = new VectorCollection(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._savedResult) { this.parseListVideosResult(this._savedResult); this._savedResult = 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:String = this._loader.data as String; this.cleanUpLoader(); try { var result:Object = JSON.parse(loaderData); if(this._isTransitioning) { //if this screen is still transitioning in, the we'll save //the result until later to ensure that the animation isn't //affected. this._savedResult = result; return; } this.parseListVideosResult(result); } catch(error:Error) { this._message.text = "Unable to read video list. Please try again later."; this._message.visible = true; this.invalidate(INVALIDATION_FLAG_STYLES); trace(error.toString()); return; } } private function loader_errorHandler(event:ErrorEvent):void { this.cleanUpLoader(); this._message.text = "Unable to load video list. Please try again later."; this._message.visible = true; this.invalidate(INVALIDATION_FLAG_STYLES); trace(event.toString()); } } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/screens/MainMenuScreen.as ================================================ package feathers.examples.youtube.screens { import feathers.controls.Label; import feathers.controls.List; import feathers.controls.PanelScreen; import feathers.controls.renderers.DefaultListItemRenderer; import feathers.controls.renderers.IListItemRenderer; import feathers.data.VectorCollection; import feathers.events.FeathersEventType; import feathers.examples.youtube.models.VideoFeed; 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.URLLoaderDataFormat; import flash.net.URLRequest; import starling.events.Event; [Event(name="listVideos",type="starling.events.Event")] public class MainMenuScreen extends PanelScreen { public static const LIST_VIDEOS:String = "listVideos"; private static const PART_PARAMETER:String = "?part=snippet"; //must be first private static const CHART_PARAMETER:String = "&chart=mostPopular"; private static const REGION_CODE_PARAMETER:String = "®ionCode=US"; private static const MAX_RESULTS_PARAMETER:String = "&maxResults=25"; private static const VIDEO_CATEGORY_ID_PARAMETER:String = "&videoCategoryId="; private static const KEY_PARAMETER:String = "&key=" + CONFIG::YOUTUBE_API_KEY; private static const FIELDS_PARAMETER:String = "&fields=items%2Fid%2Citems%2Fsnippet%2Ftitle%2Citems%2Fsnippet%2FchannelTitle%2Citems%2Fsnippet%2Fdescription%2Citems%2Fsnippet%2Fthumbnails"; private static const LIST_CATEGORIES_URL:String = "https://www.googleapis.com/youtube/v3/videoCategories" + PART_PARAMETER + REGION_CODE_PARAMETER + KEY_PARAMETER; private static const LIST_VIDEOS_IN_CATEGORY_URL:String = "https://www.googleapis.com/youtube/v3/videos" + PART_PARAMETER + CHART_PARAMETER + REGION_CODE_PARAMETER + MAX_RESULTS_PARAMETER + FIELDS_PARAMETER + KEY_PARAMETER + VIDEO_CATEGORY_ID_PARAMETER; 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:VectorCollection; 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 = this.createItemRenderer; //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.dataFormat = URLLoaderDataFormat.TEXT; 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(LIST_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 parseListVideoCategoriesResult(result:Object):void { this._message.visible = false; var items:Vector. = new []; var categories:Array = result.items as Array; var categoryCount:int = categories.length; for(var i:int = 0; i < categoryCount; i++) { var category:Object = categories[i]; var assignable:Boolean = category.snippet.assignable as Boolean; if(!assignable) { continue; } var item:VideoFeed = new VideoFeed(); item.name = category.snippet.title as String; var categoryID:String = category.id as String; item.url = LIST_VIDEOS_IN_CATEGORY_URL + categoryID; items.push(item); } var collection:VectorCollection = new VectorCollection(items); this._list.dataProvider = collection; //show the scroll bars so that the user knows they can scroll this._list.revealScrollBars(); } private function createItemRenderer():IListItemRenderer { var renderer:DefaultListItemRenderer = new DefaultListItemRenderer(); renderer.styleNameList.add(DefaultListItemRenderer.ALTERNATE_STYLE_NAME_DRILL_DOWN); //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"; return renderer; } 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:String = this._loader.data as String; this.parseListVideoCategoriesResult(JSON.parse(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()); } } } ================================================ FILE: examples/YouTubeFeeds/source/feathers/examples/youtube/screens/VideoDetailsScreen.as ================================================ package feathers.examples.youtube.screens { import feathers.controls.Button; import feathers.controls.Header; import feathers.controls.ImageLoader; import feathers.controls.PanelScreen; import feathers.controls.ScrollPolicy; 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; import starling.utils.ScaleMode; [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 _thumbnail:ImageLoader; private var _portraitThumbnailLayoutData:AnchorLayoutData; private var _landscapeThumbnailLayoutData:AnchorLayoutData; private var _scrollText:ScrollText; private var _portraitTextLayoutData:AnchorLayoutData; private var _landscapeTextLayoutData:AnchorLayoutData; 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._thumbnail = new ImageLoader(); this._thumbnail.scaleMode = ScaleMode.NO_BORDER; this._thumbnail.layoutData = new AnchorLayoutData(0, 0, NaN, 0); this.addChild(this._thumbnail); this._scrollText = new ScrollText(); this._scrollText.isHTML = true; this._scrollText.verticalScrollPolicy = ScrollPolicy.ON; this.addChild(this._scrollText); //we're going to use these AnchorLayoutData objects later, when we //know if this screen is displayed in portrait or landscape. //we'll change it dynamically if the device is rotated while this //screen is visible. this._portraitThumbnailLayoutData = new AnchorLayoutData(0, 0, NaN, 0); this._landscapeThumbnailLayoutData = new AnchorLayoutData(0, NaN, 0, 0); this._landscapeThumbnailLayoutData.percentWidth = 50; this._portraitTextLayoutData = new AnchorLayoutData(0, 0, 0, 0); this._portraitTextLayoutData.topAnchorDisplayObject = this._thumbnail; this._landscapeTextLayoutData = new AnchorLayoutData(0, 0, 0, 0); this._landscapeTextLayoutData.leftAnchorDisplayObject = this._thumbnail; 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); var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE); if(dataInvalid) { if(this._model && this._model.selectedVideo) { this.title = this._model.selectedVideo.title; this._thumbnail.source = this._model.selectedVideo.thumbnailURL; 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._thumbnail.source = null; this._scrollText.text = ""; } } if(sizeInvalid) { this.refreshLayout(); } //never forget to call super.draw()! super.draw(); } protected function refreshLayout():void { if(this.actualHeight > this.actualWidth && this._thumbnail.layoutData != this._portraitThumbnailLayoutData) //portrait { //in landscape, the height of the thumbnail may have been set //explicitly. we need to reset it so that the thumbnail can //resize itself automatically. this._thumbnail.height = NaN; this._thumbnail.layoutData = this._portraitThumbnailLayoutData; this._scrollText.layoutData = this._portraitTextLayoutData; } else if(this.actualWidth > this.actualHeight) //landscape { this._thumbnail.layoutData = this._landscapeThumbnailLayoutData; this._scrollText.layoutData = this._landscapeTextLayoutData; } } private function onBackButton(event:Event = null):void { this.dispatchEventWith(Event.COMPLETE); } private function transitionInCompleteHandler(event:Event):void { this._scrollText.revealScrollBars(); } private function watchButton_triggeredHandler(event:Event):void { navigateToURL(new URLRequest(this._model.selectedVideo.url), "_blank"); } } } ================================================ FILE: examples/build.xml ================================================ ================================================ FILE: package-src.json ================================================ { "id": "feathersui-source", "name": "feathersui-source", "url": "https://feathersui.com/as3-starling/", "docUrl": "https://feathersui/api-reference/", "description": "Cross-platform user interface components for creative frontend projects built with Starling", "type": "src", "version": "4.2.0", "sourceUrl": "https://github.com/feathersui/feathersui-starling/releases/download/v4.2.0/feathersui-source_4.2.0.airpackage", "publishedAt": "2021-11-19T00:00:00.000Z", "dependencies": ["starling-source:2.x.x"], "parameters": [], "tags": ["components", "gui", "starling", "ui", "widgets"], "status": "release", "license": { "type": "Simplified BSD", "url": "https://github.com/feathersui/feathersui-starling/blob/v4.2.0/LICENSE.md", "public": true } } ================================================ FILE: package-swc.json ================================================ { "id": "feathersui", "name": "feathersui", "url": "https://feathersui.com/as3-starling/", "docUrl": "https://feathersui/api-reference/", "description": "Cross-platform user interface components for creative frontend projects built with Starling", "type": "swc", "version": "4.2.0", "sourceUrl": "https://github.com/feathersui/feathersui-starling/releases/download/v4.2.0/feathersui_4.2.0.airpackage", "publishedAt": "2021-11-19T00:00:00.000Z", "dependencies": ["starling:2.x.x"], "parameters": [], "tags": ["components", "gui", "starling", "ui", "widgets"], "status": "release", "license": { "type": "Simplified BSD", "url": "https://github.com/feathersui/feathersui-starling/blob/v4.2.0/LICENSE.md", "public": true } } ================================================ FILE: sdk.properties ================================================ # The location of the AIR SDK with ASC 2.0 flashsdk.root = c:/Users/josht/Development/Flash/sdks/AIR32.0.0.89 flashsdk.bin = ${flashsdk.root}/bin flashsdk.lib = ${flashsdk.root}/lib flashsdk.config = ${flashsdk.root}/frameworks/flex-config.xml flashsdk.framework = ${flashsdk.root}/frameworks # 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.lib}/legacy/asdoc.jar compc = ${flashsdk.lib}/compc-cli.jar mxmlc = ${flashsdk.lib}/mxmlc-cli.jar adt = ${flashsdk.lib}/adt.jar apm = /opt/apm/apm ================================================ FILE: source/feathers/FEATHERS_VERSION.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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 { /** * The current version of Feathers. Stable versions will use the format * major.minor.patch. Prerelease versions may append additional * information after a hyphen. For example, the beta release of Feathers 2.2 * would use the following value: 2.2.0-beta. Special builds * may append additional information after a plus sign. For example, the * stable release of Feathers SDK 2.2 would use the following value: * 2.2.0+sdk. The beta version of Feathers SDK 2.2 would use * the following value: 2.2.0-beta+sdk. * * @productversion Feathers 2.1.0 */ public const FEATHERS_VERSION:String = "4.2.0"; } ================================================ FILE: source/feathers/controls/Alert.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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.IMeasureDisplayObject; import feathers.core.ITextRenderer; import feathers.core.IValidating; import feathers.core.PopUpManager; import feathers.core.PropertyProxy; import feathers.data.IListCollection; import feathers.events.FeathersEventType; import feathers.layout.HorizontalAlign; import feathers.layout.VerticalLayout; import feathers.skins.IStyleProvider; import feathers.text.FontStylesSet; import feathers.utils.display.getDisplayObjectDepthFromStage; import feathers.utils.skins.resetFluidChildDimensionsForMeasurement; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import starling.core.Starling; import starling.display.DisplayObject; import starling.events.Event; import starling.text.TextFormat; [Exclude(name="layout",kind="property")] [Exclude(name="footer",kind="property")] [Exclude(name="footerFactory",kind="property")] [Exclude(name="footerProperties",kind="property")] [Exclude(name="customFooterStyleName",kind="style")] [Exclude(name="createFooter",kind="method")] /** * 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 */ [Style(name="customButtonGroupStyleName",type="String")] /** * A style name to add to the alert's message text renderer * sub-component. Typically used by a theme to provide different styles * to different alerts. * *

    In the following example, a custom message style name is passed * to the alert:

    * * * alert.customMessageStyleName = "my-custom-button-group"; * *

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

    * * * getStyleProviderForClass( BitmapFontTextRenderer ).setFunctionForStyleName( "my-custom-message", setCustomMessageStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_MESSAGE * @see feathers.core.FeathersControl#styleNameList * @see #messageFactory */ [Style(name="customMessageStyleName",type="String")] /** * The font styles used to display the alert's message text when the * alert is disabled. * *

    These styles will only apply to the alert's message. The header's * title font styles should be set directly on the header. The button * font styles should be set directly on the buttons.

    * *

    In the following example, the disabled font styles are customized:

    * * * alert.disabledFontStyles = new TextFormat( "Helvetica", 20, 0x999999 ); * *

    Note: The starling.text.TextFormat class defines a * number of common font styles, but the text renderer being used may * support a larger number of ways to be customized. Use the * messageFactory to set more advanced styles on the * text renderer.

    * * @default null * * @see http://doc.starling-framework.org/current/starling/text/TextFormat.html starling.text.TextFormat * @see #style:fontStyles */ [Style(name="disabledFontStyles",type="starling.text.TextFormat")] /** * The font styles used to display the alert's message text. * *

    These styles will only apply to the alert's message. The header's * title font styles should be set directly on the header. The button * font styles should be set directly on the buttons.

    * *

    In the following example, the font styles are customized:

    * * * alert.fontStyles = new TextFormat( "Helvetica", 20, 0xcc0000 ); * *

    Note: The starling.text.TextFormat class defines a * number of common font styles, but the text renderer being used may * support a larger number of ways to be customized. Use the * messageFactory to set more advanced styles.

    * * @default null * * @see http://doc.starling-framework.org/current/starling/text/TextFormat.html starling.text.TextFormat * @see #style:disabledFontStyles */ [Style(name="fontStyles",type="starling.text.TextFormat")] /** * 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 */ [Style(name="gap",type="Number")] /** * The alert's optional icon content to display next to the text. * *

    In the following example, the icon is privated:

    * * * alert.icon = new Image( texture ); * * @default null */ [Style(name="icon",type="starling.display.DisplayObject")] /** * 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 ArrayCollection( * [ * { label: "OK" } * ])); * } * * @see ../../../help/alert.html How to use the Feathers Alert component * * @productversion Feathers 1.2.0 */ 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"; /** * 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"; /** * The default value added to the styleNameList of the * message text renderer. * * @see feathers.core.FeathersControl#styleNameList * @see ../../../help/text-renderers.html Introduction to Feathers text renderers */ public static const DEFAULT_CHILD_STYLE_NAME_MESSAGE:String = "feathers-alert-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; /** * Creates overlays for modal alerts. When this property is * null, uses the overlayFactory defined by * PopUpManager instead. * *

    Note: Specific, individual alerts may have custom overlays that * are different than the default by passing a different overlay factory * to Alert.show().

    * *

    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; * }; * * @default null * * @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 ArrayCollection( * [ * { label: "OK" } * ]); * } */ public static function show(message:String, title:String = null, buttons:IListCollection = 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.headerStyleName = DEFAULT_CHILD_STYLE_NAME_HEADER; this.footerStyleName = DEFAULT_CHILD_STYLE_NAME_BUTTON_GROUP; if(this._fontStylesSet === null) { this._fontStylesSet = new FontStylesSet(); this._fontStylesSet.addEventListener(Event.CHANGE, fontStyles_changeHandler); } this.buttonGroupFactory = defaultButtonGroupFactory; this.addEventListener(Event.ADDED_TO_STAGE, alert_addedToStageHandler); } /** * 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; /** * 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; /** * @private */ public function get icon():DisplayObject { return this._icon; } /** * @private */ public function set icon(value:DisplayObject):void { if(this.processStyleRestriction(arguments.callee)) { if(value !== null) { value.dispose(); } return; } if(this._icon === value) { return; } var oldDisplayListBypassEnabled:Boolean = this.displayListBypassEnabled; this.displayListBypassEnabled = false; if(this._icon) { this._icon.removeEventListener(FeathersEventType.RESIZE, icon_resizeHandler); this.removeChild(this._icon); } this._icon = value; if(this._icon) { this._icon.addEventListener(FeathersEventType.RESIZE, icon_resizeHandler); this.addChild(this._icon); } this.displayListBypassEnabled = oldDisplayListBypassEnabled; this.invalidate(INVALIDATION_FLAG_DATA); } /** * @private */ protected var _gap:Number = 0; /** * @private */ public function get gap():Number { return this._gap; } /** * @private */ public function set gap(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._gap == value) { return; } this._gap = value; this.invalidate(INVALIDATION_FLAG_LAYOUT); } /** * @private */ protected var _buttonsDataProvider:IListCollection = null; /** * The data provider of the alert's ButtonGroup. */ public function get buttonsDataProvider():IListCollection { return this._buttonsDataProvider; } /** * @private */ public function set buttonsDataProvider(value:IListCollection):void { if(this._buttonsDataProvider == value) { return; } this._buttonsDataProvider = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _acceptButtonIndex:int; /** * The index of the button in the buttonsDataProvider to * trigger when Keyboard.ENTER is pressed. * *

    In the following example, the acceptButtonIndex is * set to the first button in the data provider.

    * * * var alert:Alert = Alert.show( "This is an alert!", "Hello World", new ArrayCollection( * [ * { label: "OK" } * ])); * alert.acceptButtonIndex = 0; * * @default -1 */ public function get acceptButtonIndex():int { return this._acceptButtonIndex; } /** * @private */ public function set acceptButtonIndex(value:int):void { this._acceptButtonIndex = value; } /** * @private */ protected var _cancelButtonIndex:int; /** * The index of the button in the buttonsDataProvider to * trigger when Keyboard.ESCAPE or * Keyboard.BACK is pressed. * *

    In the following example, the cancelButtonIndex is * set to the second button in the data provider.

    * * * var alert:Alert = Alert.show( "This is an alert!", "Hello World", new ArrayCollection( * [ * { label: "OK" }, * { label: "Cancel" }, * ])); * alert.cancelButtonIndex = 1; * * @default -1 */ public function get cancelButtonIndex():int { return this._cancelButtonIndex; } /** * @private */ public function set cancelButtonIndex(value:int):void { this._cancelButtonIndex = value; } /** * @private */ protected var _fontStylesSet:FontStylesSet; /** * @private */ public function get fontStyles():TextFormat { return this._fontStylesSet.format; } /** * @private */ public function set fontStyles(value:TextFormat):void { if(this.processStyleRestriction(arguments.callee)) { return; } var savedCallee:Function = arguments.callee; function changeHandler(event:Event):void { processStyleRestriction(savedCallee); } var oldValue:TextFormat = this._fontStylesSet.format; if(oldValue !== null) { oldValue.removeEventListener(Event.CHANGE, changeHandler); } this._fontStylesSet.format = value; if(value !== null) { value.addEventListener(Event.CHANGE, changeHandler); } } /** * @private */ public function get disabledFontStyles():TextFormat { return this._fontStylesSet.disabledFormat; } /** * @private */ public function set disabledFontStyles(value:TextFormat):void { if(this.processStyleRestriction(arguments.callee)) { return; } var savedCallee:Function = arguments.callee; function changeHandler(event:Event):void { processStyleRestriction(savedCallee); } var oldValue:TextFormat = this._fontStylesSet.disabledFormat; if(oldValue !== null) { oldValue.removeEventListener(Event.CHANGE, changeHandler); } this._fontStylesSet.disabledFormat = value; if(value !== null) { value.addEventListener(Event.CHANGE, changeHandler); } } /** * @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 */ 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; /** * An object that stores properties for the alert's message text * renderer sub-component, and the properties will be passed down to the * text renderer when the alert validates. The available properties * depend on which ITextRenderer implementation is returned * by messageFactory. Refer to * feathers.core.ITextRenderer * for a list of available text renderer implementations. * *

    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 */ 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); } /** * @private */ protected var _customMessageStyleName:String; /** * @private */ public function get customMessageStyleName():String { return this._customMessageStyleName; } /** * @private */ public function set customMessageStyleName(value:String):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._customMessageStyleName === value) { return; } this._customMessageStyleName = value; this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER); } /** * 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 */ public function get buttonGroupFactory():Function { return super.footerFactory; } /** * @private */ public function set buttonGroupFactory(value:Function):void { super.footerFactory = value; } /** * @private */ public function get customButtonGroupStyleName():String { return super.customFooterStyleName; } /** * @private */ public function set customButtonGroupStyleName(value:String):void { super.customFooterStyleName = value; } /** * An object that stores properties for the alert's button group * sub-component, and the properties will be passed down to the button * group when the alert validates. For a list of available properties, * refer to feathers.controls.ButtonGroup. * *

    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 public function dispose():void { if(this._fontStylesSet !== null) { this._fontStylesSet.dispose(); this._fontStylesSet = null; } super.dispose(); } /** * @private */ override protected function initialize():void { if(this._layout === null) { var layout:VerticalLayout = new VerticalLayout(); layout.horizontalAlign = HorizontalAlign.JUSTIFY; this.ignoreNextStyleRestriction(); 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 stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE); 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 !== null) { if(this._icon is IValidating) { IValidating(this._icon).validate(); } this._icon.x = this._paddingLeft; this._icon.y = this._topViewPortOffset + (this._viewPort.visibleHeight - this._icon.height) / 2; } } /** * @private */ override protected function autoSizeIfNeeded():Boolean { if(this._autoSizeMode === AutoSizeMode.STAGE) { //the implementation in a super class can handle this return super.autoSizeIfNeeded(); } var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN var needsMinWidth:Boolean = this._explicitMinWidth !== this._explicitMinWidth; //isNaN var needsMinHeight:Boolean = this._explicitMinHeight !== this._explicitMinHeight; //isNaN if(!needsWidth && !needsHeight && !needsMinWidth && !needsMinHeight) { return false; } resetFluidChildDimensionsForMeasurement(this.currentBackgroundSkin, this._explicitWidth, this._explicitHeight, this._explicitMinWidth, this._explicitMinHeight, this._explicitMaxWidth, this._explicitMaxHeight, this._explicitBackgroundWidth, this._explicitBackgroundHeight, this._explicitBackgroundMinWidth, this._explicitBackgroundMinHeight, this._explicitBackgroundMaxWidth, this._explicitBackgroundMaxHeight); var measureBackground:IMeasureDisplayObject = this.currentBackgroundSkin as IMeasureDisplayObject; if(this.currentBackgroundSkin is IValidating) { IValidating(this.currentBackgroundSkin).validate(); } if(this._icon is IValidating) { IValidating(this._icon).validate(); } //we don't measure the header and footer here because they are //handled in calculateViewPortOffsets(), which is automatically //called by Scroller before autoSizeIfNeeded(). var newWidth:Number = this._explicitWidth; var newHeight:Number = this._explicitHeight; var newMinWidth:Number = this._explicitMinWidth; var newMinHeight:Number = this._explicitMinHeight; if(needsWidth) { if(this._measureViewPort) { newWidth = this._viewPort.visibleWidth; } else { newWidth = 0; } //we don't need to account for the icon and gap because it is //already included in the left offset newWidth += this._rightViewPortOffset + this._leftViewPortOffset; var headerWidth:Number = this.header.width + this._outerPaddingLeft + this._outerPaddingRight; if(headerWidth > newWidth) { newWidth = headerWidth; } if(this.footer !== null) { var footerWidth:Number = this.footer.width + this._outerPaddingLeft + this._outerPaddingRight; if(footerWidth > newWidth) { newWidth = footerWidth; } } if(this.currentBackgroundSkin !== null && this.currentBackgroundSkin.width > newWidth) { newWidth = this.currentBackgroundSkin.width; } } if(needsHeight) { if(this._measureViewPort) { newHeight = this._viewPort.visibleHeight; } else { newHeight = 0; } if(this._icon !== null) { var iconHeight:Number = this._icon.height; if(iconHeight === iconHeight && //!isNaN iconHeight > newHeight) { newHeight = iconHeight; } } newHeight += this._bottomViewPortOffset + this._topViewPortOffset; //we don't need to account for the header and footer because //they're already included in the top and bottom offsets if(this.currentBackgroundSkin !== null && this.currentBackgroundSkin.height > newHeight) { newHeight = this.currentBackgroundSkin.height; } } if(needsMinWidth) { if(this._measureViewPort) { newMinWidth = this._viewPort.minVisibleWidth; } else { newMinWidth = 0; } //we don't need to account for the icon and gap because it is //already included in the left offset newMinWidth += this._rightViewPortOffset + this._leftViewPortOffset; var headerMinWidth:Number = this.header.minWidth + this._outerPaddingLeft + this._outerPaddingRight; if(headerMinWidth > newMinWidth) { newMinWidth = headerMinWidth; } if(this.footer !== null) { var footerMinWidth:Number = this.footer.minWidth + this._outerPaddingLeft + this._outerPaddingRight; if(footerMinWidth > newMinWidth) { newMinWidth = footerMinWidth; } } if(this.currentBackgroundSkin !== null) { if(measureBackground !== null) { if(measureBackground.minWidth > newMinWidth) { newMinWidth = measureBackground.minWidth; } } else if(this._explicitBackgroundMinWidth > newMinWidth) { newMinWidth = this._explicitBackgroundMinWidth; } } } if(needsMinHeight) { if(this._measureViewPort) { newMinHeight = this._viewPort.minVisibleHeight; } else { newMinHeight = 0; } if(this._icon !== null) { iconHeight = this._icon.height; if(iconHeight === iconHeight && //!isNaN iconHeight > newMinHeight) { newMinHeight = iconHeight; } } newMinHeight += this._bottomViewPortOffset + this._topViewPortOffset; //we don't need to account for the header and footer because //they're already included in the top and bottom offsets if(this.currentBackgroundSkin !== null) { if(measureBackground !== null) { if(measureBackground.minHeight > newMinHeight) { newMinHeight = measureBackground.minHeight; } } else if(this._explicitBackgroundMinHeight > newMinHeight) { newMinHeight = this._explicitBackgroundMinHeight; } } } return this.saveMeasurements(newWidth, newHeight, newMinWidth, newMinHeight); } /** * 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 #style: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 #style: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()); this.messageTextRenderer.wordWrap = true; var messageStyleName:String = this._customMessageStyleName != null ? this._customMessageStyleName : this.messageStyleName; var uiTextRenderer:IFeathersControl = IFeathersControl(this.messageTextRenderer); uiTextRenderer.styleNameList.add(messageStyleName); 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 { this.messageTextRenderer.fontStyles = this._fontStylesSet; 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 !== null) { if(this._icon is IValidating) { IValidating(this._icon).validate(); } var iconWidth:Number = this._icon.width; if(iconWidth === iconWidth) //!isNaN { this._leftViewPortOffset += iconWidth + this._gap; } } } /** * @private */ protected function closeAlert(item:Object):void { this.removeFromParent(); this.dispatchEventWith(Event.CLOSE, false, item); this.dispose(); } /** * @private */ protected function buttonsFooter_triggeredHandler(event:Event, data:Object):void { this.closeAlert(data); } /** * @private */ protected function icon_resizeHandler(event:Event):void { this.invalidate(INVALIDATION_FLAG_LAYOUT); } /** * @private */ protected function fontStyles_changeHandler(event:Event):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function alert_addedToStageHandler(event:Event):void { var starling:Starling = this.stage !== null ? this.stage.starling : Starling.current; //using priority here is a hack so that objects higher up in the //display list have a chance to cancel the event first. var priority:int = -getDisplayObjectDepthFromStage(this); starling.nativeStage.addEventListener(KeyboardEvent.KEY_DOWN, alert_nativeStage_keyDownHandler, false, priority, true); this.addEventListener(Event.REMOVED_FROM_STAGE, alert_removedFromStageHandler); } /** * @private */ protected function alert_removedFromStageHandler(event:Event):void { this.removeEventListener(Event.REMOVED_FROM_STAGE, alert_removedFromStageHandler); var starling:Starling = this.stage !== null ? this.stage.starling : Starling.current; starling.nativeStage.removeEventListener(KeyboardEvent.KEY_DOWN, alert_nativeStage_keyDownHandler); } /** * @private */ protected function alert_nativeStage_keyDownHandler(event:KeyboardEvent):void { if(event.isDefaultPrevented()) { //someone else already handled this one return; } if(this._buttonsDataProvider === null) { //no buttons to trigger return; } var keyCode:uint = event.keyCode; if(this._acceptButtonIndex != -1 && keyCode == Keyboard.ENTER) { //don't let the OS handle the event event.preventDefault(); var item:Object = this._buttonsDataProvider.getItemAt(this._acceptButtonIndex); this.closeAlert(item); return; } if(this._cancelButtonIndex != -1 && (keyCode == Keyboard.BACK || keyCode == Keyboard.ESCAPE)) { //don't let the OS handle the event event.preventDefault(); item = this._buttonsDataProvider.getItemAt(this._cancelButtonIndex); this.closeAlert(item); return; } } } } ================================================ FILE: source/feathers/controls/AutoComplete.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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.controls.popups.DropDownPopUpContentManager; import feathers.controls.popups.IPopUpContentManager; import feathers.core.PropertyProxy; import feathers.data.ArrayCollection; import feathers.data.IAutoCompleteSource; import feathers.data.IListCollection; import feathers.events.FeathersEventType; import feathers.skins.IStyleProvider; import feathers.utils.display.getDisplayObjectDepthFromStage; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import flash.utils.getTimer; import starling.events.Event; import starling.events.EventDispatcher; import starling.events.KeyboardEvent; import starling.events.Touch; import starling.events.TouchEvent; import starling.events.TouchPhase; /** * A style name to add to the list sub-component of the * AutoComplete. Typically used by a theme to provide * different styles to different AutoComplete instances. * *

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

    * * * input.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 */ [Style(name="customListStyleName",type="String")] /** * 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:

    * * * input.popUpContentManager = new CalloutPopUpContentManager(); * * @default null */ [Style(name="popUpContentManager",type="feathers.controls.popups.IPopUpContentManager")] /** * 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. * *

    The following example creates an AutoComplete with a * local collection of suggestions:

    * * * var input:AutoComplete = new AutoComplete(); * input.source = new LocalAutoCompleteSource( new VectorCollection(new <String> * [ * "Apple", * "Banana", * "Cherry", * "Grape", * "Lemon", * "Orange", * "Watermelon" * ])); * this.addChild( input ); * * @see ../../../help/auto-complete.html How to use the Feathers AutoComplete component * @see feathers.controls.TextInput * * @productversion Feathers 2.1.0 */ 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 #style: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:IListCollection; /** * @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. * *

    In the following example, a source of suggestions is provided:

    * * * input.source = new LocalAutoCompleteSource( new VectorCollection(new <String> * [ * "Apple", * "Banana", * "Cherry", * "Grape", * "Lemon", * "Orange", * "Watermelon" * ])); * * @default null */ 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. * *

    In the following example, the delay is changed to 1.5 seconds:

    * * * input.autoCompleteDelay = 1.5; * * @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. * *

    In the following example, the minimum number of characters is * changed to 3:

    * * * input.minimumAutoCompleteLength = 3; * * @default 2 * * @see #source */ public function get minimumAutoCompleteLength():int { return this._minimumAutoCompleteLength; } /** * @private */ public function set minimumAutoCompleteLength(value:int):void { this._minimumAutoCompleteLength = value; } /** * @private */ protected var _popUpContentManager:IPopUpContentManager; /** * @private */ public function get popUpContentManager():IPopUpContentManager { return this._popUpContentManager; } /** * @private */ public function set popUpContentManager(value:IPopUpContentManager):void { if(this.processStyleRestriction(arguments.callee)) { return; } 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 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 * AutoComplete:

    * * * input.listFactory = function():List * { * var popUpList:List = new List(); * popUpList.backgroundSkin = new Image( texture ); * return popUpList; * }; * * @default null * * @see feathers.controls.List */ 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; /** * @private */ public function get customListStyleName():String { return this._customListStyleName; } /** * @private */ public function set customListStyleName(value:String):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._customListStyleName === value) { return; } this._customListStyleName = value; this.invalidate(INVALIDATION_FLAG_LIST_FACTORY); } /** * @private */ protected var _listProperties:PropertyProxy; /** * An object that stores properties for the auto-complete's pop-up list * sub-component, and the properties will be passed down to the pop-up * list when the auto-complete validates. For a list of available * properties, refer to * feathers.controls.List. * *

    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 _listTouchPointID:int = -1; /** * @private */ protected var _triggered: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 ArrayCollection(); if(this._popUpContentManager === null) { this.ignoreNextStyleRestriction(); 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 #style: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(TouchEvent.TOUCH, list_touchHandler); 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 { //using priority here is a hack so that objects deeper in the //display list have a chance to cancel the event first. var priority:int = -getDisplayObjectDepthFromStage(this); this.stage.starling.nativeStage.addEventListener(flash.events.KeyboardEvent.KEY_DOWN, nativeStage_keyDownHandler, false, priority, true); super.focusInHandler(event); } /** * @private */ override protected function focusOutHandler(event:Event):void { this.stage.starling.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; } if(event.isDefaultPrevented()) { 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.preventDefault(); 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.preventDefault(); 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:IListCollection):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; } if(this._listTouchPointID == -1) { //triggered by keyboard this.closeList(); this.selectRange(this.text.length, this.text.length); return; } this._triggered = true; } /** * @private */ protected function list_touchHandler(event:TouchEvent):void { var touch:Touch = event.getTouch(this.list); if(touch === null) { return; } if(touch.phase === TouchPhase.BEGAN) { this._listTouchPointID = touch.id; this._triggered = false; } if(touch.phase === TouchPhase.ENDED && this._triggered) { this._listTouchPointID = -1; 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); } } } } ================================================ FILE: source/feathers/controls/AutoSizeMode.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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 { /** * Constants that determine how a component should automatically calculate * its own dimensions when no explicit dimensions are provided. * * @productversion Feathers 3.0.0 */ public class AutoSizeMode { /** * The component will automatically calculate its dimensions to fill the * entire stage. * * @productversion Feathers 3.0.0 */ public static const STAGE:String = "stage"; /** * The component will automatically calculate its dimensions to fit its * content's ideal dimensions. * * @productversion Feathers 3.0.0 */ public static const CONTENT:String = "content"; } } ================================================ FILE: source/feathers/controls/BasicButton.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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.IMeasureDisplayObject; import feathers.core.IStateContext; import feathers.core.IStateObserver; import feathers.core.IValidating; import feathers.events.FeathersEventType; import feathers.skins.IStyleProvider; import feathers.utils.skins.resetFluidChildDimensionsForMeasurement; import feathers.utils.touch.TapToTrigger; import feathers.utils.touch.TouchToState; import flash.geom.Point; import starling.display.DisplayObject; /** * 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. * *

    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 #setSkinForState() */ [Style(name="defaultSkin",type="starling.display.DisplayObject")] /** * 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 ); * *

    Alternatively, you may use setSkinForState() with * ButtonState.DISABLED to set the same skin:

    * * * var skin:Image = new Image( texture ); * button.setSkinForState( ButtonState.DISABLED, skin ); * * @default null * * @see #style:defaultSkin * @see #setSkinForState() * @see feathers.controls.ButtonState#DISABLED */ [Style(name="disabledSkin",type="starling.display.DisplayObject")] /** * 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 ); * *

    Alternatively, you may use setSkinForState() with * ButtonState.DOWN to set the same skin:

    * * * var skin:Image = new Image( texture ); * button.setSkinForState( ButtonState.DOWN, skin ); * * @default null * * @see #style:defaultSkin * @see #setSkinForState() * @see feathers.controls.ButtonState#DOWN */ [Style(name="downSkin",type="starling.display.DisplayObject")] /** * 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 ); * *

    Alternatively, you may use setSkinForState() with * ButtonState.HOVER to set the same skin:

    * * * var skin:Image = new Image( texture ); * button.setSkinForState( ButtonState.HOVER, skin ); * * @default null * * @see #style:defaultSkin * @see #setSkinForState() * @see feathers.controls.ButtonState#HOVER */ [Style(name="hoverSkin",type="starling.display.DisplayObject")] /** * 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; * * @default false */ [Style(name="keepDownStateOnRollOut",type="Boolean")] /** * 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 ); * *

    Alternatively, you may use setSkinForState() with * ButtonState.UP to set the same skin:

    * * * var skin:Image = new Image( texture ); * button.setSkinForState( ButtonState.UP, skin ); * * @default null * * @see #style:defaultSkin * @see #setSkinForState() * @see feathers.controls.ButtonState#UP */ [Style(name="upSkin",type="starling.display.DisplayObject")] /** * 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 display object's state changes. * *

    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.STATE_CHANGE * * @see #currentState */ [Event(name="stateChange",type="starling.events.Event")] /** * A simple button control with states, but no content, that is useful for * purposes like skinning. For a more full-featured button, with a label and * icon, see feathers.controls.Button instead. * * @see feathers.controls.Button * * @productversion Feathers 3.0.0 */ public class BasicButton extends FeathersControl implements IStateContext { /** * @private */ private static const HELPER_POINT:Point = new Point(); /** * The default IStyleProvider for all BasicButton * components. * * @default null * @see feathers.core.FeathersControl#styleProvider */ public static var globalStyleProvider:IStyleProvider; /** * Constructor. */ public function BasicButton() { super(); this.isQuickHitAreaEnabled = true; } /** * @private */ override protected function get defaultStyleProvider():IStyleProvider { return BasicButton.globalStyleProvider; } /** * @private */ protected var touchToState:TouchToState; /** * @private */ protected var tapToTrigger:TapToTrigger; /** * @private */ protected var _currentState:String = ButtonState.UP; /** * The current state of the button. * * @see feathers.controls.ButtonState * @see #event:stateChange feathers.events.FeathersEventType.STATE_CHANGE */ public function get currentState():String { return this._currentState; } /** * 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; /** * @private */ override public function set isEnabled(value:Boolean):void { if(this._isEnabled === value) { return; } super.isEnabled = value; if(this._isEnabled) { //might be in another state for some reason //let's only change to up if needed if(this._currentState === ButtonState.DISABLED) { this.changeState(ButtonState.UP); } } else { this.changeState(ButtonState.DISABLED); } } /** * @private */ protected var _keepDownStateOnRollOut:Boolean = false; /** * @private */ public function get keepDownStateOnRollOut():Boolean { return this._keepDownStateOnRollOut; } /** * @private */ public function set keepDownStateOnRollOut(value:Boolean):void { if(this.processStyleRestriction(arguments.callee)) { return; } this._keepDownStateOnRollOut = value; if(this.touchToState !== null) { this.touchToState.keepDownStateOnRollOut = value; } } /** * @private */ protected var _defaultSkin:DisplayObject; /** * @private */ public function get defaultSkin():DisplayObject { return this._defaultSkin; } /** * @private */ public function set defaultSkin(value:DisplayObject):void { if(this.processStyleRestriction(arguments.callee)) { if(value !== null) { value.dispose(); } return; } if(this._defaultSkin === value) { return; } if(this._defaultSkin !== null && this.currentSkin === this._defaultSkin) { //if this skin needs to be reused somewhere else, we need to //properly clean it up this.removeCurrentSkin(this._defaultSkin); this.currentSkin = null; } this._defaultSkin = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ public function get upSkin():DisplayObject { return this.getSkinForState(ButtonState.UP); } /** * @private */ public function set upSkin(value:DisplayObject):void { this.setSkinForState(ButtonState.UP, value); } /** * @private */ public function get downSkin():DisplayObject { return this.getSkinForState(ButtonState.DOWN); } /** * @private */ public function set downSkin(value:DisplayObject):void { this.setSkinForState(ButtonState.DOWN, value); } /** * @private */ public function get hoverSkin():DisplayObject { return this.getSkinForState(ButtonState.HOVER); } /** * @private */ public function set hoverSkin(value:DisplayObject):void { this.setSkinForState(ButtonState.HOVER, value); } /** * @private */ public function get disabledSkin():DisplayObject { return this.getSkinForState(ButtonState.DISABLED); } /** * @private */ public function set disabledSkin(value:DisplayObject):void { this.setSkinForState(ButtonState.DISABLED, value); } /** * @private * Chooses an appropriate skin based on the state and the selection. */ protected var _stateToSkin:Object = {}; /** * @private */ protected var _explicitSkinWidth:Number; /** * @private */ protected var _explicitSkinHeight:Number; /** * @private */ protected var _explicitSkinMinWidth:Number; /** * @private */ protected var _explicitSkinMinHeight:Number; /** * @private */ protected var _explicitSkinMaxWidth:Number; /** * @private */ protected var _explicitSkinMaxHeight:Number; /** * Gets the skin to be used by the button when its * currentState property matches the specified state value. * *

    If a skin is not defined for a specific state, returns * null.

    * * @see #setSkinForState() */ public function getSkinForState(state:String):DisplayObject { return this._stateToSkin[state] as DisplayObject; } /** * Sets the skin to be used by the button when its * currentState property matches the specified state value. * *

    If a skin is not defined for a specific state, the value of the * defaultSkin property will be used instead.

    * * @see #style:defaultSkin * @see #getSkinForState() * @see feathers.controls.ButtonState */ public function setSkinForState(state:String, skin:DisplayObject):void { var key:String = "setSkinForState--" + state; if(this.processStyleRestriction(key)) { if(skin !== null) { skin.dispose(); } return; } var oldSkin:DisplayObject = this._stateToSkin[state] as DisplayObject; if(oldSkin !== null && this.currentSkin === oldSkin) { //if this skin needs to be reused somewhere else, we need to //properly clean it up this.removeCurrentSkin(oldSkin); this.currentSkin = null; } if(skin !== null) { this._stateToSkin[state] = skin; } else { delete this._stateToSkin[state]; } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ override public function dispose():void { //we don't dispose it if the button is the parent because it'll //already get disposed in super.dispose() if(this._defaultSkin !== null && this._defaultSkin.parent !== this) { this._defaultSkin.dispose(); } for(var state:String in this._stateToSkin) { var skin:DisplayObject = this._stateToSkin[state] as DisplayObject; if(skin !== null && skin.parent !== this) { skin.dispose(); } } if(this.touchToState !== null) { //setting the target to null will remove listeners and do any //other clean up that is needed this.touchToState.target = null; } if(this.tapToTrigger !== null) { this.tapToTrigger.target = null; } super.dispose(); } /** * @private */ override protected function initialize():void { super.initialize(); if(!this.touchToState) { this.touchToState = new TouchToState(this, this.changeState); } this.touchToState.keepDownStateOnRollOut = this._keepDownStateOnRollOut; if(!this.tapToTrigger) { this.tapToTrigger = new TapToTrigger(this); } } /** * @private */ override protected function draw():void { var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES); var stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE); var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE); if(stylesInvalid || stateInvalid) { this.refreshTriggeredEvents(); this.refreshSkin(); } this.autoSizeIfNeeded(); this.scaleSkin(); } /** * 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 saveMeasurements() 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 var needsMinWidth:Boolean = this._explicitMinWidth !== this._explicitMinWidth; //isNaN var needsMinHeight:Boolean = this._explicitMinHeight !== this._explicitMinHeight; //isNaN if(!needsWidth && !needsHeight && !needsMinWidth && !needsMinHeight) { return false; } resetFluidChildDimensionsForMeasurement(this.currentSkin, this._explicitWidth, this._explicitHeight, this._explicitMinWidth, this._explicitMinHeight, this._explicitMaxWidth, this._explicitMaxHeight, this._explicitSkinWidth, this._explicitSkinHeight, this._explicitSkinMinWidth, this._explicitSkinMinHeight, this._explicitSkinMaxWidth, this._explicitSkinMaxHeight); var measureSkin:IMeasureDisplayObject = this.currentSkin as IMeasureDisplayObject; if(this.currentSkin is IValidating) { IValidating(this.currentSkin).validate(); } var newMinWidth:Number = this._explicitMinWidth; if(needsMinWidth) { if(measureSkin !== null) { newMinWidth = measureSkin.minWidth; } else if(this.currentSkin !== null) { newMinWidth = this._explicitSkinMinWidth; } else { newMinWidth = 0; } } var newMinHeight:Number = this._explicitMinHeight; if(needsMinHeight) { if(measureSkin !== null) { newMinHeight = measureSkin.minHeight; } else if(this.currentSkin !== null) { newMinHeight = this._explicitSkinMinHeight; } else { newMinHeight = 0; } } var newWidth:Number = this._explicitWidth; if(needsWidth) { if(this.currentSkin !== null) { newWidth = this.currentSkin.width; } else { newWidth = 0; } } var newHeight:Number = this._explicitHeight; if(needsHeight) { if(this.currentSkin !== null) { newHeight = this.currentSkin.height; } else { newHeight = 0; } } return this.saveMeasurements(newWidth, newHeight, newMinWidth, newMinHeight); } /** * Sets the currentSkin property. * *

    For internal use in subclasses.

    */ protected function refreshSkin():void { var oldSkin:DisplayObject = this.currentSkin; this.currentSkin = this.getCurrentSkin(); if(this.currentSkin !== oldSkin) { this.removeCurrentSkin(oldSkin); if(this.currentSkin !== null) { if(this.currentSkin is IFeathersControl) { IFeathersControl(this.currentSkin).initializeNow(); } if(this.currentSkin is IMeasureDisplayObject) { var measureSkin:IMeasureDisplayObject = IMeasureDisplayObject(this.currentSkin); this._explicitSkinWidth = measureSkin.explicitWidth; this._explicitSkinHeight = measureSkin.explicitHeight; this._explicitSkinMinWidth = measureSkin.explicitMinWidth; this._explicitSkinMinHeight = measureSkin.explicitMinHeight; this._explicitSkinMaxWidth = measureSkin.explicitMaxWidth; this._explicitSkinMaxHeight = measureSkin.explicitMaxHeight; } else { this._explicitSkinWidth = this.currentSkin.width; this._explicitSkinHeight = this.currentSkin.height; this._explicitSkinMinWidth = this._explicitSkinWidth; this._explicitSkinMinHeight = this._explicitSkinHeight; this._explicitSkinMaxWidth = this._explicitSkinWidth; this._explicitSkinMaxHeight = this._explicitSkinHeight; } if(this.currentSkin is IStateObserver) { IStateObserver(this.currentSkin).stateContext = this; } this.addChildAt(this.currentSkin, 0); } } } /** * @private */ protected function getCurrentSkin():DisplayObject { var result:DisplayObject = this._stateToSkin[this._currentState] as DisplayObject; if(result !== null) { return result; } return this._defaultSkin; } /** * @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(); } } /** * @private */ protected function removeCurrentSkin(skin:DisplayObject):void { if(skin === null) { return; } if(skin is IStateObserver) { IStateObserver(skin).stateContext = null; } if(skin.parent === this) { //we need to restore these values so that they won't be lost the //next time that this skin is used for measurement skin.width = this._explicitSkinWidth; skin.height = this._explicitSkinHeight; if(skin is IMeasureDisplayObject) { var measureSkin:IMeasureDisplayObject = IMeasureDisplayObject(skin); measureSkin.minWidth = this._explicitSkinMinWidth; measureSkin.minHeight = this._explicitSkinMinHeight; measureSkin.maxWidth = this._explicitSkinMaxWidth; measureSkin.maxHeight = this._explicitSkinMaxHeight; } this.removeChild(skin, false); } } /** * @private */ protected function refreshTriggeredEvents():void { this.tapToTrigger.isEnabled = this._isEnabled; } /** * @private */ protected function changeState(state:String):void { if(!this._isEnabled) { state = ButtonState.DISABLED; } if(this._currentState === state) { return; } this._currentState = state; this.invalidate(INVALIDATION_FLAG_STATE); this.dispatchEventWith(FeathersEventType.STATE_CHANGE); } } } ================================================ FILE: source/feathers/controls/Button.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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.IMeasureDisplayObject; import feathers.core.IStateObserver; import feathers.core.ITextBaselineControl; import feathers.core.ITextRenderer; import feathers.core.IValidating; import feathers.core.PropertyProxy; import feathers.events.FeathersEventType; import feathers.layout.HorizontalAlign; import feathers.layout.RelativePosition; import feathers.layout.VerticalAlign; import feathers.skins.IStyleProvider; import feathers.text.FontStylesSet; import feathers.utils.keyboard.KeyToState; import feathers.utils.keyboard.KeyToTrigger; import feathers.utils.skins.resetFluidChildDimensionsForMeasurement; import feathers.utils.touch.LongPress; import flash.geom.Matrix; import flash.geom.Point; import flash.ui.Keyboard; import starling.display.DisplayObject; import starling.events.Event; import starling.rendering.Painter; import starling.text.TextFormat; import starling.utils.Pool; [Exclude(name="stateToIconFunction",kind="property")] [Exclude(name="stateToLabelPropertiesFunction",kind="property")] [Exclude(name="stateToSkinFunction",kind="property")] [Exclude(name="upLabelProperties",kind="property")] [Exclude(name="downLabelProperties",kind="property")] [Exclude(name="hoverLabelProperties",kind="property")] [Exclude(name="disabledLabelProperties",kind="property")] /** * A style name to add to the button's label text renderer * sub-component. Typically used by a theme to provide different styles * to different buttons. * *

    In the following example, a custom label style name is passed to * the button:

    * * * button.customLabelStyleName = "my-custom-button-label"; * *

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

    * * * getStyleProviderForClass( BitmapFontTextRenderer ).setFunctionForStyleName( "my-custom-button-label", setCustomButtonLabelStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_LABEL * @see feathers.core.FeathersControl#styleNameList * @see #labelFactory */ [Style(name="customLabelStyleName",type="String")] /** * 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 #setIconForState() */ [Style(name="defaultIcon",type="starling.display.DisplayObject")] /** * The font styles used to display the button's text when the button is * disabled. * *

    In the following example, the disabled font styles are customized:

    * * * button.disabledFontStyles = new TextFormat( "Helvetica", 20, 0x999999 ); * *

    Alternatively, you may use setFontStylesForState() with * ButtonState.DISABLED to set the same font styles:

    * * * var fontStyles:TextFormat = new TextFormat( "Helvetica", 20, 0x999999 ); * button.setFontStylesForState( ButtonState.DISABLED, fontStyles ); * *

    Note: The starling.text.TextFormat class defines a * number of common font styles, but the text renderer being used may * support a larger number of ways to be customized. Use the * labelFactory to set more advanced styles on the * text renderer.

    * * @default null * * @see http://doc.starling-framework.org/current/starling/text/TextFormat.html starling.text.TextFormat * @see #style:fontStyles * @see #setFontStylesForState() */ [Style(name="disabledFontStyles",type="starling.text.TextFormat")] /** * 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 ); * *

    Alternatively, you may use setIconForState() with * ButtonState.DISABLED to set the same icon:

    * * * var icon:Image = new Image( texture ); * button.setIconForState( ButtonState.DISABLED, icon ); * * @default null * * @see #style:defaultIcon * @see #setIconForState() * @see feathers.controls.ButtonState#DISABLED */ [Style(name="disabledIcon",type="starling.display.DisplayObject")] /** * 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 ); * *

    Alternatively, you may use setIconForState() with * ButtonState.DOWN to set the same icon:

    * * * var icon:Image = new Image( texture ); * button.setIconForState( ButtonState.DOWN, icon ); * * @default null * * @see #style:defaultIcon * @see #setIconForState() * @see feathers.controls.ButtonState#DOWN */ [Style(name="downIcon",type="starling.display.DisplayObject")] /** * The font styles used to display the button's text. * *

    In the following example, the font styles are customized:

    * * * button.fontStyles = new TextFormat( "Helvetica", 20, 0xcc0000 ); * *

    Note: The starling.text.TextFormat class defines a * number of common font styles, but the text renderer being used may * support a larger number of ways to be customized. Use the * labelFactory to set more advanced styles.

    * * @default null * * @see http://doc.starling-framework.org/current/starling/text/TextFormat.html starling.text.TextFormat * @see #style:disabledFontStyles * @see #setFontStylesForState() */ [Style(name="fontStyles",type="starling.text.TextFormat")] /** * 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 #style:iconPosition * @see #style:minGap */ [Style(name="gap",type="Number")] /** * 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 */ [Style(name="hasLabelTextRenderer",type="Boolean")] /** * 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 = HorizontalAlign.LEFT; * *

    Note: The HorizontalAlign.JUSTIFY * constant is not supported.

    * * @default feathers.layout.HorizontalAlign.CENTER * * @see feathers.layout.HorizontalAlign#LEFT * @see feathers.layout.HorizontalAlign#CENTER * @see feathers.layout.HorizontalAlign#RIGHT */ [Style(name="horizontalAlign",type="String")] /** * 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 ); * *

    Alternatively, you may use setIconForState() with * ButtonState.HOVER to set the same icon:

    * * * var icon:Image = new Image( texture ); * button.setIconForState( ButtonState.HOVER, icon ); * * @default null * * @see #style:defaultIcon * @see #setIconForState() * @see feathers.controls.ButtonState#HOVER */ [Style(name="hoverIcon",type="starling.display.DisplayObject")] /** * 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 #style:iconOffsetY */ [Style(name="iconOffsetX",type="Number")] /** * 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 #style:iconOffsetX */ [Style(name="iconOffsetY",type="Number")] /** * 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 = RelativePosition.RIGHT; * * @default feathers.layout.RelativePosition.LEFT * * @see feathers.layout.RelativePosition#TOP * @see feathers.layout.RelativePosition#RIGHT * @see feathers.layout.RelativePosition#BOTTOM * @see feathers.layout.RelativePosition#LEFT * @see feathers.layout.RelativePosition#RIGHT_BASELINE * @see feathers.layout.RelativePosition#LEFT_BASELINE * @see feathers.layout.RelativePosition#MANUAL */ [Style(name="iconPosition",type="String")] /** * 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 #style:labelOffsetY */ [Style(name="labelOffsetX",type="Number")] /** * 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 #style:labelOffsetX */ [Style(name="labelOffsetY",type="Number")] /** * 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 #style:gap */ [Style(name="minGap",type="Number")] /** * 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 #style:paddingTop * @see #style:paddingRight * @see #style:paddingBottom * @see #style:paddingLeft */ [Style(name="padding",type="Number")] /** * 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 * * @see #style:padding */ [Style(name="paddingTop",type="Number")] /** * 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 * * @see #style:padding */ [Style(name="paddingRight",type="Number")] /** * 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 * * @see #style:padding */ [Style(name="paddingBottom",type="Number")] /** * 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 * * @see #style:padding */ [Style(name="paddingLeft",type="Number")] /** * 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 * * @see #getScaleForState() * @see #setScaleForState() */ [Style(name="scaleWhenDown",type="Number")] /** * 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 * * @see #getScaleForState() * @see #setScaleForState() */ [Style(name="scaleWhenHovering",type="Number")] /** * 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 ); * *

    Alternatively, you may use setIconForState() with * ButtonState.UP to set the same icon:

    * * * var icon:Image = new Image( texture ); * button.setIconForState( ButtonState.UP, icon ); * * @default null * * @see #style:defaultIcon * @see #setIconForState() * @see feathers.controls.ButtonState#UP */ [Style(name="upIcon",type="starling.display.DisplayObject")] /** * 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 = VerticalAlign.TOP; * *

    Note: The VerticalAlign.JUSTIFY * constant is not supported.

    * * @default feathers.layout.VerticalAlign.MIDDLE * * @see feathers.layout.VerticalAlign#TOP * @see feathers.layout.VerticalAlign#MIDDLE * @see feathers.layout.VerticalAlign#BOTTOM */ [Style(name="verticalAlign",type="String")] /** * Determines if the text wraps to the next line when it reaches the * width (or max width) of the component. * *

    In the following example, the button's text is wrapped:

    * * * button.wordWrap = true; * * @default false */ [Style(name="wordWrap",type="Boolean")] /** * 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 * * @productversion Feathers 1.0.0 */ public class Button extends BasicButton implements IFocusDisplayObject, ITextBaselineControl { /** * @private */ private static const HELPER_POINT:Point = new Point(); /** * The default value added to the styleNameList of the * label text renderer. * *

    Note: the label text renderer is not a * feathers.controls.Label. It is an instance of one of the * ITextRenderer implementations.

    * * @see feathers.core.FeathersControl#styleNameList * @see ../../../help/text-renderers.html Introduction to Feathers text renderers */ public static const DEFAULT_CHILD_STYLE_NAME_LABEL:String = "feathers-button-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"; /** * 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"; /** * 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"; /** * 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"; /** * 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"; /** * The default IStyleProvider for all Button * components. * * @default null * @see feathers.core.FeathersControl#styleProvider */ public static var globalStyleProvider:IStyleProvider; /** * Constructor. */ public function Button() { super(); if(this._fontStylesSet === null) { this._fontStylesSet = new FontStylesSet(); this._fontStylesSet.addEventListener(Event.CHANGE, fontStyles_changeHandler); } } /** * 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. * *

    To customize the label text renderer style name without * subclassing, see customLabelStyleName.

    * * @see #style:customLabelStyleName * * @see feathers.core.FeathersControl#styleNameList */ protected var labelStyleName:String = DEFAULT_CHILD_STYLE_NAME_LABEL; /** * The text renderer for the button's label. * *

    For internal use in subclasses.

    * * @see #label * @see #labelFactory * @see #createLabel() */ protected var labelTextRenderer:ITextRenderer; /** * @private */ protected var _explicitLabelWidth:Number; /** * @private */ protected var _explicitLabelHeight:Number; /** * @private */ protected var _explicitLabelMinWidth:Number; /** * @private */ protected var _explicitLabelMinHeight:Number; /** * @private */ protected var _explicitLabelMaxWidth:Number; /** * @private */ protected var _explicitLabelMaxHeight:Number; /** * 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; /** * @private */ override protected function get defaultStyleProvider():IStyleProvider { return Button.globalStyleProvider; } /** * @private */ protected var keyToTrigger:KeyToTrigger; /** * @private */ protected var keyToState:KeyToState; /** * @private */ protected var longPress:LongPress; /** * @private */ protected var dpadEnterKeyToTrigger:KeyToTrigger; /** * @private */ protected var dpadEnterKeyToState:KeyToState; /** * @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; /** * @private */ public function get hasLabelTextRenderer():Boolean { return this._hasLabelTextRenderer; } /** * @private */ public function set hasLabelTextRenderer(value:Boolean):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._hasLabelTextRenderer === value) { return; } this._hasLabelTextRenderer = value; this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER); } /** * @private */ protected var _iconPosition:String = RelativePosition.LEFT; [Inspectable(type="String",enumeration="top,right,bottom,left,rightBaseline,leftBaseline,manual")] /** * @private */ public function get iconPosition():String { return this._iconPosition; } /** * @private */ public function set iconPosition(value:String):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._iconPosition === value) { return; } this._iconPosition = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _gap:Number = 0; /** * @private */ public function get gap():Number { return this._gap; } /** * @private */ public function set gap(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._gap == value) { return; } this._gap = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _minGap:Number = 0; /** * @private */ public function get minGap():Number { return this._minGap; } /** * @private */ public function set minGap(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._minGap == value) { return; } this._minGap = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _horizontalAlign:String = HorizontalAlign.CENTER; [Inspectable(type="String",enumeration="left,center,right")] /** * @private */ public function get horizontalAlign():String { return this._horizontalAlign; } /** * @private */ public function set horizontalAlign(value:String):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._horizontalAlign === value) { return; } this._horizontalAlign = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _verticalAlign:String = VerticalAlign.MIDDLE; [Inspectable(type="String",enumeration="top,middle,bottom")] /** * @private */ public function get verticalAlign():String { return _verticalAlign; } /** * @private */ public function set verticalAlign(value:String):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._verticalAlign === value) { return; } this._verticalAlign = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ 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; /** * @private */ public function get paddingTop():Number { return this._paddingTop; } /** * @private */ public function set paddingTop(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._paddingTop == value) { return; } this._paddingTop = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _paddingRight:Number = 0; /** * @private */ public function get paddingRight():Number { return this._paddingRight; } /** * @private */ public function set paddingRight(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._paddingRight == value) { return; } this._paddingRight = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _paddingBottom:Number = 0; /** * @private */ public function get paddingBottom():Number { return this._paddingBottom; } /** * @private */ public function set paddingBottom(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._paddingBottom == value) { return; } this._paddingBottom = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _paddingLeft:Number = 0; /** * @private */ public function get paddingLeft():Number { return this._paddingLeft; } /** * @private */ public function set paddingLeft(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._paddingLeft == value) { return; } this._paddingLeft = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _labelOffsetX:Number = 0; /** * @private */ public function get labelOffsetX():Number { return this._labelOffsetX; } /** * @private */ public function set labelOffsetX(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._labelOffsetX == value) { return; } this._labelOffsetX = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _labelOffsetY:Number = 0; /** * @private */ public function get labelOffsetY():Number { return this._labelOffsetY; } /** * @private */ public function set labelOffsetY(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._labelOffsetY == value) { return; } this._labelOffsetY = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _iconOffsetX:Number = 0; /** * @private */ public function get iconOffsetX():Number { return this._iconOffsetX; } /** * @private */ public function set iconOffsetX(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._iconOffsetX == value) { return; } this._iconOffsetX = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _iconOffsetY:Number = 0; /** * @private */ public function get iconOffsetY():Number { return this._iconOffsetY; } /** * @private */ public function set iconOffsetY(value:Number):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._iconOffsetY == value) { return; } this._iconOffsetY = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _fontStylesSet:FontStylesSet; /** * @private */ public function get fontStyles():TextFormat { return this._fontStylesSet.format; } /** * @private */ public function set fontStyles(value:TextFormat):void { if(this.processStyleRestriction(arguments.callee)) { return; } var savedCallee:Function = arguments.callee; function changeHandler(event:Event):void { processStyleRestriction(savedCallee); } var oldValue:TextFormat = this._fontStylesSet.format; if(oldValue !== null) { oldValue.removeEventListener(Event.CHANGE, changeHandler); } this._fontStylesSet.format = value; if(value !== null) { value.addEventListener(Event.CHANGE, changeHandler); } } /** * @private */ public function get disabledFontStyles():TextFormat { return this._fontStylesSet.disabledFormat; } /** * @private */ public function set disabledFontStyles(value:TextFormat):void { if(this.processStyleRestriction(arguments.callee)) { return; } var savedCallee:Function = arguments.callee; function changeHandler(event:Event):void { processStyleRestriction(savedCallee); } var oldValue:TextFormat = this._fontStylesSet.disabledFormat; if(oldValue !== null) { oldValue.removeEventListener(Event.CHANGE, changeHandler); } this._fontStylesSet.disabledFormat = value; if(value !== null) { value.addEventListener(Event.CHANGE, changeHandler); } } /** * @private */ private var _wordWrap:Boolean = false; /** * @private */ public function get wordWrap():Boolean { return this._wordWrap; } /** * @private */ public function set wordWrap(value:Boolean):void { if(this.processStyleRestriction(arguments.callee)) { return; } this._wordWrap = value; 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 */ 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 _customLabelStyleName:String; /** * @private */ public function get customLabelStyleName():String { return this._customLabelStyleName; } /** * @private */ public function set customLabelStyleName(value:String):void { if(this.processStyleRestriction(arguments.callee)) { return; } if(this._customLabelStyleName === value) { return; } this._customLabelStyleName = value; this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER); } /** * @private */ protected var _defaultLabelProperties:PropertyProxy; /** * An object that stores properties for the button's label text renderer * when no specific properties are defined for the button's current * state, and the properties will be passed down to the label text * renderer when the button validates. The available properties depend * on which ITextRenderer implementation is returned by * labelFactory. Refer to * feathers.core.ITextRenderer * for a list of available text renderer implementations. * *

    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 #fontStyles */ public function get defaultLabelProperties():Object { if(this._defaultLabelProperties === null) { this._defaultLabelProperties = new PropertyProxy(childProperties_onChange); } return this._defaultLabelProperties; } /** * @private */ public function set defaultLabelProperties(value:Object):void { if(!(value is PropertyProxy)) { value = PropertyProxy.fromObject(value); } if(this._defaultLabelProperties !== null) { this._defaultLabelProperties.removeOnChangeCallback(childProperties_onChange); } this._defaultLabelProperties = PropertyProxy(value); if(this._defaultLabelProperties !== null) { this._defaultLabelProperties.addOnChangeCallback(childProperties_onChange); } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _defaultIcon:DisplayObject; /** * @private */ public function get defaultIcon():DisplayObject { return this._defaultIcon; } /** * @private */ public function set defaultIcon(value:DisplayObject):void { if(this.processStyleRestriction(arguments.callee)) { if(value !== null) { value.dispose(); } return; } if(this._defaultIcon === value) { return; } if(this._defaultIcon !== null && this.currentIcon === this._defaultIcon) { //if this icon needs to be reused somewhere else, we need to //properly clean it up this.removeCurrentIcon(this._defaultIcon); this.currentIcon = null; } this._defaultIcon = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _stateToIcon:Object = {}; /** * @private */ public function get upIcon():DisplayObject { return this.getIconForState(ButtonState.UP); } /** * @private */ public function set upIcon(value:DisplayObject):void { this.setIconForState(ButtonState.UP, value); } /** * @private */ public function get downIcon():DisplayObject { return this.getIconForState(ButtonState.DOWN); } /** * @private */ public function set downIcon(value:DisplayObject):void { this.setIconForState(ButtonState.DOWN, value); } /** * @private */ public function get hoverIcon():DisplayObject { return this.getIconForState(ButtonState.HOVER); } /** * @private */ public function set hoverIcon(value:DisplayObject):void { this.setIconForState(ButtonState.HOVER, value); } /** * @private */ public function get disabledIcon():DisplayObject { return this.getIconForState(ButtonState.DISABLED); } /** * @private */ public function set disabledIcon(value:DisplayObject):void { this.setIconForState(ButtonState.DISABLED, value); } /** * @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 { if(this._longPressDuration == value) { return; } this._longPressDuration = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @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 { if(this._isLongPressEnabled === value) { return; } this._isLongPressEnabled = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _stateToScale:Object = {}; /** * @private */ public function get scaleWhenDown():Number { return this.getScaleForState(ButtonState.DOWN); } /** * @private */ public function set scaleWhenDown(value:Number):void { this.setScaleForState(ButtonState.DOWN, value); } /** * @private */ public function get scaleWhenHovering():Number { return this.getScaleForState(ButtonState.HOVER); } /** * @private */ public function set scaleWhenHovering(value:Number):void { this.setScaleForState(ButtonState.HOVER, value); } /** * @inheritDoc */ public function get baseline():Number { if(!this.labelTextRenderer) { return this.scaledActualHeight; } return this.scaleY * (this.labelTextRenderer.y + this.labelTextRenderer.baseline); } /** * The number of text lines displayed by the button. The component may * contain multiple text lines if the text contains line breaks or if * the wordWrap property is enabled. * * @see #wordWrap */ public function get numLines():int { if(this.labelTextRenderer === null) { return 0; } return this.labelTextRenderer.numLines; } /** * @private */ protected var _ignoreIconResizes:Boolean = false; /** * @private */ override public function render(painter:Painter):void { var scale:Number = this.getScaleForCurrentState(); if(scale != 1) { var matrix:Matrix = Pool.getMatrix(); //scale first, then translate... issue #1455 matrix.scale(scale, scale); matrix.translate(Math.round((1 - scale) / 2 * this.actualWidth), Math.round((1 - scale) / 2 * this.actualHeight)); painter.state.transformModelviewMatrix(matrix); Pool.putMatrix(matrix); } super.render(painter); } /** * @private */ override public function dispose():void { //we don't dispose it if the button is the parent because it'll //already get disposed in super.dispose() if(this._defaultIcon !== null && this._defaultIcon.parent !== this) { this._defaultIcon.dispose(); } for(var state:String in this._stateToIcon) { var icon:DisplayObject = this._stateToIcon[state] as DisplayObject; if(icon !== null && icon.parent !== this) { icon.dispose(); } } if(this.keyToState !== null) { //setting the target to null will remove listeners and do any //other clean up that is needed this.keyToState.target = null; } if(this.keyToTrigger !== null) { this.keyToTrigger.target = null; } if(this.dpadEnterKeyToState !== null) { this.dpadEnterKeyToState.target = null; } if(this.dpadEnterKeyToTrigger !== null) { this.dpadEnterKeyToTrigger.target = null; } if(this._fontStylesSet !== null) { this._fontStylesSet.dispose(); this._fontStylesSet = null; } super.dispose(); } /** * Gets the font styles to be used to display the button's text when the * button's currentState property matches the specified * state value. * *

    If font styles are not defined for a specific state, returns * null.

    * * @see http://doc.starling-framework.org/current/starling/text/TextFormat.html starling.text.TextFormat * @see #setFontStylesForState() * @see #style:fontStyles */ public function getFontStylesForState(state:String):TextFormat { if(this._fontStylesSet === null) { return null; } return this._fontStylesSet.getFormatForState(state); } /** * Sets the font styles to be used to display the button's text when the * button's currentState property matches the specified * state value. * *

    If font styles are not defined for a specific state, the value of * the fontStyles property will be used instead.

    * *

    Note: if the text renderer has been customized with advanced font * formatting, it may override the values specified with * setFontStylesForState() and properties like * fontStyles and disabledFontStyles.

    * * @see http://doc.starling-framework.org/current/starling/text/TextFormat.html starling.text.TextFormat * @see #style:fontStyles */ public function setFontStylesForState(state:String, format:TextFormat):void { var key:String = "setFontStylesForState--" + state; if(this.processStyleRestriction(key)) { return; } function changeHandler(event:Event):void { processStyleRestriction(key); } var oldFormat:TextFormat = this._fontStylesSet.getFormatForState(state); if(oldFormat !== null) { oldFormat.removeEventListener(Event.CHANGE, changeHandler); } this._fontStylesSet.setFormatForState(state, format); if(format !== null) { format.addEventListener(Event.CHANGE, changeHandler); } } /** * Gets the icon to be used by the button when the button's * currentState property matches the specified state value. * *

    If a icon is not defined for a specific state, returns * null.

    * * @see #setIconForState() */ public function getIconForState(state:String):DisplayObject { return this._stateToIcon[state] as DisplayObject; } /** * Sets the icon to be used by the button when the button's * currentState property matches the specified state value. * *

    If an icon is not defined for a specific state, the value of the * defaultIcon property will be used instead.

    * * @see #style:defaultIcon * @see #getIconForState() * @see feathers.controls.ButtonState */ public function setIconForState(state:String, icon:DisplayObject):void { var key:String = "setIconForState--" + state; if(this.processStyleRestriction(key)) { if(icon !== null) { icon.dispose(); } return; } var oldIcon:DisplayObject = this._stateToIcon[state] as DisplayObject; if(oldIcon !== null && this.currentIcon === oldIcon) { //if this icon needs to be reused somewhere else, we need to //properly clean it up this.removeCurrentIcon(oldIcon); this.currentIcon = null; } if(icon !== null) { this._stateToIcon[state] = icon; } else { delete this._stateToIcon[state]; } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * Gets the scale to be used by the button when the button's * currentState property matches the specified state value. * *

    If a scale is not defined for a specific state, returns * NaN.

    * * @see #setScaleForState() */ public function getScaleForState(state:String):Number { if(state in this._stateToScale) { return this._stateToScale[state] as Number; } return NaN; } /** * Sets the scale to be used by the button when the button's * currentState property matches the specified state value. * *

    If an icon is not defined for a specific state, the value of the * defaultIcon property will be used instead.

    * * @see #getScaleForState() * @see feathers.controls.ButtonState */ public function setScaleForState(state:String, scale:Number):void { var key:String = "setScaleForState--" + state; if(this.processStyleRestriction(key)) { return; } if(scale === scale) //!isNaN { this._stateToScale[state] = scale; } else { delete this._stateToScale[state]; } } /** * @private */ override protected function initialize():void { super.initialize(); if(this.keyToState === null) { this.keyToState = new KeyToState(this, this.changeState); } if(this.keyToTrigger === null) { this.keyToTrigger = new KeyToTrigger(this); } if(this.longPress === null) { this.longPress = new LongPress(this); } if(this.dpadEnterKeyToState === null) { this.dpadEnterKeyToState = new KeyToState(this, this.changeState); this.dpadEnterKeyToState.keyCode = Keyboard.ENTER; this.dpadEnterKeyToState.keyLocation = 4; //KeyLocation.D_PAD is only in AIR } if(this.dpadEnterKeyToTrigger === null) { this.dpadEnterKeyToTrigger = new KeyToTrigger(this, Keyboard.ENTER); this.dpadEnterKeyToTrigger.keyLocation = 4; //KeyLocation.D_PAD is only in AIR } this.longPress.tapToTrigger = this.tapToTrigger; } /** * @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.refreshLongPressEvents(); this.refreshIcon(); } //most components don't need to check the state before passing //properties to a child component, but button is an exception if(textRendererInvalid || stylesInvalid || stateInvalid) { this.refreshLabelStyles(); } super.draw(); if(textRendererInvalid || stylesInvalid || stateInvalid || dataInvalid || sizeInvalid) { this.layoutContent(); } if(sizeInvalid || focusInvalid) { this.refreshFocusIndicator(); } } /** * @private */ override protected function autoSizeIfNeeded():Boolean { var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN var needsMinWidth:Boolean = this._explicitMinWidth !== this._explicitMinWidth; //isNaN var needsMinHeight:Boolean = this._explicitMinHeight !== this._explicitMinHeight; //isNaN if(!needsWidth && !needsHeight && !needsMinWidth && !needsMinHeight) { return false; } var labelRenderer:ITextRenderer = null; if(this._label !== null && this.labelTextRenderer) { labelRenderer = this.labelTextRenderer; this.refreshLabelTextRendererDimensions(true); this.labelTextRenderer.measureText(HELPER_POINT); } var adjustedGap:Number = this._gap; if(adjustedGap == Number.POSITIVE_INFINITY) { adjustedGap = this._minGap; } resetFluidChildDimensionsForMeasurement(this.currentSkin, this._explicitWidth, this._explicitHeight, this._explicitMinWidth, this._explicitMinHeight, this._explicitMaxWidth, this._explicitMaxHeight, this._explicitSkinWidth, this._explicitSkinHeight, this._explicitSkinMinWidth, this._explicitSkinMinHeight, this._explicitSkinMaxWidth, this._explicitSkinMaxHeight); var measureSkin:IMeasureDisplayObject = this.currentSkin as IMeasureDisplayObject; if(this.currentIcon is IValidating) { IValidating(this.currentIcon).validate(); } if(this.currentSkin is IValidating) { IValidating(this.currentSkin).validate(); } var newMinWidth:Number = this._explicitMinWidth; if(needsMinWidth) { if(labelRenderer !== null) { newMinWidth = HELPER_POINT.x; } else { newMinWidth = 0; } if(this.currentIcon !== null) { if(labelRenderer !== null) //both label and icon { if(this._iconPosition !== RelativePosition.TOP && this._iconPosition !== RelativePosition.BOTTOM && this._iconPosition !== RelativePosition.MANUAL) { newMinWidth += adjustedGap; if(this.currentIcon is IFeathersControl) { newMinWidth += IFeathersControl(this.currentIcon).minWidth; } else { newMinWidth += this.currentIcon.width; } } else //top, bottom, or manual { if(this.currentIcon is IFeathersControl) { var iconMinWidth:Number = IFeathersControl(this.currentIcon).minWidth; if(iconMinWidth > newMinWidth) { newMinWidth = iconMinWidth; } } else if(this.currentIcon.width > newMinWidth) { newMinWidth = this.currentIcon.width; } } } else //no label { if(this.currentIcon is IFeathersControl) { newMinWidth = IFeathersControl(this.currentIcon).minWidth; } else { newMinWidth = this.currentIcon.width; } } } newMinWidth += this._paddingLeft + this._paddingRight; if(this.currentSkin !== null) { if(measureSkin !== null) { if(measureSkin.minWidth > newMinWidth) { newMinWidth = measureSkin.minWidth; } } else if(this._explicitSkinMinWidth > newMinWidth) { newMinWidth = this._explicitSkinMinWidth; } } } var newMinHeight:Number = this._explicitMinHeight; if(needsMinHeight) { if(labelRenderer !== null) { newMinHeight = HELPER_POINT.y; } else { newMinHeight = 0; } if(this.currentIcon !== null) { if(labelRenderer !== null) //both label and icon { if(this._iconPosition === RelativePosition.TOP || this._iconPosition === RelativePosition.BOTTOM) { newMinHeight += adjustedGap; if(this.currentIcon is IFeathersControl) { newMinHeight += IFeathersControl(this.currentIcon).minHeight; } else { newMinHeight += this.currentIcon.height; } } else //left, right, manual { if(this.currentIcon is IFeathersControl) { var iconMinHeight:Number = IFeathersControl(this.currentIcon).minHeight; if(iconMinHeight > newMinHeight) { newMinHeight = iconMinHeight; } } else if(this.currentIcon.height > newMinHeight) { newMinHeight = this.currentIcon.height; } } } else //no label { if(this.currentIcon is IFeathersControl) { newMinHeight = IFeathersControl(this.currentIcon).minHeight; } else { newMinHeight = this.currentIcon.height; } } } newMinHeight += this._paddingTop + this._paddingBottom; if(this.currentSkin !== null) { if(measureSkin !== null) { if(measureSkin.minHeight > newMinHeight) { newMinHeight = measureSkin.minHeight; } } else if(this._explicitSkinMinHeight > newMinHeight) { newMinHeight = this._explicitSkinMinHeight; } } } var newWidth:Number = this._explicitWidth; if(needsWidth) { if(labelRenderer !== null) { newWidth = HELPER_POINT.x; } else { newWidth = 0; } if(this.currentIcon !== null) { if(labelRenderer !== null) //both label and icon { if(this._iconPosition !== RelativePosition.TOP && this._iconPosition !== RelativePosition.BOTTOM && this._iconPosition !== RelativePosition.MANUAL) { newWidth += adjustedGap + this.currentIcon.width; } else if(this.currentIcon.width > newWidth) //top, bottom, or manual { newWidth = this.currentIcon.width; } } else //no label { newWidth = this.currentIcon.width; } } newWidth += this._paddingLeft + this._paddingRight; if(this.currentSkin !== null && this.currentSkin.width > newWidth) { newWidth = this.currentSkin.width; } } var newHeight:Number = this._explicitHeight; if(needsHeight) { if(labelRenderer !== null) { newHeight = HELPER_POINT.y; } else { newHeight = 0; } if(this.currentIcon !== null) { if(labelRenderer !== null) //both label and icon { if(this._iconPosition === RelativePosition.TOP || this._iconPosition === RelativePosition.BOTTOM) { newHeight += adjustedGap + this.currentIcon.height; } else if(this.currentIcon.height > newHeight) //left, right, manual { newHeight = this.currentIcon.height; } } else //no label { newHeight = this.currentIcon.height; } } newHeight += this._paddingTop + this._paddingBottom; if(this.currentSkin !== null && this.currentSkin.height > newHeight) { newHeight = this.currentSkin.height; } } return this.saveMeasurements(newWidth, newHeight, newMinWidth, newMinHeight); } /** * @private */ override protected function changeState(state:String):void { var oldState:String = this._currentState; if(oldState === state) { return; } super.changeState(state); if(this.getScaleForCurrentState() != this.getScaleForCurrentState(oldState)) { this.setRequiresRedraw(); } } /** * 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()); var labelStyleName:String = this._customLabelStyleName != null ? this._customLabelStyleName : this.labelStyleName; this.labelTextRenderer.styleNameList.add(labelStyleName); if(this.labelTextRenderer is IStateObserver) { IStateObserver(this.labelTextRenderer).stateContext = this; } this.addChild(DisplayObject(this.labelTextRenderer)); this._explicitLabelWidth = this.labelTextRenderer.explicitWidth; this._explicitLabelHeight = this.labelTextRenderer.explicitHeight; this._explicitLabelMinWidth = this.labelTextRenderer.explicitMinWidth; this._explicitLabelMinHeight = this.labelTextRenderer.explicitMinHeight; this._explicitLabelMaxWidth = this.labelTextRenderer.explicitMaxWidth; this._explicitLabelMaxHeight = this.labelTextRenderer.explicitMaxHeight; } } /** * @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 currentIcon property. * *

    For internal use in subclasses.

    */ protected function refreshIcon():void { var oldIcon:DisplayObject = this.currentIcon; this.currentIcon = this.getCurrentIcon(); if(this.currentIcon is IFeathersControl) { IFeathersControl(this.currentIcon).isEnabled = this._isEnabled; } if(this.currentIcon !== oldIcon) { if(oldIcon !== null) { this.removeCurrentIcon(oldIcon); } if(this.currentIcon !== null) { if(this.currentIcon is IStateObserver) { IStateObserver(this.currentIcon).stateContext = this; } //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); if(this.currentIcon is IFeathersControl) { IFeathersControl(this.currentIcon).addEventListener(FeathersEventType.RESIZE, currentIcon_resizeHandler); } } } } /** * @private */ protected function removeCurrentIcon(icon:DisplayObject):void { if(icon === null) { return; } if(icon is IFeathersControl) { IFeathersControl(icon).removeEventListener(FeathersEventType.RESIZE, currentIcon_resizeHandler); } if(icon is IStateObserver) { IStateObserver(icon).stateContext = null; } if(icon.parent === this) { this.removeChild(icon, false); } } /** * @private */ protected function getCurrentIcon():DisplayObject { var result:DisplayObject = this._stateToIcon[this._currentState] as DisplayObject; if(result !== null) { return result; } return this._defaultIcon; } /** * @private */ protected function getScaleForCurrentState(state:String = null):Number { if(state === null) { state = this._currentState; } if(state in this._stateToScale) { return this._stateToScale[state]; } return 1; } /** * @private */ protected function refreshLabelStyles():void { if(this.labelTextRenderer === null) { return; } this.labelTextRenderer.fontStyles = this._fontStylesSet; this.labelTextRenderer.wordWrap = this._wordWrap; for(var propertyName:String in this._defaultLabelProperties) { var propertyValue:Object = this._defaultLabelProperties[propertyName]; this.labelTextRenderer[propertyName] = propertyValue; } } /** * @private */ override protected function refreshTriggeredEvents():void { super.refreshTriggeredEvents(); this.keyToTrigger.isEnabled = this._isEnabled; this.dpadEnterKeyToTrigger.isEnabled = this._isEnabled; } /** * @private */ protected function refreshLongPressEvents():void { this.longPress.isEnabled = this._isEnabled && this._isLongPressEnabled; this.longPress.longPressDuration = this._longPressDuration; } /** * Positions and sizes the button's content. * *

    For internal use in subclasses.

    */ protected function layoutContent():void { this.refreshLabelTextRendererDimensions(false); var labelRenderer:DisplayObject = null; if(this._label !== null && this.labelTextRenderer !== null) { labelRenderer = DisplayObject(this.labelTextRenderer); } var iconIsInLayout:Boolean = this.currentIcon && this._iconPosition != RelativePosition.MANUAL; if(labelRenderer && iconIsInLayout) { this.positionSingleChild(labelRenderer); this.positionLabelAndIcon(); } else if(labelRenderer) { this.positionSingleChild(labelRenderer); } else if(iconIsInLayout) { this.positionSingleChild(this.currentIcon); } if(this.currentIcon) { if(this._iconPosition == RelativePosition.MANUAL) { this.currentIcon.x = this._paddingLeft; this.currentIcon.y = this._paddingTop; } this.currentIcon.x += this._iconOffsetX; this.currentIcon.y += this._iconOffsetY; } if(labelRenderer) { this.labelTextRenderer.x += this._labelOffsetX; this.labelTextRenderer.y += this._labelOffsetY; } } /** * @private */ protected function refreshLabelTextRendererDimensions(forMeasurement:Boolean):void { var oldIgnoreIconResizes:Boolean = this._ignoreIconResizes; this._ignoreIconResizes = true; if(this.currentIcon is IValidating) { IValidating(this.currentIcon).validate(); } this._ignoreIconResizes = oldIgnoreIconResizes; if(this._label === null || this.labelTextRenderer === null) { return; } var calculatedWidth:Number = this.actualWidth; var calculatedHeight:Number = this.actualHeight; if(forMeasurement) { calculatedWidth = this._explicitWidth; if(calculatedWidth !== calculatedWidth) //isNaN { calculatedWidth = this._explicitMaxWidth; } calculatedHeight = this._explicitHeight; if(calculatedHeight !== calculatedHeight) //isNaN { calculatedHeight = this._explicitMaxHeight; } } calculatedWidth -= (this._paddingLeft + this._paddingRight); calculatedHeight -= (this._paddingTop + this._paddingBottom); if(this.currentIcon !== null) { var adjustedGap:Number = this._gap; if(adjustedGap == Number.POSITIVE_INFINITY) { adjustedGap = this._minGap; } if(this._iconPosition === RelativePosition.LEFT || this._iconPosition === RelativePosition.LEFT_BASELINE || this._iconPosition === RelativePosition.RIGHT || this._iconPosition === RelativePosition.RIGHT_BASELINE) { calculatedWidth -= (this.currentIcon.width + adjustedGap); } if(this._iconPosition === RelativePosition.TOP || this._iconPosition === RelativePosition.BOTTOM) { calculatedHeight -= (this.currentIcon.height + adjustedGap); } } if(calculatedWidth < 0) { calculatedWidth = 0; } if(calculatedHeight < 0) { calculatedHeight = 0; } if(calculatedWidth > this._explicitLabelMaxWidth) { calculatedWidth = this._explicitLabelMaxWidth; } if(calculatedHeight > this._explicitLabelMaxHeight) { calculatedHeight = this._explicitLabelMaxHeight; } this.labelTextRenderer.width = this._explicitLabelWidth; this.labelTextRenderer.height = this._explicitLabelHeight; this.labelTextRenderer.minWidth = this._explicitLabelMinWidth; this.labelTextRenderer.minHeight = this._explicitLabelMinHeight; this.labelTextRenderer.maxWidth = calculatedWidth; this.labelTextRenderer.maxHeight = calculatedHeight; this.labelTextRenderer.validate(); if(!forMeasurement) { calculatedWidth = this.labelTextRenderer.width; calculatedHeight = this.labelTextRenderer.height; //setting all of these dimensions explicitly means that the text //renderer won't measure itself again when it validates, which //helps performance. we'll reset them when the button needs to //measure itself. this.labelTextRenderer.width = calculatedWidth; this.labelTextRenderer.height = calculatedHeight; this.labelTextRenderer.minWidth = calculatedWidth; this.labelTextRenderer.minHeight = calculatedHeight; } } /** * @private */ protected function positionSingleChild(displayObject:DisplayObject):void { if(this._horizontalAlign == HorizontalAlign.LEFT) { displayObject.x = this._paddingLeft; } else if(this._horizontalAlign == HorizontalAlign.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 == VerticalAlign.TOP) { displayObject.y = this._paddingTop; } else if(this._verticalAlign == VerticalAlign.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 == RelativePosition.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 == VerticalAlign.TOP) { this.labelTextRenderer.y += this.currentIcon.height + this._gap; } else if(this._verticalAlign == VerticalAlign.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 == RelativePosition.RIGHT || this._iconPosition == RelativePosition.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 == HorizontalAlign.RIGHT) { this.labelTextRenderer.x -= this.currentIcon.width + this._gap; } else if(this._horizontalAlign == HorizontalAlign.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 == RelativePosition.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 == VerticalAlign.BOTTOM) { this.labelTextRenderer.y -= this.currentIcon.height + this._gap; } else if(this._verticalAlign == VerticalAlign.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 == RelativePosition.LEFT || this._iconPosition == RelativePosition.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 == HorizontalAlign.LEFT) { this.labelTextRenderer.x += this._gap + this.currentIcon.width; } else if(this._horizontalAlign == HorizontalAlign.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 == RelativePosition.LEFT || this._iconPosition == RelativePosition.RIGHT) { if(this._verticalAlign == VerticalAlign.TOP) { this.currentIcon.y = this._paddingTop; } else if(this._verticalAlign == VerticalAlign.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 == RelativePosition.LEFT_BASELINE || this._iconPosition == RelativePosition.RIGHT_BASELINE) { this.currentIcon.y = this.labelTextRenderer.y + (this.labelTextRenderer.baseline) - this.currentIcon.height; } else //top or bottom { if(this._horizontalAlign == HorizontalAlign.LEFT) { this.currentIcon.x = this._paddingLeft; } else if(this._horizontalAlign == HorizontalAlign.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 childProperties_onChange(proxy:PropertyProxy, name:Object):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function currentIcon_resizeHandler():void { if(this._ignoreIconResizes) { return; } this.invalidate(INVALIDATION_FLAG_SIZE); } /** * @private */ protected function fontStyles_changeHandler(event:Event):void { this.invalidate(INVALIDATION_FLAG_STYLES); } } } ================================================ FILE: source/feathers/controls/ButtonGroup.as ================================================ /* Feathers Copyright 2012-2021 Bowler Hat LLC. 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.ITextBaselineControl; import feathers.core.PropertyProxy; import feathers.data.IListCollection; import feathers.events.CollectionEventType; import feathers.events.FeathersEventType; import feathers.layout.Direction; import feathers.layout.FlowLayout; import feathers.layout.HorizontalAlign; import feathers.layout.HorizontalLayout; import feathers.layout.ILayout; import feathers.layout.IVirtualLayout; import feathers.layout.LayoutBoundsResult; import feathers.layout.VerticalAlign; import feathers.layout.VerticalLayout; import feathers.layout.ViewPortBounds; import feathers.skins.IStyleProvider; import flash.utils.Dictionary; import starling.display.DisplayObject; import starling.events.Event; /** * A style name to add to all buttons in this button group. Typically * used by a theme to provide different styles to different button groups. * *

    The following example provides a custom button style name:

    * * * group.customButtonStyleName = "my-custom-button"; * *

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

    * * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-button", setCustomButtonStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_BUTTON * @see feathers.core.FeathersControl#styleNameList */ [Style(name="customButtonStyleName",type="String")] /** * A style name to add to the first button in this button group. * Typically used by a theme to provide different styles to the first * button. * *

    The following example provides a custom first button style name:

    * * * group.customFirstButtonStyleName = "my-custom-first-button"; * *

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

    * * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-first-button", setCustomFirstButtonStyles ); * * @default null * * @see feathers.core.FeathersControl#styleNameList */ [Style(name="customFirstButtonStyleName",type="String")] /** * A style name to add to the last button in this button group. * Typically used by a theme to provide different styles to the last * button. * *

    The following example provides a custom last button style name:

    * * * group.customLastButtonStyleName = "my-custom-last-button"; * *

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

    * * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-last-button", setCustomLastButtonStyles ); * * @default null * * @see feathers.core.FeathersControl#styleNameList */ [Style(name="customLastButtonStyleName",type="String")] /** * The button group layout is either vertical or horizontal. * *

    If the direction is * Direction.HORIZONTAL and * distributeButtonSizes is false, the buttons * may be displayed in multiple rows, if they won't fit in one row * horizontally.

    * *

    The following example sets the layout direction of the buttons * to line them up horizontally:

    * * * group.direction = Direction.HORIZONTAL; * *

    Note: The Direction.NONE * constant is not supported.

    * * @default feathers.layout.Direction.VERTICAL * * @see feathers.layout.Direction#HORIZONTAL * @see feathers.layout.Direction#VERTICAL */ [Style(name="direction",type="String")] /** * If true, the buttons will be equally sized in the * direction of the layout. In other words, if the button group is * horizontal, each button will have the same width, and if the button * group is vertical, each button will have the same height. If * false, the buttons will be sized to their ideal * dimensions. * *

    The following example doesn't distribute the button sizes:

    * * * group.distributeButtonSizes = false; * * @default true */ [Style(name="distributeButtonSizes",type="Boolean")] /** * Space, in pixels, between the first two buttons. If NaN, * the default gap property will be used. * *

    The following example sets the gap between the first and second * button to a different value than the standard gap:

    * * * group.firstGap = 30; * group.gap = 20; * * @default NaN * * @see #style:gap * @see #style:lastGap */ [Style(name="firstGap",type="Number")] /** * Space, in pixels, between buttons. * *

    The following example sets the gap used for the button layout to * 20 pixels:

    * * * group.gap = 20; * * @default 0 * * @see #style:firstGap * @see #style:lastGap */ [Style(name="gap",type="Number")] /** * Determines how the buttons are horizontally aligned within the bounds * of the button group (on the x-axis). * *

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

    * * * group.horizontalAlign = HorizontalAlign.LEFT; * * @default feathers.layout.HorizontalAlign.JUSTIFY * * @see feathers.layout.HorizontalAlign#LEFT * @see feathers.layout.HorizontalAlign#CENTER * @see feathers.layout.HorizontalAlign#RIGHT * @see feathers.layout.HorizontalAlign#JUSTIFY */ [Style(name="horizontalAlign",type="String")] /** * Space, in pixels, between the last two buttons. If NaN, * the default gap property will be used. * *

    The following example sets the gap between the last and next to last * button to a different value than the standard gap:

    * * * group.lastGap = 30; * group.gap = 20; * * @default NaN * * @see #style:gap * @see #style:firstGap */ [Style(name="lastGap",type="Number")] /** * 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. * *

    In the following example, the padding of all sides of the group * is set to 20 pixels:

    * * * group.padding = 20; * * @default 0 * * @see #style:paddingTop * @see #style:paddingRight * @see #style:paddingBottom * @see #style:paddingLeft */ [Style(name="padding",type="Number")] /** * The minimum space, in pixels, between the group's top edge and the * group's buttons. * *

    In the following example, the padding on the top edge of the * group is set to 20 pixels:

    * * * group.paddingTop = 20; * * @default 0 * * @see #style:padding */ [Style(name="paddingTop",type="Number")] /** * The minimum space, in pixels, between the group's right edge and the * group's buttons. * *

    In the following example, the padding on the right edge of the * group is set to 20 pixels:

    * * * group.paddingRight = 20; * * @default 0 * * @see #style:padding */ [Style(name="paddingRight",type="Number")] /** * The minimum space, in pixels, between the group's bottom edge and the * group's buttons. * *

    In the following example, the padding on the bottom edge of the * group is set to 20 pixels:

    * * * group.paddingBottom = 20; * * @default 0 * * @see #style:padding */ [Style(name="paddingBottom",type="Number")] /** * The minimum space, in pixels, between the group's left edge and the * group's buttons. * *

    In the following example, the padding on the left edge of the * group is set to 20 pixels:

    * * * group.paddingLeft = 20; * * @default 0 * * @see #style:padding */ [Style(name="paddingLeft",type="Number")] /** * Determines how the buttons are vertically aligned within the bounds * of the button group (on the y-axis). * *

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

    * * * group.verticalAlign = VerticalAlign.TOP; * * @default feathers.layout.VerticalAlign.JUSTIFY * * @see feathers.layout.VerticalAlign#TOP * @see feathers.layout.VerticalAlign#MIDDLE * @see feathers.layout.VerticalAlign#BOTTOM * @see feathers.layout.VerticalAlign#JUSTIFY */ [Style(name="verticalAlign",type="String")] /** * 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 ArrayCollection( * [ * { 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")] /** * 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 ArrayCollection( * [ * { 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 * * @productversion Feathers 1.0.0 */ public class ButtonGroup extends FeathersControl implements ITextBaselineControl { /** * 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", "isLongPressEnabled", "name", ]; /** * @private */ private static const DEFAULT_BUTTON_EVENTS:Vector. = new [ Event.TRIGGERED, Event.CHANGE, FeathersEventType.LONG_PRESS, ]; /** * 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"; /** * @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 #style:customButtonStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var buttonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; /** * The value added to the styleNameList of the first button. * *

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

    * * @see #style:customFirstButtonStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var firstButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; /** * The value added to the styleNameList of the last button. * *

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

    * * @see #style:customLastButtonStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var lastButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON; /** * @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.