added in Android Skins Signed-off-by: OmPrakash Muppirala <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/flex-examples/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-examples/commit/539852e9 Tree: http://git-wip-us.apache.org/repos/asf/flex-examples/tree/539852e9 Diff: http://git-wip-us.apache.org/repos/asf/flex-examples/diff/539852e9 Branch: refs/heads/develop Commit: 539852e984111a284dfda239de6f2d26e42b2e5e Parents: 1f0cce9 Author: nasha001 <[email protected]> Authored: Tue Nov 4 13:00:50 2014 -0500 Committer: OmPrakash Muppirala <[email protected]> Committed: Tue Nov 4 11:07:41 2014 -0800 ---------------------------------------------------------------------- tourdeflexmobile/slideoff.png | Bin 15894 -> 0 bytes .../src/spark/skins/android4/ActionBarSkin.as | 725 +++++++++++++++ .../skins/android4/ButtonBarFirstButtonSkin.as | 93 ++ .../skins/android4/ButtonBarMiddleButtonSkin.as | 95 ++ .../src/spark/skins/android4/ButtonBarSkin.as | 166 ++++ .../src/spark/skins/android4/ButtonSkin.as | 397 +++++++++ .../src/spark/skins/android4/CalloutSkin.as | 825 +++++++++++++++++ .../src/spark/skins/android4/CheckBoxSkin.as | 268 ++++++ .../src/spark/skins/android4/DateSpinnerSkin.as | 153 ++++ .../src/spark/skins/android4/HScrollBarSkin.as | 205 +++++ .../spark/skins/android4/HScrollBarThumbSkin.as | 169 ++++ .../src/spark/skins/android4/HSliderSkin.as | 293 ++++++ .../spark/skins/android4/HSliderThumbSkin.as | 333 +++++++ .../spark/skins/android4/HSliderTrackSkin.as | 227 +++++ .../src/spark/skins/android4/ListSkin.as | 204 +++++ .../android4/MobileGridHeaderButtonBarSkin.as | 90 ++ .../src/spark/skins/android4/MobileGridSkin.as | 159 ++++ .../src/spark/skins/android4/RadioButtonSkin.as | 253 ++++++ .../android4/ScrollingStageTextAreaSkin.as | 53 ++ .../android4/ScrollingStageTextInputSkin.as | 54 ++ .../skins/android4/SpinnerListContainerSkin.as | 327 +++++++ .../skins/android4/SpinnerListScrollerSkin.mxml | 94 ++ .../src/spark/skins/android4/SpinnerListSkin.as | 293 ++++++ .../skins/android4/SplitViewNavigatorSkin.as | 157 ++++ .../spark/skins/android4/StageTextAreaSkin.as | 185 ++++ .../spark/skins/android4/StageTextInputSkin.as | 130 +++ .../android4/TabbedViewNavigatorTabBarSkin.as | 122 +++ .../skins/android4/TextAreaHScrollBarSkin.as | 105 +++ .../android4/TextAreaHScrollBarThumbSkin.as | 116 +++ .../src/spark/skins/android4/TextAreaSkin.as | 892 +++++++++++++++++++ .../skins/android4/TextAreaVScrollBarSkin.as | 105 +++ .../android4/TextAreaVScrollBarThumbSkin.as | 117 +++ .../src/spark/skins/android4/TextInputSkin.as | 375 ++++++++ .../spark/skins/android4/ToggleSwitchSkin.as | 506 +++++++++++ .../android4/TransparentActionButtonSkin.as | 108 +++ .../android4/TransparentNavigationButtonSkin.as | 109 +++ .../src/spark/skins/android4/VScrollBarSkin.as | 207 +++++ .../spark/skins/android4/VScrollBarThumbSkin.as | 178 ++++ .../spark/skins/android4/ViewMenuItemSkin.as | 238 +++++ .../src/spark/skins/android4/ViewMenuSkin.mxml | 184 ++++ .../android4/assets/ActionBarBackground.fxg | 55 ++ .../skins/android4/assets/BusyIndicator.fxg | 64 ++ .../assets/ButtonBarFirstButton_down.fxg | 34 + .../ButtonBarFirstButton_selectedDown.fxg | 39 + .../assets/ButtonBarFirstButton_selectedUp.fxg | 34 + .../android4/assets/ButtonBarFirstButton_up.fxg | 29 + .../assets/ButtonBarMiddleButton_down.fxg | 70 ++ .../ButtonBarMiddleButton_selectedDown.fxg | 75 ++ .../assets/ButtonBarMiddleButton_selectedUp.fxg | 70 ++ .../assets/ButtonBarMiddleButton_up.fxg | 65 ++ .../spark/skins/android4/assets/Button_down.fxg | 73 ++ .../spark/skins/android4/assets/Button_up.fxg | 60 ++ .../assets/CalloutContentBackground.fxg | 51 ++ .../skins/android4/assets/CheckBox_down.fxg | 34 + .../android4/assets/CheckBox_downSelected.fxg | 35 + .../assets/CheckBox_downSymbolSelected.fxg | 29 + .../spark/skins/android4/assets/CheckBox_up.fxg | 31 + .../android4/assets/CheckBox_upSelected.fxg | 29 + .../assets/CheckBox_upSymbolSelected.fxg | 33 + .../android4/assets/HSliderThumb_normal.fxg | 34 + .../android4/assets/HSliderThumb_pressed.fxg | 39 + .../skins/android4/assets/HSliderTrack.fxg | 29 + .../android4/assets/HSliderTrack_filled.fxg | 29 + .../skins/android4/assets/RadioButton_down.fxg | 34 + .../assets/RadioButton_downSymbolSelected.fxg | 29 + .../skins/android4/assets/RadioButton_up.fxg | 29 + .../assets/RadioButton_upSymbolSelected.fxg | 36 + .../assets/SpinnerListContainerBackground.fxg | 48 + .../SpinnerListContainerSelectionIndicator.fxg | 45 + .../assets/SpinnerListContainerShadow.fxg | 40 + .../skins/android4/assets/TextInput_border.fxg | 34 + .../assets/TextInput_border_Rectangle.fxg | 28 + .../assets/TextInput_border_Rectangle_focus.fxg | 28 + .../android4/assets/TextInput_border_focus.fxg | 34 + .../android4/assets/ToggleSwitchBackground.fxg | 29 + .../android4/assets/ToggleSwitchThumb_off.fxg | 40 + .../android4/assets/ToggleSwitchThumb_on.fxg | 40 + .../assets/TransparentActionButton_down.fxg | 69 ++ .../assets/TransparentActionButton_up.fxg | 59 ++ .../assets/TransparentNavigationButton_down.fxg | 69 ++ .../assets/TransparentNavigationButton_up.fxg | 59 ++ .../skins/android4/assets/ViewMenuItem_down.fxg | 36 + .../android4/assets/ViewMenuItem_showsCaret.fxg | 36 + .../skins/android4/assets/ViewMenuItem_up.fxg | 35 + .../skins/android4/assets/fonts/Roboto-Bold.ttf | Bin 0 -> 84924 bytes .../android4/assets/fonts/Roboto-Regular.ttf | Bin 0 -> 84564 bytes .../android4/supportClasses/CalloutArrow.as | 457 ++++++++++ .../supportClasses/StageTextSkinBase.as | 402 +++++++++ .../android4/supportClasses/TextSkinBase.as | 213 +++++ 89 files changed, 12280 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/slideoff.png ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/slideoff.png b/tourdeflexmobile/slideoff.png deleted file mode 100644 index 538d0f8..0000000 Binary files a/tourdeflexmobile/slideoff.png and /dev/null differ http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as b/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as new file mode 100644 index 0000000..f1ef220 --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as @@ -0,0 +1,725 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ + import flash.display.GradientType; + import flash.events.Event; + import flash.text.TextFormatAlign; + + import mx.core.DPIClassification; + import mx.core.mx_internal; + import mx.utils.ColorUtil; + + import spark.components.ActionBar; + import spark.components.Group; + import spark.components.supportClasses.StyleableTextField; + import spark.core.SpriteVisualElement; + import spark.layouts.HorizontalAlign; + import spark.layouts.HorizontalLayout; + import spark.layouts.VerticalAlign; + import spark.skins.android4.assets.ActionBarBackground; + import spark.skins.mobile.supportClasses.MobileSkin; + + use namespace mx_internal; + + /** + * The default skin class for the Spark ActionBar component in mobile + * applications. + * + * @see spark.components.ActionBar + * @see spark.skins.mobile.TransparentNavigationButtonSkin + * @see spark.skins.mobile.BeveledBackButtonSkin + * @see spark.skins.mobile.TransparentActionButtonSkin + * @see spark.skins.mobile.BeveledActionButtonSkin + * + * @langversion 3.0 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public class ActionBarSkin extends MobileSkin + { + //-------------------------------------------------------------------------- + // + // Class constants + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + mx_internal static const ACTIONBAR_CHROME_COLOR_RATIOS:Array = [0, 80]; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public function ActionBarSkin() + { + super(); + + borderClass = spark.skins.android4.assets.ActionBarBackground; + + switch (applicationDPI) + { + + case DPIClassification.DPI_640: + { + borderSize = 2; + layoutContentGroupHeight = 172; + layoutTitleGroupHorizontalPadding = 52; + + break; + } + case DPIClassification.DPI_480: + { + borderSize = 2; + layoutContentGroupHeight = 130; + layoutTitleGroupHorizontalPadding = 40; + + + break; + } + case DPIClassification.DPI_320: + { + borderSize = 2; + layoutContentGroupHeight = 86; + layoutTitleGroupHorizontalPadding = 26; + + break; + } + case DPIClassification.DPI_240: + { + borderSize = 1; + layoutContentGroupHeight = 65; + layoutTitleGroupHorizontalPadding = 20; + + break; + } + case DPIClassification.DPI_120: + { + borderSize = 1; + layoutContentGroupHeight = 32; + layoutTitleGroupHorizontalPadding = 10; + + break; + } + default: + { + // default DPI_160 + borderSize = 1; + layoutContentGroupHeight = 43; + layoutTitleGroupHorizontalPadding = 13; + + break; + } + } + } + + //-------------------------------------------------------------------------- + // + // Graphics variables + // + //-------------------------------------------------------------------------- + + /** + * FXG Class reference for the ActionBar background border graphic. + * + * @langversion 3.0 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected var borderClass:Class; + + //-------------------------------------------------------------------------- + // + // Layout variables + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private var borderSize:uint; + + /** + * Default height for navigationGroup, titleGroup and actionGroup. + * + * @langversion 3.0 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected var layoutContentGroupHeight:uint; + + /** + * Default horizontal padding for the titleGroup and titleDisplay. + * + * @langversion 3.0 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected var layoutTitleGroupHorizontalPadding:uint; + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @copy spark.skins.spark.ApplicationSkin#hostComponent + */ + public var hostComponent:ActionBar; + + /** + * @private + */ + private var _navigationVisible:Boolean = false; + + /** + * @private + */ + private var _titleContentVisible:Boolean = false; + + /** + * @private + */ + private var _actionVisible:Boolean = false; + + /** + * @private + */ + private var border:SpriteVisualElement; + + //-------------------------------------------------------------------------- + // + // Skin parts + // + //-------------------------------------------------------------------------- + + /** + * @copy spark.components.ActionBar#navigationGroup + */ + public var navigationGroup:Group; + + /** + * @copy spark.components.ActionBar#titleGroup + */ + public var titleGroup:Group; + + /** + * @copy spark.components.ActionBar#actionGroup + */ + public var actionGroup:Group; + + /** + * @copy spark.components.ActionBar#titleDisplay + * + * @private + * Wraps a StyleableTextField in a UIComponent to be compatible with + * ViewTransition effects. + */ + public var titleDisplay:TitleDisplayComponent; + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + override protected function createChildren():void + { + if (borderClass) + { + border = new borderClass(); + addChild(border); + } + + navigationGroup = new Group(); + var hLayout:HorizontalLayout = new HorizontalLayout(); + hLayout.horizontalAlign = HorizontalAlign.LEFT; + hLayout.verticalAlign = VerticalAlign.MIDDLE; + hLayout.gap = 0; + hLayout.paddingLeft = hLayout.paddingTop = hLayout.paddingRight = hLayout.paddingBottom = 0; + navigationGroup.layout = hLayout; + navigationGroup.id = "navigationGroup"; + + titleGroup = new Group(); + hLayout = new HorizontalLayout(); + hLayout.horizontalAlign = HorizontalAlign.LEFT; + hLayout.verticalAlign = VerticalAlign.MIDDLE; + hLayout.gap = 0; + hLayout.paddingLeft = hLayout.paddingRight = layoutTitleGroupHorizontalPadding; + hLayout.paddingTop = hLayout.paddingBottom = 0; + titleGroup.layout = hLayout; + titleGroup.id = "titleGroup"; + + actionGroup = new Group(); + hLayout = new HorizontalLayout(); + hLayout.horizontalAlign = HorizontalAlign.RIGHT; + hLayout.verticalAlign = VerticalAlign.MIDDLE; + hLayout.gap = 0; + hLayout.paddingLeft = hLayout.paddingTop = hLayout.paddingRight = hLayout.paddingBottom = 0; + actionGroup.layout = hLayout; + actionGroup.id = "actionGroup"; + + titleDisplay = new TitleDisplayComponent(); + titleDisplay.id = "titleDisplay"; + + // initialize titleAlign style (center is managed explicitly in layoutContents) + var titleAlign:String = getStyle("titleAlign"); + titleAlign = (titleAlign == "center") ? TextFormatAlign.LEFT : titleAlign; + titleDisplay.setStyle("textAlign", titleAlign); + + addChild(navigationGroup); + addChild(titleGroup); + addChild(actionGroup); + addChild(titleDisplay); + } + + /** + * @private + */ + override protected function measure():void + { + var titleWidth:Number = 0; + var titleHeight:Number = 0; + + if (_titleContentVisible) + { + titleWidth = titleGroup.getPreferredBoundsWidth(); + titleHeight = titleGroup.getPreferredBoundsHeight(); + } + else + { + // use titleLayout for paddingLeft and paddingRight + var layoutObject:Object = hostComponent.titleLayout; + titleWidth = ((layoutObject.paddingLeft) ? Number(layoutObject.paddingLeft) : 0) + + ((layoutObject.paddingRight) ? Number(layoutObject.paddingRight) : 0) + + titleDisplay.getPreferredBoundsWidth(); + + titleHeight = titleDisplay.getPreferredBoundsHeight(); + } + + measuredWidth = + getStyle("paddingLeft") + + navigationGroup.getPreferredBoundsWidth() + + titleWidth + + actionGroup.getPreferredBoundsWidth() + + getStyle("paddingRight"); + + // measuredHeight is contentGroupHeight, 2x border on top and bottom + measuredHeight = + getStyle("paddingTop") + + Math.max(layoutContentGroupHeight, + navigationGroup.getPreferredBoundsHeight(), + actionGroup.getPreferredBoundsHeight(), + titleHeight) + + getStyle("paddingBottom"); + } + + /** + * @private + */ + override protected function commitCurrentState():void + { + super.commitCurrentState(); + + _titleContentVisible = currentState.indexOf("titleContent") >= 0; + _navigationVisible = currentState.indexOf("Navigation") >= 0; + _actionVisible = currentState.indexOf("Action") >= 0; + + invalidateSize(); + invalidateDisplayList(); + } + + /** + * @private + */ + override public function styleChanged(styleProp:String):void + { + if (titleDisplay) + { + var allStyles:Boolean = !styleProp || styleProp == "styleName"; + + if (allStyles || (styleProp == "titleAlign")) + { + var titleAlign:String = getStyle("titleAlign"); + + if (titleAlign == "center") + { + // If the title align is set to center, the alignment is set to LEFT + // so that the skin can manually center the component in layoutContents + titleDisplay.setStyle("textAlign", TextFormatAlign.LEFT); + } + else + { + titleDisplay.setStyle("textAlign", titleAlign); + } + } + } + + super.styleChanged(styleProp); + } + + /** + * @private + */ + override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void + { + super.layoutContents(unscaledWidth, unscaledHeight); + + var navigationGroupWidth:Number = 0; + + var paddingLeft:Number = getStyle("paddingLeft"); + var paddingRight:Number = getStyle("paddingRight"); + var paddingTop:Number = getStyle("paddingTop"); + var paddingBottom:Number = getStyle("paddingBottom"); + + var titleCompX:Number = paddingLeft; + var titleCompWidth:Number = 0; + + var actionGroupX:Number = unscaledWidth; + var actionGroupWidth:Number = 0; + + // remove top and bottom padding from content group height + var contentGroupsHeight:Number = Math.max(0, unscaledHeight - paddingTop - paddingBottom); + + if (border) + { + // FXG uses scale-9, drop shadow is drawn outside the bounds + setElementSize(border, unscaledWidth, unscaledHeight); + } + + // position groups, overlap of navigation and action groups is allowed + // when overlap occurs, titleDisplay/titleGroup is not visible + if (_navigationVisible) + { + navigationGroupWidth = navigationGroup.getPreferredBoundsWidth(); + titleCompX += navigationGroupWidth; + + setElementSize(navigationGroup, navigationGroupWidth, contentGroupsHeight); + setElementPosition(navigationGroup, paddingLeft, paddingTop); + } + + if (_actionVisible) + { + // actionGroup x position can be negative + actionGroupWidth = actionGroup.getPreferredBoundsWidth(); + actionGroupX = unscaledWidth - actionGroupWidth - paddingRight; + + setElementSize(actionGroup, actionGroupWidth, contentGroupsHeight); + setElementPosition(actionGroup, actionGroupX, paddingTop); + } + + // titleGroup or titleDisplay is given remaining width after navigation + // and action groups preferred widths + titleCompWidth = unscaledWidth - navigationGroupWidth - actionGroupWidth + - paddingLeft - paddingRight; + + if (titleCompWidth <= 0) + { + titleDisplay.visible = false; + titleGroup.visible = false; + } + else if (_titleContentVisible) + { + titleDisplay.visible = false; + titleGroup.visible = true; + + // use titleGroup for titleContent + setElementSize(titleGroup, titleCompWidth, contentGroupsHeight); + setElementPosition(titleGroup, titleCompX, paddingTop); + } + else + { + // use titleDisplay for title text label + titleGroup.visible = false; + + // use titleLayout for paddingLeft and paddingRight + var layoutObject:Object = hostComponent.titleLayout; + var titlePaddingLeft:Number = (layoutObject.paddingLeft) ? Number(layoutObject.paddingLeft) : 0; + var titlePaddingRight:Number = (layoutObject.paddingRight) ? Number(layoutObject.paddingRight) : 0; + + // align titleDisplay to the absolute center + var titleAlign:String = getStyle("titleAlign"); + + // check for available width after padding + if ((titleCompWidth - titlePaddingLeft - titlePaddingRight) <= 0) + { + titleCompX = 0; + titleCompWidth = 0; + } + else if (titleAlign == "center") + { + // use LEFT instead of CENTER + titleCompWidth = titleDisplay.getExplicitOrMeasuredWidth(); + + // use x position of titleDisplay to implement CENTER + titleCompX = Math.round((unscaledWidth - titleCompWidth) / 2); + + var navigationOverlap:Number = navigationGroupWidth + titlePaddingLeft - titleCompX; + var actionOverlap:Number = (titleCompX + titleCompWidth + titlePaddingRight) - actionGroupX; + + // shrink and/or move titleDisplay width if there is any + // overlap after centering + if ((navigationOverlap > 0) && (actionOverlap > 0)) + { + // remaining width + titleCompX = navigationGroupWidth + titlePaddingLeft; + titleCompWidth = unscaledWidth - navigationGroupWidth - actionGroupWidth - titlePaddingLeft - titlePaddingRight; + } + else if ((navigationOverlap > 0) || (actionOverlap > 0)) + { + if (navigationOverlap > 0) + { + // nudge to the right + titleCompX += navigationOverlap; + } + else if (actionOverlap > 0) + { + // nudge to the left + titleCompX -= actionOverlap; + + // force left padding + if (titleCompX < (navigationGroupWidth + titlePaddingLeft)) + titleCompX = navigationGroupWidth + titlePaddingLeft; + } + + // recompute action overlap and force right padding + actionOverlap = (titleCompX + titleCompWidth + titlePaddingRight) - actionGroupX; + + if (actionOverlap > 0) + titleCompWidth -= actionOverlap; + } + } + else + { + // implement padding by adjusting width and position + titleCompX += titlePaddingLeft; + titleCompWidth = titleCompWidth - titlePaddingLeft - titlePaddingRight; + } + + // check for negative width + titleCompWidth = (titleCompWidth < 0) ? 0 : titleCompWidth; + + setElementSize(titleDisplay, titleCompWidth, contentGroupsHeight); + setElementPosition(titleDisplay, titleCompX, paddingTop); + + titleDisplay.visible = true; + } + } + + /** + * @private + */ + override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void + { + super.drawBackground(unscaledWidth, unscaledHeight); + + var chromeColor:uint = getStyle("chromeColor"); + var backgroundAlphaValue:Number = getStyle("backgroundAlpha"); + var colors:Array = []; + + // apply alpha to chromeColor fill only + var backgroundAlphas:Array = [backgroundAlphaValue, backgroundAlphaValue]; + + // exclude top and bottom 1px borders + colorMatrix.createGradientBox(unscaledWidth, unscaledHeight - (borderSize * 2), Math.PI / 2, 0, 0); + + colors[0] = ColorUtil.adjustBrightness2(chromeColor, 20); + colors[1] = chromeColor; + + graphics.beginGradientFill(GradientType.LINEAR, colors, backgroundAlphas, ACTIONBAR_CHROME_COLOR_RATIOS, colorMatrix); + graphics.drawRect(0, borderSize, unscaledWidth, unscaledHeight - (borderSize * 2)); + graphics.endFill(); + } + + } +} +import flash.events.Event; + +import mx.core.UIComponent; +import mx.core.mx_internal; +import mx.events.FlexEvent; + +import spark.components.supportClasses.StyleableTextField; +import spark.core.IDisplayText; + +use namespace mx_internal; + +/** + * @private + * Component that holds StyleableTextFields to produce a drop shadow effect. + * Combines label and shadow into a single component to allow transitions to + * target them both. + */ +class TitleDisplayComponent extends UIComponent implements IDisplayText +{ + private var titleDisplay:StyleableTextField; + private var titleDisplayShadow:StyleableTextField; + private var title:String; + private var titleChanged:Boolean; + + public function TitleDisplayComponent() + { + super(); + title = ""; + } + + override public function get baselinePosition():Number + { + return titleDisplay.baselinePosition; + } + + /** + * @private + */ + override protected function createChildren():void + { + super.createChildren(); + + titleDisplay = StyleableTextField(createInFontContext(StyleableTextField)); + titleDisplay.styleName = this; + titleDisplay.editable = false; + titleDisplay.selectable = false; + titleDisplay.multiline = false; + titleDisplay.wordWrap = false; + titleDisplay.addEventListener(FlexEvent.VALUE_COMMIT, + titleDisplay_valueCommitHandler); + + titleDisplayShadow = + StyleableTextField(createInFontContext(StyleableTextField)); + titleDisplayShadow.styleName = this; + titleDisplayShadow.colorName = "textShadowColor"; + titleDisplayShadow.editable = false; + titleDisplayShadow.selectable = false; + titleDisplayShadow.multiline = false; + titleDisplayShadow.wordWrap = false; + + addChild(titleDisplayShadow); + addChild(titleDisplay); + } + + /** + * @private + */ + override protected function commitProperties():void + { + super.commitProperties(); + + if (titleChanged) + { + titleDisplay.text = title; + + invalidateSize(); + invalidateDisplayList(); + + titleChanged = false; + } + } + + /** + * @private + */ + override protected function measure():void + { + // reset text if it was truncated before. + if (titleDisplay.isTruncated) + titleDisplay.text = title; + + measuredWidth = titleDisplay.getPreferredBoundsWidth(); + + // tightTextHeight + measuredHeight = titleDisplay.getPreferredBoundsHeight(); + } + + /** + * @private + */ + override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void + { + super.updateDisplayList(unscaledWidth, unscaledHeight); + + // reset text if it was truncated before. + if (titleDisplay.isTruncated) + titleDisplay.text = title; + titleDisplay.commitStyles(); + + // use preferred height, setLayoutBoundsSize will accommodate for tight + // text adjustment + var tightHeight:Number = titleDisplay.getPreferredBoundsHeight(); + var tightY:Number = (unscaledHeight - tightHeight) / 2; + + titleDisplay.setLayoutBoundsSize(unscaledWidth, tightHeight); + titleDisplay.setLayoutBoundsPosition(0, (unscaledHeight - tightHeight) / 2); + + // now truncate the text + titleDisplay.truncateToFit(); + + titleDisplayShadow.commitStyles(); + titleDisplayShadow.setLayoutBoundsSize(unscaledWidth, tightHeight); + titleDisplayShadow.setLayoutBoundsPosition(0, tightY + 1); + + titleDisplayShadow.alpha = getStyle("textShadowAlpha"); + + // if labelDisplay is truncated, then push it down here as well. + // otherwise, it would have gotten pushed in the labelDisplay_valueCommitHandler() + if (titleDisplay.isTruncated) + titleDisplayShadow.text = titleDisplay.text; + } + + /** + * @private + */ + private function titleDisplay_valueCommitHandler(event:Event):void + { + titleDisplayShadow.text = titleDisplay.text; + } + + public function get text():String + { + return title; + } + + public function set text(value:String):void + { + title = value; + titleChanged = true; + + invalidateProperties(); + } + + public function get isTruncated():Boolean + { + return titleDisplay.isTruncated; + } +} http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as new file mode 100644 index 0000000..4b8cbba --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ + import spark.skins.android4.assets.ButtonBarFirstButton_selectedDown; + import spark.skins.android4.assets.ButtonBarFirstButton_selectedUp; + import spark.skins.mobile.supportClasses.ButtonBarButtonSkinBase; + + /** + * Android 4.x specific Button skin for the first Button in a ButtonBar. + * + * @see spark.components.ButtonBar#firstButton + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public class ButtonBarFirstButtonSkin extends ButtonBarButtonSkinBase + { + + /** + * Class to use for the border in the selected and down state. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected var selectedDownBorderSkin:Class; + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public function ButtonBarFirstButtonSkin() + { + super(); + + upBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_up; + downBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_down; + selectedBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_selectedUp; + selectedDownBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_selectedDown; + } + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void + { + //Dont draw background + } + + override protected function getBorderClassForCurrentState():Class + { + var isSelected:Boolean = currentState.indexOf("Selected") >= 0; + var isDown:Boolean = currentState.indexOf("down") >= 0; + + if (isSelected && !isDown ) + return selectedBorderSkin; + else if (isSelected && isDown) + return selectedDownBorderSkin; + else if (!isSelected && !isDown) + return upBorderSkin; + else + return downBorderSkin; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as new file mode 100644 index 0000000..c6206d0 --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as @@ -0,0 +1,95 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ + + import spark.skins.android4.assets.ButtonBarMiddleButton_selectedDown; + import spark.skins.android4.assets.ButtonBarMiddleButton_selectedUp; + import spark.skins.android4.assets.ButtonBarMiddleButton_up; + import spark.skins.mobile.supportClasses.ButtonBarButtonSkinBase; + + /** + * Android 4.x specific Button skin for middle Buttons in a ButtonBar. + * + * @see spark.components.ButtonBar#middleButton + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public class ButtonBarMiddleButtonSkin extends ButtonBarButtonSkinBase + { + + /** + * Class to use for the border in the selected and down state. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected var selectedDownBorderSkin:Class; + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public function ButtonBarMiddleButtonSkin() + { + super(); + + upBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_up; + downBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_down; + selectedBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_selectedUp; + selectedDownBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_selectedDown; + } + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void + { + //Dont draw background + } + + override protected function getBorderClassForCurrentState():Class + { + var isSelected:Boolean = currentState.indexOf("Selected") >= 0; + var isDown:Boolean = currentState.indexOf("down") >= 0; + + if (isSelected && !isDown ) + return selectedBorderSkin; + else if (isSelected && isDown) + return selectedDownBorderSkin; + else if (!isSelected && !isDown) + return upBorderSkin; + else + return downBorderSkin; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as new file mode 100644 index 0000000..4b194fd --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as @@ -0,0 +1,166 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ +import spark.components.ButtonBar; +import spark.components.ButtonBarButton; +import spark.components.DataGroup; +import spark.components.supportClasses.ButtonBarHorizontalLayout; +import spark.skins.android4.ButtonBarFirstButtonSkin; +import spark.skins.mobile.ButtonBarLastButtonSkin; +import spark.skins.mobile.supportClasses.ButtonBarButtonClassFactory; +import spark.skins.mobile.supportClasses.MobileSkin; + +/** + * The Android 4.x specific skin class for the Spark ButtonBar component. + * + * @see spark.components.ButtonBar + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ +public class ButtonBarSkin extends MobileSkin +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + * + */ + public function ButtonBarSkin() + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Skin parts + // + //-------------------------------------------------------------------------- + + /** + * @copy spark.skins.spark.ApplicationSkin#hostComponent + */ + public var hostComponent:ButtonBar; + + /** + * @copy spark.components.ButtonBar#firstButton + */ + public var firstButton:ButtonBarButtonClassFactory; + + /** + * @copy spark.components.ButtonBar#lastButton + */ + public var lastButton:ButtonBarButtonClassFactory; + + /** + * @copy spark.components.ButtonBar#middleButton + */ + public var middleButton:ButtonBarButtonClassFactory; + + /** + * @copy spark.components.SkinnableDataContainer#dataGroup + */ + public var dataGroup:DataGroup; + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + override protected function createChildren():void + { + // Set up the class factories for the buttons + if (!firstButton) + { + firstButton = new ButtonBarButtonClassFactory(ButtonBarButton); + firstButton.skinClass = spark.skins.android4.ButtonBarFirstButtonSkin; + } + + if (!lastButton) + { + lastButton = new ButtonBarButtonClassFactory(ButtonBarButton); + lastButton.skinClass = spark.skins.android4.ButtonBarFirstButtonSkin; + } + + if (!middleButton) + { + middleButton = new ButtonBarButtonClassFactory(ButtonBarButton); + middleButton.skinClass = spark.skins.android4.ButtonBarMiddleButtonSkin; + } + + // create the data group to house the buttons + if (!dataGroup) + { + dataGroup = new DataGroup(); + var hLayout:ButtonBarHorizontalLayout = new ButtonBarHorizontalLayout(); + hLayout.gap = 0; + dataGroup.layout = hLayout; + addChild(dataGroup); + } + } + + /** + * @private + */ + override protected function commitCurrentState():void + { + alpha = (currentState == "disabled") ? 0.5 : 1; + } + + /** + * @private + */ + override protected function measure():void + { + measuredWidth = dataGroup.measuredWidth; + measuredHeight = dataGroup.measuredHeight; + + measuredMinWidth = dataGroup.measuredMinWidth; + measuredMinHeight = dataGroup.measuredMinHeight; + } + + /** + * @private + */ + override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void + { + super.layoutContents(unscaledWidth, unscaledHeight); + + setElementPosition(dataGroup, 0, 0); + setElementSize(dataGroup, unscaledWidth, unscaledHeight); + } +} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as new file mode 100644 index 0000000..43fb108 --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as @@ -0,0 +1,397 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ + +import flash.display.DisplayObject; + +import mx.core.DPIClassification; +import mx.core.mx_internal; +import mx.events.FlexEvent; + +import spark.components.supportClasses.StyleableTextField; +import spark.skins.android4.assets.Button_down; +import spark.skins.android4.assets.Button_up; +import spark.skins.mobile.supportClasses.ButtonSkinBase; + + +use namespace mx_internal; + +/** + * ActionScript-based skin for Button controls in mobile applications. The skin supports + * iconClass and labelPlacement. It uses FXG classes to + * implement the vector drawing. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ +public class ButtonSkin extends ButtonSkinBase +{ + //-------------------------------------------------------------------------- + // + // Class constants + // + //-------------------------------------------------------------------------- + + /** + * An array of color distribution ratios. + * This is used in the chrome color fill. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + mx_internal static const CHROME_COLOR_RATIOS:Array = [0, 127.5]; + + /** + * An array of alpha values for the corresponding colors in the colors array. + * This is used in the chrome color fill. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + mx_internal static const CHROME_COLOR_ALPHAS:Array = [1, 1]; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public function ButtonSkin() + { + super(); + upBorderSkin = spark.skins.android4.assets.Button_up; + downBorderSkin = spark.skins.android4.assets.Button_down; + layoutCornerEllipseSize = 0; + + switch (applicationDPI) + { + case DPIClassification.DPI_640: + { + + layoutGap = 20; + layoutPaddingLeft = 40; + layoutPaddingRight = 40; + layoutPaddingTop = 40; + layoutPaddingBottom = 40; + layoutBorderSize = 2; + measuredDefaultWidth = 128; + measuredDefaultHeight = 172; + + break; + } + case DPIClassification.DPI_480: + { + + layoutGap = 14; + layoutPaddingLeft = 30; + layoutPaddingRight = 30; + layoutPaddingTop = 30; + layoutPaddingBottom = 30; + layoutBorderSize = 2; + measuredDefaultWidth = 96; + measuredDefaultHeight = 130; + + break; + } + case DPIClassification.DPI_320: + { + + layoutGap = 10; + layoutPaddingLeft = 20; + layoutPaddingRight = 20; + layoutPaddingTop = 20; + layoutPaddingBottom = 20; + layoutBorderSize = 2; + measuredDefaultWidth = 64; + measuredDefaultHeight = 86; + + break; + } + case DPIClassification.DPI_240: + { + + layoutGap = 7; + layoutPaddingLeft = 15; + layoutPaddingRight = 15; + layoutPaddingTop = 15; + layoutPaddingBottom = 15; + layoutBorderSize = 1; + measuredDefaultWidth = 48; + measuredDefaultHeight = 65; + + break; + } + case DPIClassification.DPI_120: + { + + layoutGap = 4; + layoutPaddingLeft = 8; + layoutPaddingRight = 8; + layoutPaddingTop = 8; + layoutPaddingBottom = 8; + layoutBorderSize = 1; + measuredDefaultWidth = 24; + measuredDefaultHeight = 33; + + break; + } + default: + { + + layoutGap = 5; + layoutPaddingLeft = 10; + layoutPaddingRight = 10; + layoutPaddingTop = 10; + layoutPaddingBottom = 10; + layoutBorderSize = 1; + measuredDefaultWidth = 32; + measuredDefaultHeight = 43; + + break; + } + } + } + + //-------------------------------------------------------------------------- + // + // Layout variables + // + //-------------------------------------------------------------------------- + + /** + * Defines the corner radius. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected var layoutCornerEllipseSize:uint; + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + private var _border:DisplayObject; + + private var changeFXGSkin:Boolean = false; + + private var borderClass:Class; + + mx_internal var fillColorStyleName:String = "chromeColor"; + + /** + * Defines the shadow for the Button control's label. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public var labelDisplayShadow:StyleableTextField; + + /** + * Read-only button border graphic. Use getBorderClassForCurrentState() + * to specify a graphic per-state. + * + * @see #getBorderClassForCurrentState() + */ + protected function get border():DisplayObject + { + return _border; + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + /** + * Class to use for the border in the up state. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + * + * @default Button_up + */ + protected var upBorderSkin:Class; + + /** + * Class to use for the border in the down state. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + * + * @default Button_down + */ + protected var downBorderSkin:Class; + + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + override protected function createChildren():void + { + super.createChildren(); + + if (!labelDisplayShadow && labelDisplay) + { + labelDisplayShadow = StyleableTextField(createInFontContext(StyleableTextField)); + labelDisplayShadow.styleName = this; + labelDisplayShadow.colorName = "textShadowColor"; + labelDisplayShadow.useTightTextBounds = false; + + // add shadow before display + addChildAt(labelDisplayShadow, getChildIndex(labelDisplay)); + } + + setStyle("textAlign", "center"); + } + + /** + * @private + */ + override protected function commitCurrentState():void + { + super.commitCurrentState(); + + borderClass = getBorderClassForCurrentState(); + + if (!(_border is borderClass)) + changeFXGSkin = true; + + // update borderClass and background + invalidateDisplayList(); + } + + /** + * @private + */ + override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void + { + super.layoutContents(unscaledWidth, unscaledHeight); + + // size the FXG background + if (changeFXGSkin) + { + changeFXGSkin = false; + + if (_border) + { + removeChild(_border); + _border = null; + } + + if (borderClass) + { + _border = new borderClass(); + addChildAt(_border, 0); + } + } + + layoutBorder(unscaledWidth, unscaledHeight); + + // update label shadow + labelDisplayShadow.alpha = getStyle("textShadowAlpha"); + labelDisplayShadow.commitStyles(); + + // don't use tightText positioning on shadow + setElementPosition(labelDisplayShadow, labelDisplay.x, labelDisplay.y + 1); + setElementSize(labelDisplayShadow, labelDisplay.width, labelDisplay.height); + + // if labelDisplay is truncated, then push it down here as well. + // otherwise, it would have gotten pushed in the labelDisplay_valueCommitHandler() + if (labelDisplay.isTruncated) + labelDisplayShadow.text = labelDisplay.text; + } + + /** + * Position the background of the skin. Override this function to re-position the background. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + mx_internal function layoutBorder(unscaledWidth:Number, unscaledHeight:Number):void + { + setElementSize(border, unscaledWidth, unscaledHeight); + setElementPosition(border, 0, 0); + } + + /** + * Returns the borderClass to use based on the currentState. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + protected function getBorderClassForCurrentState():Class + { + if (currentState == "down") + return downBorderSkin; + else + return upBorderSkin; + } + + //-------------------------------------------------------------------------- + // + // Event Handlers + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + override protected function labelDisplay_valueCommitHandler(event:FlexEvent):void + { + super.labelDisplay_valueCommitHandler(event); + labelDisplayShadow.text = labelDisplay.text; + } + +} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as b/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as new file mode 100644 index 0000000..22f04f5 --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as @@ -0,0 +1,825 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ + import flash.display.BlendMode; + import flash.display.GradientType; + import flash.display.Graphics; + import flash.display.Sprite; + import flash.events.Event; + + import mx.core.DPIClassification; + import mx.core.UIComponent; + import mx.core.mx_internal; + import mx.events.EffectEvent; + import mx.events.FlexEvent; + import mx.utils.ColorUtil; + + import spark.components.ArrowDirection; + import spark.components.Callout; + import spark.components.ContentBackgroundAppearance; + import spark.components.Group; + import spark.core.SpriteVisualElement; + import spark.effects.Fade; + import spark.primitives.RectangularDropShadow; + import spark.skins.android4.assets.CalloutContentBackground; + import spark.skins.android4.supportClasses.CalloutArrow; + import spark.skins.mobile.supportClasses.MobileSkin; + + use namespace mx_internal; + + /** + * The default skin class for the Spark Callout component in mobile + * applications. + * + * <p>The <code>contentGroup</code> lies above a <code>backgroundColor</code> fill + * which frames the <code>contentGroup</code>. The position and size of the frame + * adjust based on the host component <code>arrowDirection</code>, leaving + * space for the <code>arrow</code> to appear on the outside edge of the + * frame.</p> + * + * <p>The <code>arrow</code> skin part is not positioned by the skin. Instead, + * the Callout component positions the arrow relative to the owner in + * <code>updateSkinDisplayList()</code>. This method assumes that Callout skin + * and the <code>arrow</code> use the same coordinate space.</p> + * + * @see spark.components.Callout + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + public class CalloutSkin extends MobileSkin + { + mx_internal static const BACKGROUND_GRADIENT_BRIGHTNESS_TOP:int = 15; + + mx_internal static const BACKGROUND_GRADIENT_BRIGHTNESS_BOTTOM:int = -15; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + public function CalloutSkin() + { + super(); + + dropShadowAlpha = 0.7; + contentBackgroundInsetClass = spark.skins.android4.assets.CalloutContentBackground; + + switch (applicationDPI) + { + case DPIClassification.DPI_640: + { + + backgroundCornerRadius = 24; + backgroundGradientHeight = 440; + frameThickness = 12; + arrowWidth = 160; + arrowHeight = 80; + contentCornerRadius = 40; + dropShadowBlurX = 64; + dropShadowBlurY = 64; + dropShadowDistance = 12; + highlightWeight = 4; + + break; + } + case DPIClassification.DPI_480: + { + backgroundCornerRadius = 16; + backgroundGradientHeight = 330; + frameThickness = 8; + arrowWidth = 120; + arrowHeight = 60; + contentCornerRadius = 28; + dropShadowBlurX = 48; + dropShadowBlurY = 48; + dropShadowDistance = 8; + highlightWeight = 2; + + break; + } + case DPIClassification.DPI_320: + { + + backgroundCornerRadius = 12; + backgroundGradientHeight = 220; + frameThickness = 6; + arrowWidth = 80; + arrowHeight = 40; + contentCornerRadius = 20; + dropShadowBlurX = 32; + dropShadowBlurY = 32; + dropShadowDistance = 6; + highlightWeight = 2; + + break; + } + case DPIClassification.DPI_240: + { + backgroundCornerRadius = 8; + backgroundGradientHeight = 165; + frameThickness = 4; + arrowWidth = 60; + arrowHeight = 30; + contentCornerRadius = 14; + dropShadowBlurX = 24; + dropShadowBlurY = 24; + dropShadowDistance = 4; + highlightWeight = 1; + + break; + } + case DPIClassification.DPI_120: + { + backgroundCornerRadius = 4; + backgroundGradientHeight = 83; + frameThickness = 2; + arrowWidth = 30; + arrowHeight = 15; + contentCornerRadius = 7; + dropShadowBlurX = 12; + dropShadowBlurY = 12; + dropShadowDistance = 2; + highlightWeight = 0.5; + + break; + } + default: + { + // default DPI_160 + backgroundCornerRadius = 6; + backgroundGradientHeight = 110; + frameThickness = 3; + arrowWidth = 40; + arrowHeight = 20; + contentCornerRadius = 10; + dropShadowBlurX = 16; + dropShadowBlurY = 16; + dropShadowDistance = 3; + highlightWeight = 1; + + break; + } + } + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @copy spark.skins.spark.ApplicationSkin#hostComponent + */ + public var hostComponent:Callout; + + /** + * Enables a RectangularDropShadow behind the <code>backgroundColor</code> frame. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var dropShadowVisible:Boolean = true; + + /** + * Enables a vertical linear gradient in the <code>backgroundColor</code> frame. This + * gradient fill is drawn across both the arrow and the frame. By default, + * the gradient brightens the background color by 15% and darkens it by 60%. + * + * @default true + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var useBackgroundGradient:Boolean = true; + + /** + * Corner radius used for the <code>contentBackgroundColor</code> fill. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var contentCornerRadius:uint; + + /** + * A class reference to an FXG class that is layered underneath the + * <code>contentGroup</code>. The instance of this class is sized to match the + * <code>contentGroup</code>. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var contentBackgroundInsetClass:Class; + + /** + * Corner radius of the <code>backgroundColor</code> "frame". + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var backgroundCornerRadius:Number; + + /** + * The thickness of the <code>backgroundColor</code> "frame" that surrounds the + * <code>contentGroup</code>. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var frameThickness:Number; + + /** + * Color of the border stroke around the <code>backgroundColor</code> "frame". + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var borderColor:Number = -1; // not set + + /** + * Thickness of the border stroke around the <code>backgroundColor</code> + * "frame". + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var borderThickness:Number = -1 ; // marker that borderThickness was not set directly + + /** + * Width of the arrow in vertical directions. This property also controls + * the height of the arrow in horizontal directions. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var arrowWidth:Number; + + /** + * Height of the arrow in vertical directions. This property also controls + * the width of the arrow in horizontal directions. + * + * @langversion 3.0 + * @playerversion AIR 3 + * @productversion Flex 4.6 + */ + protected var arrowHeight:Number; + + /** + * @private + * Instance of the contentBackgroundClass + */ + mx_internal var contentBackgroundGraphic:SpriteVisualElement; + + /** + * @private + * Tracks changes to the skin state to support the fade out tranisition + * when closed; + */ + mx_internal var isOpen:Boolean; + + private var backgroundGradientHeight:Number; + + private var contentMask:Sprite; + + private var backgroundFill:SpriteVisualElement; + + private var dropShadow:RectangularDropShadow; + + private var dropShadowBlurX:Number; + + private var dropShadowBlurY:Number; + + private var dropShadowDistance:Number; + + private var dropShadowAlpha:Number; + + private var fade:Fade; + + private var highlightWeight:Number; + + //-------------------------------------------------------------------------- + // + // Skin parts + // + //-------------------------------------------------------------------------- + + /** + * @copy spark.components.SkinnableContainer#contentGroup + */ + public var contentGroup:Group; + + /** + * @copy spark.components.Callout#arrow + */ + public var arrow:UIComponent; + + /* helper private accessors */ + + /* returns borderThickness from style if member is -1, or borderThickness. Returns 0 if NaN */ + mx_internal function get actualBorderThickness():Number + { + var border: Number = borderThickness != -1 ? borderThickness : getStyle('borderThickness'); + return isNaN(border)? 0: border; + } + + mx_internal function get actualBorderColor():uint + { + return borderColor != -1 ? borderColor: getStyle('borderColor'); + } + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + override protected function createChildren():void + { + super.createChildren(); + + if (dropShadowVisible) + { + dropShadow = new RectangularDropShadow(); + dropShadow.angle = 90; + dropShadow.distance = dropShadowDistance; + dropShadow.blurX = dropShadowBlurX; + dropShadow.blurY = dropShadowBlurY; + dropShadow.tlRadius = dropShadow.trRadius = dropShadow.blRadius = + dropShadow.brRadius = backgroundCornerRadius ; + dropShadow.mouseEnabled = false; + dropShadow.alpha = dropShadowAlpha; + addChild(dropShadow); + } + + // background fill placed above the drop shadow + backgroundFill = new SpriteVisualElement(); + addChild(backgroundFill); + + // arrow + if (!arrow) + { + arrow = new CalloutArrow(); + arrow.id = "arrow"; + arrow.styleName = this; + addChild(arrow); + } + + // contentGroup + if (!contentGroup) + { + contentGroup = new Group(); + contentGroup.id = "contentGroup"; + addChild(contentGroup); + } + + + } + + /** + * @private + */ + override protected function commitProperties():void + { + super.commitProperties(); + + // add or remove the contentBackgroundGraphic + var contentBackgroundAppearance:String = getStyle("contentBackgroundAppearance"); + + if (contentBackgroundAppearance == ContentBackgroundAppearance.INSET) + { + // create the contentBackgroundGraphic + if (!contentBackgroundGraphic && contentBackgroundInsetClass) + { + contentBackgroundGraphic = new contentBackgroundInsetClass() as SpriteVisualElement; + + // with the current skin structure, contentBackgroundGraphic is + // always the last child + addChild(contentBackgroundGraphic); + } + } + else if (contentBackgroundGraphic) + { + // if already created, remove the graphic for "flat" and "none" + removeChild(contentBackgroundGraphic); + contentBackgroundGraphic = null; + } + + // always invalidate to accomodate arrow direction changes + invalidateSize(); + invalidateDisplayList(); + } + + + /** + * @private + */ + override protected function measure():void + { + super.measure(); + + var borderWeight:Number =actualBorderThickness; + var frameAdjustment:Number = (frameThickness + borderWeight) * 2; + + var arrowMeasuredWidth:Number; + var arrowMeasuredHeight:Number; + + // pad the arrow so that the edges are within the background corner radius + if (isArrowHorizontal) + { + arrowMeasuredWidth = arrowHeight; + arrowMeasuredHeight = arrowWidth + (backgroundCornerRadius * 2); + } + else if (isArrowVertical) + { + arrowMeasuredWidth = arrowWidth + (backgroundCornerRadius * 2); + arrowMeasuredHeight = arrowHeight; + } + + // count the contentGroup size and frame size + measuredMinWidth = contentGroup.measuredMinWidth + frameAdjustment; + measuredMinHeight = contentGroup.measuredMinHeight + frameAdjustment; + + measuredWidth = contentGroup.getPreferredBoundsWidth() + frameAdjustment; + measuredHeight = contentGroup.getPreferredBoundsHeight() + frameAdjustment; + + // add the arrow size based on the arrowDirection + if (isArrowHorizontal) + { + measuredMinWidth += arrowMeasuredWidth; + measuredMinHeight = Math.max(measuredMinHeight, arrowMeasuredHeight); + + measuredWidth += arrowMeasuredWidth; + measuredHeight = Math.max(measuredHeight, arrowMeasuredHeight); + } + else if (isArrowVertical) + { + measuredMinWidth += Math.max(measuredMinWidth, arrowMeasuredWidth); + measuredMinHeight += arrowMeasuredHeight; + + measuredWidth = Math.max(measuredWidth, arrowMeasuredWidth); + measuredHeight += arrowMeasuredHeight; + } + } + + /** + * @private + * SkinnaablePopUpContainer skins must dispatch a + * FlexEvent.STATE_CHANGE_COMPLETE event for the component to properly + * update the skin state. + */ + override protected function commitCurrentState():void + { + super.commitCurrentState(); + + var isNormal:Boolean = (currentState == "normal"); + var isDisabled:Boolean = (currentState == "disabled") + + // play a fade out if the callout was previously open + if (!(isNormal || isDisabled) && isOpen) + { + if (!fade) + { + fade = new Fade(); + fade.target = this; + fade.duration = 200; + fade.alphaTo = 0; + } + + // BlendMode.LAYER while fading out + blendMode = BlendMode.LAYER; + + // play a short fade effect + fade.addEventListener(EffectEvent.EFFECT_END, stateChangeComplete); + fade.play(); + + isOpen = false; + } + else + { + isOpen = isNormal || isDisabled; + + // handle re-opening the Callout while fading out + if (fade && fade.isPlaying) + { + // Do not dispatch a state change complete. + // SkinnablePopUpContainer handles state interruptions. + fade.removeEventListener(EffectEvent.EFFECT_END, stateChangeComplete); + fade.stop(); + } + + if (isDisabled) + { + // BlendMode.LAYER to allow CalloutArrow BlendMode.ERASE + blendMode = BlendMode.LAYER; + + alpha = 0.5; + } + else + { + // BlendMode.NORMAL for non-animated state transitions + blendMode = BlendMode.NORMAL; + + if (isNormal) + alpha = 1; + else + alpha = 0; + } + + stateChangeComplete(); + } + } + + /** + * @private + */ + override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void + { + super.drawBackground(unscaledWidth, unscaledHeight); + + var frameEllipseSize:Number = backgroundCornerRadius * 2; + + // account for borderThickness center stroke alignment + var borderWeight:Number =actualBorderThickness; + var showBorder:Boolean = borderWeight > 0 ; + + + // contentBackgroundGraphic already accounts for the arrow position + // use it's positioning instead of recalculating based on unscaledWidth + // and unscaledHeight + var frameX:Number = Math.floor(contentGroup.getLayoutBoundsX() - frameThickness) - (borderWeight / 2); + var frameY:Number = Math.floor(contentGroup.getLayoutBoundsY() - frameThickness) - (borderWeight / 2); + var frameWidth:Number = contentGroup.getLayoutBoundsWidth() + (frameThickness * 2) + borderWeight; + var frameHeight:Number = contentGroup.getLayoutBoundsHeight() + (frameThickness * 2) + borderWeight; + + var backgroundColor:Number = getStyle("primaryAccentColor"); + var backgroundAlpha:Number = getStyle("backgroundAlpha"); + + var bgFill:Graphics = backgroundFill.graphics; + bgFill.clear(); + + if (showBorder) + bgFill.lineStyle(borderWeight, actualBorderColor, 1, true); + + if (useBackgroundGradient) + { + // top color is brighter if arrowDirection == ArrowDirection.UP + var backgroundColorTop:Number = ColorUtil.adjustBrightness2(backgroundColor, + BACKGROUND_GRADIENT_BRIGHTNESS_TOP); + var backgroundColorBottom:Number = ColorUtil.adjustBrightness2(backgroundColor, + BACKGROUND_GRADIENT_BRIGHTNESS_BOTTOM); + + // max gradient height = backgroundGradientHeight + colorMatrix.createGradientBox(unscaledWidth, backgroundGradientHeight, + Math.PI / 2, 0, 0); + + bgFill.beginGradientFill(GradientType.LINEAR, + [backgroundColorTop, backgroundColorBottom], + [backgroundAlpha, backgroundAlpha], + [0, 255], + colorMatrix); + } + else + { + bgFill.beginFill(backgroundColor, backgroundAlpha); + } + + bgFill.drawRoundRect(frameX, frameY, frameWidth, + frameHeight, frameEllipseSize, frameEllipseSize); + bgFill.endFill(); + + // draw content background styles + var contentBackgroundAppearance:String = getStyle("contentBackgroundAppearance"); + + if (contentBackgroundAppearance != ContentBackgroundAppearance.NONE) + { + var contentEllipseSize:Number = contentCornerRadius * 2; + var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha"); + var contentWidth:Number = contentGroup.getLayoutBoundsWidth(); + var contentHeight:Number = contentGroup.getLayoutBoundsHeight(); + + // all appearance values except for "none" use a mask + if (!contentMask) + contentMask = new SpriteVisualElement(); + + contentGroup.mask = contentMask; + + // draw contentMask in contentGroup coordinate space + var maskGraphics:Graphics = contentMask.graphics; + maskGraphics.clear(); + maskGraphics.beginFill(0, 1); + maskGraphics.drawRoundRect(0, 0, contentWidth, contentHeight, + contentEllipseSize, contentEllipseSize); + maskGraphics.endFill(); + + // reset line style to none + if (showBorder) + bgFill.lineStyle(NaN); + + // draw the contentBackgroundColor + bgFill.beginFill(getStyle("contentBackgroundColor"), + contentBackgroundAlpha); + bgFill.drawRoundRect(contentGroup.getLayoutBoundsX(), + contentGroup.getLayoutBoundsY(), + contentWidth, contentHeight, contentEllipseSize, contentEllipseSize); + bgFill.endFill(); + + if (contentBackgroundGraphic) + contentBackgroundGraphic.alpha = contentBackgroundAlpha; + } + else // if (contentBackgroundAppearance == CalloutContentBackgroundAppearance.NONE)) + { + // remove the mask + if (contentMask) + { + contentGroup.mask = null; + contentMask = null; + } + } + + // draw highlight in the callout when the arrow is hidden + if (useBackgroundGradient && !isArrowHorizontal && !isArrowVertical) + { + // highlight width spans the callout width minus the corner radius + var highlightWidth:Number = frameWidth - frameEllipseSize; + var highlightX:Number = frameX + backgroundCornerRadius; + var highlightOffset:Number = (highlightWeight * 1.5); + + // straight line across the top + bgFill.lineStyle(highlightWeight, 0xFFFFFF, 0.2 * backgroundAlpha); + bgFill.moveTo(highlightX, highlightOffset); + bgFill.lineTo(highlightX + highlightWidth, highlightOffset); + } + } + + /** + * @private + */ + override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void + { + super.layoutContents(unscaledWidth, unscaledHeight); + + // pad the arrow so that the edges are within the background corner radius + if (isArrowHorizontal) + { + arrow.width = arrowHeight; + arrow.height = arrowWidth + (backgroundCornerRadius * 2); + } + else if (isArrowVertical) + { + arrow.width = arrowWidth + (backgroundCornerRadius * 2); + arrow.height = arrowHeight; + } + + setElementSize(backgroundFill, unscaledWidth, unscaledHeight); + setElementPosition(backgroundFill, 0, 0); + + var frameX:Number = 0; + var frameY:Number = 0; + var frameWidth:Number = unscaledWidth; + var frameHeight:Number = unscaledHeight; + + switch (hostComponent.arrowDirection) + { + case ArrowDirection.UP: + frameY = arrow.height; + frameHeight -= arrow.height; + break; + case ArrowDirection.DOWN: + frameHeight -= arrow.height; + break; + case ArrowDirection.LEFT: + frameX = arrow.width; + frameWidth -= arrow.width; + break; + case ArrowDirection.RIGHT: + frameWidth -= arrow.width; + break; + default: + // no arrow, content takes all available space + break; + } + + if (dropShadow) + { + setElementSize(dropShadow, frameWidth, frameHeight); + setElementPosition(dropShadow, frameX, frameY); + } + + // Show frameThickness by inset of contentGroup + var borderWeight:Number = actualBorderThickness; + var contentBackgroundAdjustment:Number = frameThickness + borderWeight; + + var contentBackgroundX:Number = frameX + contentBackgroundAdjustment; + var contentBackgroundY:Number = frameY + contentBackgroundAdjustment; + + contentBackgroundAdjustment = contentBackgroundAdjustment * 2; + var contentBackgroundWidth:Number = frameWidth - contentBackgroundAdjustment; + var contentBackgroundHeight:Number = frameHeight - contentBackgroundAdjustment; + + if (contentBackgroundGraphic) + { + setElementSize(contentBackgroundGraphic, contentBackgroundWidth, contentBackgroundHeight); + setElementPosition(contentBackgroundGraphic, contentBackgroundX, contentBackgroundY); + } + + setElementSize(contentGroup, contentBackgroundWidth, contentBackgroundHeight); + setElementPosition(contentGroup, contentBackgroundX, contentBackgroundY); + + // mask position is in the contentGroup coordinate space + if (contentMask) + setElementSize(contentMask, contentBackgroundWidth, contentBackgroundHeight); + } + + override public function styleChanged(styleProp:String):void + { + super.styleChanged(styleProp); + + var allStyles:Boolean = !styleProp || styleProp == "styleName"; + + if (allStyles || (styleProp == "contentBackgroundAppearance")) + invalidateProperties(); + + if (allStyles || (styleProp == "backgroundAlpha")) + { + var backgroundAlpha:Number = getStyle("backgroundAlpha"); + + // Use BlendMode.LAYER to allow CalloutArrow to erase the dropShadow + // when the Callout background is transparent + blendMode = (backgroundAlpha < 1) ? BlendMode.LAYER : BlendMode.NORMAL; + } + } + + /** + * @private + */ + mx_internal function get isArrowHorizontal():Boolean + { + return (hostComponent.arrowDirection == ArrowDirection.LEFT + || hostComponent.arrowDirection == ArrowDirection.RIGHT); + } + + /** + * @private + */ + mx_internal function get isArrowVertical():Boolean + { + return (hostComponent.arrowDirection == ArrowDirection.UP + || hostComponent.arrowDirection == ArrowDirection.DOWN); + } + + //-------------------------------------------------------------------------- + // + // Event handlers + // + //-------------------------------------------------------------------------- + + private function stateChangeComplete(event:Event=null):void + { + if (fade && event) + fade.removeEventListener(EffectEvent.EFFECT_END, stateChangeComplete); + + // SkinnablePopUpContainer relies on state changes for open and close + dispatchEvent(new FlexEvent(FlexEvent.STATE_CHANGE_COMPLETE)); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as ---------------------------------------------------------------------- diff --git a/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as b/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as new file mode 100644 index 0000000..f091205 --- /dev/null +++ b/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as @@ -0,0 +1,268 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.skins.android4 +{ + import flash.display.DisplayObject; + + import mx.core.DPIClassification; + + import spark.skins.android4.assets.CheckBox_up; + import spark.skins.mobile.supportClasses.SelectableButtonSkinBase; + + /** + * ActionScript-based skin for CheckBox components in mobile applications. + * + * @see spark.components.CheckBox + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public class CheckBoxSkin extends SelectableButtonSkinBase + { + //-------------------------------------------------------------------------- + // + // Class constants + // + //-------------------------------------------------------------------------- + + private static const exclusions:Array = ["labelDisplay", "labelDisplayShadow"]; + + //-------------------------------------------------------------------------- + // + // Member variables + // + //-------------------------------------------------------------------------- + + protected var symbolOffsetX:Number; + protected var symbolOffsetY:Number; + protected var iconWidth:Number; + protected var iconHeight:Number; + protected var symbolWidth:Number; + protected var symbolHeight:Number; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + public function CheckBoxSkin() + { + super(); + + layoutPaddingLeft = 0; + layoutPaddingRight = 0; + layoutPaddingTop = 0; + layoutPaddingBottom = 0; + + upIconClass = spark.skins.android4.assets.CheckBox_up; + upSelectedIconClass = spark.skins.android4.assets.CheckBox_upSelected; + downIconClass = spark.skins.android4.assets.CheckBox_down; + downSelectedIconClass = spark.skins.android4.assets.CheckBox_downSelected; + upSymbolIconClass = null; + upSymbolIconSelectedClass = spark.skins.android4.assets.CheckBox_upSymbolSelected; + downSymbolIconSelectedClass = spark.skins.android4.assets.CheckBox_downSymbolSelected; + downSymbolIconClass = null; + + switch (applicationDPI) + { + case DPIClassification.DPI_640: + { + + layoutGap = 16; + minWidth = 128; + minHeight = 128; + layoutBorderSize = 6; + iconWidth = 128; + iconHeight = 128; + symbolWidth = 64; + symbolHeight = 64; + symbolOffsetX = 32; + symbolOffsetY = 32; + + break; + } + case DPIClassification.DPI_480: + { + + layoutGap = 12; + minWidth = 96; + minHeight = 96; + layoutBorderSize = 4; + iconWidth = 96; + iconHeight = 96; + symbolWidth = 48; + symbolHeight = 48; + symbolOffsetX = 24; + symbolOffsetY = 24; + + break; + } + case DPIClassification.DPI_320: + { + + layoutGap = 8; + minWidth = 64; + minHeight = 64; + layoutBorderSize = 3; + iconWidth = 64; + iconHeight = 64; + symbolWidth = 32; + symbolHeight = 32; + symbolOffsetX = 16; + symbolOffsetY = 16; + + break; + } + case DPIClassification.DPI_240: + { + + layoutGap = 6; + minWidth = 48; + minHeight = 48; + layoutBorderSize = 2; + iconWidth = 48; + iconHeight = 48; + symbolWidth = 24; + symbolHeight = 24; + symbolOffsetX = 12; + symbolOffsetY = 12; + + break; + } + case DPIClassification.DPI_120: + { + + layoutGap = 3; + minWidth = 24; + minHeight = 24; + layoutBorderSize = 1; + iconWidth = 24; + iconHeight = 24; + symbolWidth = 12; + symbolHeight = 12; + symbolOffsetX = 6; + symbolOffsetY = 6; + + break; + } + default: + { + // default DPI_160 + + layoutGap = 4; + minWidth = 32; + minHeight = 32; + layoutBorderSize = 2; + iconWidth = 32; + iconHeight = 32; + symbolWidth = 16; + symbolHeight = 16; + symbolOffsetX = 8; + symbolOffsetY = 8; + + + break; + } + } + } + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * @private + * CheckBox <code>chromeColor</code> is drawn to match the FXG rectangle + * shape and position. + */ + override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void + { + // super draws a transparent hit zone + super.drawBackground(unscaledWidth, unscaledHeight); + + // get the size and position of iconDisplay + var currentIcon:DisplayObject = getIconDisplay(); + var widthAdjustment:Number = layoutBorderSize * 2; + + graphics.beginFill(getStyle("chromeColor")); + graphics.drawRoundRect(currentIcon.x + layoutBorderSize, + currentIcon.y + layoutBorderSize, + currentIcon.width - widthAdjustment, + currentIcon.height - widthAdjustment, layoutBorderSize, layoutBorderSize); + graphics.endFill(); + } + + /** + * List of IDs of items that should be excluded when rendering the focus ring. + * Only items of type DisplayObject or GraphicElement should be excluded. Items + * of other types are ignored. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 2.5 + * @productversion Flex 4.5 + */ + override protected function get focusSkinExclusions():Array + { + return exclusions; + } + + override protected function commitCurrentState():void + { + super.commitCurrentState(); + if(symbolIcon != null) + { + symbolIcon.width = symbolWidth; + symbolIcon.height = symbolHeight; + } + var iconDisplay:DisplayObject = getIconDisplay(); + if(iconDisplay != null) + { + iconDisplay.width = iconWidth; + iconDisplay.height = iconHeight; + } + } + + override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void + { + super.layoutContents(unscaledWidth, unscaledHeight); + // position the symbols to align with the background "icon" + if (symbolIcon) + { + var currentIcon:DisplayObject = getIconDisplay(); + setElementPosition(symbolIcon, symbolOffsetX, symbolOffsetY); + } + } + + } +} \ No newline at end of file
