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

commonMain.androidx.constraintlayout.compose.MotionRenderDebug.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.compose
/*

import android.graphics.*
import androidx.constraintlayout.core.motion.Motion
import androidx.constraintlayout.core.motion.MotionPaths

internal class MotionRenderDebug(textSize: Float) {
    var mPoints: FloatArray? = null
    var mPathMode: IntArray
    var mKeyFramePoints: FloatArray
    var mPath: Path? = null
    var mPaint: Paint
    var mPaintKeyframes: Paint
    var mPaintGraph: Paint
    var mTextPaint: Paint
    var mFillPaint: Paint
    private val mRectangle: FloatArray
    val RED_COLOR = -0x55cd
    val KEYFRAME_COLOR = -0x1f8a66
    val GRAPH_COLOR = -0xcc5600
    val SHADOW_COLOR = 0x77000000
    val DIAMOND_SIZE = 10
    var mDashPathEffect: DashPathEffect
    var mKeyFrameCount = 0
    var mBounds = Rect()
    var mPresentationMode = false
    var mShadowTranslate = 1
    fun draw(
        canvas: Canvas,
        frameArrayList: HashMap?,
        duration: Int, debugPath: Int,
        layoutWidth: Int, layoutHeight: Int
    ) {
        if (frameArrayList == null || frameArrayList.size == 0) {
            return
        }
        canvas.save()
        for (motionController in frameArrayList.values) {
            draw(
                canvas, motionController, duration, debugPath,
                layoutWidth, layoutHeight
            )
        }
        canvas.restore()
    }

    fun draw(
        canvas: Canvas,
        motionController: Motion,
        duration: Int, debugPath: Int,
        layoutWidth: Int, layoutHeight: Int
    ) {
        var mode = motionController.drawPath
        if (debugPath > 0 && mode == Motion.DRAW_PATH_NONE) {
            mode = Motion.DRAW_PATH_BASIC
        }
        if (mode == Motion.DRAW_PATH_NONE) { // do not draw path
            return
        }
        mKeyFrameCount = motionController.buildKeyFrames(mKeyFramePoints, mPathMode, null)
        if (mode >= Motion.DRAW_PATH_BASIC) {
            val frames = duration / DEBUG_PATH_TICKS_PER_MS
            if (mPoints == null || mPoints!!.size != frames * 2) {
                mPoints = FloatArray(frames * 2)
                mPath = Path()
            }
            canvas.translate(mShadowTranslate.toFloat(), mShadowTranslate.toFloat())
            mPaint.color = SHADOW_COLOR
            mFillPaint.color = SHADOW_COLOR
            mPaintKeyframes.color = SHADOW_COLOR
            mPaintGraph.color = SHADOW_COLOR
            motionController.buildPath(mPoints!!, frames)
            drawAll(canvas, mode, mKeyFrameCount, motionController, layoutWidth, layoutHeight)
            mPaint.color = RED_COLOR
            mPaintKeyframes.color = KEYFRAME_COLOR
            mFillPaint.color = KEYFRAME_COLOR
            mPaintGraph.color = GRAPH_COLOR
            canvas.translate(-mShadowTranslate.toFloat(), -mShadowTranslate.toFloat())
            drawAll(canvas, mode, mKeyFrameCount, motionController, layoutWidth, layoutHeight)
            if (mode == Motion.DRAW_PATH_RECTANGLE) {
                drawRectangle(canvas, motionController)
            }
        }
    }

    fun drawAll(
        canvas: Canvas, mode: Int, keyFrames: Int, motionController: Motion,
        layoutWidth: Int, layoutHeight: Int
    ) {
        if (mode == Motion.DRAW_PATH_AS_CONFIGURED) {
            drawPathAsConfigured(canvas)
        }
        if (mode == Motion.DRAW_PATH_RELATIVE) {
            drawPathRelative(canvas)
        }
        if (mode == Motion.DRAW_PATH_CARTESIAN) {
            drawPathCartesian(canvas)
        }
        drawBasicPath(canvas)
        drawTicks(canvas, mode, keyFrames, motionController, layoutWidth, layoutHeight)
    }

    private fun drawBasicPath(canvas: Canvas) {
        canvas.drawLines(mPoints!!, mPaint)
    }

    private fun drawTicks(
        canvas: Canvas, mode: Int, keyFrames: Int, motionController: Motion,
        layoutWidth: Int, layoutHeight: Int
    ) {
        var viewWidth = 0
        var viewHeight = 0
        if (motionController.view != null) {
            viewWidth = motionController.view!!.width
            viewHeight = motionController.view!!.height
        }
        for (i in 1 until keyFrames - 1) {
            if (mode == Motion.DRAW_PATH_AS_CONFIGURED
                && mPathMode[i - 1] == Motion.DRAW_PATH_NONE
            ) {
                continue
            }
            val x = mKeyFramePoints[i * 2]
            val y = mKeyFramePoints[i * 2 + 1]
            mPath!!.reset()
            mPath!!.moveTo(x, y + DIAMOND_SIZE)
            mPath!!.lineTo(x + DIAMOND_SIZE, y)
            mPath!!.lineTo(x, y - DIAMOND_SIZE)
            mPath!!.lineTo(x - DIAMOND_SIZE, y)
            mPath!!.close()
            val framePoint = motionController.getKeyFrame(i - 1)
            val dx = 0f //framePoint.translationX;
            val dy = 0f //framePoint.translationY;
            if (mode == Motion.DRAW_PATH_AS_CONFIGURED) {
                if (mPathMode[i - 1] == MotionPaths.PERPENDICULAR) {
                    drawPathRelativeTicks(canvas, x - dx, y - dy)
                } else if (mPathMode[i - 1] == MotionPaths.CARTESIAN) {
                    drawPathCartesianTicks(canvas, x - dx, y - dy)
                } else if (mPathMode[i - 1] == MotionPaths.SCREEN) {
                    drawPathScreenTicks(canvas, x - dx, y - dy, viewWidth, viewHeight, layoutWidth, layoutHeight)
                }
                canvas.drawPath(mPath!!, mFillPaint)
            }
            if (mode == Motion.DRAW_PATH_RELATIVE) {
                drawPathRelativeTicks(canvas, x - dx, y - dy)
            }
            if (mode == Motion.DRAW_PATH_CARTESIAN) {
                drawPathCartesianTicks(canvas, x - dx, y - dy)
            }
            if (mode == Motion.DRAW_PATH_SCREEN) {
                drawPathScreenTicks(canvas, x - dx, y - dy, viewWidth, viewHeight, layoutWidth, layoutHeight)
            }
            if (dx != 0f || dy != 0f) {
                drawTranslation(canvas, x - dx, y - dy, x, y)
            } else {
                canvas.drawPath(mPath!!, mFillPaint)
            }
        }
        if (mPoints!!.size > 1) {
            // Draw the starting and ending circle
            canvas.drawCircle(mPoints!![0], mPoints!![1], 8f, mPaintKeyframes)
            canvas.drawCircle(
                mPoints!![mPoints!!.size - 2],
                mPoints!![mPoints!!.size - 1], 8f, mPaintKeyframes
            )
        }
    }

    private fun drawTranslation(canvas: Canvas, x1: Float, y1: Float, x2: Float, y2: Float) {
        canvas.drawRect(x1, y1, x2, y2, mPaintGraph)
        canvas.drawLine(x1, y1, x2, y2, mPaintGraph)
    }

    private fun drawPathRelative(canvas: Canvas) {
        canvas.drawLine(
            mPoints!![0], mPoints!![1],
            mPoints!![mPoints!!.size - 2], mPoints!![mPoints!!.size - 1], mPaintGraph
        )
    }

    private fun drawPathAsConfigured(canvas: Canvas) {
        var path = false
        var cart = false
        for (i in 0 until mKeyFrameCount) {
            if (mPathMode[i] == MotionPaths.PERPENDICULAR) {
                path = true
            }
            if (mPathMode[i] == MotionPaths.CARTESIAN) {
                cart = true
            }
        }
        if (path) {
            drawPathRelative(canvas)
        }
        if (cart) {
            drawPathCartesian(canvas)
        }
    }

    private fun drawPathRelativeTicks(canvas: Canvas, x: Float, y: Float) {
        val x1 = mPoints!![0]
        val y1 = mPoints!![1]
        val x2 = mPoints!![mPoints!!.size - 2]
        val y2 = mPoints!![mPoints!!.size - 1]
        val dist = Math.hypot((x1 - x2).toDouble(), (y1 - y2).toDouble()).toFloat()
        val t = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / (dist * dist)
        val xp = x1 + t * (x2 - x1)
        val yp = y1 + t * (y2 - y1)
        val path = Path()
        path.moveTo(x, y)
        path.lineTo(xp, yp)
        val len = Math.hypot((xp - x).toDouble(), (yp - y).toDouble()).toFloat()
        val text = "" + (100 * len / dist).toInt() / 100.0f
        getTextBounds(text, mTextPaint)
        val off = len / 2 - mBounds.width() / 2
        canvas.drawTextOnPath(text, path, off, -20f, mTextPaint)
        canvas.drawLine(x, y, xp, yp, mPaintGraph)
    }

    fun getTextBounds(text: String, paint: Paint) {
        paint.getTextBounds(text, 0, text.length, mBounds)
    }

    private fun drawPathCartesian(canvas: Canvas) {
        val x1 = mPoints!![0]
        val y1 = mPoints!![1]
        val x2 = mPoints!![mPoints!!.size - 2]
        val y2 = mPoints!![mPoints!!.size - 1]
        canvas.drawLine(
            Math.min(x1, x2), Math.max(y1, y2),
            Math.max(x1, x2), Math.max(y1, y2), mPaintGraph
        )
        canvas.drawLine(
            Math.min(x1, x2), Math.min(y1, y2),
            Math.min(x1, x2), Math.max(y1, y2), mPaintGraph
        )
    }

    private fun drawPathCartesianTicks(canvas: Canvas, x: Float, y: Float) {
        val x1 = mPoints!![0]
        val y1 = mPoints!![1]
        val x2 = mPoints!![mPoints!!.size - 2]
        val y2 = mPoints!![mPoints!!.size - 1]
        val minx = Math.min(x1, x2)
        val maxy = Math.max(y1, y2)
        val xgap = x - Math.min(x1, x2)
        val ygap = Math.max(y1, y2) - y
        // Horizontal line
        var text = "" + (0.5 + 100 * xgap / Math.abs(x2 - x1)).toInt() / 100.0f
        getTextBounds(text, mTextPaint)
        var off = xgap / 2 - mBounds.width() / 2
        canvas.drawText(text, off + minx, y - 20, mTextPaint)
        canvas.drawLine(
            x, y,
            Math.min(x1, x2), y, mPaintGraph
        )

        // Vertical line
        text = "" + (0.5 + 100 * ygap / Math.abs(y2 - y1)).toInt() / 100.0f
        getTextBounds(text, mTextPaint)
        off = ygap / 2 - mBounds.height() / 2
        canvas.drawText(text, x + 5, maxy - off, mTextPaint)
        canvas.drawLine(
            x, y,
            x, Math.max(y1, y2), mPaintGraph
        )
    }

    private fun drawPathScreenTicks(
        canvas: Canvas, x: Float, y: Float, viewWidth: Int, viewHeight: Int,
        layoutWidth: Int, layoutHeight: Int
    ) {
        val x1 = 0f
        val y1 = 0f
        val x2 = 1f
        val y2 = 1f
        val minx = 0f
        val maxy = 0f
        // Horizontal line
        var text = "" + (0.5 + 100 * (x - viewWidth / 2) / (layoutWidth - viewWidth)).toInt() / 100.0f
        getTextBounds(text, mTextPaint)
        var off = x / 2 - mBounds.width() / 2
        canvas.drawText(text, off + minx, y - 20, mTextPaint)
        canvas.drawLine(
            x, y,
            Math.min(x1, x2), y, mPaintGraph
        )

        // Vertical line
        text = "" + (0.5 + 100 * (y - viewHeight / 2) / (layoutHeight - viewHeight)).toInt() / 100.0f
        getTextBounds(text, mTextPaint)
        off = y / 2 - mBounds.height() / 2
        canvas.drawText(text, x + 5, maxy - off, mTextPaint)
        canvas.drawLine(
            x, y,
            x, Math.max(y1, y2), mPaintGraph
        )
    }

    private fun drawRectangle(canvas: Canvas, motionController: Motion) {
        mPath!!.reset()
        val rectFrames = 50
        for (i in 0..rectFrames) {
            val p = i / rectFrames.toFloat()
            motionController.buildRect(p, mRectangle, 0)
            mPath!!.moveTo(mRectangle[0], mRectangle[1])
            mPath!!.lineTo(mRectangle[2], mRectangle[3])
            mPath!!.lineTo(mRectangle[4], mRectangle[5])
            mPath!!.lineTo(mRectangle[6], mRectangle[7])
            mPath!!.close()
        }
        mPaint.color = 0x44000000
        canvas.translate(2f, 2f)
        canvas.drawPath(mPath!!, mPaint)
        canvas.translate(-2f, -2f)
        mPaint.color = -0x10000
        canvas.drawPath(mPath!!, mPaint)
    }

    companion object {
        const val DEBUG_SHOW_NONE = 0
        const val DEBUG_SHOW_PROGRESS = 1
        const val DEBUG_SHOW_PATH = 2
        const val MAX_KEY_FRAMES = 50
        private const val DEBUG_PATH_TICKS_PER_MS = 16
    }

    init {
        mPaint = Paint()
        mPaint.isAntiAlias = true
        mPaint.color = RED_COLOR
        mPaint.strokeWidth = 2f
        mPaint.style = Paint.Style.STROKE
        mPaintKeyframes = Paint()
        mPaintKeyframes.isAntiAlias = true
        mPaintKeyframes.color = KEYFRAME_COLOR
        mPaintKeyframes.strokeWidth = 2f
        mPaintKeyframes.style = Paint.Style.STROKE
        mPaintGraph = Paint()
        mPaintGraph.isAntiAlias = true
        mPaintGraph.color = GRAPH_COLOR
        mPaintGraph.strokeWidth = 2f
        mPaintGraph.style = Paint.Style.STROKE
        mTextPaint = Paint()
        mTextPaint.isAntiAlias = true
        mTextPaint.color = GRAPH_COLOR
        mTextPaint.textSize = textSize
        mRectangle = FloatArray(8)
        mFillPaint = Paint()
        mFillPaint.isAntiAlias = true
        mDashPathEffect = DashPathEffect(floatArrayOf(4f, 8f), 0f)
        mPaintGraph.pathEffect = mDashPathEffect
        mKeyFramePoints = FloatArray(MAX_KEY_FRAMES * 2)
        mPathMode = IntArray(MAX_KEY_FRAMES)
        if (mPresentationMode) {
            mPaint.strokeWidth = 8f
            mFillPaint.strokeWidth = 8f
            mPaintKeyframes.strokeWidth = 8f
            mShadowTranslate = 4
        }
    }
}
 */




© 2015 - 2025 Weber Informatics LLC | Privacy Policy