| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.mobile |
| { |
| import flash.display.BlendMode; |
| import flash.display.DisplayObject; |
| import flash.display.GradientType; |
| import flash.display.Graphics; |
| import flash.display.Sprite; |
| import flash.events.Event; |
| |
| import mx.core.DPIClassification; |
| import mx.core.IVisualElement; |
| import mx.core.UIComponent; |
| import mx.core.mx_internal; |
| import mx.utils.ColorUtil; |
| |
| import spark.components.ToggleSwitch; |
| import spark.components.supportClasses.StyleableTextField; |
| import spark.core.SpriteVisualElement; |
| import spark.skins.mobile.supportClasses.MobileSkin; |
| import spark.skins.mobile120.assets.ToggleSwitch_contentShadow; |
| import spark.skins.mobile160.assets.ToggleSwitch_contentShadow; |
| import spark.skins.mobile240.assets.ToggleSwitch_contentShadow; |
| import spark.skins.mobile320.assets.ToggleSwitch_contentShadow; |
| import spark.skins.mobile480.assets.ToggleSwitch_contentShadow; |
| import spark.skins.mobile640.assets.ToggleSwitch_contentShadow; |
| |
| use namespace mx_internal; |
| |
| /** |
| * ActionScript-based skin for the ToggleSwitch control. |
| * The colors of the component can |
| * be customized using styles. This class is responsible for most of the |
| * graphics drawing, with some additional fxg assets. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| * |
| * @see spark.components.ToggleSwitch |
| */ |
| public class ToggleSwitchSkin extends MobileSkin |
| { |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //---------------------------------------------------------------------------------------------- |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| **/ |
| public function ToggleSwitchSkin() |
| { |
| super(); |
| |
| switch(applicationDPI) |
| { |
| case DPIClassification.DPI_640: |
| { |
| layoutThumbWidth = 94; |
| layoutThumbHeight = 56; |
| layoutStrokeWeight = 2; |
| layoutBorderSize = 2; |
| layoutTextShadowOffset = -2; |
| layoutInnerPadding = 14; |
| layoutOuterPadding = 22; |
| slidingContentOverlayClass = spark.skins.mobile320.assets.ToggleSwitch_contentShadow; |
| break; |
| } |
| case DPIClassification.DPI_480: |
| { |
| // Note provisional may need changes |
| layoutThumbWidth = 140; |
| layoutThumbHeight = 84; |
| layoutStrokeWeight = 2; |
| layoutBorderSize = 2; |
| layoutTextShadowOffset = -2; |
| layoutInnerPadding = 20; |
| layoutOuterPadding = 34; |
| slidingContentOverlayClass = spark.skins.mobile480.assets.ToggleSwitch_contentShadow; |
| break; |
| } |
| case DPIClassification.DPI_320: |
| { |
| layoutThumbWidth = 94; |
| layoutThumbHeight = 56; |
| layoutStrokeWeight = 2; |
| layoutBorderSize = 2; |
| layoutTextShadowOffset = -2; |
| layoutInnerPadding = 14; |
| layoutOuterPadding = 22; |
| slidingContentOverlayClass = spark.skins.mobile320.assets.ToggleSwitch_contentShadow; |
| break; |
| } |
| case DPIClassification.DPI_240: |
| { |
| layoutThumbWidth = 70; |
| layoutThumbHeight = 42; |
| layoutStrokeWeight = 2; |
| layoutBorderSize = 1; |
| layoutTextShadowOffset = -1; |
| layoutInnerPadding = 10; |
| layoutOuterPadding = 17; |
| slidingContentOverlayClass = spark.skins.mobile240.assets.ToggleSwitch_contentShadow; |
| break; |
| } |
| case DPIClassification.DPI_120: |
| { |
| layoutThumbWidth = 35; |
| layoutThumbHeight = 21; |
| layoutStrokeWeight = 2; |
| layoutBorderSize = 1; |
| layoutTextShadowOffset = -1; |
| layoutInnerPadding = 5; |
| layoutOuterPadding = 9; |
| slidingContentOverlayClass = spark.skins.mobile120.assets.ToggleSwitch_contentShadow; |
| break; |
| } |
| default: |
| { |
| layoutThumbWidth = 47; |
| layoutThumbHeight = 28; |
| layoutStrokeWeight = 1; |
| layoutBorderSize = 1; |
| layoutTextShadowOffset = -1; |
| layoutInnerPadding = 7; |
| layoutOuterPadding = 11; |
| slidingContentOverlayClass = spark.skins.mobile160.assets.ToggleSwitch_contentShadow; |
| break; |
| } |
| } |
| |
| layoutCornerEllipseSize = layoutThumbHeight; |
| selectedLabel = resourceManager.getString("components","toggleSwitchSelectedLabel"); |
| unselectedLabel = resourceManager.getString("components","toggleSwitchUnselectedLabel"); |
| } |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| /** |
| * The width to draw the thumb skin part. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutThumbWidth:Number; |
| |
| /** |
| * The height to draw the thumb skin part. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutThumbHeight:Number; |
| |
| /** |
| * The corner radius of the thumb and track. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutCornerEllipseSize:Number; |
| |
| /** |
| * The stroke weight outlining the graphics of the skin. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutStrokeWeight:Number; |
| |
| /** |
| * The size of the border surrounding the component. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutBorderSize:Number; |
| |
| /** |
| * The padding between the labels and the thumb. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutInnerPadding:Number; |
| |
| /** |
| * The padding between the labels and the edge of the track. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutOuterPadding:Number; |
| |
| /** |
| * The offset between a label and its shadow. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected var layoutTextShadowOffset:Number; |
| |
| /** |
| * The label for the selected side of the component. |
| * Exposed for styling purposes only. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| public var selectedLabelDisplay:LabelDisplayComponent; |
| |
| /** |
| * The label for the unselected side of the component. |
| * Exposed for styling purposes only. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| public var unselectedLabelDisplay:LabelDisplayComponent; |
| |
| /** |
| * The content clipped by the track that slides to match the thumb's |
| * position. |
| * Contents include a background and the (un)selected labels. |
| * The sliding content is stacked, from back to front, as background, |
| * shadow, foreground. |
| */ |
| private var slidingContentBackground:SpriteVisualElement; |
| private var slidingContentForeground:UIComponent; |
| private var slidingContentOverlayClass:Class; |
| private var slidingContentOverlay:DisplayObject; |
| |
| /** |
| * The contents inside the skin, not including the outline |
| * stroke |
| */ |
| private var contents:UIComponent; |
| |
| /** |
| * The thumb erase overlay erases pixels behind the thumb. The thumb |
| * content contains the thumb graphics, and sits above the overlay. |
| */ |
| private var thumbEraseOverlay:Sprite; |
| private var thumbContent:Sprite; |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Skin parts |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| /** |
| * The thumb skin part. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| public var thumb:IVisualElement; |
| |
| /** |
| * The track skin part. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| public var track:IVisualElement; |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Overridden properties |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // currentState |
| //---------------------------------- |
| /** |
| * @private |
| */ |
| override public function set currentState(value:String):void |
| { |
| var isDown:Boolean = currentState && currentState.indexOf("down") >=0; |
| |
| super.currentState = value; |
| |
| if (isDown != currentState.indexOf("down") >= 0) |
| { |
| invalidateDisplayList(); |
| } |
| } |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // hostComponent |
| //---------------------------------- |
| |
| private var _hostComponent:ToggleSwitch; |
| |
| /** |
| * @copy spark.skins.spark.ApplicationSkin#hostComponent |
| */ |
| public function get hostComponent():ToggleSwitch |
| { |
| return _hostComponent; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set hostComponent(value:ToggleSwitch):void |
| { |
| if (_hostComponent) |
| _hostComponent.removeEventListener("thumbPositionChanged", thumbPositionChanged_handler); |
| _hostComponent = value; |
| if (_hostComponent) |
| _hostComponent.addEventListener("thumbPositionChanged", thumbPositionChanged_handler); |
| } |
| |
| //---------------------------------- |
| // selectedLabel |
| //---------------------------------- |
| |
| private var _selectedLabel:String; |
| /** |
| * The text of the label showing when the component is selected. |
| * Subclasses can set or override this property to customize the selected label. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected function get selectedLabel():String |
| { |
| return _selectedLabel; |
| } |
| |
| protected function set selectedLabel(value:String):void |
| { |
| _selectedLabel = value; |
| } |
| |
| //---------------------------------- |
| // unselectedLabel |
| //---------------------------------- |
| |
| private var _unselectedLabel:String; |
| /** |
| * The text of the label showing when the component is not selected. |
| * Subclasses can set or override this property to customize the unselected label. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3 |
| * @productversion Flex 4.6 |
| */ |
| protected function get unselectedLabel():String |
| { |
| return _unselectedLabel; |
| } |
| |
| protected function set unselectedLabel(value:String):void |
| { |
| _unselectedLabel = value; |
| } |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Overridden Methods |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Redraw the graphics of the skin as necessary |
| */ |
| override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| super.drawBackground(unscaledWidth, unscaledHeight); |
| |
| // calculate skin dimensions - outer stroke |
| var calculatedContentWidth:Number = Math.max(unscaledWidth - 2 * layoutBorderSize, |
| getElementPreferredWidth(thumb)); |
| var calculatedContentHeight:Number = Math.max(unscaledHeight - 2 * layoutBorderSize, |
| getElementPreferredHeight(thumb)); |
| |
| drawSlidingContent(calculatedContentWidth, calculatedContentHeight); |
| drawTrack(calculatedContentWidth, calculatedContentHeight); |
| drawThumb(calculatedContentWidth, calculatedContentHeight); |
| drawMask(calculatedContentWidth, calculatedContentHeight); |
| |
| // simulate outer stroke using a larger filled rounded rect |
| graphics.beginFill(0xffffff, 0.3); |
| graphics.drawRoundRect(0, (calculatedContentHeight - layoutThumbHeight) / 2, |
| calculatedContentWidth + 2 * layoutBorderSize, |
| layoutThumbHeight + 2 * layoutBorderSize, |
| layoutCornerEllipseSize + layoutBorderSize); |
| graphics.endFill(); |
| } |
| |
| /** |
| * @private |
| * Resize and reposition as necessary |
| */ |
| override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| super.layoutContents(unscaledWidth, unscaledHeight); |
| |
| // calculate skin dimensions - outer stroke |
| var calculatedContentWidth:Number = Math.max(unscaledWidth - 2 * layoutBorderSize, |
| getElementPreferredWidth(thumb)); |
| var calculatedContentHeight:Number = Math.max(unscaledHeight - 2 * layoutBorderSize, |
| getElementPreferredHeight(thumb)); |
| |
| setElementSize(contents, calculatedContentWidth, layoutThumbHeight); |
| setElementPosition(contents, layoutBorderSize, |
| layoutBorderSize + (calculatedContentHeight - layoutThumbHeight) / 2); |
| |
| layoutTrack(calculatedContentWidth, layoutThumbHeight); |
| layoutThumb(calculatedContentWidth, layoutThumbHeight); |
| // Sliding content must be positioned after the track & thumb have been sized |
| layoutSlidingContent(calculatedContentWidth, layoutThumbHeight); |
| layoutMask(calculatedContentWidth, layoutThumbHeight); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function measure():void |
| { |
| // The skin must be at least as large as the thumb + outer stroke |
| measuredMinWidth = layoutThumbWidth + 2 * layoutBorderSize; |
| measuredMinHeight = layoutThumbWidth + 2 * layoutBorderSize; |
| |
| // The preferred size will display all label text |
| var labelWidth:Number = Math.max(getElementPreferredWidth(selectedLabelDisplay), |
| getElementPreferredWidth(unselectedLabelDisplay)); |
| |
| measuredWidth = layoutThumbWidth + labelWidth + layoutInnerPadding + |
| layoutOuterPadding + 2 * layoutBorderSize; |
| measuredHeight = layoutThumbHeight + 2 * layoutBorderSize; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function commitCurrentState():void |
| { |
| if (currentState && currentState.indexOf("disabled") >= 0) |
| { |
| alpha = 0.5; |
| selectedLabelDisplay.showShadow(false); |
| unselectedLabelDisplay.showShadow(false); |
| } |
| else |
| { |
| alpha = 1.0; |
| selectedLabelDisplay.showShadow(true); |
| unselectedLabelDisplay.showShadow(true); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| contents = new UIComponent(); |
| contents.blendMode = BlendMode.LAYER; |
| addChild(contents); |
| |
| // SlidingContent: background, overlay, labels |
| slidingContentBackground = new SpriteVisualElement(); |
| contents.addChild(slidingContentBackground); |
| |
| slidingContentOverlay = new slidingContentOverlayClass(); |
| contents.addChild(slidingContentOverlay); |
| |
| slidingContentForeground = new UIComponent(); |
| contents.addChild(slidingContentForeground); |
| |
| selectedLabelDisplay = new LabelDisplayComponent(); |
| selectedLabelDisplay.id = "selectedLabelDisplay"; |
| selectedLabelDisplay.text = selectedLabel; |
| selectedLabelDisplay.shadowYOffset = layoutTextShadowOffset; |
| slidingContentForeground.addChild(selectedLabelDisplay); |
| |
| unselectedLabelDisplay = new LabelDisplayComponent(); |
| unselectedLabelDisplay.id = "unselectedLabelDisplay"; |
| unselectedLabelDisplay.text = unselectedLabel; |
| unselectedLabelDisplay.shadowYOffset = layoutTextShadowOffset; |
| slidingContentForeground.addChild(unselectedLabelDisplay); |
| |
| // Track |
| track = new SpriteVisualElement(); |
| contents.addChild(SpriteVisualElement(track)); |
| |
| // Thumb |
| thumb = new SpriteVisualElement(); |
| contents.addChild(SpriteVisualElement(thumb)); |
| |
| thumbEraseOverlay = new Sprite(); |
| thumbEraseOverlay.blendMode = BlendMode.ERASE; |
| SpriteVisualElement(thumb).addChild(thumbEraseOverlay); |
| thumbContent = new Sprite(); |
| SpriteVisualElement(thumb).addChild(thumbContent); |
| |
| // Content clipping mask |
| var contentMask:Sprite = new SpriteVisualElement(); |
| contents.mask = contentMask; |
| contents.addChild(contentMask); |
| } |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| /** |
| * Draw the sliding content background |
| * SlidingContent's x origin matches the thumb's x origin, meaning some of |
| * the background is drawn to the left, and some to the right. |
| */ |
| private function drawSlidingContent(skinWidth:Number, skinHeight:Number):void |
| { |
| slidingContentBackground.graphics.clear(); |
| |
| // selected side of the sliding content |
| slidingContentBackground.graphics.beginFill(getStyle("accentColor")); |
| slidingContentBackground.graphics.drawRect(layoutThumbWidth - skinWidth, 0, skinWidth - layoutThumbWidth / 2, |
| layoutThumbHeight); |
| slidingContentBackground.graphics.endFill(); |
| |
| // unselected side of the sliding content |
| slidingContentBackground.graphics.beginFill(ColorUtil.adjustBrightness2(getStyle("chromeColor"), -25)); |
| slidingContentBackground.graphics.drawRect(layoutThumbWidth / 2, 0, skinWidth - layoutThumbWidth / 2, |
| layoutThumbHeight); |
| slidingContentBackground.graphics.endFill(); |
| } |
| |
| /** |
| * Lay out SlidingContent and its children. Because we only need the x,y |
| * coordinate of SlidingContent, we can ignore its size. |
| * The origin of SlidingContent overlaps the origin of the thumb, and the |
| * positioning is handled by thumbPositionChanged_handler. |
| */ |
| private function layoutSlidingContent(skinWidth:Number, skinHeight:Number):void |
| { |
| var visibleTrackWidth:Number = skinWidth - layoutThumbWidth; |
| var labelWidth:Number = visibleTrackWidth - layoutInnerPadding - layoutOuterPadding; |
| |
| setElementSize(selectedLabelDisplay, labelWidth, layoutThumbHeight); |
| setElementPosition(selectedLabelDisplay, -visibleTrackWidth + layoutOuterPadding, 0); |
| |
| setElementSize(unselectedLabelDisplay, labelWidth, layoutThumbHeight); |
| setElementPosition(unselectedLabelDisplay, layoutThumbWidth + layoutInnerPadding, 0); |
| |
| setElementSize(slidingContentOverlay, skinWidth, layoutThumbHeight); |
| setElementPosition(slidingContentOverlay, 0, (skinHeight - layoutThumbHeight) / 2); |
| |
| moveSlidingContent(); |
| } |
| |
| /** |
| * Draw the track and its shadow |
| */ |
| private function drawTrack(skinWidth:Number, skinHeight:Number):void |
| { |
| var graphics:Graphics = SpriteVisualElement(track).graphics; |
| graphics.clear(); |
| graphics.lineStyle(layoutStrokeWeight, 0, .3); |
| graphics.drawRoundRect(layoutStrokeWeight / 2, layoutStrokeWeight / 2, |
| skinWidth - layoutStrokeWeight, |
| (layoutThumbHeight - layoutStrokeWeight), (layoutCornerEllipseSize - layoutStrokeWeight / 2)); |
| graphics.lineStyle(); |
| } |
| |
| /** |
| * Resize and reposition the track |
| */ |
| private function layoutTrack(skinWidth:Number, skinHeight:Number):void |
| { |
| setElementSize(track, skinWidth, layoutThumbHeight); |
| setElementPosition(track, 0, (skinHeight - layoutThumbHeight) / 2); |
| } |
| |
| /** |
| * Draw the thumb. The thumb has an outer border, inner gradient, and |
| * inner highlight stroke. |
| */ |
| private function drawThumb(skinWidth:Number, skinHeight:Number):void |
| { |
| var graphics:Graphics = thumbContent.graphics; |
| var colors:Array = []; |
| var alphas:Array = []; |
| var ratios:Array = []; |
| var baseColor:Number = getStyle("chromeColor"); |
| |
| if (currentState && currentState.indexOf("down") >= 0) |
| baseColor = ColorUtil.adjustBrightness(baseColor, -60); |
| |
| graphics.clear(); |
| |
| // Thumb outline |
| colors[0] = ColorUtil.adjustBrightness2(baseColor, -70); |
| colors[1] = ColorUtil.adjustBrightness2(baseColor, -55); |
| |
| alphas[0] = 1; |
| alphas[1] = 1; |
| |
| ratios[0] = 0; |
| ratios[1] = 255; |
| |
| colorMatrix.createGradientBox(layoutThumbWidth, layoutThumbHeight, Math.PI / 2); |
| graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, colorMatrix); |
| graphics.drawRoundRect(0, 0, layoutThumbWidth, layoutThumbHeight, layoutCornerEllipseSize); |
| graphics.endFill(); |
| |
| // Base gradient fill, one stroke weight inside outline |
| colors[0] = ColorUtil.adjustBrightness2(baseColor, -30); |
| colors[1] = baseColor; |
| colors[2] = ColorUtil.adjustBrightness2(baseColor, 20); |
| |
| alphas[2] = 1; |
| |
| ratios[0] = 0; |
| ratios[1] = .7 * 255; |
| ratios[2] = 255; |
| |
| colorMatrix.createGradientBox(layoutThumbWidth - layoutStrokeWeight * 2, |
| layoutThumbHeight - layoutStrokeWeight * 2, Math.PI / 2); |
| graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, colorMatrix); |
| graphics.drawRoundRect(layoutStrokeWeight, layoutStrokeWeight, |
| layoutThumbWidth - layoutStrokeWeight * 2, |
| layoutThumbHeight - layoutStrokeWeight * 2, layoutCornerEllipseSize - layoutStrokeWeight * 2); |
| graphics.endFill(); |
| |
| // Thumb highlight, one stroke weight inside outline |
| colors[0] = 0xffffff; |
| colors[1] = 0xffffff; |
| colors[2] = 0x0; |
| |
| alphas[0] = .9; |
| alphas[1] = 0; |
| alphas[2] = .2; |
| |
| ratios[0] = .33 * 255; |
| ratios[1] = .5 * 255; |
| ratios[2] = 255; |
| |
| colorMatrix.createGradientBox(layoutThumbWidth - layoutStrokeWeight * 3, |
| layoutThumbHeight - layoutStrokeWeight * 3, Math.PI / 2); |
| graphics.lineStyle(layoutStrokeWeight); |
| graphics.lineGradientStyle(GradientType.LINEAR, colors, alphas, ratios, colorMatrix); |
| graphics.drawRoundRect(layoutStrokeWeight * 1.5, layoutStrokeWeight * 1.5, |
| layoutThumbWidth - layoutStrokeWeight * 3, layoutThumbHeight - layoutStrokeWeight * 3, |
| layoutCornerEllipseSize - layoutStrokeWeight * 3); |
| graphics.lineStyle(); |
| |
| // Redraw the erase overlay as a silhouette of the thumb |
| thumbEraseOverlay.graphics.clear(); |
| thumbEraseOverlay.graphics.beginFill(0); |
| thumbEraseOverlay.graphics.drawRoundRect(0, 0, layoutThumbWidth, layoutThumbHeight, layoutCornerEllipseSize); |
| thumbEraseOverlay.graphics.endFill(); |
| } |
| |
| /** |
| * Resize the thumb. Its position is handled by the component. |
| */ |
| private function layoutThumb(skinWidth:Number, skinHeight:Number):void |
| { |
| setElementSize(thumb, layoutThumbWidth, layoutThumbHeight); |
| } |
| |
| /** |
| * Draw the clipping mask for the component. This is roughly the |
| * same as the track area. |
| */ |
| private function drawMask(skinWidth:Number, skinHeight:Number):void |
| { |
| var graphics:Graphics = SpriteVisualElement(contents.mask).graphics; |
| graphics.clear(); |
| graphics.beginFill(0x0); |
| graphics.drawRoundRect(0, 0, skinWidth, layoutThumbHeight, layoutCornerEllipseSize); |
| graphics.endFill(); |
| } |
| |
| /** |
| * Resize and reposition the clipping mask |
| */ |
| private function layoutMask(skinWidth:Number, skinHeight:Number):void |
| { |
| setElementSize(contents.mask, skinWidth, layoutThumbHeight); |
| setElementPosition(contents.mask, 0, (skinHeight - layoutThumbHeight) / 2); |
| } |
| |
| /** |
| * Move the sliding content to line up with thumbPosition. |
| * This version assumes the thumb and track share the same coordinate system. |
| */ |
| private function moveSlidingContent():void |
| { |
| if (!hostComponent) |
| return; |
| var x:Number = (track.getLayoutBoundsWidth() - thumb.getLayoutBoundsWidth()) * |
| hostComponent.thumbPosition + track.getLayoutBoundsX(); |
| var y:Number = thumb.getLayoutBoundsY(); |
| setElementPosition(slidingContentBackground, x, y); |
| setElementPosition(slidingContentForeground, x, y); |
| } |
| |
| //---------------------------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //---------------------------------------------------------------------------------------------- |
| |
| /** |
| * When the thumb position changes, reposition the sliding content. |
| */ |
| private function thumbPositionChanged_handler(event:Event):void |
| { |
| moveSlidingContent(); |
| } |
| } |
| } |
| |
| 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 combining two labels to create the effect of text and its drop |
| * shadow. The component can be used with advanced style selectors and the |
| * styles "color", "textShadowColor", and "textShadowAlpha". Based off of |
| * ActionBar.TitleDisplayComponent. These two should eventually be factored. |
| */ |
| class LabelDisplayComponent extends UIComponent implements IDisplayText |
| { |
| public var shadowYOffset:Number = 0; |
| private var labelChanged:Boolean = false; |
| private var labelDisplay:StyleableTextField; |
| private var labelDisplayShadow:StyleableTextField; |
| private var _text:String; |
| |
| public function LabelDisplayComponent() |
| { |
| super(); |
| _text = ""; |
| } |
| |
| override public function get baselinePosition():Number |
| { |
| return labelDisplay.baselinePosition; |
| } |
| |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| labelDisplay = StyleableTextField(createInFontContext(StyleableTextField)); |
| labelDisplay.styleName = this; |
| labelDisplay.editable = false; |
| labelDisplay.selectable = false; |
| labelDisplay.multiline = false; |
| labelDisplay.wordWrap = false; |
| labelDisplay.addEventListener(FlexEvent.VALUE_COMMIT, |
| labelDisplay_valueCommitHandler); |
| |
| labelDisplayShadow = StyleableTextField(createInFontContext(StyleableTextField)); |
| labelDisplayShadow.styleName = this; |
| labelDisplayShadow.colorName = "textShadowColor"; |
| labelDisplayShadow.editable = false; |
| labelDisplayShadow.selectable = false; |
| labelDisplayShadow.multiline = false; |
| labelDisplayShadow.wordWrap = false; |
| |
| addChild(labelDisplayShadow); |
| addChild(labelDisplay); |
| } |
| |
| override protected function commitProperties():void |
| { |
| super.commitProperties(); |
| |
| if (labelChanged) |
| { |
| labelDisplay.text = text; |
| invalidateSize(); |
| invalidateDisplayList(); |
| labelChanged = false; |
| } |
| } |
| |
| override protected function measure():void |
| { |
| if (labelDisplay.isTruncated) |
| labelDisplay.text = text; |
| labelDisplay.commitStyles(); |
| measuredWidth = labelDisplay.getPreferredBoundsWidth(); |
| measuredHeight = labelDisplay.getPreferredBoundsHeight(); |
| } |
| |
| override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| if (labelDisplay.isTruncated) |
| labelDisplay.text = text; |
| labelDisplay.commitStyles(); |
| |
| var labelHeight:Number = labelDisplay.getPreferredBoundsHeight(); |
| var labelY:Number = (unscaledHeight - labelHeight) / 2; |
| |
| var labelWidth:Number = Math.min(unscaledWidth, labelDisplay.getPreferredBoundsWidth()); |
| var labelX:Number = (unscaledWidth - labelWidth) / 2; |
| |
| labelDisplay.setLayoutBoundsSize(labelWidth, labelHeight); |
| labelDisplay.setLayoutBoundsPosition(labelX, labelY); |
| |
| labelDisplay.truncateToFit(); |
| |
| labelDisplayShadow.commitStyles(); |
| labelDisplayShadow.setLayoutBoundsSize(labelWidth, labelHeight); |
| labelDisplayShadow.setLayoutBoundsPosition(labelX, labelY + shadowYOffset); |
| |
| labelDisplayShadow.alpha = getStyle("textShadowAlpha"); |
| |
| // unless the label was truncated, labelDisplayShadow.text was set in |
| // the value commit handler |
| if (labelDisplay.isTruncated) |
| labelDisplayShadow.text = labelDisplay.text; |
| } |
| |
| private function labelDisplay_valueCommitHandler(event:Event):void |
| { |
| labelDisplayShadow.text = labelDisplay.text; |
| } |
| |
| public function get text():String |
| { |
| return _text; |
| } |
| |
| public function set text(value:String):void |
| { |
| _text = value; |
| labelChanged = true; |
| invalidateProperties(); |
| } |
| |
| public function get isTruncated():Boolean |
| { |
| return labelDisplay.isTruncated; |
| } |
| |
| public function showShadow(value:Boolean):void |
| { |
| labelDisplayShadow.visible = value; |
| } |
| } |