You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by bi...@apache.org on 2014/10/02 00:54:13 UTC
[3/5] Adding new branch for working on ios7 skins.
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as
new file mode 100644
index 0000000..e076a6b
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as
@@ -0,0 +1,326 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.Graphics;
+ import flash.display.InteractiveObject;
+ import flash.display.Sprite;
+
+ import mx.core.DPIClassification;
+ import mx.core.mx_internal;
+
+ import spark.components.Group;
+ import spark.components.SpinnerListContainer;
+ import spark.layouts.HorizontalLayout;
+ import spark.skins.android4.assets.SpinnerListContainerBackground;
+ import spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+ import spark.skins.android4.assets.SpinnerListContainerShadow;
+ import spark.skins.mobile.supportClasses.MobileSkin;
+
+ use namespace mx_internal;
+ /**
+ * ActionScript-based skin for the SpinnerListContainer in mobile applications.
+ *
+ * @see spark.components.SpinnerListContainer
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public class SpinnerListContainerSkin extends MobileSkin
+ {
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ *
+ */
+ public function SpinnerListContainerSkin()
+ {
+ super();
+
+ borderClass = spark.skins.android4.assets.SpinnerListContainerBackground;
+ selectionIndicatorClass = spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+ shadowClass = spark.skins.android4.assets.SpinnerListContainerShadow;
+ cornerRadius = 0;
+ borderThickness = 0;
+ switch (applicationDPI)
+ {
+ case DPIClassification.DPI_640:
+ {
+ selectionIndicatorHeight = 182;
+ break;
+ }
+ case DPIClassification.DPI_480:
+ {
+ selectionIndicatorHeight = 144;
+ break;
+ }
+ case DPIClassification.DPI_320:
+ {
+ selectionIndicatorHeight = 96;
+ break;
+ }
+ case DPIClassification.DPI_240:
+ {
+ selectionIndicatorHeight = 72;
+ break;
+ }
+ case DPIClassification.DPI_120:
+ {
+ selectionIndicatorHeight = 36;
+ break;
+ }
+ default: // default DPI_160
+ {
+ selectionIndicatorHeight = 48;
+
+ break;
+ }
+ }
+
+ minWidth = 30;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * Pixel thickness of the border.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var borderThickness:Number;
+
+ /**
+ * Radius of the border corners.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var cornerRadius:Number;
+
+ /**
+ * Height of the selection indicator.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var selectionIndicatorHeight:Number;
+
+ /**
+ * Class for the border part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var borderClass:Class;
+
+ /**
+ * Class for the selection indicator skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var selectionIndicatorClass:Class;
+
+ /**
+ * Class for the shadow skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var shadowClass:Class;
+
+ /**
+ * Border skin part which includes the background.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var border:InteractiveObject;
+
+ /**
+ * Selection indicator skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var selectionIndicator:InteractiveObject;
+
+ /**
+ * Shadow skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var shadow:InteractiveObject;
+
+ /**
+ * Mask for the content group.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var contentGroupMask:Sprite;
+
+ //--------------------------------------------------------------------------
+ //
+ // Skin parts
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * An optional skin part that defines the Group where the content
+ * children are pushed into and laid out.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public var contentGroup:Group;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public var hostComponent:SpinnerListContainer;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden Methods
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * @private
+ */
+ override protected function createChildren():void
+ {
+ super.createChildren();
+
+ if (!border)
+ {
+ // Border and background
+ border = new borderClass();
+ border.mouseEnabled = false;
+ addChild(border);
+ }
+
+ if (!contentGroup)
+ {
+ // Contains the child elements
+ contentGroup = new Group();
+ var hLayout:HorizontalLayout = new HorizontalLayout();
+ hLayout.gap = 0;
+ hLayout.verticalAlign = "middle";
+ contentGroup.layout = hLayout;
+ contentGroup.id = "contentGroup";
+ addChild(contentGroup);
+ }
+
+ if (!shadow)
+ {
+ // Shadowing sits on top of the content
+ shadow = new shadowClass();
+ shadow.mouseEnabled = false;
+ addChild(shadow);
+ }
+
+
+ if (!contentGroupMask)
+ {
+ // Create a mask for the content
+ contentGroupMask = new Sprite();
+ addChild(contentGroupMask);
+ }
+ }
+
+ /**
+ * @private
+ */
+ override protected function measure():void
+ {
+ super.measure();
+
+ var contentW:Number = contentGroup.getPreferredBoundsWidth();
+ var contentH:Number = contentGroup.getPreferredBoundsHeight();
+
+ measuredWidth = measuredMinWidth = contentW + borderThickness * 2;
+ measuredHeight = contentH + borderThickness * 2;
+
+ }
+
+ /**
+ * @private
+ */
+ override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.layoutContents(unscaledWidth, unscaledHeight);
+
+ setElementSize(contentGroup, unscaledWidth - borderThickness * 2, unscaledHeight - borderThickness * 2);
+ setElementPosition(contentGroup, borderThickness, borderThickness);
+
+ // Inset by the borderThickness horizontally because the selectionIndicator starts at 0
+ setElementSize(border, unscaledWidth - borderThickness * 2, unscaledHeight);
+ setElementPosition(border, borderThickness, 0);
+
+ setElementSize(shadow, unscaledWidth - borderThickness * 4, measuredHeight - borderThickness * 2);
+ setElementPosition(shadow, borderThickness * 2, unscaledHeight/2 - measuredHeight/2);
+
+ // The SpinnerLists contain a left and right border. We don't want to show the leftmost
+ // SpinnerLists's left border nor the rightmost one's right border.
+ // We inset the mask on the left and right sides to accomplish this.
+ var g:Graphics = contentGroupMask.graphics;
+ g.clear();
+ g.beginFill(0x00FF00);
+ g.drawRoundRect(borderThickness * 2, borderThickness, unscaledWidth - borderThickness * 4, unscaledHeight - borderThickness * 2, cornerRadius, cornerRadius);
+ g.endFill();
+
+ contentGroup.mask = contentGroupMask;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml
new file mode 100644
index 0000000..270818e
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+
+
+<!--
+
+Scroller unconditionally sets its skin's layout to private layout
+implementation that handles the scroll policies. Scroller skins can
+only provide replacement scrollbars. The skin's layout and
+constraints or dimensions set on skin parts will not be honored. To
+gain more control over the layout of a viewport and its scrollbars,
+instead of using Scroller, add them to a Group and use the ScrollBar component's
+viewport property to link them together.
+
+-->
+
+<!--- The default skin class for the Spark Scroller that is used by the SpinnerList component.
+
+@see spark.components.SpinnerList
+@see spark.components.Scroller
+
+@langversion 3.0
+@playerversion AIR 3
+@productversion Flex 4.6
+-->
+<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
+
+ <fx:Metadata>
+ <![CDATA[
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ [HostComponent("spark.components.Scroller")]
+ ]]>
+ </fx:Metadata>
+
+ <fx:Script>
+ <![CDATA[
+ /**
+ * @private
+ */
+ override public function beginHighlightBitmapCapture() : Boolean
+ {
+ var needUpdate:Boolean = super.beginHighlightBitmapCapture();
+
+ // Draw an opaque rect that fill our entire skin. Our background
+ // is transparent, but we don't want focus/error skins to
+ // poke through. This is safe to do since we don't have any
+ // graphic elements as direct children.
+ graphics.beginFill(0);
+ graphics.drawRect(0, 0, width, height);
+ graphics.endFill();
+
+ return needUpdate;
+ }
+
+ /**
+ * @private
+ */
+ override public function endHighlightBitmapCapture() : Boolean
+ {
+ var needUpdate:Boolean = super.endHighlightBitmapCapture();
+
+ // Clear the rect we drew in beginBitmapCapture();
+ graphics.clear();
+
+ return needUpdate;
+ }
+ ]]>
+ </fx:Script>
+
+</s:SparkSkin>
+
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as
new file mode 100644
index 0000000..b86553f
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as
@@ -0,0 +1,294 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.InteractiveObject;
+
+ import mx.core.ClassFactory;
+ import mx.core.DPIClassification;
+ import mx.core.mx_internal;
+
+ import spark.components.DataGroup;
+ import spark.components.Scroller;
+ import spark.components.SpinnerList;
+ import spark.components.SpinnerListItemRenderer;
+ import spark.layouts.VerticalSpinnerLayout;
+ import spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+ import spark.skins.mobile.supportClasses.MobileSkin;
+
+
+ use namespace mx_internal;
+ /**
+ * ActionScript-based skin for the SpinnerList in mobile applications.
+ *
+ * @see spark.components.SpinnerList
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public class SpinnerListSkin extends MobileSkin
+ {
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public function SpinnerListSkin()
+ {
+ super();
+
+ selectionIndicatorClass = spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+ borderThickness = 1;
+ switch (applicationDPI)
+ {
+ case DPIClassification.DPI_640:
+ {
+ selectionIndicatorHeight = 182;
+ minWidth = 64;
+ borderThickness = 3;
+ break;
+ }
+ case DPIClassification.DPI_480:
+ {
+ selectionIndicatorHeight = 144;
+ minWidth = 48;
+ borderThickness = 2;
+ break;
+ }
+ case DPIClassification.DPI_320:
+ {
+ selectionIndicatorHeight = 96;
+ minWidth = 32;
+ borderThickness = 2;
+ break;
+ }
+ case DPIClassification.DPI_240:
+ {
+ selectionIndicatorHeight = 72;
+ minWidth = 24;
+ borderThickness = 1;
+ break;
+ }
+ case DPIClassification.DPI_120:
+ {
+ selectionIndicatorHeight = 36;
+ minWidth = 12;
+ borderThickness = 0;
+ break;
+ }
+ default:
+ {
+ selectionIndicatorHeight = 48;
+ minWidth = 16;
+ borderThickness = 1;
+ }
+ }
+
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Skin parts
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Scroller skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public var scroller:Scroller;
+
+ /**
+ * DataGroup skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public var dataGroup:DataGroup;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ public var hostComponent:SpinnerList;
+
+ /**
+ * Pixel size of the border.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var borderThickness:int;
+
+ /**
+ * Class for the selection indicator skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var selectionIndicatorClass:Class;
+
+ /**
+ * Selection indicator skin part.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var selectionIndicator:InteractiveObject;
+
+ /**
+ * Height of the selection indicator.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Flex 4.6
+ */
+ protected var selectionIndicatorHeight:Number;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override protected function commitCurrentState():void
+ {
+ super.commitCurrentState();
+
+ alpha = currentState.indexOf("disabled") == -1 ? 1 : 0.5;
+ }
+
+ /**
+ * @private
+ */
+ override protected function createChildren():void
+ {
+ super.createChildren();
+
+ if (!dataGroup)
+ {
+ // Create data group layout
+ var layout:VerticalSpinnerLayout = new VerticalSpinnerLayout();
+ layout.requestedRowCount = 5;
+
+ // Create data group
+ dataGroup = new DataGroup();
+ dataGroup.id = "dataGroup";
+ dataGroup.layout = layout;
+
+ dataGroup.itemRenderer = new ClassFactory(spark.components.SpinnerListItemRenderer);
+ }
+
+ if (!scroller)
+ {
+ // Create scroller
+ scroller = new Scroller();
+ scroller.id = "scroller";
+ scroller.hasFocusableChildren = false;
+ scroller.ensureElementIsVisibleForSoftKeyboard = false;
+
+ // Only support vertical scrolling
+ scroller.setStyle("verticalScrollPolicy","on");
+ scroller.setStyle("horizontalScrollPolicy", "off");
+ scroller.setStyle("skinClass", spark.skins.android4.SpinnerListScrollerSkin);
+
+ addChild(scroller);
+ }
+
+ if (!selectionIndicator)
+ {
+ // Selection indicator is on top
+ selectionIndicator = new selectionIndicatorClass();
+ selectionIndicator.mouseEnabled = false;
+ addChild(selectionIndicator);
+ }
+
+ // Associate scroller with data group
+ if (!scroller.viewport)
+ scroller.viewport = dataGroup;
+ }
+
+ /**
+ * @private
+ */
+ override protected function measure():void
+ {
+ measuredWidth = scroller.getPreferredBoundsWidth() + borderThickness * 2;
+ measuredHeight = scroller.getPreferredBoundsHeight();
+ //add in for selection indicator
+ measuredMinHeight = selectionIndicatorHeight + borderThickness * 4;
+ minHeight = measuredMinHeight;
+ }
+
+ /**
+ * @private
+ */
+ override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.layoutContents(unscaledWidth, unscaledHeight);
+
+ // Scroller
+ setElementSize(scroller, unscaledWidth - borderThickness * 2, unscaledHeight);
+ setElementPosition(scroller, borderThickness, 0);
+ //selection indicator
+ unscaledHeight = Math.max(unscaledHeight, selectionIndicatorHeight + borderThickness * 4);
+
+ setElementSize(selectionIndicator, unscaledWidth, selectionIndicatorHeight);
+ setElementPosition(selectionIndicator, 0, Math.floor((unscaledHeight - selectionIndicatorHeight) / 2));
+ }
+
+ /**
+ * @private
+ */
+ override public function styleChanged(styleProp:String):void
+ {
+ // Reinitialize the typical element so it picks up the latest styles
+ // Font styles might impact the size of the SpinnerList
+ if (styleProp != "color" && styleProp != "accentColor")
+ {
+ if (dataGroup)
+ dataGroup.invalidateTypicalItemRenderer();
+ }
+
+ super.styleChanged(styleProp);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as
new file mode 100644
index 0000000..d48377d
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as
@@ -0,0 +1,190 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 mx.core.DPIClassification;
+ import mx.core.mx_internal;
+
+ import spark.components.TextArea;
+ import spark.components.supportClasses.IStyleableEditableText;
+ import spark.components.supportClasses.ScrollableStageText;
+ import spark.components.supportClasses.StyleableTextField;
+ import spark.skins.android4.supportClasses.StageTextSkinBase;
+
+ use namespace mx_internal;
+
+ /**
+ * ActionScript-based skin for TextArea controls in mobile applications that uses a
+ * StyleableStageText class for the text display.
+ *
+ * @see spark.components.TextArea
+ * @see spark.components.supportClasses.StyleableStageText
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3.0
+ * @productversion Flex 4.6
+ */
+ public class StageTextAreaSkin extends StageTextSkinBase
+ {
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The underlying native text control on iOS has internal margins of its
+ * own. In order to remain faithful to the paddingTop and paddingBottom
+ * style values that developers may specify, those internal margins need to
+ * be compensated for. This variable contains size of that compensation in
+ * pixels.
+ */
+ mx_internal static var iOSVerticalPaddingAdjustment:Number = 5;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3.0
+ * @productversion Flex 4.6
+ */
+ public function StageTextAreaSkin()
+ {
+ super();
+ multiline = true;
+
+ switch (applicationDPI)
+ {
+ case DPIClassification.DPI_640:
+ {
+ measuredDefaultHeight = 212;
+ break;
+ }
+ case DPIClassification.DPI_480:
+ {
+ measuredDefaultHeight = 140;
+ break;
+ }
+ case DPIClassification.DPI_320:
+ {
+ measuredDefaultHeight = 106;
+ break;
+ }
+ case DPIClassification.DPI_240:
+ {
+ measuredDefaultHeight = 70;
+ break;
+ }
+ case DPIClassification.DPI_120:
+ {
+ measuredDefaultHeight = 35;
+ break;
+ }
+ default:
+ {
+ measuredDefaultHeight = 48;
+ break;
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ */
+ public var hostComponent:TextArea; // SkinnableComponent will populate
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override protected function measure():void
+ {
+ super.measure();
+ measureTextComponent(hostComponent);
+ }
+
+ /**
+ * @private
+ */
+ override protected function layoutContents(unscaledWidth:Number,
+ unscaledHeight:Number):void
+ {
+ // base class handles border position & size
+ super.layoutContents(unscaledWidth, unscaledHeight);
+
+ // position & size the text
+ var paddingLeft:Number = getStyle("paddingLeft");
+ var paddingRight:Number = getStyle("paddingRight");
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+
+ var unscaledTextWidth:Number = Math.max(0, unscaledWidth - paddingLeft - paddingRight);
+ var unscaledTextHeight:Number = Math.max(0, unscaledHeight - paddingTop - paddingBottom);
+
+ if (textDisplay)
+ {
+ var verticalPosAdjustment:Number = 0;
+ var heightAdjustment:Number = 0;
+
+ /* if (Platform.isIOS)
+ {
+ verticalPosAdjustment = Math.min(iOSVerticalPaddingAdjustment, paddingTop);
+ heightAdjustment = verticalPosAdjustment + Math.min(iOSVerticalPaddingAdjustment, paddingBottom);
+ }*/
+
+ textDisplay.commitStyles();
+ setElementSize(textDisplay, unscaledTextWidth, unscaledTextHeight + heightAdjustment);
+ setElementPosition(textDisplay, paddingLeft, paddingTop - verticalPosAdjustment);
+ }
+
+ if (promptDisplay)
+ {
+ if (promptDisplay is StyleableTextField)
+ StyleableTextField(promptDisplay).commitStyles();
+
+ setElementSize(promptDisplay, unscaledTextWidth, unscaledTextHeight);
+ setElementPosition(promptDisplay, paddingLeft, paddingTop);
+ }
+ }
+
+ override protected function createTextDisplay():IStyleableEditableText
+ {
+ return new ScrollableStageText(multiline);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as
new file mode 100644
index 0000000..7f92647
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as
@@ -0,0 +1,134 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.TextInput;
+ import spark.components.supportClasses.IStyleableEditableText;
+ import spark.components.supportClasses.ScrollableStageText;
+ import spark.components.supportClasses.StyleableTextField;
+ import spark.skins.android4.supportClasses.StageTextSkinBase;
+
+ /**
+ * ActionScript-based skin for TextInput controls in mobile applications that uses a
+ * StyleableStageText class for the text input.
+ *
+ * @see spark.components.TextInput
+ * @see spark.components.supportClasses.StyleableStageText
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3.0
+ * @productversion Flex 4.6
+ */
+ public class StageTextInputSkin extends StageTextSkinBase
+ {
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3.0
+ * @productversion Flex 4.6
+ */
+ public function StageTextInputSkin()
+ {
+ super();
+ multiline = false;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ */
+ public var hostComponent:TextInput; // SkinnableComponent will populate
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override protected function measure():void
+ {
+ super.measure();
+ measureTextComponent(hostComponent);
+ }
+
+ /**
+ * @private
+ */
+ override protected function layoutContents(unscaledWidth:Number,
+ unscaledHeight:Number):void
+ {
+ // base class handles border position & size
+ super.layoutContents(unscaledWidth, unscaledHeight);
+
+ // position & size the text
+ var paddingLeft:Number = getStyle("paddingLeft");
+ var paddingRight:Number = getStyle("paddingRight");
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+
+ var unscaledTextWidth:Number = Math.max(0, unscaledWidth - paddingLeft - paddingRight);
+ var unscaledTextHeight:Number = Math.max(0, unscaledHeight - paddingTop - paddingBottom);
+
+ // default vertical positioning is centered
+ var textHeight:Number = getElementPreferredHeight(textDisplay);
+ var textY:Number = Math.round(0.5 * (unscaledTextHeight - textHeight)) + paddingTop;
+
+ if (textDisplay)
+ {
+ textDisplay.commitStyles();
+ setElementSize(textDisplay, unscaledTextWidth, unscaledTextHeight);
+ setElementPosition(textDisplay, paddingLeft, textY);
+ }
+
+ if (promptDisplay)
+ {
+ if (promptDisplay is StyleableTextField)
+ StyleableTextField(promptDisplay).commitStyles();
+
+ var promptHeight:Number = getElementPreferredHeight(promptDisplay);
+ var promptY:Number = Math.round(0.5 * (unscaledTextHeight - promptHeight)) + paddingTop;
+
+ setElementSize(promptDisplay, unscaledTextWidth, promptHeight);
+ setElementPosition(promptDisplay, paddingLeft, promptY);
+ }
+ }
+
+ override protected function createTextDisplay():IStyleableEditableText
+ {
+ return new ScrollableStageText(multiline);
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as
new file mode 100644
index 0000000..eea5948
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as
@@ -0,0 +1,122 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.ButtonBarButton;
+import spark.components.DataGroup;
+import spark.skins.mobile.supportClasses.ButtonBarButtonClassFactory;
+import spark.skins.mobile.supportClasses.TabbedViewNavigatorTabBarHorizontalLayout;
+
+/**
+ * The Android 4.x specific skin class for the Spark TabbedViewNavigator tabBar skin part.
+ * It uses the ButtonBarFirstButtonSkin and ButtonBarMiddleButtonSkin as skins for first
+ * middle buttons
+ *
+ * @see spark.components.TabbedViewNavigator#tabBar
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+public class TabbedViewNavigatorTabBarSkin extends ButtonBarSkin
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ *
+ */
+ public function TabbedViewNavigatorTabBarSkin()
+ {
+ super();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override protected function createChildren():void
+ {
+ 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;
+ }
+
+ if (!dataGroup)
+ {
+ // TabbedViewNavigatorButtonBarHorizontalLayout for even percent layout
+ var tabLayout:TabbedViewNavigatorTabBarHorizontalLayout =
+ new TabbedViewNavigatorTabBarHorizontalLayout();
+ tabLayout.useVirtualLayout = false;
+
+ dataGroup = new DataGroup();
+ dataGroup.layout = tabLayout;
+ addChild(dataGroup);
+ }
+ }
+
+ /**
+ * @private
+ */
+ override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.drawBackground(unscaledWidth, unscaledHeight);
+
+ // backgroundAlpha style is not supported by ButtonBar
+ // TabbedViewNavigatorSkin sets a hard-coded value to support
+ // overlayControls
+ var backgroundAlphaValue:* = getStyle("backgroundAlpha");
+ var backgroundAlpha:Number = (backgroundAlphaValue === undefined)
+ ? 1 : getStyle("backgroundAlpha");
+
+ graphics.beginFill(getStyle("chromeColor"), backgroundAlpha);
+ graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
+ graphics.endFill();
+ }
+}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as
new file mode 100644
index 0000000..0c231a6
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as
@@ -0,0 +1,892 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.events.Event;
+import flash.events.FocusEvent;
+import flash.events.KeyboardEvent;
+import flash.events.MouseEvent;
+import flash.events.SoftKeyboardEvent;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.system.Capabilities;
+import flash.text.TextLineMetrics;
+import flash.ui.Keyboard;
+
+import mx.core.DPIClassification;
+import mx.core.EventPriority;
+import mx.core.FlexGlobals;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+import mx.utils.Platform;
+
+import spark.components.Group;
+import spark.components.Scroller;
+import spark.components.TextArea;
+import spark.components.supportClasses.StyleableTextField;
+import spark.events.CaretBoundsChangeEvent;
+import spark.skins.android4.supportClasses.TextSkinBase;
+
+use namespace mx_internal;
+
+/**
+ * ActionScript-based skin for TextArea components in mobile applications.
+ *
+ * @see spark.components.TextArea
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+public class TextAreaSkin extends TextSkinBase
+{
+ /**
+ * @private
+ * Right-margin of iOS native text control when editing on a retina display
+ * based on fontSize 32.
+ */
+ mx_internal static var IOS_RIGHT_MARGIN_320:Number = 19;
+
+ /**
+ * @private
+ * Right-margin of iOS native text control when editing on a retina display
+ * based on fontSize 16 scaling from applicationDPI 160.
+ */
+ mx_internal static var IOS_RIGHT_MARGIN_160_SCALED_TO_320:Number = 9.4;
+
+ /**
+ * @private
+ * Right-margin of iOS native text control when editing on a standard display
+ * based on fontSize 16 and runtimeDPI 160.
+ */
+ mx_internal static var IOS_RIGHT_MARGIN_160:Number = 20.6;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function TextAreaSkin()
+ {
+ super();
+
+ addEventListener(Event.RESIZE, resizeHandler);
+
+ switch (applicationDPI)
+ {
+ case DPIClassification.DPI_640:
+ {
+ measuredDefaultWidth = 1024;
+ measuredDefaultHeight = 212;
+ layoutBorderSize = 4;
+ flatheight = 9;
+ break;
+ }
+ case DPIClassification.DPI_480:
+ {
+ measuredDefaultWidth = 880;
+ measuredDefaultHeight = 140;
+ layoutBorderSize = 3;
+ flatheight = 7;
+ break;
+ }
+ case DPIClassification.DPI_320:
+ {
+ measuredDefaultWidth = 612;
+ measuredDefaultHeight = 106;
+ layoutBorderSize = 2;
+ flatheight = 6;
+ break;
+ }
+ case DPIClassification.DPI_240:
+ {
+ measuredDefaultWidth = 440;
+ measuredDefaultHeight = 70;
+ layoutBorderSize = 2;
+ flatheight = 5;
+ break;
+ }
+ case DPIClassification.DPI_120:
+ {
+ measuredDefaultWidth = 220;
+ measuredDefaultHeight = 35;
+ layoutBorderSize = 1;
+ flatheight = 2;
+ break;
+ }
+ default:
+ {
+ measuredDefaultWidth = 306;
+ measuredDefaultHeight = 53;
+ layoutBorderSize = 1;
+ flatheight = 3;
+ break;
+ }
+ }
+ addEventListener(FocusEvent.FOCUS_IN, focusChangeHandler);
+ addEventListener(FocusEvent.FOCUS_OUT, focusChangeHandler);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Skin parts
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Scroller skin part.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public var scroller:Scroller;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ */
+ public var hostComponent:TextArea;
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ protected var isFocused:Boolean = false;
+
+ protected var flatheight:uint;
+
+ /**
+ * @private
+ * The width of the component on the previous layout manager
+ * pass. This gets set in updateDisplayList() and used in measure() on
+ * the next layout pass. This is so our "guessed width" in measure()
+ * will be as accurate as possible since textDisplay is multiline and
+ * the textDisplay height is dependent on the width.
+ *
+ * In the constructor this is actually set based on the DPI.
+ */
+ mx_internal var oldUnscaledWidth:Number;
+
+ private var textDisplayGroup:Group;
+ private var _isIOS:Boolean;
+ private var invalidateCaretPosition:Boolean = true;
+ private var oldCaretBounds:Rectangle = new Rectangle(-1, -1, -1, -1);
+ private var lastTextHeight:Number;
+ private var lastTextWidth:Number;
+
+ private var isTextDisplayTall:Boolean = true;
+ private var growTextDisplay:Boolean = false;
+ private var shrinkTextDisplay:Boolean = false;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override protected function createChildren():void
+ {
+ if (!textDisplay)
+ {
+ // wrap StyleableTextField in UIComponent
+ textDisplay = StyleableTextField(createInFontContext(StyleableTextField));
+ textDisplay.styleName = this;
+ textDisplay.multiline = true;
+ textDisplay.editable = true;
+ textDisplay.lineBreak = getStyle("lineBreak");
+ textDisplay.useTightTextBounds = false;
+ textDisplay.scrollToRangeDelegate = scrollToRange;
+
+ // on iOS, resize the TextField and let the native control handle scrolling
+ _isIOS = Platform.isIOS;
+
+ if (_isIOS)
+ {
+ // hard-coded rightMargin for iOS native text control
+ // this value is independent of the paddingRight style
+ var rightMargin:Number = 0;
+ var isRetina:Boolean = false;
+ var isScaling160to320:Boolean = false;
+
+ // check for scaling
+ if ("runtimeDPI" in FlexGlobals.topLevelApplication)
+ {
+ var runtimeDPI:Number = FlexGlobals.topLevelApplication.runtimeDPI as Number;
+ isRetina = (runtimeDPI == DPIClassification.DPI_320);
+ isScaling160to320 = isRetina
+ && (applicationDPI == DPIClassification.DPI_160);
+ }
+
+ if (isRetina && !isScaling160to320)
+ rightMargin = IOS_RIGHT_MARGIN_320;
+ else if (isRetina && isScaling160to320)
+ rightMargin = IOS_RIGHT_MARGIN_160_SCALED_TO_320;
+ else
+ rightMargin = IOS_RIGHT_MARGIN_160;
+
+ textDisplay.rightMargin = rightMargin;
+ }
+ else
+ {
+ textDisplay.addEventListener(KeyboardEvent.KEY_DOWN, textDisplay_keyHandler);
+ }
+
+ textDisplay.addEventListener(Event.CHANGE, textDisplay_changeHandler);
+ textDisplay.addEventListener(FlexEvent.VALUE_COMMIT, textDisplay_changeHandler);
+ textDisplay.addEventListener(Event.SCROLL, textDisplay_scrollHandler);
+ // Use a lower priority so that the StyleableTextField event handler is called first.
+ // That handler cancels the event and we need to check for that case
+ textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING, textDisplay_softKeyboardActivatingHandler, false, EventPriority.DEFAULT_HANDLER);
+ textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, textDisplay_softKeyboardActivateHandler);
+ textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, textDisplay_softKeyboardDeactivateHandler);
+
+ textDisplay.left = getStyle("paddingLeft");
+ textDisplay.top = getStyle("paddingTop");
+ textDisplay.right = getStyle("paddingRight");
+ textDisplay.bottom = getStyle("paddingBottom");
+
+ // wrap StyleableTextComponent in Group for viewport
+ textDisplayGroup = new Group();
+ textDisplayGroup.clipAndEnableScrolling = true;
+ textDisplayGroup.addElement(textDisplay);
+ }
+
+ if (!scroller)
+ {
+ scroller = new Scroller();
+ scroller.minViewportInset = 0;
+ scroller.measuredSizeIncludesScrollBars = false;
+ scroller.ensureElementIsVisibleForSoftKeyboard = false;
+
+ addChild(scroller);
+ }
+
+ if (!scroller.viewport)
+ scroller.viewport = textDisplayGroup;
+
+ super.createChildren();
+ }
+
+ /**
+ * @private
+ * TextArea prompt supports wrapping and multiline
+ */
+ override protected function createPromptDisplay():StyleableTextField
+ {
+ var prompt:StyleableTextField = super.createPromptDisplay();
+ prompt.editable = true;
+ prompt.wordWrap = true;
+
+ return prompt;
+ }
+
+ /**
+ * @private
+ */
+ override protected function measure():void
+ {
+ super.measure();
+
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+ var paddingLeft:Number = getStyle("paddingLeft");
+ var paddingRight:Number = getStyle("paddingRight");
+
+ // TextDisplay always defaults to 440 pixels wide (the value is DPI dependent),
+ // and tall enough to show all text.
+ //
+ // You can set an explicit width and the height will adjust accordingly. The opposite
+ // is not true: setting an explicit height will not adjust the width accordingly.
+
+ measuredWidth = measuredDefaultWidth;
+
+ // now we need to measure textDisplay's height. Unfortunately, this is tricky and
+ // is dependent on textDisplay's width. Let's use the heuristic that our width
+ // is the same as our last width.
+ // We don't use layoutMeasuredWidth, because that value is just a constant and doesn't
+ // take into account the fact that the TextArea could have an explicitWidth or could
+ // be constrained by some value. However, we still default oldTextDisplayWidth to
+ // be layoutMeasuredWidth the first time through.
+ var textDisplayEstimatedWidth:Number = oldUnscaledWidth - paddingLeft - paddingRight;
+
+ // now we need to measure textDisplay's height. Unfortunately, this is tricky and
+ // is dependent on textDisplay's width.
+ // Use the old textDisplay width as an estimte for the new one.
+ // If we are wrong, we'll find out in updateDisplayList()
+ textDisplay.commitStyles();
+
+ // Clear min sizes first.
+ textDisplay.minWidth = textDisplay.minHeight = NaN;
+
+ // If lineBreak == explicit, always use NaN for estimated width
+ if (getStyle("lineBreak") == "explicit")
+ textDisplayEstimatedWidth = NaN;
+
+ setElementSize(textDisplay, textDisplayEstimatedWidth, NaN);
+
+ measuredHeight = getElementPreferredHeight(textDisplay) + paddingTop + paddingBottom;
+ }
+
+ /**
+ * @private
+ */
+ override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.layoutContents(unscaledWidth, unscaledHeight);
+
+ // position & size border
+ if (border)
+ {
+ setElementSize(border, unscaledWidth, unscaledHeight);
+ setElementPosition(border, 0, 0);
+ }
+
+ setElementSize(scroller, unscaledWidth, unscaledHeight);
+ setElementPosition(scroller, 0, 0);
+
+ // position & size the text
+ var explicitLineBreak:Boolean = getStyle("lineBreak") == "explicit";
+ var paddingLeft:Number = getStyle("paddingLeft");
+ var paddingRight:Number = getStyle("paddingRight");
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+
+ var unscaledTextWidth:Number = unscaledWidth - paddingLeft - paddingRight;
+ var unscaledTextHeight:Number = unscaledHeight - paddingTop - paddingBottom;
+ var textHeight:Number;
+ var textWidth:Number = explicitLineBreak ? textDisplay.measuredTextSize.x : unscaledTextWidth;
+
+ var lineIndex:int;
+ var topCharIndex:int;
+ var charBounds:Rectangle;
+
+ // grab old measured textDisplay height before resizing it
+ var oldPreferredTextHeight:Number = getElementPreferredHeight(textDisplay);
+
+ // set width first to measure height correctly
+ textDisplay.commitStyles();
+ textDisplay.setLayoutBoundsSize(textWidth, NaN);
+
+ // In iOS, when we go into editing mode, the runtime overlays a native
+ // text control over the textDisplay. In order to prevent the text
+ // from overflowing the component and to get scrolling support, the
+ // native text control must be the same size as the TextArea
+ if (_isIOS)
+ {
+ if (shrinkTextDisplay)
+ {
+ // Switching to edit mode. Convert from viewport scrolling to
+ // TextField scrolling
+ var vsp:Number = textDisplayGroup.verticalScrollPosition;
+
+ var lineMetrics:TextLineMetrics = textDisplay.getLineMetrics(0);
+ var lineHeight:Number = lineMetrics.ascent + lineMetrics.descent;
+
+ // TODO Figure out how to get the x offset. Right now is hard coded to 2
+ // At least half the line should be showing before we scroll to that line
+ // This makes the conversion from pixel to line based scrolling a little less jumpy
+ lineIndex = textDisplay.getLineIndexAtPoint(2, vsp + lineHeight / 2) + 1;
+ textDisplayGroup.verticalScrollPosition = 0;
+ isTextDisplayTall = false;
+ //trace("TAS.layoutContents shrinkText vsp",vsp,"lineIndex",lineIndex);
+ }
+
+ else if (growTextDisplay)
+ {
+ // Leaving edit mode. Convert from TextField scrolling to
+ // viewport scrolling
+ var scrollV:Number = textDisplay.scrollV;
+
+ // TODO (jszeto) investigate using lineMetrics.lineHeight * scrollV instead of getCharBoundaries
+ topCharIndex = textDisplay.getLineOffset(scrollV - 1);
+ charBounds = textDisplay.getCharBoundaries(topCharIndex);
+ // If the charBounds is null, just set vsp to 0
+ if (charBounds == null)
+ charBounds = new Rectangle(0, 0, 0, 0);
+ textDisplay.scrollV = 1;
+ isTextDisplayTall = true;
+ //trace("TAS.layoutContents growText scrollV",scrollV,"topCharIndex",topCharIndex,"charBounds",charBounds);
+ }
+ }
+
+ // TextField height should match its content or the TextArea bounds at minimum
+ // iOS special case to prevent Flex Scroller scrolling when editable
+ if (isTextDisplayTall)
+ textHeight = Math.max(textDisplay.measuredTextSize.y, unscaledTextHeight);
+ else
+ textHeight = unscaledTextHeight;
+
+ // FIXME (jasonsj): iOS native scroll bar appears even when explictHeight
+ // is not specified. Focus-in is jumpy.
+
+ if (promptDisplay)
+ {
+ promptDisplay.commitStyles();
+ setElementSize(promptDisplay, unscaledTextWidth, textHeight);
+ setElementPosition(promptDisplay, paddingLeft, paddingTop);
+
+ // no need to update textDisplay if promptDisplay is present
+ return;
+ }
+
+ // keep track of oldUnscaledWidth so we have a good guess as to the width
+ // of the textDisplay on the next measure() pass
+ oldUnscaledWidth = unscaledWidth;
+
+ // set the width of textDisplay to textWidth.
+ // set the height to oldTextHeight. If the height's actually wrong,
+ // we'll invalidateSize() and go through this layout pass again anyways
+ setElementSize(textDisplay, textWidth, textHeight);
+
+ // Set minWidth/Height on the text so the textDisplayGroup sizes accordingly
+ textDisplay.minWidth = textWidth;
+ textDisplay.minHeight = textHeight;
+ textDisplayGroup.invalidateDisplayList();
+
+ // grab new measured textDisplay height after the textDisplay has taken its final width
+ var newPreferredTextHeight:Number = getElementPreferredHeight(textDisplay);
+
+ // if the resize caused the textDisplay's height to change (because of
+ // text reflow), then we need to remeasure ourselves with our new width
+ if (oldPreferredTextHeight != newPreferredTextHeight)
+ invalidateSize();
+
+ if (_isIOS)
+ {
+ if (shrinkTextDisplay)
+ {
+ scroller.validateNow();
+ textDisplay.scrollV = lineIndex;
+ }
+ else if (growTextDisplay)
+ {
+ scroller.validateNow();
+ textDisplayGroup.verticalScrollPosition = charBounds.y;
+ }
+
+ shrinkTextDisplay = false;
+ growTextDisplay = false;
+ }
+
+ //trace("TAS.layoutContents tH",textHeight,"tW",textWidth,"invalidateCaret",invalidateCaretPosition);
+
+ // checking if text fits in TextArea
+ // does not apply to iOS due to native text editing and scrolling
+ // invalidateCaretPosition will never be true for iOS
+ if (invalidateCaretPosition && isTextDisplayTall)
+ {
+ // if the caret is outside the viewport, update the Group verticalScrollPosition
+ var charIndex:int = textDisplay.selectionBeginIndex;
+ var caretBounds:Rectangle = textDisplay.getCharBoundaries(charIndex);
+ lineIndex = textDisplay.getLineIndexOfChar(charIndex);
+
+ // getCharBoundaries() returns null for new lines
+ if (!caretBounds)
+ {
+ // temporarily insert a character at the caretIndex
+ textDisplay.replaceText(charIndex, charIndex, "W");
+ caretBounds = textDisplay.getCharBoundaries(charIndex);
+ lineIndex = textDisplay.getLineIndexOfChar(charIndex);
+ textDisplay.replaceText(charIndex, charIndex + 1, "");
+ }
+
+ if (caretBounds)
+ {
+ // Scroll the internal Scroller to ensure the caret is visible
+ if (textHeight > unscaledTextHeight)
+ {
+
+ if (charIndex == textDisplay.text.length)
+ {
+ // Make sure textDisplayGroup is validated, otherwise the
+ // verticalScrollPosition may be out of bounds, which will
+ // cause a bounce effect.
+ textDisplayGroup.validateNow();
+ textDisplayGroup.verticalScrollPosition = textHeight;
+ }
+ else
+ {
+ // caretTopPositon and caretBottomPosition are TextField-relative positions
+ // the TextField is inset by padding styles of the TextArea (via the VGroup)
+
+ // adjust top position to 0 when on the first line
+ // caretTopPosition will be negative when off stage
+ var caretTopPosition:Number = ((caretBounds.y) < 0 || (lineIndex == 0))
+ ? 0 : caretBounds.y;
+
+ // caretBottomPosition is the y coordinate of the bottom bounds of the caret
+ var caretBottomPosition:Number = caretBounds.y + caretBounds.height;
+
+ // note that verticalScrollPosition min/max do not account for padding
+ var vspTop:Number = textDisplayGroup.verticalScrollPosition;
+
+ // vspBottom should be the max visible Y in the TextField
+ // coordinate space.
+ // remove paddingBottom for some clearance between caret and border
+ var vspBottom:Number = vspTop + unscaledHeight - paddingTop - paddingBottom;
+
+ // is the caret in or below the padding and viewport?
+ if (caretBottomPosition > vspBottom)
+ {
+ // adjust caretBottomPosition to max scroll position when on the last line
+ if (lineIndex + 1 == textDisplay.numLines)
+ {
+ // use textHeight+paddings instead of textDisplayGroup.contentHeight
+ // Group has not been resized by this point
+ textDisplayGroup.verticalScrollPosition = (textHeight + paddingTop + paddingBottom) - textDisplayGroup.height;
+ }
+ else
+ {
+ // bottom edge of the caret moves just inside the bottom edge of the scroller
+ // add delta between caret and vspBottom
+ textDisplayGroup.verticalScrollPosition = vspTop + (caretBottomPosition - vspBottom);
+ }
+ }
+ // is the caret above the viewport?
+ else if (caretTopPosition < vspTop)
+ {
+ // top edge of the caret moves inside the top edge of the scroller
+ textDisplayGroup.verticalScrollPosition = caretTopPosition;
+ }
+ }
+
+ scroller.validateNow();
+ }
+
+ // Convert to local coordinates
+ // Dispatch an event for an ancestor Scroller
+ // It will scroll the TextArea so the caret is in view
+ convertBoundsToLocal(caretBounds);
+ if (oldCaretBounds == null || caretBounds.bottom != oldCaretBounds.bottom || caretBounds.top != oldCaretBounds.top)
+ {
+ //trace("TAS.layoutContents send caret CHANGE");
+ dispatchEvent(new CaretBoundsChangeEvent(CaretBoundsChangeEvent.CARET_BOUNDS_CHANGE,true,true,oldCaretBounds,caretBounds));
+ }
+
+ oldCaretBounds = caretBounds;
+ }
+
+ invalidateCaretPosition = false;
+ }
+
+ // Make sure final scroll position is valid
+ if (isTextDisplayTall)
+ snapTextScrollPosition();
+ }
+
+ override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.drawBackground(unscaledWidth, unscaledHeight);
+
+ var contentBackgroundColor:uint = getStyle("contentBackgroundColor");
+ var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha");
+ //change border color and thickness when in focus
+ var borderColor:uint = isFocused ? getStyle("focusColor") : getStyle("borderColor");
+ var selectWidth:uint = isFocused ? layoutBorderSize + 1 : layoutBorderSize;
+ if (isNaN(contentBackgroundAlpha))
+ {
+ contentBackgroundAlpha = 1;
+ }
+ if (getStyle("contentBackgroundBorder") == "flat")
+ {
+ var halfGap:int = flatheight * 2;
+ //background
+ graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+ graphics.drawRect(0, 0, unscaledWidth, unscaledHeight - flatheight);
+ graphics.endFill();
+ //begin flat border
+ graphics.beginFill(borderColor, 1);
+ //left half border
+ graphics.drawRect(0, unscaledHeight - halfGap, selectWidth, flatheight );
+ //bottom border
+ graphics.drawRect(0, unscaledHeight - flatheight, unscaledWidth, selectWidth);
+ //right border
+ graphics.drawRect(unscaledWidth - selectWidth, unscaledHeight - halfGap, selectWidth, flatheight);
+ graphics.endFill();
+ }
+ else if (getStyle("contentBackgroundBorder") == "rectangle")
+ {
+ var borderWidth:uint = layoutBorderSize * 2;
+ //rectangle border and background
+ graphics.lineStyle(selectWidth, borderColor, 1);
+ graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+ graphics.drawRect(layoutBorderSize, layoutBorderSize, unscaledWidth - borderWidth, unscaledHeight - borderWidth);
+ graphics.endFill();
+ }
+ }
+
+ /**
+ * @private
+ * Make sure the scroll positions are valid, and adjust if needed.
+ */
+ private function snapTextScrollPosition():void
+ {
+ var maxHsp:Number = textDisplayGroup.contentWidth > textDisplayGroup.width ?
+ textDisplayGroup.contentWidth-textDisplayGroup.width : 0;
+ textDisplayGroup.horizontalScrollPosition =
+ Math.min(Math.max(0,textDisplayGroup.horizontalScrollPosition),maxHsp);
+
+ var maxVsp:Number = textDisplayGroup.contentHeight > textDisplayGroup.height ?
+ textDisplayGroup.contentHeight-textDisplayGroup.height : 0;
+
+ textDisplayGroup.verticalScrollPosition =
+ Math.min(Math.max(0,textDisplayGroup.verticalScrollPosition),maxVsp);
+ }
+
+ /**
+ * @private
+ * Get the bounds of the caret
+ */
+ private function getCaretBounds():Rectangle
+ {
+ var charIndex:int = textDisplay.selectionBeginIndex;
+ var caretBounds:Rectangle = textDisplay.getCharBoundaries(charIndex);
+
+ if (!caretBounds)
+ {
+ textDisplay.replaceText(charIndex, charIndex, "W");
+ caretBounds = textDisplay.getCharBoundaries(charIndex);
+ textDisplay.replaceText(charIndex, charIndex + 1, "");
+ }
+
+ return caretBounds;
+ }
+
+ /**
+ * @private
+ * Convert bounds from textDisplay to local coordinates
+ */
+ private function convertBoundsToLocal(bounds:Rectangle):void
+ {
+ if (bounds)
+ {
+ var position:Point = new Point(bounds.x, bounds.y);
+ position = textDisplay.localToGlobal(position);
+ position = globalToLocal(position);
+ bounds.x = position.x;
+ bounds.y = position.y;
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function scrollToRange(anchorPosition:int, activePosition:int):void
+ {
+ var pos:int = Math.min(anchorPosition, activePosition);
+ var bounds:Rectangle = textDisplay.getCharBoundaries(pos);
+ var vsp:int = textDisplayGroup.verticalScrollPosition;
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+
+ if (bounds && (bounds.top < vsp - paddingTop ||
+ bounds.bottom > vsp + unscaledHeight - paddingTop - paddingBottom))
+ {
+ textDisplayGroup.verticalScrollPosition = bounds.top + paddingTop;
+ snapTextScrollPosition();
+ }
+ }
+
+ /**
+ * @private
+ * Handle size and caret position changes that occur when text content
+ * changes.
+ */
+ private function textDisplay_changeHandler(event:Event):void
+ {
+ var tH:Number = textDisplay.textHeight;
+ var tW:Number = textDisplay.textWidth;
+ var explicitLineBreak:Boolean = getStyle("lineBreak") == "explicit";
+
+ // Size and caret position have changed if the text height is different or
+ // the text width is different and we aren't word wrapping
+ if (tH != lastTextHeight || ( explicitLineBreak && tW != lastTextWidth))
+ {
+ invalidateSize();
+ invalidateDisplayList();
+ invalidateCaretPosition = true;
+ }
+
+ lastTextHeight = tH;
+ lastTextWidth = tW;
+ }
+
+ /**
+ * @private
+ * Cancels any native scroll that the Flash Player attempts to do
+ */
+ private function textDisplay_scrollHandler(event:Event):void
+ {
+ // if iOS, let the OS handle scrolling
+ if (_isIOS)
+ return;
+
+ // If not IOS, we will handle scrolling, so don't let the native
+ // flash textfield scroll at all.
+ if (textDisplay.scrollV > 1)
+ textDisplay.scrollV = 1;
+ if (textDisplay.scrollH > 0)
+ textDisplay.scrollH = 0;
+ }
+
+ /**
+ * @private
+ * Adjust viewport when using key navigation
+ */
+ private function textDisplay_keyHandler(event:KeyboardEvent):void
+ {
+ // update scroll position when caret changes
+ if ((event.keyCode == Keyboard.UP
+ || event.keyCode == Keyboard.DOWN
+ || event.keyCode == Keyboard.LEFT
+ || event.keyCode == Keyboard.RIGHT))
+ {
+ invalidateDisplayList();
+ invalidateCaretPosition = true;
+ }
+
+ // Change event is not always sent when delete key is pressed, so
+ // invalidate the size here
+ if (event.keyCode == Keyboard.BACKSPACE)
+ {
+ invalidateSize();
+ }
+ }
+
+ /**
+ * @private
+ * When entering edit mode on iOS, we need to shrink the textDisplay to
+ * the size of the TextArea
+ */
+ private function textDisplay_softKeyboardActivatingHandler(event:SoftKeyboardEvent):void
+ {
+ if (event.isDefaultPrevented())
+ return;
+
+ if (_isIOS && isTextDisplayTall)
+ {
+ //trace("TAS.SK ACTIVATING targ",event.target);
+ shrinkTextDisplay = true;
+ invalidateDisplayList();
+ validateNow();
+ }
+ }
+
+ /**
+ * @private
+ * Send a caret change event to an ancestor Scroller
+ */
+ private function textDisplay_softKeyboardActivateHandler(event:SoftKeyboardEvent):void
+ {
+ var keyboardRect:Rectangle = stage.softKeyboardRect;
+
+ if (keyboardRect.width > 0 && keyboardRect.height > 0)
+ {
+ var newCaretBounds:Rectangle = getCaretBounds();
+ convertBoundsToLocal(newCaretBounds);
+
+ if (oldCaretBounds != newCaretBounds)
+ {
+ //trace("TAS.SK ACTIVATE",keyboardRect,"dispatch caret CHANGE","newCaretBounds",newCaretBounds);
+ dispatchEvent(new CaretBoundsChangeEvent(CaretBoundsChangeEvent.CARET_BOUNDS_CHANGE,true,true,oldCaretBounds,newCaretBounds));
+ oldCaretBounds = newCaretBounds;
+ }
+ }
+ }
+
+ /**
+ * @private
+ * On iOS, when leaving edit mode, we need to restore the textDisplay to the
+ * height of the text.
+ */
+ private function textDisplay_softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void
+ {
+ if (_isIOS && !isTextDisplayTall)
+ {
+ growTextDisplay = true;
+ invalidateDisplayList();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function resizeHandler(event:Event):void
+ {
+ // Resizing needs to tickle the TextArea's internal auto-scroll logic
+ invalidateCaretPosition = true;
+ invalidateDisplayList();
+ }
+
+ /**
+ * @private
+ */
+ override public function styleChanged(styleProp:String):void
+ {
+ super.styleChanged(styleProp);
+
+ // propogate styleChanged explicitly to textDisplay
+ if (textDisplay)
+ textDisplay.styleChanged(styleProp);
+
+ // Check for padding style changes
+ if (!styleProp || styleProp == "styleName" || styleProp.indexOf("padding") >= 0)
+ {
+ if (textDisplay)
+ {
+ textDisplay.left = getStyle("paddingLeft");
+ textDisplay.top = getStyle("paddingTop");
+ textDisplay.right = getStyle("paddingRight");
+ textDisplay.bottom = getStyle("paddingBottom");
+ }
+ }
+ }
+
+ private function focusChangeHandler(event:FocusEvent):void
+ {
+ isFocused = event.type == FocusEvent.FOCUS_IN;
+ invalidateDisplayList();
+ }
+
+}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as
new file mode 100644
index 0000000..7488e1f
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as
@@ -0,0 +1,375 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.events.Event;
+ import flash.events.FocusEvent;
+ import flash.events.SoftKeyboardEvent;
+
+ import mx.core.DPIClassification;
+ import mx.core.EventPriority;
+ import mx.core.mx_internal;
+ import mx.events.FlexEvent;
+ import mx.utils.Platform;
+
+ import spark.components.TextInput;
+ import spark.components.supportClasses.StyleableTextField;
+ import spark.skins.android4.supportClasses.TextSkinBase;
+
+ use namespace mx_internal;
+
+ /**
+ * ActionScript-based skin for TextInput controls in mobile applications.
+ *
+ * @see spark.components.TextInput
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public class TextInputSkin extends TextSkinBase
+ {
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function TextInputSkin()
+ {
+ super();
+
+ // on iOS, make adjustments for native text rendering
+ _isIOS = Platform.isIOS;
+
+ switch (applicationDPI)
+ {
+ case DPIClassification.DPI_640:
+ {
+ measuredDefaultWidth = 1200;
+ measuredDefaultHeight = 132;
+ layoutBorderSize = 4;
+ flatheight = 9;
+ break;
+ }
+ case DPIClassification.DPI_480:
+ {
+
+ measuredDefaultWidth = 880;
+ measuredDefaultHeight = 100;
+ layoutBorderSize = 3;
+ flatheight = 7;
+ break;
+ }
+ case DPIClassification.DPI_320:
+ {
+ measuredDefaultWidth = 600;
+ measuredDefaultHeight = 66;
+ layoutBorderSize = 2;
+ flatheight = 6;
+ break;
+ }
+ case DPIClassification.DPI_240:
+ {
+ measuredDefaultWidth = 440;
+ measuredDefaultHeight = 50;
+ layoutBorderSize = 2;
+ flatheight = 5;
+ break;
+ }
+ case DPIClassification.DPI_120:
+ {
+ measuredDefaultWidth = 220;
+ measuredDefaultHeight = 25;
+ layoutBorderSize = 1;
+ flatheight = 2;
+ break;
+ }
+ default:
+ {
+ measuredDefaultWidth = 300;
+ measuredDefaultHeight = 33;
+ layoutBorderSize = 1;
+ flatheight = 3;
+ break;
+ }
+ }
+ addEventListener(FocusEvent.FOCUS_IN, focusChangeHandler);
+ addEventListener(FocusEvent.FOCUS_OUT, focusChangeHandler);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ protected var isFocused:Boolean = false;
+
+ protected var flatheight:uint;
+
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ */
+ public var hostComponent:TextInput; // SkinnableComponent will populate
+
+ /**
+ * @private
+ */
+ private var _isIOS:Boolean;
+
+ /**
+ * @private
+ */
+ private var _isEditing:Boolean;
+
+ /**
+ * @private
+ */
+ override protected function createChildren():void
+ {
+ super.createChildren();
+
+ textDisplay.addEventListener("editableChanged", editableChangedHandler);
+ textDisplay.addEventListener(FlexEvent.VALUE_COMMIT, valueCommitHandler);
+
+ // remove hit area improvements on iOS when editing
+ if (_isIOS)
+ {
+ textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING, textDisplay_softKeyboardActivatingHandler, false, EventPriority.DEFAULT_HANDLER);
+ textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, textDisplay_softKeyboardDeactivateHandler);
+ }
+ }
+
+ /**
+ * @private
+ */
+ override protected function measure():void
+ {
+ super.measure();
+
+ var paddingLeft:Number = getStyle("paddingLeft");
+ var paddingRight:Number = getStyle("paddingRight");
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+ var textHeight:Number = getStyle("fontSize") as Number;
+
+ if (textDisplay)
+ {
+ // temporarily change text for measurement
+ var oldText:String = textDisplay.text;
+
+ // commit styles so we can get a valid textHeight
+ textDisplay.text = "Wj";
+ textDisplay.commitStyles();
+
+ textHeight = textDisplay.measuredTextSize.y;
+ textDisplay.text = oldText;
+ }
+
+ // width is based on maxChars (if set)
+ if (hostComponent && hostComponent.maxChars)
+ {
+ // Grab the fontSize and subtract 2 as the pixel value for each character.
+ // This is just an approximation, but it appears to be a reasonable one
+ // for most input and most font.
+ var characterWidth:int = Math.max(1, (getStyle("fontSize") - 2));
+ measuredWidth = (characterWidth * hostComponent.maxChars) +
+ paddingLeft + paddingRight + StyleableTextField.TEXT_WIDTH_PADDING;
+ }
+
+ measuredHeight = paddingTop + textHeight + paddingBottom;
+ }
+
+ /**
+ * @private
+ */
+ override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.layoutContents(unscaledWidth, unscaledHeight);
+
+ // position & size border
+ if (border)
+ {
+ setElementSize(border, unscaledWidth, unscaledHeight);
+ setElementPosition(border, 0, 0);
+ }
+
+ // position & size the text
+ var paddingLeft:Number = getStyle("paddingLeft");
+ var paddingRight:Number = getStyle("paddingRight");
+ var paddingTop:Number = getStyle("paddingTop");
+ var paddingBottom:Number = getStyle("paddingBottom");
+
+ var unscaledTextWidth:Number = unscaledWidth - paddingLeft - paddingRight;
+ var unscaledTextHeight:Number = unscaledHeight - paddingTop - paddingBottom;
+
+ // default vertical positioning is centered
+ var textHeight:Number = getElementPreferredHeight(textDisplay);
+ var textY:Number = Math.round(0.5 * (unscaledTextHeight - textHeight)) + paddingTop;
+
+ // On iOS the TextField top and bottom edges are bounded by the padding.
+ // On all other platforms, the height of the textDisplay is
+ // textHeight + paddingBottom to increase hitArea on bottom.
+ // Note: We don't move the Y position upwards because TextField
+ // has way to set vertical positioning.
+ // Note: iOS is a special case due to the clear button provided by the
+ // native text control used while editing.
+ var adjustedTextHeight:Number = (_isIOS && _isEditing) ? textHeight : textHeight + paddingBottom;
+
+ if (textDisplay)
+ {
+ // We're going to do a few tricks to try to increase the size of our hitArea to make it
+ // easier for users to select text or put the caret in a certain spot. To do that,
+ // rather than set textDisplay.x=paddingLeft, we are going to set
+ // textDisplay.leftMargin = paddingLeft. In addition, we're going to size the height
+ // of the textDisplay larger than just the size of the text inside to increase the hitArea
+ // on the bottom. We'll also assign textDisplay.rightMargin = paddingRight to increase the
+ // the hitArea on the right. Unfortunately, there's no way to increase the hitArea on the top
+ // just yet, but these three tricks definitely help out with regards to user experience.
+ // See http://bugs.adobe.com/jira/browse/SDK-29406 and http://bugs.adobe.com/jira/browse/SDK-29405
+
+ // set leftMargin, rightMargin to increase the hitArea. Need to set it before calling commitStyles().
+ var marginChanged:Boolean = ((textDisplay.leftMargin != paddingLeft) ||
+ (textDisplay.rightMargin != paddingRight));
+
+ textDisplay.leftMargin = paddingLeft;
+ textDisplay.rightMargin = paddingRight;
+
+ // need to force a styleChanged() after setting leftMargin, rightMargin if they
+ // changed values. Then we can validate the styles through commitStyles()
+ if (marginChanged)
+ textDisplay.styleChanged(null);
+ textDisplay.commitStyles();
+
+ setElementSize(textDisplay, unscaledWidth, adjustedTextHeight);
+
+ // set x=0 since we're using textDisplay.leftMargin = paddingLeft
+ setElementPosition(textDisplay, 0, textY);
+ }
+
+ if (promptDisplay)
+ {
+ promptDisplay.commitStyles();
+ setElementSize(promptDisplay, unscaledTextWidth, adjustedTextHeight);
+ setElementPosition(promptDisplay, paddingLeft, textY);
+ }
+ }
+
+ override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.drawBackground(unscaledWidth, unscaledHeight);
+
+ var contentBackgroundColor:uint = getStyle("contentBackgroundColor");
+ var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha");
+ //change border color and thickness when in focus
+ var borderColor:uint = isFocused ? getStyle("focusColor") : getStyle("borderColor");
+ var selectWidth:uint = isFocused ? layoutBorderSize + 1 : layoutBorderSize;
+ if (isNaN(contentBackgroundAlpha))
+ {
+ contentBackgroundAlpha = 1;
+ }
+ if (getStyle("contentBackgroundBorder") == "flat")
+ {
+ var halfGap:int = flatheight * 2;
+ //background
+ graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+ graphics.drawRect(0, 0, unscaledWidth, unscaledHeight - flatheight);
+ graphics.endFill();
+ //begin flat border
+ graphics.beginFill(borderColor, 1);
+ //left half border
+ graphics.drawRect(0, unscaledHeight - halfGap, selectWidth, flatheight );
+ //bottom border
+ graphics.drawRect(0, unscaledHeight - flatheight, unscaledWidth, selectWidth);
+ //right border
+ graphics.drawRect(unscaledWidth - selectWidth, unscaledHeight - halfGap, selectWidth, flatheight);
+ graphics.endFill();
+ }
+ else if (getStyle("contentBackgroundBorder") == "rectangle")
+ {
+ var borderWidth:uint = layoutBorderSize * 2;
+ //rectangle border and background
+ graphics.lineStyle(selectWidth, borderColor, 1);
+ graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+ graphics.drawRect(layoutBorderSize, layoutBorderSize, unscaledWidth - borderWidth, unscaledHeight - borderWidth);
+ graphics.endFill();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function editableChangedHandler(event:Event):void
+ {
+ invalidateDisplayList();
+ }
+
+ /**
+ * @private
+ * The text changed in some way.
+ *
+ * Dynamic fields (ie !editable) with no text measure with width=0 and height=0.
+ * If the text changed, need to remeasure the text to get the correct height so it
+ * will be laid out correctly.
+ */
+ private function valueCommitHandler(event:Event):void
+ {
+ if (textDisplay && !textDisplay.editable)
+ invalidateDisplayList();
+ }
+
+ /**
+ * @private
+ */
+ private function textDisplay_softKeyboardActivatingHandler(event:SoftKeyboardEvent):void
+ {
+ if (event.isDefaultPrevented())
+ return;
+
+ _isEditing = true;
+ invalidateDisplayList();
+ }
+
+ /**
+ * @private
+ */
+ private function textDisplay_softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void
+ {
+ _isEditing = false;
+ invalidateDisplayList();
+ }
+
+ private function focusChangeHandler(event:FocusEvent):void
+ {
+ isFocused = event.type == FocusEvent.FOCUS_IN;
+ invalidateDisplayList();
+ }
+ }
+}
\ No newline at end of file