1/* 2 * Copyright (C) 2010 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 */ 16package com.android.calendar; 17 18import android.content.Context; 19import android.graphics.Canvas; 20import android.graphics.drawable.Drawable; 21import android.util.AttributeSet; 22import android.util.Log; 23import android.view.Gravity; 24import android.widget.Button; 25 26/** 27 * <p> 28 * A button with more than two states. When the button is pressed 29 * or clicked, the state transitions automatically. 30 * </p> 31 * 32 * <p><strong>XML attributes</strong></p> 33 * <p> 34 * See {@link R.styleable#MultiStateButton 35 * MultiStateButton Attributes}, {@link android.R.styleable#Button Button 36 * Attributes}, {@link android.R.styleable#TextView TextView Attributes}, {@link 37 * android.R.styleable#View View Attributes} 38 * </p> 39 */ 40 41public class MultiStateButton extends Button { 42 //The current state for this button, ranging from 0 to maxState-1 43 private int mState; 44 //The maximum number of states allowed for this button. 45 private int mMaxStates; 46 //The currently displaying resource ID. This gets set to a default on creation and remains 47 //on the last set if the resources get set to null. 48 private int mButtonResource; 49 //A list of all drawable resources used by this button in the order it uses them. 50 private int[] mButtonResources; 51 private Drawable mButtonDrawable; 52 53 public MultiStateButton(Context context) { 54 this(context, null); 55 } 56 57 public MultiStateButton(Context context, AttributeSet attrs) { 58 this(context, attrs, 0); 59 } 60 61 public MultiStateButton(Context context, AttributeSet attrs, int defStyle) { 62 //Currently using the standard buttonStyle, will update when new resources are added. 63 super(context, attrs, defStyle); 64 mMaxStates = 1; 65 mState = 0; 66 //TODO add a more generic default button 67 mButtonResources = new int[] { R.drawable.widget_show }; 68 setButtonDrawable(mButtonResources[mState]); 69 } 70 71 @Override 72 public boolean performClick() { 73 /* When clicked, toggle the state */ 74 transitionState(); 75 return super.performClick(); 76 } 77 78 public void transitionState() { 79 mState = (mState + 1) % mMaxStates; 80 setButtonDrawable(mButtonResources[mState]); 81 } 82 83 /** 84 * Allows for a new set of drawable resource ids to be set. 85 * 86 * This sets the maximum states allowed to the length of the resources array. It will also 87 * set the current state to the maximum allowed if it's greater than the new max. 88 */ 89 public void setButtonResources(int[] resources) throws IllegalArgumentException { 90 if(resources == null) { 91 throw new IllegalArgumentException("Button resources cannot be null"); 92 } 93 mMaxStates = resources.length; 94 if(mState >= mMaxStates) { 95 mState = mMaxStates - 1; 96 } 97 mButtonResources = resources; 98 } 99 100 /** 101 * Attempts to set the state. Returns true if successful, false otherwise. 102 */ 103 public boolean setState(int state){ 104 if(state >= mMaxStates || state < 0) { 105 //When moved out of Calendar the tag should be changed. 106 Log.w("Cal", "MultiStateButton state set to value greater than maxState or < 0"); 107 return false; 108 } 109 mState = state; 110 setButtonDrawable(mButtonResources[mState]); 111 return true; 112 } 113 114 public int getState() { 115 return mState; 116 } 117 118 /** 119 * Set the background to a given Drawable, identified by its resource id. 120 * 121 * @param resid the resource id of the drawable to use as the background 122 */ 123 public void setButtonDrawable(int resid) { 124 if (resid != 0 && resid == mButtonResource) { 125 return; 126 } 127 128 mButtonResource = resid; 129 130 Drawable d = null; 131 if (mButtonResource != 0) { 132 d = getResources().getDrawable(mButtonResource); 133 } 134 setButtonDrawable(d); 135 } 136 137 /** 138 * Set the background to a given Drawable 139 * 140 * @param d The Drawable to use as the background 141 */ 142 public void setButtonDrawable(Drawable d) { 143 if (d != null) { 144 if (mButtonDrawable != null) { 145 mButtonDrawable.setCallback(null); 146 unscheduleDrawable(mButtonDrawable); 147 } 148 d.setCallback(this); 149 d.setState(getDrawableState()); 150 d.setVisible(getVisibility() == VISIBLE, false); 151 mButtonDrawable = d; 152 mButtonDrawable.setState(null); 153 setMinHeight(mButtonDrawable.getIntrinsicHeight()); 154 setWidth(mButtonDrawable.getIntrinsicWidth()); 155 } 156 refreshDrawableState(); 157 } 158 159 @Override 160 protected void onDraw(Canvas canvas) { 161 super.onDraw(canvas); 162 if (mButtonDrawable != null) { 163 final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK; 164 final int horizontalGravity = getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK; 165 final int height = mButtonDrawable.getIntrinsicHeight(); 166 final int width = mButtonDrawable.getIntrinsicWidth(); 167 168 int y = 0; 169 int x = 0; 170 171 switch (verticalGravity) { 172 case Gravity.BOTTOM: 173 y = getHeight() - height; 174 break; 175 case Gravity.CENTER_VERTICAL: 176 y = (getHeight() - height) / 2; 177 break; 178 } 179 switch (horizontalGravity) { 180 case Gravity.RIGHT: 181 x = getWidth() - width; 182 break; 183 case Gravity.CENTER_HORIZONTAL: 184 x = (getWidth() - width) / 2; 185 break; 186 } 187 188 mButtonDrawable.setBounds(x, y, x + width, y + height); 189 mButtonDrawable.draw(canvas); 190 } 191 } 192} 193