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

commonMain.me.saket.telephoto.zoomable.internal.dimens.kt Maven / Gradle / Ivy

The newest version!
package me.saket.telephoto.zoomable.internal

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.isFinite
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.withTransform
import androidx.compose.ui.layout.ScaleFactor
import androidx.compose.ui.layout.times
import androidx.compose.ui.unit.IntSize
import me.saket.telephoto.zoomable.BaseZoomFactor
import me.saket.telephoto.zoomable.ContentZoomFactor
import me.saket.telephoto.zoomable.UserZoomFactor
import kotlin.math.roundToInt

internal fun Size.roundToIntSize() =
  IntSize(width.roundToInt(), height.roundToInt())

internal fun Size.discardFractionalParts(): IntSize {
  return IntSize(width = width.toInt(), height = height.toInt())
}

internal val Size.isSpecifiedAndNonEmpty: Boolean
  get() = isSpecified && !isEmpty()

internal val ScaleFactor.maxScale: Float
  get() = maxOf(scaleX, scaleY)

internal val ScaleFactor.minScale: Float
  get() = minOf(scaleX, scaleY)

internal operator fun ScaleFactor.unaryMinus(): ScaleFactor =
  this * -1f

internal val ScaleFactor.Companion.Zero
  get() = ScaleFactor(0f, 0f)

internal fun ScaleFactor.isPositiveAndFinite(): Boolean {
  return scaleX.isPositiveAndFinite() && scaleY.isPositiveAndFinite()
}

internal fun Offset.isSpecifiedAndFinite(): Boolean {
  return isSpecified && isFinite
}

internal fun Float.isPositiveAndFinite(): Boolean {
  return this.isFinite() && this >= 0f
}

internal val TransformOrigin.Companion.Zero
  get() = TransformOrigin(0f, 0f)

internal operator fun Offset.times(factor: ScaleFactor) =
  Offset(x = x * factor.scaleX, y = y * factor.scaleY)

internal operator fun Offset.div(factor: ScaleFactor) =
  Offset(x = x / factor.scaleX, y = y / factor.scaleY)

internal operator fun Offset.div(zoom: ContentZoomFactor): Offset =
  div(zoom.finalZoom())

internal operator fun Offset.times(zoom: ContentZoomFactor): Offset =
  times(zoom.finalZoom())

internal operator fun Size.times(zoom: ContentZoomFactor): Size =
  times(zoom.finalZoom())

internal operator fun UserZoomFactor.times(operand: Float): UserZoomFactor =
  UserZoomFactor(value.times(operand))

internal operator fun BaseZoomFactor.times(factor: UserZoomFactor): ScaleFactor =
  value.times(factor.value)

internal operator fun UserZoomFactor.minus(other: UserZoomFactor): UserZoomFactor {
  return UserZoomFactor(value = value - other.value)
}

internal operator fun UserZoomFactor.div(other: UserZoomFactor): UserZoomFactor {
  return UserZoomFactor(value = value / other.value)
}

internal fun UserZoomFactor.coerceIn(minimumValue: UserZoomFactor, maximumValue: UserZoomFactor): UserZoomFactor {
  return UserZoomFactor(value = value.coerceIn(minimumValue.value, maximumValue.value))
}

/**
 * Call [action] with [zoom] and [translate] applied to this offset. The value
 * generated by [action] is returned by applying the inverse of [translate] and [zoom].
 *
 * The name of this function was inspired from [DrawScope.withTransform].
 */
internal fun Offset.withZoomAndTranslate(
  zoom: ScaleFactor,
  translate: Offset,
  action: (Offset) -> Offset,
): Offset {
  return (action((this * zoom) + translate) - translate) / zoom
}

internal fun Offset.withZoom(
  zoom: ScaleFactor,
  action: (Offset) -> Offset,
): Offset {
  return withZoomAndTranslate(zoom, Offset.Zero, action)
}

internal fun Rect.times(scale: ScaleFactor): Rect =
  Rect(offset = topLeft * scale, size = size * scale)

internal fun Rect.withOrigin(origin: TransformOrigin, action: Rect.() -> Rect): Rect {
  val pivot = Offset(
    x = size.width * origin.pivotFractionX,
    y = size.height * origin.pivotFractionY,
  )
  val atOrigin = this.translate(-pivot)
  val newRect = atOrigin.action()
  return newRect.translate(pivot)
}

internal fun Rect.scaledAndOffsetBy(scale: ScaleFactor, offset: Offset): Rect {
  return Rect(
    left = (left * scale.scaleX) + offset.x,
    right = (right * scale.scaleX) + offset.x,
    top = (top * scale.scaleY) + offset.y,
    bottom = (bottom * scale.scaleY) + offset.y,
  )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy