diff --git a/api/current.txt b/api/current.txt index 2f5b9b428072d..fdef20fc5ad41 100644 --- a/api/current.txt +++ b/api/current.txt @@ -301,7 +301,9 @@ package android { field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab field public static final int colorForeground = 16842800; // 0x1010030 field public static final int colorForegroundInverse = 16843270; // 0x1010206 + field public static final int columnCount = 16843633; // 0x1010371 field public static final int columnDelay = 16843215; // 0x10101cf + field public static final int columnOrderPreserved = 16843634; // 0x1010372 field public static final int columnWidth = 16843031; // 0x1010117 field public static final int completionHint = 16843122; // 0x1010172 field public static final int completionHintView = 16843123; // 0x1010173 @@ -575,6 +577,8 @@ package android { field public static final int layout_centerInParent = 16843151; // 0x101018f field public static final int layout_centerVertical = 16843153; // 0x1010191 field public static final int layout_column = 16843084; // 0x101014c + field public static final int layout_columnSpan = 16843639; // 0x1010377 + field public static final int layout_columnWeight = 16843640; // 0x1010378 field public static final int layout_gravity = 16842931; // 0x10100b3 field public static final int layout_height = 16842997; // 0x10100f5 field public static final int layout_margin = 16842998; // 0x10100f6 @@ -582,6 +586,9 @@ package android { field public static final int layout_marginLeft = 16842999; // 0x10100f7 field public static final int layout_marginRight = 16843001; // 0x10100f9 field public static final int layout_marginTop = 16843000; // 0x10100f8 + field public static final int layout_row = 16843636; // 0x1010374 + field public static final int layout_rowSpan = 16843637; // 0x1010375 + field public static final int layout_rowWeight = 16843638; // 0x1010376 field public static final int layout_scale = 16843155; // 0x1010193 field public static final int layout_span = 16843085; // 0x101014d field public static final int layout_toLeftOf = 16843138; // 0x1010182 @@ -751,9 +758,11 @@ package android { field public static final int rotation = 16843558; // 0x1010326 field public static final int rotationX = 16843559; // 0x1010327 field public static final int rotationY = 16843560; // 0x1010328 + field public static final int rowCount = 16843631; // 0x101036f field public static final int rowDelay = 16843216; // 0x10101d0 field public static final int rowEdgeFlags = 16843329; // 0x1010241 field public static final int rowHeight = 16843058; // 0x1010132 + field public static final int rowOrderPreserved = 16843632; // 0x1010370 field public static final int saveEnabled = 16842983; // 0x10100e7 field public static final int scaleGravity = 16843262; // 0x10101fe field public static final int scaleHeight = 16843261; // 0x10101fd @@ -984,6 +993,7 @@ package android { field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344 field public static final int unselectedAlpha = 16843278; // 0x101020e field public static final int updatePeriodMillis = 16843344; // 0x1010250 + field public static final int useDefaultMargins = 16843635; // 0x1010373 field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310 field public static final int useLevel = 16843167; // 0x101019f field public static final int userVisible = 16843409; // 0x1010291 @@ -24167,6 +24177,67 @@ package android.widget { ctor public Gallery.LayoutParams(android.view.ViewGroup.LayoutParams); } + public class GridLayout extends android.view.ViewGroup { + ctor public GridLayout(android.content.Context); + ctor public GridLayout(android.content.Context, android.util.AttributeSet, int); + ctor public GridLayout(android.content.Context, android.util.AttributeSet); + method public int getColumnCount(); + method public int getOrientation(); + method public int getRowCount(); + method public boolean getUseDefaultMargins(); + method public boolean isColumnOrderPreserved(); + method public boolean isRowOrderPreserved(); + method protected void onLayout(boolean, int, int, int, int); + method public void setColumnCount(int); + method public void setColumnOrderPreserved(boolean); + method public void setOrientation(int); + method public void setRowCount(int); + method public void setRowOrderPreserved(boolean); + method public void setUseDefaultMargins(boolean); + field public static final android.widget.GridLayout.Alignment BASELINE; + field public static final android.widget.GridLayout.Alignment BOTTOM; + field public static final android.widget.GridLayout.Alignment CENTER; + field public static final android.widget.GridLayout.Alignment FILL; + field public static final int HORIZONTAL = 0; // 0x0 + field public static final android.widget.GridLayout.Alignment LEFT; + field public static final android.widget.GridLayout.Alignment RIGHT; + field public static final android.widget.GridLayout.Alignment TOP; + field public static final int VERTICAL = 1; // 0x1 + } + + public static abstract interface GridLayout.Alignment { + method public abstract int getAlignmentValue(android.view.View, int); + method public abstract int getSizeInCell(android.view.View, int, int); + } + + public static class GridLayout.Group { + ctor public GridLayout.Group(android.widget.GridLayout.Interval, android.widget.GridLayout.Alignment); + ctor public GridLayout.Group(int, int, android.widget.GridLayout.Alignment); + ctor public GridLayout.Group(int, android.widget.GridLayout.Alignment); + field public final android.widget.GridLayout.Alignment alignment; + field public final android.widget.GridLayout.Interval span; + } + + public static class GridLayout.Interval { + ctor public GridLayout.Interval(int, int); + field public final int max; + field public final int min; + } + + public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams { + ctor public GridLayout.LayoutParams(android.widget.GridLayout.Group, android.widget.GridLayout.Group); + ctor public GridLayout.LayoutParams(); + ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams); + ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams); + ctor public GridLayout.LayoutParams(android.widget.GridLayout.LayoutParams); + ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet); + method public void setGravity(int); + field public android.widget.GridLayout.Group columnGroup; + field public float columnWeight; + field public android.widget.GridLayout.Group rowGroup; + field public float rowWeight; + } + public class GridView extends android.widget.AbsListView { ctor public GridView(android.content.Context); ctor public GridView(android.content.Context, android.util.AttributeSet); @@ -25049,6 +25120,12 @@ package android.widget { method public abstract void onScrollStarted(); } + public final class Space extends android.view.View { + ctor public Space(android.content.Context, android.util.AttributeSet, int); + ctor public Space(android.content.Context, android.util.AttributeSet); + ctor public Space(android.content.Context); + } + public class Spinner extends android.widget.AbsSpinner implements android.content.DialogInterface.OnClickListener { ctor public Spinner(android.content.Context); ctor public Spinner(android.content.Context, int); diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java new file mode 100644 index 0000000000000..488910152cef1 --- /dev/null +++ b/core/java/android/widget/GridLayout.java @@ -0,0 +1,2036 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import com.android.internal.R.styleable; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +/** + * A layout that places its children in a rectangular grid. + *
+ * The grid is composed of a set of infinitely thin lines that separate the
+ * viewing area into cells. Throughout the API, grid lines are referenced
+ * by grid indices. A grid that has N columns
+ * has N + 1 grid indices that run from 0
+ * through N inclusive. Regardless of how GridLayout is
+ * configured, grid index 0 is fixed to the leading edge of the
+ * container and grid index N is fixed to its trailing edge
+ * (after padding is taken into account).
+ *
+ *
+ *
+ * See {@link GridLayout.LayoutParams} for a full description of the + * layout parameters used by GridLayout. + * + * @attr ref android.R.styleable#GridLayout_orientation + * @attr ref android.R.styleable#GridLayout_rowCount + * @attr ref android.R.styleable#GridLayout_columnCount + * @attr ref android.R.styleable#GridLayout_useDefaultMargins + * @attr ref android.R.styleable#GridLayout_rowOrderPreserved + * @attr ref android.R.styleable#GridLayout_columnOrderPreserved + */ +public class GridLayout extends ViewGroup { + + // Public constants + + /** + * The horizontal orientation. + */ + public static final int HORIZONTAL = LinearLayout.HORIZONTAL; + /** + * The vertical orientation. + */ + public static final int VERTICAL = LinearLayout.VERTICAL; + + // Misc constants + + private static final String TAG = GridLayout.class.getName(); + private static final boolean DEBUG = false; + private static final int UNDEFINED = Integer.MIN_VALUE; + private static final Paint GRID_PAINT = new Paint(); + private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2; + private static final int MIN = 0; + private static final int PRF = 1; + private static final int MAX = 2; + + // Defaults + + private static final int DEFAULT_ORIENTATION = HORIZONTAL; + private static final int DEFAULT_COUNT = UNDEFINED; + private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false; + private static final boolean DEFAULT_ORDER_PRESERVED = false; + + // TypedArray indices + + private static final int ORIENTATION = styleable.GridLayout_orientation; + private static final int ROW_COUNT = styleable.GridLayout_rowCount; + private static final int COLUMN_COUNT = styleable.GridLayout_columnCount; + private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins; + private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved; + private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved; + + // Instance variables + + private final Axis mHorizontalAxis = new Axis(true); + private final Axis mVerticalAxis = new Axis(false); + private boolean mLayoutParamsValid = false; + private int mOrientation = DEFAULT_ORIENTATION; + private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; + private int mDefaultGravity = Gravity.NO_GRAVITY; + boolean maximizing = false; + boolean accommodateBothMinAndMax = false; + + // Constructors + + /** + * {@inheritDoc} + */ + public GridLayout(Context context) { + super(context); + if (DEBUG) { + setWillNotDraw(false); + } + } + + /** + * {@inheritDoc} + */ + public GridLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + processAttributes(context, attrs); + } + + /** + * {@inheritDoc} + */ + public GridLayout(Context context, AttributeSet attrs) { + super(context, attrs); + processAttributes(context, attrs); + } + + private void processAttributes(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout); + try { + setRowCount(a.getInteger(ROW_COUNT, DEFAULT_COUNT)); + setColumnCount(a.getInteger(COLUMN_COUNT, DEFAULT_COUNT)); + mOrientation = a.getInteger(ORIENTATION, DEFAULT_ORIENTATION); + mUseDefaultMargins = a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS); + setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); + setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); + } finally { + a.recycle(); + } + } + + // Implementation + + /** + * Returns the current orientation. + * + * @return either {@link #HORIZONTAL} or {@link #VERTICAL}. The default + * is {@link #HORIZONTAL}. + * + * @see #setOrientation(int) + * + * @attr ref android.R.styleable#GridLayout_orientation + */ + public int getOrientation() { + return mOrientation; + } + + /** + * The orientation property does not affect layout. Orientation is used + * only to generate default row/column indices when they are not specified + * by a component's layout parameters. + * + * @param orientation the orientation, either {@link #HORIZONTAL} or {@link #VERTICAL}. + * + * @see #getOrientation() + * + * @attr ref android.R.styleable#GridLayout_orientation + */ + public void setOrientation(int orientation) { + if (mOrientation != orientation) { + mOrientation = orientation; + requestLayout(); + } + } + + /** + * Returns the current number of rows. This is either the last value that was set + * with {@link #setRowCount(int)} or, if no such value was set, the maximum + * value of each the upper bounds defined in {@link LayoutParams#rowGroup}. + * + * @return the current number of rows + * + * @see #setRowCount(int) + * @see LayoutParams#rowGroup + * + * @attr ref android.R.styleable#GridLayout_rowCount + */ + public int getRowCount() { + return mVerticalAxis.getCount(); + } + + /** + * The rowCount property does not affect layout. RowCount is used + * only to generate default row/column indices when they are not specified + * by a component's layout parameters. + * + * @param rowCount the number of rows. + * + * @see #getRowCount() + * @see LayoutParams#rowGroup + * + * @attr ref android.R.styleable#GridLayout_rowCount + */ + public void setRowCount(int rowCount) { + mVerticalAxis.setCount(rowCount); + } + + /** + * Returns the current number of columns. This is either the last value that was set + * with {@link #setColumnCount(int)} or, if no such value was set, the maximum + * value of each the upper bounds defined in {@link LayoutParams#columnGroup}. + * + * @return the current number of columns + * + * @see #setColumnCount(int) + * @see LayoutParams#columnGroup + * + * @attr ref android.R.styleable#GridLayout_columnCount + */ + public int getColumnCount() { + return mHorizontalAxis.getCount(); + } + + /** + * The columnCount property does not affect layout. ColumnCount is used + * only to generate default column/column indices when they are not specified + * by a component's layout parameters. + * + * @param columnCount the number of columns. + * + * @see #getColumnCount() + * @see LayoutParams#columnGroup + * + * @attr ref android.R.styleable#GridLayout_columnCount + */ + public void setColumnCount(int columnCount) { + mHorizontalAxis.setCount(columnCount); + } + + /** + * Returns whether or not this GridLayout will allocate default margins when no + * corresponding layout parameters are defined. + * + * @return true if default margins should be allocated. + * + * @see #setUseDefaultMargins(boolean) + * + * @attr ref android.R.styleable#GridLayout_useDefaultMargins + */ + public boolean getUseDefaultMargins() { + return mUseDefaultMargins; + } + + /** + * When true, GridLayout allocates default margins around children + * based on the child's visual characteristics. Each of the + * margins so defined may be independently overridden by an assignment + * to the appropriate layout parameter. + *
+ * When false, the default value of all margins is zero.
+ *
+ * @param useDefaultMargins use true to make GridLayout allocate default margins
+ *
+ * @see #getUseDefaultMargins()
+ *
+ * @see MarginLayoutParams#leftMargin
+ * @see MarginLayoutParams#topMargin
+ * @see MarginLayoutParams#rightMargin
+ * @see MarginLayoutParams#bottomMargin
+ *
+ * @attr ref android.R.styleable#GridLayout_useDefaultMargins
+ */
+ public void setUseDefaultMargins(boolean useDefaultMargins) {
+ mUseDefaultMargins = useDefaultMargins;
+ }
+
+ /**
+ * Returns whether or not row boundaries are ordered by their grid indices.
+ *
+ * @return true if row boundaries must appear in the order of their indices, false otherwise.
+ * The default is false.
+ *
+ * @see #setRowOrderPreserved(boolean)
+ *
+ * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
+ */
+ public boolean isRowOrderPreserved() {
+ return mVerticalAxis.isOrderPreserved();
+ }
+
+ /**
+ * When this property is false, the default state, GridLayout
+ * is at liberty to choose an order that better suits the heights of its children.
+
+ * When this property is true, GridLayout is forced to place row boundaries
+ * (the {@link Interval#min min} and {@link Interval#max max} values of
+ * a {@link LayoutParams#rowGroup rowGroup}'s {@link Group#span span})
+ * so that they appear in ascending order in the view.
+ *
+ * GridLayout implements this specification by creating ordering constraints between
+ * the variables that represent the locations of the row boundaries.
+ *
+ * When this property is true, constraints are added for each pair of consecutive
+ * indices: i.e. between row boundaries: [0..1], [1..2], [3..4],... etc.
+ *
+ * When the property is false, the ordering constraints are placed
+ * only between boundaries that separate opposing edges of the layout's children.
+ *
+ * @param rowOrderPreserved use true to force GridLayout to respect the order
+ * of row boundaries.
+ *
+ * @see #isRowOrderPreserved()
+ *
+ * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
+ */
+ public void setRowOrderPreserved(boolean rowOrderPreserved) {
+ mVerticalAxis.setOrderPreserved(rowOrderPreserved);
+ }
+
+ /**
+ * Returns whether or not column boundaries are ordered by their grid indices.
+ *
+ * @return true if column boundaries must appear in the order of their indices, false otherwise.
+ * The default is false.
+ *
+ * @see #setColumnOrderPreserved(boolean)
+ *
+ * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
+ */
+ public boolean isColumnOrderPreserved() {
+ return mHorizontalAxis.isOrderPreserved();
+ }
+
+ /**
+ * When this property is false, the default state, GridLayout
+ * is at liberty to choose an order that better suits the widths of its children.
+
+ * When this property is true, GridLayout is forced to place column boundaries
+ * (the {@link Interval#min min} and {@link Interval#max max} values of
+ * a {@link LayoutParams#columnGroup columnGroup}'s {@link Group#span span})
+ * so that they appear in ascending order in the view.
+ *
+ * GridLayout implements this specification by creating ordering constraints between
+ * the variables that represent the locations of the column boundaries.
+ *
+ * When this property is
+ * GridLayout supports both row and column spanning and arbitrary forms of alignment within
+ * each cell group. The fundamental parameters associated with each cell group are
+ * gathered into their vertical and horizontal components and stored
+ * in the {@link #rowGroup} and {@link #columnGroup} layout parameters.
+ * {@link Group Groups} are immutable structures and may be shared between the layout
+ * parameters of different children.
+ *
+ * The {@link Group#span span} fields of the row and column groups together specify
+ * the four grid indices that delimit the cells of this cell group.
+ *
+ * The {@link Group#alignment alignment} fields of the row and column groups together specify
+ * both aspects of alignment within the cell group. It is also possible to specify a child's
+ * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
+ * method.
+ *
+ * See {@link GridLayout} for a description of the conventions used by GridLayout
+ * in reference to grid indices.
+ *
+ *
+ * Intervals are immutable so may be passed as values and used as keys in hash tables.
+ * It is not necessary to have multiple instances of Intervals which have the same
+ * {@link #min} and {@link #max} values.
+ *
+ * Intervals are often written as
+ * Groups are immutable and so may be shared between views with the same
+ *
+ * See {@link GridLayout} for a description of the conventions used by GridLayout
+ * for grid indices.
+ */
+ public final Interval span;
+ /**
+ * Specifies how cells should be aligned in this group.
+ * For row groups, this specifies the vertical alignment.
+ * For column groups, this specifies the horizontal alignment.
+ */
+ public final Alignment alignment;
+
+ /**
+ * Construct a new Group,
+ * The {@link LayoutParams} class contains a {@link LayoutParams#rowGroup rowGroup}
+ * and a {@link LayoutParams#columnGroup columnGroup} each of which contains an
+ * {@link Group#alignment alignment}. Overall placement of the view in the cell
+ * group is specified by the two alignments which act along each axis independently.
+ *
+ * An Alignment implementation must define the {@link #getAlignmentValue(View, int)}
+ * to return the appropriate value for the type of alignment being defined.
+ * The enclosing algorithms position the children
+ * so that the values returned from the alignment
+ * are the same for all of the views in a group.
+ *
+ * The GridLayout class defines the most common alignments used in general layout:
+ * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link
+ * #BASELINE} and {@link #FILL}.
+ */
+ public static interface Alignment {
+ /**
+ * Returns an alignment value. In the case of vertical alignments the value
+ * returned should indicate the distance from the top of the view to the
+ * alignment location.
+ * For horizontal alignments measurement is made from the left edge of the component.
+ *
+ * @param view the view to which this alignment should be applied.
+ * @param viewSize the measured size of the view.
+ * @return the alignment value.
+ */
+ public int getAlignmentValue(View view, int viewSize);
+
+ /**
+ * Returns the size of the view specified by this alignment.
+ * In the case of vertical alignments this method should return a height; for
+ * horizontal alignments this method should return the width.
+ *
+ * @param view the view to which this alignment should be applied.
+ * @param viewSize the measured size of the view.
+ * @param cellSize the size of the cell into which this view will be placed.
+ * @return the aligned size.
+ */
+ public int getSizeInCell(View view, int viewSize, int cellSize);
+ }
+
+ private static abstract class AbstractAlignment implements Alignment {
+ public int getSizeInCell(View view, int viewSize, int cellSize) {
+ return viewSize;
+ }
+ }
+
+ private static final Alignment LEADING = new AbstractAlignment() {
+ public int getAlignmentValue(View view, int viewSize) {
+ return 0;
+ }
+
+ };
+
+ private static final Alignment TRAILING = new AbstractAlignment() {
+ public int getAlignmentValue(View view, int viewSize) {
+ return viewSize;
+ }
+ };
+
+ /**
+ * Indicates that a view should be aligned with the top
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment TOP = LEADING;
+
+ /**
+ * Indicates that a view should be aligned with the bottom
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment BOTTOM = TRAILING;
+
+ /**
+ * Indicates that a view should be aligned with the right
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment RIGHT = TRAILING;
+
+ /**
+ * Indicates that a view should be aligned with the left
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment LEFT = LEADING;
+
+ /**
+ * Indicates that a view should be centered with the other views in its cell group.
+ * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and {@link
+ * LayoutParams#columnGroup columnGroups}.
+ */
+ public static final Alignment CENTER = new AbstractAlignment() {
+ public int getAlignmentValue(View view, int viewSize) {
+ return viewSize >> 1;
+ }
+ };
+
+ /**
+ * Indicates that a view should be aligned with the baselines
+ * of the other views in its cell group.
+ * This constant may only be used as an alignment in {@link LayoutParams#rowGroup rowGroups}.
+ *
+ * @see View#getBaseline()
+ */
+ public static final Alignment BASELINE = new AbstractAlignment() {
+ public int getAlignmentValue(View view, int viewSize) {
+ if (view == null) {
+ return UNDEFINED;
+ }
+ // todo do we need to call measure first?
+ int baseline = view.getBaseline();
+ return baseline == -1 ? UNDEFINED : baseline;
+ }
+
+ };
+
+ /**
+ * Indicates that a view should expanded to fit the boundaries of its cell group.
+ * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and
+ * {@link LayoutParams#columnGroup columnGroups}.
+ */
+ public static final Alignment FILL = new Alignment() {
+ public int getAlignmentValue(View view, int viewSize) {
+ return UNDEFINED;
+ }
+
+ public int getSizeInCell(View view, int viewSize, int cellSize) {
+ return cellSize;
+ }
+ };
+}
\ No newline at end of file
diff --git a/core/java/android/widget/Space.java b/core/java/android/widget/Space.java
new file mode 100644
index 0000000000000..d98b9378f5156
--- /dev/null
+++ b/core/java/android/widget/Space.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Space is a lightweight View subclass that may be used to create gaps between components
+ * in general purpose layouts.
+ */
+public final class Space extends View {
+ /**
+ * {@inheritDoc}
+ */
+ public Space(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Space(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Space(Context context) {
+ super(context);
+ }
+
+ /**
+ * Draw nothing.
+ *
+ * @param canvas an unused parameter.
+ */
+ @Override
+ public void draw(Canvas canvas) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ViewGroup.LayoutParams getLayoutParams() {
+ return super.getLayoutParams();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setLayoutParams(ViewGroup.LayoutParams params) {
+ super.setLayoutParams(params);
+ }
+}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c1e81c3fbe758..f854e9304098a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2429,6 +2429,36 @@
true, constraints are added for each pair of consecutive
+ * indices: i.e. between column boundaries: [0..1], [1..2], [3..4],... etc.
+ *
+ * When the property is false, the ordering constraints are placed
+ * only between boundaries that separate opposing edges of the layout's children.
+ *
+ * @param columnOrderPreserved use true to force GridLayout to respect the order
+ * of column boundaries.
+ *
+ * @see #isColumnOrderPreserved()
+ *
+ * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
+ */
+ public void setColumnOrderPreserved(boolean columnOrderPreserved) {
+ mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
+ }
+
+ private static int compare(int i, int j) {
+ return i < j ? -1 : i > j ? 1 : 0;
+ }
+
+ private static int sum(int[] a) {
+ int result = 0;
+ for (int i = 0, length = a.length; i < length; i++) {
+ result += a[i];
+ }
+ return result;
+ }
+
+ private int getDefaultMargin(View c, boolean leading, boolean horizontal) {
+ // In the absence of any other information, calculate a default gap such
+ // that, in a grid of identical components, the heights and the vertical
+ // gaps are in the proportion of the golden ratio.
+ // To effect this with equal margins at each edge, set each of the
+ // four margin values to half this amount.
+ c.measure(0, 0);
+ return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2);
+ }
+
+ private int getDefaultMargin(View c, boolean isAtEdge, boolean leading, boolean horizontal) {
+ // todo remove 20 - use padding here?
+ return isAtEdge ? 20 : getDefaultMargin(c, leading, horizontal);
+ }
+
+ private int getDefaultMarginValue(View c, LayoutParams p, boolean leading, boolean horizontal) {
+ if (!mUseDefaultMargins) {
+ return 0;
+ }
+ Group group = horizontal ? p.columnGroup : p.rowGroup;
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
+ Interval span = group.span;
+ boolean isAtEdge = leading ? span.min == 0 : span.max == axis.getCount();
+
+ return getDefaultMargin(c, isAtEdge, leading, horizontal);
+ }
+
+ private int getMargin(View view, boolean leading, boolean horizontal) {
+ LayoutParams lp = getLayoutParams(view);
+ int margin = horizontal ?
+ leading ? lp.leftMargin : lp.rightMargin :
+ leading ? lp.topMargin : lp.bottomMargin;
+ return margin == UNDEFINED ? getDefaultMarginValue(view, lp, leading, horizontal) : margin;
+ }
+
+ private static boolean isUndefined(Interval span) {
+ return span.min == UNDEFINED || span.max == UNDEFINED;
+ }
+
+ private void validateLayoutParams() {
+ // install default indices for cells if *none* are defined
+ if (mHorizontalAxis.maxIndex1() == UNDEFINED || mVerticalAxis.maxIndex1() == UNDEFINED) {
+ boolean horizontal = mOrientation == HORIZONTAL;
+ int count = horizontal ? mHorizontalAxis.count : mVerticalAxis.count;
+ if (count == UNDEFINED) {
+ count = Integer.MAX_VALUE;
+ }
+ int x = 0;
+ int y = 0;
+ int maxSize = 0;
+ for (int i = 0, size = getChildCount(); i < size; i++) {
+ LayoutParams lp = getLayoutParams1(getChildAt(i));
+
+ Interval hSpan = lp.columnGroup.span;
+ int cellWidth = hSpan.size();
+
+ Interval vSpan = lp.rowGroup.span;
+ int cellHeight = vSpan.size();
+
+ if (horizontal) {
+ if (x + cellWidth > count) {
+ x = 0;
+ y += maxSize;
+ maxSize = 0;
+ }
+ } else {
+ if (y + cellHeight > count) {
+ y = 0;
+ x += maxSize;
+ maxSize = 0;
+ }
+ }
+ lp.setHorizontalGroupSpan(new Interval(x, x + cellWidth));
+ lp.setVerticalGroupSpan(new Interval(y, y + cellHeight));
+
+ if (horizontal) {
+ x = x + cellWidth;
+ } else {
+ y = y + cellHeight;
+ }
+ maxSize = max(maxSize, horizontal ? cellHeight : cellWidth);
+ }
+ } else {
+ /*
+ At least one row and one column index have been defined.
+ Assume missing row/cols are in error and set them to zero so that
+ they will display top/left and the developer can add the right indices.
+ Without this UNDEFINED would cause ArrayIndexOutOfBoundsException.
+ */
+ for (int i = 0, size = getChildCount(); i < size; i++) {
+ LayoutParams lp = getLayoutParams1(getChildAt(i));
+ if (isUndefined(lp.columnGroup.span)) {
+ lp.setHorizontalGroupSpan(LayoutParams.DEFAULT_SPAN);
+ }
+ if (isUndefined(lp.rowGroup.span)) {
+ lp.setVerticalGroupSpan(LayoutParams.DEFAULT_SPAN);
+ }
+ }
+ }
+ }
+
+ private void invalidateStructure() {
+ mLayoutParamsValid = false;
+ mHorizontalAxis.invalidateStructure();
+ mVerticalAxis.invalidateStructure();
+
+ // This can end up being done twice. But better that than not at all.
+ invalidateValues();
+ }
+
+ private void invalidateValues() {
+ mHorizontalAxis.invalidateValues();
+ mVerticalAxis.invalidateValues();
+ }
+
+ private LayoutParams getLayoutParams1(View c) {
+ return (LayoutParams) c.getLayoutParams();
+ }
+
+ private LayoutParams getLayoutParams(View c) {
+ if (!mLayoutParamsValid) {
+ validateLayoutParams();
+ mLayoutParamsValid = true;
+ }
+ return getLayoutParams1(c);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams();
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(getContext(), attrs, mDefaultGravity);
+ }
+
+ @Override
+ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ return new LayoutParams(p);
+ }
+
+ // Draw grid
+
+ private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
+ int dx = getPaddingLeft();
+ int dy = getPaddingTop();
+ graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (DEBUG) {
+ int height = getHeight() - getPaddingTop() - getPaddingBottom();
+ int width = getWidth() - getPaddingLeft() - getPaddingRight();
+
+ int[] xs = mHorizontalAxis.locations;
+ for (int i = 0, length = xs.length; i < length; i++) {
+ int x = xs[i];
+ drawLine(canvas, x, 0, x, height - 1, GRID_PAINT);
+ }
+ int[] ys = mVerticalAxis.locations;
+ for (int i = 0, length = ys.length; i < length; i++) {
+ int y = ys[i];
+ drawLine(canvas, 0, y, width - 1, y, GRID_PAINT);
+ }
+ }
+ }
+
+ static {
+ GRID_PAINT.setColor(Color.argb(50, 255, 255, 255));
+ }
+
+ // Add/remove
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ super.addView(child, index, params);
+ invalidateStructure();
+ }
+
+ @Override
+ public void removeView(View view) {
+ super.removeView(view);
+ invalidateStructure();
+ }
+
+ @Override
+ public void removeViewInLayout(View view) {
+ super.removeViewInLayout(view);
+ invalidateStructure();
+ }
+
+ @Override
+ public void removeViewsInLayout(int start, int count) {
+ super.removeViewsInLayout(start, count);
+ invalidateStructure();
+ }
+
+ @Override
+ public void removeViewAt(int index) {
+ super.removeViewAt(index);
+ invalidateStructure();
+ }
+
+ // Measurement
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ invalidateValues();
+ // int width = MeasureSpec.getSize(widthSpec);
+ // int widthMode = MeasureSpec.getMode(widthSpec);
+ // int height = MeasureSpec.getSize(heightSpec);
+ // int heightMode = MeasureSpec.getMode(heightSpec);
+
+ // todo - handle widthSpec and heightSpec properly
+
+ int computedWidth = getPaddingLeft() + mHorizontalAxis.getPref() + getPaddingRight();
+ int computedHeight = getPaddingTop() + mVerticalAxis.getPref() + getPaddingBottom();
+
+ setMeasuredDimension(
+ resolveSizeAndState(computedWidth, widthSpec, 0),
+ resolveSizeAndState(computedHeight, heightSpec, 0));
+ }
+
+ private int protect(int alignment) {
+ return alignment == UNDEFINED ? 0 : alignment;
+ }
+
+ private int getLocationIncludingMargin(Axis state, int index, boolean leading) {
+ int margin = leading ? state.leadingMargins[index] : -state.trailingMargins[index];
+ return state.locations[index] + margin;
+ }
+
+ private int getMeasurement(View c, boolean horizontal, int measurementType) {
+ LayoutParams lp = (LayoutParams) c.getLayoutParams();
+ // First check to see if the user has specified the size.
+ // If so, return the specified size.
+ int size = horizontal ? lp.width : lp.height;
+ if (size >= 0) {
+ return size;
+ }
+
+ // measureChild(c, 0, 0);
+ c.measure(0, 0);// todo work out correct order of events for measurement calls
+ int result = horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
+
+ float weight = horizontal ? lp.columnWeight : lp.rowWeight;
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
+ if (weight != 0) {
+ return result + axis.prefSizeOfWeightedComponent;
+ }
+ return result;
+ }
+
+ // Layout container
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ invalidateValues();
+
+ int targetWidth = r - l;
+ int targetHeight = b - t;
+
+ int paddingLeft = getPaddingLeft();
+ int paddingTop = getPaddingTop();
+ int paddingRight = getPaddingRight();
+ int paddingBottom = getPaddingBottom();
+
+ mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
+ mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
+
+ for (int i = 0, size = getChildCount(); i < size; i++) {
+ View view = getChildAt(i);
+ LayoutParams constraints = getLayoutParams(view);
+ Interval hRange = constraints.columnGroup.span;
+ Interval vRange = constraints.rowGroup.span;
+
+ int x1 = getLocationIncludingMargin(mHorizontalAxis, hRange.min, true);
+ int y1 = getLocationIncludingMargin(mVerticalAxis, vRange.min, true);
+
+ int x2 = getLocationIncludingMargin(mHorizontalAxis, hRange.max, false);
+ int y2 = getLocationIncludingMargin(mVerticalAxis, vRange.max, false);
+
+ int cellWidth = x2 - x1;
+ int cellHeight = y2 - y1;
+
+ Bounds minMaxX = mHorizontalAxis.getGroupBounds().getValue(i);
+ Bounds minMaxY = mVerticalAxis.getGroupBounds().getValue(i);
+
+ int pWidth = getMeasurement(view, true, PRF);
+ int pHeight = getMeasurement(view, false, PRF);
+
+ Alignment hAlignment = constraints.columnGroup.alignment;
+ Alignment vAlignment = constraints.rowGroup.alignment;
+
+ int ddx = protect(hAlignment.getAlignmentValue(null, cellWidth - minMaxX.size()));
+ int ddy = protect(vAlignment.getAlignmentValue(null, cellHeight - minMaxY.size()));
+
+ int dx = ddx + -minMaxX.below - hAlignment.getAlignmentValue(view, pWidth);
+ int dy = ddy + -minMaxY.below - vAlignment.getAlignmentValue(view, pHeight);
+
+ int width = hAlignment.getSizeInCell(view, pWidth, cellWidth);
+ int height = vAlignment.getSizeInCell(view, pHeight, cellHeight);
+
+ int cx = paddingLeft + x1 + dx;
+ int cy = paddingTop + y1 + dy;
+ view.layout(cx, cy, cx + width, cy + height);
+ }
+ }
+
+ // Inner classes
+
+ private class Axis {
+ private static final int MIN_VALUE = -1000000;
+ private static final int MAX_VALUE = 1000000;
+
+ private static final int UNVISITED = 0;
+ private static final int PENDING = 1;
+ private static final int COMPLETE = 2;
+
+ public final boolean horizontal;
+
+ public int count = UNDEFINED;
+ public boolean countValid = false;
+ public boolean countWasExplicitySet = false;
+
+ PackedMapDefault values
+ *
+ *
+ *
+ *
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_row
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_column
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
+ */
+ public static class LayoutParams extends MarginLayoutParams {
+
+ // Default values
+
+ private static final int DEFAULT_WIDTH = WRAP_CONTENT;
+ private static final int DEFAULT_HEIGHT = WRAP_CONTENT;
+ private static final int DEFAULT_MARGIN = UNDEFINED;
+ private static final int DEFAULT_ROW = UNDEFINED;
+ private static final int DEFAULT_COLUMN = UNDEFINED;
+ private static final Interval DEFAULT_SPAN = new Interval(0, 1);
+ private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size();
+ private static final Alignment DEFAULT_HORIZONTAL_ALIGNMENT = LEFT;
+ private static final Alignment DEFAULT_VERTCIAL_ALGIGNMENT = BASELINE;
+ private static final Group DEFAULT_HORIZONTAL_GROUP =
+ new Group(DEFAULT_SPAN, DEFAULT_HORIZONTAL_ALIGNMENT);
+ private static final Group DEFAULT_VERTICAL_GROUP =
+ new Group(DEFAULT_SPAN, DEFAULT_VERTCIAL_ALGIGNMENT);
+ private static final int DEFAULT_WEIGHT = 0;
+
+ // Misc
+
+ private static final Rect CONTAINER_BOUNDS = new Rect(0, 0, 2, 2);
+ private static final Alignment[] HORIZONTAL_ALIGNMENTS = { LEFT, CENTER, RIGHT };
+ private static final Alignment[] VERTICAL_ALIGNMENTS = { TOP, CENTER, BOTTOM };
+
+ // TypedArray indices
+
+ private static final int MARGIN = styleable.ViewGroup_MarginLayout_layout_margin;
+ private static final int LEFT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginLeft;
+ private static final int TOP_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginTop;
+ private static final int RIGHT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginRight;
+ private static final int BOTTOM_MARGIN =
+ styleable.ViewGroup_MarginLayout_layout_marginBottom;
+
+ private static final int COLUMN = styleable.GridLayout_Layout_layout_column;
+ private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan;
+ private static final int COLUMN_WEIGHT = styleable.GridLayout_Layout_layout_columnWeight;
+ private static final int ROW = styleable.GridLayout_Layout_layout_row;
+ private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan;
+ private static final int ROW_WEIGHT = styleable.GridLayout_Layout_layout_rowWeight;
+ private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity;
+
+ // Instance variables
+
+ /**
+ * The group that specifies the vertical characteristics of the cell group
+ * described by these layout parameters.
+ */
+ public Group rowGroup;
+ /**
+ * The group that specifies the horizontal characteristics of the cell group
+ * described by these layout parameters.
+ */
+ public Group columnGroup;
+ /**
+ * The proportional space that should be taken by the associated row group
+ * during excess space distribution.
+ */
+ public float rowWeight;
+ /**
+ * The proportional space that should be taken by the associated column group
+ * during excess space distribution.
+ */
+ public float columnWeight;
+
+ // Constructors
+
+ private LayoutParams(
+ int width, int height,
+ int left, int top, int right, int bottom,
+ Group rowGroup, Group columnGroup, float rowWeight, float columnWeight) {
+ super(width, height);
+ setMargins(left, top, right, bottom);
+ this.rowGroup = rowGroup;
+ this.columnGroup = columnGroup;
+ this.rowWeight = rowWeight;
+ this.columnWeight = columnWeight;
+ }
+
+ /**
+ * Constructs a new LayoutParams instance for this false; otherwise {@link Integer#MIN_VALUE}, to
+ * indicate that a default value should be computed on demand. false; otherwise {@link Integer#MIN_VALUE}, to
+ * indicate that a default value should be computed on demand. false; otherwise {@link Integer#MIN_VALUE}, to
+ * indicate that a default value should be computed on demand. false; otherwise {@link Integer#MIN_VALUE}, to
+ * indicate that a default value should be computed on demand. .span = [0, 1] .alignment = {@link #BASELINE} .span = [0, 1] .alignment = {@link #LEFT} 0f 0f rowGroup
+ * and columnGroup. All other fields are initialized with
+ * default values as defined in {@link LayoutParams}.
+ *
+ * @param rowGroup the rowGroup
+ * @param columnGroup the columnGroup
+ */
+ public LayoutParams(Group rowGroup, Group columnGroup) {
+ this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
+ rowGroup, columnGroup, DEFAULT_WEIGHT, DEFAULT_WEIGHT);
+ }
+
+ /**
+ * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
+ */
+ public LayoutParams() {
+ this(DEFAULT_HORIZONTAL_GROUP, DEFAULT_VERTICAL_GROUP);
+ }
+
+ // Copying constructors
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(ViewGroup.LayoutParams params) {
+ super(params);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(MarginLayoutParams params) {
+ super(params);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(LayoutParams that) {
+ super(that);
+ this.columnGroup = that.columnGroup;
+ this.rowGroup = that.rowGroup;
+ this.columnWeight = that.columnWeight;
+ this.rowWeight = that.rowWeight;
+ }
+
+ // AttributeSet constructors
+
+ private LayoutParams(Context context, AttributeSet attrs, int defaultGravity) {
+ super(context, attrs);
+ reInitSuper(context, attrs);
+ init(context, attrs, defaultGravity);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Values not defined in the attribute set take the default values
+ * defined in {@link LayoutParams}.
+ */
+ public LayoutParams(Context context, AttributeSet attrs) {
+ this(context, attrs, Gravity.NO_GRAVITY);
+ }
+
+ // Implementation
+
+ private static boolean definesVertical(int gravity) {
+ return gravity > 0 && (gravity & Gravity.VERTICAL_GRAVITY_MASK) != 0;
+ }
+
+ private static boolean definesHorizontal(int gravity) {
+ return gravity > 0 && (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) != 0;
+ }
+
+ private static LEFT | BASELINE.
+ *
+ * @param gravity the new gravity. See {@link android.view.Gravity}.
+ *
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
+ */
+ public void setGravity(int gravity) {
+ columnGroup = columnGroup.copyWriteAlignment(getHorizontalAlignment(gravity, width));
+ rowGroup = rowGroup.copyWriteAlignment(getVerticalAlignment(gravity, height));
+ }
+
+ @Override
+ protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) {
+ this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH);
+ this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
+ }
+
+ private void setVerticalGroupSpan(Interval span) {
+ rowGroup = rowGroup.copyWriteSpan(span);
+ }
+
+ private void setHorizontalGroupSpan(Interval span) {
+ columnGroup = columnGroup.copyWriteSpan(span);
+ }
+ }
+
+ private static class Arc {
+ public final Interval span;
+ public final Int value;
+ public boolean completesCycle;
+
+ public Arc(Interval span, Int value) {
+ this.span = span;
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return span + " " + (completesCycle ? "+>" : "->") + " " + value;
+ }
+ }
+
+ // A mutable Integer - used to avoid heap allocation during the layout operation
+
+ private static class Int {
+ public int value;
+
+ private Int() {
+ reset();
+ }
+
+ private Int(int value) {
+ this.value = value;
+ }
+
+ private void reset() {
+ value = Integer.MIN_VALUE;
+ }
+
+ private Int neg() {
+ // this should never be called
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @SuppressWarnings(value = "unchecked")
+ private static class PackedMap[min, max] and represent the set of values
+ * x such that min <= x < max.
+ */
+ public static class Interval {
+ /**
+ * The minimum value.
+ */
+ public final int min;
+ /**
+ * The maximum value.
+ */
+ public final int max;
+
+ /**
+ * Construct a new Interval, interval, where:
+ *
+ *
+ *
+ * @param min the minimum value.
+ * @param max the maximum value.
+ */
+ public Interval(int min, int max) {
+ this.min = min;
+ this.max = max;
+ }
+
+ private int size() {
+ return max - min;
+ }
+
+ private Interval inverse() {
+ return new Interval(max, min);
+ }
+
+ /**
+ * Returns true if the {@link #getClass class}, {@link #min} and {@link #max} properties
+ * of this Interval and the supplied parameter are pairwise equal; false otherwise.
+ *
+ * @param that the object to compare this interval with.
+ *
+ * @return {@code true} if the specified object is equal to this
+ * {@code Interval}; {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that == null || getClass() != that.getClass()) {
+ return false;
+ }
+
+ Interval interval = (Interval) that;
+
+ if (max != interval.max) {
+ return false;
+ }
+ if (min != interval.min) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = min;
+ result = 31 * result + max;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + min + ", " + max + "]";
+ }
+ }
+
+ /**
+ * A group specifies either the horizontal or vertical characteristics of a group of
+ * cells.
+ * interval.min = min interval.max = max span and alignment.
+ */
+ public static class Group {
+ /**
+ * The {@link Interval#min min} and {@link Interval#max max} values of
+ * a span specify the grid indices of the leading and trailing edges of
+ * the cell group.
+ * group, where:
+ *
+ *
+ *
+ * @param span the span.
+ * @param alignment the alignment.
+ */
+ public Group(Interval span, Alignment alignment) {
+ this.span = span;
+ this.alignment = alignment;
+ }
+
+ /**
+ * Construct a new Group, group.span = span group.alignment = alignment group, where:
+ *
+ *
+ *
+ * @param min the minimum.
+ * @param max the maximum.
+ * @param alignment the alignment.
+ */
+ public Group(int min, int max, Alignment alignment) {
+ this(new Interval(min, max), alignment);
+ }
+
+ /**
+ * Construct a new Group, group.span = [min, max] group.alignment = alignment group, where:
+ *
+ *
+ *
+ * @param min the minimum.
+ * @param alignment the alignment.
+ */
+ public Group(int min, Alignment alignment) {
+ this(min, min + 1, alignment);
+ }
+
+ private Group copyWriteSpan(Interval span) {
+ return new Group(span, alignment);
+ }
+
+ private Group copyWriteAlignment(Alignment alignment) {
+ return new Group(span, alignment);
+ }
+
+ /**
+ * Returns true if the {@link #getClass class}, {@link #alignment} and {@link #span}
+ * properties of this Group and the supplied parameter are pairwise equal; false otherwise.
+ *
+ * @param that the object to compare this group with.
+ *
+ * @return {@code true} if the specified object is equal to this
+ * {@code Group}; {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that == null || getClass() != that.getClass()) {
+ return false;
+ }
+
+ Group group = (Group) that;
+
+ if (!alignment.equals(group.alignment)) {
+ return false;
+ }
+ if (!span.equals(group.span)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = span.hashCode();
+ result = 31 * result + alignment.hashCode();
+ return result;
+ }
+ }
+
+ // Alignments
+
+
+ /**
+ * Alignments specify where a view should be placed within a cell group and
+ * what size it should be.
+ * group.span = [min, min + 1] group.alignment = alignment