content: /*
   * Copyright (C) 2015 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.tools.idea.editors.theme.widgets;
  
  import android.content.Context;
  import android.util.AttributeSet;
  import android.util.DisplayMetrics;
  import android.util.TypedValue;
  import android.view.View;
  import android.view.ViewGroup;
  
  /**
   * Custom layout used in the theme editor to display the component preview. It arranges the child
   * Views as a grid of cards.
   * <p/>
   * The Views are measured and the maximum width and height are used to dimension all the child
   * components. Any margin attributes from the children are ignored and only the item_margin element
   * is used.
   */
  @SuppressWarnings("unused")
  public class ThemePreviewLayout extends ViewGroup {
      private final int mMaxColumns;
      private final int mMaxColumnWidth;
      private final int mMinColumnWidth;
      private final int mItemHorizontalMargin;
      private final int mItemVerticalMargin;
  
      /** Item width to use for every card component. This includes margins. */
      private int mItemWidth;
      /** Item height to use for every card component. This includes margins. */
      private int mItemHeight;
  
      /** Calculated number of columns */
      private int mNumColumns;
  
      public ThemePreviewLayout(Context context) {
          this(context, null);
      }
  
      public ThemePreviewLayout(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public ThemePreviewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
  
          if (attrs == null) {
              mMaxColumnWidth = Integer.MAX_VALUE;
              mMinColumnWidth = 0;
              mMaxColumns = Integer.MAX_VALUE;
              mItemHorizontalMargin = 0;
              mItemVerticalMargin = 0;
              return;
          }
  
          DisplayMetrics dm = getResources().getDisplayMetrics();
          int maxColumnWidth = attrs.getAttributeIntValue(null, "max_column_width", Integer
                  .MAX_VALUE);
          int minColumnWidth = attrs.getAttributeIntValue(null, "min_column_width", 0);
          int itemHorizontalMargin = attrs.getAttributeIntValue(null, "item_horizontal_margin", 0);
          int itemVerticalMargin = attrs.getAttributeIntValue(null, "item_vertical_margin", 0);
  
          mMaxColumnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                  maxColumnWidth,
                  dm);
          mMinColumnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                  minColumnWidth,
                  dm);
          mItemHorizontalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                  itemHorizontalMargin,
                  dm);
          mItemVerticalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                  itemVerticalMargin,
                  dm);
          mMaxColumns = attrs.getAttributeIntValue(null, "max_columns", Integer.MAX_VALUE);
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          // Measure the column size.
          // The column has a minimum width that will be used to calculate the maximum number of
          // columns that we can fit in the available space.
          //
          // Once we have the maximum number of columns, we will span all columns width evenly to fill
          // all the available space.
          int wSize = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
  
          // Calculate the desired width of all columns and take the maximum.
          // This step can be skipped if we have a fixed column height so we do not have to
          // dynamically calculate it.
          int childWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
          int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
          int itemWidth = 0;
          int itemHeight = 0;
          for (int i = 0; i < getChildCount(); i++) {
              View v = getChildAt(i);
  
              if (v.getVisibility() == GONE) {
                  continue;
              }
  
              measureChild(v, childWidthSpec, childHeightSpec);
  
              itemWidth = Math.max(itemWidth, v.getMeasuredWidth());
              itemHeight = Math.max(itemHeight, v.getMeasuredHeight());
          }
  
          itemWidth = Math.min(Math.max(itemWidth, mMinColumnWidth), mMaxColumnWidth);
          mNumColumns = Math.min((int) Math.ceil((double) wSize / itemWidth), mMaxColumns);
  
          // Check how much space this distribution would take taking into account the margins.
          // If it's bigger than what we have, remove one column.
          int wSizeNeeded = mNumColumns * itemWidth + (mNumColumns - 1) * mItemHorizontalMargin;
          if (wSizeNeeded > wSize && mNumColumns > 1) {
              mNumColumns--;
          }
  
          if (getChildCount() < mNumColumns) {
              mNumColumns = getChildCount();
          }
          if (mNumColumns == 0) {
              mNumColumns = 1;
          }
  
          // Inform each child of the measurement
          childWidthSpec = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
          childHeightSpec = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
          for (int i = 0; i < getChildCount(); i++) {
              View v = getChildAt(i);
  
              if (v.getVisibility() == GONE) {
                  continue;
              }
  
              measureChild(v, childWidthSpec, childHeightSpec);
          }
  
          // Calculate the height of the first column to measure our own size
          int firstColumnItems = getChildCount() / mNumColumns + ((getChildCount() % mNumColumns) > 0
                  ? 1 : 0);
  
          int horizontalMarginsTotalWidth = (mNumColumns - 1) * mItemHorizontalMargin;
          int verticalMarginsTotalHeight = (firstColumnItems - 1) * mItemVerticalMargin;
          int totalWidth = mNumColumns * itemWidth + horizontalMarginsTotalWidth +
                  mPaddingRight + mPaddingLeft;
          int totalHeight = firstColumnItems * itemHeight + verticalMarginsTotalHeight +
                  mPaddingBottom + mPaddingTop;
  
          setMeasuredDimension(resolveSize(totalWidth, widthMeasureSpec),
                  resolveSize(totalHeight, heightMeasureSpec));
  
          mItemWidth = itemWidth;
          mItemHeight = itemHeight;
      }
  
      @Override
      protected void onLayout(boolean changed, int l, int t, int r, int b) {
          int itemsPerColumn = getChildCount() / mNumColumns;
          // The remainder items are distributed one per column.
          int remainderItems = getChildCount() % mNumColumns;
  
          int x = mPaddingLeft;
          int y = mPaddingTop;
          int position = 1;
          for (int i = 0; i < getChildCount(); i++) {
              View v = getChildAt(i);
              v.layout(x,
                      y,
                      x + mItemWidth,
                      y + mItemHeight);
  
              if (position == itemsPerColumn + (remainderItems > 0 ? 1 : 0)) {
                  // Break column
                  position = 1;
                  remainderItems--;
                  x += mItemWidth + mItemHorizontalMargin;
                  y = mPaddingTop;
              } else {
                  position++;
                  y += mItemHeight + mItemVerticalMargin;
              }
          }
      }
  }
  
  
  