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