Search in sources :

Example 11 with ConstraintAnchor

use of android.support.constraint.solver.widgets.ConstraintAnchor in project android by JetBrains.

the class SnapPlacement method findSnapMargin.

/**
     * Utility function iterating through the widgets, comparing the specified anchors,
     * and finding snapping candidate on the indicated margin.
     * <p/>
     * TODO: iterate only on the closest widget (right now we iterate on all of them
     * and *then* check the distance)
     *
     * @param widgets      the list of known widgets
     * @param widget       the widget we operate on
     * @param candidate    the SnapCandidate instance we need to fill
     * @param isVertical   flag set indicating if we are looking at horizontal or vertical anchors
     * @param sourceAnchor the anchor type we are looking at on the widget
     * @param targetAnchor the anchor type we will compare to
     * @param margin       the margin value we are trying to snap on
     * @param slope        the allowed slope
     */
private static void findSnapMargin(Collection<ConstraintWidget> widgets, ConstraintWidget widget, SnapCandidate candidate, boolean isVertical, ConstraintAnchor.Type sourceAnchor, ConstraintAnchor.Type targetAnchor, int margin, int slope) {
    if (widget instanceof Guideline) {
        return;
    }
    ConstraintAnchor source = widget.getAnchor(sourceAnchor);
    for (ConstraintWidget w : widgets) {
        if (w == widget) {
            continue;
        }
        ConstraintAnchor target = w.getAnchor(targetAnchor);
        if (target == null) {
            // for e.g. guidelines
            continue;
        }
        ConstraintHandle sourceHandle = WidgetInteractionTargets.constraintHandle(source);
        ConstraintHandle targetHandle = WidgetInteractionTargets.constraintHandle(target);
        if (sourceHandle == null || targetHandle == null) {
            continue;
        }
        int anchorDistance = sourceHandle.getDrawX() - targetHandle.getDrawX() - margin;
        if (isVertical) {
            anchorDistance = sourceHandle.getDrawY() - targetHandle.getDrawY() - margin;
        }
        if (anchorDistance < 0) {
            continue;
        }
        int minDistance = sourceHandle.getDistanceFrom(target.getOwner());
        double distance = Math.sqrt(anchorDistance * anchorDistance + minDistance * minDistance);
        if (target.getOwner() instanceof Guideline) {
            distance = Math.sqrt(anchorDistance * anchorDistance);
        }
        if (anchorDistance < slope && distance <= candidate.distance && (ALLOWS_ALL_SNAP_MARGIN || distance < MAX_SNAP_MARGIN_DISTANCE)) {
            if (candidate.target == null || (candidate.margin > margin || (candidate.target.getType() == ConstraintAnchor.Type.CENTER_X || candidate.target.getType() == ConstraintAnchor.Type.CENTER || candidate.target.getType() == ConstraintAnchor.Type.CENTER_Y))) {
                candidate.distance = distance;
                candidate.target = target;
                candidate.source = source;
                candidate.margin = margin;
            }
        }
    }
}
Also used : ConstraintAnchor(android.support.constraint.solver.widgets.ConstraintAnchor) ConstraintWidget(android.support.constraint.solver.widgets.ConstraintWidget) Guideline(android.support.constraint.solver.widgets.Guideline) Point(java.awt.Point)

Example 12 with ConstraintAnchor

use of android.support.constraint.solver.widgets.ConstraintAnchor in project android by JetBrains.

the class SnapPlacement method snapWidget.

/**
     * Constraint a candidate position for a given widget.
     * If the widget has existing connections, we'll allow moving on the corresponding axis
     * by modifying the margin of the connection; we'll also snap to WidgetsView.GRID_SPACING
     * the margin's value.
     * If the widget did not have connections on that axis, we'll try to snap the new position to
     * closeby widget. Otherwise, we'll snap the position on the base grid,
     * using WidgetsView.GRID_SPACING. The function will also fill in the snapCandidates
     * array with any SnapCandidate used.
     *
     * @param widgets        the list of known widgets
     * @param widget         the widget we operate on
     * @param candidatePoint the candidate new position
     * @param useGridSnap    flag to use or not snapping on the base grid
     * @param snapCandidates an array that will contain the snap candidates if any.
     * @param transform      the view transform
     */
public static void snapWidget(Collection<ConstraintWidget> widgets, ConstraintWidget widget, Point candidatePoint, boolean useGridSnap, ArrayList<SnapCandidate> snapCandidates, ViewTransform transform) {
    if (widget instanceof Guideline) {
        return;
    }
    ConstraintAnchor left = widget.getAnchor(ConstraintAnchor.Type.LEFT);
    ConstraintAnchor right = widget.getAnchor(ConstraintAnchor.Type.RIGHT);
    if (left.isConnected() && right.isConnected()) {
    // do nothing, as movement is constrained
    } else {
        widget.setDrawX(candidatePoint.x);
        WidgetCompanion widgetCompanion = (WidgetCompanion) widget.getCompanionWidget();
        WidgetInteractionTargets widgetInteraction = widgetCompanion.getWidgetInteractionTargets();
        widgetInteraction.updatePosition(transform);
        if (!checkHorizontalMarginsSnap(snapCandidates, widget, candidatePoint, DEFAULT_MARGIN)) {
            if (!snapExistingHorizontalMargin(widget, candidatePoint)) {
                SnapCandidate candidate = new SnapCandidate();
                findSnap(widgets, widget, candidate, true);
                if (candidate.target == null || candidate.target.getType() == ConstraintAnchor.Type.CENTER_X || candidate.target.getType() == ConstraintAnchor.Type.CENTER) {
                    // no anchor found, let's try to find margins
                    for (int i = SNAP_MARGIN_INCREMENT; i <= SNAP_MARGIN_MAX; i += SNAP_MARGIN_INCREMENT) {
                        findSnapMargin(widgets, widget, candidate, false, ConstraintAnchor.Type.LEFT, ConstraintAnchor.Type.RIGHT, i, CONNECTION_SLOPE);
                        findSnapMargin(widgets, widget, candidate, false, ConstraintAnchor.Type.RIGHT, ConstraintAnchor.Type.LEFT, -i, CONNECTION_SLOPE);
                    }
                }
                if (!snapToHorizontalAnchor(candidatePoint, widget, candidate)) {
                    if (useGridSnap) {
                        snapHorizontalGrid(candidatePoint);
                    }
                } else {
                    snapCandidates.add(candidate);
                }
            }
        }
    }
    ConstraintAnchor top = widget.getAnchor(ConstraintAnchor.Type.TOP);
    ConstraintAnchor bottom = widget.getAnchor(ConstraintAnchor.Type.BOTTOM);
    ConstraintAnchor baseline = widget.getAnchor(ConstraintAnchor.Type.BASELINE);
    if (baseline.isConnected() || (top.isConnected() && bottom.isConnected())) {
    // do nothing, as movement is constrained
    } else {
        widget.setDrawY(candidatePoint.y);
        WidgetCompanion widgetCompanion = (WidgetCompanion) widget.getCompanionWidget();
        WidgetInteractionTargets widgetInteraction = widgetCompanion.getWidgetInteractionTargets();
        widgetInteraction.updatePosition(transform);
        if (!checkVerticalMarginsSnap(snapCandidates, widget, candidatePoint, DEFAULT_MARGIN)) {
            if (!snapExistingVerticalMargin(widget, candidatePoint)) {
                SnapCandidate candidate = new SnapCandidate();
                findSnap(widgets, widget, candidate, false);
                if (candidate.target == null || candidate.target.getType() == ConstraintAnchor.Type.CENTER_Y || candidate.target.getType() == ConstraintAnchor.Type.CENTER) {
                    // no anchor found, let's try to find margins
                    for (int i = SNAP_MARGIN_INCREMENT; i <= SNAP_MARGIN_MAX; i += SNAP_MARGIN_INCREMENT) {
                        findSnapMargin(widgets, widget, candidate, true, ConstraintAnchor.Type.TOP, ConstraintAnchor.Type.BOTTOM, i, CONNECTION_SLOPE);
                        findSnapMargin(widgets, widget, candidate, true, ConstraintAnchor.Type.BOTTOM, ConstraintAnchor.Type.TOP, -i, CONNECTION_SLOPE);
                    }
                }
                if (!snapToVerticalAnchor(candidatePoint, widget, candidate)) {
                    if (useGridSnap) {
                        snapVerticalGrid(candidatePoint);
                    }
                } else {
                    snapCandidates.add(candidate);
                }
            }
        }
    }
}
Also used : ConstraintAnchor(android.support.constraint.solver.widgets.ConstraintAnchor) WidgetCompanion(com.android.tools.sherpa.structure.WidgetCompanion) Guideline(android.support.constraint.solver.widgets.Guideline) Point(java.awt.Point)

Example 13 with ConstraintAnchor

use of android.support.constraint.solver.widgets.ConstraintAnchor in project android by JetBrains.

the class SnapPlacement method createSnapCandidate.

/**
     * Internal utility function to create a snap candidate on the fly for a margin.
     *
     * @param widget the widget we operate on
     * @param type   the type of ConstraintAnchor we want to use for the target
     * @param x      the horizontal position for the ConstraintAnchor target
     * @param y      the vertical position for the ConstraintAnchor target
     * @return a new instance of SnapCandidate representing the margin
     */
private static SnapCandidate createSnapCandidate(ConstraintWidget widget, ConstraintAnchor.Type type, int x, int y) {
    SnapCandidate candidate = new SnapCandidate();
    candidate.source = widget.getAnchor(type);
    ConstraintWidget owner = widget.getParent();
    ConstraintAnchor anchor = new ConstraintAnchor(owner, type);
    candidate.x = x;
    candidate.y = y;
    candidate.target = anchor;
    return candidate;
}
Also used : ConstraintAnchor(android.support.constraint.solver.widgets.ConstraintAnchor) ConstraintWidget(android.support.constraint.solver.widgets.ConstraintWidget)

Example 14 with ConstraintAnchor

use of android.support.constraint.solver.widgets.ConstraintAnchor in project android by JetBrains.

the class SnapPlacement method snapExistingHorizontalMargin.

/**
     * Try move the widget on the horizontal axis, snapping an existing margin
     * to WidgetsView.GRID_SPACING
     *
     * @param widget         the widget we operate on
     * @param candidatePoint the candidate new position
     * @return true if we changed the margin on the horizontal axis
     */
private static boolean snapExistingHorizontalMargin(ConstraintWidget widget, Point candidatePoint) {
    int x = candidatePoint.x;
    ConstraintAnchor left = widget.getAnchor(ConstraintAnchor.Type.LEFT);
    ConstraintAnchor right = widget.getAnchor(ConstraintAnchor.Type.RIGHT);
    boolean snapped = false;
    if (left.isConnected() && right.isConnected()) {
    // we do nothing in this case.
    } else if (left.isConnected()) {
        int x1 = x;
        int x2 = WidgetInteractionTargets.constraintHandle(left.getTarget()).getDrawX();
        int margin = ((x1 - x2) / SceneDraw.GRID_SPACING) * SceneDraw.GRID_SPACING;
        if (margin < 0) {
            margin = 0;
        }
        left.setMargin(margin);
        snapped = true;
    } else if (right != null && right.isConnected()) {
        int x1 = x + widget.getDrawWidth();
        int x2 = WidgetInteractionTargets.constraintHandle(right.getTarget()).getDrawX();
        int margin = ((x2 - x1) / SceneDraw.GRID_SPACING) * SceneDraw.GRID_SPACING;
        if (margin < 0) {
            margin = 0;
        }
        right.setMargin(margin);
        snapped = true;
    }
    return snapped;
}
Also used : ConstraintAnchor(android.support.constraint.solver.widgets.ConstraintAnchor) Point(java.awt.Point)

Example 15 with ConstraintAnchor

use of android.support.constraint.solver.widgets.ConstraintAnchor in project android by JetBrains.

the class WidgetInteractionTargets method findResizeHandle.

/**
     * Iterate through the resize handles of this widget and return the handle intersecting
     * with the point (x, y), if any. Corner resize handles takes precedence over side handles.
     * We also don't return hits if the handles is inoperable (due to constraints on the widget)
     *
     * @param x the x coordinate of the point
     * @param y the y coordinate of the point
     * @return true if we find a resize handle below the given point
     */
public ResizeHandle findResizeHandle(float x, float y) {
    ResizeHandle candidate = null;
    if (mWidget instanceof Guideline) {
        Guideline guideline = (Guideline) mWidget;
        if (guideline.getOrientation() == Guideline.VERTICAL) {
            if (mLeftSide.hit(x, y)) {
                return mLeftSide;
            }
        } else {
            if (mTopSide.hit(x, y)) {
                return mTopSide;
            }
        }
    }
    ConstraintAnchor leftAnchor = mWidget.getAnchor(ConstraintAnchor.Type.LEFT);
    ConstraintAnchor topAnchor = mWidget.getAnchor(ConstraintAnchor.Type.TOP);
    ConstraintAnchor rightAnchor = mWidget.getAnchor(ConstraintAnchor.Type.RIGHT);
    ConstraintAnchor bottomAnchor = mWidget.getAnchor(ConstraintAnchor.Type.BOTTOM);
    ConstraintAnchor baselineAnchor = mWidget.getAnchor(ConstraintAnchor.Type.BASELINE);
    for (ResizeHandle handle : mResizeHandles) {
        if (handle.hit(x, y)) {
            boolean leftAnchorIsConnected = leftAnchor != null && leftAnchor.isConnected();
            boolean topAnchorIsConnected = topAnchor != null && topAnchor.isConnected();
            boolean rightAnchorIsConnected = rightAnchor != null && rightAnchor.isConnected();
            boolean bottomAnchorIsConnected = bottomAnchor != null && bottomAnchor.isConnected();
            boolean baselineAnchorIsConnected = baselineAnchor != null && baselineAnchor.isConnected();
            switch(handle.getType()) {
                case LEFT_TOP:
                    {
                        if (leftAnchorIsConnected || topAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case RIGHT_TOP:
                    {
                        if (rightAnchorIsConnected || topAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case LEFT_BOTTOM:
                    {
                        if (leftAnchorIsConnected || bottomAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case RIGHT_BOTTOM:
                    {
                        if (rightAnchorIsConnected || bottomAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case LEFT_SIDE:
                    {
                        if (leftAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case RIGHT_SIDE:
                    {
                        if (rightAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case TOP_SIDE:
                    {
                        if (topAnchorIsConnected || baselineAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
                case BOTTOM_SIDE:
                    {
                        if (bottomAnchorIsConnected) {
                            continue;
                        }
                    }
                    break;
            }
            if (candidate == null || candidate.isSideHandle()) {
                candidate = handle;
            }
        }
    }
    return candidate;
}
Also used : ConstraintAnchor(android.support.constraint.solver.widgets.ConstraintAnchor) Guideline(android.support.constraint.solver.widgets.Guideline)

Aggregations

ConstraintAnchor (android.support.constraint.solver.widgets.ConstraintAnchor)26 ConstraintWidget (android.support.constraint.solver.widgets.ConstraintWidget)10 Guideline (android.support.constraint.solver.widgets.Guideline)8 Point (java.awt.Point)7 ConstraintHandle (com.android.tools.sherpa.interaction.ConstraintHandle)4 ConstraintWidgetContainer (android.support.constraint.solver.widgets.ConstraintWidgetContainer)3 WidgetCompanion (com.android.tools.sherpa.structure.WidgetCompanion)3 Graphics2D (java.awt.Graphics2D)2 ArrayList (java.util.ArrayList)2 ConstraintTableLayout (android.support.constraint.solver.widgets.ConstraintTableLayout)1 WidgetDecorator (com.android.tools.sherpa.drawing.decorator.WidgetDecorator)1 WidgetInteractionTargets (com.android.tools.sherpa.interaction.WidgetInteractionTargets)1