Skip to content

Commit d8bf5da

Browse files
authored
feature: String widget creation functions, MinecraftDispatchers.Main (#40)
1 parent 881e53f commit d8bf5da

File tree

8 files changed

+126
-20
lines changed

8 files changed

+126
-20
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.noxcrew.sheeplib.mixin;
2+
3+
import net.minecraft.client.Minecraft;
4+
import net.minecraft.client.gui.screens.Screen;
5+
import net.minecraft.network.chat.ClickEvent;
6+
import org.jetbrains.annotations.Nullable;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
import org.spongepowered.asm.mixin.gen.Invoker;
9+
10+
@Mixin(Screen.class)
11+
public interface ScreenAccessor {
12+
@Invoker("defaultHandleGameClickEvent")
13+
public static void sheeplib$defaultHandleGameClickEvent(ClickEvent clickEvent, Minecraft minecraft, @Nullable Screen screen) {
14+
throw new AssertionError();
15+
}
16+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.noxcrew.sheeplib.widget
2+
3+
import com.noxcrew.sheeplib.mixin.ScreenAccessor
4+
import net.minecraft.client.Minecraft
5+
import net.minecraft.client.gui.Font
6+
import net.minecraft.client.gui.components.AbstractStringWidget
7+
import net.minecraft.client.gui.components.MultiLineTextWidget
8+
import net.minecraft.client.gui.components.StringWidget
9+
import net.minecraft.network.chat.Component
10+
import net.minecraft.network.chat.Style
11+
import java.util.function.Consumer
12+
13+
/**
14+
* Utilities for creating text widgets.
15+
*/
16+
public object TextWidgets {
17+
18+
private val font = Minecraft.getInstance().font
19+
20+
private val clickHandler: Consumer<Style> = Consumer {
21+
val click = it.clickEvent ?: return@Consumer
22+
ScreenAccessor.`sheeplib$defaultHandleGameClickEvent`(
23+
click,
24+
Minecraft.getInstance(),
25+
null,
26+
)
27+
28+
}
29+
30+
/**
31+
* Applies the SheepLib click handler to a widget and sets it to active, so that it can handle click events.
32+
*/
33+
public fun <T : AbstractStringWidget> T.withSheepLibClickHandler(): T = this.apply {
34+
setComponentClickHandler(clickHandler)
35+
active = true
36+
}
37+
38+
/**
39+
* Creates a single-line string widget.
40+
*/
41+
public fun singleLine(
42+
/** The text component to display. */
43+
text: Component,
44+
/** The font to use. Uses Minecraft's default font if not set. */
45+
font: Font = this.font,
46+
/** The maximum width of the widget. Defaults to [Int.MAX_VALUE]. */
47+
maxWidth: Int = Int.MAX_VALUE,
48+
/** How strings that are too long to fit should be handled. Defaults to [StringWidget.TextOverflow.CLAMPED]. */
49+
overflow: StringWidget.TextOverflow = StringWidget.TextOverflow.CLAMPED
50+
): StringWidget = StringWidget(text, font).apply {
51+
withSheepLibClickHandler()
52+
setMaxWidth(maxWidth, overflow)
53+
}
54+
55+
public fun multiLine(
56+
/** The text component to display. */
57+
text: Component,
58+
/** The font to use. Uses Minecraft's default font if not set. */
59+
font: Font = this.font,
60+
/** The widget's X coordinate. Defaults to 0. */
61+
x: Int = 0,
62+
/** The widget's Y coordinate. Defaults to 0. */
63+
y: Int = 0,
64+
/** Whether the text should be centered vertically. Defaults to false. */
65+
center: Boolean = false,
66+
/** The maximum width of the widget. */
67+
maxWidth: Int? = null,
68+
/** The maximum number of rows that the widget can show. */
69+
maxRows: Int? = null,
70+
): MultiLineTextWidget = MultiLineTextWidget(x, y, text, font).apply {
71+
withSheepLibClickHandler()
72+
setCentered(center)
73+
if (maxWidth != null) setMaxWidth(maxWidth)
74+
if (maxRows != null) setMaxRows(maxRows)
75+
}
76+
}

api/src/main/resources/sheeplib.mixins.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"AbstractWidgetMixin",
55
"ChatScreenMixin",
66
"GuiGraphicsMixin",
7-
"GuiMixin"
7+
"GuiMixin",
8+
"ScreenAccessor"
89
]
910
}

coroutines/src/main/kotlin/com/noxcrew/sheeplib/coroutines/MinecraftDispatchers.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.noxcrew.sheeplib.coroutines
22

33
import kotlinx.coroutines.CoroutineDispatcher
4+
import kotlinx.coroutines.Runnable
45
import kotlinx.coroutines.asCoroutineDispatcher
6+
import net.minecraft.client.Minecraft
57
import net.minecraft.util.Util
8+
import kotlin.coroutines.CoroutineContext
69

710

811
/** Some coroutine dispatchers, backed by Minecraft's own thread pools. */
@@ -13,4 +16,15 @@ public object MinecraftDispatchers {
1316

1417
/** A coroutine dispatcher, backed by [Util.ioPool]. Use this for blocking operations. */
1518
public val IO: CoroutineDispatcher = Util.ioPool().asCoroutineDispatcher()
19+
20+
/**
21+
* A coroutine dispatcher that runs coroutines on the render thread.
22+
*/
23+
public val Main: CoroutineDispatcher = object : CoroutineDispatcher() {
24+
override fun isDispatchNeeded(context: CoroutineContext): Boolean = !Minecraft.getInstance().isSameThread
25+
26+
override fun dispatch(context: CoroutineContext, block: Runnable) {
27+
Minecraft.getInstance().execute(block)
28+
}
29+
}
1630
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import com.noxcrew.sheeplib.theme.Theme
88
import com.noxcrew.sheeplib.theme.Themed
99
import com.noxcrew.sheeplib.widget.DropdownButton
1010
import com.noxcrew.sheeplib.widget.SliderWidget
11+
import com.noxcrew.sheeplib.widget.TextWidgets
1112
import com.noxcrew.sheeplib.widget.ThemedButton
1213
import com.noxcrew.sheeplib.widget.ToggleButton
1314
import net.minecraft.client.Minecraft
14-
import net.minecraft.client.gui.components.StringWidget
1515
import net.minecraft.client.gui.layouts.Layout
1616
import net.minecraft.client.gui.layouts.LinearLayout
1717
import net.minecraft.network.chat.Component
@@ -32,7 +32,7 @@ public class ComponentsDialog(x: Int, y: Int) : Dialog(x, y), Themed by Theme.Ac
3232
defaultAlignment(0.5f)
3333
val font = Minecraft.getInstance().font
3434

35-
+StringWidget(Component.literal("Buttons"), font)
35+
+TextWidgets.singleLine(Component.literal("Buttons"), font)
3636
+ThemedButton(Component.literal("Default")) {}
3737
+ThemedButton(
3838
Component.literal("Positive"),

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import com.noxcrew.sheeplib.coroutines.CoroutineScopeDialog
44
import com.noxcrew.sheeplib.layout.grid
55
import com.noxcrew.sheeplib.theme.DefaultTheme
66
import com.noxcrew.sheeplib.theme.Themed
7+
import com.noxcrew.sheeplib.widget.TextWidgets
78
import kotlinx.coroutines.delay
89
import kotlinx.coroutines.launch
910
import net.minecraft.client.Minecraft
10-
import net.minecraft.client.gui.components.StringWidget
1111
import net.minecraft.client.gui.layouts.Layout
1212
import net.minecraft.network.chat.Component
1313
import kotlin.time.Duration.Companion.seconds
@@ -22,6 +22,6 @@ public class ExceptionCoroutineDialog(x: Int, y: Int) : CoroutineScopeDialog(x,
2222
error("Test exception from the exception coroutine dialog. This is not a bug.")
2323
}
2424

25-
StringWidget(Component.literal("This dialog will error shortly"), Minecraft.getInstance().font).atBottom(0)
25+
TextWidgets.singleLine(Component.literal("This dialog will error shortly"), Minecraft.getInstance().font).atBottom(0)
2626
}
2727
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import com.noxcrew.sheeplib.dialog.title.TextTitleWidget
55
import com.noxcrew.sheeplib.layout.grid
66
import com.noxcrew.sheeplib.theme.Theme
77
import com.noxcrew.sheeplib.theme.Themed
8+
import com.noxcrew.sheeplib.widget.TextWidgets
89
import com.noxcrew.sheeplib.widget.ThemedButton
910
import net.minecraft.client.Minecraft
1011
import net.minecraft.client.gui.components.Button
11-
import net.minecraft.client.gui.components.StringWidget
1212
import net.minecraft.client.gui.layouts.GridLayout
1313
import net.minecraft.network.chat.Component
1414

@@ -23,7 +23,7 @@ public class MyFirstDialog(x: Int, y: Int) : Dialog(x, y), Themed by Theme.Activ
2323

2424
override fun layout(): GridLayout = grid {
2525
// Some static text.
26-
StringWidget(Component.literal("Hello world!"), Minecraft.getInstance().font).at(0, 0)
26+
TextWidgets.singleLine(Component.literal("Hello world!"), Minecraft.getInstance().font).at(0, 0)
2727

2828
// A close button.
2929
ThemedButton(

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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.noxcrew.sheeplib.layout.linear
88
import com.noxcrew.sheeplib.theme.Theme
99
import com.noxcrew.sheeplib.theme.Themed
1010
import com.noxcrew.sheeplib.util.ComponentBuilder
11+
import com.noxcrew.sheeplib.widget.TextWidgets
1112
import net.minecraft.client.Minecraft
1213
import net.minecraft.client.gui.components.MultiLineTextWidget
1314
import net.minecraft.client.gui.components.StringWidget
@@ -22,22 +23,21 @@ public class StringsDialog(x: Int, y: Int) : Dialog(x, y), Themed by Theme.Activ
2223
override val title: DialogTitleWidget = TextTitleWidget(this, literal("Strings"))
2324

2425
override fun layout(): Layout = linear(LinearLayout.Orientation.VERTICAL) {
25-
val font = Minecraft.getInstance().font
26-
27-
+StringWidget(literal("Simple string"), font).setMaxWidth(100)
28-
+StringWidget(literal("CLAMPED Really long string that is too big to fit in the button"), font).setMaxWidth(100)
29-
+StringWidget(literal("SCROLL Really long string that is too big to fit in the button"), font).setMaxWidth(
30-
100,
31-
StringWidget.TextOverflow.SCROLLING
26+
+TextWidgets.singleLine(literal("Simple string"), maxWidth = 100)
27+
+TextWidgets.singleLine(literal("CLAMPED Really long string that is too big to fit in the button"), maxWidth = 100)
28+
+TextWidgets.singleLine(
29+
literal("SCROLL Really long string that is too big to fit in the button"),
30+
maxWidth = 100,
31+
overflow = StringWidget.TextOverflow.SCROLLING
3232
)
3333

34-
+MultiLineTextWidget(literal("Multi line 1\nMulti line 2\nMulti line 3"), font).setMaxWidth(100)
35-
+MultiLineTextWidget(
34+
+TextWidgets.multiLine(literal("Multi line 1\nMulti line 2\nMulti line 3"), maxWidth = 100)
35+
+TextWidgets.multiLine(
3636
literal("Multi line 1\nMulti line 2 but really long, too big to fit\nMulti line 3"),
37-
font
38-
).setMaxWidth(100)
37+
maxWidth = 100
38+
)
3939

40-
+StringWidget(
40+
+TextWidgets.singleLine(
4141
ComponentBuilder.build {
4242
+"literal"
4343
space()
@@ -49,7 +49,6 @@ public class StringsDialog(x: Int, y: Int) : Dialog(x, y), Themed by Theme.Activ
4949
space()
5050
+"literal"
5151
},
52-
font
5352
)
5453
}
5554
}

0 commit comments

Comments
 (0)