diff options
author | Tor Norbye <tnorbye@google.com> | 2011-06-06 12:39:25 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-06-06 17:44:18 -0700 |
commit | 628f0f8dcdfaad793a97690a1479ba0f22d8b0ee (patch) | |
tree | 27d36a08b7d4b3a89c5f322dc5423ed05b881ffe | |
parent | 6c770dd7f0e651f9b61b61ce90081d917c6ceeb4 (diff) | |
download | sdk-628f0f8dcdfaad793a97690a1479ba0f22d8b0ee.zip sdk-628f0f8dcdfaad793a97690a1479ba0f22d8b0ee.tar.gz sdk-628f0f8dcdfaad793a97690a1479ba0f22d8b0ee.tar.bz2 |
Guidelines for match_parent, and linear layout weight fixes
First, add guidelines to allow snapping to "match_parent" (or
fill_parent, depending on the API level).
Second, fix the linear layout resizing scheme to handle corner cases a
bit better (corner cases such as resizing to a smaller size than the
wrap_content bounds, or resizing inside a layout that is "full"). Also
split up the resizing code into a compute-method and an apply-method
such that we can display feedback for the current weight during the
resizing operation.
Change-Id: Idd2917230870d26f94473dabc1a2a6becc3ba738
4 files changed, 358 insertions, 156 deletions
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 111434f..de03a19 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 @@ -20,7 +20,6 @@ import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_X; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_Y; import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP; -import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; @@ -239,9 +238,6 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { return String.format("Set bounds to (x = %d, y = %d, width = %s, height = %s)", mRulesEngine.pxToDp(newBounds.x - parentBounds.x), mRulesEngine.pxToDp(newBounds.y - parentBounds.y), - resizeState.wrapWidth ? - VALUE_WRAP_CONTENT : Integer.toString(mRulesEngine.pxToDp(newBounds.w)), - resizeState.wrapHeight ? - VALUE_WRAP_CONTENT : Integer.toString(mRulesEngine.pxToDp(newBounds.h))); + resizeState.getWidthAttribute(), resizeState.getHeightAttribute()); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java index 4e6ea98..fa87fa4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java @@ -28,7 +28,6 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT; import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT; import static com.android.ide.common.layout.LayoutConstants.VALUE_MATCH_PARENT; -import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP; import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import com.android.ide.common.api.DrawingStyle; @@ -44,10 +43,12 @@ import com.android.ide.common.api.INodeHandler; import com.android.ide.common.api.MenuAction; import com.android.ide.common.api.Point; import com.android.ide.common.api.Rect; +import com.android.ide.common.api.Segment; import com.android.ide.common.api.SegmentType; import com.android.ide.common.api.IAttributeInfo.Format; import com.android.ide.common.api.IDragElement.IDragAttribute; import com.android.ide.common.api.MenuAction.ChoiceProvider; +import com.android.ide.common.layout.relative.MarginType; import com.android.sdklib.SdkConstants; import com.android.util.Pair; @@ -575,31 +576,15 @@ public class BaseLayoutRule extends BaseViewRule { // ---- Resizing ---- - /** State held during resizing operations */ - protected static class ResizeState { - /** The proposed resized bounds of the node */ - public Rect bounds; - - /** The preferred wrap_content bounds of the node */ - public Rect wrapBounds; - - /** The type of horizontal edge being resized, or null */ - public SegmentType horizontalEdgeType; - - /** The type of vertical edge being resized, or null */ - public SegmentType verticalEdgeType; - - /** Whether the user has snapped to the wrap_content width */ - public boolean wrapWidth; - - /** Whether the user has snapped to the wrap_content height */ - public boolean wrapHeight; + /** Creates a new {@link ResizeState} object to track resize state */ + protected ResizeState createResizeState(INode layout, INode node) { + return new ResizeState(this, layout, node); } @Override public DropFeedback onResizeBegin(INode child, INode parent, SegmentType horizontalEdge, SegmentType verticalEdge) { - ResizeState state = new ResizeState(); + ResizeState state = createResizeState(parent, child); state.horizontalEdgeType = horizontalEdge; state.verticalEdgeType = verticalEdge; @@ -633,6 +618,17 @@ public class BaseLayoutRule extends BaseViewRule { Rect b = resizeState.bounds; gc.drawRect(b); + if (resizeState.horizontalFillSegment != null) { + gc.useStyle(DrawingStyle.GUIDELINE); + Segment s = resizeState.horizontalFillSegment; + gc.drawLine(s.from, s.at, s.to, s.at); + } + if (resizeState.verticalFillSegment != null) { + gc.useStyle(DrawingStyle.GUIDELINE); + Segment s = resizeState.verticalFillSegment; + gc.drawLine(s.at, s.from, s.at, s.to); + } + if (resizeState.wrapBounds != null) { gc.useStyle(DrawingStyle.GUIDELINE); int wrapWidth = resizeState.wrapBounds.w; @@ -703,7 +699,6 @@ public class BaseLayoutRule extends BaseViewRule { return 20; } - @Override public void onResizeUpdate(DropFeedback feedback, INode child, INode parent, Rect newBounds, int modifierMask) { @@ -735,6 +730,32 @@ public class BaseLayoutRule extends BaseViewRule { } } + // Match on fill bounds + state.horizontalFillSegment = null; + state.fillHeight = false; + if (state.horizontalEdgeType == SegmentType.BOTTOM && !state.wrapHeight) { + Rect parentBounds = parent.getBounds(); + state.horizontalFillSegment = new Segment(parentBounds.y2(), newBounds.x, + newBounds.x2(), + null /*node*/, null /*id*/, SegmentType.BOTTOM, MarginType.NO_MARGIN); + if (Math.abs(newBounds.y2() - parentBounds.y2()) < getMaxMatchDistance()) { + state.fillHeight = true; + newBounds.h = parentBounds.y2() - newBounds.y; + } + } + state.verticalFillSegment = null; + state.fillWidth = false; + if (state.verticalEdgeType == SegmentType.RIGHT && !state.wrapWidth) { + Rect parentBounds = parent.getBounds(); + state.verticalFillSegment = new Segment(parentBounds.x2(), newBounds.y, + newBounds.y2(), + null /*node*/, null /*id*/, SegmentType.RIGHT, MarginType.NO_MARGIN); + if (Math.abs(newBounds.x2() - parentBounds.x2()) < getMaxMatchDistance()) { + state.fillWidth = true; + newBounds.w = parentBounds.x2() - newBounds.x; + } + } + feedback.message = getResizeUpdateMessage(state, child, parent, newBounds, state.horizontalEdgeType, state.verticalEdgeType); } @@ -767,10 +788,8 @@ public class BaseLayoutRule extends BaseViewRule { */ protected String getResizeUpdateMessage(ResizeState resizeState, INode child, INode parent, Rect newBounds, SegmentType horizontalEdge, SegmentType verticalEdge) { - String width = resizeState.wrapWidth ? VALUE_WRAP_CONTENT : - String.format(VALUE_N_DP, mRulesEngine.pxToDp(newBounds.w)); - String height = resizeState.wrapHeight ? VALUE_WRAP_CONTENT : - String.format(VALUE_N_DP, mRulesEngine.pxToDp(newBounds.h)); + String width = resizeState.getWidthAttribute(); + String height = resizeState.getHeightAttribute(); // U+00D7: Unicode for multiplication sign return String.format("Resize to %s \u00D7 %s", width, height); @@ -790,15 +809,13 @@ public class BaseLayoutRule extends BaseViewRule { */ protected void setNewSizeBounds(ResizeState resizeState, INode node, INode layout, Rect oldBounds, Rect newBounds, SegmentType horizontalEdge, SegmentType verticalEdge) { - if (verticalEdge != null && (newBounds.w != oldBounds.w || resizeState.wrapWidth)) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, - resizeState.wrapWidth ? VALUE_WRAP_CONTENT : - String.format(VALUE_N_DP, mRulesEngine.pxToDp(newBounds.w))); + if (verticalEdge != null + && (newBounds.w != oldBounds.w || resizeState.wrapWidth || resizeState.fillWidth)) { + node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, resizeState.getWidthAttribute()); } - if (horizontalEdge != null && (newBounds.h != oldBounds.h || resizeState.wrapHeight)) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, - resizeState.wrapHeight ? VALUE_WRAP_CONTENT : - String.format(VALUE_N_DP, mRulesEngine.pxToDp(newBounds.h))); + if (horizontalEdge != null + && (newBounds.h != oldBounds.h || resizeState.wrapHeight || resizeState.fillHeight)) { + node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, resizeState.getHeightAttribute()); } } } 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 4b13b84..77cd7fe 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 @@ -25,9 +25,7 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION; import static com.android.ide.common.layout.LayoutConstants.ATTR_WEIGHT_SUM; import static com.android.ide.common.layout.LayoutConstants.VALUE_HORIZONTAL; -import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP; import static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL; -import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import com.android.annotations.VisibleForTesting; import com.android.ide.common.api.DrawingStyle; @@ -685,60 +683,128 @@ public class LinearLayoutRule extends BaseLayoutRule { } } - @Override - public DropFeedback onResizeBegin(INode child, INode parent, SegmentType horizontalEdge, - SegmentType verticalEdge) { - return super.onResizeBegin(child, parent, horizontalEdge, verticalEdge); - } + /** Custom resize state used during linear layout resizing */ + private class LinearResizeState extends ResizeState { + /** Whether the node should be assigned a new weight */ + public boolean useWeight; + /** Weight sum to be applied to the parent */ + private float mNewWeightSum; + /** The weight to be set on the node (provided {@link #useWeight} is true) */ + private float mWeight; + /** Map from nodes to preferred bounds of nodes where the weights have been cleared */ + public final Map<INode, Rect> unweightedSizes; + /** Total required size required by the siblings <b>without</b> weights */ + public int totalLength; + /** List of nodes which should have their weights cleared */ + public List<INode> mClearWeights; + + private LinearResizeState(BaseLayoutRule rule, INode layout, INode node) { + super(rule, layout, node); + + unweightedSizes = mRulesEngine.measureChildren(layout, + new IClientRulesEngine.AttributeFilter() { + public String getAttribute(INode n, String namespace, String localName) { + // Clear out layout weights; we need to measure the unweighted sizes + // of the children + if (ATTR_LAYOUT_WEIGHT.equals(localName) + && SdkConstants.NS_RESOURCES.equals(namespace)) { + return ""; //$NON-NLS-1$ + } - /** - * {@inheritDoc} - * <p> - * Overridden in this layout in order to make resizing affect the layout_weight - * attribute instead of the layout_width (for horizontal LinearLayouts) or - * layout_height (for vertical LinearLayouts). - */ - @Override - protected void setNewSizeBounds(ResizeState resizeState, INode node, INode layout, - Rect previousBounds, Rect newBounds, SegmentType horizontalEdge, - SegmentType verticalEdge) { - final Rect oldBounds = node.getBounds(); - if (oldBounds.equals(newBounds)) { - return; - } - // Handle resizing in the opposite dimension of the layout - boolean isVertical = isVertical(layout); - if (!isVertical && horizontalEdge != null) { - if (newBounds.h != oldBounds.h || resizeState.wrapHeight) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, - resizeState.wrapHeight ? VALUE_WRAP_CONTENT : - String.format(VALUE_N_DP, mRulesEngine.pxToDp(newBounds.h))); + return null; + } + }); + + // Compute total required size required by the siblings *without* weights + totalLength = 0; + final boolean isVertical = isVertical(layout); + for (Map.Entry<INode, Rect> entry : unweightedSizes.entrySet()) { + Rect preferredSize = entry.getValue(); + if (isVertical) { + totalLength += preferredSize.h; + } else { + totalLength += preferredSize.w; + } } - if (verticalEdge == null) { - return; + } + + /** Resets the computed state */ + void reset() { + mNewWeightSum = -1; + useWeight = false; + mClearWeights = null; + } + + /** Sets a weight to be applied to the node */ + void setWeight(float weight) { + useWeight = true; + mWeight = weight; + } + + /** Sets a weight sum to be applied to the parent layout */ + void setWeightSum(float weightSum) { + mNewWeightSum = weightSum; + } + + /** Marks that the given node should be cleared when applying the new size */ + void clearWeight(INode n) { + if (mClearWeights == null) { + mClearWeights = new ArrayList<INode>(); } - // else: fall through to compute a dynamic weight + mClearWeights.add(n); } - if (isVertical && verticalEdge != null) { - if (newBounds.w != oldBounds.w || resizeState.wrapWidth) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, - resizeState.wrapWidth ? VALUE_WRAP_CONTENT : - String.format(VALUE_N_DP, mRulesEngine.pxToDp(newBounds.w))); + + /** Applies the state to the nodes */ + public void apply() { + assert useWeight; + + String value = mWeight > 0 ? formatFloatAttribute(mWeight) : null; + node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, value); + + if (mClearWeights != null) { + for (INode n : mClearWeights) { + if (getWeight(n) > 0.0f) { + n.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, null); + } + } } - if (horizontalEdge == null) { - return; + + if (mNewWeightSum > 0.0) { + layout.setAttribute(ANDROID_URI, ATTR_WEIGHT_SUM, + formatFloatAttribute(mNewWeightSum)); } } + } + + @Override + protected ResizeState createResizeState(INode layout, INode node) { + return new LinearResizeState(this, layout, node); + } + + protected void updateResizeState(LinearResizeState resizeState, final INode node, INode layout, + Rect oldBounds, Rect newBounds, SegmentType horizontalEdge, + SegmentType verticalEdge) { + // Update the resize state. + // This method attempts to compute a new layout weight to be used in the direction + // of the linear layout. If the superclass has already determined that we can snap to + // a wrap_content or match_parent boundary, we prefer that. Otherwise, we attempt to + // compute a layout weight - which can fail if the size is too big (not enough room), + // or if the size is too small (smaller than the natural width of the node), and so on. + // In that case this method just aborts, which will leave the resize state object + // in such a state that it will call the superclass to resize instead, which will fall + // back to device independent pixel sizing. + resizeState.reset(); + + if (oldBounds.equals(newBounds)) { + return; + } - // If we're setting the width/height to wrap_content in the dimension of the + // If we're setting the width/height to wrap_content/match_parent in the dimension of the // linear layout, then just apply wrap_content and clear weights. + boolean isVertical = isVertical(layout); if (!isVertical && verticalEdge != null) { - if (resizeState.wrapWidth) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, VALUE_WRAP_CONTENT); - // Clear weight - if (getWeight(node) > 0.0f) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, null); - } + if (resizeState.wrapWidth || resizeState.fillWidth) { + resizeState.clearWeight(node); return; } if (newBounds.w == oldBounds.w) { @@ -747,12 +813,8 @@ public class LinearLayoutRule extends BaseLayoutRule { } if (isVertical && horizontalEdge != null) { - if (resizeState.wrapHeight) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, VALUE_WRAP_CONTENT); - // Clear weight - if (getWeight(node) > 0.0f) { - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, null); - } + if (resizeState.wrapHeight || resizeState.fillHeight) { + resizeState.clearWeight(node); return; } if (newBounds.h == oldBounds.h) { @@ -760,44 +822,30 @@ public class LinearLayoutRule extends BaseLayoutRule { } } + // Compute weight sum float sum = getWeightSum(layout); if (sum <= 0.0f) { sum = 1.0f; - layout.setAttribute(ANDROID_URI, ATTR_WEIGHT_SUM, formatFloatAttribute(sum)); + resizeState.setWeightSum(sum); } - Map<INode, Rect> sizes = mRulesEngine.measureChildren(layout, - new IClientRulesEngine.AttributeFilter() { - public String getAttribute(INode n, String namespace, String localName) { - // Clear out layout weights; we need to measure the unweighted sizes - // of the children - if (ATTR_LAYOUT_WEIGHT.equals(localName) - && SdkConstants.NS_RESOURCES.equals(namespace)) { - return ""; //$NON-NLS-1$ - } - - return null; - } - }); - int totalLength = 0; - for (Map.Entry<INode, Rect> entry : sizes.entrySet()) { - Rect preferredSize = entry.getValue(); - if (isVertical) { - totalLength += preferredSize.h; - } else { - totalLength += preferredSize.w; + // If the new size of the node is smaller than its preferred/wrap_content size, + // then we cannot use weights to size it; switch to pixel-based sizing instead + Map<INode, Rect> sizes = resizeState.unweightedSizes; + Rect nodePreferredSize = sizes.get(node); + if (nodePreferredSize != null) { + if (horizontalEdge != null && newBounds.h < nodePreferredSize.h || + verticalEdge != null && newBounds.w < nodePreferredSize.w) { + return; } } Rect layoutBounds = layout.getBounds(); - int remaining = (isVertical ? layoutBounds.h : layoutBounds.w) - totalLength; + int remaining = (isVertical ? layoutBounds.h : layoutBounds.w) - resizeState.totalLength; Rect nodeBounds = sizes.get(node); if (nodeBounds == null) { - super.setNewSizeBounds(resizeState, node, layout, oldBounds, newBounds, horizontalEdge, - verticalEdge); return; } - assert nodeBounds != null; if (remaining > 0) { int missing = 0; @@ -812,7 +860,7 @@ public class LinearLayoutRule extends BaseLayoutRule { // smaller size. missing = newBounds.h - resizeState.wrapBounds.h; remaining += nodeBounds.h - resizeState.wrapBounds.h; - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, VALUE_WRAP_CONTENT); + resizeState.wrapHeight = true; } } else { if (newBounds.w > nodeBounds.w) { @@ -820,61 +868,85 @@ public class LinearLayoutRule extends BaseLayoutRule { } else if (newBounds.w > resizeState.wrapBounds.w) { missing = newBounds.w - resizeState.wrapBounds.w; remaining += nodeBounds.w - resizeState.wrapBounds.w; - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, VALUE_WRAP_CONTENT); + resizeState.wrapWidth = true; } } if (missing > 0) { // (weight / weightSum) * remaining = missing, so // weight = missing * weightSum / remaining float weight = missing * sum / remaining; - String value = weight > 0 ? formatFloatAttribute(weight) : null; - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, value); + resizeState.setWeight(weight); } - } else { - // TODO: This algorithm should be refined. - // One possible solution is to clear the weights and sizes of all children - // to the left or right of the resized node (depending on whether the right - // or left edge was resized - the key point being that the other edge should - // not move). - - // There is no leftover space after adding up the wrap-content sizes of the - // children. In that case, just make the weight of this child the same proportion - // of the sum-of-weights as its new size is out of the parent size. - - // Use actual sum of weights, not the declared sum on the parent layout, - // to get the proportions right - float otherSum = 0.0f; - for (INode child : layout.getChildren()) { - if (child != node) { - otherSum += getWeight(child); + } + } + + /** + * {@inheritDoc} + * <p> + * Overridden in this layout in order to make resizing affect the layout_weight + * attribute instead of the layout_width (for horizontal LinearLayouts) or + * layout_height (for vertical LinearLayouts). + */ + @Override + protected void setNewSizeBounds(ResizeState state, final INode node, INode layout, + Rect oldBounds, Rect newBounds, SegmentType horizontalEdge, + SegmentType verticalEdge) { + LinearResizeState resizeState = (LinearResizeState) state; + updateResizeState(resizeState, node, layout, oldBounds, newBounds, + horizontalEdge, verticalEdge); + + if (resizeState.useWeight) { + resizeState.apply(); + + // Handle resizing in the opposite dimension of the layout + final boolean isVertical = isVertical(layout); + if (!isVertical && horizontalEdge != null) { + if (newBounds.h != oldBounds.h || resizeState.wrapHeight + || resizeState.fillHeight) { + node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, + resizeState.getHeightAttribute()); } } - - float newSize = isVertical ? newBounds.h : newBounds.w; - float totalSize = isVertical ? layoutBounds.h : layoutBounds.w; - float weight; - if (newSize >= totalSize) { - // The new view was resized to something larger than the layout itself; - // that obviously can't be achieved with layout weights, so just pick - // something large to give it a lot of space but not all. - weight = 10 * otherSum; - } else { - weight = newSize * otherSum / (totalSize - newSize); + if (isVertical && verticalEdge != null) { + if (newBounds.w != oldBounds.w || resizeState.wrapWidth || resizeState.fillWidth) { + node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, + resizeState.getWidthAttribute()); + } } - String value = weight > 0 ? formatFloatAttribute(weight) : null; - node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, value); - String fill = getFillParentValueName(); - node.setAttribute(ANDROID_URI, isVertical ? ATTR_LAYOUT_WEIGHT : ATTR_LAYOUT_WIDTH, - fill); + } else { + node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, null); + super.setNewSizeBounds(resizeState, node, layout, oldBounds, newBounds, + horizontalEdge, verticalEdge); } } @Override - protected String getResizeUpdateMessage(ResizeState resizeState, INode child, INode parent, + protected String getResizeUpdateMessage(ResizeState state, INode child, INode parent, Rect newBounds, SegmentType horizontalEdge, SegmentType verticalEdge) { - return super.getResizeUpdateMessage(resizeState, child, parent, newBounds, + LinearResizeState resizeState = (LinearResizeState) state; + updateResizeState(resizeState, child, parent, child.getBounds(), newBounds, horizontalEdge, verticalEdge); - // TODO: Change message to display the current layout weight instead + + if (resizeState.useWeight) { + String weight = formatFloatAttribute(resizeState.mWeight); + String dimension = String.format("layout weight %1$s", weight); + + String width; + String height; + if (isVertical(parent)) { + width = resizeState.getWidthAttribute(); + height = dimension; + } else { + width = dimension; + height = resizeState.getHeightAttribute(); + } + + // U+00D7: Unicode for multiplication sign + return String.format("Resize to %s \u00D7 %s", width, height); + } else { + return super.getResizeUpdateMessage(state, child, parent, newBounds, + horizontalEdge, verticalEdge); + } } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ResizeState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ResizeState.java new file mode 100644 index 0000000..11f3ec6 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ResizeState.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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 com.android.ide.common.layout; + +import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP; +import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; + +import com.android.ide.common.api.INode; +import com.android.ide.common.api.Rect; +import com.android.ide.common.api.Segment; +import com.android.ide.common.api.SegmentType; + +/** State held during resizing operations */ +class ResizeState { + /** + * The associated rule + */ + private final BaseLayoutRule mRule; + + /** + * The node being resized + */ + public final INode node; + + /** + * The layout containing the resized node + */ + public final INode layout; + + /** The proposed resized bounds of the node */ + public Rect bounds; + + /** The preferred wrap_content bounds of the node */ + public Rect wrapBounds; + + /** The suggested horizontal fill_parent guideline position */ + public Segment horizontalFillSegment; + + /** The suggested vertical fill_parent guideline position */ + public Segment verticalFillSegment; + + /** The type of horizontal edge being resized, or null */ + public SegmentType horizontalEdgeType; + + /** The type of vertical edge being resized, or null */ + public SegmentType verticalEdgeType; + + /** Whether the user has snapped to the wrap_content width */ + public boolean wrapWidth; + + /** Whether the user has snapped to the wrap_content height */ + public boolean wrapHeight; + + /** Whether the user has snapped to the match_parent width */ + public boolean fillWidth; + + /** Whether the user has snapped to the match_parent height */ + public boolean fillHeight; + + /** + * Constructs a new {@link ResizeState} + * + * @param rule the associated rule + * @param layout the parent layout containing the resized node + * @param node the node being resized + */ + ResizeState(BaseLayoutRule rule, INode layout, INode node) { + mRule = rule; + + this.layout = layout; + this.node = node; + } + + /** + * Returns the width attribute to be set to match the new bounds + * + * @return the width string, never null + */ + public String getWidthAttribute() { + if (wrapWidth) { + return VALUE_WRAP_CONTENT; + } else if (fillWidth) { + return mRule.getFillParentValueName(); + } else { + return String.format(VALUE_N_DP, mRule.mRulesEngine.pxToDp(bounds.w)); + } + } + + /** + * Returns the height attribute to be set to match the new bounds + * + * @return the height string, never null + */ + public String getHeightAttribute() { + if (wrapHeight) { + return VALUE_WRAP_CONTENT; + } else if (fillHeight) { + return mRule.getFillParentValueName(); + } else { + return String.format(VALUE_N_DP, mRule.mRulesEngine.pxToDp(bounds.h)); + } + } +}
\ No newline at end of file |