aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java247
1 files changed, 247 insertions, 0 deletions
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
new file mode 100644
index 000000000..97d048108
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2010 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.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;
+
+import org.eclipse.swt.graphics.GC;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The {@link SelectionOverlay} paints the current selection as an overlay.
+ */
+public class SelectionOverlay extends Overlay {
+ private final LayoutCanvas mCanvas;
+ private boolean mHidden;
+
+ /**
+ * Constructs a new {@link SelectionOverlay} tied to the given canvas.
+ *
+ * @param canvas the associated canvas
+ */
+ public SelectionOverlay(LayoutCanvas canvas) {
+ mCanvas = canvas;
+ }
+
+ /**
+ * Set whether the selection overlay should be hidden. This is done during some
+ * gestures like resize where the new bounds could be confused with the current
+ * selection bounds.
+ *
+ * @param hidden when true, hide the selection bounds, when false, unhide.
+ */
+ public void setHidden(boolean hidden) {
+ mHidden = hidden;
+ }
+
+ /**
+ * Paints the selection.
+ *
+ * @param selectionManager The {@link SelectionManager} holding the
+ * selection.
+ * @param gcWrapper The graphics context wrapper for the layout rules to use.
+ * @param gc The SWT graphics object
+ * @param rulesEngine The {@link RulesEngine} holding the rules.
+ */
+ public void paint(SelectionManager selectionManager, GCWrapper gcWrapper,
+ GC gc, RulesEngine rulesEngine) {
+ if (mHidden) {
+ return;
+ }
+
+ List<SelectionItem> selections = selectionManager.getSelections();
+ int n = selections.size();
+ if (n > 0) {
+ List<NodeProxy> selectedNodes = new ArrayList<NodeProxy>();
+ boolean isMultipleSelection = n > 1;
+ for (SelectionItem s : selections) {
+ if (s.isRoot()) {
+ // The root selection is never painted
+ continue;
+ }
+
+ NodeProxy node = s.getNode();
+ if (node != null) {
+ paintSelection(gcWrapper, gc, s, isMultipleSelection);
+ selectedNodes.add(node);
+ }
+ }
+
+ if (selectedNodes.size() > 0) {
+ paintSelectionFeedback(gcWrapper, selectedNodes, rulesEngine);
+ } else {
+ CanvasViewInfo root = mCanvas.getViewHierarchy().getRoot();
+ if (root != null) {
+ NodeProxy parent = mCanvas.getNodeFactory().create(root);
+ rulesEngine.callPaintSelectionFeedback(gcWrapper,
+ parent, Collections.<INode>emptyList(), root.getViewObject());
+ }
+ }
+
+ if (n == 1) {
+ NodeProxy node = selections.get(0).getNode();
+ if (node != null) {
+ paintHints(gcWrapper, node, rulesEngine);
+ }
+ }
+ } else {
+ CanvasViewInfo root = mCanvas.getViewHierarchy().getRoot();
+ if (root != null) {
+ NodeProxy parent = mCanvas.getNodeFactory().create(root);
+ rulesEngine.callPaintSelectionFeedback(gcWrapper,
+ parent, Collections.<INode>emptyList(), root.getViewObject());
+ }
+ }
+ }
+
+ /** Paint hint for current selection */
+ private void paintHints(GCWrapper gcWrapper, NodeProxy node, RulesEngine rulesEngine) {
+ INode parent = node.getParent();
+ if (parent instanceof NodeProxy) {
+ NodeProxy parentNode = (NodeProxy) parent;
+ List<String> infos = rulesEngine.callGetSelectionHint(parentNode, node);
+ if (infos != null && infos.size() > 0) {
+ gcWrapper.useStyle(DrawingStyle.HELP);
+
+ Rect b = mCanvas.getImageOverlay().getImageBounds();
+ if (b == null) {
+ return;
+ }
+
+ // Compute the location to display the help. This is done in
+ // layout coordinates, so we need to apply the scale in reverse
+ // when making pixel margins
+ // TODO: We could take the Canvas dimensions into account to see
+ // where there is more room.
+ // TODO: The scrollbars should take the presence of hint text
+ // into account.
+ double scale = mCanvas.getScale();
+ int x, y;
+ if (b.w > b.h) {
+ x = (int) (b.x + 3 / scale);
+ y = (int) (b.y + b.h + 6 / scale);
+ } else {
+ x = (int) (b.x + b.w + 6 / scale);
+ y = (int) (b.y + 3 / scale);
+ }
+ gcWrapper.drawBoxedStrings(x, y, infos);
+ }
+ }
+ }
+
+ private void paintSelectionFeedback(GCWrapper gcWrapper, List<NodeProxy> nodes,
+ RulesEngine rulesEngine) {
+ // Add fastpath for n=1
+
+ // Group nodes into parent/child groups
+ Set<INode> parents = new HashSet<INode>();
+ for (INode node : nodes) {
+ INode parent = node.getParent();
+ if (/*parent == null || */parent instanceof NodeProxy) {
+ NodeProxy parentNode = (NodeProxy) parent;
+ parents.add(parentNode);
+ }
+ }
+ ViewHierarchy viewHierarchy = mCanvas.getViewHierarchy();
+ for (INode parent : parents) {
+ List<INode> children = new ArrayList<INode>();
+ for (INode node : nodes) {
+ INode nodeParent = node.getParent();
+ if (nodeParent == parent) {
+ children.add(node);
+ }
+ }
+ CanvasViewInfo viewInfo = viewHierarchy.findViewInfoFor((NodeProxy) parent);
+ Object view = viewInfo != null ? viewInfo.getViewObject() : null;
+
+ rulesEngine.callPaintSelectionFeedback(gcWrapper,
+ (NodeProxy) parent, children, view);
+ }
+ }
+
+ /** Called by the canvas when a view is being selected. */
+ private void paintSelection(IGraphics gc, GC swtGc, SelectionItem item,
+ boolean isMultipleSelection) {
+ CanvasViewInfo view = item.getViewInfo();
+ if (view.isHidden()) {
+ return;
+ }
+
+ NodeProxy selectedNode = item.getNode();
+ Rect r = selectedNode.getBounds();
+ if (!r.isValid()) {
+ return;
+ }
+
+ gc.useStyle(DrawingStyle.SELECTION);
+
+ 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
+ List<CanvasViewInfo> siblings = view.getNodeSiblings();
+ if (siblings != null) {
+ for (CanvasViewInfo sibling : siblings) {
+ if (sibling != view) {
+ r = SwtUtils.toRect(sibling.getSelectionRect());
+ gc.fillRect(r);
+ gc.drawRect(r);
+ }
+ }
+ }
+
+ // Paint selection handles. These are painted in control coordinates on the
+ // real SWT GC object rather than in layout coordinates on the GCWrapper,
+ // since we want them to have a fixed size that is independent of the
+ // screen zoom.
+ CanvasTransform horizontalTransform = mCanvas.getHorizontalTransform();
+ CanvasTransform verticalTransform = mCanvas.getVerticalTransform();
+ int radius = SelectionHandle.PIXEL_RADIUS;
+ int doubleRadius = 2 * radius;
+ for (SelectionHandle handle : item.getSelectionHandles()) {
+ int cx = horizontalTransform.translate(handle.centerX);
+ int cy = verticalTransform.translate(handle.centerY);
+
+ SwtDrawingStyle style = SwtDrawingStyle.of(DrawingStyle.SELECTION);
+ gc.setAlpha(style.getStrokeAlpha());
+ swtGc.fillRectangle(cx - radius, cy - radius, doubleRadius, doubleRadius);
+ }
+ }
+}