| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 flashx.textLayout.container |
| { |
| import flash.display.BlendMode; |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.display.InteractiveObject; |
| import flash.display.Shape; |
| import flash.display.Sprite; |
| import flash.events.ContextMenuEvent; |
| import flash.events.Event; |
| import flash.events.EventDispatcher; |
| import flash.events.FocusEvent; |
| import flash.events.IMEEvent; |
| import flash.events.KeyboardEvent; |
| import flash.events.MouseEvent; |
| import flash.events.TextEvent; |
| import flash.geom.Rectangle; |
| import flash.text.engine.TextBlock; |
| import flash.text.engine.TextLine; |
| import flash.text.engine.TextLineValidity; |
| import flash.ui.ContextMenu; |
| import flash.ui.ContextMenuClipboardItems; |
| import flash.ui.Mouse; |
| import flash.ui.MouseCursor; |
| import flash.utils.Dictionary; |
| |
| import flashx.textLayout.compose.BaseCompose; |
| import flashx.textLayout.compose.ISWFContext; |
| import flashx.textLayout.compose.SimpleCompose; |
| import flashx.textLayout.compose.StandardFlowComposer; |
| import flashx.textLayout.compose.TextFlowLine; |
| import flashx.textLayout.compose.TextLineRecycler; |
| import flashx.textLayout.debug.Debugging; |
| import flashx.textLayout.debug.assert; |
| import flashx.textLayout.edit.EditManager; |
| import flashx.textLayout.edit.EditingMode; |
| import flashx.textLayout.edit.IEditManager; |
| import flashx.textLayout.edit.IInteractionEventHandler; |
| import flashx.textLayout.edit.ISelectionManager; |
| import flashx.textLayout.edit.SelectionFormat; |
| import flashx.textLayout.edit.SelectionManager; |
| import flashx.textLayout.edit.SelectionState; |
| import flashx.textLayout.elements.Configuration; |
| import flashx.textLayout.elements.FlowElement; |
| import flashx.textLayout.elements.FlowLeafElement; |
| import flashx.textLayout.elements.IConfiguration; |
| import flashx.textLayout.elements.ParagraphElement; |
| import flashx.textLayout.elements.SpanElement; |
| import flashx.textLayout.elements.TextFlow; |
| import flashx.textLayout.events.CompositionCompleteEvent; |
| import flashx.textLayout.events.DamageEvent; |
| import flashx.textLayout.events.FlowOperationEvent; |
| import flashx.textLayout.events.SelectionEvent; |
| import flashx.textLayout.events.StatusChangeEvent; |
| import flashx.textLayout.events.TextLayoutEvent; |
| import flashx.textLayout.events.UpdateCompleteEvent; |
| import flashx.textLayout.factory.StringTextLineFactory; |
| import flashx.textLayout.factory.TextFlowTextLineFactory; |
| import flashx.textLayout.factory.TextLineFactoryBase; |
| import flashx.textLayout.formats.BlockProgression; |
| import flashx.textLayout.formats.FormatValue; |
| import flashx.textLayout.formats.ITextLayoutFormat; |
| import flashx.textLayout.formats.TextLayoutFormat; |
| import flashx.textLayout.property.Property; |
| import flashx.textLayout.tlf_internal; |
| import flashx.undo.IUndoManager; |
| import flashx.undo.UndoManager; |
| |
| use namespace tlf_internal; |
| /** |
| * |
| * @eventType flashx.textLayout.events.FlowOperationEvent.FLOW_OPERATION_BEGIN |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="flowOperationBegin", type="flashx.textLayout.events.FlowOperationEvent")] |
| |
| /** |
| * |
| * @eventType flashx.textLayout.events.FlowOperationEvent.FLOW_OPERATION_END |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="flowOperationEnd", type="flashx.textLayout.events.FlowOperationEvent")] |
| |
| |
| /** |
| * |
| * @eventType flashx.textLayout.events.FlowOperationEvent.FLOW_OPERATION_COMPLETE |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="flowOperationComplete", type="flashx.textLayout.events.FlowOperationEvent")] |
| |
| /** Dispatched whenever the selection is changed. Primarily used to update selection-dependent user interface. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="selectionChange", type="flashx.textLayout.events.SelectionEvent")] |
| |
| /** Dispatched after every recompose. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="compositionComplete", type="flashx.textLayout.events.CompositionCompleteEvent")] |
| |
| /** Dispatched when the mouse is pressed down over any link. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="mouseDown", type="flashx.textLayout.events.FlowElementMouseEvent")] |
| |
| /** Dispatched when the mouse is released over any link. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="mouseUp", type="flashx.textLayout.events.FlowElementMouseEvent")] |
| |
| /** Dispatched when the mouse passes over any link. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="mouseMove", type="flashx.textLayout.events.FlowElementMouseEvent")] |
| |
| /** Dispatched when the mouse first enters any link. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="rollOver", type="flashx.textLayout.events.FlowElementMouseEvent")] |
| |
| /** Dispatched when the mouse goes out of any link. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="rollOut", type="flashx.textLayout.events.FlowElementMouseEvent")] |
| |
| /** Dispatched when any link is clicked. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="click", type="flashx.textLayout.events.FlowElementMouseEvent")] |
| |
| /** Dispatched when a InlineGraphicElement is resized due to having width or height as auto or percent |
| * and the graphic has finished loading. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="inlineGraphicStatusChanged", type="flashx.textLayout.events.StatusChangeEvent")] |
| |
| /** Dispatched by a TextFlow object after text is scrolled within a controller container. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="scroll", type="flashx.textLayout.events.TextLayoutEvent")] |
| |
| /** Dispatched by a TextFlow object each time it is damaged |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="damage", type="flashx.textLayout.events.DamageEvent")] |
| |
| /** Dispatched by a TextFlow object each time a container has had new DisplayObjects added or updated as a result of composition. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| [Event(name="updateComplete", type="flashx.textLayout.events.UpdateCompleteEvent")] |
| |
| [Exclude(name="getBaseSWFContext",kind="method")] |
| |
| [Exclude(name="callInContext",kind="method")] |
| /** Manages text in a container. Assumes that it manages all children of the container. |
| * Consider using TextContainerManager for better performance in cases where there is a |
| * one container per TextFlow, and the TextFlow is not the main focus, is static text, or |
| * is infrequently selected. Good for text in form fields, for example. |
| * |
| * @includeExample examples\TextContainerManager.as -noswf |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see ContainerController |
| */ |
| public class TextContainerManager extends EventDispatcher implements ISWFContext, IInteractionEventHandler, ISandboxSupport |
| { |
| // all events that are listened for need to be in this list. |
| static private const eventList:Array = [ |
| FlowOperationEvent.FLOW_OPERATION_BEGIN, |
| FlowOperationEvent.FLOW_OPERATION_END, |
| FlowOperationEvent.FLOW_OPERATION_COMPLETE, |
| SelectionEvent.SELECTION_CHANGE, |
| CompositionCompleteEvent.COMPOSITION_COMPLETE, |
| MouseEvent.CLICK, //from FlowElementMouseEvent |
| MouseEvent.MOUSE_DOWN, //from FlowElementMouseEvent |
| MouseEvent.MOUSE_OUT, //from FlowElementMouseEvent |
| MouseEvent.MOUSE_UP, //from FlowElementMouseEvent |
| MouseEvent.MOUSE_OVER, //from FlowElementMouseEvent |
| MouseEvent.MOUSE_OUT, //from FlowElementMouseEvent |
| StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGE, |
| TextLayoutEvent.SCROLL, |
| DamageEvent.DAMAGE, |
| UpdateCompleteEvent.UPDATE_COMPLETE |
| ]; |
| |
| /** Configuration to be used by the TextContainerManager. This can only be set once and before the inputmanager is used. */ |
| static private var _defaultConfiguration:IConfiguration = null; |
| |
| /** The default configuration for this TextContainerManager. Column and padding attributes |
| * are set to <code>FormatValue.INHERIT</code>. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flashx.textLayout.elements.IConfiguration IConfiguration |
| * @see flashx.textLayout.formats.FormatValue#INHERIT FormatValue.INHERIT |
| */ |
| static public function get defaultConfiguration():IConfiguration |
| { |
| if (_defaultConfiguration == null) |
| _defaultConfiguration = customizeConfiguration(null); |
| return _defaultConfiguration; |
| } |
| |
| /** @private Make a configuration acceptable to the TCM */ |
| static tlf_internal function customizeConfiguration(config:IConfiguration):IConfiguration |
| { |
| var newConfig:Configuration; |
| if (config) |
| { |
| if (config.flowComposerClass == TextLineFactoryBase.getDefaultFlowComposerClass()) |
| return config; |
| newConfig = (config as Configuration).clone(); |
| } |
| else |
| newConfig = new Configuration(); |
| newConfig.flowComposerClass = TextLineFactoryBase.getDefaultFlowComposerClass(); |
| return newConfig; |
| } |
| |
| static private var _inputManagerTextFlowFactory:TCMTextFlowTextLineFactory; |
| static private function inputManagerTextFlowFactory():TCMTextFlowTextLineFactory |
| { |
| if (!_inputManagerTextFlowFactory) |
| _inputManagerTextFlowFactory = new TCMTextFlowTextLineFactory(); |
| return _inputManagerTextFlowFactory; |
| } |
| |
| // dictionary of stringfactories so that they can share a configuration |
| static private var stringFactoryDictionary:Dictionary; |
| static private function inputManagerStringFactory(config:IConfiguration):StringTextLineFactory |
| { |
| if (!stringFactoryDictionary) |
| stringFactoryDictionary = new Dictionary(true); |
| var factory:StringTextLineFactory = stringFactoryDictionary[config]; |
| if (factory == null) |
| { |
| factory = new StringTextLineFactory(config); |
| stringFactoryDictionary[config] = factory; |
| } |
| return factory; |
| } |
| |
| /** @private Method to release all references to factories so they can be gc'ed, for example when Flex unloads a module. */ |
| static tlf_internal function releaseReferences():void |
| { |
| stringFactoryDictionary = null; |
| _inputManagerTextFlowFactory = null; |
| } |
| |
| /** Shared definition of the scrollPolicy property. @private */ |
| static tlf_internal const editingModePropertyDefinition:Property = Property.NewEnumStringProperty("editingMode", EditingMode.READ_WRITE, false, null, |
| EditingMode.READ_WRITE, EditingMode.READ_ONLY, EditingMode.READ_SELECT); |
| |
| private var _container:Sprite; |
| private var _compositionWidth:Number; |
| private var _compositionHeight:Number; |
| |
| private var _text:String; |
| private var _textDamaged:Boolean; // indicates the _text property needs updating when sourceState is SOURCE_TEXTFLOW |
| private var _lastSeparator:String; |
| |
| private var _hostFormat:ITextLayoutFormat; |
| // textFlow format to be used by a string factory - combination of config.initialTextLayoutFormat and hostFormat |
| private var _stringFactoryTextFlowFormat:ITextLayoutFormat; |
| |
| private var _contentTop:Number; |
| private var _contentLeft:Number; |
| private var _contentHeight:Number; |
| private var _contentWidth:Number; |
| |
| private var _horizontalScrollPolicy:String; |
| private var _verticalScrollPolicy:String; |
| |
| private var _swfContext:ISWFContext; |
| private var _config:IConfiguration; |
| |
| //Decide whether to preserve the selection state when calling setText() [bug #2931406 from Flex SDK] |
| private var _preserveSelectionOnSetText:Boolean = false; |
| |
| /** @private */ |
| static tlf_internal const SOURCE_STRING:int = 0; |
| /** @private */ |
| static tlf_internal const SOURCE_TEXTFLOW:int = 1; |
| |
| /** @private */ |
| static tlf_internal const COMPOSE_FACTORY:int = 0; |
| /** @private */ |
| static tlf_internal const COMPOSE_COMPOSER:int = 1; |
| |
| /** @private */ |
| static tlf_internal const HANDLERS_NOTADDED:int = 0; |
| /** @private */ |
| static tlf_internal const HANDLERS_NONE:int = 1; |
| /** @private */ |
| static tlf_internal const HANDLERS_CREATION:int = 2; |
| /** @private */ |
| static tlf_internal const HANDLERS_ACTIVE:int = 3; |
| /** @private */ |
| static tlf_internal const HANDLERS_MOUSEWHEEL:int = 4; |
| |
| private var _sourceState:int; |
| private var _composeState:int; |
| private var _handlersState:int; |
| // track hasFocus. Depending on various factors focus and mouseDown can occur in different order |
| private var _hasFocus:Boolean; |
| private var _editingMode:String; |
| private var _ibeamCursorSet:Boolean; |
| private var _interactionCount:int; |
| |
| /** @private */ |
| tlf_internal function get sourceState():int |
| { return _sourceState; } |
| /** @private */ |
| tlf_internal function get composeState():int |
| { return _composeState; } |
| /** @private */ |
| tlf_internal function get handlersState():int |
| { return _handlersState; } |
| |
| // Tracks damage when sourceState is SOURCE_STRING. TODO - Might be worthwhile to always set and clear this |
| private var _damaged:Boolean; |
| private var _textFlow:TextFlow; |
| private var _needsRedraw:Boolean; |
| |
| /** Constructor function - creates a TextContainerManager instance. |
| * |
| * For best results: |
| * <ol> |
| * <li>Start with TextContainerManager.defaultConfiguration and modify it</li> |
| * <li>Share the same Configuration among many InputManagers</li> |
| * </ol> |
| * |
| * @param container The DisplayObjectContainer in which to manage the text lines. |
| * @param config - The IConfiguration instance to use with this TextContainerManager instance. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function TextContainerManager(container:Sprite,configuration:IConfiguration = null) |
| { |
| _container = container; |
| _compositionWidth = 100; |
| _compositionHeight = 100; |
| |
| _config = configuration ? customizeConfiguration(configuration) : defaultConfiguration; |
| _config = (_config as Configuration).getImmutableClone(); |
| |
| _horizontalScrollPolicy = _verticalScrollPolicy = String(ScrollPolicy.scrollPolicyPropertyDefinition.defaultValue); |
| |
| _damaged = true; |
| _needsRedraw = false; |
| _text = ""; |
| _textDamaged = false; |
| |
| _sourceState = SOURCE_STRING; |
| _composeState = COMPOSE_FACTORY; |
| _handlersState = HANDLERS_NOTADDED; |
| _hasFocus = false; |
| |
| _editingMode = editingModePropertyDefinition.defaultValue as String; |
| _ibeamCursorSet = false; |
| _interactionCount = 0; |
| |
| if (_container is InteractiveObject) |
| { |
| _container.doubleClickEnabled = true; |
| // so the textlines can be swapped on the first click and a double click still works |
| _container.mouseChildren = false; |
| _container.focusRect = false; |
| } |
| } |
| |
| /** Returns the container (DisplayObjectContainer) that holds the text that this TextContainerManager manages. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see ContainerController#container |
| */ |
| |
| public function get container():Sprite |
| { return _container; } |
| |
| /** Returns <code>true</code> if the content needs composing. |
| * |
| * @return <code>true</code> if the content needs composing; <code>false</code> otherwise. |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function isDamaged():Boolean |
| { return _composeState == COMPOSE_FACTORY ? _damaged : _textFlow.flowComposer.isDamaged(_textFlow.textLength); } |
| |
| /** Editing mode of this TextContainerManager. Modes are reading only, reading and selection permitted, |
| * and editing (reading, selection, and writing) permitted. Use the constant values of the EditingMode |
| * class to set this property. |
| * <p>Default value is READ_WRITE.</p> |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flashx.textLayout.edit.EditingMode EditingMode |
| */ |
| public function get editingMode():String |
| { return _editingMode; } |
| public function set editingMode(val:String):void |
| { |
| var newMode:String = editingModePropertyDefinition.setHelper(_editingMode, val) as String; |
| |
| if (newMode != _editingMode) |
| { |
| if (composeState == COMPOSE_COMPOSER) |
| { |
| _editingMode = newMode; |
| invalidateInteractionManager(); |
| } |
| else |
| { |
| removeActivationEventListeners(); |
| _editingMode = newMode; |
| // there is no way to turn it on here if going from READ_ONLY to editable and mouse is over the inputmanager field |
| if (_editingMode == EditingMode.READ_ONLY) |
| removeIBeamCursor(); |
| addActivationEventListeners(); |
| } |
| } |
| } |
| |
| /** |
| * Returns the current text using a separator between paragraphs. |
| * The separator can be specified with the <code>separator</code> |
| * argument. The default value of the <code>separator</code> argument |
| * is the Unicode character <code>'PARAGRAPH SEPARATOR' (U+2029)</code>. |
| * |
| * <p>Calling the setter discards any attached TextFlow. Any selection is lost.</p> |
| * |
| * @param separator String to set between paragraphs. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function getText(separator:String = '\u2029'):String |
| { |
| if (_sourceState == SOURCE_STRING) |
| return _text; |
| |
| if (_textDamaged || _lastSeparator != separator) |
| { |
| _text = ""; |
| var firstLeaf:FlowLeafElement = _textFlow.getFirstLeaf(); |
| if (firstLeaf != null) |
| { |
| var para:ParagraphElement = firstLeaf.getParagraph(); |
| while (para) |
| { |
| var nextPara:ParagraphElement = para.getNextParagraph(); |
| _text += para.getText(); |
| _text += nextPara ? separator : ""; |
| para = nextPara; |
| } |
| } |
| _textDamaged = false; |
| _lastSeparator = separator; |
| } |
| return _text; |
| } |
| /** |
| * Sets the <code>text</code> property to the specified String. |
| * |
| * Discards any attached TextFlow. Any selection is lost. |
| * |
| * @param str the String to set |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function setText(text:String):void |
| { |
| var hadPreviousSelection:Boolean = false; |
| var selectionChanged:Boolean = false; |
| var selectionState:SelectionState = null; |
| |
| var oldAnchorPosition:int = -1; |
| var oldActivePosition:int = -1; |
| |
| if (_sourceState == SOURCE_TEXTFLOW) |
| { |
| if (_textFlow.interactionManager && _textFlow.interactionManager.hasSelection()){ |
| hadPreviousSelection = true; |
| |
| //preserve the selection state [bug #2931406 from Flex SDK] |
| if (_preserveSelectionOnSetText) |
| { |
| oldAnchorPosition = Math.min(_textFlow.interactionManager.anchorPosition, text.length); |
| oldActivePosition = Math.min(_textFlow.interactionManager.activePosition, text.length); |
| if(oldAnchorPosition != _textFlow.interactionManager.anchorPosition || oldActivePosition != _textFlow.interactionManager.activePosition) |
| selectionChanged = true; |
| } |
| } |
| |
| removeTextFlowListeners(); |
| if (_textFlow.flowComposer) |
| _textFlow.flowComposer.removeAllControllers(); |
| _textFlow.unloadGraphics(); |
| _textFlow = null; |
| _sourceState = SOURCE_STRING; |
| _composeState = COMPOSE_FACTORY; |
| if (_container is InteractiveObject) |
| _container.mouseChildren = false; |
| addActivationEventListeners(); |
| } |
| _text = text ? text : ""; |
| _damaged = true; |
| _textDamaged = false; |
| |
| // Generate a damage event |
| if (hasEventListener(DamageEvent.DAMAGE)) |
| dispatchEvent(new DamageEvent(DamageEvent.DAMAGE, false, false, null, 0, _text.length)); |
| |
| // If the original tcm had selection, the selection needs to be preserved after setText. |
| if (hadPreviousSelection) |
| { |
| if (_preserveSelectionOnSetText) |
| { |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| if (_textFlow.interactionManager) |
| { |
| _textFlow.interactionManager.setSelectionState(new SelectionState(_textFlow, oldAnchorPosition, oldActivePosition)); |
| if(selectionChanged) |
| _textFlow.dispatchEvent(new SelectionEvent(SelectionEvent.SELECTION_CHANGE, false, false, _textFlow.interactionManager.getSelectionState())); |
| } |
| } |
| else if (hasEventListener(SelectionEvent.SELECTION_CHANGE)) |
| { |
| // generate a selection changed event. |
| dispatchEvent(new SelectionEvent(SelectionEvent.SELECTION_CHANGE, false, false, null)); |
| } |
| } |
| |
| if (_hasFocus) |
| requiredFocusInHandler(null); |
| } |
| |
| /** Sets the format when display just a string. If displaying a TextFlow this has no immediate effect. The supplied ITextLayoutFormat is not copied. Modifying it without calling this setter has indeterminate effects. */ |
| public function get hostFormat():ITextLayoutFormat |
| { return _hostFormat; } |
| public function set hostFormat(val:ITextLayoutFormat):void |
| { |
| _hostFormat = val; |
| _stringFactoryTextFlowFormat = null; |
| |
| if (_sourceState == SOURCE_TEXTFLOW) |
| _textFlow.hostFormat = _hostFormat; |
| if (_composeState == COMPOSE_FACTORY) |
| _damaged = true; |
| } |
| |
| /** Returns the horizontal extent allowed for text inside the container. The value is specified in pixels. |
| * |
| * <p>After setting this property, the text in the container is damaged and requires composing.</p> |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get compositionWidth():Number |
| { return _compositionWidth; } |
| public function set compositionWidth(val:Number):void |
| { |
| if (_compositionWidth == val || (isNaN(_compositionWidth) && isNaN(val))) |
| return; |
| _compositionWidth = val; |
| if (_composeState == COMPOSE_COMPOSER) |
| { |
| getController().setCompositionSize(_compositionWidth,_compositionHeight); |
| } |
| else |
| { |
| _damaged = true; |
| } |
| } |
| |
| /** Returns the vertical extent allowed for text inside the container. The value is specified in pixels. |
| * <p>After setting this property, the text in the container is damaged and requires composing.</p> |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| public function get compositionHeight():Number |
| { return _compositionHeight; } |
| public function set compositionHeight(val:Number):void |
| { |
| if (_compositionHeight == val || (isNaN(_compositionHeight) && isNaN(val))) |
| return; |
| _compositionHeight = val; |
| if (_composeState == COMPOSE_COMPOSER) |
| { |
| getController().setCompositionSize(_compositionWidth,_compositionHeight); |
| } |
| else |
| { |
| _damaged = true; |
| } |
| } |
| |
| /** The Configuration object for this TextContainerManager. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flashx.textLayout.IConfiguration IConfiguration |
| */ |
| public function get configuration():IConfiguration |
| { return _config; } |
| |
| /** Creates a rectangle that shows where the last call to either the <code>compose()</code> |
| * method or the <code>updateContainer()</code> method placed the text. |
| * |
| * @return the bounds of the content |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see #compose() |
| * @see #updateContainer() |
| */ |
| public function getContentBounds():Rectangle |
| { |
| if (_composeState == COMPOSE_FACTORY) |
| return new Rectangle(_contentLeft, _contentTop, _contentWidth, _contentHeight); |
| var controller:ContainerController = getController(); |
| return controller.getContentBounds(); |
| } |
| |
| /** The current TextFlow. Converts this to a full TextFlow representation if it |
| * isn't already one. |
| * |
| * @return the current TextFlow object |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function getTextFlow():TextFlow |
| { |
| if (_sourceState != SOURCE_TEXTFLOW) |
| { |
| var wasDamaged:Boolean = isDamaged(); |
| convertToTextFlow(); |
| if (!wasDamaged) |
| updateContainer(); |
| } |
| return _textFlow; |
| } |
| |
| /** Sets a TextFlow into this TextContainerManager replacing any existing TextFlow and discarding the |
| * current text. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function setTextFlow(textFlow:TextFlow):void |
| { |
| if (textFlow == _textFlow) |
| return; |
| |
| if (textFlow == null) |
| { |
| setText(null); |
| return; |
| } |
| |
| // Remove the old textFlow from its TextContainerManager, if it has one |
| if (textFlow.flowComposer && textFlow.flowComposer.numControllers > 0 && textFlow.flowComposer.getControllerAt(0) is TMContainerController) |
| { |
| var controller:TMContainerController = textFlow.flowComposer.getControllerAt(0) as TMContainerController; |
| if (controller.textContainerManager && controller.textContainerManager.getTextFlow() == textFlow) |
| controller.textContainerManager.setTextFlow(null); |
| } |
| |
| if (_sourceState == SOURCE_TEXTFLOW) |
| { |
| removeTextFlowListeners(); |
| if (_textFlow.flowComposer) |
| _textFlow.flowComposer.removeAllControllers(); |
| _textFlow.unloadGraphics(); |
| _textFlow = null; |
| } |
| |
| _textFlow = textFlow; |
| // damages the entire flow |
| _textFlow.hostFormat = hostFormat; |
| _sourceState = SOURCE_TEXTFLOW; |
| _composeState = textFlow.interactionManager || textFlow.mustUseComposer() ? COMPOSE_COMPOSER : COMPOSE_FACTORY; |
| _textDamaged = true; |
| addTextFlowListeners(); |
| |
| if (_composeState == COMPOSE_COMPOSER) |
| { |
| // Possible issue - this clear call could be delayed until updateToController |
| _container.mouseChildren = true; |
| clearContainerChildren(true); |
| clearComposedLines(); |
| _textFlow.flowComposer = new StandardFlowComposer(); |
| _textFlow.flowComposer.swfContext = _swfContext; |
| _textFlow.flowComposer.addController(new TMContainerController(_container,_compositionWidth,_compositionHeight,this)); |
| |
| invalidateInteractionManager(); |
| |
| // always start with an empty selection |
| if (_textFlow.interactionManager) |
| _textFlow.interactionManager.selectRange(-1,-1); |
| } |
| else |
| _damaged = true; |
| |
| if (_hasFocus) |
| requiredFocusInHandler(null); |
| |
| addActivationEventListeners(); |
| } |
| |
| /** |
| * Controls whether the factory generates all text lines or stops when the container bounds are filled. |
| * |
| * @copy flashx.textLayout.container.ContainerController#horizontalScrollPolicy |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get horizontalScrollPolicy():String |
| { |
| return _horizontalScrollPolicy; |
| } |
| public function set horizontalScrollPolicy(scrollPolicy:String):void |
| { |
| _horizontalScrollPolicy = ScrollPolicy.scrollPolicyPropertyDefinition.setHelper(_horizontalScrollPolicy, scrollPolicy) as String; |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().horizontalScrollPolicy = _horizontalScrollPolicy; |
| else |
| _damaged = true; |
| } |
| |
| /** |
| * Controls whether the factory generates all text lines or stops when the container bounds are filled. |
| * |
| * @copy flashx.textLayout.container.ContainerController#verticalScrollPolicy |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| public function get verticalScrollPolicy():String |
| { |
| return _verticalScrollPolicy; |
| } |
| public function set verticalScrollPolicy(scrollPolicy:String):void |
| { |
| _verticalScrollPolicy = ScrollPolicy.scrollPolicyPropertyDefinition.setHelper(_verticalScrollPolicy, scrollPolicy) as String; |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().verticalScrollPolicy = _verticalScrollPolicy; |
| else |
| _damaged = true; |
| } |
| |
| /** |
| * @copy flashx.textLayout.container.ContainerController#horizontalScrollPosition |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get horizontalScrollPosition():Number |
| { return _composeState == COMPOSE_COMPOSER ? getController().horizontalScrollPosition : 0; } |
| public function set horizontalScrollPosition(val:Number):void |
| { |
| if (val == 0 && _composeState == COMPOSE_FACTORY) |
| return; |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| getController().horizontalScrollPosition = val; |
| } |
| |
| /** |
| * @copy flashx.textLayout.container.ContainerController#verticalScrollPosition |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get verticalScrollPosition():Number |
| { return _composeState == COMPOSE_COMPOSER ? getController().verticalScrollPosition : 0; } |
| public function set verticalScrollPosition(val:Number):void |
| { |
| if (val == 0 && _composeState == COMPOSE_FACTORY) |
| return; |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| getController().verticalScrollPosition = val; |
| } |
| |
| /** |
| * @copy flashx.textLayout.container.ContainerController#getScrollDelta() |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function getScrollDelta(numLines:int):Number |
| { |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| return getController().getScrollDelta(numLines); |
| } |
| |
| /** |
| * @copy flashx.textLayout.container.ContainerController#scrollToRange() |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function scrollToRange(activePosition:int,anchorPosition:int):void |
| { |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| getController().scrollToRange(activePosition,anchorPosition); |
| } |
| |
| /** |
| * Optional ISWFContext instance used to make FTE calls as needed in the proper swf context. |
| * |
| * |
| * @see flashx.textLayout.compose.ISWFContext |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| public function get swfContext():ISWFContext |
| { return _swfContext; } |
| public function set swfContext(context:ISWFContext):void |
| { |
| _swfContext = context; |
| if (_composeState == COMPOSE_COMPOSER) |
| _textFlow.flowComposer.swfContext = _swfContext; |
| else |
| _damaged = true; |
| } |
| |
| /** @private - TextContainerManager wraps an underlying swfcontext - tell it to FlowComposerBase so it can avoid extra invalidation */ |
| public function getBaseSWFContext():ISWFContext |
| { return _swfContext; } |
| |
| /** @private - this is part of a performance optimziation for reusing existing TextLines in place iff recreateTextLine is available. */ |
| public function callInContext(fn:Function, thisArg:Object, argsArray:Array, returns:Boolean=true):* |
| { |
| var textBlock:TextBlock = thisArg as TextBlock; |
| if (textBlock && _expectedFactoryCompose == TextLineFactoryBase._factoryComposer) |
| { |
| if (fn == textBlock.createTextLine) |
| return createTextLine(textBlock,argsArray); |
| if (Configuration.playerEnablesArgoFeatures && fn == thisArg["recreateTextLine"]) |
| return recreateTextLine(textBlock,argsArray); |
| } |
| |
| var swfContext:ISWFContext = _swfContext ? _swfContext : BaseCompose.globalSWFContext; |
| if (returns) |
| return swfContext.callInContext(fn,thisArg,argsArray,returns); |
| swfContext.callInContext(fn,thisArg,argsArray,returns); |
| } |
| |
| public function resetLine(textLine:TextLine):void |
| { |
| // this line is being reset |
| if (textLine == _composedLines[_composeRecycledInPlaceLines-1]) |
| _composeRecycledInPlaceLines--; |
| } |
| |
| /** |
| * Uses the <code>textBlock</code> parameter, and calls the <code>TextBlock.createTextLine()</code> method on it |
| * using the remaining parameters. |
| * WARNING: modifies argsArray |
| * |
| * @copy flash.text.engine.TextBlock |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| private function createTextLine(textBlock:TextBlock, argsArray:Array):TextLine |
| { |
| var swfContext:ISWFContext = _swfContext ? _swfContext : BaseCompose.globalSWFContext; |
| CONFIG::debug { assert(Configuration.playerEnablesArgoFeatures,"Bad call to createTextLine"); } |
| |
| if (_composeRecycledInPlaceLines < _composedLines.length && _expectedFactoryCompose == TextLineFactoryBase._factoryComposer) |
| { |
| var textLine:TextLine = _composedLines[_composeRecycledInPlaceLines++]; |
| |
| argsArray.splice(0,0,textLine); |
| return swfContext.callInContext(textBlock["recreateTextLine"],textBlock,argsArray); |
| } |
| |
| return swfContext.callInContext(textBlock.createTextLine,textBlock,argsArray); |
| } |
| |
| /** |
| * Uses the <code>textBlock</code> parameter, and calls the <code>FlowComposerBase.recreateTextLine()</code> method on it |
| * using the remaining parameters. |
| * |
| * @param textBlock The TextBlock to which the TextLine belongs. |
| * @param textLine The TextLine to be recreated. |
| * @param previousLine Specifies the previously broken line after |
| * which breaking is to commence. Can be null when breaking the first line. |
| * @param width Specifies the desired width of the line in pixels. The |
| * actual width may be less. |
| * @param lineOffset An optional parameter which specifies the difference in |
| * pixels between the origin of the line and the origin of the tab stops. This can be used when lines are not aligned, |
| * but it is desirable for their tabs to be so. |
| * @param fitSomething An optional parameter that instructs the runtime to fit at least one |
| * character into the text line, no matter what width has been specified (even if width is zero or negative, which |
| * would otherwise result in an exception being thrown). |
| * @return The recreated TextLine instance. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| private function recreateTextLine(textBlock:TextBlock, argsArray:Array):TextLine |
| { |
| var swfContext:ISWFContext = _swfContext ? _swfContext : BaseCompose.globalSWFContext; |
| CONFIG::debug { assert(Configuration.playerEnablesArgoFeatures,"Bad call to createTextLine"); } |
| |
| if (_composeRecycledInPlaceLines < _composedLines.length) |
| { |
| CONFIG::debug {assert(argsArray[0] != _composedLines[_composeRecycledInPlaceLines],"Bad args"); } |
| TextLineRecycler.addLineForReuse(argsArray[0]); // not going to use this one |
| argsArray[0] = _composedLines[_composeRecycledInPlaceLines++]; |
| } |
| return swfContext.callInContext(textBlock["recreateTextLine"],textBlock,argsArray); |
| } |
| |
| |
| /** Returns the current ISelectionManager instance. Converts to TextFlow instance and creates one if necessary. |
| * |
| * @return the interaction manager for this TextContainerManager instance. |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flashx.textLayout.edit.ISelectionManager ISelectionManager |
| */ |
| public function beginInteraction():ISelectionManager |
| { |
| ++_interactionCount; |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| return _textFlow.interactionManager; |
| } |
| |
| /** Terminates interaction. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flashx.textLayout.edit.ISelectionManager ISelectionManager |
| */ |
| |
| public function endInteraction():void |
| { |
| --_interactionCount; |
| } |
| |
| /** Call this if you are editing, and want to reset the undo manager used for editing. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| */ |
| public function invalidateUndoManager():void |
| { |
| if (_editingMode == EditingMode.READ_WRITE) |
| invalidateInteractionManager(true); |
| } |
| |
| |
| /** Call this if you change the selection formats (SelectionFormat) and want the interactionManager |
| * to update. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| */ |
| public function invalidateSelectionFormats():void |
| { |
| invalidateInteractionManager(); |
| } |
| |
| /** The interactionManager is invalid - update it. Clients should call this if they change the |
| * selectionFormats. Its called automatically if editingMode is changed. */ |
| private function invalidateInteractionManager(alwaysRecreateManager:Boolean = false):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| { |
| var interactionManager:ISelectionManager = _textFlow.interactionManager; |
| var activePos:int = interactionManager ? interactionManager.activePosition : -1 |
| var anchorPos:int = interactionManager ? interactionManager.anchorPosition : -1; |
| |
| if (_editingMode == EditingMode.READ_ONLY) |
| { |
| if (interactionManager) |
| _textFlow.interactionManager = null; |
| } |
| else if (_editingMode == EditingMode.READ_WRITE) |
| { |
| if (alwaysRecreateManager || interactionManager == null || interactionManager.editingMode == EditingMode.READ_SELECT) |
| { |
| _textFlow.interactionManager = createEditManager(getUndoManager()); |
| if (_textFlow.interactionManager is SelectionManager) |
| SelectionManager(_textFlow.interactionManager).cloneSelectionFormatState(interactionManager); |
| } |
| } |
| else if (_editingMode == EditingMode.READ_SELECT) |
| { |
| if (alwaysRecreateManager || interactionManager == null || interactionManager.editingMode == EditingMode.READ_WRITE) |
| { |
| _textFlow.interactionManager = createSelectionManager(); |
| if (_textFlow.interactionManager is SelectionManager) |
| SelectionManager(_textFlow.interactionManager).cloneSelectionFormatState(interactionManager); |
| } |
| } |
| |
| interactionManager = _textFlow.interactionManager; |
| if (interactionManager) |
| { |
| interactionManager.unfocusedSelectionFormat = getUnfocusedSelectionFormat(); |
| interactionManager.focusedSelectionFormat = getFocusedSelectionFormat(); |
| interactionManager.inactiveSelectionFormat = getInactiveSelectionFormat(); |
| interactionManager.selectRange(anchorPos,activePos); |
| } |
| } |
| } |
| |
| /**Create a selection manager to use for selection. Override this method if you have a custom SelectionManager that you |
| * want to use in place of the default. |
| * |
| * @return a new SelectionManager instance. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| protected function createSelectionManager():ISelectionManager |
| { |
| return new SelectionManager(); |
| } |
| |
| /**Create an edit manager to use for editing. Override this method if you have a custom EditManager that you |
| * want to use in place of the default. |
| * |
| * @param an IUndoManager instance for the EditManager being created. |
| * @return the editing manager for this TextContainerManager instance. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| protected function createEditManager(undoManager:flashx.undo.IUndoManager):IEditManager |
| { |
| return new EditManager(undoManager); |
| } |
| |
| private function getController():TMContainerController |
| { return _textFlow.flowComposer.getControllerAt(0) as TMContainerController; } |
| |
| /** @private */ |
| tlf_internal var _composedLines:Array = []; |
| |
| /** Return the TextLine at the index from array of composed lines. |
| * |
| * @param index Finds the line at this index position in the text. |
| * |
| * @return the TextLine that occurs at the specified index. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function getLineAt(index:int):TextLine |
| { |
| // note: this method is not reliable for damaged text |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| // watch out for the empty TCM optimization and make a TextLine |
| if (_sourceState == SOURCE_STRING && _text.length == 0 && !_damaged && _composedLines.length == 0) |
| { |
| if (_needsRedraw) |
| compose(); |
| else |
| updateContainer(); |
| CONFIG::debug { assert(_composeState == COMPOSE_FACTORY,"no longer a factory??"); } |
| } |
| return _composedLines[index]; |
| } |
| var tfl:TextFlowLine = _textFlow.flowComposer.getLineAt(index); |
| return tfl ? tfl.getTextLine(true) : null; |
| } |
| |
| /** @copy flashx.textLayout.compose.IFlowComposer#numLines |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get numLines():int |
| { |
| // note: this method is not reliable for damaged text |
| if (_composeState == COMPOSE_COMPOSER) |
| return _textFlow.flowComposer.numLines; |
| // watch out for possibly optimized zero length text |
| if (_sourceState == SOURCE_STRING && _text.length == 0) |
| return 1; |
| return _composedLines.length; |
| } |
| |
| /** @private |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| tlf_internal function getActualNumLines():int |
| { |
| if (_composeState != COMPOSE_COMPOSER) |
| convertToTextFlowWithComposer(); |
| // composes all lines |
| _textFlow.flowComposer.composeToPosition(); |
| return _textFlow.flowComposer.numLines; |
| } |
| |
| /** @private */ |
| tlf_internal function clearComposedLines():void |
| { |
| if (_composedLines) |
| _composedLines.length = 0; |
| } |
| |
| private function populateComposedLines(displayObject:DisplayObject):void |
| { |
| _composedLines.push(displayObject); |
| } |
| |
| // TODO FOR ARGO - think about moving these variables into a separate helper class |
| private var _composeRecycledInPlaceLines:int; |
| private var _composePushedLines:int; |
| private function populateAndRecycleComposedLines(object:DisplayObject):void |
| { |
| var textLine:TextLine = object as TextLine; |
| if (textLine) |
| { |
| CONFIG::debug { assert(_composePushedLines >= _composedLines.length || _composedLines[_composePushedLines] == textLine,"mismatched recycled textline"); } |
| if (_composePushedLines >= _composedLines.length) |
| _composedLines.push(textLine); |
| } |
| else // this is the background color and goes at the head of the list |
| _composedLines.splice(0,0,object); |
| _composePushedLines++; |
| } |
| |
| static private var _expectedFactoryCompose:SimpleCompose; |
| |
| |
| /** Composes the container text; calls either the factory or <code>updateAllControllers()</code>. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function compose():void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| _textFlow.flowComposer.compose(); |
| else if (_damaged) |
| { |
| if (_sourceState == SOURCE_TEXTFLOW && _textFlow.mustUseComposer()) |
| { |
| convertToTextFlowWithComposer(false); |
| _textFlow.flowComposer.compose(); |
| return; |
| } |
| else |
| { |
| var callback:Function; |
| if (Configuration.playerEnablesArgoFeatures) |
| { |
| // while the first thing in the array is not a TextLine its the background color OR its some floats OR something else from the last compose - remove it |
| for (;;) |
| { |
| var firstObj:Object = _composedLines[0]; |
| if (firstObj == null || (firstObj is TextLine)) |
| break; |
| _composedLines.splice(0,1); |
| } |
| _composeRecycledInPlaceLines = 0; |
| _composePushedLines = 0; |
| callback = populateAndRecycleComposedLines; |
| } |
| else |
| { |
| clearComposedLines(); |
| callback = populateComposedLines; |
| } |
| var inputManagerFactory:TextLineFactoryBase = (_sourceState == SOURCE_STRING) ? inputManagerStringFactory(_config) : inputManagerTextFlowFactory(); |
| inputManagerFactory.verticalScrollPolicy = _verticalScrollPolicy; |
| inputManagerFactory.horizontalScrollPolicy = _horizontalScrollPolicy; |
| inputManagerFactory.compositionBounds = new Rectangle(0,0,_compositionWidth,_compositionHeight); |
| inputManagerFactory.swfContext = Configuration.playerEnablesArgoFeatures ? this : _swfContext; |
| |
| // compose can recurse for composing. this sets up the swfContext so it doesn't recycle a line into a numberline |
| _expectedFactoryCompose = TextLineFactoryBase.peekFactoryCompose(); |
| if (_sourceState == SOURCE_STRING) |
| { |
| var stringFactory:StringTextLineFactory = inputManagerFactory as StringTextLineFactory; |
| if (!_stringFactoryTextFlowFormat) |
| { |
| if (_hostFormat == null) |
| _stringFactoryTextFlowFormat = _config.textFlowInitialFormat; |
| else |
| { |
| // mini cascade of initialFormat onto the hostFormat |
| var format:TextLayoutFormat = new TextLayoutFormat(_hostFormat); |
| TextLayoutFormat.resetModifiedNoninheritedStyles(format); |
| var holderStyles:Object = (_config.textFlowInitialFormat as TextLayoutFormat).getStyles(); |
| for (var key:String in holderStyles) |
| { |
| var val:* = holderStyles[key]; |
| format[key] = (val !== FormatValue.INHERIT) ? val : _hostFormat[key]; |
| } |
| _stringFactoryTextFlowFormat = format; |
| } |
| } |
| if (!TextLayoutFormat.isEqual(stringFactory.textFlowFormat,_stringFactoryTextFlowFormat)) |
| stringFactory.textFlowFormat = _stringFactoryTextFlowFormat; |
| stringFactory.text = _text; |
| stringFactory.createTextLines(callback); |
| } |
| else |
| { |
| var factory:TCMTextFlowTextLineFactory = inputManagerFactory as TCMTextFlowTextLineFactory; |
| factory.tcm = this; |
| factory.createTextLines(callback,_textFlow); |
| factory.tcm = null; |
| } |
| inputManagerFactory.swfContext = null; // release any references to the swfContext |
| _expectedFactoryCompose = null; |
| |
| if (Configuration.playerEnablesArgoFeatures) |
| _composedLines.length = _composePushedLines; |
| |
| var bounds:Rectangle = inputManagerFactory.getContentBounds(); |
| |
| _contentLeft = bounds.x; |
| _contentTop = bounds.y; |
| _contentWidth = bounds.width; |
| _contentHeight = bounds.height; |
| _damaged = false; |
| |
| // generate a compositionComplete event. Note that the last composed position isn't known |
| if (hasEventListener(CompositionCompleteEvent.COMPOSITION_COMPLETE)) |
| dispatchEvent(new CompositionCompleteEvent(CompositionCompleteEvent.COMPOSITION_COMPLETE,false,false,_textFlow,0,-1)); |
| } |
| _needsRedraw = true; |
| } |
| |
| } |
| |
| /** Updates the display; calls either the factory or updateAllControllers(). |
| * |
| * @return true if anything changed. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function updateContainer():Boolean |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| return _textFlow.flowComposer.updateAllControllers(); |
| |
| compose(); |
| |
| // depending on edits the Flow may now have a composer |
| if (_composeState == COMPOSE_COMPOSER) |
| { |
| _textFlow.flowComposer.updateAllControllers(); |
| return true; |
| } |
| |
| if (!_needsRedraw) |
| return false; |
| |
| factoryUpdateContainerChildren(); |
| drawBackgroundAndSetScrollRect(0,0); |
| |
| if (_handlersState == HANDLERS_NOTADDED) |
| addActivationEventListeners(); |
| |
| // generate a updateComplete event. Note that the controller isn't known |
| if (hasEventListener(UpdateCompleteEvent.UPDATE_COMPLETE)) |
| dispatchEvent(new UpdateCompleteEvent(UpdateCompleteEvent.UPDATE_COMPLETE,false,false,null)); |
| |
| _needsRedraw = false; |
| return true; // things changed |
| } |
| |
| /** @private */ |
| tlf_internal function factoryUpdateContainerChildren():void |
| { |
| var textObject:DisplayObject; // scratch - TextLines and background shapes |
| if (Configuration.playerEnablesArgoFeatures) |
| { |
| // while the first child in the container is a Shape - its the background color OR a Float OR something else - lose it |
| while (_container.numChildren != 0) |
| { |
| textObject = _container.getChildAt(0); |
| if (textObject is TextLine) |
| break; |
| _container.removeChildAt(0); |
| } |
| |
| // add leading children _composedLines that are not TextLines into the Container |
| for (var idx:int = 0; idx < _composedLines.length; idx++) |
| { |
| textObject = _composedLines[idx]; |
| if (textObject is TextLine) |
| break; |
| _container.addChildAt(textObject,idx); |
| } |
| |
| // expect the leading lines are reused |
| while (_container.numChildren < _composedLines.length) |
| _container.addChild(_composedLines[_container.numChildren]); |
| // recycle any trailing lines |
| while (_container.numChildren > _composedLines.length) |
| { |
| var textLine:TextLine = _container.getChildAt(_composedLines.length) as TextLine; |
| _container.removeChildAt(_composedLines.length); |
| if (textLine) |
| { |
| // lines were rebroken but aren't being displayed |
| if (textLine.validity == TextLineValidity.VALID) |
| textLine.textBlock.releaseLines(textLine,textLine.textBlock.lastLine); |
| textLine.userData = null; |
| TextLineRecycler.addLineForReuse(textLine); |
| } |
| } |
| } |
| else |
| { |
| clearContainerChildren(false); |
| |
| for each (textObject in _composedLines) |
| _container.addChild(textObject); |
| |
| clearComposedLines(); |
| } |
| } |
| |
| private function addActivationEventListeners():void |
| { |
| var newState:int = HANDLERS_NONE; |
| |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| if (_editingMode == EditingMode.READ_ONLY) |
| newState = HANDLERS_MOUSEWHEEL; |
| else |
| newState = _handlersState == HANDLERS_NOTADDED ? HANDLERS_CREATION : HANDLERS_ACTIVE; |
| } |
| |
| if (newState == _handlersState) |
| return; |
| |
| removeActivationEventListeners(); |
| |
| if (newState == HANDLERS_CREATION) |
| { |
| _container.addEventListener(FocusEvent.FOCUS_IN, requiredFocusInHandler); |
| _container.addEventListener(MouseEvent.MOUSE_OVER, requiredMouseOverHandler); |
| } |
| else if (newState == HANDLERS_ACTIVE) |
| { |
| _container.addEventListener(FocusEvent.FOCUS_IN, requiredFocusInHandler); |
| _container.addEventListener(MouseEvent.MOUSE_OVER, requiredMouseOverHandler); |
| _container.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); |
| _container.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler); |
| _container.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); |
| // _container.addEventListener(IMEEvent.IME_START_COMPOSITION, imeStartCompositionHandler); |
| // attach by literal event name to avoid Argo dependency |
| _container.addEventListener("imeStartComposition", imeStartCompositionHandler); |
| |
| // If TCM's getContextMenu returns null assume client has control of the contextMenu |
| if (getContextMenu() != null) |
| _container.contextMenu = _contextMenu; |
| if (_container.contextMenu) |
| _container.contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, menuSelectHandler); |
| |
| _container.addEventListener(Event.SELECT_ALL, editHandler); |
| } |
| else if (newState == HANDLERS_MOUSEWHEEL) |
| _container.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); |
| |
| _handlersState = newState; |
| } |
| |
| // The ContextMenu to be used. The idea is that this is undefined until createContextMenu is called and then |
| // createContextMenu is only called once and the result is shared with the ContainerController when it gets created |
| private var _contextMenu:*; |
| |
| /** @private Returns the already created contextMenu. If not created yet create it. */ |
| tlf_internal function getContextMenu():ContextMenu |
| { |
| if (_contextMenu === undefined) |
| _contextMenu = createContextMenu(); |
| return _contextMenu; |
| } |
| |
| private function removeActivationEventListeners():void |
| { |
| if (_handlersState == HANDLERS_CREATION) |
| { |
| CONFIG::debug { assert(_composeState != COMPOSE_COMPOSER,"Bad call to removeActivationEventListeners"); } |
| _container.removeEventListener(FocusEvent.FOCUS_IN, requiredFocusInHandler); |
| _container.removeEventListener(MouseEvent.MOUSE_OVER, requiredMouseOverHandler); |
| } |
| else if (_handlersState == HANDLERS_ACTIVE) |
| { |
| CONFIG::debug { assert(_composeState != COMPOSE_COMPOSER,"Bad call to removeActivationEventListeners"); } |
| _container.removeEventListener(FocusEvent.FOCUS_IN, requiredFocusInHandler); |
| _container.removeEventListener(MouseEvent.MOUSE_OVER, requiredMouseOverHandler); |
| _container.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); |
| _container.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler); |
| _container.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); |
| // _container.removeEventListener(IMEEvent.IME_START_COMPOSITION, imeStartCompositionHandler); |
| // detach by literal event name to avoid Argo dependency |
| _container.removeEventListener("imeStartComposition", imeStartCompositionHandler); |
| // if _contextMenu is set then this TCM created the contextMenu and is manging it |
| if (_container.contextMenu) |
| _container.contextMenu.removeEventListener(ContextMenuEvent.MENU_SELECT, menuSelectHandler); |
| // otherwise client is managing it |
| if (_contextMenu) |
| _container.contextMenu = null; |
| |
| _container.removeEventListener(Event.SELECT_ALL, editHandler); |
| } |
| else if (_handlersState == HANDLERS_MOUSEWHEEL) |
| { |
| CONFIG::debug { assert(_composeState != COMPOSE_COMPOSER,"Bad call to removeActivationEventListeners"); } |
| _container.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); |
| } |
| |
| _handlersState = HANDLERS_NOTADDED; |
| } |
| |
| private function addTextFlowListeners():void |
| { |
| for each (var event:String in eventList) |
| _textFlow.addEventListener(event,dispatchEvent); |
| } |
| |
| private function removeTextFlowListeners():void |
| { |
| for each (var event:String in eventList) |
| _textFlow.removeEventListener(event,dispatchEvent); |
| _handlersState = HANDLERS_NONE; |
| } |
| |
| /** |
| * @copy flash.events.IEventDispatcher#dispatchEvent() |
| * @private |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public override function dispatchEvent(event:Event):Boolean |
| { |
| if (event.type == DamageEvent.DAMAGE) |
| { |
| _textDamaged = true; |
| if (_composeState == COMPOSE_FACTORY) |
| _damaged = true; |
| } |
| else if (event.type == FlowOperationEvent.FLOW_OPERATION_BEGIN) |
| { |
| if (_container.mouseChildren == false) |
| _container.mouseChildren = true; |
| } |
| var result:Boolean = super.dispatchEvent(event); |
| if (!result) |
| event.preventDefault(); |
| return result; |
| } |
| |
| /** @private */ |
| tlf_internal function clearContainerChildren(recycle:Boolean):void |
| { |
| while(_container.numChildren) |
| { |
| var textLine:TextLine = _container.getChildAt(0) as TextLine; |
| _container.removeChildAt(0); |
| if (textLine) |
| { |
| // releasing all textLines so release each still connected textBlock |
| if (textLine.validity != TextLineValidity.INVALID && textLine.validity != TextLineValidity.STATIC) |
| { |
| var textBlock:TextBlock = textLine.textBlock; |
| CONFIG::debug { Debugging.traceFTECall(null,textBlock,"releaseLines",textBlock.firstLine, textBlock.lastLine); } |
| textBlock.releaseLines(textBlock.firstLine,textBlock.lastLine); |
| } |
| if (recycle) |
| { |
| textLine.userData = null; // clear any userData |
| TextLineRecycler.addLineForReuse(textLine); |
| } |
| } |
| } |
| } |
| |
| private function convertToTextFlow():void |
| { |
| CONFIG::debug { assert(_sourceState != SOURCE_TEXTFLOW,"bad call to convertToTextFlow"); } |
| |
| _textFlow = new TextFlow(_config); |
| _textFlow.hostFormat = _hostFormat; |
| if(_swfContext) |
| { |
| _textFlow.flowComposer.swfContext = _swfContext; |
| } |
| |
| var p:ParagraphElement = new ParagraphElement(); |
| _textFlow.addChild(p) |
| var s:SpanElement = new SpanElement(); |
| s.text = _text; |
| p.addChild(s); |
| _sourceState = SOURCE_TEXTFLOW; |
| addTextFlowListeners(); |
| } |
| |
| /** @private */ |
| tlf_internal function convertToTextFlowWithComposer(callUpdateContainer:Boolean = true):void |
| { |
| removeActivationEventListeners(); |
| |
| if (_sourceState != SOURCE_TEXTFLOW) |
| convertToTextFlow(); |
| |
| if (_composeState != COMPOSE_COMPOSER) |
| { |
| clearContainerChildren(true); |
| clearComposedLines(); |
| var controller:TMContainerController = new TMContainerController(_container,_compositionWidth,_compositionHeight,this); |
| _textFlow.flowComposer = new StandardFlowComposer(); |
| _textFlow.flowComposer.addController(controller); |
| _textFlow.flowComposer.swfContext = _swfContext; |
| _composeState = COMPOSE_COMPOSER; |
| |
| invalidateInteractionManager(); |
| if (callUpdateContainer) |
| updateContainer(); |
| } |
| } |
| |
| private function get effectiveBlockProgression():String |
| { |
| if (_textFlow) |
| return _textFlow.computedFormat.blockProgression; |
| return _hostFormat && _hostFormat.blockProgression && _hostFormat.blockProgression != FormatValue.INHERIT ? _hostFormat.blockProgression : BlockProgression.TB; |
| } |
| |
| /* CONFIG::debug private static function doTrace(msg:String):void |
| { trace(msg); } */ |
| |
| private function removeIBeamCursor():void |
| { |
| if (_ibeamCursorSet) |
| { |
| Mouse.cursor = Configuration.getCursorString(configuration, MouseCursor.AUTO); |
| _ibeamCursorSet = false; |
| } |
| } |
| |
| private var _hasScrollRect:Boolean = false; |
| |
| /** |
| * Specifies whether this container has attached a ScrollRect object. Value is <code>true</code> |
| * or <code>false</code>. A display object is cropped to the size defined by the scroll rectangle, and |
| * it scrolls within the rectangle when you change the x and y properties of the scrollRect object. |
| * |
| * <p>This property enables a client to test for a ScrollRect object without accessing |
| * the DisplayObject.scrollRect property, which can have side effects in some cases.</p> |
| * |
| * @return true if the controller has attached a ScrollRect instance. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see #drawBackgroundAndSetScrollRect |
| */ |
| private function get hasScrollRect():Boolean |
| { return _hasScrollRect; } |
| private function set hasScrollRect(value:Boolean):void |
| { _hasScrollRect = value; } |
| |
| /** |
| * Returns <code>true</code> if it has filled in the container's scrollRect property. |
| * This method enables you to test whether <code>scrollRect</code> is set without actually accessing the <code>scrollRect</code> property |
| * which can possibly create a performance issue. |
| * <p>Override this method to draw a background or a border. Overriding this method can be tricky as the scrollRect <bold>must</bold> |
| * be set as specified.</p> |
| * |
| * @param scrollX The starting horizontal position of the scroll rectangle. |
| * @param scrollY The starting vertical position of the scroll rectangle. |
| * |
| * @return <code>true</code> if it has created the <code>scrollRect</code> object. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function drawBackgroundAndSetScrollRect(scrollX:Number,scrollY:Number):Boolean |
| { |
| var cont:Sprite = this.container; |
| |
| var contentWidth:Number; |
| var contentHeight:Number; |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| contentWidth = _contentWidth; |
| contentHeight = _contentHeight; |
| } |
| else |
| { |
| var controller:ContainerController = getController(); |
| contentWidth = controller.contentWidth; |
| contentHeight = controller.contentHeight; |
| } |
| var width:Number; |
| if (isNaN(compositionWidth)) |
| { |
| var contentLeft:Number = (_composeState == COMPOSE_FACTORY) ? _contentLeft : controller.contentLeft; |
| width = contentLeft + contentWidth - scrollX; |
| } |
| else |
| width = compositionWidth; |
| var height:Number; |
| if (isNaN(compositionHeight)) |
| { |
| var contentTop:Number = (_composeState == COMPOSE_FACTORY) ? _contentTop : controller.contentTop; |
| height = contentTop + contentHeight - scrollY; |
| } |
| else |
| height = compositionHeight; |
| |
| if (scrollX == 0 && scrollY == 0 && contentWidth <= width && contentHeight <= height) |
| { |
| // skip the scrollRect |
| if (_hasScrollRect) |
| { |
| cont.scrollRect = null; |
| _hasScrollRect = false; |
| } |
| } |
| else |
| { |
| cont.scrollRect = new Rectangle(scrollX, scrollY, width, height); |
| _hasScrollRect = true; |
| |
| // adjust to the values actually in the scrollRect |
| scrollX = cont.scrollRect.x; |
| scrollY = cont.scrollRect.y; |
| width = cont.scrollRect.width; |
| height = cont.scrollRect.height; |
| } |
| |
| // NOTE: must draw a background for interaction support - even it if is 100% transparent |
| var s:Sprite = cont as Sprite; |
| if (s) |
| { |
| s.graphics.clear(); |
| s.graphics.beginFill(0, 0); |
| s.graphics.drawRect(scrollX,scrollY,width,height); |
| s.graphics.endFill(); |
| } |
| |
| return _hasScrollRect; |
| } |
| |
| /** Returns the focusedSelectionFormat - by default get it from the configuration. |
| * This can be overridden in the subclass to supply a different SelectionFormat |
| */ |
| protected function getFocusedSelectionFormat():SelectionFormat |
| { |
| return _config.focusedSelectionFormat; |
| } |
| |
| /** Returns the inactiveSelectionFormat - by default get it from the configuration |
| * This can be overridden in the subclass to supply a different SelectionFormat |
| */ |
| protected function getInactiveSelectionFormat():SelectionFormat |
| { |
| return _config.inactiveSelectionFormat; |
| } |
| |
| /** Returns the unfocusedSelectionFormat - by default get it from the configuration |
| * You can override this method in the subclass to supply a different SelectionFormat. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| protected function getUnfocusedSelectionFormat():SelectionFormat |
| { |
| return _config.unfocusedSelectionFormat; |
| } |
| |
| /** |
| * Returns the undo manager to use. By default, creates a unique undo manager. |
| * You can override this method in the subclass if you want to customize the undo manager |
| * (for example, to use a shared undo manager for multiple TextContainerManager instances). |
| * |
| * @return new IUndoManager instance. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| |
| protected function getUndoManager():IUndoManager |
| { |
| return new UndoManager(); |
| } |
| |
| /** Creates a ContextMenu for the TextContainerManager. Use the methods of the ContextMenu |
| * class to add items to the menu. |
| * <p>You can override this method to define a custom context menu.</p> |
| * |
| * @return the created context menu. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.ui.ContextMenu ContextMenu |
| */ |
| protected function createContextMenu():ContextMenu |
| { |
| return ContainerController.createDefaultContextMenu(); |
| } |
| /** @copy flashx.textLayout.container.ContainerController#editHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.events.Event Event |
| */ |
| public function editHandler(event:Event):void |
| { |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| convertToTextFlowWithComposer(); |
| getController().editHandler(event); |
| _textFlow.interactionManager.setFocus(); |
| } |
| else |
| getController().editHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#keyDownHandler() |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.KeyboardEvent#KEY_DOWN KeyboardEvent.KEY_DOWN |
| */ |
| public function keyDownHandler(event:KeyboardEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().keyDownHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#keyUpHandler(). |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.KeyboardEvent#KEY_UP KeyboardEvent.KEY_UP |
| */ |
| public function keyUpHandler(event:KeyboardEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().keyUpHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#keyFocusChangeHandler(). |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @param event the FocusChange event |
| */ |
| public function keyFocusChangeHandler(event:FocusEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().keyFocusChangeHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#textInputHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.TextEvent#TEXT_INPUT TextEvent.TEXT_INPUT |
| */ |
| public function textInputHandler(event:TextEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().textInputHandler(event); |
| } |
| |
| /** Processes the <code>IME_START_COMPOSITION</code> event when the client manages events. |
| * |
| * @param event The IMEEvent object. |
| * |
| * @playerversion Flash 10.1 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * |
| * @see flash.events.IMEEvent#IME_START_COMPOSITION IMEEvent.IME_START_COMPOSITION |
| */ |
| public function imeStartCompositionHandler(event:IMEEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().imeStartCompositionHandler(event); |
| } |
| |
| /** Processes the <code>SOFT_KEYBOARD_ACTIVATING</code> event when the client manages events. |
| * |
| * @param event The SoftKeyboardEvent object. |
| * |
| * @playerversion Flash 10.2 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * |
| * @see flash.events.SoftKeyboardEvent#SOFT_KEYBOARD_ACTIVATING SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING |
| */ |
| public function softKeyboardActivatingHandler(event:Event):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().softKeyboardActivatingHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#mouseDownHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.MouseEvent#MOUSE_DOWN MouseEvent.MOUSE_DOWN |
| */ |
| public function mouseDownHandler(event:MouseEvent):void |
| { |
| // doTrace("IM:mouseDownHandler"); |
| // before the mouseDown do a mouseOver |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| CONFIG::debug { assert(event.currentTarget == this.container,"TextContainerManager:mouseDownHandler - unexpected currentTarget"); } |
| convertToTextFlowWithComposer(); |
| getController().requiredFocusInHandler(null); |
| getController().requiredMouseOverHandler(event.target != container ? new RemappedMouseEvent(event) : event); |
| if (_hasFocus) |
| getController().requiredFocusInHandler(null); |
| getController().requiredMouseDownHandler(event); |
| } |
| else |
| getController().mouseDownHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#mouseMoveHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.MouseEvent#MOUSE_MOVE MouseEvent.MOUSE_MOVE |
| */ |
| public function mouseMoveHandler(event:MouseEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().mouseMoveHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#mouseUpHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.MouseEvent#MOUSE_UP MouseEvent.MOUSE_UP |
| */ |
| public function mouseUpHandler(event:MouseEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().mouseUpHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#mouseDoubleClickHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.MouseEvent#DOUBLE_CLICK MouseEvent.DOUBLE_CLICK |
| */ |
| public function mouseDoubleClickHandler(event:MouseEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().mouseDoubleClickHandler(event); |
| } |
| |
| /** @private Process a mouseOver event. |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| tlf_internal final function requiredMouseOverHandler(event:MouseEvent):void |
| { |
| if (_composeState == COMPOSE_FACTORY) |
| mouseOverHandler(event); |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().requiredMouseOverHandler(event); |
| } |
| |
| |
| /** Process a mouseOver event. |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.MouseEvent#MOUSE_OVER MouseEvent.MOUSE_OVER |
| */ |
| public function mouseOverHandler(event:MouseEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().mouseOverHandler(event); |
| else |
| { |
| // doTrace("IM:mouseOverHandler"); |
| if (effectiveBlockProgression != BlockProgression.RL) |
| { |
| Mouse.cursor = MouseCursor.IBEAM; |
| _ibeamCursorSet = true; |
| } |
| addActivationEventListeners(); |
| } |
| } |
| /** @copy flashx.textLayout.container.ContainerController#mouseOutHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.MouseEvent#MOUSE_OUT MouseEvent.MOUSE_OUT |
| */ |
| public function mouseOutHandler(event:MouseEvent):void |
| { |
| // doTrace("IM:mouseOutHandler"); |
| if (_composeState == COMPOSE_FACTORY) |
| removeIBeamCursor(); |
| else |
| getController().mouseOutHandler(event); |
| } |
| /** @copy flashx.textLayout.container.ContainerController#focusInHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.FocusEvent#FOCUS_IN FocusEvent.FOCUS_IN |
| */ |
| |
| |
| /** Process a focusIn event. |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function focusInHandler(event:FocusEvent):void |
| { |
| _hasFocus = true; |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().focusInHandler(event); |
| } |
| |
| /** @private hook to get at requiredFocusOutHandler as needed */ |
| tlf_internal function requiredFocusOutHandler(event:FocusEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().requiredFocusOutHandler(event); |
| } |
| /** @copy flashx.textLayout.container.ContainerController#focusOutHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.FocusEvent#FOCUS_OUT FocusEvent.FOCUS_OUT |
| */ |
| public function focusOutHandler(event:FocusEvent):void |
| { |
| _hasFocus = false; |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().focusOutHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#activateHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.Event#ACTIVATE Event.ACTIVATE |
| */ |
| public function activateHandler(event:Event):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().activateHandler(event); |
| } |
| /** @copy flashx.textLayout.container.ContainerController#deactivateHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * @see flash.events.Event#DEACTIVATE Event.DEACTIVATE |
| */ |
| public function deactivateHandler(event:Event):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().deactivateHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#focusChangeHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.events.FocusEvent#KEY_FOCUS_CHANGE FocusEvent.KEY_FOCUS_CHANGE |
| * @see flash.events.FocusEvent#MOUSE_FOCUS_CHANGE FocusEvent.MOUSE_FOCUS_CHANGE |
| */ |
| public function focusChangeHandler(event:FocusEvent):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().focusChangeHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#menuSelectHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.events.ContextMenuEvent#MENU_SELECT ContextMenuEvent.MENU_SELECT |
| */ |
| public function menuSelectHandler(event:ContextMenuEvent):void |
| { |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| // there is no selection |
| var contextMenu:ContextMenu = _container.contextMenu as ContextMenu; |
| if (contextMenu) |
| { |
| var cbItems:ContextMenuClipboardItems = contextMenu.clipboardItems; |
| cbItems.selectAll = _editingMode != EditingMode.READ_ONLY; |
| cbItems.clear = false; |
| cbItems.copy = false; |
| cbItems.cut = false; |
| cbItems.paste = false; |
| } |
| } |
| else |
| getController().menuSelectHandler(event); |
| } |
| |
| /** @copy flashx.textLayout.container.ContainerController#mouseWheelHandler() |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.events.MouseEvent#MOUSE_WHEEL MouseEvent.MOUSE_WHEEL |
| */ |
| public function mouseWheelHandler(event:MouseEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| convertToTextFlowWithComposer(); |
| getController().requiredMouseOverHandler(event); |
| } |
| getController().mouseWheelHandler(event); |
| } |
| |
| |
| /** @private required FocusIn handler. Clients override focusInHandler |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| tlf_internal final function requiredFocusInHandler(event:FocusEvent):void |
| { |
| // doTrace("IM:focusInHandler"); |
| if (_composeState == COMPOSE_FACTORY) |
| { |
| addActivationEventListeners(); |
| focusInHandler(event); |
| } |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().requiredFocusInHandler(event); |
| } |
| |
| /** |
| * Called to request clients to begin the forwarding of mouseup and mousemove events from outside a security sandbox. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| */ |
| public function beginMouseCapture():void |
| { } |
| /** |
| * Called to inform clients that the the forwarding of mouseup and mousemove events from outside a security sandbox is no longer needed. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| */ |
| public function endMouseCapture():void |
| { } |
| /** Client call to forward a mouseUp event from outside a security sandbox. Coordinates of the mouse up are not needed. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| */ |
| public function mouseUpSomewhere(e:Event):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().mouseUpSomewhere(e); |
| } |
| /** Client call to forward a mouseMove event from outside a security sandbox. Coordinates of the mouse move are not needed. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| */ |
| public function mouseMoveSomewhere(e:Event):void |
| { |
| if (_composeState == COMPOSE_COMPOSER) |
| getController().mouseUpSomewhere(e); |
| } |
| |
| /** @private |
| * Gets the index at which the first text line must appear in its parent. |
| * The default implementation of this method, which may be overriden, returns the child index |
| * of the first <code>flash.text.engine.TextLine</code> child of <code>container</code> |
| * if one exists, and that of the last child of <code>container</code> otherwise. |
| * |
| * @return the index at which the first text line must appear in its parent. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.text.engine.TextLine |
| * @see #container |
| */ |
| tlf_internal function getFirstTextLineChildIndex():int |
| { |
| // skip past any non-TextLine children below the text in the container, |
| // This also means that in a container devoid of text, we will always |
| // populate the text starting at index container.numChildren, which is intentional. |
| var firstTextLine:int; |
| for(firstTextLine = 0; firstTextLine<_container.numChildren; ++firstTextLine) |
| { |
| if(_container.getChildAt(firstTextLine) is TextLine) |
| { |
| break; |
| } |
| } |
| return firstTextLine; |
| } |
| |
| /** @private |
| * Adds a <code>flash.text.engine.TextLine</code> object as a descendant of <code>container</code>. |
| * The default implementation of this method, which may be overriden, adds the object |
| * as a direct child of <code>container</code> at the specified index. |
| * |
| * @param textLine the <code>flash.text.engine.TextLine</code> object to add |
| * @param index insertion index of the text line in its parent |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.text.engine.TextLine |
| * @see #container |
| * |
| */ |
| tlf_internal function addTextLine(textLine:TextLine, index:int):void |
| { |
| _container.addChildAt(textLine, index); |
| } |
| |
| /** @private |
| * Removes a <code>flash.text.engine.TextLine</code> object from its parent. |
| * The default implementation of this method, which may be overriden, removes the object |
| * from <code>container</code> if it is a direct child of the latter. |
| * |
| * This method may be called even if the object is not a descendant of <code>container</code>. |
| * Any implementation of this method must ensure that no action is taken in this case. |
| * |
| * @param textLine the <code>flash.text.engine.TextLine</code> object to remove |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.text.engine.TextLine |
| * @see #container |
| * |
| */ |
| tlf_internal function removeTextLine(textLine:TextLine):void |
| { |
| if (_container.contains(textLine)) |
| _container.removeChild(textLine); |
| } |
| |
| /** @private |
| * Adds a <code>flash.display.Shape</code> object on which background shapes (such as background color) are drawn. |
| * The default implementation of this method, which may be overriden, adds the object to <code>container</code> |
| * just before the first <code>flash.text.engine.TextLine</code> child, if one exists, and after the last exisiting |
| * child otherwise. |
| * |
| * @param shape <code>flash.display.Shape</code> object to add |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.display.Shape |
| * @see flash.text.engine.TextLine |
| * @see #container |
| * |
| */ |
| tlf_internal function addBackgroundShape(shape:Shape):void // No PMD |
| { |
| _container.addChildAt(shape, getFirstTextLineChildIndex()); |
| } |
| |
| /** @private |
| * Removes a <code>flash.display.Shape</code> object on which background shapes (such as background color) are drawn. |
| * The default implementation of this method, which may be overriden, removes the object from its <code>parent</code>. |
| * |
| * @param shape <code>flash.display.Shape</code> object to remove |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.display.Shape |
| * @see flash.text.engine.TextLine |
| * @see #container |
| * |
| */ |
| tlf_internal function removeBackgroundShape(shape:Shape):void |
| { |
| if (shape.parent) |
| shape.parent.removeChild(shape); |
| } |
| |
| /** @private |
| * Adds a <code>flash.display.DisplayObjectContainer</code> object to which selection shapes (such as block selection highlight, cursor etc.) are added. |
| * The default implementation of this method, which may be overriden, has the following behavior: |
| * The object is added just before first <code>flash.text.engine.TextLine</code> child of <code>container</code> if one exists |
| * and the object is opaque and has normal blend mode. |
| * In all other cases, it is added as the last child of <code>container</code>. |
| * |
| * @param selectionContainer <code>flash.display.DisplayObjectContainer</code> object to add |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.display.DisplayObjectContainer |
| * @see flash.text.engine.TextLine |
| * @see #container |
| */ |
| tlf_internal function addSelectionContainer(selectionContainer:DisplayObjectContainer):void |
| { |
| if (selectionContainer.blendMode == BlendMode.NORMAL && selectionContainer.alpha == 1) |
| { |
| // don't put selection behind background color or existing content in container, put it behind first text line |
| _container.addChildAt(selectionContainer, getFirstTextLineChildIndex()); |
| } |
| else |
| _container.addChild(selectionContainer); |
| } |
| |
| /** @private |
| * Removes the <code>flash.display.DisplayObjectContainer</code> object which contains selection shapes (such as block selection highlight, cursor etc.). |
| * The default implementation of this method, which may be overriden, removes the object from its parent if one exists. |
| * |
| * @param selectionContainer <code>flash.display.DisplayObjectContainer</code> object to remove |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| * |
| * @see flash.display.DisplayObjectContainer |
| * @see #container |
| * |
| */ |
| tlf_internal function removeSelectionContainer(selectionContainer:DisplayObjectContainer):void |
| { |
| selectionContainer.parent.removeChild(selectionContainer); |
| } |
| |
| /** @private |
| * Adds a <code>flash.display.DisplayObject</code> object as a descendant of <code>parent</code>. |
| * The default implementation of this method, which may be overriden, adds the object |
| * as a direct child of <code>parent</code> at the specified index. This is called to add |
| * InlineGraphicElements to the TextLine or container. |
| * |
| * @param parent the <code>flash.display.DisplayObjectContainer</code> object to add the inlineGraphicElement to |
| * @param inlineGraphicElement the <code>flash.display.DisplayObject</code> object to add |
| * @param index insertion index of the float in its parent |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.0 |
| * @langversion 3.0 |
| * |
| * @see flash.display.DisplayObjectContainer |
| * @see flash.display.DisplayObject |
| * @see #container |
| * |
| */ |
| tlf_internal function addInlineGraphicElement(parent:DisplayObjectContainer, inlineGraphicElement:DisplayObject, index:int):void |
| { |
| if (parent) |
| parent.addChildAt(inlineGraphicElement, index); |
| } |
| |
| /** @private |
| * Removes a <code>flash.display.DisplayObject</code> object from its parent. |
| * The default implementation of this method, which may be overriden, removes the object |
| * from <code>container</code> if it is a direct child of the latter. |
| * |
| * This method may be called even if the object is not a descendant of <code>parent</code>. |
| * Any implementation of this method must ensure that no action is taken in this case. |
| * |
| * @param float the <code>flash.display.DisplayObject</code> object to remove |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.0 |
| * @langversion 3.0 |
| * |
| * @see flash.display.DisplayObjectContainer |
| * @see flash.display.DisplayObject |
| * @see #container |
| * |
| */ |
| tlf_internal function removeInlineGraphicElement(parent:DisplayObjectContainer, inlineGraphicElement:DisplayObject):void |
| { |
| if (parent && inlineGraphicElement.parent == parent) |
| parent.removeChild(inlineGraphicElement); |
| } |
| |
| /** @public |
| * It's <code>_preserveSelectionOnSetText</code> to decide whether or not TLF preserve selection state during setText(). |
| * |
| * The default value is false, which means <code>setText()</code> does not preserve original selection state, |
| * <code>setText()</code> acts as what it was. If <code>_preserveSelectionOnSetText</code> is true, |
| * the original selection state is preserved during <code>setText()</code>. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get preserveSelectionOnSetText():Boolean |
| { |
| return _preserveSelectionOnSetText; |
| } |
| public function set preserveSelectionOnSetText(value:Boolean):void |
| { |
| _preserveSelectionOnSetText = value; |
| } |
| |
| } |
| |
| } |
| |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.display.Shape; |
| import flash.display.Sprite; |
| import flash.events.Event; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.geom.Rectangle; |
| import flash.text.engine.TextLine; |
| import flash.ui.ContextMenu; |
| |
| import flashx.textLayout.compose.IFlowComposer; |
| import flashx.textLayout.compose.SimpleCompose; |
| import flashx.textLayout.container.ContainerController; |
| import flashx.textLayout.container.ScrollPolicy; |
| import flashx.textLayout.container.TextContainerManager; |
| import flashx.textLayout.edit.IInteractionEventHandler; |
| import flashx.textLayout.elements.ContainerFormattedElement; |
| import flashx.textLayout.factory.FactoryDisplayComposer; |
| import flashx.textLayout.factory.TextFlowTextLineFactory; |
| import flashx.textLayout.factory.TextLineFactoryBase; |
| import flashx.textLayout.formats.BackgroundColor; |
| import flashx.textLayout.formats.BlockProgression; |
| import flashx.textLayout.tlf_internal; |
| |
| use namespace tlf_internal; |
| |
| class TMContainerController extends ContainerController |
| { |
| private var _inputManager:TextContainerManager; |
| |
| public function TMContainerController(container:Sprite, compositionWidth:Number, compositionHeight:Number, tm:TextContainerManager) |
| { |
| super(container,compositionWidth,compositionHeight); |
| _inputManager = tm; |
| verticalScrollPolicy = tm.verticalScrollPolicy; |
| horizontalScrollPolicy = tm.horizontalScrollPolicy; |
| } |
| |
| public function get textContainerManager():TextContainerManager { return _inputManager; } |
| |
| /** Reroute to the TextContainerManger's override. Reuse the one that's already been created. */ |
| protected override function createContextMenu():ContextMenu |
| { return _inputManager.getContextMenu(); } |
| |
| /** @private */ |
| protected override function get attachTransparentBackground():Boolean |
| { return false; } |
| |
| /** @private */ |
| tlf_internal function doUpdateVisibleRectangle():void |
| { updateVisibleRectangle(); } |
| |
| /** @private. Override clones and enhances parent class functionality. */ |
| protected override function updateVisibleRectangle() :void |
| { |
| var xpos:Number; |
| var ypos:Number; |
| // see the adjustLines boolean in ContainerController.fillShapeChildren - this logic clones that and allows for skipping the scrollRect |
| xpos = horizontalScrollPosition; |
| if (effectiveBlockProgression == BlockProgression.RL && (verticalScrollPolicy != ScrollPolicy.OFF || horizontalScrollPolicy != ScrollPolicy.OFF)) |
| xpos -= !isNaN(compositionWidth) ? compositionWidth : contentWidth; |
| |
| ypos = verticalScrollPosition; |
| |
| _hasScrollRect = _inputManager.drawBackgroundAndSetScrollRect(xpos,ypos); |
| } |
| |
| /** @private */ |
| tlf_internal override function getInteractionHandler():IInteractionEventHandler |
| { return _inputManager; } |
| |
| |
| /** @private */ |
| tlf_internal override function attachContextMenu():void |
| { |
| if (_inputManager.getContextMenu() != null) |
| super.attachContextMenu(); |
| } |
| |
| /** @private */ |
| tlf_internal override function removeContextMenu():void |
| { |
| // otherwise client is managing it |
| if (_inputManager.getContextMenu()) |
| super.removeContextMenu(); |
| } |
| |
| // //////////////////////////////////////////////////////////////////////////// |
| // push all these methods for manipulating the object list to the _inputmanager |
| // //////////////////////////////////////////////////////////////////////////// |
| protected override function getFirstTextLineChildIndex():int |
| { return _inputManager.getFirstTextLineChildIndex(); } |
| protected override function addTextLine(textLine:TextLine, index:int):void |
| { _inputManager.addTextLine(textLine,index); } |
| protected override function removeTextLine(textLine:TextLine):void |
| { _inputManager.removeTextLine(textLine); } |
| protected override function addBackgroundShape(shape:Shape):void |
| { _inputManager.addBackgroundShape(shape); } |
| protected override function removeBackgroundShape(shape:Shape):void |
| { _inputManager.removeBackgroundShape(shape); } |
| protected override function addSelectionContainer(selectionContainer:DisplayObjectContainer):void |
| { _inputManager.addSelectionContainer(selectionContainer); } |
| protected override function removeSelectionContainer(selectionContainer:DisplayObjectContainer):void |
| { _inputManager.removeSelectionContainer(selectionContainer); } |
| protected override function addInlineGraphicElement(parent:DisplayObjectContainer, inlineGraphicElement:DisplayObject, index:int):void |
| { _inputManager.addInlineGraphicElement(parent,inlineGraphicElement,index); } |
| protected override function removeInlineGraphicElement(parent:DisplayObjectContainer, inlineGraphicElement:DisplayObject):void |
| { _inputManager.removeInlineGraphicElement(parent,inlineGraphicElement); } |
| } |
| |
| // remap the mouse event for processing inside TLF. This is just the initial click. Make it as if the event was on the container and not the textline |
| class RemappedMouseEvent extends MouseEvent |
| { |
| private var _event:MouseEvent; |
| |
| public function RemappedMouseEvent(event:MouseEvent,cloning:Boolean = false) |
| { |
| var containerPoint:Point; |
| if (!cloning) |
| { |
| containerPoint = DisplayObject(event.target).localToGlobal(new Point(event.localX, event.localY)); |
| containerPoint = DisplayObject(event.currentTarget).globalToLocal(containerPoint); |
| } |
| else |
| containerPoint = new Point(); |
| |
| /* event.commandKey,event.controlKey,event.clickCount are also supported in AIR. IMHO they are a nonissue for the initial click */ |
| super(event.type,event.bubbles,event.cancelable,containerPoint.x,containerPoint.y,event.relatedObject,event.ctrlKey,event.altKey,event.shiftKey,event.buttonDown,event.delta); |
| |
| _event = event; |
| } |
| |
| // override methods/getters for things we couldn't set in the base class |
| |
| public override function get target():Object |
| { return _event.currentTarget; } |
| |
| public override function get currentTarget():Object |
| { return _event.currentTarget; } |
| |
| public override function get eventPhase():uint |
| { return _event.eventPhase; } |
| |
| public override function get isRelatedObjectInaccessible():Boolean |
| { return _event.isRelatedObjectInaccessible; } |
| |
| public override function get stageX():Number |
| { return _event.stageX; } |
| |
| public override function get stageY():Number |
| { return _event.stageY; } |
| |
| public override function clone():Event |
| { |
| var rslt:RemappedMouseEvent = new RemappedMouseEvent(_event,true); |
| rslt.localX = localX; |
| rslt.localY = localY; |
| return rslt; |
| } |
| |
| public override function updateAfterEvent():void |
| { _event.updateAfterEvent(); } |
| |
| public override function isDefaultPrevented():Boolean |
| { return _event.isDefaultPrevented(); } |
| |
| public override function preventDefault():void |
| { _event.preventDefault(); } |
| |
| public override function stopImmediatePropagation():void |
| { _event.stopImmediatePropagation(); } |
| |
| public override function stopPropagation():void |
| { _event.stopPropagation(); } |
| } |
| |
| class TCMTextFlowTextLineFactory extends TextFlowTextLineFactory |
| { |
| private var _tcm:TextContainerManager; |
| |
| public function TCMTextFlowTextLineFactory() |
| { super(); } |
| |
| /** @private */ |
| tlf_internal override function createFlowComposer():IFlowComposer |
| { return new TCMFactoryDisplayComposer(_tcm); } |
| |
| public function get tcm():TextContainerManager |
| { return _tcm; } |
| public function set tcm(val:TextContainerManager):void |
| { _tcm = val; } |
| } |
| |
| |
| class TCMFactoryDisplayComposer extends FactoryDisplayComposer |
| { |
| tlf_internal var _tcm:TextContainerManager; |
| public function TCMFactoryDisplayComposer(tcm:TextContainerManager) |
| { _tcm = tcm; } |
| |
| tlf_internal override function callTheComposer(absoluteEndPosition:int, controllerEndIndex:int):ContainerController |
| { |
| // always do a full compose |
| clearCompositionResults(); |
| |
| var state:SimpleCompose = TextLineFactoryBase._factoryComposer; |
| state.resetLineHandler = _tcm.resetLine; |
| state.composeTextFlow(textFlow, -1, -1); |
| state.releaseAnyReferences() |
| return getControllerAt(0); |
| } |
| } |