diff options
author | Tor Norbye <tnorbye@google.com> | 2011-07-07 11:57:59 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-07-08 20:31:19 -0700 |
commit | 0595b4123048f53179b5c2c65cf88968ac488ad3 (patch) | |
tree | d518ec578c0d0c3812cb4855337deb9275fa6743 | |
parent | d50c45bbd9e0d031c6fd86e92a78ffc3f8550b23 (diff) | |
download | sdk-0595b4123048f53179b5c2c65cf88968ac488ad3.zip sdk-0595b4123048f53179b5c2c65cf88968ac488ad3.tar.gz sdk-0595b4123048f53179b5c2c65cf88968ac488ad3.tar.bz2 |
Simple insets support
This changeset adds the basic plumbing for supporting insets, such
that selection handles can reflect the true bounds of a widget, and
such that guidelines which show adjacent matches can show and measure
the correct visual distance between the widgets.
The actual insets data is not available (though there are some
commented out measurements for some of the most important widgets,
like buttons), so the purpose of this changeset is to put the APIs in
place such that the various view rules can correctly account for these
deltas when they become available.
Change-Id: I326bfa22f0d239d76685b371d38bb8eac594a53b
9 files changed, 177 insertions, 8 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewMetadata.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewMetadata.java index 22fcb50..0687f30 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewMetadata.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewMetadata.java @@ -35,6 +35,13 @@ public interface IViewMetadata { public String getDisplayName(); /** + * Gets the insets for this view + * + * @return the insets for this view + */ + public Margins getInsets(); + + /** * Returns the {@link FillPreference} of this view * * @return the {@link FillPreference} of this view diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Margins.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Margins.java index 9e7c1d9..40f44ce 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Margins.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Margins.java @@ -17,7 +17,9 @@ package com.android.ide.common.api; /** - * Set of margins for a node. + * Set of margins - distances to outer left, top, right and bottom edges. These objects + * can be used for both actual <b>margins</b> as well as insets - and in general any + * deltas to the bounds of a rectangle. */ public class Margins { /** The left margin */ 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 0ef178d..d6bfa30 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 @@ -178,6 +178,12 @@ public class LayoutConstants { /** The fully qualified class name of a RadioButton view */ public static final String FQCN_RADIO_BUTTON = "android.widget.RadioButton"; //$NON-NLS-1$ + /** The fully qualified class name of a ToggleButton view */ + public static final String FQCN_TOGGLE_BUTTON = "android.widget.ToggleButton"; //$NON-NLS-1$ + + /** The fully qualified class name of a Spinner view */ + public static final String FQCN_SPINNER = "android.widget.Spinner"; //$NON-NLS-1$ + /** The fully qualified class name of an AdapterView */ public static final String FQCN_ADAPTER_VIEW = "android.widget.AdapterView"; //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java index 1d36f7b..76a511e 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; import com.android.ide.common.api.INode; +import com.android.ide.common.api.Margins; import com.android.ide.common.api.Point; import com.android.ide.common.layout.LayoutConstants; import com.android.ide.common.rendering.api.Capability; @@ -30,9 +31,11 @@ import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewEleme import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference; import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory; import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine; +import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository; import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; +import com.android.resources.Density; import com.android.sdklib.SdkConstants; import org.eclipse.core.filesystem.EFS; @@ -83,8 +86,8 @@ import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.ContributionItemFactory; import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.actions.ContributionItemFactory; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; import org.eclipse.ui.texteditor.ITextEditor; @@ -589,7 +592,7 @@ public class LayoutCanvas extends Canvas { redraw(); } - /* package */ double getScale() { + public double getScale() { return mHScale.getScale(); } @@ -1335,6 +1338,25 @@ public class LayoutCanvas extends Canvas { }); } + /** + * Returns the insets associated with views of the given fully qualified name, for the + * current theme and screen type. + * + * @param fqcn the fully qualified name to the widget type + * @return the insets, or null if unknown + */ + public Margins getInsets(String fqcn) { + if (ViewMetadataRepository.INSETS_SUPPORTED) { + ConfigurationComposite configComposite = + mLayoutEditor.getGraphicalEditor().getConfigurationComposite(); + String theme = configComposite.getTheme(); + Density density = configComposite.getDensity(); + return ViewMetadataRepository.getInsets(fqcn, density, theme); + } else { + return null; + } + } + private void debugPrintf(String message, Object... params) { if (DEBUG) { AdtPlugin.printToConsole("Canvas", String.format(message, params)); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionHandles.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionHandles.java index 9b10b6e..07285ea 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionHandles.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionHandles.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.ide.common.api.Margins; import com.android.ide.common.api.Rect; import com.android.ide.common.api.ResizePolicy; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionHandle.Position; @@ -43,7 +44,7 @@ public class SelectionHandles implements Iterable<SelectionHandle> { public SelectionHandles(SelectionItem item) { mItem = item; - createHandles(); + createHandles(item.getCanvas()); } /** @@ -69,7 +70,7 @@ public class SelectionHandles implements Iterable<SelectionHandle> { * Create the {@link SelectionHandle} objects for the selection item, according to its * {@link ResizePolicy}. */ - private void createHandles() { + private void createHandles(LayoutCanvas canvas) { NodeProxy selectedNode = mItem.getNode(); Rect r = selectedNode.getBounds(); if (!r.isValid()) { @@ -88,9 +89,17 @@ public class SelectionHandles implements Iterable<SelectionHandle> { int y1 = r.y; int w = r.w; int h = r.h; - int x2 = x1 + w; int y2 = y1 + h; + + Margins insets = canvas.getInsets(mItem.getNode().getFqcn()); + if (insets != null) { + x1 += insets.left; + x2 -= insets.right; + y1 += insets.top; + y2 -= insets.bottom; + } + int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2; 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 4afb123..7b869a5 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 @@ -75,6 +75,7 @@ class SelectionItem { /** * Returns true when this selection item represents the root, the top level * layout element in the editor. + * * @return True if and only if this element is at the root of the hierarchy */ public boolean isRoot() { @@ -104,6 +105,11 @@ class SelectionItem { return mNodeProxy; } + /** Returns the canvas associated with this selection (never null) */ + LayoutCanvas getCanvas() { + return mCanvas; + } + //---- /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java index b3cc13b..0186212 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java @@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.IGraphics; import com.android.ide.common.api.INode; +import com.android.ide.common.api.Margins; import com.android.ide.common.api.Rect; import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy; import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine; @@ -189,7 +190,21 @@ public class SelectionOverlay extends Overlay { } gc.useStyle(DrawingStyle.SELECTION); - gc.drawRect(r); + + Margins insets = mCanvas.getInsets(selectedNode.getFqcn()); + int x1 = r.x; + int y1 = r.y; + int x2 = r.x2() + 1; + int y2 = r.y2() + 1; + + if (insets != null) { + x1 += insets.left; + x2 -= insets.right; + y1 += insets.top; + y2 -= insets.bottom; + } + + gc.drawRect(x1, y1, x2, y2); // Paint sibling rectangles, if applicable CanvasViewInfo view = item.getViewInfo(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java index e23f05c..0bddcf1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java @@ -24,6 +24,7 @@ import com.android.ide.common.api.INode; import com.android.ide.common.api.IValidator; import com.android.ide.common.api.IViewMetadata; import com.android.ide.common.api.IViewRule; +import com.android.ide.common.api.Margins; import com.android.ide.common.api.Rect; import com.android.ide.common.resources.ResourceRepository; import com.android.ide.eclipse.adt.AdtPlugin; @@ -163,6 +164,10 @@ class ClientRulesEngine implements IClientRulesEngine { public FillPreference getFillPreference() { return ViewMetadataRepository.get().getFillPreference(fqcn); } + + public Margins getInsets() { + return mRulesEngine.getEditor().getCanvasControl().getInsets(fqcn); + } }; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java index abe4a83..9234d73 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java @@ -18,17 +18,22 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gre; 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.FQCN_BUTTON; +import static com.android.ide.common.layout.LayoutConstants.FQCN_SPINNER; +import static com.android.ide.common.layout.LayoutConstants.FQCN_TOGGLE_BUTTON; import static com.android.ide.common.layout.LayoutConstants.ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX; import com.android.annotations.VisibleForTesting; -import com.android.ide.common.api.ResizePolicy; import com.android.ide.common.api.IViewMetadata.FillPreference; +import com.android.ide.common.api.Margins; +import com.android.ide.common.api.ResizePolicy; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.IconFactory; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; +import com.android.resources.Density; import com.android.util.Pair; import org.w3c.dom.Document; @@ -697,4 +702,96 @@ public class ViewMetadataRepository { } } } + + /** + * Are insets supported yet? This flag indicates whether the {@link #getInsets} method + * can return valid data, such that clients can avoid doing any work computing the + * current theme or density if there's no chance that valid insets will be returned + */ + public static final boolean INSETS_SUPPORTED = false; + + /** + * Returns the insets of widgets with the given fully qualified name, in the given + * theme and the given screen density. + * + * @param fqcn the fully qualified name of the view + * @param density the screen density + * @param theme the theme name + * @return the insets of the visual bounds relative to the view info bounds, or null + * if not known or if there are no insets + */ + public static Margins getInsets(String fqcn, Density density, String theme) { + if (INSETS_SUPPORTED) { + // Some sample data measured manually for common themes and widgets. + if (fqcn.equals(FQCN_BUTTON)) { + if (density == Density.HIGH) { + if (theme.startsWith(HOLO_PREFIX)) { + // Theme.Holo, Theme.Holo.Light, WVGA + return new Margins(5, 5, 5, 5); + } else { + // Theme.Light, WVGA + return new Margins(4, 4, 0, 7); + } + } else if (density == Density.MEDIUM) { + if (theme.startsWith(HOLO_PREFIX)) { + // Theme.Holo, Theme.Holo.Light, WVGA + return new Margins(3, 3, 3, 3); + } else { + // Theme.Light, HVGA + return new Margins(2, 2, 0, 4); + } + } else if (density == Density.LOW) { + if (theme.startsWith(HOLO_PREFIX)) { + // Theme.Holo, Theme.Holo.Light, QVGA + return new Margins(2, 2, 2, 2); + } else { + // Theme.Light, QVGA + return new Margins(1, 3, 0, 4); + } + } + } else if (fqcn.equals(FQCN_TOGGLE_BUTTON)) { + if (density == Density.HIGH) { + if (theme.startsWith(HOLO_PREFIX)) { + // Theme.Holo, Theme.Holo.Light, WVGA + return new Margins(5, 5, 5, 5); + } else { + // Theme.Light, WVGA + return new Margins(2, 2, 0, 5); + } + } else if (density == Density.MEDIUM) { + if (theme.startsWith(HOLO_PREFIX)) { + // Theme.Holo, Theme.Holo.Light, WVGA + return new Margins(3, 3, 3, 3); + } else { + // Theme.Light, HVGA + return new Margins(0, 1, 0, 3); + } + } else if (density == Density.LOW) { + if (theme.startsWith(HOLO_PREFIX)) { + // Theme.Holo, Theme.Holo.Light, QVGA + return new Margins(2, 2, 2, 2); + } else { + // Theme.Light, QVGA + return new Margins(2, 2, 0, 4); + } + } + } else if (fqcn.equals(FQCN_SPINNER)) { + if (density == Density.HIGH) { + if (!theme.startsWith(HOLO_PREFIX)) { + // Theme.Light, WVGA + return new Margins(3, 4, 2, 8); + } // Doesn't render on Holo! + } else if (density == Density.MEDIUM) { + if (!theme.startsWith(HOLO_PREFIX)) { + // Theme.Light, HVGA + return new Margins(1, 1, 0, 4); + } + } + } + } + + return null; + } + + private static final String HOLO_PREFIX = "Theme.Holo"; //$NON-NLS-1$ } |