1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.printspooler.widget;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.util.AttributeSet;
22import android.view.View;
23import android.view.ViewGroup;
24
25import com.android.printspooler.R;
26
27/**
28 * This class is a layout manager for the print options. The options are
29 * arranged in a configurable number of columns and enough rows to fit all
30 * the options given the column count.
31 */
32@SuppressWarnings("unused")
33public final class PrintOptionsLayout extends ViewGroup {
34
35    private int mColumnCount;
36
37    public PrintOptionsLayout(Context context, AttributeSet attrs) {
38        super(context, attrs);
39
40        TypedArray typedArray = context.obtainStyledAttributes(attrs,
41                R.styleable.PrintOptionsLayout);
42        mColumnCount = typedArray.getInteger(R.styleable.PrintOptionsLayout_columnCount, 0);
43        typedArray.recycle();
44    }
45
46    public void setColumnCount(int columnCount) {
47        if (mColumnCount != columnCount) {
48            mColumnCount = columnCount;
49            requestLayout();
50        }
51    }
52
53    @Override
54    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
55        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
56        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
57
58        final int columnWidth = (widthSize != 0)
59                ? (widthSize - mPaddingLeft - mPaddingRight) / mColumnCount : 0;
60
61        int width = 0;
62        int height = 0;
63        int childState = 0;
64
65        final int childCount = getChildCount();
66        final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
67
68        for (int row = 0; row < rowCount; row++) {
69            int rowWidth = 0;
70            int rowHeight = 0;
71
72            for (int col = 0; col < mColumnCount; col++) {
73                final int childIndex = row * mColumnCount + col;
74
75                if (childIndex >= childCount) {
76                    break;
77                }
78
79                View child = getChildAt(childIndex);
80
81                if (child.getVisibility() == GONE) {
82                    continue;
83                }
84
85                MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
86
87                final int childWidthMeasureSpec;
88                if (columnWidth > 0) {
89                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
90                            columnWidth - childParams.getMarginStart() - childParams.getMarginEnd(),
91                            MeasureSpec.EXACTLY);
92                } else {
93                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
94                            getPaddingStart() + getPaddingEnd() + width, childParams.width);
95                }
96
97                final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
98                        getPaddingTop() + getPaddingBottom() + height, childParams.height);
99
100                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
101
102                childState = combineMeasuredStates(childState, child.getMeasuredState());
103
104                rowWidth += child.getMeasuredWidth() + childParams.getMarginStart()
105                        + childParams.getMarginEnd();
106
107                rowHeight = Math.max(rowHeight, child.getMeasuredHeight() + childParams.topMargin
108                        + childParams.bottomMargin);
109            }
110
111            width = Math.max(width, rowWidth);
112            height += rowHeight;
113        }
114
115        width += getPaddingStart() + getPaddingEnd();
116        width = Math.max(width, getMinimumWidth());
117
118        height += getPaddingTop() + getPaddingBottom();
119        height = Math.max(height, getMinimumHeight());
120
121        setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
122                resolveSizeAndState(height, heightMeasureSpec,
123                        childState << MEASURED_HEIGHT_STATE_SHIFT));
124    }
125
126    @Override
127    protected void onLayout(boolean changed, int l, int t, int r, int b) {
128        final int childCount = getChildCount();
129        final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
130        final boolean isLayoutRtl = isLayoutRtl();
131
132        int cellStart = getPaddingStart();
133        int cellTop = getPaddingTop();
134
135        for (int row = 0; row < rowCount; row++) {
136            int rowHeight = 0;
137
138            for (int col = 0; col < mColumnCount; col++) {
139                final int childIndex;
140                if (isLayoutRtl) {
141                    // if RTL, layout the right most child first
142                    childIndex = row * mColumnCount + (mColumnCount - col - 1);
143                } else {
144                    childIndex = row * mColumnCount + col;
145                }
146
147                if (childIndex >= childCount) {
148                    break;
149                }
150
151                View child = getChildAt(childIndex);
152
153                if (child.getVisibility() == GONE) {
154                    continue;
155                }
156
157                MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
158
159                final int childStart = cellStart + childParams.getMarginStart();
160                final int childTop = cellTop + childParams.topMargin;
161                final int childEnd = childStart + child.getMeasuredWidth();
162                final int childBottom = childTop + child.getMeasuredHeight();
163
164                child.layout(childStart, childTop, childEnd, childBottom);
165
166                cellStart = childEnd + childParams.getMarginEnd();
167
168                rowHeight = Math.max(rowHeight, child.getMeasuredHeight()
169                        + childParams.topMargin + childParams.bottomMargin);
170            }
171
172            cellStart = getPaddingStart();
173            cellTop += rowHeight;
174        }
175    }
176
177    @Override
178    public LayoutParams generateLayoutParams(AttributeSet attrs) {
179        return new ViewGroup.MarginLayoutParams(getContext(), attrs);
180    }
181}
182