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