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 
25 import 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")
33 public final class PrintOptionsLayout extends ViewGroup {
34 
35     private int mColumnCount;
36 
PrintOptionsLayout(Context context, AttributeSet attrs)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 
setColumnCount(int columnCount)46     public void setColumnCount(int columnCount) {
47         if (mColumnCount != columnCount) {
48             mColumnCount = columnCount;
49             requestLayout();
50         }
51     }
52 
53     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)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
onLayout(boolean changed, int l, int t, int r, int b)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
generateLayoutParams(AttributeSet attrs)178     public LayoutParams generateLayoutParams(AttributeSet attrs) {
179         return new ViewGroup.MarginLayoutParams(getContext(), attrs);
180     }
181 }
182