diff options
11 files changed, 395 insertions, 153 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/BaseView.groovy b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/BaseView.groovy index 9c5b52f..7241a6b 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/BaseView.groovy +++ b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/BaseView.groovy @@ -313,9 +313,8 @@ public class BaseView implements IViewRule { return; } - gc.useStyle(DrawingStyle.SELECTION_FILL); + gc.useStyle(DrawingStyle.SELECTION); gc.fillRect(r); - gc.useStyle(DrawingStyle.SELECTION_BORDER); gc.drawRect(r); if (displayName == null || isMultipleSelection) { @@ -327,7 +326,9 @@ public class BaseView implements IViewRule { if (ys < 0) { ys = r.y + r.h; } - gc.drawString(displayName, xs, ys); + gc.useStyle(DrawingStyle.HELP); + gc.drawBoxedStrings(xs, ys, [displayName]); + } public void onChildSelected(IGraphics gc, INode parentNode, INode childNode) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.AbsoluteLayout.groovy b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.AbsoluteLayout.groovy index 4e8daad..e2a58f0 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.AbsoluteLayout.groovy +++ b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.AbsoluteLayout.groovy @@ -51,9 +51,7 @@ public class AndroidWidgetAbsoluteLayoutRule extends BaseLayout { } // Highlight the receiver - gc.setForeground(gc.registerColor(0x00FFFF00)); - gc.setLineStyle(IGraphics.LineStyle.LINE_SOLID); - gc.setLineWidth(2); + gc.useStyle(DrawingStyle.DROP_RECIPIENT); gc.drawRect(b); // Get the drop point @@ -74,15 +72,23 @@ public class AndroidWidgetAbsoluteLayoutRule extends BaseLayout { // the drop point. int offsetX = x - be.x; int offsetY = y - be.y; + gc.useStyle(DrawingStyle.DROP_PREVIEW); elements.each { drawElement(gc, it, offsetX, offsetY); } } else { // We don't have bounds for new elements. In this case - // just draw a mark at the drop point. - gc.drawLine(x - 10, y - 10, x + 10, y + 10); - gc.drawLine(x + 10, y - 10, x - 10, y + 10); - gc.drawOval(x - 10, y - 10, x + 10, y + 10); + // just draw cross hairs to the drop point. + gc.useStyle(DrawingStyle.GUIDELINE); + gc.drawLine(x, b.y, x, b.y + b.h); + gc.drawLine(b.x, y, b.x + b.w, y); + + // Use preview lines to indicate the bottom quadrant as well (to indicate + // that you are looking at the top left position of the drop, not the center + // for example) + gc.useStyle(DrawingStyle.DROP_PREVIEW); + gc.drawLine(x, y, b.x + b.w, y); + gc.drawLine(x, y, x, b.y + b.h); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.FrameLayout.groovy b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.FrameLayout.groovy index 97d67ba..5a30a9f 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.FrameLayout.groovy +++ b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.FrameLayout.groovy @@ -48,9 +48,7 @@ public class AndroidWidgetFrameLayoutRule extends BaseLayout { return; } - gc.setForeground(gc.registerColor(0x00FFFF00)); - gc.setLineStyle(IGraphics.LineStyle.LINE_SOLID); - gc.setLineWidth(2); + gc.useStyle(DrawingStyle.DROP_RECIPIENT); gc.drawRect(b); // Get the drop point @@ -71,6 +69,7 @@ public class AndroidWidgetFrameLayoutRule extends BaseLayout { // the drop point. int offsetX = x - be.x; int offsetY = y - be.y; + gc.useStyle(DrawingStyle.DROP_PREVIEW); elements.each { drawElement(gc, it, offsetX, offsetY); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.LinearLayout.groovy b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.LinearLayout.groovy index 1865044..ac6543b 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.LinearLayout.groovy +++ b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.LinearLayout.groovy @@ -80,12 +80,24 @@ public class AndroidWidgetLinearLayoutRule extends BaseLayout { targetNode.getChildren().each { def bc = it.getBounds(); if (bc.isValid()) { - // add an insertion point between the last point and the start of this child - int v = isVertical ? bc.y : bc.x; - v = (last + v) / 2; - indexes.add( [v, pos++] ); + // First see if this node looks like it's the same as one of the *dragged* bounds + boolean isDragged = false; + for (element in elements) { + // This tries to determine if an INode corresponds to an IDragElement, by + // comparing their bounds. + if (bc == element.getBounds()) { + isDragged = true; + } + } - last = isVertical ? (bc.y + bc.h) : (bc.x + bc.w); + if (!isDragged) { + // add an insertion point between the last point and the start of this child + int v = isVertical ? bc.y : bc.x; + v = (last + v) / 2; + indexes.add( [v, pos++] ); + + last = isVertical ? (bc.y + bc.h) : (bc.x + bc.w); + } } } @@ -123,8 +135,6 @@ public class AndroidWidgetLinearLayoutRule extends BaseLayout { gc.drawRect(b); gc.useStyle(DrawingStyle.DROP_ZONE); - gc.setLineStyle(IGraphics.LineStyle.LINE_DOT); - gc.setLineWidth(1); def indexes = feedback.userData.indexes; boolean isVertical = feedback.userData.isVertical; @@ -149,17 +159,26 @@ public class AndroidWidgetLinearLayoutRule extends BaseLayout { int x = currX; int y = currY; - // Draw a mark at the drop point. - gc.setLineStyle(IGraphics.LineStyle.LINE_SOLID); - gc.setLineWidth(2); - - gc.drawLine(x - 10, y - 10, x + 10, y + 10); - gc.drawLine(x + 10, y - 10, x - 10, y + 10); - gc.drawOval(x - 10, y - 10, x + 10, y + 10); - Rect be = elements[0].getBounds(); - if (be.isValid()) { + // Draw a mark at the drop point. + if (!be.isValid()) { + // We don't have valid bounds; this typically means we are dragging a new + // View from the palette whose bounds are unknown, so we simply show a single + // dividing line in the center of the position between the children + gc.useStyle(DrawingStyle.DROP_PREVIEW); + if (feedback.userData.width != null) { + int width = feedback.userData.width; + int fromX = x - width / 2; + int toX = x + width / 2; + gc.drawLine(fromX, y, toX, y); + } else if (feedback.userData.height != null) { + int height = (int)feedback.userData.height; + int fromY = y - height / 2; + int toY = y + height / 2; + gc.drawLine(x, fromY, x, toY); + } + } else { // At least the first element has a bound. Draw rectangles // for all dropped elements with valid bounds, offset at // the drop point. @@ -172,11 +191,16 @@ public class AndroidWidgetLinearLayoutRule extends BaseLayout { if (pb.isValid()) { if (isVertical) { offsetX = b.x - pb.x; + // Place the -center- of the bounds at child boundary! + offsetY -= be.h / 2; } else { offsetY = b.y - pb.y; + // Place the -center- of the bounds at child boundary! + offsetX -= be.w / 2; } } + gc.useStyle(DrawingStyle.DROP_PREVIEW); for (element in elements) { drawElement(gc, element, offsetX, offsetY); } @@ -221,9 +245,11 @@ public class AndroidWidgetLinearLayoutRule extends BaseLayout { if (isVertical) { data.currX = b.x + b.w / 2; data.currY = bestIndex; + data.width = b.w; } else { data.currX = bestIndex; data.currY = b.y + b.h / 2; + data.height = b.h; } data.insertPos = bestPos; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy index 2cd34aa..983f45a 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy +++ b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy @@ -74,14 +74,11 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout { addAttr("centerVertical"); if (infos) { - gc.setForeground(gc.registerColor(0x00222222)); + gc.useStyle(DrawingStyle.HELP); int x = b.x + 10; int y = b.y + b.h + 10; int h = gc.getFontHeight(); - infos.each { - y += h; - gc.drawString(it, x, y); - } + gc.drawBoxedStrings(x, y, infos); } } @@ -452,9 +449,7 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout { if (data.curr) { gc.useStyle(DrawingStyle.DROP_ZONE_ACTIVE); - gc.setAlpha(200); gc.fillRect(data.curr.rect); - gc.setAlpha(255); def r = feedback.captureArea; int x = r.x + 5; @@ -466,11 +461,13 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout { id = data.child.getStringAttr(ANDROID_URI, ATTR_ID); } - for (s in data.curr.attr) { - if (id) s = "$s=$id"; - gc.drawString(s, x, y); - y += h; + // Print constraints (with id appended if applicable) + gc.useStyle(DrawingStyle.HELP); + def strings = [] + data.curr.attr.each { + strings << id ? it + "=" + id : it; } + gc.drawBoxedStrings(x, y, strings); def mark = data.curr.get("mark"); if (mark) { @@ -511,7 +508,7 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout { offsetX -= be.w; } - gc.setForeground(gc.registerColor(0x00FFFF00)); + gc.useStyle(DrawingStyle.DROP_PREVIEW); for (element in elements) { drawElement(gc, element, offsetX, offsetY); @@ -522,6 +519,7 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout { if (data.rejected) { def br = data.rejected; gc.useStyle(DrawingStyle.INVALID); + gc.fillRect(br); gc.drawLine(br.x, br.y , br.x + br.w, br.y + br.h); gc.drawLine(br.x, br.y + br.h, br.x + br.w, br.y ); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/DrawingStyle.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/DrawingStyle.java index ea6c5e8..712e95c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/DrawingStyle.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/DrawingStyle.java @@ -23,14 +23,15 @@ package com.android.ide.eclipse.adt.editors.layout.gscripts; */ public enum DrawingStyle { /** - * The style used for the border of a selected view + * The style used to draw the selected views */ - SELECTION_BORDER, + SELECTION, /** - * The style used for the interior of a selected view + * The style used to draw guidelines - overlay lines which indicate + * significant geometric positions. */ - SELECTION_FILL, + GUIDELINE, /** * The style used for hovered views (e.g. when the mouse is directly on top @@ -75,6 +76,17 @@ public enum DrawingStyle { DROP_ZONE_ACTIVE, /** + * The style used to draw a preview of where a dropped view would appear if + * it were to be dropped at a given location. + */ + DROP_PREVIEW, + + /** + * The style used to draw help/hint text. + */ + HELP, + + /** * The style used to raw illegal/error/invalid markers */ INVALID, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/IGraphics.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/IGraphics.java index 7c1dc15..ef10e73 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/IGraphics.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/editors/layout/gscripts/IGraphics.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.editors.layout.gscripts; +import java.util.List; + /** * Represents a graphical context that rules can use to draw on the canvas. * <p/> @@ -94,6 +96,21 @@ public interface IGraphics { void drawString(String string, Point topLeft); /** + * Draw the given strings, using the current stroke color and alpha for the + * text, and the current fill color and alpha for a rectangle behind the + * bounding box fitting all the lines of text. Each subsequent string is + * drawn on consecutive lines below the previous string. + * + * @param x The left edge to start each string at + * @param y The top position of the first string; subsequent strings are + * painted on lines below + * @param strings An array of labels to be displayed (should not be null). + * The actual String used is the {@link Object#toString()} value + * of each list item. + */ + void drawBoxedStrings(int x, int y, List<?> strings); + + /** * Set up the graphics context to use the given style for subsequent drawing * operations. * @@ -158,10 +175,8 @@ public interface IGraphics { * This operation requires the operating system's advanced * graphics subsystem which may not be available on some * platforms. - * - * @return False if the GC doesn't support alpha. */ - boolean setAlpha(int alpha); + void setAlpha(int alpha); /** * A line style for {@link IGraphics#setLineStyle(LineStyle)}. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java index d6e8f0c..ff176de 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java @@ -278,7 +278,7 @@ public class LayoutEditor extends AndroidXmlEditor implements IShowEditorInput, /** * Returns the custom IContentOutlinePage or IPropertySheetPage when asked for it. */ - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") @Override public Object getAdapter(Class adapter) { // for the outline, force it to come from the Graphical Editor. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java index 2927c0e..676606a 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java @@ -32,6 +32,7 @@ import org.eclipse.swt.graphics.RGB; import java.util.EnumMap; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -50,6 +51,11 @@ public class GCWrapper implements IGraphics { private GC mGc; /** + * Current style being used for drawing. + */ + private SwtDrawingStyle mCurrentStyle = SwtDrawingStyle.INVALID; + + /** * Implementation of IColor wrapping an SWT color. */ private class ColorWrapper implements IColor { @@ -68,10 +74,17 @@ public class GCWrapper implements IGraphics { private final HashMap<Integer, ColorWrapper> mColorMap = new HashMap<Integer, ColorWrapper>(); /** - * A map of the {@link SwtDrawingStyle} colors that we have actually used - * (to be disposed) + * A map of the {@link SwtDrawingStyle} stroke colors that we have actually + * used (to be disposed) */ - private final Map<DrawingStyle, Color> mStyleColorMap = new EnumMap<DrawingStyle, Color>( + private final Map<DrawingStyle, Color> mStyleStrokeMap = new EnumMap<DrawingStyle, Color>( + DrawingStyle.class); + + /** + * A map of the {@link SwtDrawingStyle} fill colors that we have actually + * used (to be disposed) + */ + private final Map<DrawingStyle, Color> mStyleFillMap = new EnumMap<DrawingStyle, Color>( DrawingStyle.class); /** The cached pixel height of the default current font. */ @@ -108,10 +121,15 @@ public class GCWrapper implements IGraphics { } mColorMap.clear(); - for (Color c : mStyleColorMap.values()) { + for (Color c : mStyleStrokeMap.values()) { c.dispose(); } - mStyleColorMap.clear(); + mStyleStrokeMap.clear(); + + for (Color c : mStyleFillMap.values()) { + c.dispose(); + } + mStyleFillMap.clear(); } //------------- @@ -166,13 +184,13 @@ public class GCWrapper implements IGraphics { getGc().setBackground(((ColorWrapper) color).getColor()); } - public boolean setAlpha(int alpha) { + public void setAlpha(int alpha) { checkGC(); try { getGc().setAlpha(alpha); - return true; } catch (SWTException e) { - return false; + // This means that we cannot set the alpha on this platform; this is + // an acceptable no-op. } } @@ -213,6 +231,7 @@ public class GCWrapper implements IGraphics { public void drawLine(int x1, int y1, int x2, int y2) { checkGC(); + useStrokeAlpha(); x1 = mHScale.translate(x1); y1 = mVScale.translate(y1); x2 = mHScale.translate(x2); @@ -228,6 +247,7 @@ public class GCWrapper implements IGraphics { public void drawRect(int x1, int y1, int x2, int y2) { checkGC(); + useStrokeAlpha(); int x = mHScale.translate(x1); int y = mVScale.translate(y1); int w = mHScale.scale(x2 - x1); @@ -241,6 +261,7 @@ public class GCWrapper implements IGraphics { public void drawRect(Rect r) { checkGC(); + useStrokeAlpha(); int x = mHScale.translate(r.x); int y = mVScale.translate(r.y); int w = mHScale.scale(r.w); @@ -250,6 +271,7 @@ public class GCWrapper implements IGraphics { public void fillRect(int x1, int y1, int x2, int y2) { checkGC(); + useFillAlpha(); int x = mHScale.translate(x1); int y = mVScale.translate(y1); int w = mHScale.scale(x2 - x1); @@ -263,6 +285,7 @@ public class GCWrapper implements IGraphics { public void fillRect(Rect r) { checkGC(); + useFillAlpha(); int x = mHScale.translate(r.x); int y = mVScale.translate(r.y); int w = mHScale.scale(r.w); @@ -274,6 +297,7 @@ public class GCWrapper implements IGraphics { public void drawOval(int x1, int y1, int x2, int y2) { checkGC(); + useStrokeAlpha(); int x = mHScale.translate(x1); int y = mVScale.translate(y1); int w = mHScale.scale(x2 - x1); @@ -287,6 +311,7 @@ public class GCWrapper implements IGraphics { public void drawOval(Rect r) { checkGC(); + useStrokeAlpha(); int x = mHScale.translate(r.x); int y = mVScale.translate(r.y); int w = mHScale.scale(r.w); @@ -296,6 +321,7 @@ public class GCWrapper implements IGraphics { public void fillOval(int x1, int y1, int x2, int y2) { checkGC(); + useFillAlpha(); int x = mHScale.translate(x1); int y = mVScale.translate(y1); int w = mHScale.scale(x2 - x1); @@ -309,6 +335,7 @@ public class GCWrapper implements IGraphics { public void fillOval(Rect r) { checkGC(); + useFillAlpha(); int x = mHScale.translate(r.x); int y = mVScale.translate(r.y); int w = mHScale.scale(r.w); @@ -321,11 +348,48 @@ public class GCWrapper implements IGraphics { public void drawString(String string, int x, int y) { checkGC(); + useStrokeAlpha(); x = mHScale.translate(x); y = mVScale.translate(y); + // Background fill of text is not useful because it does not + // use the alpha; we instead supply a separate method (drawBoxedStrings) which + // first paints a semi-transparent mask for the text to sit on + // top of (this ensures that the text is readable regardless of + // colors of the pixels below the text) getGc().drawString(string, x, y, true /*isTransparent*/); } + public void drawBoxedStrings(int x, int y, List<?> strings) { + checkGC(); + + x = mHScale.translate(x); + y = mVScale.translate(y); + + // Compute bounds of the box by adding up the sum of the text heights + // and the max of the text widths + int width = 0; + int height = 0; + int lineHeight = getGc().getFontMetrics().getHeight(); + for (Object s : strings) { + org.eclipse.swt.graphics.Point extent = getGc().stringExtent(s.toString()); + height += extent.y; + width = Math.max(width, extent.x); + } + + // Paint a box below the text + int padding = 2; + useFillAlpha(); + getGc().fillRectangle(x - padding, y - padding, width + 2 * padding, height + 2 * padding); + + // Finally draw strings on top + useStrokeAlpha(); + int lineY = y; + for (Object s : strings) { + getGc().drawString(s.toString(), x, lineY, true /* isTransparent */); + lineY += lineHeight; + } + } + public void drawString(String string, Point topLeft) { drawString(string, topLeft.x, topLeft.y); } @@ -338,37 +402,84 @@ public class GCWrapper implements IGraphics { // Look up the specific SWT style which defines the actual // colors and attributes to be used for the logical drawing style. SwtDrawingStyle swtStyle = SwtDrawingStyle.of(style); - RGB fg = swtStyle.getForeground(); - if (fg != null) { - Color color = getStyleColor(style, fg); + RGB stroke = swtStyle.getStrokeColor(); + if (stroke != null) { + Color color = getStrokeColor(style, stroke); mGc.setForeground(color); } - RGB bg = swtStyle.getBackground(); - if (bg != null) { - Color color = getStyleColor(style, bg); + RGB fill = swtStyle.getFillColor(); + if (fill != null) { + Color color = getFillColor(style, fill); mGc.setBackground(color); } mGc.setLineWidth(swtStyle.getLineWidth()); mGc.setLineStyle(swtStyle.getLineStyle()); - mGc.setAlpha(swtStyle.getAlpha()); + if (swtStyle.getLineStyle() == SWT.LINE_CUSTOM) { + mGc.setLineDash(new int[] { + 8, 4 + }); + } + mCurrentStyle = swtStyle; + } + + /** Use the stroke alpha for subsequent drawing operations */ + private void useStrokeAlpha() { + mGc.setAlpha(mCurrentStyle.getStrokeAlpha()); + } + + /** Use the fill alpha for subsequent drawing operations */ + private void useFillAlpha() { + mGc.setAlpha(mCurrentStyle.getFillAlpha()); + } + + /** + * Get the SWT stroke color (foreground/border) to use for the given style, + * using the provided color description if we haven't seen this color yet. + * The color will also be placed in the {@link #mStyleStrokeMap} such that + * it can be disposed of at cleanup time. + * + * @param style The drawing style for which we want a color + * @param defaultColorDesc The RGB values to initialize the color to if we + * haven't seen this color before + * @return The color object + */ + private Color getStrokeColor(DrawingStyle style, RGB defaultColorDesc) { + return getStyleColor(style, defaultColorDesc, mStyleStrokeMap); + } + + /** + * Get the SWT fill (background/interior) color to use for the given style, + * using the provided color description if we haven't seen this color yet. + * The color will also be placed in the {@link #mStyleStrokeMap} such that + * it can be disposed of at cleanup time. + * + * @param style The drawing style for which we want a color + * @param defaultColorDesc The RGB values to initialize the color to if we + * haven't seen this color before + * @return The color object + */ + private Color getFillColor(DrawingStyle style, RGB defaultColorDesc) { + return getStyleColor(style, defaultColorDesc, mStyleFillMap); } /** * Get the SWT color to use for the given style, using the provided color * description if we haven't seen this color yet. The color will also be - * placed in the {@link #mStyleColorMap} such that it can be disposed of at - * cleanup time. + * placed in the map referenced by the map parameter such that it can be + * disposed of at cleanup time. * * @param style The drawing style for which we want a color * @param defaultColorDesc The RGB values to initialize the color to if we * haven't seen this color before + * @param map The color map to use * @return The color object */ - private Color getStyleColor(DrawingStyle style, RGB defaultColorDesc) { - Color color = mStyleColorMap.get(style); + private Color getStyleColor(DrawingStyle style, RGB defaultColorDesc, + Map<DrawingStyle, Color> map) { + Color color = map.get(style); if (color == null) { color = new Color(getGc().getDevice(), defaultColorDesc); - mStyleColorMap.put(style, color); + map.put(style, color); } return color; 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 237deb8..705021e 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 @@ -208,9 +208,12 @@ class LayoutCanvas extends Canvas implements ISelectionProvider { private Rectangle mHoverRect; /** Hover border color. Must be disposed, it's NOT a system color. */ - private Color mHoverFgColor; + private Color mHoverStrokeColor; - /** Outline color. Do not dispose, it's a system color. */ + /** Hover fill color. Must be disposed, it's NOT a system color. */ + private Color mHoverFillColor; + + /** Outline color. Must be disposed, it's NOT a system color. */ private Color mOutlineColor; /** @@ -287,9 +290,14 @@ class LayoutCanvas extends Canvas implements ISelectionProvider { mGCWrapper = new GCWrapper(mHScale, mVScale); Display d = getDisplay(); - mSelectionFgColor = new Color(d, SwtDrawingStyle.SELECTION_BORDER.getForeground()); - mHoverFgColor = new Color(d, SwtDrawingStyle.HOVER.getForeground()); - mOutlineColor = new Color(d, SwtDrawingStyle.OUTLINE.getForeground()); + mSelectionFgColor = new Color(d, SwtDrawingStyle.SELECTION.getStrokeColor()); + if (SwtDrawingStyle.HOVER.getStrokeColor() != null) { + mHoverStrokeColor = new Color(d, SwtDrawingStyle.HOVER.getStrokeColor()); + } + if (SwtDrawingStyle.HOVER.getFillColor() != null) { + mHoverFillColor = new Color(d, SwtDrawingStyle.HOVER.getFillColor()); + } + mOutlineColor = new Color(d, SwtDrawingStyle.OUTLINE.getStrokeColor()); mFont = d.getSystemFont(); @@ -358,9 +366,19 @@ class LayoutCanvas extends Canvas implements ISelectionProvider { mOutlinePage = null; } - if (mHoverFgColor != null) { - mHoverFgColor.dispose(); - mHoverFgColor = null; + if (mOutlineColor != null) { + mOutlineColor.dispose(); + mOutlineColor = null; + } + + if (mHoverStrokeColor != null) { + mHoverStrokeColor.dispose(); + mHoverStrokeColor = null; + } + + if (mHoverFillColor != null) { + mHoverFillColor.dispose(); + mHoverFillColor = null; } if (mDropTarget != null) { @@ -963,19 +981,33 @@ class LayoutCanvas extends Canvas implements ISelectionProvider { if (mShowOutline && mLastValidViewInfoRoot != null) { gc.setForeground(mOutlineColor); gc.setLineStyle(SwtDrawingStyle.OUTLINE.getLineStyle()); + int oldAlpha = gc.getAlpha(); + gc.setAlpha(SwtDrawingStyle.OUTLINE.getStrokeAlpha()); drawOutline(gc, mLastValidViewInfoRoot); + gc.setAlpha(oldAlpha); } if (mHoverRect != null) { - gc.setForeground(mHoverFgColor); - gc.setLineStyle(SwtDrawingStyle.HOVER.getLineStyle()); - int x = mHScale.translate(mHoverRect.x); int y = mVScale.translate(mHoverRect.y); int w = mHScale.scale(mHoverRect.width); int h = mVScale.scale(mHoverRect.height); - gc.drawRectangle(x, y, w, h); + if (mHoverStrokeColor != null) { + int oldAlpha = gc.getAlpha(); + gc.setForeground(mHoverStrokeColor); + gc.setLineStyle(SwtDrawingStyle.HOVER.getLineStyle()); + gc.setAlpha(SwtDrawingStyle.HOVER.getStrokeAlpha()); + gc.drawRectangle(x, y, w, h); + gc.setAlpha(oldAlpha); + } + + if (mHoverFillColor != null) { + int oldAlpha = gc.getAlpha(); + gc.setAlpha(SwtDrawingStyle.HOVER.getFillAlpha()); + gc.fillRectangle(x, y, w, h); + gc.setAlpha(oldAlpha); + } } int n = mSelections.size(); @@ -1011,7 +1043,12 @@ class LayoutCanvas extends Canvas implements ISelectionProvider { int w = mHScale.scale(r.width); int h = mVScale.scale(r.height); - gc.drawRectangle(x, y, w, h); + // Add +1 to the width and +1 to the height such that when you have a + // series of boxes (in say a LinearLayout), instead of the bottom of one + // box and the top of the next box being -adjacent-, they -overlap-. + // This makes the outline nicer visually since you don't get + // "double thickness" lines for all adjacent boxes. + gc.drawRectangle(x, y, w + 1, h + 1); for (CanvasViewInfo vi : info.getChildren()) { drawOutline(gc, vi); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtDrawingStyle.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtDrawingStyle.java index 1d30c7b..cb2c7f1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtDrawingStyle.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtDrawingStyle.java @@ -27,122 +27,136 @@ import org.eclipse.swt.graphics.RGB; * class which defines the drawing styles but does not introduce any specific * SWT values to the API clients. * <p> - * TODO: This class should eventually pick up theme preferences. + * TODO: This class should eventually be replaced by a scheme where the color + * constants are instead coming from the theme. */ public enum SwtDrawingStyle { /** - * The style used for the border of a selected view + * The style definition corresponding to {@link DrawingStyle#SELECTION} */ - SELECTION_BORDER(new RGB(0xFF, 0x00, 0x00), null, 1, SWT.LINE_SOLID, 255), + SELECTION(new RGB(0x00, 0x99, 0xFF), 255, new RGB(0x00, 0x99, 0xFF), 64, 2, SWT.LINE_DASH), /** - * The style used for the interior of a selected view + * The style definition corresponding to {@link DrawingStyle#GUIDELINE} */ - SELECTION_FILL(null, new RGB(0xFF, 0x00, 0x00), 1, SWT.LINE_SOLID, 64), + GUIDELINE(new RGB(0x00, 0xFF, 0x00), 255, SWT.LINE_DOT), /** - * The style used for hovered views (e.g. when the mouse is directly on top - * of the view) + * The style definition corresponding to {@link DrawingStyle#HOVER} */ - HOVER(new RGB(0xFF, 0x99, 0x00), null, 1, SWT.LINE_DOT, 255), + HOVER(null, 0, new RGB(0xFF, 0xFF, 0xFF), 64, 1, SWT.LINE_DOT), /** - * The style used to draw anchors (lines to the other views the given view - * is anchored to) + * The style definition corresponding to {@link DrawingStyle#ANCHOR} */ - ANCHOR(new RGB(0xFF, 0x00, 0x00), null, 1, SWT.LINE_SOLID, 255), + ANCHOR(new RGB(0x00, 0x99, 0xFF), 96, SWT.LINE_SOLID), /** - * The style used to draw outlines (the structure of views) + * The style definition corresponding to {@link DrawingStyle#OUTLINE} */ - OUTLINE(new RGB(0x00, 0xFF, 0x00), null, 1, SWT.LINE_DOT, 255), + OUTLINE(new RGB(0x88, 0xFF, 0x88), 160, SWT.LINE_SOLID), /** - * The style used to draw the recipient/target View of a drop. This is - * typically going to be the bounding-box of the view into which you are - * adding a new child. + * The style definition corresponding to {@link DrawingStyle#DROP_RECIPIENT} */ - DROP_RECIPIENT(new RGB(0xFF, 0x99, 0x00), new RGB(0xFF, 0x99, 0x00), 1, SWT.LINE_SOLID, 255), + DROP_RECIPIENT(new RGB(0xFF, 0x99, 0x00), 255, new RGB(0xFF, 0x99, 0x00), 160, 1, + SWT.LINE_SOLID), /** - * The style used to draw a potential drop area <b>within</b> a - * {@link #DROP_RECIPIENT}. For example, if you are dragging into a view - * with a LinearLayout, the {@link #DROP_RECIPIENT} will be the view itself, - * whereas each possible insert position between two children will be a - * {@link #DROP_ZONE}. If the mouse is over a {@link #DROP_ZONE} it should - * be drawn using the style {@link #DROP_ZONE_ACTIVE}. + * The style definition corresponding to {@link DrawingStyle#DROP_ZONE} */ - DROP_ZONE(new RGB(0xFF, 0x99, 0x00), new RGB(0xFF, 0x99, 0x00), 1, SWT.LINE_DOT, 255), + DROP_ZONE(new RGB(0x00, 0xAA, 0x00), 220, new RGB(0x55, 0xAA, 0x00), 200, 1, SWT.LINE_SOLID), /** - * The style used to draw a currently active drop zone within a drop - * recipient. See the documentation for {@link #DROP_ZONE} for details on - * the distinction between {@link #DROP_RECIPIENT}, {@link #DROP_ZONE} and - * {@link #DROP_ZONE_ACTIVE}. + * The style definition corresponding to + * {@link DrawingStyle#DROP_ZONE_ACTIVE} */ - DROP_ZONE_ACTIVE(new RGB(0xFF, 0x99, 0x00), new RGB(0xFF, 0x99, 0x00), 1, SWT.LINE_SOLID, 255), + DROP_ZONE_ACTIVE(new RGB(0x00, 0xAA, 0x00), 220, new RGB(0x00, 0xAA, 0x00), 128, 2, + SWT.LINE_SOLID), /** - * The style used to raw illegal/error/invalid markers + * The style definition corresponding to {@link DrawingStyle#DROP_PREVIEW} */ - INVALID(new RGB(0x00, 0x00, 0xFF), null, 3, SWT.LINE_SOLID, 255), + DROP_PREVIEW(new RGB(0xFF, 0x99, 0x00), 255, null, 0, 2, SWT.LINE_CUSTOM), /** - * A style used for unspecified purposes; can be used by a client to have - * yet another color that is domain specific; using this color constant - * rather than your own hardcoded value means that you will be guaranteed to - * pick up a color that is themed properly and will look decent with the - * rest of the colors + * The style definition corresponding to {@link DrawingStyle#HELP} */ - CUSTOM1(new RGB(0xFF, 0x00, 0xFF), null, 1, SWT.LINE_SOLID, 255), + HELP(new RGB(0xFF, 0xFF, 0xFF), 255, new RGB(0x00, 0x00, 0x00), 128, 1, SWT.LINE_SOLID), /** - * A second styled used for unspecified purposes; see {@link #CUSTOM1} for - * details. + * The style definition corresponding to {@link DrawingStyle#INVALID} */ - CUSTOM2(new RGB(0x00, 0xFF, 0xFF), null, 1, SWT.LINE_DOT, 255); + INVALID(new RGB(0xFF, 0xFF, 0xFF), 255, new RGB(0xFF, 0x00, 0x00), 150, 2, SWT.LINE_SOLID), + + /** + * The style definition corresponding to {@link DrawingStyle#CUSTOM1} + */ + CUSTOM1(new RGB(0xFF, 0x00, 0xFF), 255, null, 0, 1, SWT.LINE_SOLID), + + /** + * The style definition corresponding to {@link DrawingStyle#CUSTOM2} + */ + CUSTOM2(new RGB(0x00, 0xFF, 0xFF), 255, null, 0, 1, SWT.LINE_DOT); /** * Construct a new style value with the given foreground, background, width, * linestyle and transparency. * - * @param fg A color descriptor for the foreground color, or null if no + * @param stroke A color descriptor for the foreground color, or null if no * foreground color should be set - * @param bg A color descriptor for the background color, or null if no + * @param fill A color descriptor for the background color, or null if no * foreground color should be set - * @param width The line width, in pixels, or 0 if no line width should be - * set + * @param lineWidth The line width, in pixels, or 0 if no line width should + * be set * @param lineStyle The SWT line style - such as {@link SWT#LINE_SOLID}. - * @param alpha The alpha value, an integer in the range 0 to 255 where 0 is - * fully transparent and 255 is fully opaque. + * @param strokeAlpha The alpha value of the stroke, an integer in the range 0 to 255 + * where 0 is fully transparent and 255 is fully opaque. + * @param fillAlpha The alpha value of the fill, an integer in the range 0 to 255 + * where 0 is fully transparent and 255 is fully opaque. */ - private SwtDrawingStyle(RGB fg, RGB bg, int width, int lineStyle, int alpha) { - mFg = fg; - mBg = bg; - mWidth = width; + private SwtDrawingStyle(RGB stroke, int strokeAlpha, RGB fill, int fillAlpha, int lineWidth, + int lineStyle) { + mStroke = stroke; + mFill = fill; + mLineWidth = lineWidth; mLineStyle = lineStyle; - mAlpha = alpha; + mStrokeAlpha = strokeAlpha; + mFillAlpha = fillAlpha; } /** - * Return the foreground RGB color description to be used for this style, or - * null if none + * Convenience constructor for typical drawing styles, which do not specify + * a fill and use a standard thickness line + * + * @param stroke Stroke color to be used (e.g. for the border/foreground) + * @param strokeAlpha Transparency to use for the stroke; 0 is transparent + * and 255 is fully opaque. + * @param lineStyle The SWT line style - such as {@link SWT#LINE_SOLID}. */ - public RGB getForeground() { - return mFg; + private SwtDrawingStyle(RGB stroke, int strokeAlpha, int lineStyle) { + this(stroke, strokeAlpha, null, 255, 1, lineStyle); } /** - * Return the background RGB color description to be used for this style, or - * null if none + * Return the stroke/foreground/border RGB color description to be used for + * this style, or null if none */ - public RGB getBackground() { - return mBg; + public RGB getStrokeColor() { + return mStroke; + } + + /** + * Return the fill/background/interior RGB color description to be used for + * this style, or null if none + */ + public RGB getFillColor() { + return mFill; } /** Return the line width to be used for this style */ public int getLineWidth() { - return mWidth; + return mLineWidth; } /** Return the SWT line style to be used for this style */ @@ -150,9 +164,20 @@ public enum SwtDrawingStyle { return mLineStyle; } - /** Return the alpha value (in the range 0,255) to be used for this style */ - public int getAlpha() { - return mAlpha; + /** + * Return the stroke alpha value (in the range 0,255) to be used for this + * style + */ + public int getStrokeAlpha() { + return mStrokeAlpha; + } + + /** + * Return the fill alpha value (in the range 0,255) to be used for this + * style + */ + public int getFillAlpha() { + return mFillAlpha; } /** @@ -161,10 +186,10 @@ public enum SwtDrawingStyle { */ public static SwtDrawingStyle of(DrawingStyle style) { switch (style) { - case SELECTION_BORDER: - return SELECTION_BORDER; - case SELECTION_FILL: - return SELECTION_FILL; + case SELECTION: + return SELECTION; + case GUIDELINE: + return GUIDELINE; case HOVER: return HOVER; case ANCHOR: @@ -177,6 +202,10 @@ public enum SwtDrawingStyle { return DROP_ZONE_ACTIVE; case DROP_RECIPIENT: return DROP_RECIPIENT; + case DROP_PREVIEW: + return DROP_PREVIEW; + case HELP: + return HELP; case INVALID: return INVALID; case CUSTOM1: @@ -190,13 +219,21 @@ public enum SwtDrawingStyle { } } - private final RGB mFg; + /** RGB description of the stroke/foreground/border color */ + private final RGB mStroke; - private final RGB mBg; + /** RGB description of the fill/foreground/interior color */ + private final RGB mFill; - private final int mWidth; + /** Pixel thickness of the stroke/border */ + private final int mLineWidth; + /** SWT line style of the border/stroke */ private final int mLineStyle; - private final int mAlpha; + /** Alpha (in the range 0-255) of the stroke/border */ + private final int mStrokeAlpha; + + /** Alpha (in the range 0-255) of the fill/interior */ + private final int mFillAlpha; } |