use of com.android.tools.sherpa.structure.WidgetCompanion in project android by JetBrains.
the class WidgetInteractionTargets method constraintHandle.
/**
* Utility function giving the ConstraintHandle associated to the given ConstraintAnchor
* @param anchor the ConstraintAnchor
* @return the associated ConstraintHandle, or null if not found
*/
public static ConstraintHandle constraintHandle(ConstraintAnchor anchor) {
if (anchor == null) {
return null;
}
ConstraintWidget widget = anchor.getOwner();
if (widget == null) {
return null;
}
if (widget.getCompanionWidget() == null) {
return null;
}
WidgetCompanion widgetCompanion = (WidgetCompanion) widget.getCompanionWidget();
WidgetInteractionTargets widgetInteraction = widgetCompanion.getWidgetInteractionTargets();
return widgetInteraction.getConstraintHandle(anchor);
}
use of com.android.tools.sherpa.structure.WidgetCompanion in project android by JetBrains.
the class WidgetMotion method dragWidget.
/**
* Drag widget to a new position
*
* @param widget widget we are moving
* @param x in android coordinate
* @param y in android coordinate
* @param snap true if we want to snap this widget against others
* @param isShiftDown true if the shift button is pressed
* @param transform the view transform
* @return the type of direction (locked in x/y or not)
*/
public int dragWidget(Point startPoint, Selection.Element widget, int x, int y, boolean snap, boolean isShiftDown, ViewTransform transform) {
int directionLockedStatus = Selection.DIRECTION_UNLOCKED;
if (widget == null) {
return directionLockedStatus;
}
Animator.setAnimationEnabled(false);
int dX = startPoint.x - widget.origin.x;
int dY = startPoint.y - widget.origin.y;
int dragX = Math.abs(widget.widget.getDrawX() - widget.origin.x);
int dragY = Math.abs(widget.widget.getDrawY() - widget.origin.y);
if (dragX > SLOPE || dragY > SLOPE) {
// Let's not show the anchors and resize handles if we are dragging
mShowDecorations = false;
}
if (isShiftDown) {
// check which overall direction we are going after enough drag
if (widget.directionLocked == Selection.DIRECTION_UNLOCKED) {
if (dragX > SLOPE || dragY > SLOPE) {
if (dragX > dragY) {
// lock in x
widget.directionLocked = Selection.DIRECTION_LOCKED_X;
directionLockedStatus = Selection.DIRECTION_LOCKED_X;
} else {
widget.directionLocked = Selection.DIRECTION_LOCKED_Y;
directionLockedStatus = Selection.DIRECTION_LOCKED_Y;
}
} else {
// prevent snapping while we are figuring out the locked axis
snap = false;
}
}
} else {
widget.directionLocked = Selection.DIRECTION_UNLOCKED;
}
candidatePoint.setLocation(x - dX, y - dY);
ConstraintWidget base = widget.widget.getParent();
if (base != null) {
// limit motion to inside base
if (candidatePoint.x < base.getDrawX()) {
candidatePoint.x = base.getDrawX();
} else if (candidatePoint.x > base.getDrawRight()) {
candidatePoint.x = base.getDrawRight();
}
if (candidatePoint.y < base.getDrawY()) {
candidatePoint.y = base.getDrawY();
} else if (candidatePoint.y > base.getDrawBottom()) {
candidatePoint.y = base.getDrawBottom();
}
}
mSnapCandidates.clear();
ArrayList<ConstraintWidget> widgetsToCheck = new ArrayList<>();
for (ConstraintWidget w : mWidgetsScene.getWidgets()) {
if (w.hasAncestor(widget.widget)) {
continue;
}
if (mSelection.contains(w)) {
continue;
}
widgetsToCheck.add(w);
}
// lock direction before applying the snap
if (widget.directionLocked == Selection.DIRECTION_LOCKED_X) {
candidatePoint.y = widget.origin.y;
} else if (widget.directionLocked == Selection.DIRECTION_LOCKED_Y) {
candidatePoint.x = widget.origin.x;
}
if (snap) {
SnapPlacement.snapWidget(widgetsToCheck, widget.widget, candidatePoint, false, mSnapCandidates, transform);
}
WidgetCompanion widgetCompanion = (WidgetCompanion) widget.widget.getCompanionWidget();
WidgetInteractionTargets widgetInteraction = widgetCompanion.getWidgetInteractionTargets();
// check if we have centered connections, if so allow moving and snapping
// on specific percentage positions
snapBias(widget.widget, candidatePoint);
widget.widget.setDrawOrigin(candidatePoint.x, candidatePoint.y);
widget.widget.forceUpdateDrawPosition();
widgetInteraction.updatePosition(transform);
mSimilarMargins.clear();
for (SnapCandidate candidate : mSnapCandidates) {
if (candidate.margin != 0) {
mSimilarMargins.add(candidate);
}
}
for (SnapCandidate candidate : mSnapCandidates) {
SnapPlacement.gatherMargins(mWidgetsScene.getWidgets(), mSimilarMargins, candidate.margin, candidate.source.isVerticalAnchor());
}
return directionLockedStatus;
}
use of com.android.tools.sherpa.structure.WidgetCompanion in project android by JetBrains.
the class WidgetMotion method snapBias.
/**
* Snap the widget's horizontal or vertical bias if we have horizontal/vertical
* centered connections
*
* @param widget the current widget
* @param candidatePoint the candidate point containing the current location
*/
private void snapBias(ConstraintWidget widget, Point candidatePoint) {
WidgetCompanion widgetCompanion = (WidgetCompanion) widget.getCompanionWidget();
int currentStyle = WidgetDecorator.BLUEPRINT_STYLE;
if (mSceneDraw != null) {
currentStyle = mSceneDraw.getCurrentStyle();
}
WidgetDecorator decorator = widgetCompanion.getWidgetDecorator(currentStyle);
ConstraintAnchor leftAnchor = widget.getAnchor(ConstraintAnchor.Type.LEFT);
ConstraintAnchor rightAnchor = widget.getAnchor(ConstraintAnchor.Type.RIGHT);
if (leftAnchor != null && rightAnchor != null && leftAnchor.isConnected() && rightAnchor.isConnected() && leftAnchor.getTarget() != rightAnchor.getTarget()) {
int begin = WidgetInteractionTargets.constraintHandle(leftAnchor.getTarget()).getDrawX();
int end = WidgetInteractionTargets.constraintHandle(rightAnchor.getTarget()).getDrawX();
int width = widget.getDrawWidth();
int delta = candidatePoint.x - begin;
float percent = delta / (float) (end - begin - width);
percent = Math.max(0, Math.min(1, percent));
percent = snapPercent(percent);
widget.setHorizontalBiasPercent(percent);
decorator.updateBias();
}
ConstraintAnchor topAnchor = widget.getAnchor(ConstraintAnchor.Type.TOP);
ConstraintAnchor bottomAnchor = widget.getAnchor(ConstraintAnchor.Type.BOTTOM);
if (topAnchor != null && bottomAnchor != null && topAnchor.isConnected() && bottomAnchor.isConnected() && topAnchor.getTarget() != bottomAnchor.getTarget()) {
int begin = WidgetInteractionTargets.constraintHandle(topAnchor.getTarget()).getDrawY();
int end = WidgetInteractionTargets.constraintHandle(bottomAnchor.getTarget()).getDrawY();
int height = widget.getDrawHeight();
int delta = candidatePoint.y - begin;
float percent = delta / (float) (end - begin - height);
percent = Math.max(0, Math.min(1, percent));
percent = snapPercent(percent);
widget.setVerticalBiasPercent(percent);
decorator.updateBias();
}
}
use of com.android.tools.sherpa.structure.WidgetCompanion in project android by JetBrains.
the class ConstraintHandle method draw.
/**
* Draw function for the ConstraintHandle
*
* @param transform the view transform
* @param g the graphics context
* @param colorSet the current colorset
* @param isSelected if the constraint is selected or not
*/
public void draw(ViewTransform transform, Graphics2D g, ColorSet colorSet, boolean isSelected) {
ConstraintWidget widget = getOwner();
WidgetCompanion companion = (WidgetCompanion) widget.getCompanionWidget();
WidgetDecorator decorator = companion.getWidgetDecorator(colorSet.getStyle());
Color backgroundColor = decorator.getBackgroundColor();
if (mType == ConstraintAnchor.Type.BASELINE) {
int x = transform.getSwingX(getOwner().getDrawX());
int y = transform.getSwingY(getOwner().getDrawY());
int w = transform.getSwingDimension(getOwner().getDrawWidth());
int baseline = transform.getSwingDimension(getOwner().getBaselineDistance());
int padding = (w - getBaselineHandleWidth(transform)) / 2;
int bh = 7;
int by = y + baseline;
if (isSelected) {
Color pre = g.getColor();
Stroke preStroke = g.getStroke();
g.setColor(colorSet.getShadow());
g.setStroke(colorSet.getShadowStroke());
g.drawRoundRect(x + padding, by - bh / 2, w - 2 * padding, bh, bh, bh);
g.setStroke(preStroke);
g.setColor(pre);
}
Color previous = g.getColor();
g.setColor(new Color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue(), previous.getAlpha()));
g.fillRoundRect(x + padding, by - bh / 2, w - 2 * padding, bh, bh, bh);
g.setColor(previous);
g.drawRoundRect(x + padding, by - bh / 2, w - 2 * padding, bh, bh, bh);
g.drawLine(x, by, x + padding, by);
g.drawLine(x + w - padding, by, x + w, by);
if (mAnchor.isConnected()) {
int margin = 2;
g.fillRoundRect(x + padding + margin, by - bh / 2 + margin, w - 2 * padding - 2 * margin, bh - 2 * margin, bh, bh);
g.drawRoundRect(x + padding + margin, by - bh / 2 + margin, w - 2 * padding - 2 * margin, bh - 2 * margin, bh, bh);
}
} else {
int innerMargin = 3;
int radius = ConnectionDraw.CONNECTION_ANCHOR_SIZE;
int dimension = radius * 2;
int cx = transform.getSwingFX(mX) - dimension / 2;
int cy = transform.getSwingFY(mY) - dimension / 2;
Ellipse2D.Float outerCircle = new Ellipse2D.Float(cx, cy, dimension, dimension);
if (isSelected) {
Color pre = g.getColor();
Stroke preStroke = g.getStroke();
g.setColor(sShadowColor);
g.setStroke(sShadowStroke);
g.draw(outerCircle);
g.setStroke(preStroke);
g.setColor(pre);
}
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(backgroundColor);
g2.fill(outerCircle);
g2.dispose();
g.draw(outerCircle);
if (mAnchor.isConnected()) {
int d = dimension - innerMargin * 2;
g.fillRoundRect(cx + innerMargin, cy + innerMargin, d, d, d, d);
g.drawRoundRect(cx + innerMargin, cy + innerMargin, d, d, d, d);
}
}
}
use of com.android.tools.sherpa.structure.WidgetCompanion 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);
}
}
}
}
}
Aggregations