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 
17 package com.android.printspooler.widget;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.view.ViewGroup;
24 import com.android.printspooler.R;
25 
26 /**
27  * This class is a layout manager for the print options. The options are
28  * arranged in a configurable number of columns and enough rows to fit all
29  * the options given the column count.
30  */
31 @SuppressWarnings("unused")
32 public final class PrintOptionsLayout extends ViewGroup {
33 
34     private int mColumnCount;
35 
PrintOptionsLayout(Context context, AttributeSet attrs)36     public PrintOptionsLayout(Context context, AttributeSet attrs) {
37         super(context, attrs);
38 
39         TypedArray typedArray = context.obtainStyledAttributes(attrs,
40                 R.styleable.PrintOptionsLayout);
41         mColumnCount = typedArray.getInteger(R.styleable.PrintOptionsLayout_columnCount, 0);
42         typedArray.recycle();
43     }
44 
setColumnCount(int columnCount)45     public void setColumnCount(int columnCount) {
46         if (mColumnCount != columnCount) {
47             mColumnCount = columnCount;
48             requestLayout();
49         }
50     }
51 
52     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)53     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
54         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
55         final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
56 
57         final int columnWidth = (widthSize != 0)
58                 ? (widthSize - mPaddingLeft - mPaddingRight) / mColumnCount : 0;
59 
60         int width = 0;
61         int height = 0;
62         int childState = 0;
63 
64         final int childCount = getChildCount();
65         final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
66 
67         for (int row = 0; row < rowCount; row++) {
68             int rowWidth = 0;
69             int rowHeight = 0;
70 
71             for (int col = 0; col < mColumnCount; col++) {
72                 final int childIndex = row * mColumnCount + col;
73 
74                 if (childIndex >= childCount) {
75                     break;
76                 }
77 
78                 View child = getChildAt(childIndex);
79 
80                 if (child.getVisibility() == GONE) {
81                     continue;
82                 }
83 
84                 MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
85 
86                 final int childWidthMeasureSpec;
87                 if (columnWidth > 0) {
88                     childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
89                             columnWidth - childParams.getMarginStart() - childParams.getMarginEnd(),
90                             MeasureSpec.EXACTLY);
91                 } else {
92                     childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
93                             getPaddingStart() + getPaddingEnd() + width, childParams.width);
94                 }
95 
96                 final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
97                         getPaddingTop() + getPaddingBottom() + height, childParams.height);
98 
99                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
100 
101                 childState = combineMeasuredStates(childState, child.getMeasuredState());
102 
103                 rowWidth += child.getMeasuredWidth() + childParams.getMarginStart()
104                         + childParams.getMarginEnd();
105 
106                 rowHeight = Math.max(rowHeight, child.getMeasuredHeight() + childParams.topMargin
107                         + childParams.bottomMargin);
108             }
109 
110             width = Math.max(width, rowWidth);
111             height += rowHeight;
112         }
113 
114         width += getPaddingStart() + getPaddingEnd();
115         width = Math.max(width, getMinimumWidth());
116 
117         height += getPaddingTop() + getPaddingBottom();
118         height = Math.max(height, getMinimumHeight());
119 
120         setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
121                 resolveSizeAndState(height, heightMeasureSpec,
122                         childState << MEASURED_HEIGHT_STATE_SHIFT));
123     }
124 
125     @Override
onLayout(boolean changed, int l, int t, int r, int b)126     protected void onLayout(boolean changed, int l, int t, int r, int b) {
127         final int childCount = getChildCount();
128         final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
129 
130         int cellStart = getPaddingStart();
131         int cellTop = getPaddingTop();
132 
133         for (int row = 0; row < rowCount; row++) {
134             int rowHeight = 0;
135 
136             for (int col = 0; col < mColumnCount; col++) {
137                 final int childIndex = row * mColumnCount + col;
138 
139                 if (childIndex >= childCount) {
140                     break;
141                 }
142 
143                 View child = getChildAt(childIndex);
144 
145                 if (child.getVisibility() == GONE) {
146                     continue;
147                 }
148 
149                 MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
150 
151                 final int childLeft = cellStart + childParams.getMarginStart();
152                 final int childTop = cellTop + childParams.topMargin;
153                 final int childRight = childLeft + child.getMeasuredWidth();
154                 final int childBottom = childTop + child.getMeasuredHeight();
155 
156                 child.layout(childLeft, childTop, childRight, childBottom);
157 
158                 cellStart = childRight + childParams.getMarginEnd();
159 
160                 rowHeight = Math.max(rowHeight, child.getMeasuredHeight()
161                         + childParams.topMargin + childParams.bottomMargin);
162             }
163 
164             cellStart = getPaddingStart();
165             cellTop += rowHeight;
166         }
167     }
168 
169     @Override
generateLayoutParams(AttributeSet attrs)170     public LayoutParams generateLayoutParams(AttributeSet attrs) {
171         return new ViewGroup.MarginLayoutParams(getContext(), attrs);
172     }
173 }
174