//////////////////////////////////////////////////////////////////////////////// // // 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 mx.managers { import flash.display.DisplayObject; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.events.MouseEvent; import flash.geom.Matrix; import flash.geom.Point; import mx.core.DragSource; import mx.core.IFlexDisplayObject; import mx.core.IFlexModule; import mx.core.IFlexModuleFactory; import mx.core.ILayoutDirectionElement; import mx.core.IUIComponent; import mx.core.LayoutDirection; import mx.core.UIComponentGlobals; import mx.core.mx_internal; import mx.events.DragEvent; import mx.events.Request; import mx.managers.dragClasses.DragProxy; import mx.styles.CSSStyleDeclaration; import mx.styles.IStyleManager2; import mx.styles.StyleManager; import mx.utils.MatrixUtil; use namespace mx_internal; [ExcludeClass] /** * @private */ public class DragManagerImpl extends EventDispatcher implements IDragManager { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class variables // //-------------------------------------------------------------------------- /** * @private */ private static var sm:ISystemManager; /** * @private */ private static var instance:IDragManager; /** * @private * * Place to hook in additional classes */ public static var mixins:Array; //-------------------------------------------------------------------------- // // Class methods // //-------------------------------------------------------------------------- /** * @private */ public static function getInstance():IDragManager { if (!instance) { sm = SystemManagerGlobals.topLevelSystemManagers[0]; instance = new DragManagerImpl(); } return instance; } //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * @private */ public function DragManagerImpl() { super(); if (instance) throw new Error("Instance already exists."); if (mixins) { var n:int = mixins.length; for (var i:int = 0; i < n; i++) { new mixins[i](this); } } sandboxRoot = sm.getSandboxRoot(); if (sm.isTopLevelRoot()) { sm.addEventListener(MouseEvent.MOUSE_DOWN, sm_mouseDownHandler, false, 0, true); sm.addEventListener(MouseEvent.MOUSE_UP, sm_mouseUpHandler, false, 0, true); } if (hasEventListener("initialize")) dispatchEvent(new Event("initialize")); } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private * The highest place we can listen for events in our DOM */ private var sandboxRoot:IEventDispatcher; /** * @private * Object that initiated the drag. */ private var dragInitiator:IUIComponent; /** * @private * Object being dragged around. */ public var dragProxy:DragProxy; /** * @private */ public var bDoingDrag:Boolean = false; /** * @private */ private var mouseIsDown:Boolean = false; //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- /** * Read-only property that returns true * if a drag is in progress. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get isDragging():Boolean { return bDoingDrag; } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * Initiates a drag and drop operation. * * @param dragInitiator IUIComponent that specifies the component initiating * the drag. * * @param dragSource DragSource object that contains the data * being dragged. * * @param mouseEvent The MouseEvent that contains the mouse information * for the start of the drag. * * @param dragImage The image to drag. This argument is optional. * If omitted, a standard drag rectangle is used during the drag and * drop operation. If you specify an image, you must explicitly set a * height and width of the image or else it will not appear. * * @param xOffset Number that specifies the x offset, in pixels, for the * dragImage. This argument is optional. If omitted, the drag proxy * is shown at the upper-left corner of the drag initiator. The offset is expressed * in pixels from the left edge of the drag proxy to the left edge of the drag * initiator, and is usually a negative number. * * @param yOffset Number that specifies the y offset, in pixels, for the * dragImage. This argument is optional. If omitted, the drag proxy * is shown at the upper-left corner of the drag initiator. The offset is expressed * in pixels from the top edge of the drag proxy to the top edge of the drag * initiator, and is usually a negative number. * * @param imageAlpha Number that specifies the alpha value used for the * drag image. This argument is optional. If omitted, the default alpha * value is 0.5. A value of 0.0 indicates that the image is transparent; * a value of 1.0 indicates it is fully opaque. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function doDrag( dragInitiator:IUIComponent, dragSource:DragSource, mouseEvent:MouseEvent, dragImage:IFlexDisplayObject = null, // instance of dragged item(s) xOffset:Number = 0, yOffset:Number = 0, imageAlpha:Number = 0.5, allowMove:Boolean = true):void { var proxyWidth:Number; var proxyHeight:Number; // Can't start a new drag if we're already in the middle of one... if (bDoingDrag) return; // Can't do a drag if the mouse isn't down if (!(mouseEvent.type == MouseEvent.MOUSE_DOWN || mouseEvent.type == MouseEvent.CLICK || mouseIsDown || mouseEvent.buttonDown)) { return; } bDoingDrag = true; if (hasEventListener("doDrag")) dispatchEvent(new Event("doDrag")); this.dragInitiator = dragInitiator; // The drag proxy is a UIComponent with a single child - // an instance of the dragImage. dragProxy = new DragProxy(dragInitiator, dragSource); var e:Event; if (hasEventListener("popUpChildren")) e = new DragEvent("popUpChildren", false, true, dragProxy); if (!e || dispatchEvent(e)) sm.popUpChildren.addChild(dragProxy); if (!dragImage) { // No drag image specified, use default var dragManagerStyleDeclaration:CSSStyleDeclaration = getStyleManager(dragInitiator).getMergedStyleDeclaration("mx.managers.DragManager"); var dragImageClass:Class = dragManagerStyleDeclaration.getStyle("defaultDragImageSkin"); dragImage = new dragImageClass(); dragProxy.addChild(DisplayObject(dragImage)); proxyWidth = dragInitiator.width; proxyHeight = dragInitiator.height; } else { dragProxy.addChild(DisplayObject(dragImage)); if (dragImage is ILayoutManagerClient ) UIComponentGlobals.layoutManager.validateClient(ILayoutManagerClient (dragImage), true); if (dragImage is IUIComponent) { proxyWidth = (dragImage as IUIComponent).getExplicitOrMeasuredWidth(); proxyHeight = (dragImage as IUIComponent).getExplicitOrMeasuredHeight(); } else { proxyWidth = dragImage.measuredWidth; proxyHeight = dragImage.measuredHeight; } } // Set the layoutDirection of the dragProxy and dragImage to match the dragInitiator // to ensure that they will be in the right position and orientation. if (dragInitiator is ILayoutDirectionElement && ILayoutDirectionElement(dragInitiator).layoutDirection == LayoutDirection.RTL) dragProxy.layoutDirection = LayoutDirection.RTL; dragImage.setActualSize(proxyWidth, proxyHeight); dragProxy.setActualSize(proxyWidth, proxyHeight); // Alpha dragProxy.alpha = imageAlpha; dragProxy.allowMove = allowMove; // Make sure any scale/rotation from the initiator will be reflected. var concatenatedMatrix:Matrix = MatrixUtil.getConcatenatedMatrix(DisplayObject(dragInitiator), DisplayObject(sandboxRoot)); // Zero out the translation part of the matrix, as we're going to // position the dragProxy explicitly further below. concatenatedMatrix.tx = 0; concatenatedMatrix.ty = 0; // Combine with the matrix of the dragImage if it has any. var m:Matrix = dragImage.transform.matrix; if (m) { concatenatedMatrix.concat(dragImage.transform.matrix); dragImage.transform.matrix = concatenatedMatrix; } // Find mouse coordinates in global space var nonNullTarget:Object = mouseEvent.target; if (nonNullTarget == null) nonNullTarget = dragInitiator; var point:Point = new Point(mouseEvent.localX, mouseEvent.localY); point = DisplayObject(nonNullTarget).localToGlobal(point); point = DisplayObject(sandboxRoot).globalToLocal(point); var mouseX:Number = point.x; var mouseY:Number = point.y; // Find the proxy origin in global space var proxyOrigin:Point = DisplayObject(dragInitiator).localToGlobal(new Point(-xOffset, -yOffset)); proxyOrigin = DisplayObject(sandboxRoot).globalToLocal(proxyOrigin); // Set dragProxy.offset to the mouse offset within the drag proxy. dragProxy.xOffset = mouseX - proxyOrigin.x; dragProxy.yOffset = mouseY - proxyOrigin.y; // Setup the initial position of the drag proxy. dragProxy.x = proxyOrigin.x; dragProxy.y = proxyOrigin.y; // Remember the starting location of the drag proxy so it can be // "snapped" back if the drop was refused. dragProxy.startX = dragProxy.x; dragProxy.startY = dragProxy.y; // Turn on caching. if (dragImage is DisplayObject) DisplayObject(dragImage).cacheAsBitmap = true; var delegate:Object = dragProxy.automationDelegate; if (delegate) delegate.recordAutomatableDragStart(dragInitiator, mouseEvent); } /** * Call this method from your dragEnter event handler if you accept * the drag/drop data. * For example: * *
DragManager.acceptDragDrop(event.target);
* * @param target The drop target accepting the drag. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function acceptDragDrop(target:IUIComponent):void { // trace("-->acceptDragDrop for DragManagerImpl", sm, target); if (dragProxy) dragProxy.target = target as DisplayObject; if (hasEventListener("acceptDragDrop")) dispatchEvent(new Request("acceptDragDrop", false, false, target)); } /** * Sets the feedback indicator for the drag and drop operation. * Possible values are DragManager.COPY, DragManager.MOVE, * DragManager.LINK, or DragManager.NONE. * * @param feedback The type of feedback indicator to display. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function showFeedback(feedback:String):void { // trace("-->showFeedback for DragManagerImpl", sm, feedback); if (dragProxy) { if (feedback == DragManager.MOVE && !dragProxy.allowMove) feedback = DragManager.COPY; dragProxy.action = feedback; } if (hasEventListener("showFeedback")) dispatchEvent(new Request("showFeedback", false, false, feedback)); } /** * Returns the current drag and drop feedback. * * @return Possible return values are DragManager.COPY, * DragManager.MOVE, * DragManager.LINK, or DragManager.NONE. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getFeedback():String { if (hasEventListener("getFeedback")) { var request:Request = new Request("getFeedback", false, true); if (!dispatchEvent(request)) { return request.value as String; } } // trace("<--getFeedback for DragManagerImpl", sm); return dragProxy ? dragProxy.action : DragManager.NONE; } /** * @private */ public function endDrag():void { var e:Event; if (hasEventListener("endDrag")) { e = new Event("endDrag", false, true); } if (!e || dispatchEvent(e)) { if (dragProxy) { sm.popUpChildren.removeChild(dragProxy); if (dragProxy.numChildren > 0) dragProxy.removeChildAt(0); // The drag image is the only child dragProxy = null; } } dragInitiator = null; bDoingDrag = false; } /** * @private */ static private function getStyleManager(dragInitiator:IUIComponent):IStyleManager2 { // If the dragInitiator has a styleManager, use that one. // In a situation where a main application that loads a module with drag initiator, // the main application may not link in the DragManager and appropriate styles. // We want to use the styles of the module of the dragInitiator. See SDK-24324. if (dragInitiator is IFlexModule) return StyleManager.getStyleManager(IFlexModule(dragInitiator).moduleFactory); return StyleManager.getStyleManager(sm as IFlexModuleFactory); } //-------------------------------------------------------------------------- // // Event handlers // //-------------------------------------------------------------------------- /** * @private */ private function sm_mouseDownHandler(event:MouseEvent):void { mouseIsDown = true; } /** * @private */ private function sm_mouseUpHandler(event:MouseEvent):void { mouseIsDown = false; } } }