diff options
9 files changed, 126 insertions, 18 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java index 04373e1..a1571e2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java @@ -304,8 +304,9 @@ public class LinearLayoutRule extends BaseLayoutRule { for (IDragElement element : elements) { // This tries to determine if an INode corresponds to an // IDragElement, by comparing their bounds. - if (bc.equals(element.getBounds())) { + if (element.isSame(it)) { isDragged = true; + break; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java index d8a45b6..e2c1d5e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java @@ -717,6 +717,7 @@ public class GestureManager { // operation. List<SelectionItem> selections = selectionManager.getSelections(); mDragSelection.clear(); + SelectionItem primary = null; if (!selections.isEmpty()) { // Is the cursor on top of a selected element? @@ -724,6 +725,7 @@ public class GestureManager { for (SelectionItem cs : selections) { if (!cs.isRoot() && cs.getRect().contains(p.x, p.y)) { + primary = cs; insideSelection = true; break; } @@ -732,7 +734,7 @@ public class GestureManager { if (!insideSelection) { CanvasViewInfo vi = mCanvas.getViewHierarchy().findViewInfoAt(p); if (vi != null && !vi.isRoot() && !vi.isHidden()) { - selectionManager.selectSingle(vi); + primary = selectionManager.selectSingle(vi); insideSelection = true; } } @@ -753,6 +755,8 @@ public class GestureManager { for (SelectionItem cs : selections) { if (!cs.isRoot() && !cs.isHidden()) { mDragSelection.add(cs); + } else if (cs == primary) { + primary = null; } } } @@ -763,7 +767,7 @@ public class GestureManager { if (mDragSelection.isEmpty()) { CanvasViewInfo vi = mCanvas.getViewHierarchy().findViewInfoAt(p); if (vi != null && !vi.isRoot() && !vi.isHidden()) { - selectionManager.selectSingle(vi); + primary = selectionManager.selectSingle(vi); mDragSelection.addAll(selections); } } @@ -773,7 +777,7 @@ public class GestureManager { e.doit = !mDragSelection.isEmpty(); int imageCount = mDragSelection.size(); if (e.doit) { - mDragElements = SelectionItem.getAsElements(mDragSelection); + mDragElements = SelectionItem.getAsElements(mDragSelection, primary); GlobalCanvasDragInfo.getInstance().startDrag(mDragElements, mDragSelection.toArray(new SelectionItem[imageCount]), mCanvas, new Runnable() { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GlobalCanvasDragInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GlobalCanvasDragInfo.java index 06986cd..b918b00 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GlobalCanvasDragInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GlobalCanvasDragInfo.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.Rect; @@ -63,6 +65,10 @@ final class GlobalCanvasDragInfo { * Registers the XML elements being dragged. * * @param elements The elements being dragged + * @param primary the "primary" element among the elements; when there is a + * single item dragged this will be the same, but in + * multi-selection it will be the element under the mouse as the + * selection was initiated * @param selection The selection (which can be null, for example when the * user drags from the palette) * @param sourceCanvas An object representing the source we are dragging @@ -71,8 +77,11 @@ final class GlobalCanvasDragInfo { * source. It should only be invoked if the drag operation is a * move, not a copy. */ - public void startDrag(SimpleElement[] elements, SelectionItem[] selection, - Object sourceCanvas, Runnable removeSourceHandler) { + public void startDrag( + @NonNull SimpleElement[] elements, + @Nullable SelectionItem[] selection, + @Nullable Object sourceCanvas, + @Nullable Runnable removeSourceHandler) { mCurrentElements = elements; mCurrentSelection = selection; mSourceCanvas = sourceCanvas; @@ -93,6 +102,7 @@ final class GlobalCanvasDragInfo { } /** Returns the elements being dragged. */ + @NonNull public SimpleElement[] getCurrentElements() { return mCurrentElements; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java index 5d49426..d104e37 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java @@ -169,13 +169,39 @@ class SelectionItem { * @return An array of wrapper elements. Never null. */ @NonNull - static SimpleElement[] getAsElements(List<SelectionItem> items) { - ArrayList<SimpleElement> elements = new ArrayList<SimpleElement>(); + static SimpleElement[] getAsElements(@NonNull List<SelectionItem> items) { + return getAsElements(items, null); + } + + /** + * Returns elements representing the given selection of canvas items. + * + * @param items Items to wrap in elements + * @param primary The primary selected item which should be listed first + * @return An array of wrapper elements. Never null. + */ + @NonNull + static SimpleElement[] getAsElements( + @NonNull List<SelectionItem> items, + @Nullable SelectionItem primary) { + List<SimpleElement> elements = new ArrayList<SimpleElement>(); + + if (primary != null) { + CanvasViewInfo vi = primary.getViewInfo(); + SimpleElement e = vi.toSimpleElement(); + e.setSelectionItem(primary); + elements.add(e); + } for (SelectionItem cs : items) { - CanvasViewInfo vi = cs.getViewInfo(); + if (cs == primary) { + // Already handled + continue; + } + CanvasViewInfo vi = cs.getViewInfo(); SimpleElement e = vi.toSimpleElement(); + e.setSelectionItem(cs); elements.add(e); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java index 1450768..dc8a383 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java @@ -21,6 +21,7 @@ import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.Selection import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionHandle.PIXEL_RADIUS; import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.INode; import com.android.ide.common.layout.GridLayoutRule; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; @@ -429,11 +430,15 @@ public class SelectionManager implements ISelectionProvider { /** * Removes all the currently selected item and only select the given item. - * Issues a {@link #redraw()} if the selection changes. + * Issues a redraw() if the selection changes. * * @param vi The new selected item if non-null. Selection becomes empty if null. + * @return the item selected, or null if the selection was cleared (e.g. vi was null) */ - /* package */ void selectSingle(CanvasViewInfo vi) { + @Nullable + SelectionItem selectSingle(CanvasViewInfo vi) { + SelectionItem item = null; + // reset alternate selection if any mAltSelection = null; @@ -449,13 +454,14 @@ public class SelectionManager implements ISelectionProvider { if (!mSelections.isEmpty()) { if (mSelections.size() == 1 && mSelections.getFirst().getViewInfo() == vi) { // CanvasSelection remains the same, don't touch it. - return; + return mSelections.getFirst(); } mSelections.clear(); } if (vi != null) { - mSelections.add(createSelection(vi)); + item = createSelection(vi); + mSelections.add(item); if (vi.isInvisible()) { redoLayout = true; } @@ -467,6 +473,8 @@ public class SelectionManager implements ISelectionProvider { } redraw(); + + return item; } /** Returns true if the view hierarchy is showing exploded items. */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java index 4feff25..9acc8c2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java @@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.api.IDragElement; +import com.android.ide.common.api.INode; import com.android.ide.common.api.Rect; import java.util.ArrayList; @@ -47,6 +48,7 @@ public class SimpleElement implements IDragElement { private IDragAttribute[] mCachedAttributes = null; private IDragElement[] mCachedElements = null; + private SelectionItem mSelectionItem; /** * Creates a new {@link SimpleElement} with the specified element name. @@ -141,6 +143,43 @@ public class SimpleElement implements IDragElement { mElements.add(e); } + @Override + public boolean isSame(@NonNull INode node) { + if (mSelectionItem != null) { + return node == mSelectionItem.getNode(); + } else { + return node.getBounds().equals(mBounds); + } + } + + void setSelectionItem(@Nullable SelectionItem selectionItem) { + mSelectionItem = selectionItem; + } + + @Nullable + SelectionItem getSelectionItem() { + return mSelectionItem; + } + + @Nullable + static SimpleElement findPrimary(SimpleElement[] elements, SelectionItem primary) { + if (elements == null || elements.length == 0) { + return null; + } + + if (elements.length == 1 || primary == null) { + return elements[0]; + } + + for (SimpleElement element : elements) { + if (element.getSelectionItem() == primary) { + return element; + } + } + + return elements[0]; + } + // reader and writer methods @Override diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java index eb0a432..5b55532 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java @@ -21,6 +21,7 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.api.IDragElement; +import com.android.ide.common.api.INode; import com.android.ide.common.api.Rect; import java.util.ArrayList; @@ -150,5 +151,8 @@ public class TestDragElement implements IDragElement { + mRect + "]"; } - + @Override + public boolean isSame(INode node) { + return node.getBounds().equals(getBounds()); + } } diff --git a/rule_api/src/com/android/ide/common/api/IDragElement.java b/rule_api/src/com/android/ide/common/api/IDragElement.java index 885ba35..50a5014 100644 --- a/rule_api/src/com/android/ide/common/api/IDragElement.java +++ b/rule_api/src/com/android/ide/common/api/IDragElement.java @@ -86,6 +86,14 @@ public interface IDragElement { public abstract IDragElement[] getInnerElements(); /** + * Returns true if the given {@link INode} represents this drag element + * + * @param node the node to be checked + * @return true if the given node represents this drag element + */ + public abstract boolean isSame(@NonNull INode node); + + /** * An XML attribute in the {@link IDragElement}. * <p/> * The attribute is always represented by a namespace URI, a name and a value. diff --git a/rule_api/src/com/android/ide/common/api/IViewRule.java b/rule_api/src/com/android/ide/common/api/IViewRule.java index bcf4e89..c115795 100644 --- a/rule_api/src/com/android/ide/common/api/IViewRule.java +++ b/rule_api/src/com/android/ide/common/api/IViewRule.java @@ -161,7 +161,9 @@ public interface IViewRule { * @param targetView the corresponding View object for the target layout, or * null if not known * @param elements an array of {@link IDragElement} element descriptors for - * the dragged views + * the dragged views. When there are more than one element, the + * first element will always be the "primary" element (e.g. the + * one that the mouse is actively dragging.) * @return a {@link DropFeedback} object with drop state (which will be * supplied to a follow-up {@link #onDropMove} call), or null if the * drop should be ignored @@ -178,7 +180,9 @@ public interface IViewRule { * @param targetNode the {@link INode} for the target layout receiving a * drop event * @param elements an array of {@link IDragElement} element descriptors for - * the dragged views + * the dragged views. When there are more than one element, the + * first element will always be the "primary" element (e.g. the + * one that the mouse is actively dragging.) * @param feedback the {@link DropFeedback} object created by * {@link #onDropEnter(INode, Object, IDragElement[])} * @param where the current mouse drag position @@ -211,7 +215,9 @@ public interface IViewRule { * @param targetNode the {@link INode} for the target layout receiving a * drop event * @param elements an array of {@link IDragElement} element descriptors for - * the dragged views + * the dragged views. When there are more than one element, the + * first element will always be the "primary" element (e.g. the + * one that the mouse is actively dragging.) * @param feedback the {@link DropFeedback} object created by * {@link #onDropEnter(INode, Object, IDragElement[])} */ @@ -230,7 +236,9 @@ public interface IViewRule { * @param targetNode the {@link INode} for the target layout receiving a * drop event * @param elements an array of {@link IDragElement} element descriptors for - * the dragged views + * the dragged views. When there are more than one element, the + * first element will always be the "primary" element (e.g. the + * one that the mouse is actively dragging.) * @param feedback the {@link DropFeedback} object created by * {@link #onDropEnter(INode, Object, IDragElement[])} * @param where the mouse drop position |