aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ConstraintPainter.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ConstraintPainter.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ConstraintPainter.java783
1 files changed, 0 insertions, 783 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ConstraintPainter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ConstraintPainter.java
deleted file mode 100644
index 447d2d880..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ConstraintPainter.java
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * 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.relative;
-
-import static com.android.ide.common.api.DrawingStyle.DEPENDENCY;
-import static com.android.ide.common.api.DrawingStyle.GUIDELINE;
-import static com.android.ide.common.api.DrawingStyle.GUIDELINE_DASHED;
-import static com.android.ide.common.api.SegmentType.BASELINE;
-import static com.android.ide.common.api.SegmentType.BOTTOM;
-import static com.android.ide.common.api.SegmentType.CENTER_HORIZONTAL;
-import static com.android.ide.common.api.SegmentType.CENTER_VERTICAL;
-import static com.android.ide.common.api.SegmentType.LEFT;
-import static com.android.ide.common.api.SegmentType.RIGHT;
-import static com.android.ide.common.api.SegmentType.TOP;
-import static com.android.ide.common.api.SegmentType.UNKNOWN;
-import static com.android.ide.common.layout.relative.ConstraintType.ALIGN_BASELINE;
-import static com.android.ide.common.layout.relative.ConstraintType.ALIGN_BOTTOM;
-import static com.android.ide.common.layout.relative.ConstraintType.LAYOUT_ABOVE;
-import static com.android.ide.common.layout.relative.ConstraintType.LAYOUT_BELOW;
-import static com.android.ide.common.layout.relative.ConstraintType.LAYOUT_LEFT_OF;
-import static com.android.ide.common.layout.relative.ConstraintType.LAYOUT_RIGHT_OF;
-
-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.common.api.SegmentType;
-import com.android.ide.common.layout.relative.DependencyGraph.Constraint;
-import com.android.ide.common.layout.relative.DependencyGraph.ViewData;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * The {@link ConstraintPainter} is responsible for painting relative layout constraints -
- * such as a source node having its top edge constrained to a target node with a given margin.
- * This painter is used both to show static constraints, as well as visualizing proposed
- * constraints during a move or resize operation.
- */
-public class ConstraintPainter {
- /** The size of the arrow head */
- private static final int ARROW_SIZE = 5;
- /** Size (height for horizontal, and width for vertical) parent feedback rectangles */
- private static final int PARENT_RECT_SIZE = 12;
-
- /**
- * Paints a given match as a constraint.
- *
- * @param graphics the graphics context
- * @param sourceBounds the source bounds
- * @param match the match
- */
- static void paintConstraint(IGraphics graphics, Rect sourceBounds, Match match) {
- Rect targetBounds = match.edge.node.getBounds();
- ConstraintType type = match.type;
- assert type != null;
- paintConstraint(graphics, type, match.with.node, sourceBounds, match.edge.node,
- targetBounds, null /* allConstraints */, true /* highlightTargetEdge */);
- }
-
- /**
- * Paints a constraint.
- * <p>
- * TODO: when there are multiple links originating in the same direction from
- * center, maybe offset them slightly from each other?
- *
- * @param graphics the graphics context to draw into
- * @param constraint The constraint to be drawn
- */
- private static void paintConstraint(IGraphics graphics, Constraint constraint,
- Set<Constraint> allConstraints) {
- ViewData source = constraint.from;
- ViewData target = constraint.to;
-
- INode sourceNode = source.node;
- INode targetNode = target.node;
- if (sourceNode == targetNode) {
- // Self reference - don't visualize
- return;
- }
-
- Rect sourceBounds = sourceNode.getBounds();
- Rect targetBounds = targetNode.getBounds();
- paintConstraint(graphics, constraint.type, sourceNode, sourceBounds, targetNode,
- targetBounds, allConstraints, false /* highlightTargetEdge */);
- }
-
- /**
- * Paint selection feedback by painting constraints for the selected nodes
- *
- * @param graphics the graphics context
- * @param parentNode the parent relative layout
- * @param childNodes the nodes whose constraints should be painted
- * @param showDependents whether incoming constraints should be shown as well
- */
- public static void paintSelectionFeedback(IGraphics graphics, INode parentNode,
- List<? extends INode> childNodes, boolean showDependents) {
-
- DependencyGraph dependencyGraph = new DependencyGraph(parentNode);
- Set<INode> horizontalDeps = dependencyGraph.dependsOn(childNodes, false /* vertical */);
- Set<INode> verticalDeps = dependencyGraph.dependsOn(childNodes, true /* vertical */);
- Set<INode> deps = new HashSet<INode>(horizontalDeps.size() + verticalDeps.size());
- deps.addAll(horizontalDeps);
- deps.addAll(verticalDeps);
- if (deps.size() > 0) {
- graphics.useStyle(DEPENDENCY);
- for (INode node : deps) {
- // Don't highlight the selected nodes themselves
- if (childNodes.contains(node)) {
- continue;
- }
- Rect bounds = node.getBounds();
- graphics.fillRect(bounds);
- }
- }
-
- graphics.useStyle(GUIDELINE);
- for (INode childNode : childNodes) {
- ViewData view = dependencyGraph.getView(childNode);
- if (view == null) {
- continue;
- }
-
- // Paint all incoming constraints
- if (showDependents) {
- paintConstraints(graphics, view.dependedOnBy);
- }
-
- // Paint all outgoing constraints
- paintConstraints(graphics, view.dependsOn);
- }
- }
-
- /**
- * Paints a set of constraints.
- */
- private static void paintConstraints(IGraphics graphics, List<Constraint> constraints) {
- Set<Constraint> mutableConstraintSet = new HashSet<Constraint>(constraints);
-
- // WORKAROUND! Hide alignBottom attachments if we also have a alignBaseline
- // constraint; this is because we also *add* alignBottom attachments when you add
- // alignBaseline constraints to work around a surprising behavior of baseline
- // constraints.
- for (Constraint constraint : constraints) {
- if (constraint.type == ALIGN_BASELINE) {
- // Remove any baseline
- for (Constraint c : constraints) {
- if (c.type == ALIGN_BOTTOM && c.to.node == constraint.to.node) {
- mutableConstraintSet.remove(c);
- }
- }
- }
- }
-
- for (Constraint constraint : constraints) {
- // paintConstraint can digest more than one constraint, so we need to keep
- // checking to see if the given constraint is still relevant.
- if (mutableConstraintSet.contains(constraint)) {
- paintConstraint(graphics, constraint, mutableConstraintSet);
- }
- }
- }
-
- /**
- * Paints a constraint of the given type from the given source node, to the
- * given target node, with the specified bounds.
- */
- private static void paintConstraint(IGraphics graphics, ConstraintType type, INode sourceNode,
- Rect sourceBounds, INode targetNode, Rect targetBounds,
- Set<Constraint> allConstraints, boolean highlightTargetEdge) {
-
- SegmentType sourceSegmentTypeX = type.sourceSegmentTypeX;
- SegmentType sourceSegmentTypeY = type.sourceSegmentTypeY;
- SegmentType targetSegmentTypeX = type.targetSegmentTypeX;
- SegmentType targetSegmentTypeY = type.targetSegmentTypeY;
-
- // Horizontal center constraint?
- if (sourceSegmentTypeX == CENTER_VERTICAL && targetSegmentTypeX == CENTER_VERTICAL) {
- paintHorizontalCenterConstraint(graphics, sourceBounds, targetBounds);
- return;
- }
-
- // Vertical center constraint?
- if (sourceSegmentTypeY == CENTER_HORIZONTAL && targetSegmentTypeY == CENTER_HORIZONTAL) {
- paintVerticalCenterConstraint(graphics, sourceBounds, targetBounds);
- return;
- }
-
- // Corner constraint?
- if (allConstraints != null
- && (type == LAYOUT_ABOVE || type == LAYOUT_BELOW
- || type == LAYOUT_LEFT_OF || type == LAYOUT_RIGHT_OF)) {
- if (paintCornerConstraint(graphics, type, sourceNode, sourceBounds, targetNode,
- targetBounds, allConstraints)) {
- return;
- }
- }
-
- // Vertical constraint?
- if (sourceSegmentTypeX == UNKNOWN) {
- paintVerticalConstraint(graphics, type, sourceNode, sourceBounds, targetNode,
- targetBounds, highlightTargetEdge);
- return;
- }
-
- // Horizontal constraint?
- if (sourceSegmentTypeY == UNKNOWN) {
- paintHorizontalConstraint(graphics, type, sourceNode, sourceBounds, targetNode,
- targetBounds, highlightTargetEdge);
- return;
- }
-
- // This shouldn't happen - it means we have a constraint that defines all sides
- // and is not a centering constraint
- assert false;
- }
-
- /**
- * Paints a corner constraint, or returns false if this constraint is not a corner.
- * A corner is one where there are two constraints from this source node to the
- * same target node, one horizontal and one vertical, to the closest edges on
- * the target node.
- * <p>
- * Corners are a common occurrence. If we treat the horizontal and vertical
- * constraints separately (below & toRightOf), then we end up with a lot of
- * extra lines and arrows -- e.g. two shared edges and arrows pointing to these
- * shared edges:
- *
- * <pre>
- * +--------+ |
- * | Target -->
- * +----|---+ |
- * v
- * - - - - - -|- - - - - -
- * ^
- * | +---|----+
- * <-- Source |
- * | +--------+
- *
- * Instead, we can simply draw a diagonal arrow here to represent BOTH constraints and
- * reduce clutter:
- *
- * +---------+
- * | Target _|
- * +-------|\+
- * \
- * \--------+
- * | Source |
- * +--------+
- * </pre>
- *
- * @param graphics the graphics context to draw
- * @param type the constraint to be drawn
- * @param sourceNode the source node
- * @param sourceBounds the bounds of the source node
- * @param targetNode the target node
- * @param targetBounds the bounds of the target node
- * @param allConstraints the set of all constraints; if a corner is found and painted the
- * matching corner constraint is removed from the set
- * @return true if the constraint was handled and painted as a corner, false otherwise
- */
- private static boolean paintCornerConstraint(IGraphics graphics, ConstraintType type,
- INode sourceNode, Rect sourceBounds, INode targetNode, Rect targetBounds,
- Set<Constraint> allConstraints) {
-
- SegmentType sourceSegmentTypeX = type.sourceSegmentTypeX;
- SegmentType sourceSegmentTypeY = type.sourceSegmentTypeY;
- SegmentType targetSegmentTypeX = type.targetSegmentTypeX;
- SegmentType targetSegmentTypeY = type.targetSegmentTypeY;
-
- ConstraintType opposite1 = null, opposite2 = null;
- switch (type) {
- case LAYOUT_BELOW:
- case LAYOUT_ABOVE:
- opposite1 = LAYOUT_LEFT_OF;
- opposite2 = LAYOUT_RIGHT_OF;
- break;
- case LAYOUT_LEFT_OF:
- case LAYOUT_RIGHT_OF:
- opposite1 = LAYOUT_ABOVE;
- opposite2 = LAYOUT_BELOW;
- break;
- default:
- return false;
- }
- Constraint pair = null;
- for (Constraint constraint : allConstraints) {
- if ((constraint.type == opposite1 || constraint.type == opposite2) &&
- constraint.to.node == targetNode && constraint.from.node == sourceNode) {
- pair = constraint;
- break;
- }
- }
-
- // TODO -- ensure that the nodes are adjacent! In other words, that
- // their bounds are within N pixels.
-
- if (pair != null) {
- // Visualize the corner constraint
- if (sourceSegmentTypeX == UNKNOWN) {
- sourceSegmentTypeX = pair.type.sourceSegmentTypeX;
- }
- if (sourceSegmentTypeY == UNKNOWN) {
- sourceSegmentTypeY = pair.type.sourceSegmentTypeY;
- }
- if (targetSegmentTypeX == UNKNOWN) {
- targetSegmentTypeX = pair.type.targetSegmentTypeX;
- }
- if (targetSegmentTypeY == UNKNOWN) {
- targetSegmentTypeY = pair.type.targetSegmentTypeY;
- }
-
- int x1, y1, x2, y2;
- if (sourceSegmentTypeX == LEFT) {
- x1 = sourceBounds.x + 1 * sourceBounds.w / 4;
- } else {
- x1 = sourceBounds.x + 3 * sourceBounds.w / 4;
- }
- if (sourceSegmentTypeY == TOP) {
- y1 = sourceBounds.y + 1 * sourceBounds.h / 4;
- } else {
- y1 = sourceBounds.y + 3 * sourceBounds.h / 4;
- }
- if (targetSegmentTypeX == LEFT) {
- x2 = targetBounds.x + 1 * targetBounds.w / 4;
- } else {
- x2 = targetBounds.x + 3 * targetBounds.w / 4;
- }
- if (targetSegmentTypeY == TOP) {
- y2 = targetBounds.y + 1 * targetBounds.h / 4;
- } else {
- y2 = targetBounds.y + 3 * targetBounds.h / 4;
- }
-
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(x1, y1, x2, y2, ARROW_SIZE);
-
- // Don't process this constraint on its own later.
- allConstraints.remove(pair);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Paints a vertical constraint, handling the various scenarios where there are
- * margins, or where the two nodes overlap horizontally and where they don't, etc.
- * <p>
- * Here's an example of what will be shown for a "below" constraint where the
- * nodes do not overlap horizontally and the target node has a bottom margin:
- * <pre>
- * +--------+
- * | Target |
- * +--------+
- * |
- * v
- * - - - - - - - - - - - - - -
- * ^
- * |
- * +--------+
- * | Source |
- * +--------+
- * </pre>
- */
- private static void paintVerticalConstraint(IGraphics graphics, ConstraintType type,
- INode sourceNode, Rect sourceBounds, INode targetNode, Rect targetBounds,
- boolean highlightTargetEdge) {
- SegmentType sourceSegmentTypeY = type.sourceSegmentTypeY;
- SegmentType targetSegmentTypeY = type.targetSegmentTypeY;
- Margins targetMargins = targetNode.getMargins();
-
- assert sourceSegmentTypeY != UNKNOWN;
- assert targetBounds != null;
-
- int sourceY = sourceSegmentTypeY.getY(sourceNode, sourceBounds);
- int targetY = targetSegmentTypeY ==
- UNKNOWN ? sourceY : targetSegmentTypeY.getY(targetNode, targetBounds);
-
- if (highlightTargetEdge && type.isRelativeToParentEdge()) {
- graphics.useStyle(DrawingStyle.DROP_ZONE_ACTIVE);
- graphics.fillRect(targetBounds.x, targetY - PARENT_RECT_SIZE / 2,
- targetBounds.x2(), targetY + PARENT_RECT_SIZE / 2);
- }
-
- // First see if the two views overlap horizontally. If so, we can just draw a direct
- // arrow from the source up to (or down to) the target.
- //
- // +--------+
- // | Target |
- // +--------+
- // ^
- // |
- // |
- // +--------+
- // | Source |
- // +--------+
- //
- int maxLeft = Math.max(sourceBounds.x, targetBounds.x);
- int minRight = Math.min(sourceBounds.x2(), targetBounds.x2());
-
- int center = (maxLeft + minRight) / 2;
- if (center > sourceBounds.x && center < sourceBounds.x2()) {
- // Yes, the lines overlap -- just draw a straight arrow
- //
- //
- // If however there is a margin on the target edge, it should be drawn like this:
- //
- // +--------+
- // | Target |
- // +--------+
- // |
- // |
- // v
- // - - - - - - -
- // ^
- // |
- // |
- // +--------+
- // | Source |
- // +--------+
- //
- // Use a minimum threshold for this visualization since it doesn't look good
- // for small margins
- if (targetSegmentTypeY == BOTTOM && targetMargins.bottom > 5) {
- int sharedY = targetY + targetMargins.bottom;
- if (sourceY > sharedY + 2) { // Skip when source falls on the margin line
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(targetBounds.x, sharedY, targetBounds.x2(), sharedY);
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(center, sourceY, center, sharedY + 2, ARROW_SIZE);
- graphics.drawArrow(center, targetY, center, sharedY - 3, ARROW_SIZE);
- } else {
- graphics.useStyle(GUIDELINE);
- // Draw reverse arrow to make it clear the node is as close
- // at it can be
- graphics.drawArrow(center, targetY, center, sourceY, ARROW_SIZE);
- }
- return;
- } else if (targetSegmentTypeY == TOP && targetMargins.top > 5) {
- int sharedY = targetY - targetMargins.top;
- if (sourceY < sharedY - 2) {
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(targetBounds.x, sharedY, targetBounds.x2(), sharedY);
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(center, sourceY, center, sharedY - 3, ARROW_SIZE);
- graphics.drawArrow(center, targetY, center, sharedY + 3, ARROW_SIZE);
- } else {
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(center, targetY, center, sourceY, ARROW_SIZE);
- }
- return;
- }
-
- // TODO: If the center falls smack in the center of the sourceBounds,
- // AND the source node is part of the selection, then adjust the
- // center location such that it is off to the side, let's say 1/4 or 3/4 of
- // the overlap region, to ensure that it does not overlap the center selection
- // handle
-
- // When the constraint is for two immediately adjacent edges, we
- // need to make some adjustments to make sure the arrow points in the right
- // direction
- if (sourceY == targetY) {
- if (sourceSegmentTypeY == BOTTOM || sourceSegmentTypeY == BASELINE) {
- sourceY -= 2 * ARROW_SIZE;
- } else if (sourceSegmentTypeY == TOP) {
- sourceY += 2 * ARROW_SIZE;
- } else {
- assert sourceSegmentTypeY == CENTER_HORIZONTAL : sourceSegmentTypeY;
- sourceY += sourceBounds.h / 2 - 2 * ARROW_SIZE;
- }
- } else if (sourceSegmentTypeY == BASELINE) {
- sourceY = targetY - 2 * ARROW_SIZE;
- }
-
- // Center the vertical line in the overlap region
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(center, sourceY, center, targetY, ARROW_SIZE);
-
- return;
- }
-
- // If there is no horizontal overlap in the vertical constraints, then we
- // will show the attachment relative to a dashed line that extends beyond
- // the target bounds, like this:
- //
- // +--------+
- // | Target |
- // +--------+ - - - - - - - - -
- // ^
- // |
- // +--------+
- // | Source |
- // +--------+
- //
- // However, if the target node has a vertical margin, we may need to offset
- // the line:
- //
- // +--------+
- // | Target |
- // +--------+
- // |
- // v
- // - - - - - - - - - - - - - -
- // ^
- // |
- // +--------+
- // | Source |
- // +--------+
- //
- // If not, we'll need to indicate a shared edge. This is the edge that separate
- // them (but this will require me to evaluate margins!)
-
- // Compute overlap region and pick the middle
- int sharedY = targetSegmentTypeY ==
- UNKNOWN ? sourceY : targetSegmentTypeY.getY(targetNode, targetBounds);
- if (type.relativeToMargin) {
- if (targetSegmentTypeY == TOP) {
- sharedY -= targetMargins.top;
- } else if (targetSegmentTypeY == BOTTOM) {
- sharedY += targetMargins.bottom;
- }
- }
-
- int startX;
- int endX;
- if (center <= sourceBounds.x) {
- startX = targetBounds.x + targetBounds.w / 4;
- endX = sourceBounds.x2();
- } else {
- assert (center >= sourceBounds.x2());
- startX = sourceBounds.x;
- endX = targetBounds.x + 3 * targetBounds.w / 4;
- }
- // Must draw segmented line instead
- // Place the arrow 1/4 instead of 1/2 in the source to avoid overlapping with the
- // selection handles
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(startX, sharedY, endX, sharedY);
-
- // Adjust position of source arrow such that it does not sit across edge; it
- // should point directly at the edge
- if (Math.abs(sharedY - sourceY) < 2 * ARROW_SIZE) {
- if (sourceSegmentTypeY == BASELINE) {
- sourceY = sharedY - 2 * ARROW_SIZE;
- } else if (sourceSegmentTypeY == TOP) {
- sharedY = sourceY;
- sourceY = sharedY + 2 * ARROW_SIZE;
- } else {
- sharedY = sourceY;
- sourceY = sharedY - 2 * ARROW_SIZE;
- }
- }
-
- graphics.useStyle(GUIDELINE);
-
- // Draw the line from the source anchor to the shared edge
- int x = sourceBounds.x + ((sourceSegmentTypeY == BASELINE) ?
- sourceBounds.w / 2 : sourceBounds.w / 4);
- graphics.drawArrow(x, sourceY, x, sharedY, ARROW_SIZE);
-
- // Draw the line from the target to the horizontal shared edge
- int tx = targetBounds.centerX();
- if (targetSegmentTypeY == TOP) {
- int ty = targetBounds.y;
- int margin = targetMargins.top;
- if (margin == 0 || !type.relativeToMargin) {
- graphics.drawArrow(tx, ty + 2 * ARROW_SIZE, tx, ty, ARROW_SIZE);
- } else {
- graphics.drawArrow(tx, ty, tx, ty - margin, ARROW_SIZE);
- }
- } else if (targetSegmentTypeY == BOTTOM) {
- int ty = targetBounds.y2();
- int margin = targetMargins.bottom;
- if (margin == 0 || !type.relativeToMargin) {
- graphics.drawArrow(tx, ty - 2 * ARROW_SIZE, tx, ty, ARROW_SIZE);
- } else {
- graphics.drawArrow(tx, ty, tx, ty + margin, ARROW_SIZE);
- }
- } else {
- assert targetSegmentTypeY == BASELINE : targetSegmentTypeY;
- int ty = targetSegmentTypeY.getY(targetNode, targetBounds);
- graphics.drawArrow(tx, ty - 2 * ARROW_SIZE, tx, ty, ARROW_SIZE);
- }
-
- return;
- }
-
- /**
- * Paints a horizontal constraint, handling the various scenarios where there are margins,
- * or where the two nodes overlap horizontally and where they don't, etc.
- */
- private static void paintHorizontalConstraint(IGraphics graphics, ConstraintType type,
- INode sourceNode, Rect sourceBounds, INode targetNode, Rect targetBounds,
- boolean highlightTargetEdge) {
- SegmentType sourceSegmentTypeX = type.sourceSegmentTypeX;
- SegmentType targetSegmentTypeX = type.targetSegmentTypeX;
- Margins targetMargins = targetNode.getMargins();
-
- assert sourceSegmentTypeX != UNKNOWN;
- assert targetBounds != null;
-
- // See paintVerticalConstraint for explanations of the various cases.
-
- int sourceX = sourceSegmentTypeX.getX(sourceNode, sourceBounds);
- int targetX = targetSegmentTypeX == UNKNOWN ?
- sourceX : targetSegmentTypeX.getX(targetNode, targetBounds);
-
- if (highlightTargetEdge && type.isRelativeToParentEdge()) {
- graphics.useStyle(DrawingStyle.DROP_ZONE_ACTIVE);
- graphics.fillRect(targetX - PARENT_RECT_SIZE / 2, targetBounds.y,
- targetX + PARENT_RECT_SIZE / 2, targetBounds.y2());
- }
-
- int maxTop = Math.max(sourceBounds.y, targetBounds.y);
- int minBottom = Math.min(sourceBounds.y2(), targetBounds.y2());
-
- // First see if the two views overlap vertically. If so, we can just draw a direct
- // arrow from the source over to the target.
- int center = (maxTop + minBottom) / 2;
- if (center > sourceBounds.y && center < sourceBounds.y2()) {
- // See if we should draw a margin line
- if (targetSegmentTypeX == RIGHT && targetMargins.right > 5) {
- int sharedX = targetX + targetMargins.right;
- if (sourceX > sharedX + 2) { // Skip when source falls on the margin line
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(sharedX, targetBounds.y, sharedX, targetBounds.y2());
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(sourceX, center, sharedX + 2, center, ARROW_SIZE);
- graphics.drawArrow(targetX, center, sharedX - 3, center, ARROW_SIZE);
- } else {
- graphics.useStyle(GUIDELINE);
- // Draw reverse arrow to make it clear the node is as close
- // at it can be
- graphics.drawArrow(targetX, center, sourceX, center, ARROW_SIZE);
- }
- return;
- } else if (targetSegmentTypeX == LEFT && targetMargins.left > 5) {
- int sharedX = targetX - targetMargins.left;
- if (sourceX < sharedX - 2) {
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(sharedX, targetBounds.y, sharedX, targetBounds.y2());
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(sourceX, center, sharedX - 3, center, ARROW_SIZE);
- graphics.drawArrow(targetX, center, sharedX + 3, center, ARROW_SIZE);
- } else {
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(targetX, center, sourceX, center, ARROW_SIZE);
- }
- return;
- }
-
- if (sourceX == targetX) {
- if (sourceSegmentTypeX == RIGHT) {
- sourceX -= 2 * ARROW_SIZE;
- } else if (sourceSegmentTypeX == LEFT ) {
- sourceX += 2 * ARROW_SIZE;
- } else {
- assert sourceSegmentTypeX == CENTER_VERTICAL : sourceSegmentTypeX;
- sourceX += sourceBounds.w / 2 - 2 * ARROW_SIZE;
- }
- }
-
- graphics.useStyle(GUIDELINE);
- graphics.drawArrow(sourceX, center, targetX, center, ARROW_SIZE);
- return;
- }
-
- // Segment line
-
- // Compute overlap region and pick the middle
- int sharedX = targetSegmentTypeX == UNKNOWN ?
- sourceX : targetSegmentTypeX.getX(targetNode, targetBounds);
- if (type.relativeToMargin) {
- if (targetSegmentTypeX == LEFT) {
- sharedX -= targetMargins.left;
- } else if (targetSegmentTypeX == RIGHT) {
- sharedX += targetMargins.right;
- }
- }
-
- int startY, endY;
- if (center <= sourceBounds.y) {
- startY = targetBounds.y + targetBounds.h / 4;
- endY = sourceBounds.y2();
- } else {
- assert (center >= sourceBounds.y2());
- startY = sourceBounds.y;
- endY = targetBounds.y + 3 * targetBounds.h / 2;
- }
-
- // Must draw segmented line instead
- // Place at 1/4 instead of 1/2 to avoid overlapping with selection handles
- int y = sourceBounds.y + sourceBounds.h / 4;
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(sharedX, startY, sharedX, endY);
-
- // Adjust position of source arrow such that it does not sit across edge; it
- // should point directly at the edge
- if (Math.abs(sharedX - sourceX) < 2 * ARROW_SIZE) {
- if (sourceSegmentTypeX == LEFT) {
- sharedX = sourceX;
- sourceX = sharedX + 2 * ARROW_SIZE;
- } else {
- sharedX = sourceX;
- sourceX = sharedX - 2 * ARROW_SIZE;
- }
- }
-
- graphics.useStyle(GUIDELINE);
-
- // Draw the line from the source anchor to the shared edge
- graphics.drawArrow(sourceX, y, sharedX, y, ARROW_SIZE);
-
- // Draw the line from the target to the horizontal shared edge
- int ty = targetBounds.centerY();
- if (targetSegmentTypeX == LEFT) {
- int tx = targetBounds.x;
- int margin = targetMargins.left;
- if (margin == 0 || !type.relativeToMargin) {
- graphics.drawArrow(tx + 2 * ARROW_SIZE, ty, tx, ty, ARROW_SIZE);
- } else {
- graphics.drawArrow(tx, ty, tx - margin, ty, ARROW_SIZE);
- }
- } else {
- assert targetSegmentTypeX == RIGHT;
- int tx = targetBounds.x2();
- int margin = targetMargins.right;
- if (margin == 0 || !type.relativeToMargin) {
- graphics.drawArrow(tx - 2 * ARROW_SIZE, ty, tx, ty, ARROW_SIZE);
- } else {
- graphics.drawArrow(tx, ty, tx + margin, ty, ARROW_SIZE);
- }
- }
-
- return;
- }
-
- /**
- * Paints a vertical center constraint. The constraint is shown as a dashed line
- * through the vertical view, and a solid line over the node bounds.
- */
- private static void paintVerticalCenterConstraint(IGraphics graphics, Rect sourceBounds,
- Rect targetBounds) {
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(targetBounds.x, targetBounds.centerY(),
- targetBounds.x2(), targetBounds.centerY());
- graphics.useStyle(GUIDELINE);
- graphics.drawLine(sourceBounds.x, sourceBounds.centerY(),
- sourceBounds.x2(), sourceBounds.centerY());
- }
-
- /**
- * Paints a horizontal center constraint. The constraint is shown as a dashed line
- * through the horizontal view, and a solid line over the node bounds.
- */
- private static void paintHorizontalCenterConstraint(IGraphics graphics, Rect sourceBounds,
- Rect targetBounds) {
- graphics.useStyle(GUIDELINE_DASHED);
- graphics.drawLine(targetBounds.centerX(), targetBounds.y,
- targetBounds.centerX(), targetBounds.y2());
- graphics.useStyle(GUIDELINE);
- graphics.drawLine(sourceBounds.centerX(), sourceBounds.y,
- sourceBounds.centerX(), sourceBounds.y2());
- }
-} \ No newline at end of file