All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.androidx.constraintlayout.core.motion.CustomAttribute.kt Maven / Gradle / Ivy

The newest version!
/*
 * 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 androidx.constraintlayout.core.motion

import androidx.constraintlayout.utility.Utils.pow
import kotlin.jvm.JvmField

/*
 * Copyright (C) 2017 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.
 */ /**
 * Defines non standard Attributes
 *
 * @suppress
 */
class CustomAttribute {
    private var mMethod = false
    @JvmField
    var mName: String
    var type: AttributeType
        private set
    private var mIntegerValue = 0
    private var mFloatValue = 0f
    private var mStringValue: String? = null
    var mBooleanValue = false
    private var mColorValue = 0

    enum class AttributeType {
        INT_TYPE, FLOAT_TYPE, COLOR_TYPE, COLOR_DRAWABLE_TYPE, STRING_TYPE, BOOLEAN_TYPE, DIMENSION_TYPE, REFERENCE_TYPE
    }

    /**
     * Continuous types are interpolated they are fired only at
     *
     * @return
     */
    val isContinuous: Boolean
        get() = when (type) {
            AttributeType.REFERENCE_TYPE, AttributeType.BOOLEAN_TYPE, AttributeType.STRING_TYPE -> false
            else -> true
        }

    fun setFloatValue(value: Float) {
        mFloatValue = value
    }

    fun setColorValue(value: Int) {
        mColorValue = value
    }

    fun setIntValue(value: Int) {
        mIntegerValue = value
    }

    fun setStringValue(value: String?) {
        mStringValue = value
    }

    /**
     * The number of interpolation values that need to be interpolated
     * Typically 1 but 3 for colors.
     *
     * @return Typically 1 but 3 for colors.
     */
    fun numberOfInterpolatedValues(): Int {
        return when (type) {
            AttributeType.COLOR_TYPE, AttributeType.COLOR_DRAWABLE_TYPE -> 4
            else -> 1
        }
    }

    /**
     * Transforms value to a float for the purpose of interpolation
     *
     * @return interpolation value
     */
    val valueToInterpolate: Float
        get() = when (type) {
            AttributeType.INT_TYPE -> mIntegerValue.toFloat()
            AttributeType.FLOAT_TYPE -> mFloatValue
            AttributeType.COLOR_TYPE, AttributeType.COLOR_DRAWABLE_TYPE -> throw RuntimeException(
                "Color does not have a single color to interpolate"
            )
            AttributeType.STRING_TYPE -> throw RuntimeException("Cannot interpolate String")
            AttributeType.BOOLEAN_TYPE -> if (mBooleanValue) 1f else 0f
            AttributeType.DIMENSION_TYPE -> mFloatValue
            else -> Float.NaN
        }

    fun getValuesToInterpolate(ret: FloatArray) {
        when (type) {
            AttributeType.INT_TYPE -> ret[0] = mIntegerValue.toFloat()
            AttributeType.FLOAT_TYPE -> ret[0] = mFloatValue
            AttributeType.COLOR_DRAWABLE_TYPE, AttributeType.COLOR_TYPE -> {
                val a = 0xFF and (mColorValue shr 24)
                val r = 0xFF and (mColorValue shr 16)
                val g = 0xFF and (mColorValue shr 8)
                val b = 0xFF and mColorValue
                val f_r = pow((r / 255.0f).toDouble(), 2.2).toFloat()
                val f_g = pow((g / 255.0f).toDouble(), 2.2).toFloat()
                val f_b = pow((b / 255.0f).toDouble(), 2.2).toFloat()
                ret[0] = f_r
                ret[1] = f_g
                ret[2] = f_b
                ret[3] = a / 255f
            }
            AttributeType.STRING_TYPE -> throw RuntimeException("Color does not have a single color to interpolate")
            AttributeType.BOOLEAN_TYPE -> ret[0] = if (mBooleanValue) 1f else 0f
            AttributeType.DIMENSION_TYPE -> ret[0] = mFloatValue
            else -> {}
        }
    }

    fun setValue(value: FloatArray) {
        when (type) {
            AttributeType.REFERENCE_TYPE, AttributeType.INT_TYPE -> mIntegerValue = value[0]
                .toInt()
            AttributeType.FLOAT_TYPE -> mFloatValue = value[0]
            AttributeType.COLOR_DRAWABLE_TYPE, AttributeType.COLOR_TYPE -> {
                mColorValue = hsvToRgb(value[0], value[1], value[2])
                mColorValue = mColorValue and 0xFFFFFF or (clamp((0xFF * value[3]).toInt()) shl 24)
            }
            AttributeType.STRING_TYPE -> throw RuntimeException("Color does not have a single color to interpolate")
            AttributeType.BOOLEAN_TYPE -> mBooleanValue = value[0] > 0.5
            AttributeType.DIMENSION_TYPE -> mFloatValue = value[0]
            else -> {}
        }
    }

    /**
     * test if the two attributes are different
     *
     * @param CustomAttribute
     * @return
     */
    fun diff(CustomAttribute: CustomAttribute?): Boolean {
        return if (CustomAttribute == null || type != CustomAttribute.type) {
            false
        } else when (type) {
            AttributeType.INT_TYPE, AttributeType.REFERENCE_TYPE -> mIntegerValue == CustomAttribute.mIntegerValue
            AttributeType.FLOAT_TYPE -> mFloatValue == CustomAttribute.mFloatValue
            AttributeType.COLOR_TYPE, AttributeType.COLOR_DRAWABLE_TYPE -> mColorValue == CustomAttribute.mColorValue
            AttributeType.STRING_TYPE -> mIntegerValue == CustomAttribute.mIntegerValue
            AttributeType.BOOLEAN_TYPE -> mBooleanValue == CustomAttribute.mBooleanValue
            AttributeType.DIMENSION_TYPE -> mFloatValue == CustomAttribute.mFloatValue
            else -> false
        }
    }

    constructor(name: String, attributeType: AttributeType) {
        mName = name
        type = attributeType
    }

    constructor(name: String, attributeType: AttributeType, value: Any, method: Boolean) {
        mName = name
        type = attributeType
        mMethod = method
        setValue(value)
    }

    constructor(source: CustomAttribute, value: Any) {
        mName = source.mName
        type = source.type
        setValue(value)
    }

    fun setValue(value: Any) {
        when (type) {
            AttributeType.REFERENCE_TYPE, AttributeType.INT_TYPE -> mIntegerValue = value as Int
            AttributeType.FLOAT_TYPE -> mFloatValue = value as Float
            AttributeType.COLOR_TYPE, AttributeType.COLOR_DRAWABLE_TYPE -> mColorValue = value as Int
            AttributeType.STRING_TYPE -> mStringValue = value as String
            AttributeType.BOOLEAN_TYPE -> mBooleanValue = value as Boolean
            AttributeType.DIMENSION_TYPE -> mFloatValue = value as Float
            else -> {}
        }
    }

    companion object {
        private const val TAG = "TransitionLayout"
        fun hsvToRgb(hue: Float, saturation: Float, value: Float): Int {
            val h = (hue * 6).toInt()
            val f = hue * 6 - h
            val p = (0.5f + 255 * value * (1 - saturation)).toInt()
            val q = (0.5f + 255 * value * (1 - f * saturation)).toInt()
            val t = (0.5f + 255 * value * (1 - (1 - f) * saturation)).toInt()
            val v = (0.5f + 255 * value).toInt()
            return when (h) {
                0 -> -0x1000000 or (v shl 16) + (t shl 8) + p
                1 -> -0x1000000 or (q shl 16) + (v shl 8) + p
                2 -> -0x1000000 or (p shl 16) + (v shl 8) + t
                3 -> -0x1000000 or (p shl 16) + (q shl 8) + v
                4 -> -0x1000000 or (t shl 16) + (p shl 8) + v
                5 -> -0x1000000 or (v shl 16) + (p shl 8) + q
                else -> 0
            }
        }

        private fun clamp(c: Int): Int {
            var c = c
            val N = 255
            c = c and (c shr 31).inv()
            c -= N
            c = c and (c shr 31)
            c += N
            return c
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy