Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2011 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.settings.widget;
     18 
     19 import static com.google.common.base.Preconditions.checkNotNull;
     20 
     21 import android.content.Context;
     22 import android.content.res.TypedArray;
     23 import android.graphics.Rect;
     24 import android.util.AttributeSet;
     25 import android.view.Gravity;
     26 import android.view.View;
     27 import android.view.ViewDebug;
     28 import android.widget.FrameLayout;
     29 
     30 import com.android.settings.R;
     31 
     32 /**
     33  * Container for two-dimensional chart, drawn with a combination of
     34  * {@link ChartGridView}, {@link ChartNetworkSeriesView} and {@link ChartSweepView}
     35  * children. The entire chart uses {@link ChartAxis} to map between raw values
     36  * and screen coordinates.
     37  */
     38 public class ChartView extends FrameLayout {
     39     // TODO: extend something that supports two-dimensional scrolling
     40 
     41     private static final int SWEEP_GRAVITY = Gravity.TOP | Gravity.LEFT;
     42 
     43     ChartAxis mHoriz;
     44     ChartAxis mVert;
     45 
     46     @ViewDebug.ExportedProperty
     47     private int mOptimalWidth = -1;
     48     private float mOptimalWidthWeight = 0;
     49 
     50     private Rect mContent = new Rect();
     51 
     52     public ChartView(Context context) {
     53         this(context, null, 0);
     54     }
     55 
     56     public ChartView(Context context, AttributeSet attrs) {
     57         this(context, attrs, 0);
     58     }
     59 
     60     public ChartView(Context context, AttributeSet attrs, int defStyle) {
     61         super(context, attrs, defStyle);
     62 
     63         final TypedArray a = context.obtainStyledAttributes(
     64                 attrs, R.styleable.ChartView, defStyle, 0);
     65         setOptimalWidth(a.getDimensionPixelSize(R.styleable.ChartView_optimalWidth, -1),
     66                 a.getFloat(R.styleable.ChartView_optimalWidthWeight, 0));
     67         a.recycle();
     68 
     69         setClipToPadding(false);
     70         setClipChildren(false);
     71     }
     72 
     73     void init(ChartAxis horiz, ChartAxis vert) {
     74         mHoriz = checkNotNull(horiz, "missing horiz");
     75         mVert = checkNotNull(vert, "missing vert");
     76     }
     77 
     78     public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) {
     79         mOptimalWidth = optimalWidth;
     80         mOptimalWidthWeight = optimalWidthWeight;
     81         requestLayout();
     82     }
     83 
     84     @Override
     85     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     86         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     87 
     88         final int slack = getMeasuredWidth() - mOptimalWidth;
     89         if (mOptimalWidth > 0 && slack > 0) {
     90             final int targetWidth = (int) (mOptimalWidth + (slack * mOptimalWidthWeight));
     91             widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY);
     92             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     93         }
     94     }
     95 
     96     @Override
     97     protected void onLayout(boolean changed, int l, int t, int r, int b) {
     98         mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
     99                 b - t - getPaddingBottom());
    100         final int width = mContent.width();
    101         final int height = mContent.height();
    102 
    103         // no scrolling yet, so tell dimensions to fill exactly
    104         mHoriz.setSize(width);
    105         mVert.setSize(height);
    106 
    107         final Rect parentRect = new Rect();
    108         final Rect childRect = new Rect();
    109 
    110         for (int i = 0; i < getChildCount(); i++) {
    111             final View child = getChildAt(i);
    112             final LayoutParams params = (LayoutParams) child.getLayoutParams();
    113 
    114             parentRect.set(mContent);
    115 
    116             if (child instanceof ChartNetworkSeriesView || child instanceof ChartGridView) {
    117                 // series are always laid out to fill entire graph area
    118                 // TODO: handle scrolling for series larger than content area
    119                 Gravity.apply(params.gravity, width, height, parentRect, childRect);
    120                 child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
    121 
    122             } else if (child instanceof ChartSweepView) {
    123                 layoutSweep((ChartSweepView) child, parentRect, childRect);
    124                 child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
    125             }
    126         }
    127     }
    128 
    129     protected void layoutSweep(ChartSweepView sweep) {
    130         final Rect parentRect = new Rect(mContent);
    131         final Rect childRect = new Rect();
    132 
    133         layoutSweep(sweep, parentRect, childRect);
    134         sweep.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
    135     }
    136 
    137     protected void layoutSweep(ChartSweepView sweep, Rect parentRect, Rect childRect) {
    138         final Rect sweepMargins = sweep.getMargins();
    139 
    140         // sweep is always placed along specific dimension
    141         if (sweep.getFollowAxis() == ChartSweepView.VERTICAL) {
    142             parentRect.top += sweepMargins.top + (int) sweep.getPoint();
    143             parentRect.bottom = parentRect.top;
    144             parentRect.left += sweepMargins.left;
    145             parentRect.right += sweepMargins.right;
    146             Gravity.apply(SWEEP_GRAVITY, parentRect.width(), sweep.getMeasuredHeight(),
    147                     parentRect, childRect);
    148 
    149         } else {
    150             parentRect.left += sweepMargins.left + (int) sweep.getPoint();
    151             parentRect.right = parentRect.left;
    152             parentRect.top += sweepMargins.top;
    153             parentRect.bottom += sweepMargins.bottom;
    154             Gravity.apply(SWEEP_GRAVITY, sweep.getMeasuredWidth(), parentRect.height(),
    155                     parentRect, childRect);
    156         }
    157     }
    158 
    159 }
    160