This is an automated email from the ASF dual-hosted git repository. yishayw pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
The following commit(s) were added to refs/heads/develop by this push: new ffdeb4e096 Emulation - Add drag and drop (no move yet) to List ffdeb4e096 is described below commit ffdeb4e0967b32f07dfd3b7afcf90801e6f214f0 Author: Yishay Weiss <yishayj...@hotmail.com> AuthorDate: Mon Sep 12 10:23:08 2022 +0300 Emulation - Add drag and drop (no move yet) to List --- .../projects/Core/src/main/royale/CoreClasses.as | 1 + .../org/apache/royale/utils/getOrAddBeadByType.as | 54 +++ .../MXRoyale/src/main/royale/mx/controls/List.as | 31 ++ .../beads/SingleSelectionDropTargetBead.as | 426 +++++++++++++++++++++ .../royale/mx/controls/listClasses/ListBase.as | 33 ++ 5 files changed, 545 insertions(+) diff --git a/frameworks/projects/Core/src/main/royale/CoreClasses.as b/frameworks/projects/Core/src/main/royale/CoreClasses.as index 3e53c27281..b5a6d3f13f 100644 --- a/frameworks/projects/Core/src/main/royale/CoreClasses.as +++ b/frameworks/projects/Core/src/main/royale/CoreClasses.as @@ -332,6 +332,7 @@ internal class CoreClasses import org.apache.royale.utils.measureComponent; measureComponent; import org.apache.royale.utils.loadBeadFromValuesManager; loadBeadFromValuesManager; + import org.apache.royale.utils.getOrAddBeadByType; getOrAddBeadByType; import org.apache.royale.utils.removeBeadFromBeads;removeBeadFromBeads; import org.apache.royale.utils.HSV; HSV; import org.apache.royale.utils.rgbToHsv; rgbToHsv; diff --git a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/getOrAddBeadByType.as b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/getOrAddBeadByType.as new file mode 100644 index 0000000000..e0b0efeea0 --- /dev/null +++ b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/getOrAddBeadByType.as @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.royale.utils +{ + import org.apache.royale.core.IBead; + import org.apache.royale.core.IStrand; + + /** + * @return added or existing bead. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + * @royalesuppressexport + * @royaleignorecoercion Class + * @royaleignorecoercion Function + * @royaleignorecoercion org.apache.royale.core.IBead + */ + public function getOrAddBeadByType(c:Class, strand:IStrand):IBead + { + var result:IBead = strand.getBeadByType(c); + if (!result) + { + COMPILE::JS + { + var f:Function = c as Function; + result = new f() as IBead; + } + COMPILE::SWF + { + result = new c() as IBead; + } + strand.addBead(result); + } + return result; + } +} diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/List.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/List.as index c1a875d3c8..5fdbc5074b 100644 --- a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/List.as +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/List.as @@ -78,6 +78,12 @@ use namespace mx_internal; import mx.core.ClassFactory; import mx.controls.listClasses.ListBase; +import org.apache.royale.html.beads.DataGridDrawingLayerBead; +import mx.controls.beads.SingleSelectionDropTargetBead; +import org.apache.royale.html.beads.SingleSelectionDropIndicatorBead; +import org.apache.royale.html.beads.SingleSelectionDragSourceBead; +import org.apache.royale.html.beads.SingleSelectionDragImageBead; +import org.apache.royale.utils.getOrAddBeadByType; //[IconFile("List.png")] @@ -338,6 +344,31 @@ public class List extends ListBase // implements IIMESupport // //-------------------------------------------------------------------------- + /** + * @private + */ + override protected function setDropEnabled():void + { + getOrAddBeadByType(DataGridDrawingLayerBead, this); + getOrAddBeadByType(SingleSelectionDropTargetBead, this); + getOrAddBeadByType(SingleSelectionDropIndicatorBead, this); + } + + /** + * @private + */ + override protected function setDragMoveEnabled():void + { + } + + /** + * @private + */ + override protected function setDragEnabled():void + { + getOrAddBeadByType(SingleSelectionDragSourceBead, this); + getOrAddBeadByType(SingleSelectionDragImageBead, this); + } [Inspectable(category="Data", defaultValue="undefined")] /** diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/SingleSelectionDropTargetBead.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/SingleSelectionDropTargetBead.as new file mode 100644 index 0000000000..3360e98fe9 --- /dev/null +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/beads/SingleSelectionDropTargetBead.as @@ -0,0 +1,426 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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.controls.beads +{ + import org.apache.royale.collections.ArrayList; + import org.apache.royale.core.DropType; + import org.apache.royale.core.IBead; + import org.apache.royale.core.IItemRendererOwnerView; + import org.apache.royale.core.IChild; + import org.apache.royale.core.IDataProviderModel; + import org.apache.royale.core.IItemRenderer; + import org.apache.royale.core.ItemRendererOwnerViewBead; + import org.apache.royale.core.IParent; + import org.apache.royale.core.ILayoutHost; + import org.apache.royale.core.ISelectionModel; + import org.apache.royale.core.IStrand; + import org.apache.royale.core.IUIBase; + import org.apache.royale.core.UIBase; + import org.apache.royale.events.DragEvent; + import org.apache.royale.events.Event; + import org.apache.royale.events.EventDispatcher; + import org.apache.royale.events.IEventDispatcher; + import org.apache.royale.geom.Point; + import org.apache.royale.geom.Rectangle; + import org.apache.royale.html.beads.controllers.DropMouseController; + import org.apache.royale.html.supportClasses.DataItemRenderer; + import org.apache.royale.utils.PointUtils; + import org.apache.royale.utils.UIUtils; + import org.apache.royale.core.IIndexedItemRenderer; + import org.apache.royale.utils.sendStrandEvent; + import org.apache.royale.utils.sendEvent; + import org.apache.royale.html.util.getModelByType; + import mx.collections.IList; + import org.apache.royale.html.beads.SingleSelectionDropIndicatorBead; + import org.apache.royale.html.beads.IDrawingLayerBead; + + + /** + * The enter event is dispatched when a DragEnter has been detected in the drop target + * strand. This event can be used to determine if the strand can and will accept the data + * being dragged onto it. If the data cannot be used by the drop target strand this event + * should be cancelled. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9 + */ + [Event(name="enter", type="org.apache.royale.events.Event")] + + /** + * The exit event is sent when the drag goes outside of the drop target space. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9 + */ + [Event(name="exit", type="org.apache.royale.events.Event")] + + /** + * The over event is dispatched while the drag is happening over the drop target space. This + * event may be cancelled if that particular area of the drop target cannot accept the + * drag source data. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9 + */ + [Event(name="over", type="org.apache.royale.events.Event")] + + /** + * The drop event is dispatched just prior to incorporating the drag source data into the drop + * target's dataProvider. This event may be cancelled to prevent that from happening. + * Note that a "exit" event always precedes this event to allow any drag-drop graphics + * to be cleared. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9 + */ + [Event(name="drop", type="org.apache.royale.events.Event")] + + /** + * The complete event is dispatched when the drop operation has completed from the drop + * target's perspective. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9 + */ + [Event(name="complete", type="org.apache.royale.events.Event")] + + /** + * The SingleSelectionDropTargetBead enables items to be dropped onto single-selection List + * components. This bead can be used with SingleSelectionDragSourceBead to enable the re-arrangement + * of rows within the same list. + * + * @see org.apache.royale.html.beads.SingleSelectionDropIndicatorBead + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.8 + */ + public class SingleSelectionDropTargetBead extends EventDispatcher implements IBead + { + /** + * Constructor + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.8 + */ + public function SingleSelectionDropTargetBead() + { + super(); + } + + private var _dropController:DropMouseController; + private var _itemRendererOwnerView:IItemRendererOwnerView; + private var _dropIndicatorBead:SingleSelectionDropIndicatorBead; + private var _dropIndicator:UIBase; + private var lastItemVisited:Object; + private var indicatorVisible:Boolean = false; + + private var _strand:IStrand; + + /** + * @private + */ + public function set strand(value:IStrand):void + { + _strand = value; + + _dropController = new DropMouseController(); + _strand.addBead(_dropController); + + _dropController.addEventListener(DragEvent.DRAG_ENTER, handleDragEnter); + _dropController.addEventListener(DragEvent.DRAG_EXIT, handleDragExit); + _dropController.addEventListener(DragEvent.DRAG_OVER, handleDragOver); + _dropController.addEventListener(DragEvent.DRAG_DROP, handleDragDrop); + } + + private var _dropDirection: String = "horizontal"; + + /** + * The direction the drop indicator should display. "horizontal" (default) or "vertical". + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.9 + */ + public function get dropDirection():String + { + return _dropDirection; + } + public function set dropDirection(value:String):void + { + _dropDirection = value; + } + + protected var _indicatorParent:UIBase; + + /** + * @private + * @royaleignorecoercion org.apache.royale.html.beads.IDrawingLayerBead + */ + protected function get indicatorParent():UIBase + { + if (_indicatorParent == null) { + var layerBead:IDrawingLayerBead = _strand.getBeadByType(IDrawingLayerBead) as IDrawingLayerBead; + if (layerBead != null) { + _indicatorParent = layerBead.layer; + } + } + return _indicatorParent; + } + /** + * @private + * @royaleignorecoercion org.apache.royale.core.IItemRendererOwnerView + */ + private function get itemRendererOwnerView():IItemRendererOwnerView + { + if (!_itemRendererOwnerView) + _itemRendererOwnerView = _strand.getBeadByType(IItemRendererOwnerView) as IItemRendererOwnerView; + return _itemRendererOwnerView; + } + + /** + * @private + * @royaleignorecoercion org.apache.royale.html.beads.SingleSelectionDropIndicatorBead + */ + protected function getDropIndicator(ir:Object, width:Number, height:Number):UIBase + { + if (_dropIndicatorBead == null) { + _dropIndicatorBead = _strand.getBeadByType(SingleSelectionDropIndicatorBead) as SingleSelectionDropIndicatorBead; + if (_dropIndicatorBead == null) return null; + } + _dropIndicator = _dropIndicatorBead.getDropIndicator(ir, width, height); + return _dropIndicator; + } + + /** + * @private + * @royaleignorecoercion org.apache.royale.core.IUIBase + * @royaleignorecoercion org.apache.royale.core.IItemRenderer + */ + private function handleDragEnter(event:DragEvent):void + { + //trace("SingleSelectionDropTargetBead received DragEnter via: "+event.relatedObject.toString()); + var newEvent:Event = new Event("enter", false, true); + dispatchEvent(newEvent); + if (newEvent.defaultPrevented) return; + + var pt0:Point; + var pt1:Point; + var pt2:Point; + + _dropController.acceptDragDrop(event.relatedObject as IUIBase, DropType.COPY); + + var startHere:Object = event.relatedObject; + while( !(startHere is IItemRenderer) && startHere != null) { + startHere = startHere.parent; + } + + if (startHere is IItemRenderer) { + var ir:IItemRenderer = startHere as IItemRenderer; + lastItemVisited = ir; + } else if (itemRendererOwnerView && itemRendererOwnerView.numItemRenderers > 0) + { + // as long as we're assuming the last item is dropped into in case there's no item renderer under mouse + // this is needed + lastItemVisited = itemRendererOwnerView.getItemRendererAt(itemRendererOwnerView.numItemRenderers - 1); + } + + if (lastItemVisited && !indicatorVisible && indicatorParent) { + var di:UIBase = getDropIndicator(lastItemVisited, (dropDirection == "horizontal") ? indicatorParent.width : 4, + (dropDirection == "horizontal") ? 4 : indicatorParent.height); + indicatorVisible = true; + displayDropIndicator(lastItemVisited as IUIBase); + + if (indicatorParent != null) { + indicatorParent.addElement(di); + } + } + + } + + /** + * @private + */ + private function handleDragExit(event:DragEvent):void + { + //trace("SingleSelectionDropTargetBead received DragExit via: "+event.relatedObject.toString()); + dispatchEvent(new Event("exit", false, true)); + + if (indicatorVisible) { + if (indicatorParent != null) { + indicatorParent.removeElement(_dropIndicator); + } + indicatorVisible = false; + } + } + + /** + * @private + * @royaleignorecoercion org.apache.royale.core.IUIBase + */ + private function handleDragOver(event:DragEvent):void + { + //trace("SingleSelectionDropTargetBead received DragOver via: "+event.relatedObject.toString()); + var newEvent:Event = new Event("over", false, true); + dispatchEvent(newEvent); + if (event.defaultPrevented) { + return; + } + + var startHere:Object = event.relatedObject; + while( !(startHere is IItemRenderer) && startHere != null) { + startHere = startHere.parent; + } + + if ((startHere is IItemRenderer) && _dropIndicator != null && indicatorParent) { + displayDropIndicator(startHere as IUIBase); + lastItemVisited = startHere; + + } + else if (lastItemVisited && _dropIndicator != null && indicatorParent) { + displayDropIndicator(lastItemVisited as IUIBase); + } + } + + /** + * @private + * @royaleignorecoercion mx.collections.IList + * @royaleignorecoercion org.apache.royale.core.IDataProviderModel + * @royaleignorecoercion org.apache.royale.core.IIndexedItemRenderer + * @royaleignorecoercion org.apache.royale.core.ISelectionModel + */ + private function handleDragDrop(event:DragEvent):void + { + //trace("SingleSelectionDropTargetBead received DragDrop via: "+event.relatedObject.toString()); + + handleDragExit(event); + + var newEvent:Event = new Event("drop", false, true); + dispatchEvent(newEvent); + if (newEvent.defaultPrevented) { + return; + } + + var targetIndex:int = -1; // indicates drop beyond length of items + // var contentViewAsParent:IParent; + + var startHere:Object = event.relatedObject; + while( !(startHere is IIndexedItemRenderer) && startHere != null) { + startHere = startHere.parent; + } + + if (startHere) { + var ir:IIndexedItemRenderer = startHere as IIndexedItemRenderer; + targetIndex = ir.index; + } + + var downPoint:Point = new Point(event.clientX, event.clientY); + //trace("Dropping at this point: "+downPoint.x+", "+downPoint.y); + //trace("-- find the itemRenderer this object is over"); + + // Let the dragInitiator know that the drop was accepted so it can do + // whatever it needs to do to prepare the data or structures. + if (DragEvent.dragInitiator) { + DragEvent.dragInitiator.acceptingDrop(_strand, "object"); + } + + var dragSource:Object = DragEvent.dragSource; + var sourceIndex:int = 0; + + var dataProviderModel:IDataProviderModel = getModelByType(_strand,IDataProviderModel) as IDataProviderModel; + if (dataProviderModel.dataProvider is IList) + { + var dataList:IList = dataProviderModel.dataProvider as IList; + + // insert the item being dropped + if (targetIndex == -1) { + // sppend to the end + dataList.addItem(dragSource); + } else { + // insert before target index + dataList.addItemAt(dragSource, targetIndex); + } + } + + // Let the dragInitiator know the drop has been completed. + if (DragEvent.dragInitiator) { + DragEvent.dragInitiator.acceptedDrop(_strand, "object"); + } + + if (dataProviderModel is ISelectionModel) { + (dataProviderModel as ISelectionModel).selectedIndex = targetIndex; + } + + // is this event necessary? isn't "complete" enough? + sendStrandEvent(_strand,"dragDropAccepted"); + sendEvent(this,"complete"); + } + + COMPILE::SWF + private function displayDropIndicator(item:IUIBase):void + { + var pt0:Point; + var pt1:Point; + var pt2:Point; + + if (dropDirection == "horizontal") { + pt0 = new Point(0, item.y+item.height); + pt1 = PointUtils.localToGlobal(pt0, item.parent); + pt2 = PointUtils.globalToLocal(pt1, indicatorParent); + _dropIndicator.x = 0; + _dropIndicator.y = pt2.y - 1; + } + else { + pt0 = new Point(item.x, 0); + pt1 = PointUtils.localToGlobal(pt0, item.parent); + pt2 = PointUtils.globalToLocal(pt1, indicatorParent); + _dropIndicator.x = pt2.x - 1; + _dropIndicator.y = 0; + } + } + + COMPILE::JS + private function displayDropIndicator(item:IUIBase):void + { + var pt:Point = PointUtils.localToGlobal(new Point(0,0), item); + pt = PointUtils.globalToLocal(pt,indicatorParent); + if (dropDirection == "horizontal") { + _dropIndicator.x = 0; + _dropIndicator.y = pt.y; + } else { + _dropIndicator.x = pt.x; + _dropIndicator.y = 0; + } + } + } +} diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/listClasses/ListBase.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/listClasses/ListBase.as index 361a74bcd7..312e17e336 100644 --- a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/listClasses/ListBase.as +++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/listClasses/ListBase.as @@ -179,6 +179,27 @@ use namespace mx_internal; { return null; } + + /** + * @private + */ + protected function setDropEnabled():void + { + } + + /** + * @private + */ + protected function setDragMoveEnabled():void + { + } + + /** + * @private + */ + protected function setDragEnabled():void + { + } //---------------------------------- // dragEnabled //---------------------------------- @@ -215,6 +236,10 @@ use namespace mx_internal; public function set dragEnabled(value:Boolean):void { _dragEnabled = value; + if (value) + { + setDragEnabled(); + } } //---------------------------------- @@ -257,6 +282,10 @@ use namespace mx_internal; public function set dragMoveEnabled(value:Boolean):void { _dragMoveEnabled = value; + if (value) + { + setDragMoveEnabled(); + } } @@ -424,6 +453,10 @@ use namespace mx_internal; public function set dropEnabled(value:Boolean):void { _dropEnabled = value; + if (value) + { + setDropEnabled(); + } } //----------------------------------