/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 androidx.constraintlayout.core.dsl;
import java.util.HashMap;
import java.util.Map;
/**
* Provides the API for creating a Constraint Object for use in the Core
* ConstraintLayout & MotionLayout system
*/
public class Constraint {
private final String mId;
public static final Constraint PARENT = new Constraint("parent");
public Constraint(String id) {
mId = id;
}
public class VAnchor extends Anchor {
VAnchor(VSide side) {
super(Side.valueOf(side.name()));
}
}
public class HAnchor extends Anchor {
HAnchor(HSide side) {
super(Side.valueOf(side.name()));
}
}
public class Anchor {
final Side mSide;
Anchor mConnection = null;
int mMargin;
int mGoneMargin = Integer.MIN_VALUE;
Anchor(Side side) {
mSide = side;
}
public String getId() {
return mId;
}
Constraint getParent() {
return Constraint.this;
}
public void build(StringBuilder builder) {
if (mConnection != null) {
builder.append(mSide.toString().toLowerCase())
.append(":").append(this).append(",\n");
}
}
@Override
public String toString() {
StringBuilder ret = new StringBuilder("[");
if (mConnection != null) {
ret.append("'").append(mConnection.getId()).append("',")
.append("'").append(mConnection.mSide.toString().toLowerCase()).append("'");
}
if (mMargin != 0) {
ret.append(",").append(mMargin);
}
if (mGoneMargin != Integer.MIN_VALUE) {
if ( mMargin == 0) {
ret.append(",0,").append(mGoneMargin);
} else {
ret.append(",").append(mGoneMargin);
}
}
ret.append("]");
return ret.toString();
}
}
public enum Behaviour {
SPREAD,
WRAP,
PERCENT,
RATIO,
RESOLVED,
}
public enum ChainMode {
SPREAD,
SPREAD_INSIDE,
PACKED,
}
public enum VSide {
TOP,
BOTTOM,
BASELINE
}
public enum HSide {
LEFT,
RIGHT,
START,
END
}
public enum Side {
LEFT,
RIGHT,
TOP,
BOTTOM,
START,
END,
BASELINE
}
static int UNSET = Integer.MIN_VALUE;
static Map<ChainMode, String> chainModeMap = new HashMap<>();
static {
chainModeMap.put(ChainMode.SPREAD, "spread");
chainModeMap.put(ChainMode.SPREAD_INSIDE, "spread_inside");
chainModeMap.put(ChainMode.PACKED, "packed");
}
String helperType = null;
String helperJason = null;
private HAnchor mLeft = new HAnchor(HSide.LEFT);
private HAnchor mRight = new HAnchor(HSide.RIGHT);
private VAnchor mTop = new VAnchor(VSide.TOP);
private VAnchor mBottom = new VAnchor(VSide.BOTTOM);
private HAnchor mStart = new HAnchor(HSide.START);
private HAnchor mEnd = new HAnchor(HSide.END);
private VAnchor mBaseline = new VAnchor(VSide.BASELINE);
private int mWidth = UNSET;
private int mHeight = UNSET;
private float mHorizontalBias = Float.NaN;
private float mVerticalBias = Float.NaN;
private String mDimensionRatio = null;
private String mCircleConstraint = null;
private int mCircleRadius = Integer.MIN_VALUE;
private float mCircleAngle = Float.NaN;
private int mEditorAbsoluteX = Integer.MIN_VALUE;
private int mEditorAbsoluteY = Integer.MIN_VALUE;
private float mVerticalWeight = Float.NaN;
private float mHorizontalWeight = Float.NaN;
private ChainMode mHorizontalChainStyle = null;
private ChainMode mVerticalChainStyle = null;
private Behaviour mWidthDefault = null;
private Behaviour mHeightDefault = null;
private int mWidthMax = UNSET;
private int mHeightMax = UNSET;
private int mWidthMin = UNSET;
private int mHeightMin = UNSET;
private float mWidthPercent = Float.NaN;
private float mHeightPercent = Float.NaN;
private String[] mReferenceIds = null;
private boolean mConstrainedWidth = false;
private boolean mConstrainedHeight = false;
/**
* get left anchor
*
* @return left anchor
*/
public HAnchor getLeft() {
return mLeft;
}
/**
* get right anchor
*
* @return right anchor
*/
public HAnchor getRight() {
return mRight;
}
/**
* get top anchor
*
* @return top anchor
*/
public VAnchor getTop() {
return mTop;
}
/**
* get bottom anchor
*
* @return bottom anchor
*/
public VAnchor getBottom() {
return mBottom;
}
/**
* get start anchor
*
* @return start anchor
*/
public HAnchor getStart() {
return mStart;
}
/**
* get end anchor
*
* @return end anchor
*/
public HAnchor getEnd() {
return mEnd;
}
/**
* get baseline anchor
*
* @return baseline anchor
*/
public VAnchor getBaseline() {
return mBaseline;
}
/**
* get horizontalBias
*
* @return horizontalBias
*/
public float getHorizontalBias() {
return mHorizontalBias;
}
/**
* set horizontalBias
*
* @param horizontalBias
*/
public void setHorizontalBias(float horizontalBias) {
this.mHorizontalBias = horizontalBias;
}
/**
* get verticalBias
*
* @return verticalBias
*/
public float getVerticalBias() {
return mVerticalBias;
}
/**
* set verticalBias
*
* @param verticalBias
*/
public void setVerticalBias(float verticalBias) {
this.mVerticalBias = verticalBias;
}
/**
* get dimensionRatio
*
* @return dimensionRatio
*/
public String getDimensionRatio() {
return mDimensionRatio;
}
/**
* set dimensionRatio
*
* @param dimensionRatio
*/
public void setDimensionRatio(String dimensionRatio) {
this.mDimensionRatio = dimensionRatio;
}
/**
* get circleConstraint
*
* @return circleConstraint
*/
public String getCircleConstraint() {
return mCircleConstraint;
}
/**
* set circleConstraint
*
* @param circleConstraint
*/
public void setCircleConstraint(String circleConstraint) {
this.mCircleConstraint = circleConstraint;
}
/**
* get circleRadius
*
* @return circleRadius
*/
public int getCircleRadius() {
return mCircleRadius;
}
/**
* set circleRadius
*
* @param circleRadius
*/
public void setCircleRadius(int circleRadius) {
this.mCircleRadius = circleRadius;
}
/**
* get circleAngle
*
* @return circleAngle
*/
public float getCircleAngle() {
return mCircleAngle;
}
/**
* set circleAngle
*
* @param circleAngle
*/
public void setCircleAngle(float circleAngle) {
this.mCircleAngle = circleAngle;
}
/**
* get editorAbsoluteX
* @return editorAbsoluteX
*/
public int getEditorAbsoluteX() {
return mEditorAbsoluteX;
}
/**
* set editorAbsoluteX
* @param editorAbsoluteX
*/
public void setEditorAbsoluteX(int editorAbsoluteX) {
mEditorAbsoluteX = editorAbsoluteX;
}
/**
* get editorAbsoluteY
* @return editorAbsoluteY
*/
public int getEditorAbsoluteY() {
return mEditorAbsoluteY;
}
/**
* set editorAbsoluteY
* @param editorAbsoluteY
*/
public void setEditorAbsoluteY(int editorAbsoluteY) {
mEditorAbsoluteY = editorAbsoluteY;
}
/**
* get verticalWeight
*
* @return verticalWeight
*/
public float getVerticalWeight() {
return mVerticalWeight;
}
/**
* set verticalWeight
*
* @param verticalWeight
*/
public void setVerticalWeight(float verticalWeight) {
this.mVerticalWeight = verticalWeight;
}
/**
* get horizontalWeight
*
* @return horizontalWeight
*/
public float getHorizontalWeight() {
return mHorizontalWeight;
}
/**
* set horizontalWeight
*
* @param horizontalWeight
*/
public void setHorizontalWeight(float horizontalWeight) {
this.mHorizontalWeight = horizontalWeight;
}
/**
* get horizontalChainStyle
*
* @return horizontalChainStyle
*/
public ChainMode getHorizontalChainStyle() {
return mHorizontalChainStyle;
}
/**
* set horizontalChainStyle
*
* @param horizontalChainStyle
*/
public void setHorizontalChainStyle(
ChainMode horizontalChainStyle) {
this.mHorizontalChainStyle = horizontalChainStyle;
}
/**
* get verticalChainStyle
*
* @return verticalChainStyle
*/
@SuppressWarnings("HiddenTypeParameter")
public ChainMode getVerticalChainStyle() {
return mVerticalChainStyle;
}
/**
* set verticalChainStyle
*
* @param verticalChainStyle
*/
public void setVerticalChainStyle(
@SuppressWarnings("HiddenTypeParameter") ChainMode verticalChainStyle) {
this.mVerticalChainStyle = verticalChainStyle;
}
/**
* get widthDefault
*
* @return widthDefault
*/
@SuppressWarnings("HiddenTypeParameter")
public Behaviour getWidthDefault() {
return mWidthDefault;
}
/**
* set widthDefault
*
* @param widthDefault
*/
public void setWidthDefault(@SuppressWarnings("HiddenTypeParameter")
Behaviour widthDefault) {
this.mWidthDefault = widthDefault;
}
/**
* get heightDefault
*
* @return heightDefault
*/
@SuppressWarnings("HiddenTypeParameter")
public Behaviour getHeightDefault() {
return mHeightDefault;
}
/**
* set heightDefault
*
* @param heightDefault
*/
public void setHeightDefault(@SuppressWarnings("HiddenTypeParameter")
Behaviour heightDefault) {
this.mHeightDefault = heightDefault;
}
/**
* get widthMax
*
* @return widthMax
*/
public int getWidthMax() {
return mWidthMax;
}
/**
* set widthMax
*
* @param widthMax
*/
public void setWidthMax(int widthMax) {
this.mWidthMax = widthMax;
}
/**
* get heightMax
*
* @return heightMax
*/
public int getHeightMax() {
return mHeightMax;
}
/**
* set heightMax
*
* @param heightMax
*/
public void setHeightMax(int heightMax) {
this.mHeightMax = heightMax;
}
/**
* get widthMin
*
* @return widthMin
*/
public int getWidthMin() {
return mWidthMin;
}
/**
* set widthMin
*
* @param widthMin
*/
public void setWidthMin(int widthMin) {
this.mWidthMin = widthMin;
}
/**
* get heightMin
*
* @return heightMin
*/
public int getHeightMin() {
return mHeightMin;
}
/**
* set heightMin
*
* @param heightMin
*/
public void setHeightMin(int heightMin) {
this.mHeightMin = heightMin;
}
/**
* get widthPercent
*
* @return
*/
public float getWidthPercent() {
return mWidthPercent;
}
/**
* set widthPercent
*
* @param widthPercent
*/
public void setWidthPercent(float widthPercent) {
this.mWidthPercent = widthPercent;
}
/**
* get heightPercent
*
* @return heightPercent
*/
public float getHeightPercent() {
return mHeightPercent;
}
/**
* set heightPercent
*
* @param heightPercent
*/
public void setHeightPercent(float heightPercent) {
this.mHeightPercent = heightPercent;
}
/**
* get referenceIds
*
* @return referenceIds
*/
public String[] getReferenceIds() {
return mReferenceIds;
}
/**
* set referenceIds
*
* @param referenceIds
*/
public void setReferenceIds(String[] referenceIds) {
mReferenceIds = referenceIds;
}
/**
* is constrainedWidth
*
* @return true if width constrained
*/
public boolean isConstrainedWidth() {
return mConstrainedWidth;
}
/**
* set constrainedWidth
*
* @param constrainedWidth
*/
public void setConstrainedWidth(boolean constrainedWidth) {
this.mConstrainedWidth = constrainedWidth;
}
/**
* is constrainedHeight
*
* @return true if height constrained
*/
public boolean isConstrainedHeight() {
return mConstrainedHeight;
}
/**
* set constrainedHeight
*
* @param constrainedHeight
*/
public void setConstrainedHeight(boolean constrainedHeight) {
this.mConstrainedHeight = constrainedHeight;
}
/**
* get width
* @return width
*/
public int getWidth() {
return mWidth;
}
/**
* set width
*
* @param width
*/
public void setWidth(int width) {
mWidth = width;
}
/**
* get height
* @return height
*/
public int getHeight() {
return mHeight;
}
/**
* set height
*
* @param height
*/
public void setHeight(int height) {
mHeight = height;
}
/**
* Connect anchor to Top
*
* @param anchor anchor to be connected
*/
public void linkToTop(VAnchor anchor) {
linkToTop(anchor, 0);
}
/**
* Connect anchor to Left
*
* @param anchor anchor to be connected
*/
public void linkToLeft(HAnchor anchor) {
linkToLeft(anchor, 0);
}
/**
* Connect anchor to Right
*
* @param anchor anchor to be connected
*/
public void linkToRight(HAnchor anchor) {
linkToRight(anchor, 0);
}
/**
* Connect anchor to Start
*
* @param anchor anchor to be connected
*/
public void linkToStart(HAnchor anchor) {
linkToStart(anchor, 0);
}
/**
* Connect anchor to End
*
* @param anchor anchor to be connected
*/
public void linkToEnd(HAnchor anchor) {
linkToEnd(anchor, 0);
}
/**
* Connect anchor to Bottom
*
* @param anchor anchor to be connected
*/
public void linkToBottom(VAnchor anchor) {
linkToBottom(anchor, 0);
}
/**
* Connect anchor to Baseline
*
* @param anchor anchor to be connected
*/
public void linkToBaseline(VAnchor anchor) {
linkToBaseline(anchor, 0);
}
/**
* Connect anchor to Top
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToTop(VAnchor anchor, int margin) {
linkToTop(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to Left
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToLeft(HAnchor anchor, int margin) {
linkToLeft(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to Right
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToRight(HAnchor anchor, int margin) {
linkToRight(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to Start
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToStart(HAnchor anchor, int margin) {
linkToStart(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to End
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToEnd(HAnchor anchor, int margin) {
linkToEnd(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to Bottom
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToBottom(VAnchor anchor, int margin) {
linkToBottom(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to Baseline
*
* @param anchor anchor to be connected
* @param margin value of the margin
*/
public void linkToBaseline(VAnchor anchor, int margin) {
linkToBaseline(anchor, margin, Integer.MIN_VALUE);
}
/**
* Connect anchor to Top
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToTop(VAnchor anchor, int margin, int goneMargin) {
mTop.mConnection = anchor;
mTop.mMargin = margin;
mTop.mGoneMargin = goneMargin;
}
/**
* Connect anchor to Left
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToLeft(HAnchor anchor, int margin, int goneMargin) {
mLeft.mConnection = anchor;
mLeft.mMargin = margin;
mLeft.mGoneMargin = goneMargin;
}
/**
* Connect anchor to Right
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToRight(HAnchor anchor, int margin, int goneMargin) {
mRight.mConnection = anchor;
mRight.mMargin = margin;
mRight.mGoneMargin = goneMargin;
}
/**
* Connect anchor to Start
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToStart(HAnchor anchor, int margin, int goneMargin) {
mStart.mConnection = anchor;
mStart.mMargin = margin;
mStart.mGoneMargin = goneMargin;
}
/**
* Connect anchor to End
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToEnd(HAnchor anchor, int margin, int goneMargin) {
mEnd.mConnection = anchor;
mEnd.mMargin = margin;
mEnd.mGoneMargin = goneMargin;
}
/**
* Connect anchor to Bottom
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToBottom(VAnchor anchor, int margin, int goneMargin) {
mBottom.mConnection = anchor;
mBottom.mMargin = margin;
mBottom.mGoneMargin = goneMargin;
}
/**
* Connect anchor to Baseline
*
* @param anchor anchor to be connected
* @param margin value of the margin
* @param goneMargin value of the goneMargin
*/
public void linkToBaseline(VAnchor anchor, int margin, int goneMargin) {
mBaseline.mConnection = anchor;
mBaseline.mMargin = margin;
mBaseline.mGoneMargin = goneMargin;
}
/**
* convert a String array into a String representation
*
* @param str String array to be converted
* @return a String representation of the input array.
*/
public String convertStringArrayToString(String[] str) {
StringBuilder ret = new StringBuilder("[");
for (int i = 0; i < str.length; i++) {
ret.append((i == 0) ? "'" : ",'");
ret.append(str[i]);
ret.append("'");
}
ret.append("]");
return ret.toString();
}
protected void append(StringBuilder builder, String name, float value) {
if (Float.isNaN(value)) {
return;
}
builder.append(name);
builder.append(":").append(value).append(",\n");
}
@Override
public String toString() {
StringBuilder ret = new StringBuilder(mId + ":{\n");
mLeft.build(ret);
mRight.build(ret);
mTop.build(ret);
mBottom.build(ret);
mStart.build(ret);
mEnd.build(ret);
mBaseline.build(ret);
if (mWidth != UNSET) {
ret.append("width:").append(mWidth).append(",\n");
}
if (mHeight != UNSET) {
ret.append("height:").append(mHeight).append(",\n");
}
append(ret, "horizontalBias", mHorizontalBias);
append(ret, "verticalBias", mVerticalBias);
if (mDimensionRatio != null) {
ret.append("dimensionRatio:'").append(mDimensionRatio).append("',\n");
}
if (mCircleConstraint != null) {
if (!Float.isNaN(mCircleAngle) || mCircleRadius != Integer.MIN_VALUE) {
ret.append("circular:['").append(mCircleConstraint).append("'");
if (!Float.isNaN(mCircleAngle)) {
ret.append(",").append(mCircleAngle);
}
if (mCircleRadius != Integer.MIN_VALUE) {
if (Float.isNaN(mCircleAngle)) {
ret.append(",0,").append(mCircleRadius);
} else {
ret.append(",").append(mCircleRadius);
}
}
ret.append("],\n");
}
}
append(ret, "verticalWeight", mVerticalWeight);
append(ret, "horizontalWeight", mHorizontalWeight);
if (mHorizontalChainStyle != null) {
ret.append("horizontalChainStyle:'").append(chainModeMap.get(mHorizontalChainStyle))
.append("',\n");
}
if (mVerticalChainStyle != null) {
ret.append("verticalChainStyle:'").append(chainModeMap.get(mVerticalChainStyle))
.append("',\n");
}
if (mWidthDefault != null) {
if (mWidthMax == UNSET && mWidthMin == UNSET) {
ret.append("width:'").append(mWidthDefault.toString().toLowerCase())
.append("',\n");
} else {
ret.append("width:{value:'").append(mWidthDefault.toString().toLowerCase())
.append("'");
if (mWidthMax != UNSET) {
ret.append(",max:").append(mWidthMax);
}
if (mWidthMin != UNSET) {
ret.append(",min:").append(mWidthMin);
}
ret.append("},\n");
}
}
if (mHeightDefault != null) {
if (mHeightMax == UNSET && mHeightMin == UNSET) {
ret.append("height:'").append(mHeightDefault.toString().toLowerCase())
.append("',\n");
} else {
ret.append("height:{value:'").append(mHeightDefault.toString().toLowerCase())
.append("'");
if (mHeightMax != UNSET) {
ret.append(",max:").append(mHeightMax);
}
if (mHeightMin != UNSET) {
ret.append(",min:").append(mHeightMin);
}
ret.append("},\n");
}
}
if (!Double.isNaN(mWidthPercent)) {
ret.append("width:'").append((int) mWidthPercent).append("%',\n");
}
if (!Double.isNaN(mHeightPercent)) {
ret.append("height:'").append((int) mHeightPercent).append("%',\n");
}
if (mReferenceIds != null) {
ret.append("referenceIds:")
.append(convertStringArrayToString(mReferenceIds))
.append(",\n");
}
if (mConstrainedWidth) {
ret.append("constrainedWidth:").append(mConstrainedWidth).append(",\n");
}
if (mConstrainedHeight) {
ret.append("constrainedHeight:").append(mConstrainedHeight).append(",\n");
}
ret.append("},\n");
return ret.toString();
}
}