Skip to content

Commit 6d7a6cd

Browse files
committed
feature: DropdownButton now scrolls instead of overflowing when the options don't fit on the screen
1 parent 5871da7 commit 6d7a6cd

File tree

4 files changed

+57
-12
lines changed

4 files changed

+57
-12
lines changed

api/src/main/kotlin/com/noxcrew/sheeplib/DialogContainer.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ public object DialogContainer : ContainerEventHandler, NarratableEntry, Renderab
124124
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean =
125125
children.value.lastOrNull { it.mouseDragged(d, e, i, f, g) } != null
126126

127+
override fun mouseScrolled(d: Double, e: Double, f: Double, g: Double): Boolean =
128+
children.value.lastOrNull { it.mouseScrolled(d, e, f, g) } != null
129+
130+
127131
override fun isDragging(): Boolean = isDragging
128132

129133
override fun setDragging(bl: Boolean) {

api/src/main/kotlin/com/noxcrew/sheeplib/dialog/Dialog.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ public abstract class Dialog(
185185
return true
186186
}
187187

188+
override fun mouseScrolled(d: Double, e: Double, f: Double, g: Double): Boolean {
189+
if (popup?.mouseScrolled(d, e, f, g) == true) return true
190+
return super.mouseScrolled(d, e, f, g)
191+
}
192+
188193
/**
189194
* Renders the widget's background.
190195
* The default implementation renders an opaque [Theme.Colors.dialogBackground] background with a
@@ -229,7 +234,7 @@ public abstract class Dialog(
229234
popup?.render(graphics, i, j, f)
230235
}
231236

232-
protected companion object {
237+
internal companion object {
233238
public const val BOTTOM_EDGE_DEAD_ZONE: Int = 20
234239
private const val POPUP_FOCUSED_OPACITY = 0.7f
235240
}

api/src/main/kotlin/com/noxcrew/sheeplib/widget/DropdownButton.kt

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import com.noxcrew.sheeplib.theme.Themed
77
import com.noxcrew.sheeplib.util.withOuterPadding
88
import net.minecraft.client.Minecraft
99
import net.minecraft.client.gui.GuiGraphics
10+
import net.minecraft.client.gui.components.StringWidget
1011
import net.minecraft.client.gui.layouts.Layout
1112
import net.minecraft.client.gui.layouts.LinearLayout
1213
import net.minecraft.network.chat.Component
14+
import kotlin.math.roundToInt
15+
import kotlin.math.sign
1316

1417
/**
1518
* A dropdown button widget that displays a list of options in a popup dialog.
@@ -87,21 +90,44 @@ public class DropdownButton<T : Any>(
8790
init()
8891
}
8992

93+
private var scroll = 0
94+
private var pageSize = 0
95+
96+
override fun renderBackground(graphics: GuiGraphics) {
97+
if (pageSize >= options.size) return
98+
val scrollbarHeight = (height * pageSize.toFloat() / options.size).roundToInt()
99+
val scrollbarY = y + ((height - scrollbarHeight) * scroll / (options.size - pageSize))
100+
101+
graphics.fill(
102+
x + width + 1,
103+
scrollbarY,
104+
x + width + 2,
105+
scrollbarY + scrollbarHeight,
106+
theme.colors.textSecondary
107+
)
108+
}
90109

91110
override fun layout(): Layout {
92111
val buttonHeight = Minecraft.getInstance().font.lineHeight + 3
93-
this@SelectionPopup.height = buttonHeight * options.size
112+
pageSize = (Minecraft.getInstance().window.guiScaledHeight - BOTTOM_EDGE_DEAD_ZONE) / buttonHeight
113+
114+
this@SelectionPopup.height = buttonHeight * options.size.coerceAtMost(pageSize)
115+
val isScrolling = options.size > pageSize
94116

95117
return linear(LinearLayout.Orientation.VERTICAL) {
96-
options.forEach {
97-
ThemedButton(
98-
displayMapper(it),
99-
width = this@DropdownButton.width,
100-
height = buttonHeight,
101-
) {
102-
select(it)
103-
}.add(LayoutConstants.CENTRE)
104-
}
118+
options
119+
.let {
120+
if (isScrolling) it.drop(scroll).take(pageSize) else it
121+
}
122+
.forEach {
123+
ThemedButton(
124+
displayMapper(it),
125+
width = this@DropdownButton.width,
126+
height = buttonHeight,
127+
) {
128+
select(it)
129+
}.add(LayoutConstants.LEFT)
130+
}
105131
}
106132
}
107133

@@ -117,5 +143,15 @@ public class DropdownButton<T : Any>(
117143
}
118144
return super.mouseClicked(d, e, i)
119145
}
146+
147+
override fun mouseScrolled(d: Double, e: Double, f: Double, g: Double): Boolean {
148+
if (this@DropdownButton.isHoveredOrFocused) {
149+
val oldScroll = scroll
150+
scroll = (scroll + g.sign.toInt()).coerceIn(0, (options.size - pageSize).coerceAtLeast(0))
151+
if (oldScroll != scroll) init()
152+
return true
153+
}
154+
return super.mouseScrolled(d, e, f, g)
155+
}
120156
}
121157
}

test-mod/src/main/kotlin/com/noxcrew/sheeplib/testmod/ComponentsDialog.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class ComponentsDialog(x: Int, y: Int) : Dialog(x, y), Themed by Theme.Ac
3434

3535
DropdownButton(
3636
this@ComponentsDialog,
37-
(0..10).map { "Dropdown $it" },
37+
(0..100).map { "Dropdown $it" },
3838
displayMapper = Component::literal
3939
).at(4, 0)
4040

0 commit comments

Comments
 (0)