/* * Copyright (C) 2013 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 com.android.colorpicker; import android.content.Context; import android.content.res.Resources; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TableLayout; import android.widget.TableRow; import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener; /** * A color picker custom view which creates an grid of color squares. The number of squares per * row (and the padding between the squares) is determined by the user. */ public class ColorPickerPalette extends TableLayout { public OnColorSelectedListener mOnColorSelectedListener; private String mDescription; private String mDescriptionSelected; private int mSwatchLength; private int mMarginSize; private int mNumColumns; public ColorPickerPalette(Context context, AttributeSet attrs) { super(context, attrs); } public ColorPickerPalette(Context context) { super(context); } /** * Initialize the size, columns, and listener. Size should be a pre-defined size (SIZE_LARGE * or SIZE_SMALL) from ColorPickerDialogFragment. */ public void init(int size, int columns, OnColorSelectedListener listener) { mNumColumns = columns; Resources res = getResources(); if (size == ColorPickerDialog.SIZE_LARGE) { mSwatchLength = res.getDimensionPixelSize(R.dimen.color_swatch_large); mMarginSize = res.getDimensionPixelSize(R.dimen.color_swatch_margins_large); } else { mSwatchLength = res.getDimensionPixelSize(R.dimen.color_swatch_small); mMarginSize = res.getDimensionPixelSize(R.dimen.color_swatch_margins_small); } mOnColorSelectedListener = listener; mDescription = res.getString(R.string.color_swatch_description); mDescriptionSelected = res.getString(R.string.color_swatch_description_selected); } private TableRow createTableRow() { TableRow row = new TableRow(getContext()); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); row.setLayoutParams(params); return row; } /** * Adds swatches to table in a serpentine format. */ public void drawPalette(int[] colors, int selectedColor) { drawPalette(colors, selectedColor, null); } /** * Adds swatches to table in a serpentine format. */ public void drawPalette(int[] colors, int selectedColor, String[] colorContentDescriptions) { if (colors == null) { return; } this.removeAllViews(); int tableElements = 0; int rowElements = 0; int rowNumber = 0; // Fills the table with swatches based on the array of colors. TableRow row = createTableRow(); for (int color : colors) { View colorSwatch = createColorSwatch(color, selectedColor); setSwatchDescription(rowNumber, tableElements, rowElements, color == selectedColor, colorSwatch, colorContentDescriptions); addSwatchToRow(row, colorSwatch, rowNumber); tableElements++; rowElements++; if (rowElements == mNumColumns) { addView(row); row = createTableRow(); rowElements = 0; rowNumber++; } } // Create blank views to fill the row if the last row has not been filled. if (rowElements > 0) { while (rowElements != mNumColumns) { addSwatchToRow(row, createBlankSpace(), rowNumber); rowElements++; } addView(row); } } /** * Appends a swatch to the end of the row for even-numbered rows (starting with row 0), * to the beginning of a row for odd-numbered rows. */ private static void addSwatchToRow(TableRow row, View swatch, int rowNumber) { if (rowNumber % 2 == 0) { row.addView(swatch); } else { row.addView(swatch, 0); } } /** * Add a content description to the specified swatch view. Because the colors get added in a * snaking form, every other row will need to compensate for the fact that the colors are added * in an opposite direction from their left->right/top->bottom order, which is how the system * will arrange them for accessibility purposes. */ private void setSwatchDescription(int rowNumber, int index, int rowElements, boolean selected, View swatch, String[] contentDescriptions) { String description; if (contentDescriptions != null && contentDescriptions.length > index) { description = contentDescriptions[index]; } else { int accessibilityIndex; if (rowNumber % 2 == 0) { // We're in a regular-ordered row accessibilityIndex = index + 1; } else { // We're in a backwards-ordered row. int rowMax = ((rowNumber + 1) * mNumColumns); accessibilityIndex = rowMax - rowElements; } if (selected) { description = String.format(mDescriptionSelected, accessibilityIndex); } else { description = String.format(mDescription, accessibilityIndex); } } swatch.setContentDescription(description); } /** * Creates a blank space to fill the row. */ private ImageView createBlankSpace() { ImageView view = new ImageView(getContext()); TableRow.LayoutParams params = new TableRow.LayoutParams(mSwatchLength, mSwatchLength); params.setMargins(mMarginSize, mMarginSize, mMarginSize, mMarginSize); view.setLayoutParams(params); return view; } /** * Creates a color swatch. */ private ColorPickerSwatch createColorSwatch(int color, int selectedColor) { ColorPickerSwatch view = new ColorPickerSwatch(getContext(), color, color == selectedColor, mOnColorSelectedListener); TableRow.LayoutParams params = new TableRow.LayoutParams(mSwatchLength, mSwatchLength); params.setMargins(mMarginSize, mMarginSize, mMarginSize, mMarginSize); view.setLayoutParams(params); return view; } }