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