diff options
12 files changed, 277 insertions, 107 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/DropFeedback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/DropFeedback.java index 9926571..232ab5b 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/DropFeedback.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/DropFeedback.java @@ -87,6 +87,17 @@ public class DropFeedback { public boolean isCopy; /** + * The bounds of the drag, relative to the starting mouse position. For example, if + * you have a rectangular view of size 100x80, and you start dragging at position + * (15,20) from the top left corner of this rectangle, then the drag bounds would be + * (-15,-20, 100x80). + * <p> + * NOTE: The coordinate units will be in layout/view coordinates. In other words, they + * are unaffected by the canvas zoom. + */ + public Rect dragBounds; + + /** * Set to true when the drag'n'drop starts and ends in the same canvas of the * same Eclipse instance. * <p/> @@ -95,6 +106,12 @@ public class DropFeedback { public boolean sameCanvas; /** + * Density scale for pixels. To compute the dip (device independent pixel) in the + * view from a layout coordinate, apply this scale. + */ + public double dipScale = 1.0; + + /** * Initializes the drop feedback with the given user data and paint * callback. A paint is requested if the paint callback is non-null. * diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java index ffa43d9..559c3bf 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java @@ -86,8 +86,8 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { // At least the first element has a bound. Draw rectangles // for all dropped elements with valid bounds, offset at // the drop point. - int offsetX = x - be.x - be.w / 2; - int offsetY = y - be.y - be.h / 2; + int offsetX = x - be.x + (feedback.dragBounds != null ? feedback.dragBounds.x : 0); + int offsetY = y - be.y + (feedback.dragBounds != null ? feedback.dragBounds.y : 0); gc.useStyle(DrawingStyle.DROP_PREVIEW); for (IDragElement element : elements) { drawElement(gc, element, offsetX, offsetY); @@ -152,8 +152,11 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { // Copy all the attributes, modifying them as needed. addAttributes(newChild, element, idMap, DEFAULT_ATTR_FILTER); - int x = p.x - b.x - (be.isValid() ? be.w / 2 : 0); - int y = p.y - b.y - (be.isValid() ? be.h / 2 : 0); + int deltaX = (feedback.dragBounds != null ? feedback.dragBounds.x : 0); + int deltaY = (feedback.dragBounds != null ? feedback.dragBounds.y : 0); + + int x = p.x - b.x + deltaX; + int y = p.y - b.y + deltaY; if (first) { first = false; @@ -168,6 +171,12 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { y += be.isValid() ? be.h : 10; } + double scale = feedback.dipScale; + if (scale != 1.0) { + x *= scale; + y *= scale; + } + newChild.setAttribute(ANDROID_URI, "layout_x", //$NON-NLS-1$ x + "dip"); //$NON-NLS-1$ newChild.setAttribute(ANDROID_URI, "layout_y", //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java index 1bc511b..5b90c7f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java @@ -68,6 +68,25 @@ public class LayoutConstants { public static final String VALUE_TRUE = "true"; //$NON-NLS-1$ public static final String VALUE_N_DIP = "%ddip"; //$NON-NLS-1$ + public static final String VALUE_CENTER_VERTICAL = "centerVertical"; //$NON-NLS-1$ + public static final String VALUE_CENTER_IN_PARENT = "centerInParent"; //$NON-NLS-1$ + public static final String VALUE_CENTER_HORIZONTAL = "centerHorizontal"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_PARENT_RIGHT = "alignParentRight"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_PARENT_LEFT = "alignParentLeft"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_PARENT_BOTTOM = "alignParentBottom"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_PARENT_TOP = "alignParentTop"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_RIGHT = "alignRight"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_LEFT = "alignLeft"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_BOTTOM = "alignBottom"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_TOP = "alignTop"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_BASELINE = "alignBaseline"; //$NON-NLS-1$ + public static final String VAUE_TO_RIGHT_OF = "toRightOf"; //$NON-NLS-1$ + public static final String VALUE_TO_LEFT_OF = "toLeftOf"; //$NON-NLS-1$ + public static final String VALUE_BELOW = "below"; //$NON-NLS-1$ + public static final String VALUE_ABOVE = "above"; //$NON-NLS-1$ + public static final String VALUE_ALIGN_WITH_PARENT_MISSING = + "alignWithParentMissing"; //$NON-NLS-1$ + /** * Namespace for the Android resource XML, i.e. * "http://schemas.android.com/apk/res/android" diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java index bf708a3..15d18fc 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java @@ -18,20 +18,37 @@ package com.android.ide.common.layout; import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ABOVE; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_BASELINE; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_BOTTOM; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_LEFT; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_PARENT_BOTTOM; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_PARENT_LEFT; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_PARENT_RIGHT; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_PARENT_TOP; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_RIGHT; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_TOP; +import static com.android.ide.common.layout.LayoutConstants.VALUE_ALIGN_WITH_PARENT_MISSING; +import static com.android.ide.common.layout.LayoutConstants.VALUE_BELOW; +import static com.android.ide.common.layout.LayoutConstants.VALUE_CENTER_HORIZONTAL; +import static com.android.ide.common.layout.LayoutConstants.VALUE_CENTER_IN_PARENT; +import static com.android.ide.common.layout.LayoutConstants.VALUE_CENTER_VERTICAL; +import static com.android.ide.common.layout.LayoutConstants.VALUE_TO_LEFT_OF; +import static com.android.ide.common.layout.LayoutConstants.VAUE_TO_RIGHT_OF; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IAttributeInfo; -import com.android.ide.common.api.IAttributeInfo.Format; import com.android.ide.common.api.IDragElement; import com.android.ide.common.api.IFeedbackPainter; import com.android.ide.common.api.IGraphics; import com.android.ide.common.api.INode; -import com.android.ide.common.api.INode.IAttribute; import com.android.ide.common.api.INodeHandler; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.Point; import com.android.ide.common.api.Rect; +import com.android.ide.common.api.IAttributeInfo.Format; +import com.android.ide.common.api.INode.IAttribute; import java.util.ArrayList; import java.util.Collections; @@ -52,23 +69,23 @@ public class RelativeLayoutRule extends BaseLayoutRule { @Override public List<String> getSelectionHint(INode parentNode, INode childNode) { List<String> infos = new ArrayList<String>(18); - addAttr("above", childNode, infos); //$NON-NLS-1$ - addAttr("below", childNode, infos); //$NON-NLS-1$ - addAttr("toLeftOf", childNode, infos); //$NON-NLS-1$ - addAttr("toRightOf", childNode, infos); //$NON-NLS-1$ - addAttr("alignBaseline", childNode, infos); //$NON-NLS-1$ - addAttr("alignTop", childNode, infos); //$NON-NLS-1$ - addAttr("alignBottom", childNode, infos); //$NON-NLS-1$ - addAttr("alignLeft", childNode, infos); //$NON-NLS-1$ - addAttr("alignRight", childNode, infos); //$NON-NLS-1$ - addAttr("alignParentTop", childNode, infos); //$NON-NLS-1$ - addAttr("alignParentBottom", childNode, infos); //$NON-NLS-1$ - addAttr("alignParentLeft", childNode, infos); //$NON-NLS-1$ - addAttr("alignParentRight", childNode, infos); //$NON-NLS-1$ - addAttr("alignWithParentMissing", childNode, infos); //$NON-NLS-1$ - addAttr("centerHorizontal", childNode, infos); //$NON-NLS-1$ - addAttr("centerInParent", childNode, infos); //$NON-NLS-1$ - addAttr("centerVertical", childNode, infos); //$NON-NLS-1$ + addAttr(VALUE_ABOVE, childNode, infos); + addAttr(VALUE_BELOW, childNode, infos); + addAttr(VALUE_TO_LEFT_OF, childNode, infos); + addAttr(VAUE_TO_RIGHT_OF, childNode, infos); + addAttr(VALUE_ALIGN_BASELINE, childNode, infos); + addAttr(VALUE_ALIGN_TOP, childNode, infos); + addAttr(VALUE_ALIGN_BOTTOM, childNode, infos); + addAttr(VALUE_ALIGN_LEFT, childNode, infos); + addAttr(VALUE_ALIGN_RIGHT, childNode, infos); + addAttr(VALUE_ALIGN_PARENT_TOP, childNode, infos); + addAttr(VALUE_ALIGN_PARENT_BOTTOM, childNode, infos); + addAttr(VALUE_ALIGN_PARENT_LEFT, childNode, infos); + addAttr(VALUE_ALIGN_PARENT_RIGHT, childNode, infos); + addAttr(VALUE_ALIGN_WITH_PARENT_MISSING, childNode, infos); + addAttr(VALUE_CENTER_HORIZONTAL, childNode, infos); + addAttr(VALUE_CENTER_IN_PARENT, childNode, infos); + addAttr(VALUE_CENTER_VERTICAL, childNode, infos); return infos; } @@ -185,8 +202,7 @@ public class RelativeLayoutRule extends BaseLayoutRule { data.setIndex(-1); data.setCurr(null); - DropZone zone = computeBorderDropZone(targetNode.getBounds(), p); - + DropZone zone = computeBorderDropZone(targetNode, p, feedback); if (zone == null) { data.setZones(null); } else { @@ -207,6 +223,24 @@ public class RelativeLayoutRule extends BaseLayoutRule { break; } } + + // Look to see if there's a border match if we didn't find anything better; + // a border match isn't required to have the mouse cursor within it since we + // do edge matching in the code which -adds- the border zones. + if (currZone == null && feedback.dragBounds != null) { + for (DropZone zone : data.getZones()) { + if (zone.isBorderZone()) { + currZone = zone; + break; + } + } + } + } + + // Look for border match when there are no children: always offer one in this case + if (currZone == null && targetNode.getChildren().length == 0 && data.getZones() != null + && data.getZones().size() > 0) { + currZone = data.getZones().get(0); } if (currZone != data.getCurr()) { @@ -286,7 +320,8 @@ public class RelativeLayoutRule extends BaseLayoutRule { return ids; } - private DropZone computeBorderDropZone(Rect bounds, Point p) { + private DropZone computeBorderDropZone(INode targetNode, Point p, DropFeedback feedback) { + Rect bounds = targetNode.getBounds(); int x = p.x; int y = p.y; @@ -297,34 +332,50 @@ public class RelativeLayoutRule extends BaseLayoutRule { int x2 = x1 + w; int y2 = y1 + h; + // Default border zone size int n = 10; - int n2 = n * 2; + int n2 = 2*n; + + // Size of -matched- border zone (not painted, but we detect edge overlaps here) + int hn = 0; + int vn = 0; + if (feedback.dragBounds != null) { + hn = feedback.dragBounds.w / 2; + vn = feedback.dragBounds.h / 2; + } boolean vertical = false; Rect r = null; String attr = null; - if (x <= x1 + n && y >= y1 && y <= y2) { + if (x <= x1 + n + hn && y >= y1 && y <= y2) { r = new Rect(x1 - n, y1, n2, h); - attr = "alignParentLeft"; //$NON-NLS-1$ + attr = VALUE_ALIGN_PARENT_LEFT; vertical = true; - } else if (x >= x2 - n && y >= y1 && y <= y2) { + } else if (x >= x2 - hn - n && y >= y1 && y <= y2) { r = new Rect(x2 - n, y1, n2, h); - attr = "alignParentRight"; //$NON-NLS-1$ + attr = VALUE_ALIGN_PARENT_RIGHT; vertical = true; - } else if (y <= y1 + n && x >= x1 && x <= x2) { + } else if (y <= y1 + n + vn && x >= x1 && x <= x2) { r = new Rect(x1, y1 - n, w, n2); - attr = "alignParentTop"; //$NON-NLS-1$ + attr = VALUE_ALIGN_PARENT_TOP; - } else if (y >= y2 - n && x >= x1 && x <= x2) { + } else if (y >= y2 - vn - n && x >= x1 && x <= x2) { r = new Rect(x1, y2 - n, w, n2); - attr = "alignParentBottom"; //$NON-NLS-1$ + attr = VALUE_ALIGN_PARENT_BOTTOM; } else { - // we're nowhere near a border - return null; + // We're nowhere near a border. + // If there are no children, we will offer one anyway: + if (targetNode.getChildren().length == 0) { + r = new Rect(x1 - n, y1, n2, h); + attr = VALUE_ALIGN_PARENT_LEFT; + vertical = true; + } else { + return null; + } } return new DropZone(r, Collections.singletonList(attr), r.getCenter(), vertical); @@ -371,41 +422,41 @@ public class RelativeLayoutRule extends BaseLayoutRule { Rect bounds = new Rect(x1, y1, wt, ht); List<DropZone> zones = new ArrayList<DropZone>(16); - String a = "above"; //$NON-NLS-1$ + String a = VALUE_ABOVE; int x = x1; int y = y1; - x = addx(w1, a, x, y, h1, zones, "toLeftOf"); //$NON-NLS-1$ - x = addx(w2, a, x, y, h1, zones, "alignLeft"); //$NON-NLS-1$ - x = addx(w2, a, x, y, h1, zones, "alignLeft", "alignRight"); //$NON-NLS-1$ //$NON-NLS-2$ - x = addx(w2, a, x, y, h1, zones, "alignRight"); //$NON-NLS-1$ - x = addx(w1, a, x, y, h1, zones, "toRightOf"); //$NON-NLS-1$ + x = addx(w1, a, x, y, h1, zones, VALUE_TO_LEFT_OF); + x = addx(w2, a, x, y, h1, zones, VALUE_ALIGN_LEFT); + x = addx(w2, a, x, y, h1, zones, VALUE_ALIGN_LEFT, VALUE_ALIGN_RIGHT); + x = addx(w2, a, x, y, h1, zones, VALUE_ALIGN_RIGHT); + x = addx(w1, a, x, y, h1, zones, VAUE_TO_RIGHT_OF); - a = "below"; //$NON-NLS-1$ + a = VALUE_BELOW; x = x1; y = y1 + ht - h1; - x = addx(w1, a, x, y, h1, zones, "toLeftOf"); //$NON-NLS-1$ - x = addx(w2, a, x, y, h1, zones, "alignLeft"); //$NON-NLS-1$ - x = addx(w2, a, x, y, h1, zones, "alignLeft", "alignRight"); //$NON-NLS-1$ //$NON-NLS-2$ - x = addx(w2, a, x, y, h1, zones, "alignRight"); //$NON-NLS-1$ - x = addx(w1, a, x, y, h1, zones, "toRightOf"); //$NON-NLS-1$ + x = addx(w1, a, x, y, h1, zones, VALUE_TO_LEFT_OF); + x = addx(w2, a, x, y, h1, zones, VALUE_ALIGN_LEFT); + x = addx(w2, a, x, y, h1, zones, VALUE_ALIGN_LEFT, VALUE_ALIGN_RIGHT); + x = addx(w2, a, x, y, h1, zones, VALUE_ALIGN_RIGHT); + x = addx(w1, a, x, y, h1, zones, VAUE_TO_RIGHT_OF); - a = "toLeftOf"; //$NON-NLS-1$ + a = VALUE_TO_LEFT_OF; x = x1; y = y1 + h1; - y = addy(h2, a, x, y, w1, zones, "alignTop"); //$NON-NLS-1$ - y = addy(h2, a, x, y, w1, zones, "alignTop", "alignBottom"); //$NON-NLS-1$ //$NON-NLS-2$ - y = addy(h2, a, x, y, w1, zones, "alignBottom"); //$NON-NLS-1$ + y = addy(h2, a, x, y, w1, zones, VALUE_ALIGN_TOP); + y = addy(h2, a, x, y, w1, zones, VALUE_ALIGN_TOP, VALUE_ALIGN_BOTTOM); + y = addy(h2, a, x, y, w1, zones, VALUE_ALIGN_BOTTOM); - a = "toRightOf"; //$NON-NLS-1$ + a = VAUE_TO_RIGHT_OF; x = x1 + wt - w1; y = y1 + h1; - y = addy(h2, a, x, y, w1, zones, "alignTop"); //$NON-NLS-1$ - y = addy(h2, a, x, y, w1, zones, "alignTop", "alignBottom"); //$NON-NLS-1$ //$NON-NLS-2$ - y = addy(h2, a, x, y, w1, zones, "alignBottom"); //$NON-NLS-1$ + y = addy(h2, a, x, y, w1, zones, VALUE_ALIGN_TOP); + y = addy(h2, a, x, y, w1, zones, VALUE_ALIGN_TOP, VALUE_ALIGN_BOTTOM); + y = addy(h2, a, x, y, w1, zones, VALUE_ALIGN_BOTTOM); return Pair.of(bounds, zones); } @@ -511,20 +562,20 @@ public class RelativeLayoutRule extends BaseLayoutRule { int offsetX = x - be.x; int offsetY = y - be.y; - if (data.getCurr().getAttr().contains("alignTop") //$NON-NLS-1$ - && data.getCurr().getAttr().contains("alignBottom")) { //$NON-NLS-1$ + if (data.getCurr().getAttr().contains(VALUE_ALIGN_TOP) + && data.getCurr().getAttr().contains(VALUE_ALIGN_BOTTOM)) { offsetY -= be.h / 2; - } else if (data.getCurr().getAttr().contains("above") //$NON-NLS-1$ - || data.getCurr().getAttr().contains("alignTop") //$NON-NLS-1$ - || data.getCurr().getAttr().contains("alignParentBottom")) { //$NON-NLS-1$ + } else if (data.getCurr().getAttr().contains(VALUE_ABOVE) + || data.getCurr().getAttr().contains(VALUE_ALIGN_TOP) + || data.getCurr().getAttr().contains(VALUE_ALIGN_PARENT_BOTTOM)) { offsetY -= be.h; } - if (data.getCurr().getAttr().contains("alignRight") //$NON-NLS-1$ - && data.getCurr().getAttr().contains("alignLeft")) { //$NON-NLS-1$ + if (data.getCurr().getAttr().contains(VALUE_ALIGN_RIGHT) + && data.getCurr().getAttr().contains(VALUE_ALIGN_LEFT)) { offsetX -= be.w / 2; - } else if (data.getCurr().getAttr().contains("toLeftOft") //$NON-NLS-1$ - || data.getCurr().getAttr().contains("alignLeft") //$NON-NLS-1$ - || data.getCurr().getAttr().contains("alignParentRight")) { //$NON-NLS-1$ + } else if (data.getCurr().getAttr().contains(VALUE_TO_LEFT_OF) + || data.getCurr().getAttr().contains(VALUE_ALIGN_LEFT) + || data.getCurr().getAttr().contains(VALUE_ALIGN_PARENT_RIGHT)) { offsetX -= be.w; } @@ -719,5 +770,9 @@ public class RelativeLayoutRule extends BaseLayoutRule { private boolean isVertical() { return mVertical; } + + private boolean isBorderZone() { + return mMark != null; + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DynamicContextMenu.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DynamicContextMenu.java index d702255..0875642 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DynamicContextMenu.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DynamicContextMenu.java @@ -24,7 +24,6 @@ import com.android.ide.eclipse.adt.internal.editors.IconFactory; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference; import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy; -import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -425,10 +424,11 @@ import java.util.regex.Pattern; IMenuCallback c = ((MenuAction.Action) a2).getCallback(); if (c != null) { try { - c.action(a2, null /* no valueId for a toggle */, !isChecked); + c.action(a2, null /* no valueId for a toggle */, + !isChecked); } catch (Exception e) { - RulesEngine gre = mCanvas.getRulesEngine(); - gre.logError("XML edit operation failed: %s", e.toString()); + AdtPlugin.log(e, "XML edit operation failed: %s", + e.toString()); } } } @@ -488,8 +488,8 @@ import java.util.regex.Pattern; // Values do not apply for plain actions c.action(a2, null /* valueId */, null /* newValue */); } catch (Exception e) { - RulesEngine gre = mCanvas.getRulesEngine(); - gre.logError("XML edit operation failed: %s", e.toString()); + AdtPlugin.log(e, "XML edit operation failed: %s", + e.toString()); } } } @@ -614,8 +614,8 @@ import java.util.regex.Pattern; ((MenuAction.Action) a2).getCallback().action(a2, key, !isChecked); } catch (Exception e) { - RulesEngine gre = mCanvas.getRulesEngine(); - gre.logError("XML edit operation failed: %s", e.toString()); + AdtPlugin.log(e, "XML edit operation failed: %s", + e.toString()); } } } 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 d3a7820..314719a 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 @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.ide.common.api.Rect; + import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; @@ -612,6 +614,16 @@ public class GestureManager { int deltaX = (int) (scale * (boundingBox.x - p.x)); int deltaY = (int) (scale * (boundingBox.y - p.y)); SwtUtils.setDragImageOffsets(e, -deltaX, -deltaY); + + // View rules may need to know it as well + GlobalCanvasDragInfo dragInfo = GlobalCanvasDragInfo.getInstance(); + Rect dragBounds = null; + if (dragInfo != null) { + int width = (int) (scale * boundingBox.width); + int height = (int) (scale * boundingBox.height); + dragBounds = new Rect(deltaX, deltaY, width, height); + dragInfo.setDragBounds(dragBounds); + } } } } 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 3fd98a3..9315967 100755 --- 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.ide.common.api.Rect; + /** * This singleton is used to keep track of drag'n'drops initiated within this @@ -43,6 +45,7 @@ final class GlobalCanvasDragInfo { private SelectionItem[] mCurrentSelection; private Object mSourceCanvas = null; private Runnable mRemoveSourceHandler; + private Rect mDragBounds; /** Private constructor. Use {@link #getInstance()} to retrieve the singleton. */ private GlobalCanvasDragInfo() { @@ -114,4 +117,30 @@ final class GlobalCanvasDragInfo { mRemoveSourceHandler = null; } } + + /** + * Get the bounds of the drag, relative to the starting mouse position. For example, + * if you have a rectangular view of size 100x80, and you start dragging at position + * (15,20) from the top left corner of this rectangle, then the drag bounds would be + * (-15,-20, 100x80). + * <p> + * NOTE: The coordinate units will be in SWT/control pixels, not Android view pixels. + * In other words, they are affected by the canvas zoom: If you zoom the view and the + * bounds of a view grow, the drag bounds will be larger. + * + * @return the drag bounds, or null if there are no bounds for the current drag + */ + public Rect getDragBounds() { + return mDragBounds; + } + + /** + * Set the bounds of the drag, relative to the starting mouse position. See + * {@link #getDragBounds()} for details on the semantics of the drag bounds. + * + * @param dragBounds the new drag bounds, or null if there are no drag bounds + */ + public void setDragBounds(Rect dragBounds) { + mDragBounds = dragBounds; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java index ede9115..cce6c2a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import static com.android.sdklib.resources.Density.DEFAULT_DENSITY; + import com.android.ide.common.layoutlib.BasicLayoutScene; import com.android.ide.common.layoutlib.LayoutLibrary; import com.android.ide.common.sdk.LoadStatus; @@ -1176,7 +1178,15 @@ public class GraphicalEditorPart extends EditorPart return mConfigComposite.getScreenBounds(); } - + /** + * Returns the scale to multiply pixels in the layout coordinate space with to obtain + * the corresponding dip (device independent pixel) + * + * @return the scale to multiple layout coordinates with to obtain the dip position + */ + public float getDipScale() { + return DEFAULT_DENSITY / (float) mConfigComposite.getDensity().getDpiValue(); + } // --- private methods --- diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java index f047cbc..863b250 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java @@ -446,6 +446,28 @@ public class MoveGesture extends DropGesture { } df.sameCanvas = mCanvas == mGlobalDragInfo.getSourceCanvas(); df.invalidTarget = false; + df.dipScale = mCanvas.getLayoutEditor().getGraphicalEditor().getDipScale(); + + // Set the drag bounds, after converting it from control coordinates to + // layout coordinates + GlobalCanvasDragInfo dragInfo = GlobalCanvasDragInfo.getInstance(); + Rect dragBounds = null; + if (dragInfo != null) { + Rect controlDragBounds = dragInfo.getDragBounds(); + if (controlDragBounds != null) { + CanvasTransform ht = mCanvas.getHorizontalTransform(); + CanvasTransform vt = mCanvas.getVerticalTransform(); + double horizScale = ht.getScale(); + double verticalScale = vt.getScale(); + int x = (int) (controlDragBounds.x / horizScale); + int y = (int) (controlDragBounds.y / verticalScale); + int w = (int) (controlDragBounds.w / horizScale); + int h = (int) (controlDragBounds.h / verticalScale); + + dragBounds = new Rect(x, y, w, h); + } + } + df.dragBounds = dragBounds; } /** @@ -560,6 +582,7 @@ public class MoveGesture extends DropGesture { // guideline computations in onDropMove (since only onDropMove is handed // the -position- of the mouse), and we want this computation to happen // before we ask the view to draw its feedback. + updateDropFeedback(df, event); df = mCanvas.getRulesEngine().callOnDropMove(targetNode, mCurrentDragElements, df, new Point(p.x, p.y)); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java index f5aaeed..e3bbd00 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java @@ -510,12 +510,16 @@ public class PaletteComposite extends Composite { Rect bounds = null; DragSource dragSource = mItem.getDragSource(); DragSourceEffect dragSourceEffect = dragSource.getDragSourceEffect(); + Rect dragBounds = null; if (dragSourceEffect instanceof PreviewDragSourceEffect) { PreviewDragSourceEffect preview = (PreviewDragSourceEffect) dragSourceEffect; Image previewImage = preview.getPreviewImage(); if (previewImage != null && !preview.isPlaceholder()) { ImageData data = previewImage.getImageData(); - bounds = new Rect(0, 0, data.width, data.height); + int width = data.width; + int height = data.height; + bounds = new Rect(0, 0, width, height); + dragBounds = new Rect(-width / 2, -height / 2, width, height); } } @@ -527,11 +531,13 @@ public class PaletteComposite extends Composite { mElements = new SimpleElement[] { se }; // Register this as the current dragged data - GlobalCanvasDragInfo.getInstance().startDrag( + GlobalCanvasDragInfo dragInfo = GlobalCanvasDragInfo.getInstance(); + dragInfo.startDrag( mElements, null /* selection */, null /* canvas */, null /* removeSource */); + dragInfo.setDragBounds(dragBounds); } public void dragSetData(DragSourceEvent e) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java index ff6cbfe..ae894e6 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java @@ -192,7 +192,7 @@ public class RulesEngine { return rule.getDisplayName(); } catch (Exception e) { - logError("%s.getDisplayName() failed: %s", + AdtPlugin.log(e, "%s.getDisplayName() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -218,7 +218,7 @@ public class RulesEngine { return rule.getContextMenu(selectedNode); } catch (Exception e) { - logError("%s.getContextMenu() failed: %s", + AdtPlugin.log(e, "%s.getContextMenu() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -244,7 +244,7 @@ public class RulesEngine { return rule.getSelectionHint(parentNode, childNode); } catch (Exception e) { - logError("%getSelectionHint() failed: %s", + AdtPlugin.log(e, "%getSelectionHint() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -269,7 +269,7 @@ public class RulesEngine { return rule.onDropEnter(targetNode, elements); } catch (Exception e) { - logError("%s.onDropEnter() failed: %s", + AdtPlugin.log(e, "%s.onDropEnter() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -295,7 +295,7 @@ public class RulesEngine { return rule.onDropMove(targetNode, elements, feedback, where); } catch (Exception e) { - logError("%s.onDropMove() failed: %s", + AdtPlugin.log(e, "%s.onDropMove() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -318,7 +318,7 @@ public class RulesEngine { rule.onDropLeave(targetNode, elements, feedback); } catch (Exception e) { - logError("%s.onDropLeave() failed: %s", + AdtPlugin.log(e, "%s.onDropLeave() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -342,7 +342,7 @@ public class RulesEngine { rule.onDropped(targetNode, elements, feedback, where); } catch (Exception e) { - logError("%s.onDropped() failed: %s", + AdtPlugin.log(e, "%s.onDropped() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -359,7 +359,7 @@ public class RulesEngine { try { feedback.painter.paint(gc, targetNode, feedback); } catch (Exception e) { - logError("DropFeedback.painter failed: %s", + AdtPlugin.log(e, "DropFeedback.painter failed: %s", e.toString()); } } @@ -381,7 +381,7 @@ public class RulesEngine { rule.onPaste(targetNode, pastedElements); } catch (Exception e) { - logError("%s.onPaste() failed: %s", + AdtPlugin.log(e, "%s.onPaste() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -490,7 +490,7 @@ public class RulesEngine { try { rule.onDispose(); } catch (Exception e) { - logError("%s.onDispose() failed: %s", + AdtPlugin.log(e, "%s.onDispose() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -649,10 +649,10 @@ public class RulesEngine { // class. } catch (InstantiationException e) { // This is NOT an expected error: fail. - logError("load rule error (%s): %s", realFqcn, e.toString()); + AdtPlugin.log(e, "load rule error (%s): %s", realFqcn, e.toString()); } catch (IllegalAccessException e) { // This is NOT an expected error: fail. - logError("load rule error (%s): %s", realFqcn, e.toString()); + AdtPlugin.log(e, "load rule error (%s): %s", realFqcn, e.toString()); } // Memorize in the cache that we couldn't find a rule for this real FQCN @@ -687,7 +687,7 @@ public class RulesEngine { rule.onDispose(); } } catch (Exception e) { - logError("%s.onInit() failed: %s", + AdtPlugin.log(e, "%s.onInit() failed: %s", rule.getClass().getSimpleName(), e.toString()); } @@ -696,18 +696,6 @@ public class RulesEngine { } /** - * Logs an error to the console. - * - * @param format A format string following the format specified by - * {@link String#format} - * @param params An optional set of parameters to the format string - */ - public void logError(String format, Object...params) { - String s = String.format(format, params); - AdtPlugin.printErrorToConsole(mProject, s); - } - - /** * Implementation of {@link IClientRulesEngine}. This provide {@link IViewRule} clients * with a few methods they can use to use functionality from this {@link RulesEngine}. */ @@ -750,7 +738,7 @@ public class RulesEngine { try { return filter.validate(newText); } catch (Exception e) { - logError("Custom validator failed: %s", e.toString()); + AdtPlugin.log(e, "Custom validator failed: %s", e.toString()); return ""; //$NON-NLS-1$ } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java index a6d6384..f4092eb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java @@ -52,14 +52,16 @@ public class AbsoluteLayoutRuleTest extends LayoutTestBase { 4, // Not dragging one of the existing children -1, + + // Bounds rectangle "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])", // Drop preview - "useStyle(DROP_PREVIEW), drawRect(Rect[-22,-50,105,80])"); + "useStyle(DROP_PREVIEW), drawRect(Rect[30,-10,105,80])"); - assertEquals("-22dip", inserted.getStringAttr(ANDROID_URI, "layout_x")); - assertEquals("-50dip", inserted.getStringAttr(ANDROID_URI, "layout_y")); + assertEquals("30dip", inserted.getStringAttr(ANDROID_URI, "layout_x")); + assertEquals("-10dip", inserted.getStringAttr(ANDROID_URI, "layout_y")); // Without drag bounds we should just draw guide lines instead inserted = dragInto(new Rect(0, 0, 0, 0), new Point(30, -10), 4, -1, |