GridLayout.java revision f6679c88d12e9f7e10e6884d4a8487673e53c097
13f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/*
23f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Copyright (C) 2011 The Android Open Source Project
33f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
43f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Licensed under the Apache License, Version 2.0 (the "License");
53f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * you may not use this file except in compliance with the License.
63f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * You may obtain a copy of the License at
73f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
83f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *      http://www.apache.org/licenses/LICENSE-2.0
93f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Unless required by applicable law or agreed to in writing, software
113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * distributed under the License is distributed on an "AS IS" BASIS,
123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See the License for the specific language governing permissions and
143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * limitations under the License.
153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */
163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepackage android.widget;
183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.Context;
203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.res.TypedArray;
213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Canvas;
223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Color;
233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Paint;
243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.AttributeSet;
253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.Log;
2648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milneimport android.util.Pair;
273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.Gravity;
283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.View;
293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.ViewGroup;
30b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milneimport com.android.internal.R;
313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.lang.reflect.Array;
333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.ArrayList;
343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Arrays;
353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.HashMap;
363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.List;
373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Map;
383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milneimport static android.view.Gravity.*;
40899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.EXACTLY;
41899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.makeMeasureSpec;
423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.max;
433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.min;
443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/**
463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * A layout that places its children in a rectangular <em>grid</em>.
473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The grid is composed of a set of infinitely thin lines that separate the
493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced
507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * by grid <em>indices</em>. A grid with {@code N} columns
517fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * has {@code N + 1} grid indices that run from {@code 0}
527fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * through {@code N} inclusive. Regardless of how GridLayout is
537fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * configured, grid index {@code 0} is fixed to the leading edge of the
547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * container and grid index {@code N} is fixed to its trailing edge
553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * (after padding is taken into account).
563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
5793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <h4>Row and Column Specs</h4>
583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Children occupy one or more contiguous cells, as defined
6093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
6193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
6293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Each spec defines the set of rows or columns that are to be
633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * occupied; and how children should be aligned within the resulting group of cells.
643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Although cells do not normally overlap in a GridLayout, GridLayout does
653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * not prevent children being defined to occupy the same cell or group of cells.
663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In this case however, there is no guarantee that children will not themselves
673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * overlap after the layout operation completes.
683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default Cell Assignment</h4>
703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
7148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * If a child does not specify the row and column indices of the cell it
723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * wishes to occupy, GridLayout assigns cell locations automatically using its:
733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setOrientation(int) orientation},
743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setRowCount(int) rowCount} and
753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setColumnCount(int) columnCount} properties.
763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Space</h4>
783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Space between children may be specified either by using instances of the
803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * dedicated {@link Space} view or by setting the
813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin},
833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#topMargin topMargin},
843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and
853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin}
863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters. When the
883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins}
893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * property is set, default margins around children are automatically
90f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * allocated based on the prevailing UI style guide for the platform.
91f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Each of the margins so defined may be independently overridden by an assignment
923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter.
93f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Default values will generally produce a reasonable spacing between components
94f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * but values may change between different releases of the platform.
953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Excess Space Distribution</h4>
973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
98f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's distribution of excess space is based on <em>priority</em>
99f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * rather than <em>weight</em>.
100f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
101899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A child's ability to stretch is inferred from the alignment properties of
102899d5922870c78e0e663bc5661849eb468afc984Philip Milne * its row and column groups (which are typically set by setting the
103899d5922870c78e0e663bc5661849eb468afc984Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters).
104899d5922870c78e0e663bc5661849eb468afc984Philip Milne * If alignment was defined along a given axis then the component
105f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * is taken as <em>flexible</em> in that direction. If no alignment was set,
106f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * the component is instead assumed to be <em>inflexible</em>.
107f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
108f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Multiple components in the same row or column group are
109f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * considered to act in <em>parallel</em>. Such a
110899d5922870c78e0e663bc5661849eb468afc984Philip Milne * group is flexible only if <em>all</em> of the components
111899d5922870c78e0e663bc5661849eb468afc984Philip Milne * within it are flexible. Row and column groups that sit either side of a common boundary
112899d5922870c78e0e663bc5661849eb468afc984Philip Milne * are instead considered to act in <em>series</em>. The composite group made of these two
113899d5922870c78e0e663bc5661849eb468afc984Philip Milne * elements is flexible if <em>one</em> of its elements is flexible.
114899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p>
115899d5922870c78e0e663bc5661849eb468afc984Philip Milne * To make a column stretch, make sure all of the components inside it define a
116899d5922870c78e0e663bc5661849eb468afc984Philip Milne * gravity. To prevent a column from stretching, ensure that one of the components
117899d5922870c78e0e663bc5661849eb468afc984Philip Milne * in the column does not define a gravity.
1183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
119f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When the principle of flexibility does not provide complete disambiguation,
120f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
121f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * and <em>bottom</em> edges.
122f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne *
123f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h5>Limitations</h5>
124f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne *
125f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not provide support for the principle of <em>weight</em>, as defined in
126f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
127f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * to configure a GridLayout to distribute excess space in non-trivial proportions between
128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * multiple rows or columns.
129f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
130f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Some common use-cases may nevertheless be accommodated as follows.
131f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * To place equal amounts of space around a component in a cell group;
132f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}).
133f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * For complete control over excess space distribution in a row or column;
134f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use a {@link LinearLayout} subview to hold the components in the associated cell group.
135f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When using either of these techniques, bear in mind that cell groups may be defined to overlap.
1363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
1373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See {@link GridLayout.LayoutParams} for a full description of the
1383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters used by GridLayout.
1393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
1403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation
1413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount
1423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount
1433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins
1443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
1453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
1463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */
1473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepublic class GridLayout extends ViewGroup {
1483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Public constants
1503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
1523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The horizontal orientation.
1533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
1543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
155aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
1573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The vertical orientation.
1583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
1593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final int VERTICAL = LinearLayout.VERTICAL;
1603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
161aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
162aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * The constant used to indicate that a value is undefined.
163aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * Fields can use this value to indicate that their values
164aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * have not yet been set. Similarly, methods can return this value
165aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * to indicate that there is no suitable value that the implementation
166aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * can return.
167aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * The value used for the constant (currently {@link Integer#MIN_VALUE}) is
168aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * intended to avoid confusion between valid values whose sign may not be known.
169aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
170aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    public static final int UNDEFINED = Integer.MIN_VALUE;
171aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1721e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    /**
1731e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
1741e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment
1751e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * is made between the edges of each component's raw
1761e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * view boundary: i.e. the area delimited by the component's:
1771e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getTop() top},
1781e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getLeft() left},
1791e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getBottom() bottom} and
1801e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getRight() right} properties.
1811e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * <p>
1821e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode,
1831e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * children that belong to a row group that uses {@link #TOP} alignment will
1841e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * all return the same value when their {@link android.view.View#getTop()}
1851e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * method is called.
1861e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
1871e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
1881e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     */
1891e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public static final int ALIGN_BOUNDS = 0;
1901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne
1911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    /**
1921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
1931e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS},
1941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * the bounds of each view are extended outwards, according
1951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * to their margins, before the edges of the resulting rectangle are aligned.
1961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * <p>
1971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode,
1981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * the quantity {@code top - layoutParams.topMargin} is the same for all children that
1991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * belong to a row group that uses {@link #TOP} alignment.
2001e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
2011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
2021e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     */
2031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public static final int ALIGN_MARGINS = 1;
2041e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne
2053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Misc constants
2063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
207f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final String TAG = GridLayout.class.getName();
208f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final boolean DEBUG = false;
209f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int PRF = 1;
210f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int MAX_SIZE = 100000;
211f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int DEFAULT_CONTAINER_MARGIN = 0;
2123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Defaults
2143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final int DEFAULT_ORIENTATION = HORIZONTAL;
2163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final int DEFAULT_COUNT = UNDEFINED;
2173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
218899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static final boolean DEFAULT_ORDER_PRESERVED = true;
2191e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
2203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // TypedArray indices
2223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
223b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ORIENTATION = R.styleable.GridLayout_orientation;
224b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
225b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
226b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
227b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
228b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
229b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
2303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Instance variables
2323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
233f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final Axis horizontalAxis = new Axis(true);
234f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final Axis verticalAxis = new Axis(false);
235f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    boolean layoutParamsValid = false;
236f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    int orientation = DEFAULT_ORIENTATION;
237f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
238f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    int alignmentMode = DEFAULT_ALIGNMENT_MODE;
239f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    int defaultGap;
240aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Constructors
2423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
2443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * {@inheritDoc}
2453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public GridLayout(Context context, AttributeSet attrs, int defStyle) {
2473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        super(context, attrs, defStyle);
248c655ba5e467090eb4f839f148ac31b50c389ffb2Jim Miller        if (DEBUG) {
249c655ba5e467090eb4f839f148ac31b50c389ffb2Jim Miller            setWillNotDraw(false);
250c655ba5e467090eb4f839f148ac31b50c389ffb2Jim Miller        }
251f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        defaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
252b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
2533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        try {
2541e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne            setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
2551e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne            setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
2565125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION));
2575125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS));
2585125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE));
2593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
2603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
2613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        } finally {
2623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            a.recycle();
2633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
2653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    /**
26748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     * {@inheritDoc}
26848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     */
26948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    public GridLayout(Context context, AttributeSet attrs) {
27048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        this(context, attrs, 0);
27148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
27248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
27348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    /**
27448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     * {@inheritDoc}
27548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     */
27648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    public GridLayout(Context context) {
2774c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        //noinspection NullableProblems
27848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        this(context, null);
27948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
28048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Implementation
2823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
2843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current orientation.
2853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
2867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
2873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
2883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setOrientation(int)
2893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
2903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_orientation
2913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getOrientation() {
293f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return orientation;
2943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
2953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
297f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * Orientation is used only to generate default row/column indices when
298f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
2997fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
3007fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * The default value of this property is {@link #HORIZONTAL}.
3013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3027fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL}
3033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getOrientation()
3053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_orientation
3073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setOrientation(int orientation) {
309f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        if (this.orientation != orientation) {
310f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.orientation = orientation;
311f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            invalidateStructure();
3123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            requestLayout();
3133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
3143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current number of rows. This is either the last value that was set
3183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * with {@link #setRowCount(int)} or, if no such value was set, the maximum
31993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
3203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @return the current number of rows
3223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setRowCount(int)
32493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#rowSpec
3253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowCount
3273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getRowCount() {
329f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return verticalAxis.getCount();
3303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
333f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * RowCount is used only to generate default row/column indices when
334f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
3353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3367fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param rowCount the number of rows
3373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getRowCount()
33993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#rowSpec
3403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowCount
3423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setRowCount(int rowCount) {
344f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        verticalAxis.setCount(rowCount);
345f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        invalidateStructure();
346f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        requestLayout();
3473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current number of columns. This is either the last value that was set
3513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * with {@link #setColumnCount(int)} or, if no such value was set, the maximum
35293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
3533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @return the current number of columns
3553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setColumnCount(int)
35793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#columnSpec
3583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnCount
3603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getColumnCount() {
362f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return horizontalAxis.getCount();
3633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
366f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * ColumnCount is used only to generate default column/column indices when
367f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
3683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @param columnCount the number of columns.
3703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getColumnCount()
37293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#columnSpec
3733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnCount
3753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setColumnCount(int columnCount) {
377f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        horizontalAxis.setCount(columnCount);
378f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        invalidateStructure();
379f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        requestLayout();
3803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not this GridLayout will allocate default margins when no
3843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * corresponding layout parameters are defined.
3853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if default margins should be allocated
3873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setUseDefaultMargins(boolean)
3893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
3913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean getUseDefaultMargins() {
393f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return useDefaultMargins;
3943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3977fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When {@code true}, GridLayout allocates default margins around children
3983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * based on the child's visual characteristics. Each of the
3993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * margins so defined may be independently overridden by an assignment
4003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * to the appropriate layout parameter.
4013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
4027fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When {@code false}, the default value of all margins is zero.
403aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * <p>
4047fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When setting to {@code true}, consider setting the value of the
4051e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link #setAlignmentMode(int) alignmentMode}
4061e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * property to {@link #ALIGN_BOUNDS}.
4077fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
4087fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * The default value of this property is {@code false}.
4093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4107fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins
4113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getUseDefaultMargins()
4131e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
4143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#leftMargin
4163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#topMargin
4173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#rightMargin
4183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#bottomMargin
4193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
4213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setUseDefaultMargins(boolean useDefaultMargins) {
423f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        this.useDefaultMargins = useDefaultMargins;
424aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
425aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
426aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
427aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
4281e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * Returns the alignment mode.
4291e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
4301e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
431aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4321e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_BOUNDS
4331e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_MARGINS
434aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4351e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
436aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4371e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @attr ref android.R.styleable#GridLayout_alignmentMode
438aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
4391e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public int getAlignmentMode() {
440f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return alignmentMode;
441aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
442aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
443aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
4441e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * Sets the alignment mode to be used for all of the alignments between the
4451e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * children of this container.
4467fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
4471e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * The default value of this property is {@link #ALIGN_MARGINS}.
4481e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
4491e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
450aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4511e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_BOUNDS
4521e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_MARGINS
453aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4541e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #getAlignmentMode()
455aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4561e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @attr ref android.R.styleable#GridLayout_alignmentMode
457aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
4581e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public void setAlignmentMode(int alignmentMode) {
459f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        this.alignmentMode = alignmentMode;
460aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
4613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
4643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not row boundaries are ordered by their grid indices.
4653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4667fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if row boundaries must appear in the order of their indices,
4677fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *         {@code false} otherwise
4683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setRowOrderPreserved(boolean)
4703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
4723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean isRowOrderPreserved() {
474f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return verticalAxis.isOrderPreserved();
4753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
4787fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When this property is {@code true}, GridLayout is forced to place the row boundaries
479aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * so that their associated grid indices are in ascending order in the view.
4803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
481899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * When this property is {@code false} GridLayout is at liberty to place the vertical row
482899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * boundaries in whatever order best fits the given constraints.
4837fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
484899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The default value of this property is {@code true}.
4857fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
4867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param rowOrderPreserved {@code true} to force GridLayout to respect the order
4877fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *        of row boundaries
4883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #isRowOrderPreserved()
4903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
4923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setRowOrderPreserved(boolean rowOrderPreserved) {
494f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        verticalAxis.setOrderPreserved(rowOrderPreserved);
495aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateStructure();
496aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
4973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not column boundaries are ordered by their grid indices.
5013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5027fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if column boundaries must appear in the order of their indices,
5037fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *         {@code false} otherwise
5043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setColumnOrderPreserved(boolean)
5063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
5083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean isColumnOrderPreserved() {
510f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return horizontalAxis.isOrderPreserved();
5113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5147fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When this property is {@code true}, GridLayout is forced to place the column boundaries
515aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * so that their associated grid indices are in ascending order in the view.
5163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
517899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * When this property is {@code false} GridLayout is at liberty to place the horizontal column
518899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * boundaries in whatever order best fits the given constraints.
5197fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
520899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The default value of this property is {@code true}.
5213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5227fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order
5233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *        of column boundaries.
5243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #isColumnOrderPreserved()
5263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
5283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setColumnOrderPreserved(boolean columnOrderPreserved) {
530f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        horizontalAxis.setOrderPreserved(columnOrderPreserved);
531aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateStructure();
532aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5355125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    // Static utility methods
5365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
537f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static int max2(int[] a, int valueIfEmpty) {
53851f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        int result = valueIfEmpty;
53951f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        for (int i = 0, N = a.length; i < N; i++) {
54051f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            result = Math.max(result, a[i]);
54151f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        }
54251f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        return result;
54351f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne    }
54451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne
545899d5922870c78e0e663bc5661849eb468afc984Philip Milne    @SuppressWarnings("unchecked")
546f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static <T> T[] append(T[] a, T[] b) {
54748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
54848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        System.arraycopy(a, 0, result, 0, a.length);
54948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        System.arraycopy(b, 0, result, a.length, b.length);
5503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return result;
5513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
553f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static Alignment getAlignment(int gravity, boolean horizontal) {
5545125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK;
5555125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT;
5565125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int flags = (gravity & mask) >> shift;
5575125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        switch (flags) {
5585125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
5595125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return LEADING;
5605125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
5615125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return TRAILING;
5625125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
5635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return FILL;
5645125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case AXIS_SPECIFIED:
5655125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return CENTER;
5665125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            default:
5675125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return UNDEFINED_ALIGNMENT;
5685125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
5695125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
5705125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
5714c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    /** @noinspection UnusedParameters*/
5721fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
573899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (c.getClass() == Space.class) {
574899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return 0;
575899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
576f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return defaultGap / 2;
5773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5791fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
5801fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
5813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5831fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) {
584f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        if (!useDefaultMargins) {
5853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return 0;
5863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
58793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        Spec spec = horizontal ? p.columnSpec : p.rowSpec;
588f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Axis axis = horizontal ? horizontalAxis : verticalAxis;
58993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        Interval span = spec.span;
590aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
5913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5921fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return getDefaultMargin(c, isAtEdge, horizontal, leading);
5933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
595f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    int getMargin1(View view, boolean horizontal, boolean leading) {
5963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        LayoutParams lp = getLayoutParams(view);
5973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int margin = horizontal ?
598aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                (leading ? lp.leftMargin : lp.rightMargin) :
599aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                (leading ? lp.topMargin : lp.bottomMargin);
6001fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin;
6011fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    }
6021fd16378812792913a6aa6923acbec20037e09ffPhilip Milne
6034c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    private int getMargin(View view, boolean horizontal, boolean leading) {
604f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        if (alignmentMode == ALIGN_MARGINS) {
6054c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return getMargin1(view, horizontal, leading);
6064c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        } else {
607f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            Axis axis = horizontal ? horizontalAxis : verticalAxis;
6084c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
6094c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            LayoutParams lp = getLayoutParams(view);
6104c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
6114c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int index = leading ? spec.span.min : spec.span.max;
6124c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return margins[index];
6134c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        }
6144c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    }
6154c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne
6161fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getTotalMargin(View child, boolean horizontal) {
6171fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
6183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
620899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static boolean fits(int[] a, int value, int start, int end) {
621899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (end > a.length) {
622899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return false;
623899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
624899d5922870c78e0e663bc5661849eb468afc984Philip Milne        for (int i = start; i < end; i++) {
625899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (a[i] > value) {
626899d5922870c78e0e663bc5661849eb468afc984Philip Milne                return false;
6273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
628899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
629899d5922870c78e0e663bc5661849eb468afc984Philip Milne        return true;
630899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
6313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
632899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static void procrusteanFill(int[] a, int start, int end, int value) {
633899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int length = a.length;
634899d5922870c78e0e663bc5661849eb468afc984Philip Milne        Arrays.fill(a, Math.min(start, length), Math.min(end, length), value);
635899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
6363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
637899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) {
638899d5922870c78e0e663bc5661849eb468afc984Philip Milne        lp.setRowSpecSpan(new Interval(row, row + rowSpan));
639899d5922870c78e0e663bc5661849eb468afc984Philip Milne        lp.setColumnSpecSpan(new Interval(col, col + colSpan));
640899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
6413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
642899d5922870c78e0e663bc5661849eb468afc984Philip Milne    // Logic to avert infinite loops by ensuring that the cells can be placed somewhere.
643899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static int clip(Interval minorRange, boolean minorWasDefined, int count) {
644899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int size = minorRange.size();
645899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (count == 0) {
646899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return size;
647899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
648899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int min = minorWasDefined ? min(minorRange.min, count) : 0;
649899d5922870c78e0e663bc5661849eb468afc984Philip Milne        return min(size, count - min);
650899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
651f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
652899d5922870c78e0e663bc5661849eb468afc984Philip Milne    // install default indices for cells that don't define them
653899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private void validateLayoutParams() {
654f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final boolean horizontal = (orientation == HORIZONTAL);
655f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Axis axis = horizontal ? horizontalAxis : verticalAxis;
656f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
657f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
658899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int major = 0;
659899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int minor = 0;
660899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int[] maxSizes = new int[count];
661f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
662899d5922870c78e0e663bc5661849eb468afc984Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
663899d5922870c78e0e663bc5661849eb468afc984Philip Milne            LayoutParams lp = getLayoutParams1(getChildAt(i));
664899d5922870c78e0e663bc5661849eb468afc984Philip Milne
665f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
666f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Interval majorRange = majorSpec.span;
667f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final boolean majorWasDefined = majorSpec.startDefined;
668899d5922870c78e0e663bc5661849eb468afc984Philip Milne            final int majorSpan = majorRange.size();
669899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (majorWasDefined) {
670899d5922870c78e0e663bc5661849eb468afc984Philip Milne                major = majorRange.min;
671899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
672899d5922870c78e0e663bc5661849eb468afc984Philip Milne
673f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec;
674f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Interval minorRange = minorSpec.span;
675f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final boolean minorWasDefined = minorSpec.startDefined;
676899d5922870c78e0e663bc5661849eb468afc984Philip Milne            final int minorSpan = clip(minorRange, minorWasDefined, count);
677899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (minorWasDefined) {
678899d5922870c78e0e663bc5661849eb468afc984Philip Milne                minor = minorRange.min;
679899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
680899d5922870c78e0e663bc5661849eb468afc984Philip Milne
681899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (count != 0) {
682899d5922870c78e0e663bc5661849eb468afc984Philip Milne                // Find suitable row/col values when at least one is undefined.
683899d5922870c78e0e663bc5661849eb468afc984Philip Milne                if (!majorWasDefined || !minorWasDefined) {
684899d5922870c78e0e663bc5661849eb468afc984Philip Milne                    while (!fits(maxSizes, major, minor, minor + minorSpan)) {
685899d5922870c78e0e663bc5661849eb468afc984Philip Milne                        if (minorWasDefined) {
686899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            major++;
687899d5922870c78e0e663bc5661849eb468afc984Philip Milne                        } else {
688899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            if (minor + minorSpan <= count) {
689899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                minor++;
690899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            } else {
691899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                minor = 0;
692899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                major++;
693899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            }
694f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne                        }
695f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne                    }
6963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
697899d5922870c78e0e663bc5661849eb468afc984Philip Milne                procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan);
6983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
699899d5922870c78e0e663bc5661849eb468afc984Philip Milne
700899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (horizontal) {
701899d5922870c78e0e663bc5661849eb468afc984Philip Milne                setCellGroup(lp, major, majorSpan, minor, minorSpan);
702899d5922870c78e0e663bc5661849eb468afc984Philip Milne            } else {
703899d5922870c78e0e663bc5661849eb468afc984Philip Milne                setCellGroup(lp, minor, minorSpan, major, majorSpan);
704899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
705899d5922870c78e0e663bc5661849eb468afc984Philip Milne
706899d5922870c78e0e663bc5661849eb468afc984Philip Milne            minor = minor + minorSpan;
707899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
708f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne        invalidateStructure();
7093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void invalidateStructure() {
712f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        layoutParamsValid = false;
713f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        horizontalAxis.invalidateStructure();
714f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        verticalAxis.invalidateStructure();
715899d5922870c78e0e663bc5661849eb468afc984Philip Milne        // This can end up being done twice. Better twice than not at all.
7163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        invalidateValues();
7173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void invalidateValues() {
720aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // Need null check because requestLayout() is called in View's initializer,
721aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // before we are set up.
722f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        if (horizontalAxis != null && verticalAxis != null) {
723f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            horizontalAxis.invalidateValues();
724f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            verticalAxis.invalidateValues();
725aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
7263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private LayoutParams getLayoutParams1(View c) {
7293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return (LayoutParams) c.getLayoutParams();
7303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
732f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final LayoutParams getLayoutParams(View c) {
733f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        if (!layoutParamsValid) {
7343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            validateLayoutParams();
735f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            layoutParamsValid = true;
7363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
7373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return getLayoutParams1(c);
7383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
7413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected LayoutParams generateDefaultLayoutParams() {
7423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return new LayoutParams();
7433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
7463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public LayoutParams generateLayoutParams(AttributeSet attrs) {
7475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return new LayoutParams(getContext(), attrs);
7483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
7513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
7523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return new LayoutParams(p);
7533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Draw grid
7563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
7583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int dx = getPaddingLeft();
7593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int dy = getPaddingTop();
7603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
7613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
763b559976a50c34848d602cc7138859507a379893cPhilip Milne    private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
764b559976a50c34848d602cc7138859507a379893cPhilip Milne        canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint);
765b559976a50c34848d602cc7138859507a379893cPhilip Milne    }
766b559976a50c34848d602cc7138859507a379893cPhilip Milne
7673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
7683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected void onDraw(Canvas canvas) {
7693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        super.onDraw(canvas);
7703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        if (DEBUG) {
7723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int height = getHeight() - getPaddingTop() - getPaddingBottom();
7733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int width = getWidth() - getPaddingLeft() - getPaddingRight();
7743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
775b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            Paint paint = new Paint();
7764c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            paint.setStyle(Paint.Style.STROKE);
777b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            paint.setColor(Color.argb(50, 255, 255, 255));
778b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
779f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            int[] xs = horizontalAxis.locations;
780b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            if (xs != null) {
781b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                for (int i = 0, length = xs.length; i < length; i++) {
782b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                    int x = xs[i];
783b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                    drawLine(canvas, x, 0, x, height - 1, paint);
784b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                }
7853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
786b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
787f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            int[] ys = verticalAxis.locations;
788b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            if (ys != null) {
789b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                for (int i = 0, length = ys.length; i < length; i++) {
790b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                    int y = ys[i];
791b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                    drawLine(canvas, 0, y, width - 1, y, paint);
792b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                }
793b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            }
79448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
795b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            // Draw bounds
796b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            paint.setColor(Color.BLUE);
797b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0; i < getChildCount(); i++) {
798b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
799b559976a50c34848d602cc7138859507a379893cPhilip Milne                drawRect(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), paint);
800b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            }
801b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
802b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            // Draw margins
80393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            paint.setColor(Color.MAGENTA);
804b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0; i < getChildCount(); i++) {
805b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
806b559976a50c34848d602cc7138859507a379893cPhilip Milne                drawRect(canvas,
8074c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                        c.getLeft() - getMargin1(c, true, true),
8084c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                        c.getTop() - getMargin1(c, false, true),
8094c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                        c.getRight() + getMargin1(c, true, false),
8104c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                        c.getBottom() + getMargin1(c, false, false), paint);
8113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
8123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
8133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Add/remove
8163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
817e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne    /**
818e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     * @hide
819e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     */
8203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
821f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne    protected void onViewAdded(View child) {
822f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne        super.onViewAdded(child);
8233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        invalidateStructure();
8243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
826e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne    /**
827e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     * @hide
828e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     */
8293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
830f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne    protected void onViewRemoved(View child) {
831f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne        super.onViewRemoved(child);
832b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        invalidateStructure();
833350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    }
834350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne
835350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    /**
836350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * We need to call invalidateStructure() when a child's GONE flag changes state.
837350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * This implementation is a catch-all, invalidating on any change in the visibility flags.
838350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     *
839350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * @hide
840350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     */
841350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    @Override
842350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    protected void onChildVisibilityChanged(View child, int visibility) {
843350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne        super.onChildVisibilityChanged(child, visibility);
844350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne        invalidateStructure();
845b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    }
846b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne
8473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Measurement
8483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
849f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final boolean isGone(View c) {
850b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        return c.getVisibility() == View.GONE;
851b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
852b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
8531fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private void measureChildWithMargins(View child, int widthMeasureSpec, int heightMeasureSpec) {
854b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        LayoutParams lp = getLayoutParams(child);
8551fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
8561fd16378812792913a6aa6923acbec20037e09ffPhilip Milne                mPaddingLeft + mPaddingRight + getTotalMargin(child, true), lp.width);
8571fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
8581fd16378812792913a6aa6923acbec20037e09ffPhilip Milne                mPaddingTop + mPaddingBottom + getTotalMargin(child, false), lp.height);
859b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
860b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
861b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
862b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    private void measureChildrenWithMargins(int widthMeasureSpec, int heightMeasureSpec) {
863b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
864b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            View c = getChildAt(i);
865b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            if (isGone(c)) continue;
866b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            measureChildWithMargins(c, widthMeasureSpec, heightMeasureSpec);
867b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        }
868b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
869b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
870aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    @Override
871aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    protected void onMeasure(int widthSpec, int heightSpec) {
872b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        measureChildrenWithMargins(widthSpec, heightSpec);
873aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
874f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int width = getPaddingLeft() + horizontalAxis.getMeasure(widthSpec) + getPaddingRight();
875f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int height = getPaddingTop() + verticalAxis.getMeasure(heightSpec) + getPaddingBottom();
8763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
87748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        int measuredWidth = Math.max(width, getSuggestedMinimumWidth());
87848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        int measuredHeight = Math.max(height, getSuggestedMinimumHeight());
87909e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne
8803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        setMeasuredDimension(
88109e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne                resolveSizeAndState(measuredWidth, widthSpec, 0),
88209e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne                resolveSizeAndState(measuredHeight, heightSpec, 0));
8833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private int protect(int alignment) {
886aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        return (alignment == UNDEFINED) ? 0 : alignment;
8873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
88948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    private int getMeasurement(View c, boolean horizontal) {
890aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
8913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
893f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final int getMeasurementIncludingMargin(View c, boolean horizontal) {
8945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        if (isGone(c)) {
8955125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            return 0;
8965125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
8974c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
898aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
8993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
900aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    @Override
901aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    public void requestLayout() {
902aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        super.requestLayout();
903aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateValues();
904aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
905aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
906f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final Alignment getAlignment(Alignment alignment, boolean horizontal) {
9075125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
908899d5922870c78e0e663bc5661849eb468afc984Philip Milne                (horizontal ? LEFT : BASELINE);
9095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
9105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
9113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Layout container
9123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
913aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
914aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * {@inheritDoc}
915aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
916aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
917aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     The layout operation is implemented by delegating the heavy lifting to the
918aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class.
919aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     Together they compute the locations of the vertical and horizontal lines of
920aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     the grid (respectively!).
921aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
922aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     This method is then left with the simpler task of applying margins, gravity
923aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     and sizing to each child view and then placing it in its cell.
924aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
9253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
92609e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
92709e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne        int targetWidth = right - left;
92809e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne        int targetHeight = bottom - top;
9293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingLeft = getPaddingLeft();
9313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingTop = getPaddingTop();
9323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingRight = getPaddingRight();
9333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingBottom = getPaddingBottom();
9343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
935f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        horizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
936f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        verticalAxis.layout(targetHeight - paddingTop - paddingBottom);
9373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
938f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int[] hLocations = horizontalAxis.getLocations();
939f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int[] vLocations = verticalAxis.getLocations();
9404c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne
941b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
942b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            View c = getChildAt(i);
943b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            if (isGone(c)) continue;
944b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            LayoutParams lp = getLayoutParams(c);
94593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec columnSpec = lp.columnSpec;
94693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec rowSpec = lp.rowSpec;
947aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
94893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Interval colSpan = columnSpec.span;
94993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Interval rowSpan = rowSpec.span;
9503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9514c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int x1 = hLocations[colSpan.min];
9524c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int y1 = vLocations[rowSpan.min];
9533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9544c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int x2 = hLocations[colSpan.max];
9554c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int y2 = vLocations[rowSpan.max];
9563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cellWidth = x2 - x1;
9583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cellHeight = y2 - y1;
9593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
96048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int pWidth = getMeasurement(c, true);
96148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int pHeight = getMeasurement(c, false);
9623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            Alignment hAlign = getAlignment(columnSpec.alignment, true);
9645125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            Alignment vAlign = getAlignment(rowSpec.alignment, false);
965aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
966aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int dx, dy;
9673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
968f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i);
969f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i);
9707fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
9717fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            // Gravity offsets: the location of the alignment group relative to its cell group.
9724c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection NullableProblems
97348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
9744c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection NullableProblems
97548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
9767fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
9774c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int leftMargin = getMargin(c, true, true);
9784c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int topMargin = getMargin(c, false, true);
9794c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int rightMargin = getMargin(c, true, false);
9804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int bottomMargin = getMargin(c, false, false);
9817fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
9824c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // Same calculation as getMeasurementIncludingMargin()
9834c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int mWidth = leftMargin + pWidth + rightMargin;
9844c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int mHeight = topMargin + pHeight + bottomMargin;
9853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9864c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // Alignment offsets: the location of the view relative to its alignment group.
9874c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int a2vx = colBounds.getOffset(c, hAlign, mWidth);
9884c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
9897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
9904c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            dx = c2ax + a2vx + leftMargin;
9914c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            dy = c2ay + a2vy + topMargin;
9927fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
9934c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            cellWidth -= leftMargin + rightMargin;
9944c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            cellHeight -= topMargin + bottomMargin;
9953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
99648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int type = PRF;
997b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
998b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type);
9993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cx = paddingLeft + x1 + dx;
10013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cy = paddingTop + y1 + dy;
1002899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
1003899d5922870c78e0e663bc5661849eb468afc984Philip Milne                c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
1004899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
1005b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            c.layout(cx, cy, cx + width, cy + height);
10063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
10083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Inner classes
10103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1011aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1012aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     This internal class houses the algorithm for computing the locations of grid lines;
1013aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     along either the horizontal or vertical axis. A GridLayout uses two instances of this class -
1014aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     distinguished by the "horizontal" flag which is true for the horizontal axis and false
1015aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     for the vertical one.
1016aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
1017f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final class Axis {
10183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int MIN_VALUE = -1000000;
10193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
102048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private static final int NEW = 0;
10213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int PENDING = 1;
10223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int COMPLETE = 2;
10233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final boolean horizontal;
10253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1026f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int definedCount = UNDEFINED;
1027f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private int inferredCount = UNDEFINED;
10283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
102993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        PackedMap<Spec, Bounds> groupBounds;
10303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean groupBoundsValid = false;
10313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
103248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        PackedMap<Interval, MutableInt> forwardLinks;
103348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean forwardLinksValid = false;
103448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
103548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        PackedMap<Interval, MutableInt> backwardLinks;
103648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean backwardLinksValid = false;
10373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int[] leadingMargins;
1039aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public boolean leadingMarginsValid = false;
1040aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
10413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int[] trailingMargins;
1042aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public boolean trailingMarginsValid = false;
10433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public Arc[] arcs;
10453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean arcsValid = false;
10463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1047aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public int[] locations;
104848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean locationsValid = false;
1049aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1050f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
10513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
105248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private MutableInt parentMin = new MutableInt(0);
105348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private MutableInt parentMax = new MutableInt(-MAX_SIZE);
105448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
10553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private Axis(boolean horizontal) {
10563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.horizontal = horizontal;
10573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1059f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne        private int maxIndex() {
10603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // note the number Integer.MIN_VALUE + 1 comes up in undefined cells
10613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int count = -1;
1062b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1063b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
1064b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                LayoutParams params = getLayoutParams(c);
106593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? params.columnSpec : params.rowSpec;
106693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                count = max(count, spec.span.min);
106793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                count = max(count, spec.span.max);
10683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
10693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return count == -1 ? UNDEFINED : count;
10703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1072f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private int getInferredCount() {
1073f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            if (inferredCount == UNDEFINED) {
1074f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                inferredCount = max(0, maxIndex()); // if there are no cells, actual count is zero
10753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
1076f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return inferredCount;
1077f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1078f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1079f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int getCount() {
1080f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return max(definedCount, getInferredCount());
10813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setCount(int count) {
1084f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.definedCount = count;
10853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean isOrderPreserved() {
1088f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return orderPreserved;
10893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
10913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setOrderPreserved(boolean orderPreserved) {
1092f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.orderPreserved = orderPreserved;
10933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            invalidateStructure();
10943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
10953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
109693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        private PackedMap<Spec, Bounds> createGroupBounds() {
109793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
109848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1099b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
11005125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                LayoutParams lp = getLayoutParams(c);
11015125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
11025125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
11035125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                assoc.put(spec, bounds);
11043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
110548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return assoc.pack();
11063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private void computeGroupBounds() {
1109b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            Bounds[] values = groupBounds.values;
1110b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0; i < values.length; i++) {
1111b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                values[i].reset();
11123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
1113aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
11143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                View c = getChildAt(i);
11153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                LayoutParams lp = getLayoutParams(c);
111693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
111793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
11183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
11193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1121f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public PackedMap<Spec, Bounds> getGroupBounds() {
11223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (groupBounds == null) {
11233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                groupBounds = createGroupBounds();
11243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
11253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (!groupBoundsValid) {
11263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                computeGroupBounds();
11273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                groupBoundsValid = true;
11283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
11293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return groupBounds;
11303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Add values computed by alignment - taking the max of all alignments in each span
113348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> createLinks(boolean min) {
113448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
113593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec[] keys = getGroupBounds().keys;
113648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0, N = keys.length; i < N; i++) {
113748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Interval span = min ? keys[i].span : keys[i].span.inverse();
113848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                result.put(span, new MutableInt());
11393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
114048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return result.pack();
11413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
114348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) {
114448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            MutableInt[] spans = links.values;
11453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < spans.length; i++) {
11463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                spans[i].reset();
11473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
11483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11495d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            // Use getter to trigger a re-evaluation
115048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Bounds[] bounds = getGroupBounds().values;
11513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < bounds.length; i++) {
115248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                int size = bounds[i].size(min);
115348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                MutableInt valueHolder = links.getValue(i);
11545125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                // this effectively takes the max() of the minima and the min() of the maxima
11555125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                valueHolder.value = max(valueHolder.value, min ? size : -size);
11563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
11573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
115948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> getForwardLinks() {
116048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (forwardLinks == null) {
116148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                forwardLinks = createLinks(true);
11623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
116348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!forwardLinksValid) {
116448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLinks(forwardLinks, true);
116548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                forwardLinksValid = true;
11663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
116748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return forwardLinks;
11683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
117048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> getBackwardLinks() {
117148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (backwardLinks == null) {
117248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                backwardLinks = createLinks(false);
11733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
117448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!backwardLinksValid) {
117548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLinks(backwardLinks, false);
117648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                backwardLinksValid = true;
117748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
117848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return backwardLinks;
11793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
118148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void include(List<Arc> arcs, Interval key, MutableInt size,
118248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                boolean ignoreIfAlreadyPresent) {
118348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            /*
118448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Remove self referential links.
118548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            These appear:
118648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                . as parental constraints when GridLayout has no children
118748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                . when components have been marked as GONE
118848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            */
118948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (key.size() == 0) {
119048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                return;
11913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
119248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // this bit below should really be computed outside here -
119348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // its just to stop default (row/col > 0) constraints obliterating valid entries
119448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (ignoreIfAlreadyPresent) {
119548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                for (Arc arc : arcs) {
119648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    Interval span = arc.span;
119748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    if (span.equals(key)) {
119848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        return;
119948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
120048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
120148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
120248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            arcs.add(new Arc(key, size));
12033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
120548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void include(List<Arc> arcs, Interval key, MutableInt size) {
120648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(arcs, key, size, true);
12073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1209aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // Group arcs by their first vertex, returning an array of arrays.
12103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // This is linear in the number of arcs.
1211f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
121248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = getCount() + 1; // the number of vertices
12133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Arc[][] result = new Arc[N][];
12143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int[] sizes = new int[N];
12153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (Arc arc : arcs) {
12163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                sizes[arc.span.min]++;
12175d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            }
12183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < sizes.length; i++) {
12193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i] = new Arc[sizes[i]];
12203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
12213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // reuse the sizes array to hold the current last elements as we insert each arc
12223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Arrays.fill(sizes, 0);
12233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (Arc arc : arcs) {
12243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int i = arc.span.min;
12253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i][sizes[i]++] = arc;
12263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
12273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
12293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
123148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Arc[] topologicalSort(final Arc[] arcs) {
123248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new Object() {
123348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[] result = new Arc[arcs.length];
123448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                int cursor = result.length - 1;
123548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs);
12363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int[] visited = new int[getCount() + 1];
12373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
123848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                void walk(int loc) {
123948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    switch (visited[loc]) {
124048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case NEW: {
124148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            visited[loc] = PENDING;
124248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            for (Arc arc : arcsByVertex[loc]) {
124348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                                walk(arc.span.max);
124448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                                result[cursor--] = arc;
12453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                            }
124648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            visited[loc] = COMPLETE;
124748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
124848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        }
124948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case PENDING: {
125048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            assert false;
125148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
125248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        }
125348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case COMPLETE: {
125448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
12553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                        }
12563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    }
12573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
125848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
125948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[] sort() {
126048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) {
126148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        walk(loc);
126248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
126348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    assert cursor == -1;
126448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return result;
126548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
126648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }.sort();
126748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
126848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
126948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Arc[] topologicalSort(List<Arc> arcs) {
127048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return topologicalSort(arcs.toArray(new Arc[arcs.size()]));
12713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
127348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) {
127448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0; i < links.keys.length; i++) {
127548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Interval key = links.keys[i];
127648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                include(result, key, links.values[i], false);
127748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
127848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
127948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1280aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private Arc[] createArcs() {
128148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            List<Arc> mins = new ArrayList<Arc>();
128248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            List<Arc> maxs = new ArrayList<Arc>();
12833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
128448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the minimum values from the components.
128548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            addComponentSizes(mins, getForwardLinks());
128648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the maximum values from the components.
128748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            addComponentSizes(maxs, getBackwardLinks());
12883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
128948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add ordering constraints to prevent row/col sizes from going negative
1290f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            if (orderPreserved) {
129148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                // Add a constraint for every row/col
12923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                for (int i = 0; i < getCount(); i++) {
1293899d5922870c78e0e663bc5661849eb468afc984Philip Milne                    include(mins, new Interval(i, i + 1), new MutableInt(0));
12943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
12953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
129648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
129748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the container constraints. Use the version of include that allows
129848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // duplicate entries in case a child spans the entire grid.
129948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = getCount();
130048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(mins, new Interval(0, N), parentMin, false);
130148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(maxs, new Interval(N, 0), parentMax, false);
130248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
130348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Sort
130448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Arc[] sMins = topologicalSort(mins);
130548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Arc[] sMaxs = topologicalSort(maxs);
130648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
130748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return append(sMins, sMaxs);
130848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
130948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
131048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeArcs() {
131148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // getting the links validates the values that are shared by the arc list
131248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getForwardLinks();
131348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getBackwardLinks();
13143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1316aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public Arc[] getArcs() {
13173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (arcs == null) {
1318aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                arcs = createArcs();
13193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (!arcsValid) {
132148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeArcs();
13223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                arcsValid = true;
13233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return arcs;
13253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1327aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private boolean relax(int[] locations, Arc entry) {
132848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!entry.valid) {
132948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                return false;
133048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
13313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Interval span = entry.span;
13323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int u = span.min;
13333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int v = span.max;
13343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int value = entry.value.value;
13353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int candidate = locations[u] + value;
1336aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (candidate > locations[v]) {
13373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                locations[v] = candidate;
13383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
13393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return false;
13413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1343f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private void init(int[] locations) {
1344f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            Arrays.fill(locations, MIN_VALUE);
1345f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            locations[0] = 0;
1346f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1347f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1348f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private String arcsToString(List<Arc> arcs) {
1349f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            String var = horizontal ? "c" : "r";
1350f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            StringBuilder result = new StringBuilder();
1351f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            boolean first = false;
1352f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for(Arc arc : arcs) {
1353f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (!first) {
1354f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    first = true;
1355f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                } else {
1356f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    result =result.append(", ");
1357f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1358f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int src = arc.span.min;
1359f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int dst = arc.span.max;
1360f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int value = arc.value.value;
1361f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                result.append((src < dst) ?
1362f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        var + dst + " - " + var + src + " > " + value :
1363f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        var + src + " - " + var + dst + " < " + -value);
1364f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1365f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            }
1366f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return result.toString();
1367f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1368f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1369f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private void logError(String axisName, Arc[] arcs, boolean[] culprits0) {
1370f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            List<Arc> culprits = new ArrayList<Arc>();
1371f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            List<Arc> removed = new ArrayList<Arc>();
1372f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for (int c = 0; c < arcs.length; c++) {
1373f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                Arc arc = arcs[c];
1374f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (culprits0[c]) {
1375f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    culprits.add(arc);
1376f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1377f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (!arc.valid) {
1378f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    removed.add(arc);
1379f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1380f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            }
1381f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            Log.d(TAG, axisName + " constraints: " + arcsToString(culprits) + " are inconsistent; "
1382f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    + "permanently removing: " + arcsToString(removed) + ". ");
1383f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1384f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1385aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        /*
1386aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N)
1387aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1388aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        GridLayout converts its requirements into a system of linear constraints of the
1389aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        form:
1390aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1391aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        x[i] - x[j] < a[k]
1392aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1393aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Where the x[i] are variables and the a[k] are constants.
1394aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1395aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        For example, if the variables were instead labeled x, y, z we might have:
1396aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1397aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            x - y < 17
1398aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            y - z < 23
1399aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            z - x < 42
1400aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1401aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        This is a special case of the Linear Programming problem that is, in turn,
1402aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        equivalent to the single-source shortest paths problem on a digraph, for
1403aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        which the O(n^2) Bellman-Ford algorithm the most commonly used general solution.
1404aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1405aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Other algorithms are faster in the case where no arcs have negative weights
1406aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        but allowing negative weights turns out to be the same as accommodating maximum
1407aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        size requirements as well as minimum ones.
1408aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1409aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Bellman-Ford works by iteratively 'relaxing' constraints over all nodes (an O(N)
1410aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        process) and performing this step N times. Proof of correctness hinges on the
1411aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        fact that there can be no negative weight chains of length > N - unless a
1412aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        'negative weight loop' exists. The algorithm catches this case in a final
1413aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        checking phase that reports failure.
1414aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1415aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        By topologically sorting the nodes and checking this condition at each step
1416aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        typical layout problems complete after the first iteration and the algorithm
1417aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        completes in O(N) steps with very low constants.
1418aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        */
141948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void solve(Arc[] arcs, int[] locations) {
1420f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            String axisName = horizontal ? "horizontal" : "vertical";
14213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
1422f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            boolean[] originalCulprits = null;
14233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1424f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for (int p = 0; p < arcs.length; p++) {
1425f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                init(locations);
1426f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1427f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                // We take one extra pass over traditional Bellman-Ford (and omit their final step)
1428f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < N; i++) {
1429f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    boolean changed = false;
1430f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    for (int j = 0, length = arcs.length; j < length; j++) {
1431f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        changed |= relax(locations, arcs[j]);
1432f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    }
1433f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    if (!changed) {
1434f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (originalCulprits != null) {
1435f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            logError(axisName, arcs, originalCulprits);
1436f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
1437f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (DEBUG) {
1438f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            Log.v(TAG, axisName + " iteration completed in " +
1439f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                                    (1 + i) + " steps of " + N);
1440f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
1441f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        return;
14423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    }
14433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
144448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1445f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                boolean[] culprits = new boolean[arcs.length];
1446f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < N; i++) {
1447f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    for (int j = 0, length = arcs.length; j < length; j++) {
1448f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        culprits[j] |= relax(locations, arcs[j]);
1449f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    }
1450f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
145148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1452f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (p == 0) {
1453f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    originalCulprits = culprits;
145448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
1455f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1456f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < arcs.length; i++) {
1457f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    if (culprits[i]) {
1458f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        Arc arc = arcs[i];
1459f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        // Only remove max values, min values alone cannot be inconsistent
1460f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (arc.span.min < arc.span.max) {
1461f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            continue;
1462f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
1463f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        arc.valid = false;
1464f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        break;
146548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
146648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
146748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
14683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1470aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private void computeMargins(boolean leading) {
1471aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int[] margins = leading ? leadingMargins : trailingMargins;
1472b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
14733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                View c = getChildAt(i);
1474b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                if (isGone(c)) continue;
14753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                LayoutParams lp = getLayoutParams(c);
147693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
147793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Interval span = spec.span;
14783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int index = leading ? span.min : span.max;
14794c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                margins[index] = max(margins[index], getMargin1(c, horizontal, leading));
14803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
14813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1483f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        // External entry points
1484f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1485f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getLeadingMargins() {
1486aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (leadingMargins == null) {
1487aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                leadingMargins = new int[getCount() + 1];
1488aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1489aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (!leadingMarginsValid) {
1490aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                computeMargins(true);
1491aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                leadingMarginsValid = true;
1492aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1493aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return leadingMargins;
1494aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
1495aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1496f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getTrailingMargins() {
1497aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (trailingMargins == null) {
1498aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                trailingMargins = new int[getCount() + 1];
1499aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1500aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (!trailingMarginsValid) {
1501aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                computeMargins(false);
1502aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                trailingMarginsValid = true;
1503aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1504aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return trailingMargins;
1505aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
15063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
150748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeLocations(int[] a) {
1508f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            solve(getArcs(), a);
15093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1511f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getLocations() {
1512aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (locations == null) {
1513aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                int N = getCount() + 1;
1514aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                locations = new int[N];
1515aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
151648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!locationsValid) {
151748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLocations(locations);
151848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                locationsValid = true;
151948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
1520aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return locations;
15213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1523aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private int size(int[] locations) {
152451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            return max2(locations, 0) - locations[0];
1525aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
1526aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
152748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void setParentConstraints(int min, int max) {
152848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            parentMin.value = min;
152948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            parentMax.value = -max;
153048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            locationsValid = false;
15313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
153348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private int getMeasure(int min, int max) {
153448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            setParentConstraints(min, max);
153548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return size(getLocations());
153648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
1537aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1538f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int getMeasure(int measureSpec) {
153948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int mode = MeasureSpec.getMode(measureSpec);
154048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int size = MeasureSpec.getSize(measureSpec);
154148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            switch (mode) {
154248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.UNSPECIFIED: {
154393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                    return getMeasure(0, MAX_SIZE);
154448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
154548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.EXACTLY: {
154648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return getMeasure(size, size);
154748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
154848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.AT_MOST: {
154948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return getMeasure(0, size);
155048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
155148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                default: {
155248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    assert false;
155348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return 0;
155448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
15553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
155648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
1557aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1558f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void layout(int size) {
155948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            setParentConstraints(size, size);
156048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getLocations();
15613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1563f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void invalidateStructure() {
1564f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            inferredCount = UNDEFINED;
1565aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
15663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            groupBounds = null;
156748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            forwardLinks = null;
156848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            backwardLinks = null;
156948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1570aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            leadingMargins = null;
1571aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            trailingMargins = null;
1572c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne            arcs = null;
157348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1574aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            locations = null;
15753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
15763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            invalidateValues();
15773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1579f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void invalidateValues() {
15803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            groupBoundsValid = false;
158148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            forwardLinksValid = false;
158248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            backwardLinksValid = false;
158348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1584aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            leadingMarginsValid = false;
1585aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            trailingMarginsValid = false;
158648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            arcsValid = false;
158748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
158848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            locationsValid = false;
15893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
15913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
15923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
15933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Layout information associated with each of the children of a GridLayout.
15943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
15953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * GridLayout supports both row and column spanning and arbitrary forms of alignment within
15963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * each cell group. The fundamental parameters associated with each cell group are
15973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * gathered into their vertical and horizontal components and stored
159893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
1599b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne     * {@link android.widget.GridLayout.Spec Specs} are immutable structures
1600b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne     * and may be shared between the layout parameters of different children.
16013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
160293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The row and column specs contain the leading and trailing indices along each axis
1603aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * and together specify the four grid indices that delimit the cells of this cell group.
16043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
160593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The  alignment properties of the row and column specs together specify
16063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * both aspects of alignment within the cell group. It is also possible to specify a child's
16073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
16083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * method.
1609f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1610f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * <h4>WRAP_CONTENT and MATCH_PARENT</h4>
1611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1612f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * Because the default values of the {@link #width} and {@link #height}
1613f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly
1614f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * declared in the layout parameters of GridLayout's children. In addition,
1615f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from
1616f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is
1617f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * instead controlled by the principle of <em>flexibility</em>,
1618f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * as discussed in {@link GridLayout}.
1619f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * <h4>Summary</h4>
1621f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1622f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * You should not need to use either of the special size values:
1623f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of
1624f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * a GridLayout.
16253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
16263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <h4>Default values</h4>
16273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
16283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <ul>
16293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #width} = {@link #WRAP_CONTENT}</li>
16303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #height} = {@link #WRAP_CONTENT}</li>
16313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #topMargin} = 0 when
16323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
16337fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
16343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
16353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #leftMargin} = 0 when
16363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
16377fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
16383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
16393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #bottomMargin} = 0 when
16403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
16417fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
16423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
16433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #rightMargin} = 0 when
16443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
16457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
16463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
1647f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
1648f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
1649f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
1650f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
1651f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
1652f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li>
16533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * </ul>
16543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
1655f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * See {@link GridLayout} for a more complete description of the conventions
1656f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * used by GridLayout in the interpretation of the properties of this class.
1657f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
16583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_row
16593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
16603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_column
16613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
16623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
16633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
16643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static class LayoutParams extends MarginLayoutParams {
16653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
16663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Default values
16673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
16683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_WIDTH = WRAP_CONTENT;
16693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_HEIGHT = WRAP_CONTENT;
16703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_MARGIN = UNDEFINED;
16713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_ROW = UNDEFINED;
16723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_COLUMN = UNDEFINED;
1673f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne        private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1);
16743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size();
16753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
16763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // TypedArray indices
16773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1678b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin;
1679b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft;
1680b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop;
1681b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int RIGHT_MARGIN =
1682b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                R.styleable.ViewGroup_MarginLayout_layout_marginRight;
16833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int BOTTOM_MARGIN =
1684b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
16853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1686b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
1687b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
16885d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
1689b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
1690b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
16915d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
1692b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
16933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
16943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Instance variables
16953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
16963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
1697f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne         * The spec that defines the vertical characteristics of the cell group
16983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * described by these layout parameters.
16993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
1700f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public Spec rowSpec = Spec.UNDEFINED;
1701f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
17023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
1703f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne         * The spec that defines the horizontal characteristics of the cell group
17043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * described by these layout parameters.
17053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
1706f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public Spec columnSpec = Spec.UNDEFINED;
17073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Constructors
17093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private LayoutParams(
17113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int width, int height,
17123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int left, int top, int right, int bottom,
171393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec rowSpec, Spec columnSpec) {
17143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(width, height);
17153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setMargins(left, top, right, bottom);
171693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            this.rowSpec = rowSpec;
171793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            this.columnSpec = columnSpec;
17183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
172193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * Constructs a new LayoutParams instance for this <code>rowSpec</code>
172293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * and <code>columnSpec</code>. All other fields are initialized with
17233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * default values as defined in {@link LayoutParams}.
17243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
172593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param rowSpec    the rowSpec
172693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param columnSpec the columnSpec
17273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
172893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        public LayoutParams(Spec rowSpec, Spec columnSpec) {
17293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
17303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
173193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                    rowSpec, columnSpec);
17323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
17353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
17363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
17373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams() {
1738f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this(Spec.UNDEFINED, Spec.UNDEFINED);
17393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Copying constructors
17423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
17443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
17453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
17463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(ViewGroup.LayoutParams params) {
17473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(params);
17483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
17513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
17523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
17533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(MarginLayoutParams params) {
17543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(params);
17553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
17583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
17593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
17603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(LayoutParams that) {
17613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(that);
1762f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.rowSpec = that.rowSpec;
1763f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.columnSpec = that.columnSpec;
17643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // AttributeSet constructors
17673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
17693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
17703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
17713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Values not defined in the attribute set take the default values
17723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * defined in {@link LayoutParams}.
17733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
17743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(Context context, AttributeSet attrs) {
17755125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            super(context, attrs);
17765125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            reInitSuper(context, attrs);
17775125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            init(context, attrs);
17783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Implementation
17813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Reinitialise the margins using a different default policy than MarginLayoutParams.
17833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state
17843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // so that a layout manager default can be accessed post set up. We need this as, at the
17853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // point of installation, we do not know how many rows/cols there are and therefore
17863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // which elements are positioned next to the container's trailing edges. We need to
17873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // know this as margins around the container's boundary should have different
17883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // defaults to those between peers.
17893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // This method could be parametrized and moved into MarginLayout.
17913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private void reInitSuper(Context context, AttributeSet attrs) {
1792b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne            TypedArray a =
1793b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                    context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
17943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            try {
17953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
17963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin);
17983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin);
17993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin);
18003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin);
18013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            } finally {
18023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                a.recycle();
18033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
18043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18065125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        private void init(Context context, AttributeSet attrs) {
1807b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
18083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            try {
18095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY);
18103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18111e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int column = a.getInt(COLUMN, DEFAULT_COLUMN);
18125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
1813899d5922870c78e0e663bc5661849eb468afc984Philip Milne                this.columnSpec = spec(column, colSpan, getAlignment(gravity, true));
18143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18151e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int row = a.getInt(ROW, DEFAULT_ROW);
18161e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
1817899d5922870c78e0e663bc5661849eb468afc984Philip Milne                this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false));
18183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            } finally {
18193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                a.recycle();
18203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
18213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
18247fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}.
18257fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * See {@link android.view.Gravity}.
18263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
18277fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * @param gravity the new gravity value
18283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
18293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
18303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
18313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setGravity(int gravity) {
18325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false));
18335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true));
18343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
18373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) {
18383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH);
18393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
18403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1842f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final void setRowSpecSpan(Interval span) {
184393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            rowSpec = rowSpec.copyWriteSpan(span);
18443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1846f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final void setColumnSpecSpan(Interval span) {
184793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            columnSpec = columnSpec.copyWriteSpan(span);
18483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
18503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1851aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1852aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs.
1853aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles.
1854aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
1855f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Arc {
18563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final Interval span;
1857aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public final MutableInt value;
185848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean valid = true;
18593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1860aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public Arc(Interval span, MutableInt value) {
18613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.span = span;
18623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.value = value;
18633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
18663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
186748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return span + " " + (!valid ? "+>" : "->") + " " + value;
18683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
18703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // A mutable Integer - used to avoid heap allocation during the layout operation
18723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1873f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class MutableInt {
18743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int value;
18753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1876f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public MutableInt() {
18773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            reset();
18783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1880f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public MutableInt(int value) {
18813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.value = value;
18823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1884f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void reset() {
18853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            value = Integer.MIN_VALUE;
18863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
188748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
188848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        @Override
188948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public String toString() {
189048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return Integer.toString(value);
189148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
189248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
189348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1894f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
189548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private final Class<K> keyType;
189648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private final Class<V> valueType;
189748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
189848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Assoc(Class<K> keyType, Class<V> valueType) {
189948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            this.keyType = keyType;
190048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            this.valueType = valueType;
190148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
190248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1903f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
190448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new Assoc<K, V>(keyType, valueType);
190548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
190648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
190748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public void put(K key, V value) {
190848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            add(Pair.create(key, value));
190948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
191048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
191148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        @SuppressWarnings(value = "unchecked")
191248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public PackedMap<K, V> pack() {
191348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = size();
191448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            K[] keys = (K[]) Array.newInstance(keyType, N);
191548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            V[] values = (V[]) Array.newInstance(valueType, N);
191648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0; i < N; i++) {
191748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                keys[i] = get(i).first;
191848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                values[i] = get(i).second;
191948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
192048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new PackedMap<K, V>(keys, values);
192148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
19223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
19233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1924aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1925aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    This data structure is used in place of a Map where we have an index that refers to the order
1926aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    in which each key/value pairs were added to the map. In this case we store keys and values
1927aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    in arrays of a length that is equal to the number of unique keys. We also maintain an
1928aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    array of indexes from insertion order to the compacted arrays of keys and values.
1929aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1930aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    Note that behavior differs from that of a LinkedHashMap in that repeated entries
1931aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    *do* get added multiples times. So the length of index is equals to the number of
1932aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    items added.
1933aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1934aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    This is useful in the GridLayout class where we can rely on the order of children not
1935aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    changing during layout - to use integer-based lookup for our internal structures
1936aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    rather than using (and storing) an implementation of Map<Key, ?>.
1937aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
19383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @SuppressWarnings(value = "unchecked")
1939f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class PackedMap<K, V> {
19403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int[] index;
19413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final K[] keys;
19423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final V[] values;
19433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private PackedMap(K[] keys, V[] values) {
19453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.index = createIndex(keys);
19463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1947aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            this.keys = compact(keys, index);
1948aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            this.values = compact(values, index);
19493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1951f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public V getValue(int i) {
19523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return values[index[i]];
19533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static <K> int[] createIndex(K[] keys) {
19563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int size = keys.length;
19573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int[] result = new int[size];
19583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Map<K, Integer> keyToIndex = new HashMap<K, Integer>();
19603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < size; i++) {
19613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                K key = keys[i];
19623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                Integer index = keyToIndex.get(key);
19633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                if (index == null) {
19643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    index = keyToIndex.size();
19653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    keyToIndex.put(key, index);
19663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
19673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i] = index;
19683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
19693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
19703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1972aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        /*
1973aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Create a compact array of keys or values using the supplied index.
1974aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne         */
1975aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private static <K> K[] compact(K[] a, int[] index) {
1976aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int size = a.length;
1977aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            Class<?> componentType = a.getClass().getComponentType();
197851f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1);
19793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // this overwrite duplicates, retaining the last equivalent entry
19813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < size; i++) {
1982aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                result[index[i]] = a[i];
19833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
19843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
19853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
19873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1988aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
198993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    For each group (with a given alignment) we need to store the amount of space required
19907fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne    before the alignment point and the amount of space required after it. One side of this
1991aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
1992aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
1993aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    simple optimisations are possible.
1994aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1995aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    The general algorithm therefore is to create a Map (actually a PackedMap) from
199693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    group to Bounds and to loop through all Views in the group taking the maximum
1997aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    of the values for each View.
1998aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    */
1999f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static class Bounds {
20007fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne        public int before;
20017fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne        public int after;
20025125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        public int flexibility; // we're flexible iff all included specs are flexible
20033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private Bounds() {
20053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            reset();
20063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2008a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        protected void reset() {
20097fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            before = Integer.MIN_VALUE;
20107fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            after = Integer.MIN_VALUE;
20115125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            flexibility = CAN_STRETCH; // from the above, we're flexible when empty
20123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2014a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        protected void include(int before, int after) {
20157fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            this.before = max(this.before, before);
20167fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            this.after = max(this.after, after);
20173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
201948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        protected int size(boolean min) {
20205d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            if (!min) {
20215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                if (canStretch(flexibility)) {
20225d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne                    return MAX_SIZE;
20235d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne                }
202448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
20257fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            return before + after;
20263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
202848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        protected int getOffset(View c, Alignment alignment, int size) {
202948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return before - alignment.getAlignmentValue(c, size);
203048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
203148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
20325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
20335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            this.flexibility &= spec.getFlexibility();
203448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
20355125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
20364c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // todo test this works correctly when the returned value is UNDEFINED
20375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            int before = alignment.getAlignmentValue(c, size);
203848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(before, size - before);
2039a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2040a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
20413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
20423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
20433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return "Bounds{" +
20447fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne                    "before=" + before +
20457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne                    ", after=" + after +
20463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    '}';
20473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
20493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
20513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * An Interval represents a contiguous range of values that lie between
20523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * the interval's {@link #min} and {@link #max} values.
20533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
20543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Intervals are immutable so may be passed as values and used as keys in hash tables.
20553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * It is not necessary to have multiple instances of Intervals which have the same
20563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * {@link #min} and {@link #max} values.
20573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
20587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * Intervals are often written as {@code [min, max]} and represent the set of values
20597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * {@code x} such that {@code min <= x < max}.
20603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2061f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Interval {
20623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * The minimum value.
20643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
20653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int min;
2066aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
20673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * The maximum value.
20693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
20703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int max;
20713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20737fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Construct a new Interval, {@code interval}, where:
20743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * <ul>
20757fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *     <li> {@code interval.min = min} </li>
20767fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *     <li> {@code interval.max = max} </li>
20773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * </ul>
20783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
20793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @param min the minimum value.
20803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @param max the maximum value.
20813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
20823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public Interval(int min, int max) {
20833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.min = min;
20843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.max = max;
20853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2087f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int size() {
20883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return max - min;
20893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2091f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Interval inverse() {
20923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return new Interval(max, min);
20933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20967fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Returns {@code true} if the {@link #getClass class},
20977fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * {@link #min} and {@link #max} properties of this Interval and the
20987fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * supplied parameter are pairwise equal; {@code false} otherwise.
20993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
21007fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * @param that the object to compare this interval with
21013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
21023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @return {@code true} if the specified object is equal to this
21037fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *         {@code Interval}, {@code false} otherwise.
21043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
21053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
21063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean equals(Object that) {
21073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (this == that) {
21083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
21093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (that == null || getClass() != that.getClass()) {
21113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
21123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Interval interval = (Interval) that;
21153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (max != interval.max) {
21173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
21183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21194c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection RedundantIfStatement
21203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (min != interval.min) {
21213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
21223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return true;
21253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
21283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int hashCode() {
21293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int result = min;
21303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            result = 31 * result + max;
21313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
21323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
21353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
21363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return "[" + min + ", " + max + "]";
21373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
21393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2140899d5922870c78e0e663bc5661849eb468afc984Philip Milne    /**
2141899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * A Spec defines the horizontal or vertical characteristics of a group of
2142899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * cells. Each spec. defines the <em>grid indices</em>, <em>alignment</em> and
2143899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <em>flexibility</em> along the appropriate axis.
2144899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <p>
2145899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The <em>grid indices</em> are the leading and trailing edges of this cell group.
2146899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * See {@link GridLayout} for a description of the conventions used by GridLayout
2147899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * for grid indices.
2148899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <p>
2149899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The <em>alignment</em> property specifies how cells should be aligned in this group.
2150899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * For row groups, this specifies the vertical alignment.
2151899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * For column groups, this specifies the horizontal alignment.
2152899d5922870c78e0e663bc5661849eb468afc984Philip Milne     */
215393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static class Spec {
2154f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
2155f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
2156f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final boolean startDefined;
215748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        final Interval span;
215893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        final Alignment alignment;
21593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2160f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private Spec(boolean startDefined, Interval span, Alignment alignment) {
2161f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.startDefined = startDefined;
21625d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            this.span = span;
21635d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            this.alignment = alignment;
21645d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne        }
21655d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
2166f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private Spec(boolean startDefined, int start, int size, Alignment alignment) {
2167f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this(startDefined, new Interval(start, start + size), alignment);
21683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2170f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Spec copyWriteSpan(Interval span) {
2171f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return new Spec(startDefined, span, alignment);
21723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2174f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Spec copyWriteAlignment(Alignment alignment) {
2175f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return new Spec(startDefined, span, alignment);
21765125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
21775125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
2178f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final int getFlexibility() {
21794c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
21803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
218393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
218493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * properties of this Spec and the supplied parameter are pairwise equal,
21857fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * {@code false} otherwise.
21863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
218793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param that the object to compare this spec with
21883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
21893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @return {@code true} if the specified object is equal to this
219093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         *         {@code Spec}; {@code false} otherwise
21913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
21923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
21933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean equals(Object that) {
21943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (this == that) {
21953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
21963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (that == null || getClass() != that.getClass()) {
21983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
21993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
22003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
220193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec spec = (Spec) that;
22023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
220393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            if (!alignment.equals(spec.alignment)) {
22043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
22053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
22064c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection RedundantIfStatement
220793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            if (!span.equals(spec.span)) {
22083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
22093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
22103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return true;
22123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
22153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int hashCode() {
22163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int result = span.hashCode();
22173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            result = 31 * result + alignment.hashCode();
22183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
22193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
22213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
222393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * Return a Spec, {@code spec}, where:
222493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * <ul>
222593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.span = [start, start + size]} </li>
222693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.alignment = alignment} </li>
222793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * </ul>
222893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *
222993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param start     the start
223093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param size      the size
223193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param alignment the alignment
223293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     */
223393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static Spec spec(int start, int size, Alignment alignment) {
2234f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return new Spec(start != UNDEFINED, start, size, alignment);
223593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    }
223693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne
223793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    /**
223893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * Return a Spec, {@code spec}, where:
223993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * <ul>
224093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.span = [start, start + 1]} </li>
224193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.alignment = alignment} </li>
224293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * </ul>
224393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *
224493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param start     the start index
224593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param alignment the alignment
224693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     */
224793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static Spec spec(int start, Alignment alignment) {
224893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        return spec(start, 1, alignment);
224993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    }
225093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne
225193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    /**
22525125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * Return a Spec, {@code spec}, where:
22535125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * <ul>
22545125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *     <li> {@code spec.span = [start, start + size]} </li>
22555125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * </ul>
22565125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *
22575125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param start     the start
22585125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param size      the size
22595125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     */
22605125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    public static Spec spec(int start, int size) {
22615125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return spec(start, size, UNDEFINED_ALIGNMENT);
22625125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
22635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
22645125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    /**
22655125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * Return a Spec, {@code spec}, where:
22665125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * <ul>
22675125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *     <li> {@code spec.span = [start, start + 1]} </li>
22685125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * </ul>
22695125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *
22705125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param start     the start index
22715125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     */
22725125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    public static Spec spec(int start) {
22735125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return spec(start, 1);
22745125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
22755125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
22765125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    /**
22773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Alignments specify where a view should be placed within a cell group and
22783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * what size it should be.
22793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
228093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
228193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
228293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * {@code alignment}. Overall placement of the view in the cell
22833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * group is specified by the two alignments which act along each axis independently.
22843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
2285a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     *  The GridLayout class defines the most common alignments used in general layout:
2286a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link
2287a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     * #BASELINE} and {@link #FILL}.
2288a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     */
2289a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne    /*
2290c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne     * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
22913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * to return the appropriate value for the type of alignment being defined.
22923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The enclosing algorithms position the children
22931e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * so that the locations defined by the alignment values
22943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * are the same for all of the views in a group.
22953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
22963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2297c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static abstract class Alignment {
229848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        Alignment() {
2299a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2300a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
23013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
23023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Returns an alignment value. In the case of vertical alignments the value
23033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * returned should indicate the distance from the top of the view to the
23043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * alignment location.
23053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * For horizontal alignments measurement is made from the left edge of the component.
23063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
2307c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param view              the view to which this alignment should be applied
2308c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param viewSize          the measured size of the view
2309b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne         * @return the alignment value
23103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
231148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        abstract int getAlignmentValue(View view, int viewSize);
23123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
23143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Returns the size of the view specified by this alignment.
23153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * In the case of vertical alignments this method should return a height; for
23163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * horizontal alignments this method should return the width.
2317c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * <p>
2318c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * The default implementation returns {@code viewSize}.
2319c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         *
2320c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param view              the view to which this alignment should be applied
2321c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param viewSize          the measured size of the view
2322c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param cellSize          the size of the cell into which this view will be placed
232309e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne         * @param measurementType   This parameter is currently unused as GridLayout only supports
232409e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne         *                          one type of measurement: {@link View#measure(int, int)}.
23253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
2326b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne         * @return the aligned size
23273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
232848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
23293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize;
23303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2331a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
233248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        Bounds getBounds() {
2333a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return new Bounds();
2334a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
23353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
23363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2337f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
23385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        public int getAlignmentValue(View view, int viewSize) {
23395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            return UNDEFINED;
23405125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
23415125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    };
23425125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
2343c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    private static final Alignment LEADING = new Alignment() {
234448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public int getAlignmentValue(View view, int viewSize) {
23453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return 0;
23463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
23483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2349c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    private static final Alignment TRAILING = new Alignment() {
235048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public int getAlignmentValue(View view, int viewSize) {
23513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize;
23523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
23543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
23563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>top</em>
23573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
23583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
23593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment TOP = LEADING;
23603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
23623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>bottom</em>
23633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
23643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
23653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment BOTTOM = TRAILING;
23663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
23683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>right</em>
23693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
23703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
23713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment RIGHT = TRAILING;
23723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
23743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>left</em>
23753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
23763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
23773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment LEFT = LEADING;
23783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
23803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be <em>centered</em> with the other views in its cell group.
238193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
238293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * LayoutParams#columnSpec columnSpecs}.
23833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2384c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static final Alignment CENTER = new Alignment() {
238548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public int getAlignmentValue(View view, int viewSize) {
23863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize >> 1;
23873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
23893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
23913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>baselines</em>
23923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * of the other views in its cell group.
239393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
23943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
23953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see View#getBaseline()
23963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2397c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static final Alignment BASELINE = new Alignment() {
239848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public int getAlignmentValue(View view, int viewSize) {
23993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (view == null) {
24003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return UNDEFINED;
24013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int baseline = view.getBaseline();
2403a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return (baseline == -1) ? UNDEFINED : baseline;
2404a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2405a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2406a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        @Override
2407a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        public Bounds getBounds() {
2408a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return new Bounds() {
2409a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                /*
2410a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                In a baseline aligned row in which some components define a baseline
2411a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                and some don't, we need a third variable to properly account for all
2412a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                the sizes. This tracks the maximum size of all the components -
2413a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                including those that don't define a baseline.
2414a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                */
2415a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                private int size;
2416a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2417a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
2418a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                protected void reset() {
2419a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    super.reset();
242048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    size = Integer.MIN_VALUE;
2421a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2422a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2423a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
2424a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                protected void include(int before, int after) {
2425a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    super.include(before, after);
2426a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    size = max(size, before + after);
2427a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2428a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2429a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
243048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                protected int size(boolean min) {
243148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return max(super.size(min), size);
2432a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2433a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2434a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
243548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                protected int getOffset(View c, Alignment alignment, int size) {
243648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return max(0, super.getOffset(c, alignment, size));
2437a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2438a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            };
24393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
24413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
24433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should expanded to fit the boundaries of its cell group.
244493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
244593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * {@link LayoutParams#columnSpec columnSpecs}.
24463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
24473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment FILL = new Alignment() {
244848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public int getAlignmentValue(View view, int viewSize) {
24493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return UNDEFINED;
24503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2452c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne        @Override
2453c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne        public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
24543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return cellSize;
24553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
245748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2458f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static boolean canStretch(int flexibility) {
24595d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne        return (flexibility & CAN_STRETCH) != 0;
24605d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne    }
24615d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
24625125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    private static final int INFLEXIBLE = 0;
246348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
24644c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    private static final int CAN_STRETCH = 2;
2465452eec33d667f9e705b57e60948b070536fbc1b4Jim Miller}
2466