166 lines
5.9 KiB
Kotlin
166 lines
5.9 KiB
Kotlin
/*
|
|
* Copyright (C) 2021 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.calendar
|
|
|
|
import android.content.Context
|
|
import android.graphics.Canvas
|
|
import android.graphics.drawable.Drawable
|
|
import android.util.AttributeSet
|
|
import android.util.Log
|
|
import android.view.Gravity
|
|
import android.widget.Button
|
|
|
|
/**
|
|
* A button with more than two states. When the button is pressed
|
|
* or clicked, the state transitions automatically.
|
|
*
|
|
* **XML attributes**
|
|
* See [ MultiStateButton Attributes][R.styleable.MultiStateButton],
|
|
* [Button][android.R.styleable.Button], [TextView Attributes][android.R.styleable.TextView],
|
|
* [ ][android.R.styleable.View]
|
|
*
|
|
*/
|
|
class MultiStateButton(context: Context?, attrs: AttributeSet?, defStyle: Int) :
|
|
Button(context, attrs, defStyle) {
|
|
//The current state for this button, ranging from 0 to maxState-1
|
|
var mState = 0
|
|
private set
|
|
|
|
//The maximum number of states allowed for this button.
|
|
private var mMaxStates = 1
|
|
|
|
//The currently displaying resource ID. This gets set to a default on creation and remains
|
|
//on the last set if the resources get set to null.
|
|
private var mButtonResource = 0
|
|
|
|
//A list of all drawable resources used by this button in the order it uses them.
|
|
private var mButtonResources: IntArray
|
|
private var mButtonDrawable: Drawable? = null
|
|
|
|
constructor(context: Context?) : this(context, null) {}
|
|
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0) {}
|
|
|
|
override fun performClick(): Boolean {
|
|
/* When clicked, toggle the state */
|
|
transitionState()
|
|
return super.performClick()
|
|
}
|
|
|
|
fun transitionState() {
|
|
mState = (mState + 1) % mMaxStates
|
|
setButtonDrawable(mButtonResources[mState])
|
|
}
|
|
|
|
/**
|
|
* Allows for a new set of drawable resource ids to be set.
|
|
*
|
|
* This sets the maximum states allowed to the length of the resources array. It will also
|
|
* set the current state to the maximum allowed if it's greater than the new max.
|
|
*/
|
|
//@Throws(IllegalArgumentException::class)
|
|
fun setButtonResources(resources: IntArray?) {
|
|
if (resources == null) {
|
|
throw IllegalArgumentException("Button resources cannot be null")
|
|
}
|
|
mMaxStates = resources.size
|
|
if (mState >= mMaxStates) {
|
|
mState = mMaxStates - 1
|
|
}
|
|
mButtonResources = resources
|
|
}
|
|
|
|
/**
|
|
* Attempts to set the state. Returns true if successful, false otherwise.
|
|
*/
|
|
fun setState(state: Int): Boolean {
|
|
if (state >= mMaxStates || state < 0) {
|
|
//When moved out of Calendar the tag should be changed.
|
|
Log.w("Cal", "MultiStateButton state set to value greater than maxState or < 0")
|
|
return false
|
|
}
|
|
mState = state
|
|
setButtonDrawable(mButtonResources[mState])
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* Set the background to a given Drawable, identified by its resource id.
|
|
*
|
|
* @param resid the resource id of the drawable to use as the background
|
|
*/
|
|
fun setButtonDrawable(resid: Int) {
|
|
if (resid != 0 && resid == mButtonResource) {
|
|
return
|
|
}
|
|
mButtonResource = resid
|
|
var d: Drawable? = null
|
|
if (mButtonResource != 0) {
|
|
d = getResources().getDrawable(mButtonResource)
|
|
}
|
|
setButtonDrawable(d)
|
|
}
|
|
|
|
/**
|
|
* Set the background to a given Drawable
|
|
*
|
|
* @param d The Drawable to use as the background
|
|
*/
|
|
fun setButtonDrawable(d: Drawable?) {
|
|
if (d != null) {
|
|
if (mButtonDrawable != null) {
|
|
mButtonDrawable?.setCallback(null)
|
|
unscheduleDrawable(mButtonDrawable)
|
|
}
|
|
d.setCallback(this)
|
|
d.setState(getDrawableState())
|
|
d.setVisible(getVisibility() === VISIBLE, false)
|
|
mButtonDrawable = d
|
|
mButtonDrawable?.setState(getDrawableState())
|
|
setMinHeight(mButtonDrawable?.getIntrinsicHeight() ?: 0)
|
|
setWidth(mButtonDrawable?.getIntrinsicWidth() ?: 0)
|
|
}
|
|
refreshDrawableState()
|
|
}
|
|
|
|
protected override fun onDraw(canvas: Canvas) {
|
|
super.onDraw(canvas)
|
|
if (mButtonDrawable != null) {
|
|
val verticalGravity: Int = getGravity() and Gravity.VERTICAL_GRAVITY_MASK
|
|
val horizontalGravity: Int = getGravity() and Gravity.HORIZONTAL_GRAVITY_MASK
|
|
val height: Int = mButtonDrawable?.getIntrinsicHeight() ?: 0
|
|
val width: Int = mButtonDrawable?.getIntrinsicWidth() ?: 0
|
|
var y = 0
|
|
var x = 0
|
|
when (verticalGravity) {
|
|
Gravity.BOTTOM -> y = getHeight() - height
|
|
Gravity.CENTER_VERTICAL -> y = (getHeight() - height) / 2
|
|
}
|
|
when (horizontalGravity) {
|
|
Gravity.RIGHT -> x = getWidth() - width
|
|
Gravity.CENTER_HORIZONTAL -> x = (getWidth() - width) / 2
|
|
}
|
|
mButtonDrawable?.setBounds(x, y, x + width, y + height)
|
|
mButtonDrawable?.draw(canvas)
|
|
}
|
|
}
|
|
|
|
init {
|
|
//Currently using the standard buttonStyle, will update when new resources are added.
|
|
//TODO add a more generic default button
|
|
mButtonResources = intArrayOf(R.drawable.widget_show)
|
|
setButtonDrawable(mButtonResources[mState])
|
|
}
|
|
} |