Skip to content

Commit

Permalink
ScrollComponent: Add a minimum scrollbar grip size
Browse files Browse the repository at this point in the history
Making it easier to grab when there is a lot of content within
the ScrollComponent.

GitHub: #146
  • Loading branch information
caoimhebyrne committed Jul 22, 2024
1 parent 91c492f commit b194e7f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
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

0 comments on commit b194e7f

Please sign in to comment.