public class

ConstraintWidgetContainer

extends WidgetContainer

 java.lang.Object

androidx.constraintlayout.core.widgets.ConstraintWidget

androidx.constraintlayout.core.widgets.WidgetContainer

↳androidx.constraintlayout.core.widgets.ConstraintWidgetContainer

Gradle dependencies

compile group: 'androidx.constraintlayout', name: 'constraintlayout-core', version: '1.1.0-beta01'

  • groupId: androidx.constraintlayout
  • artifactId: constraintlayout-core
  • version: 1.1.0-beta01

Artifact androidx.constraintlayout:constraintlayout-core:1.1.0-beta01 it located at Google repository (https://maven.google.com/)

Overview

A container of ConstraintWidget that can layout its children

Summary

Fields
public DependencyGraphmDependencyGraph

public booleanmGroupsWrapOptimized

public intmHorizontalChainsSize

public booleanmHorizontalWrapOptimized

public BasicMeasure.MeasuremMeasure

protected BasicMeasure.MeasurermMeasurer

public MetricsmMetrics

public booleanmSkipSolver

protected LinearSystemmSystem

public intmVerticalChainsSize

public booleanmVerticalWrapOptimized

public intmWrapFixedHeight

public intmWrapFixedWidth

from WidgetContainermChildren
from ConstraintWidgetANCHOR_BASELINE, ANCHOR_BOTTOM, ANCHOR_LEFT, ANCHOR_RIGHT, ANCHOR_TOP, BOTH, CHAIN_PACKED, CHAIN_SPREAD, CHAIN_SPREAD_INSIDE, DEFAULT_BIAS, DIRECT, frame, GONE, HORIZONTAL, horizontalChainRun, horizontalGroup, INVISIBLE, isTerminalWidget[], mAnchors, MATCH_CONSTRAINT_PERCENT, MATCH_CONSTRAINT_RATIO, MATCH_CONSTRAINT_RATIO_RESOLVED, MATCH_CONSTRAINT_SPREAD, MATCH_CONSTRAINT_WRAP, mBaseline, mBottom, mCenter, mCircleConstraintAngle, mDimensionRatio, mDimensionRatioSide, measured, mHorizontalResolution, mHorizontalRun, mIsHeightWrapContent, mIsWidthWrapContent, mLeft, mListAnchors[], mListDimensionBehaviors[], mListNextMatchConstraintsWidget[], mMatchConstraintDefaultHeight, mMatchConstraintDefaultWidth, mMatchConstraintMaxHeight, mMatchConstraintMaxWidth, mMatchConstraintMinHeight, mMatchConstraintMinWidth, mMatchConstraintPercentHeight, mMatchConstraintPercentWidth, mMinHeight, mMinWidth, mNextChainWidget[], mOffsetX, mOffsetY, mParent, mResolvedMatchConstraintDefault[], mRight, mTop, mVerticalResolution, mVerticalRun, mWeight[], mX, mY, run[], SOLVER, stringId, UNKNOWN, VERTICAL, verticalChainRun, verticalGroup, VISIBLE, WRAP_BEHAVIOR_HORIZONTAL_ONLY, WRAP_BEHAVIOR_INCLUDED, WRAP_BEHAVIOR_SKIPPED, WRAP_BEHAVIOR_VERTICAL_ONLY
Constructors
publicConstraintWidgetContainer()

Default constructor

publicConstraintWidgetContainer(int width, int height)

Constructor

publicConstraintWidgetContainer(int x, int y, int width, int height)

Constructor

publicConstraintWidgetContainer(java.lang.String debugName, int width, int height)

Methods
public booleanaddChildrenToSolver(LinearSystem system)

Add this widget to the solver

public voidaddHorizontalWrapMaxVariable(ConstraintAnchor right)

public voidaddHorizontalWrapMinVariable(ConstraintAnchor left)

public voiddefineTerminalWidgets()

public booleandirectMeasure(boolean optimizeWrap)

public booleandirectMeasureSetup(boolean optimizeWrap)

public booleandirectMeasureWithOrientation(boolean optimizeWrap, int orientation)

public voidfillMetrics(Metrics metrics)

public java.util.ArrayList<Guideline>getHorizontalGuidelines()

Accessor to the horizontal guidelines contained in the table.

public BasicMeasure.MeasurergetMeasurer()

public intgetOptimizationLevel()

Returns the current optimization level

public voidgetSceneString(java.lang.StringBuilder ret)

public LinearSystemgetSystem()

public java.lang.StringgetType()

Specify the xml type for the container

public java.util.ArrayList<Guideline>getVerticalGuidelines()

Accessor to the vertical guidelines contained in the table.

public booleanhandlesInternalConstraints()

Indicates if the container knows how to layout its content on its own

public voidinvalidateGraph()

Invalidate the graph of constraints

public voidinvalidateMeasures()

Invalidate the widgets measures

public booleanisHeightMeasuredTooSmall()

Return true if the height given is too small for the content laid out

public booleanisRtl()

Returns the rtl status.

public booleanisWidthMeasuredTooSmall()

Return true if the width given is too small for the content laid out

public voidlayout()

Layout the tree of widgets

public static booleanmeasure(int level, ConstraintWidget widget, BasicMeasure.Measurer measurer, BasicMeasure.Measure measure, int measureStrategy)

public longmeasure(int optimizationLevel, int widthMode, int widthSize, int heightMode, int heightSize, int lastMeasureWidth, int lastMeasureHeight, int paddingX, int paddingY)

Measure the layout

public booleanoptimizeFor(int feature)

Returns true if the given feature should be optimized

public voidreset()

public voidsetMeasurer(BasicMeasure.Measurer measurer)

public voidsetOptimizationLevel(int value)

Resolves the system directly when possible

public voidsetPadding(int left, int top, int right, int bottom)

Set the padding on this container.

public voidsetPass(int pass)

Keep track of the # of passes

public voidsetRtl(boolean isRtl)

Set the rtl status.

public booleanupdateChildrenFromSolver(LinearSystem system, boolean[] flags[])

Update the frame of the layout and its children from the solver

public voidupdateFromRuns(boolean updateHorizontal, boolean updateVertical)

public voidupdateHierarchy()

from WidgetContaineradd, add, getChildren, getRootConstraintContainer, remove, removeAllChildren, resetSolverVariables, setOffset
from ConstraintWidgetaddChildrenToSolverByDependency, addToSolver, allowedInBarrier, connect, connect, connect, connectCircularConstraint, copy, createObjectVariables, ensureMeasureRequested, ensureWidgetRuns, getAnchor, getAnchors, getBaselineDistance, getBiasPercent, getBottom, getCompanionWidget, getContainerItemSkip, getDebugName, getDimensionBehaviour, getDimensionRatio, getDimensionRatioSide, getHasBaseline, getHeight, getHorizontalBiasPercent, getHorizontalChainControlWidget, getHorizontalChainStyle, getHorizontalDimensionBehaviour, getHorizontalMargin, getLastHorizontalMeasureSpec, getLastVerticalMeasureSpec, getLeft, getLength, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getNextChainMember, getOptimizerWrapHeight, getOptimizerWrapWidth, getParent, getPreviousChainMember, getRight, getRootX, getRootY, getRun, getTop, getVerticalBiasPercent, getVerticalChainControlWidget, getVerticalChainStyle, getVerticalDimensionBehaviour, getVerticalMargin, getVisibility, getWidth, getWrapBehaviorInParent, getX, getY, hasBaseline, hasDanglingDimension, hasDependencies, hasDimensionOverride, hasResolvedTargets, immediateConnect, isAnimated, isHeightWrapContent, isHorizontalSolvingPassDone, isInBarrier, isInHorizontalChain, isInPlaceholder, isInVerticalChain, isInVirtualLayout, isMeasureRequested, isResolvedHorizontally, isResolvedVertically, isRoot, isSpreadHeight, isSpreadWidth, isVerticalSolvingPassDone, isWidthWrapContent, markHorizontalSolvingPassDone, markVerticalSolvingPassDone, oppositeDimensionDependsOn, oppositeDimensionsTied, resetAllConstraints, resetAnchor, resetAnchors, resetFinalResolution, resetSolvingPassFlag, serialize, setAnimated, setBaselineDistance, setCompanionWidget, setContainerItemSkip, setDebugName, setDebugSolverName, setDimension, setDimensionRatio, setDimensionRatio, setFinalBaseline, setFinalFrame, setFinalHorizontal, setFinalLeft, setFinalTop, setFinalVertical, setFrame, setFrame, setGoneMargin, setHasBaseline, setHeight, setHeightWrapContent, setHorizontalBiasPercent, setHorizontalChainStyle, setHorizontalDimension, setHorizontalDimensionBehaviour, setHorizontalMatchStyle, setHorizontalWeight, setInBarrier, setInPlaceholder, setInVirtualLayout, setLastMeasureSpec, setLength, setMaxHeight, setMaxWidth, setMeasureRequested, setMinHeight, setMinWidth, setOrigin, setParent, setType, setupDimensionRatio, setVerticalBiasPercent, setVerticalChainStyle, setVerticalDimension, setVerticalDimensionBehaviour, setVerticalMatchStyle, setVerticalWeight, setVisibility, setWidth, setWidthWrapContent, setWrapBehaviorInParent, setX, setY, toString, updateFromSolver
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Fields

public DependencyGraph mDependencyGraph

protected BasicMeasure.Measurer mMeasurer

public Metrics mMetrics

protected LinearSystem mSystem

public int mHorizontalChainsSize

public int mVerticalChainsSize

public boolean mGroupsWrapOptimized

public boolean mHorizontalWrapOptimized

public boolean mVerticalWrapOptimized

public int mWrapFixedWidth

public int mWrapFixedHeight

public boolean mSkipSolver

public BasicMeasure.Measure mMeasure

Constructors

public ConstraintWidgetContainer()

Default constructor

public ConstraintWidgetContainer(int x, int y, int width, int height)

Constructor

Parameters:

x: x position
y: y position
width: width of the layout
height: height of the layout

public ConstraintWidgetContainer(int width, int height)

Constructor

Parameters:

width: width of the layout
height: height of the layout

public ConstraintWidgetContainer(java.lang.String debugName, int width, int height)

Methods

public void invalidateGraph()

Invalidate the graph of constraints

public void invalidateMeasures()

Invalidate the widgets measures

public boolean directMeasure(boolean optimizeWrap)

public boolean directMeasureSetup(boolean optimizeWrap)

public boolean directMeasureWithOrientation(boolean optimizeWrap, int orientation)

public void defineTerminalWidgets()

public long measure(int optimizationLevel, int widthMode, int widthSize, int heightMode, int heightSize, int lastMeasureWidth, int lastMeasureHeight, int paddingX, int paddingY)

Measure the layout

public void updateHierarchy()

public void setMeasurer(BasicMeasure.Measurer measurer)

public BasicMeasure.Measurer getMeasurer()

public void fillMetrics(Metrics metrics)

public void setOptimizationLevel(int value)

Resolves the system directly when possible

Parameters:

value: optimization level

public int getOptimizationLevel()

Returns the current optimization level

public boolean optimizeFor(int feature)

Returns true if the given feature should be optimized

public java.lang.String getType()

Specify the xml type for the container

public void reset()

public boolean isWidthMeasuredTooSmall()

Return true if the width given is too small for the content laid out

public boolean isHeightMeasuredTooSmall()

Return true if the height given is too small for the content laid out

public void addHorizontalWrapMinVariable(ConstraintAnchor left)

public void addHorizontalWrapMaxVariable(ConstraintAnchor right)

public boolean addChildrenToSolver(LinearSystem system)

Add this widget to the solver

Parameters:

system: the solver we want to add the widget to

public boolean updateChildrenFromSolver(LinearSystem system, boolean[] flags[])

Update the frame of the layout and its children from the solver

Parameters:

system: the solver we get the values from.

public void updateFromRuns(boolean updateHorizontal, boolean updateVertical)

public void setPadding(int left, int top, int right, int bottom)

Set the padding on this container. It will apply to the position of the children.

Parameters:

left: left padding
top: top padding
right: right padding
bottom: bottom padding

public void setRtl(boolean isRtl)

Set the rtl status. This has implications for Chains.

Parameters:

isRtl: true if we are in RTL.

public boolean isRtl()

Returns the rtl status.

Returns:

true if in RTL, false otherwise.

public static boolean measure(int level, ConstraintWidget widget, BasicMeasure.Measurer measurer, BasicMeasure.Measure measure, int measureStrategy)

public void layout()

Layout the tree of widgets

public boolean handlesInternalConstraints()

Indicates if the container knows how to layout its content on its own

Returns:

true if the container does the layout, false otherwise

public java.util.ArrayList<Guideline> getVerticalGuidelines()

Accessor to the vertical guidelines contained in the table.

Returns:

array of guidelines

public java.util.ArrayList<Guideline> getHorizontalGuidelines()

Accessor to the horizontal guidelines contained in the table.

Returns:

array of guidelines

public LinearSystem getSystem()

public void setPass(int pass)

Keep track of the # of passes

public void getSceneString(java.lang.StringBuilder ret)

Source

/*
 * Copyright (C) 2015 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.widgets;

import static androidx.constraintlayout.core.LinearSystem.FULL_DEBUG;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.FIXED;
import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.WRAP_CONTENT;

import androidx.constraintlayout.core.LinearSystem;
import androidx.constraintlayout.core.Metrics;
import androidx.constraintlayout.core.SolverVariable;
import androidx.constraintlayout.core.widgets.analyzer.BasicMeasure;
import androidx.constraintlayout.core.widgets.analyzer.DependencyGraph;
import androidx.constraintlayout.core.widgets.analyzer.Direct;
import androidx.constraintlayout.core.widgets.analyzer.Grouping;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * A container of ConstraintWidget that can layout its children
 */
public class ConstraintWidgetContainer extends WidgetContainer {

    private static final int MAX_ITERATIONS = 8;

    private static final boolean DEBUG = FULL_DEBUG;
    private static final boolean DEBUG_LAYOUT = false;
    static final boolean DEBUG_GRAPH = false;

    BasicMeasure mBasicMeasureSolver = new BasicMeasure(this);

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Graph measures
    ////////////////////////////////////////////////////////////////////////////////////////////////

    public DependencyGraph mDependencyGraph = new DependencyGraph(this);
    private int mPass; // number of layout passes

    /**
     * Invalidate the graph of constraints
     */
    public void invalidateGraph() {
        mDependencyGraph.invalidateGraph();
    }

    /**
     * Invalidate the widgets measures
     */
    public void invalidateMeasures() {
        mDependencyGraph.invalidateMeasures();
    }


    // @TODO: add description
    public boolean directMeasure(boolean optimizeWrap) {
        return mDependencyGraph.directMeasure(optimizeWrap);
//        int paddingLeft = getX();
//        int paddingTop = getY();
//        if (mDependencyGraph.directMeasureSetup(optimizeWrap)) {
//            mDependencyGraph.measureWidgets();
//            boolean allResolved =
//                      mDependencyGraph.directMeasureWithOrientation(optimizeWrap, HORIZONTAL);
//            allResolved &= mDependencyGraph.directMeasureWithOrientation(optimizeWrap, VERTICAL);
//            for (ConstraintWidget child : mChildren) {
//                child.setDrawX(child.getDrawX() + paddingLeft);
//                child.setDrawY(child.getDrawY() + paddingTop);
//            }
//            setX(paddingLeft);
//            setY(paddingTop);
//            return allResolved;
//        }
//        return false;
    }

    // @TODO: add description
    public boolean directMeasureSetup(boolean optimizeWrap) {
        return mDependencyGraph.directMeasureSetup(optimizeWrap);
    }

    // @TODO: add description
    public boolean directMeasureWithOrientation(boolean optimizeWrap, int orientation) {
        return mDependencyGraph.directMeasureWithOrientation(optimizeWrap, orientation);
    }

    // @TODO: add description
    public void defineTerminalWidgets() {
        mDependencyGraph.defineTerminalWidgets(getHorizontalDimensionBehaviour(),
                getVerticalDimensionBehaviour());
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Measure the layout
     */
    public long measure(int optimizationLevel, int widthMode, int widthSize,
            int heightMode, int heightSize, int lastMeasureWidth,
            int lastMeasureHeight, int paddingX, int paddingY) {
        mPaddingLeft = paddingX;
        mPaddingTop = paddingY;
        return mBasicMeasureSolver.solverMeasure(this, optimizationLevel, paddingX, paddingY,
                widthMode, widthSize, heightMode, heightSize,
                lastMeasureWidth, lastMeasureHeight);
    }

    // @TODO: add description
    public void updateHierarchy() {
        mBasicMeasureSolver.updateHierarchy(this);
    }

    protected BasicMeasure.Measurer mMeasurer = null;

    // @TODO: add description
    public void setMeasurer(BasicMeasure.Measurer measurer) {
        mMeasurer = measurer;
        mDependencyGraph.setMeasurer(measurer);
    }

    public BasicMeasure.Measurer getMeasurer() {
        return mMeasurer;
    }

    private boolean mIsRtl = false;
    public Metrics mMetrics;

    // @TODO: add description
    public void fillMetrics(Metrics metrics) {
        mMetrics = metrics;
        mSystem.fillMetrics(metrics);
    }

    protected LinearSystem mSystem = new LinearSystem();

    int mPaddingLeft;
    int mPaddingTop;
    int mPaddingRight;
    int mPaddingBottom;

    public int mHorizontalChainsSize = 0;
    public int mVerticalChainsSize = 0;

    ChainHead[] mVerticalChainsArray = new ChainHead[4];
    ChainHead[] mHorizontalChainsArray = new ChainHead[4];

    public boolean mGroupsWrapOptimized = false;
    public boolean mHorizontalWrapOptimized = false;
    public boolean mVerticalWrapOptimized = false;
    public int mWrapFixedWidth = 0;
    public int mWrapFixedHeight = 0;

    private int mOptimizationLevel = Optimizer.OPTIMIZATION_STANDARD;
    public boolean mSkipSolver = false;

    private boolean mWidthMeasuredTooSmall = false;
    private boolean mHeightMeasuredTooSmall = false;

    /*-----------------------------------------------------------------------*/
    // Construction
    /*-----------------------------------------------------------------------*/

    /**
     * Default constructor
     */
    public ConstraintWidgetContainer() {
    }

    /**
     * Constructor
     *
     * @param x      x position
     * @param y      y position
     * @param width  width of the layout
     * @param height height of the layout
     */
    public ConstraintWidgetContainer(int x, int y, int width, int height) {
        super(x, y, width, height);
    }

    /**
     * Constructor
     *
     * @param width  width of the layout
     * @param height height of the layout
     */
    public ConstraintWidgetContainer(int width, int height) {
        super(width, height);
    }

    public ConstraintWidgetContainer(String debugName, int width, int height) {
        super(width, height);
        setDebugName(debugName);
    }

    /**
     * Resolves the system directly when possible
     *
     * @param value optimization level
     */
    public void setOptimizationLevel(int value) {
        mOptimizationLevel = value;
        mSystem.USE_DEPENDENCY_ORDERING = optimizeFor(Optimizer.OPTIMIZATION_DEPENDENCY_ORDERING);
    }

    /**
     * Returns the current optimization level
     */
    public int getOptimizationLevel() {
        return mOptimizationLevel;
    }

    /**
     * Returns true if the given feature should be optimized
     */
    public boolean optimizeFor(int feature) {
        return (mOptimizationLevel & feature) == feature;
    }

    /**
     * Specify the xml type for the container
     */
    @Override
    public String getType() {
        return "ConstraintLayout";
    }

    @Override
    public void reset() {
        mSystem.reset();
        mPaddingLeft = 0;
        mPaddingRight = 0;
        mPaddingTop = 0;
        mPaddingBottom = 0;
        mSkipSolver = false;
        super.reset();
    }

    /**
     * Return true if the width given is too small for the content laid out
     */
    public boolean isWidthMeasuredTooSmall() {
        return mWidthMeasuredTooSmall;
    }

    /**
     * Return true if the height given is too small for the content laid out
     */
    public boolean isHeightMeasuredTooSmall() {
        return mHeightMeasuredTooSmall;
    }

    int mDebugSolverPassCount = 0;

    private WeakReference<ConstraintAnchor> mVerticalWrapMin = null;
    private WeakReference<ConstraintAnchor> mHorizontalWrapMin = null;
    private WeakReference<ConstraintAnchor> mVerticalWrapMax = null;
    private WeakReference<ConstraintAnchor> mHorizontalWrapMax = null;

    void addVerticalWrapMinVariable(ConstraintAnchor top) {
        if (mVerticalWrapMin == null || mVerticalWrapMin.get() == null
                || top.getFinalValue() > mVerticalWrapMin.get().getFinalValue()) {
            mVerticalWrapMin = new WeakReference<>(top);
        }
    }

    // @TODO: add description
    public void addHorizontalWrapMinVariable(ConstraintAnchor left) {
        if (mHorizontalWrapMin == null || mHorizontalWrapMin.get() == null
                || left.getFinalValue() > mHorizontalWrapMin.get().getFinalValue()) {
            mHorizontalWrapMin = new WeakReference<>(left);
        }
    }

    void addVerticalWrapMaxVariable(ConstraintAnchor bottom) {
        if (mVerticalWrapMax == null || mVerticalWrapMax.get() == null
                || bottom.getFinalValue() > mVerticalWrapMax.get().getFinalValue()) {
            mVerticalWrapMax = new WeakReference<>(bottom);
        }
    }

    // @TODO: add description
    public void addHorizontalWrapMaxVariable(ConstraintAnchor right) {
        if (mHorizontalWrapMax == null || mHorizontalWrapMax.get() == null
                || right.getFinalValue() > mHorizontalWrapMax.get().getFinalValue()) {
            mHorizontalWrapMax = new WeakReference<>(right);
        }
    }

    private void addMinWrap(ConstraintAnchor constraintAnchor, SolverVariable parentMin) {
        SolverVariable variable = mSystem.createObjectVariable(constraintAnchor);
        int wrapStrength = SolverVariable.STRENGTH_EQUALITY;
        mSystem.addGreaterThan(variable, parentMin, 0, wrapStrength);
    }

    private void addMaxWrap(ConstraintAnchor constraintAnchor, SolverVariable parentMax) {
        SolverVariable variable = mSystem.createObjectVariable(constraintAnchor);
        int wrapStrength = SolverVariable.STRENGTH_EQUALITY;
        mSystem.addGreaterThan(parentMax, variable, 0, wrapStrength);
    }

    HashSet<ConstraintWidget> mWidgetsToAdd = new HashSet<>();

    /**
     * Add this widget to the solver
     *
     * @param system the solver we want to add the widget to
     */
    public boolean addChildrenToSolver(LinearSystem system) {
        if (DEBUG) {
            System.out.println("\n#######################################");
            System.out.println("##    ADD CHILDREN TO SOLVER  (" + mDebugSolverPassCount + ") ##");
            System.out.println("#######################################\n");
            mDebugSolverPassCount++;
        }

        boolean optimize = optimizeFor(Optimizer.OPTIMIZATION_GRAPH);
        addToSolver(system, optimize);
        final int count = mChildren.size();

        boolean hasBarriers = false;
        for (int i = 0; i < count; i++) {
            ConstraintWidget widget = mChildren.get(i);
            widget.setInBarrier(HORIZONTAL, false);
            widget.setInBarrier(VERTICAL, false);
            if (widget instanceof Barrier) {
                hasBarriers = true;
            }
        }

        if (hasBarriers) {
            for (int i = 0; i < count; i++) {
                ConstraintWidget widget = mChildren.get(i);
                if (widget instanceof Barrier) {
                    ((Barrier) widget).markWidgets();
                }
            }
        }

        mWidgetsToAdd.clear();
        for (int i = 0; i < count; i++) {
            ConstraintWidget widget = mChildren.get(i);
            if (widget.addFirst()) {
                if (widget instanceof VirtualLayout) {
                    mWidgetsToAdd.add(widget);
                } else {
                    widget.addToSolver(system, optimize);
                }
            }
        }

        // If we have virtual layouts, we need to add them to the solver in the correct
        // order (in case they reference one another)
        while (mWidgetsToAdd.size() > 0) {
            int numLayouts = mWidgetsToAdd.size();
            VirtualLayout layout = null;
            for (ConstraintWidget widget : mWidgetsToAdd) {
                layout = (VirtualLayout) widget;

                // we'll go through the virtual layouts that references others first, to give
                // them a shot at setting their constraints.
                if (layout.contains(mWidgetsToAdd)) {
                    layout.addToSolver(system, optimize);
                    mWidgetsToAdd.remove(layout);
                    break;
                }
            }
            if (numLayouts == mWidgetsToAdd.size()) {
                // looks we didn't find anymore dependency, let's add everything.
                for (ConstraintWidget widget : mWidgetsToAdd) {
                    widget.addToSolver(system, optimize);
                }
                mWidgetsToAdd.clear();
            }
        }

        if (LinearSystem.USE_DEPENDENCY_ORDERING) {
            HashSet<ConstraintWidget> widgetsToAdd = new HashSet<>();
            for (int i = 0; i < count; i++) {
                ConstraintWidget widget = mChildren.get(i);
                if (!widget.addFirst()) {
                    widgetsToAdd.add(widget);
                }
            }
            int orientation = VERTICAL;
            if (getHorizontalDimensionBehaviour() == WRAP_CONTENT) {
                orientation = HORIZONTAL;
            }
            addChildrenToSolverByDependency(this, system, widgetsToAdd, orientation, false);
            for (ConstraintWidget widget : widgetsToAdd) {
                Optimizer.checkMatchParent(this, system, widget);
                widget.addToSolver(system, optimize);
            }
        } else {

            for (int i = 0; i < count; i++) {
                ConstraintWidget widget = mChildren.get(i);
                if (widget instanceof ConstraintWidgetContainer) {
                    DimensionBehaviour horizontalBehaviour =
                            widget.mListDimensionBehaviors[DIMENSION_HORIZONTAL];
                    DimensionBehaviour verticalBehaviour =
                            widget.mListDimensionBehaviors[DIMENSION_VERTICAL];
                    if (horizontalBehaviour == WRAP_CONTENT) {
                        widget.setHorizontalDimensionBehaviour(FIXED);
                    }
                    if (verticalBehaviour == WRAP_CONTENT) {
                        widget.setVerticalDimensionBehaviour(FIXED);
                    }
                    widget.addToSolver(system, optimize);
                    if (horizontalBehaviour == WRAP_CONTENT) {
                        widget.setHorizontalDimensionBehaviour(horizontalBehaviour);
                    }
                    if (verticalBehaviour == WRAP_CONTENT) {
                        widget.setVerticalDimensionBehaviour(verticalBehaviour);
                    }
                } else {
                    Optimizer.checkMatchParent(this, system, widget);
                    if (!widget.addFirst()) {
                        widget.addToSolver(system, optimize);
                    }
                }
            }
        }

        if (mHorizontalChainsSize > 0) {
            Chain.applyChainConstraints(this, system, null, HORIZONTAL);
        }
        if (mVerticalChainsSize > 0) {
            Chain.applyChainConstraints(this, system, null, VERTICAL);
        }
        return true;
    }

    /**
     * Update the frame of the layout and its children from the solver
     *
     * @param system the solver we get the values from.
     */
    public boolean updateChildrenFromSolver(LinearSystem system, boolean[] flags) {
        flags[Optimizer.FLAG_RECOMPUTE_BOUNDS] = false;
        boolean optimize = optimizeFor(Optimizer.OPTIMIZATION_GRAPH);
        updateFromSolver(system, optimize);
        final int count = mChildren.size();
        boolean hasOverride = false;
        for (int i = 0; i < count; i++) {
            ConstraintWidget widget = mChildren.get(i);
            widget.updateFromSolver(system, optimize);
            if (widget.hasDimensionOverride()) {
                hasOverride = true;
            }
        }
        return hasOverride;
    }

    @Override
    public void updateFromRuns(boolean updateHorizontal, boolean updateVertical) {
        super.updateFromRuns(updateHorizontal, updateVertical);
        final int count = mChildren.size();
        for (int i = 0; i < count; i++) {
            ConstraintWidget widget = mChildren.get(i);
            widget.updateFromRuns(updateHorizontal, updateVertical);
        }
    }

    /**
     * Set the padding on this container. It will apply to the position of the children.
     *
     * @param left   left padding
     * @param top    top padding
     * @param right  right padding
     * @param bottom bottom padding
     */
    public void setPadding(int left, int top, int right, int bottom) {
        mPaddingLeft = left;
        mPaddingTop = top;
        mPaddingRight = right;
        mPaddingBottom = bottom;
    }

    /**
     * Set the rtl status. This has implications for Chains.
     *
     * @param isRtl true if we are in RTL.
     */
    public void setRtl(boolean isRtl) {
        mIsRtl = isRtl;
    }

    /**
     * Returns the rtl status.
     *
     * @return true if in RTL, false otherwise.
     */
    public boolean isRtl() {
        return mIsRtl;
    }

    /*-----------------------------------------------------------------------*/
    // Overloaded methods from ConstraintWidget
    /*-----------------------------------------------------------------------*/

    public BasicMeasure.Measure mMeasure = new BasicMeasure.Measure();

    // @TODO: add description
    public static boolean measure(int level,
            ConstraintWidget widget,
            BasicMeasure.Measurer measurer,
            BasicMeasure.Measure measure,
            int measureStrategy) {
        if (DEBUG) {
            System.out.println(Direct.ls(level) + "(M) call to measure " + widget.getDebugName());
        }
        if (measurer == null) {
            return false;
        }
        if (widget.getVisibility() == GONE
                || widget instanceof Guideline
                || widget instanceof Barrier) {
            if (DEBUG) {
                System.out.println(Direct.ls(level)
                        + "(M) no measure needed for " + widget.getDebugName());
            }
            measure.measuredWidth = 0;
            measure.measuredHeight = 0;
            return false;
        }

        measure.horizontalBehavior = widget.getHorizontalDimensionBehaviour();
        measure.verticalBehavior = widget.getVerticalDimensionBehaviour();
        measure.horizontalDimension = widget.getWidth();
        measure.verticalDimension = widget.getHeight();
        measure.measuredNeedsSolverPass = false;
        measure.measureStrategy = measureStrategy;

        boolean horizontalMatchConstraints =
                (measure.horizontalBehavior == DimensionBehaviour.MATCH_CONSTRAINT);
        boolean verticalMatchConstraints =
                (measure.verticalBehavior == DimensionBehaviour.MATCH_CONSTRAINT);

        boolean horizontalUseRatio = horizontalMatchConstraints && widget.mDimensionRatio > 0;
        boolean verticalUseRatio = verticalMatchConstraints && widget.mDimensionRatio > 0;

        if (horizontalMatchConstraints && widget.hasDanglingDimension(HORIZONTAL)
                && widget.mMatchConstraintDefaultWidth == MATCH_CONSTRAINT_SPREAD
                && !horizontalUseRatio) {
            horizontalMatchConstraints = false;
            measure.horizontalBehavior = WRAP_CONTENT;
            if (verticalMatchConstraints
                    && widget.mMatchConstraintDefaultHeight == MATCH_CONSTRAINT_SPREAD) {
                // if match x match, size would be zero.
                measure.horizontalBehavior = FIXED;
            }
        }

        if (verticalMatchConstraints && widget.hasDanglingDimension(VERTICAL)
                && widget.mMatchConstraintDefaultHeight == MATCH_CONSTRAINT_SPREAD
                && !verticalUseRatio) {
            verticalMatchConstraints = false;
            measure.verticalBehavior = WRAP_CONTENT;
            if (horizontalMatchConstraints
                    && widget.mMatchConstraintDefaultWidth == MATCH_CONSTRAINT_SPREAD) {
                // if match x match, size would be zero.
                measure.verticalBehavior = FIXED;
            }
        }

        if (widget.isResolvedHorizontally()) {
            horizontalMatchConstraints = false;
            measure.horizontalBehavior = FIXED;
        }
        if (widget.isResolvedVertically()) {
            verticalMatchConstraints = false;
            measure.verticalBehavior = FIXED;
        }

        if (horizontalUseRatio) {
            if (widget.mResolvedMatchConstraintDefault[HORIZONTAL]
                    == ConstraintWidget.MATCH_CONSTRAINT_RATIO_RESOLVED) {
                measure.horizontalBehavior = FIXED;
            } else if (!verticalMatchConstraints) {
                // let's measure here
                int measuredHeight;
                if (measure.verticalBehavior == FIXED) {
                    measuredHeight = measure.verticalDimension;
                } else {
                    measure.horizontalBehavior = WRAP_CONTENT;
                    measurer.measure(widget, measure);
                    measuredHeight = measure.measuredHeight;
                }
                measure.horizontalBehavior = FIXED;
                // regardless of which side we are using for the ratio, getDimensionRatio() already
                // made sure that it's expressed in WxH format, so we can simply go and multiply
                measure.horizontalDimension = (int) (widget.getDimensionRatio() * measuredHeight);
                if (DEBUG) {
                    System.out.println("(M) Measured once for ratio on horizontal side...");
                }
            }
        }
        if (verticalUseRatio) {
            if (widget.mResolvedMatchConstraintDefault[VERTICAL]
                    == ConstraintWidget.MATCH_CONSTRAINT_RATIO_RESOLVED) {
                measure.verticalBehavior = FIXED;
            } else if (!horizontalMatchConstraints) {
                // let's measure here
                int measuredWidth;
                if (measure.horizontalBehavior == FIXED) {
                    measuredWidth = measure.horizontalDimension;
                } else {
                    measure.verticalBehavior = WRAP_CONTENT;
                    measurer.measure(widget, measure);
                    measuredWidth = measure.measuredWidth;
                }
                measure.verticalBehavior = FIXED;
                if (widget.getDimensionRatioSide() == -1) {
                    // regardless of which side we are using for the ratio,
                    //  getDimensionRatio() already
                    // made sure that it's expressed in WxH format,
                    //  so we can simply go and divide
                    measure.verticalDimension = (int) (measuredWidth / widget.getDimensionRatio());
                } else {
                    // getDimensionRatio() already got reverted, so we can simply multiply
                    measure.verticalDimension = (int) (widget.getDimensionRatio() * measuredWidth);
                }
                if (DEBUG) {
                    System.out.println("(M) Measured once for ratio on vertical side...");
                }
            }
        }

        measurer.measure(widget, measure);
        widget.setWidth(measure.measuredWidth);
        widget.setHeight(measure.measuredHeight);
        widget.setHasBaseline(measure.measuredHasBaseline);
        widget.setBaselineDistance(measure.measuredBaseline);
        measure.measureStrategy = BasicMeasure.Measure.SELF_DIMENSIONS;
        if (DEBUG) {
            System.out.println("(M) Measured " + widget.getDebugName() + " with : "
                    + widget.getHorizontalDimensionBehaviour() + " x "
                    + widget.getVerticalDimensionBehaviour() + " => "
                    + widget.getWidth() + " x " + widget.getHeight());
        }
        return measure.measuredNeedsSolverPass;
    }

    static int sMyCounter = 0;

    /**
     * Layout the tree of widgets
     */
    @Override
    public void layout() {
        if (DEBUG) {
            System.out.println("\n#####################################");
            System.out.println("##          CL LAYOUT PASS           ##");
            System.out.println("#####################################\n");
            mDebugSolverPassCount = 0;
        }

        mX = 0;
        mY = 0;

        mWidthMeasuredTooSmall = false;
        mHeightMeasuredTooSmall = false;
        final int count = mChildren.size();

        int preW = Math.max(0, getWidth());
        int preH = Math.max(0, getHeight());
        DimensionBehaviour originalVerticalDimensionBehaviour =
                mListDimensionBehaviors[DIMENSION_VERTICAL];
        DimensionBehaviour originalHorizontalDimensionBehaviour =
                mListDimensionBehaviors[DIMENSION_HORIZONTAL];

        if (DEBUG_LAYOUT) {
            System.out.println("layout with preW: " + preW + " ("
                    + mListDimensionBehaviors[DIMENSION_HORIZONTAL] + ") preH: " + preH
                    + " (" + mListDimensionBehaviors[DIMENSION_VERTICAL] + ")");
        }

        if (mMetrics != null) {
            mMetrics.layouts++;
        }


        boolean wrap_override = false;

        if (FULL_DEBUG) {
            System.out.println("OPTIMIZATION LEVEL " + mOptimizationLevel);
        }

        // Only try the direct optimization in the first layout pass
        if (mPass == 0 && Optimizer.enabled(mOptimizationLevel, Optimizer.OPTIMIZATION_DIRECT)) {
            if (FULL_DEBUG) {
                System.out.println("Direct pass " + sMyCounter++);
            }
            Direct.solvingPass(this, getMeasurer());
            if (FULL_DEBUG) {
                System.out.println("Direct pass done.");
            }
            for (int i = 0; i < count; i++) {
                ConstraintWidget child = mChildren.get(i);
                if (FULL_DEBUG) {
                    if (child.isInHorizontalChain()) {
                        System.out.print("H");
                    } else {
                        System.out.print(" ");
                    }
                    if (child.isInVerticalChain()) {
                        System.out.print("V");
                    } else {
                        System.out.print(" ");
                    }
                    if (child.isResolvedHorizontally() && child.isResolvedVertically()) {
                        System.out.print("*");
                    } else {
                        System.out.print(" ");
                    }
                    System.out.println("[" + i + "] child " + child.getDebugName()
                            + " H: " + child.isResolvedHorizontally()
                            + " V: " + child.isResolvedVertically());
                }
                if (child.isMeasureRequested()
                        && !(child instanceof Guideline)
                        && !(child instanceof Barrier)
                        && !(child instanceof VirtualLayout)
                        && !child.isInVirtualLayout()) {
                    DimensionBehaviour widthBehavior = child.getDimensionBehaviour(HORIZONTAL);
                    DimensionBehaviour heightBehavior = child.getDimensionBehaviour(VERTICAL);

                    boolean skip = widthBehavior == DimensionBehaviour.MATCH_CONSTRAINT
                            && child.mMatchConstraintDefaultWidth != MATCH_CONSTRAINT_WRAP
                            && heightBehavior == DimensionBehaviour.MATCH_CONSTRAINT
                            && child.mMatchConstraintDefaultHeight != MATCH_CONSTRAINT_WRAP;
                    if (!skip) {
                        BasicMeasure.Measure measure = new BasicMeasure.Measure();
                        ConstraintWidgetContainer.measure(0, child, mMeasurer,
                                measure, BasicMeasure.Measure.SELF_DIMENSIONS);
                    }
                }
            }
            // let's measure children
            if (FULL_DEBUG) {
                System.out.println("Direct pass all done.");
            }
        } else {
            if (FULL_DEBUG) {
                System.out.println("No DIRECT PASS");
            }
        }

        if (count > 2 && (originalHorizontalDimensionBehaviour == WRAP_CONTENT
                || originalVerticalDimensionBehaviour == WRAP_CONTENT)
                && Optimizer.enabled(mOptimizationLevel, Optimizer.OPTIMIZATION_GROUPING)) {
            if (Grouping.simpleSolvingPass(this, getMeasurer())) {
                if (originalHorizontalDimensionBehaviour == WRAP_CONTENT) {
                    if (preW < getWidth() && preW > 0) {
                        if (DEBUG_LAYOUT) {
                            System.out.println("Override width " + getWidth() + " to " + preH);
                        }
                        setWidth(preW);
                        mWidthMeasuredTooSmall = true;
                    } else {
                        preW = getWidth();
                    }
                }
                if (originalVerticalDimensionBehaviour == WRAP_CONTENT) {
                    if (preH < getHeight() && preH > 0) {
                        if (DEBUG_LAYOUT) {
                            System.out.println("Override height " + getHeight() + " to " + preH);
                        }
                        setHeight(preH);
                        mHeightMeasuredTooSmall = true;
                    } else {
                        preH = getHeight();
                    }
                }
                wrap_override = true;
                if (DEBUG_LAYOUT) {
                    System.out.println("layout post opt, preW: " + preW
                            + " (" + mListDimensionBehaviors[DIMENSION_HORIZONTAL]
                            + ") preH: " + preH + " (" + mListDimensionBehaviors[DIMENSION_VERTICAL]
                            + "), new size " + getWidth() + " x " + getHeight());
                }
            }
        }
        boolean useGraphOptimizer = optimizeFor(Optimizer.OPTIMIZATION_GRAPH)
                || optimizeFor(Optimizer.OPTIMIZATION_GRAPH_WRAP);

        mSystem.graphOptimizer = false;
        mSystem.newgraphOptimizer = false;

        if (mOptimizationLevel != Optimizer.OPTIMIZATION_NONE
                && useGraphOptimizer) {
            mSystem.newgraphOptimizer = true;
        }

        @SuppressWarnings("unused") int countSolve = 0;
        final List<ConstraintWidget> allChildren = mChildren;
        boolean hasWrapContent = getHorizontalDimensionBehaviour() == WRAP_CONTENT
                || getVerticalDimensionBehaviour() == WRAP_CONTENT;

        // Reset the chains before iterating on our children
        resetChains();
        countSolve = 0;

        // Before we solve our system, we should call layout() on any
        // of our children that is a container.
        for (int i = 0; i < count; i++) {
            ConstraintWidget widget = mChildren.get(i);
            if (widget instanceof WidgetContainer) {
                ((WidgetContainer) widget).layout();
            }
        }
        boolean optimize = optimizeFor(Optimizer.OPTIMIZATION_GRAPH);

        // Now let's solve our system as usual
        boolean needsSolving = true;
        while (needsSolving) {
            countSolve++;
            try {
                mSystem.reset();
                resetChains();
                if (DEBUG) {
                    String debugName = getDebugName();
                    if (debugName == null) {
                        debugName = "root";
                    }
                    setDebugSolverName(mSystem, debugName);
                    for (int i = 0; i < count; i++) {
                        ConstraintWidget widget = mChildren.get(i);
                        if (widget.getDebugName() != null) {
                            widget.setDebugSolverName(mSystem, widget.getDebugName());
                        }
                    }
                } else {
                    createObjectVariables(mSystem);
                    for (int i = 0; i < count; i++) {
                        ConstraintWidget widget = mChildren.get(i);
                        widget.createObjectVariables(mSystem);
                    }
                }
                needsSolving = addChildrenToSolver(mSystem);
                if (mVerticalWrapMin != null && mVerticalWrapMin.get() != null) {
                    addMinWrap(mVerticalWrapMin.get(), mSystem.createObjectVariable(mTop));
                    mVerticalWrapMin = null;
                }
                if (mVerticalWrapMax != null && mVerticalWrapMax.get() != null) {
                    addMaxWrap(mVerticalWrapMax.get(), mSystem.createObjectVariable(mBottom));
                    mVerticalWrapMax = null;
                }
                if (mHorizontalWrapMin != null && mHorizontalWrapMin.get() != null) {
                    addMinWrap(mHorizontalWrapMin.get(), mSystem.createObjectVariable(mLeft));
                    mHorizontalWrapMin = null;
                }
                if (mHorizontalWrapMax != null && mHorizontalWrapMax.get() != null) {
                    addMaxWrap(mHorizontalWrapMax.get(), mSystem.createObjectVariable(mRight));
                    mHorizontalWrapMax = null;
                }
                if (needsSolving) {
                    mSystem.minimize();
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("EXCEPTION : " + e);
            }
            if (needsSolving) {
                needsSolving = updateChildrenFromSolver(mSystem, Optimizer.sFlags);
            } else {
                updateFromSolver(mSystem, optimize);
                for (int i = 0; i < count; i++) {
                    ConstraintWidget widget = mChildren.get(i);
                    widget.updateFromSolver(mSystem, optimize);
                }
                needsSolving = false;
            }

            if (hasWrapContent && countSolve < MAX_ITERATIONS
                    && Optimizer.sFlags[Optimizer.FLAG_RECOMPUTE_BOUNDS]) {
                // let's get the new bounds
                int maxX = 0;
                int maxY = 0;
                for (int i = 0; i < count; i++) {
                    ConstraintWidget widget = mChildren.get(i);
                    maxX = Math.max(maxX, widget.mX + widget.getWidth());
                    maxY = Math.max(maxY, widget.mY + widget.getHeight());
                }
                maxX = Math.max(mMinWidth, maxX);
                maxY = Math.max(mMinHeight, maxY);
                if (originalHorizontalDimensionBehaviour == WRAP_CONTENT) {
                    if (getWidth() < maxX) {
                        if (DEBUG_LAYOUT) {
                            System.out.println( countSolve +
                                    "layout override width from " + getWidth() + " vs " + maxX);
                        }
                        setWidth(maxX);
                        // force using the solver
                        mListDimensionBehaviors[DIMENSION_HORIZONTAL] = WRAP_CONTENT;
                        wrap_override = true;
                        needsSolving = true;
                    }
                }
                if (originalVerticalDimensionBehaviour == WRAP_CONTENT) {
                    if (getHeight() < maxY) {
                        if (DEBUG_LAYOUT) {
                            System.out.println(
                                    "layout override height from " + getHeight() + " vs " + maxY);
                        }
                        setHeight(maxY);
                        // force using the solver
                        mListDimensionBehaviors[DIMENSION_VERTICAL] = WRAP_CONTENT;
                        wrap_override = true;
                        needsSolving = true;
                    }
                }
            }
            if (true) {
                int width = Math.max(mMinWidth, getWidth());
                if (width > getWidth()) {
                    if (DEBUG_LAYOUT) {
                        System.out.println(
                                "layout override 2, width from " + getWidth() + " vs " + width);
                    }
                    setWidth(width);
                    mListDimensionBehaviors[DIMENSION_HORIZONTAL] = FIXED;
                    wrap_override = true;
                    needsSolving = true;
                }
                int height = Math.max(mMinHeight, getHeight());
                if (height > getHeight()) {
                    if (DEBUG_LAYOUT) {
                        System.out.println(
                                "layout override 2, height from " + getHeight() + " vs " + height);
                    }
                    setHeight(height);
                    mListDimensionBehaviors[DIMENSION_VERTICAL] = FIXED;
                    wrap_override = true;
                    needsSolving = true;
                }

                if (!wrap_override) {
                    if (mListDimensionBehaviors[DIMENSION_HORIZONTAL] == WRAP_CONTENT
                            && preW > 0) {
                        if (getWidth() > preW) {
                            if (DEBUG_LAYOUT) {
                                System.out.println(
                                        "layout override 3, width from " + getWidth() + " vs "
                                                + preW);
                            }
                            mWidthMeasuredTooSmall = true;
                            wrap_override = true;
                            mListDimensionBehaviors[DIMENSION_HORIZONTAL] = FIXED;
                            setWidth(preW);
                            needsSolving = true;
                        }
                    }
                    if (mListDimensionBehaviors[DIMENSION_VERTICAL] == WRAP_CONTENT
                            && preH > 0) {
                        if (getHeight() > preH) {
                            if (DEBUG_LAYOUT) {
                                System.out.println(
                                        "layout override 3, height from " + getHeight() + " vs "
                                                + preH);
                            }
                            mHeightMeasuredTooSmall = true;
                            wrap_override = true;
                            mListDimensionBehaviors[DIMENSION_VERTICAL] = FIXED;
                            setHeight(preH);
                            needsSolving = true;
                        }
                    }
                }

                if (countSolve > MAX_ITERATIONS) {
                    needsSolving = false;
                }
            }
        }
        if (DEBUG_LAYOUT) {
            System.out.println(
                    "Solved system in " + countSolve + " iterations (" + getWidth() + " x "
                            + getHeight() + ")");
        }

        mChildren = (ArrayList<ConstraintWidget>) allChildren;

        if (wrap_override) {
            mListDimensionBehaviors[DIMENSION_HORIZONTAL] = originalHorizontalDimensionBehaviour;
            mListDimensionBehaviors[DIMENSION_VERTICAL] = originalVerticalDimensionBehaviour;
        }

        resetSolverVariables(mSystem.getCache());
    }

    /**
     * Indicates if the container knows how to layout its content on its own
     *
     * @return true if the container does the layout, false otherwise
     */
    public boolean handlesInternalConstraints() {
        return false;
    }

    /*-----------------------------------------------------------------------*/
    // Guidelines
    /*-----------------------------------------------------------------------*/

    /**
     * Accessor to the vertical guidelines contained in the table.
     *
     * @return array of guidelines
     */
    public ArrayList<Guideline> getVerticalGuidelines() {
        ArrayList<Guideline> guidelines = new ArrayList<>();
        for (int i = 0, mChildrenSize = mChildren.size(); i < mChildrenSize; i++) {
            final ConstraintWidget widget = mChildren.get(i);
            if (widget instanceof Guideline) {
                Guideline guideline = (Guideline) widget;
                if (guideline.getOrientation() == Guideline.VERTICAL) {
                    guidelines.add(guideline);
                }
            }
        }
        return guidelines;
    }

    /**
     * Accessor to the horizontal guidelines contained in the table.
     *
     * @return array of guidelines
     */
    public ArrayList<Guideline> getHorizontalGuidelines() {
        ArrayList<Guideline> guidelines = new ArrayList<>();
        for (int i = 0, mChildrenSize = mChildren.size(); i < mChildrenSize; i++) {
            final ConstraintWidget widget = mChildren.get(i);
            if (widget instanceof Guideline) {
                Guideline guideline = (Guideline) widget;
                if (guideline.getOrientation() == Guideline.HORIZONTAL) {
                    guidelines.add(guideline);
                }
            }
        }
        return guidelines;
    }

    public LinearSystem getSystem() {
        return mSystem;
    }

    /*-----------------------------------------------------------------------*/
    // Chains
    /*-----------------------------------------------------------------------*/

    /**
     * Reset the chains array. Need to be called before layout.
     */
    private void resetChains() {
        mHorizontalChainsSize = 0;
        mVerticalChainsSize = 0;
    }

    /**
     * Add the chain which constraintWidget is part of. Called by ConstraintWidget::addToSolver()
     *
     * @param type HORIZONTAL or VERTICAL chain
     */
    void addChain(ConstraintWidget constraintWidget, int type) {
        ConstraintWidget widget = constraintWidget;
        if (type == HORIZONTAL) {
            addHorizontalChain(widget);
        } else if (type == VERTICAL) {
            addVerticalChain(widget);
        }
    }

    /**
     * Add a widget to the list of horizontal chains. The widget is the left-most widget
     * of the chain which doesn't have a left dual connection.
     *
     * @param widget widget starting the chain
     */
    private void addHorizontalChain(ConstraintWidget widget) {
        if (mHorizontalChainsSize + 1 >= mHorizontalChainsArray.length) {
            mHorizontalChainsArray = Arrays
                    .copyOf(mHorizontalChainsArray, mHorizontalChainsArray.length * 2);
        }
        mHorizontalChainsArray[mHorizontalChainsSize] = new ChainHead(widget, HORIZONTAL, isRtl());
        mHorizontalChainsSize++;
    }

    /**
     * Add a widget to the list of vertical chains. The widget is the top-most widget
     * of the chain which doesn't have a top dual connection.
     *
     * @param widget widget starting the chain
     */
    private void addVerticalChain(ConstraintWidget widget) {
        if (mVerticalChainsSize + 1 >= mVerticalChainsArray.length) {
            mVerticalChainsArray = Arrays
                    .copyOf(mVerticalChainsArray, mVerticalChainsArray.length * 2);
        }
        mVerticalChainsArray[mVerticalChainsSize] = new ChainHead(widget, VERTICAL, isRtl());
        mVerticalChainsSize++;
    }

    /**
     * Keep track of the # of passes
     */
    public void setPass(int pass) {
        this.mPass = pass;
    }

    // @TODO: add description
    @Override
    public void getSceneString(StringBuilder ret) {

        ret.append(stringId + ":{\n");
        ret.append("  actualWidth:" + mWidth);
        ret.append("\n");
        ret.append("  actualHeight:" + mHeight);
        ret.append("\n");

        ArrayList<ConstraintWidget> children = getChildren();
        for (ConstraintWidget child : children) {
            child.getSceneString(ret);
            ret.append(",\n");
        }
        ret.append("}");

    }
}