@@ -2,7 +2,6 @@ package gg.essential.elementa.components
22
33import gg.essential.elementa.ElementaVersion
44import gg.essential.elementa.UIComponent
5- import gg.essential.elementa.components.UpdateFunc
65import gg.essential.elementa.constraints.*
76import gg.essential.elementa.constraints.animation.Animations
87import gg.essential.elementa.constraints.resolution.ConstraintVisitor
@@ -143,7 +142,29 @@ class ScrollComponent constructor(
143142
144143
145144 private val mouseScrollLambda: UIComponent .(UIScrollEvent ) -> Unit = {
146- if (Window .of(this ).version >= ElementaVersion .v5) {
145+ if (Window .of(this ).version >= ElementaVersion .v11) {
146+ // For easier understanding we reframe the provided scroll in terms of primary and secondary directions
147+ // We used to only get vertical scrolls, so that remains as the primary direction
148+ val scrollPrimary = it.scrollY.toFloat()
149+ val scrollSecondary = it.scrollX.toFloat()
150+
151+ // We map the primary and secondary scroll values based on the scroll direction
152+ // `Vertical` and `Horizontal` directions disable the other direction, so we use 0f
153+ val (providedX, providedY) = when (scrollDirection) {
154+ Direction .Vertical -> 0f to scrollPrimary
155+ Direction .Horizontal -> scrollPrimary to 0f
156+ Direction .PreferVertical -> scrollSecondary to scrollPrimary
157+ Direction .PreferHorizontal -> scrollPrimary to scrollSecondary
158+ }
159+
160+ // We swap directions if shift is pressed
161+ val (actualX, actualY) = if (UKeyboard .isShiftKeyDown()) providedY to providedX else providedX to providedY
162+
163+ // Finally, process the scroll with computed values
164+ if (onScroll(actualX, actualY) || ! passthroughScroll) {
165+ it.stopPropagation()
166+ }
167+ } else if (Window .of(this ).version >= ElementaVersion .v5) {
147168 // new behavior
148169 val scrollDirection = if (! UKeyboard .isShiftKeyDown()) primaryScrollDirection else secondaryScrollDirection
149170 if (scrollDirection != null ) {
@@ -207,8 +228,7 @@ class ScrollComponent constructor(
207228
208229 if (needsUpdate) {
209230 needsUpdate = false
210- val horizontalRange = calculateOffsetRange(isHorizontal = true )
211- val verticalRange = calculateOffsetRange(isHorizontal = false )
231+ val (horizontalRange, verticalRange) = calculateOffsetRanges()
212232
213233 // Recalculate our scroll box and move the content inside if needed.
214234 actualHolder.animate {
@@ -317,8 +337,7 @@ class ScrollComponent constructor(
317337 verticalOffset : Float = this.verticalOffset,
318338 smoothScroll : Boolean = true
319339 ) {
320- val horizontalRange = calculateOffsetRange(isHorizontal = true )
321- val verticalRange = calculateOffsetRange(isHorizontal = false )
340+ val (horizontalRange, verticalRange) = calculateOffsetRanges()
322341 this .horizontalOffset =
323342 if (horizontalRange.isEmpty()) innerPadding else horizontalOffset.coerceIn(horizontalRange)
324343 this .verticalOffset = if (verticalRange.isEmpty()) {
@@ -425,13 +444,26 @@ class ScrollComponent constructor(
425444 * @return whether the offset changed
426445 */
427446 private fun onScroll (delta : Float , isHorizontal : Boolean ): Boolean {
447+ return if (isHorizontal) onScroll(delta, 0f ) else onScroll(0f , delta)
448+ }
449+
450+ /* *
451+ * @return whether either offset changed
452+ */
453+ private fun onScroll (scrollX : Float , scrollY : Float ): Boolean {
428454 var changed = false
429- val offset = if (isHorizontal) ::horizontalOffset else ::verticalOffset
430- val range = calculateOffsetRange(isHorizontal)
431- val newOffset = if (range.isEmpty()) innerPadding else (offset.get() + delta * pixelsPerScroll * currentScrollAcceleration).coerceIn(range)
432- if (newOffset != offset.get()) {
455+ val offsetX = ::horizontalOffset
456+ val offsetY = ::verticalOffset
457+ val (rangeX, rangeY) = calculateOffsetRanges()
458+ val newOffsetX = if (rangeX.isEmpty()) innerPadding else (offsetX.get() + scrollX * pixelsPerScroll * currentScrollAcceleration).coerceIn(rangeX)
459+ if (newOffsetX != offsetX.get()) {
433460 changed = true
434- offset.set(newOffset)
461+ offsetX.set(newOffsetX)
462+ }
463+ val newOffsetY = if (rangeY.isEmpty()) innerPadding else (offsetY.get() + scrollY * pixelsPerScroll * currentScrollAcceleration).coerceIn(rangeY)
464+ if (newOffsetY != offsetY.get()) {
465+ changed = true
466+ offsetY.set(newOffsetY)
435467 }
436468
437469 currentScrollAcceleration =
@@ -511,16 +543,16 @@ class ScrollComponent constructor(
511543 }
512544 }
513545
514- private fun calculateOffsetRange ( isHorizontal : Boolean ): ClosedFloatingPointRange <Float > {
515- return if (isHorizontal) {
516- val actualWidth = calculateActualWidth()
517- val maxNegative = this .getWidth() - actualWidth - innerPadding
518- if (horizontalScrollOpposite) ( - innerPadding) .. - maxNegative else maxNegative .. (innerPadding)
519- } else {
520- val actualHeight = calculateActualHeight()
521- val maxNegative = this .getHeight() - actualHeight - innerPadding
522- if (verticalScrollOpposite) ( - innerPadding) .. - maxNegative else maxNegative .. (innerPadding)
523- }
546+ private fun calculateOffsetRanges ( ): Pair < ClosedFloatingPointRange <Float >, ClosedFloatingPointRange<Float> > {
547+ val actualWidth = calculateActualWidth()
548+ val maxNegativeWidth = this .getWidth() - actualWidth - innerPadding
549+ val rangeX = if (horizontalScrollOpposite) ( - innerPadding) .. - maxNegativeWidth else maxNegativeWidth .. ( innerPadding)
550+
551+ val actualHeight = calculateActualHeight()
552+ val maxNegativeHeight = this .getHeight() - actualHeight - innerPadding
553+ val rangeY = if (verticalScrollOpposite) ( - innerPadding) .. - maxNegativeHeight else maxNegativeHeight .. ( innerPadding)
554+
555+ return rangeX to rangeY
524556 }
525557
526558 private fun onClick (mouseX : Float , mouseY : Float , mouseButton : Int ) {
0 commit comments