Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScrollComponent: Add a minimum scrollbar grip size #146

Merged
merged 8 commits into from
Jul 22, 2024
1 change: 1 addition & 0 deletions api/Elementa.api
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public final class gg/essential/elementa/ElementaVersion : java/lang/Enum {
public static final field V3 Lgg/essential/elementa/ElementaVersion;
public static final field V4 Lgg/essential/elementa/ElementaVersion;
public static final field V5 Lgg/essential/elementa/ElementaVersion;
public static final field V6 Lgg/essential/elementa/ElementaVersion;
public final fun enableFor (Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
public static fun valueOf (Ljava/lang/String;)Lgg/essential/elementa/ElementaVersion;
public static fun values ()[Lgg/essential/elementa/ElementaVersion;
Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/gg/essential/elementa/ElementaVersion.kt
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,14 @@ enum class ElementaVersion {
/**
* Change the behavior of scroll components to no longer require holding down shift when horizontal is the only possible scrolling direction.
*/
@Deprecated(DEPRECATION_MESSAGE)
V5,

/**
* [gg.essential.elementa.components.ScrollComponent] now has a minimum size for scrollbar grips.
*/
V6,

;

/**
Expand Down Expand Up @@ -126,7 +132,9 @@ Be sure to read through all the changes between your current version and your ne
internal val v3 = V3
@Suppress("DEPRECATION")
internal val v4 = V4
@Suppress("DEPRECATION")
internal val v5 = V5
internal val v6 = V6


@PublishedApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ScrollComponent constructor(
private val pixelsPerScroll: Float = 15f,
private val scrollAcceleration: Float = 1.0f,
customScissorBoundingBox: UIComponent? = null,
private val passthroughScroll: Boolean = true
private val passthroughScroll: Boolean = true,
) : UIContainer() {
@JvmOverloads constructor(
emptyString: String = "",
Expand All @@ -44,7 +44,7 @@ class ScrollComponent constructor(
verticalScrollOpposite: Boolean = false,
pixelsPerScroll: Float = 15f,
scrollAcceleration: Float = 1.0f,
customScissorBoundingBox: UIComponent? = null
customScissorBoundingBox: UIComponent? = null,
) : this (
emptyString,
innerPadding,
Expand All @@ -59,7 +59,7 @@ class ScrollComponent constructor(
verticalScrollOpposite,
pixelsPerScroll,
scrollAcceleration,
customScissorBoundingBox
customScissorBoundingBox,
)

private val primaryScrollDirection
Expand Down Expand Up @@ -466,10 +466,17 @@ class ScrollComponent constructor(
}
}

val relativeConstraint = RelativeConstraint(clampedPercentage)
val desiredSizeConstraint = if (Window.of(this).version >= ElementaVersion.v6) {
ScrollBarGripMinSizeConstraint(relativeConstraint)
} else {
relativeConstraint
}

if (isHorizontal) {
component.setWidth(RelativeConstraint(clampedPercentage))
component.setWidth(desiredSizeConstraint)
} else {
component.setHeight(RelativeConstraint(clampedPercentage))
component.setHeight(desiredSizeConstraint)
}

component.animate {
Expand Down Expand Up @@ -800,6 +807,48 @@ class ScrollComponent constructor(

}

/**
* Constraints the scrollbar grip's size to be a certain minimum size, or the [desiredSize].
* This is the default constraint for horizontal scrollbar grips if [ElementaVersion.V6] is used.
*
* @param desiredSize The intended size for the scrollbar grip.
*/
private class ScrollBarGripMinSizeConstraint(
private val desiredSize: SizeConstraint
) : SizeConstraint {
override var cachedValue: Float = 0f
override var recalculate: Boolean = true
override var constrainTo: UIComponent? = null

override fun animationFrame() {
super.animationFrame()
desiredSize.animationFrame()
}

override fun getWidthImpl(component: UIComponent): Float {
val parent = component.parent
val minimumWidthPercentage = if (parent.getWidth() < 200) { 0.15f } else { 0.10f }
val minimumWidth = parent.getWidth() * minimumWidthPercentage

return desiredSize.getWidth(component).coerceAtLeast(minimumWidth)
}

override fun getHeightImpl(component: UIComponent): Float {
val parent = component.parent
val minimumHeightPercentage = if (parent.getHeight() < 200) { 0.15f } else { 0.10f }
val minimumHeight = parent.getHeight() * minimumHeightPercentage

return desiredSize.getHeight(component).coerceAtLeast(minimumHeight)
}

override fun visitImpl(visitor: ConstraintVisitor, type: ConstraintType) {
}

override fun getRadiusImpl(component: UIComponent): Float {
throw IllegalStateException("`ScrollBarGripMinSizeConstraint` does not support `getRadiusImpl`.")
}
}

enum class Direction {
Vertical,
Horizontal,
Expand Down
Loading