diff options
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.java | 783 |
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 |