diff --git a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt index 6f9ae7a..03c2d12 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt @@ -1,6 +1,7 @@ package net.shadowfacts.asmr import net.minecraft.util.Identifier +import net.shadowfacts.asmr.util.RedstoneMode import net.shadowfacts.kiwidsl.dsl import net.shadowfacts.cacao.CacaoScreen import net.shadowfacts.cacao.Window @@ -11,6 +12,7 @@ import net.shadowfacts.cacao.util.NinePatchTexture import net.shadowfacts.cacao.util.Texture import net.shadowfacts.cacao.view.* import net.shadowfacts.cacao.view.button.Button +import net.shadowfacts.cacao.view.button.EnumButton /** * @author shadowfacts @@ -33,11 +35,9 @@ class TestCacaoScreen: CacaoScreen() { intrinsicContentSize = Size(50.0, 50.0) backgroundColor = Color(0x0000ff) }) - val purple = blue.addSubview(Button(Label("Hello, button!").apply { - textColor = Color.WHITE - }).apply { + val purple = blue.addSubview(EnumButton(RedstoneMode.HIGH, RedstoneMode.Companion::localize).apply { handler = { - println("$it clicked!") + println("enum button clicked, new value: ${it.value}") } }) @@ -47,6 +47,7 @@ class TestCacaoScreen: CacaoScreen() { stack.rightAnchor equalTo 150 purple.centerXAnchor equalTo blue.centerXAnchor purple.centerYAnchor equalTo blue.centerYAnchor + purple.widthAnchor equalTo 50 } layout() diff --git a/src/main/kotlin/net/shadowfacts/asmr/util/RedstoneMode.kt b/src/main/kotlin/net/shadowfacts/asmr/util/RedstoneMode.kt new file mode 100644 index 0000000..152c22b --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/asmr/util/RedstoneMode.kt @@ -0,0 +1,14 @@ +package net.shadowfacts.asmr.util + +/** + * @author shadowfacts + */ +enum class RedstoneMode { + HIGH, LOW, TOGGLE; + + companion object { + fun localize(value: RedstoneMode): String { + return value.name.toLowerCase().capitalize() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/cacao/util/RenderHelper.kt b/src/main/kotlin/net/shadowfacts/cacao/util/RenderHelper.kt index c2c77c9..b282ae4 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/util/RenderHelper.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/util/RenderHelper.kt @@ -15,7 +15,7 @@ import net.shadowfacts.cacao.geometry.Rect */ object RenderHelper { - private val disabled = (System.getProperty("cacao.drawing.disabled") ?: "false").toBoolean() + val disabled = (System.getProperty("cacao.drawing.disabled") ?: "false").toBoolean() // TODO: find a better place for this fun playSound(event: SoundEvent) { diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/Label.kt b/src/main/kotlin/net/shadowfacts/cacao/view/Label.kt index 17130c1..ea623e4 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/view/Label.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/view/Label.kt @@ -5,6 +5,7 @@ import net.minecraft.client.font.TextRenderer import net.shadowfacts.cacao.geometry.Point import net.shadowfacts.cacao.geometry.Size import net.shadowfacts.cacao.util.Color +import net.shadowfacts.cacao.util.RenderHelper /** * A simple View that displays text. Allows for controlling the color and shadow of the text. Label cannot be used @@ -29,7 +30,7 @@ class Label(text: String): View() { updateIntrinsicContentSize() } - var textColor = Color(0x404040) + var textColor = Color.WHITE override fun wasAdded() { super.wasAdded() @@ -38,6 +39,8 @@ class Label(text: String): View() { } private fun updateIntrinsicContentSize() { + if (RenderHelper.disabled) return + val width = textRenderer.getStringWidth(text) val height = textRenderer.fontHeight intrinsicContentSize = Size(width.toDouble(), height.toDouble()) diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/button/AbstractButton.kt b/src/main/kotlin/net/shadowfacts/cacao/view/button/AbstractButton.kt index 6abab16..09c67c0 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/view/button/AbstractButton.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/view/button/AbstractButton.kt @@ -126,7 +126,7 @@ abstract class AbstractButton>(val content: View, val @Suppress("UNCHECKED_CAST") handler(this as Impl) - if (clickSoundEnabled) { + if (clickSoundEnabled && !RenderHelper.disabled) { RenderHelper.playSound(SoundEvents.UI_BUTTON_CLICK) } } diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt b/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt new file mode 100644 index 0000000..d250fef --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt @@ -0,0 +1,45 @@ +package net.shadowfacts.cacao.view.button + +import net.shadowfacts.cacao.geometry.Point +import net.shadowfacts.cacao.util.EnumHelper +import net.shadowfacts.cacao.util.MouseButton +import net.shadowfacts.cacao.view.Label + +/** + * A button that cycles through enum values. + * Left click: forwards + * Right click: backwards + * All other mouse buttons call the handler with the unchanged value + * + * @author shadowfacts + * @param initialValue The initial enum value for this button. + * @param localizer A function that takes an enum value and converts into a string for the button's label. + */ +class EnumButton>(initialValue: E, val localizer: (E) -> String, padding: Double = 4.0): AbstractButton>(Label(localizer(initialValue)), padding) { + + private val label: Label + get() = content as Label + + /** + * The current value of the enum button. + * Updating this property will use the [localizer] to update the label. + */ + var value: E = initialValue + set(value) { + field = value + label.text = localizer(value) + } + + override fun mouseClicked(point: Point, mouseButton: MouseButton) { + if (!disabled) { + value = when (mouseButton) { + MouseButton.LEFT -> EnumHelper.next(value) + MouseButton.RIGHT -> EnumHelper.previous(value) + else -> value + } + } + + super.mouseClicked(point, mouseButton) + } + +} \ No newline at end of file diff --git a/src/test/kotlin/net/shadowfacts/cacao/view/EnumButtonTests.kt b/src/test/kotlin/net/shadowfacts/cacao/view/EnumButtonTests.kt new file mode 100644 index 0000000..9aff795 --- /dev/null +++ b/src/test/kotlin/net/shadowfacts/cacao/view/EnumButtonTests.kt @@ -0,0 +1,95 @@ +package net.shadowfacts.cacao.view + +import net.shadowfacts.cacao.Window +import net.shadowfacts.cacao.geometry.Point +import net.shadowfacts.cacao.geometry.Rect +import net.shadowfacts.cacao.util.MouseButton +import net.shadowfacts.cacao.view.button.EnumButton +import net.shadowfacts.kiwidsl.dsl +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +/** + * @author shadowfacts + */ +class EnumButtonTests { + + companion object { + @BeforeAll + @JvmStatic + fun setupAll() { + System.setProperty("cacao.drawing.disabled", "true") + } + } + + enum class MyEnum { + ONE, TWO, THREE + } + + lateinit var window: Window + + @BeforeEach + fun setup() { + window = Window() + } + + @Test + fun testCyclesValues() { + val values = mutableListOf() + window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = Rect(0.0, 0.0, 25.0, 25.0) + handler = { + values.add(it.value) + } + }) + + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertEquals(1, values.size) + assertEquals(MyEnum.TWO, values.last()) + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertEquals(2, values.size) + assertEquals(MyEnum.THREE, values.last()) + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertEquals(3, values.size) + assertEquals(MyEnum.ONE, values.last()) + } + + @Test + fun testCyclesValuesBackwards() { + val values = mutableListOf() + window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = Rect(0.0, 0.0, 25.0, 25.0) + handler = { + values.add(it.value) + } + }) + + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertEquals(1, values.size) + assertEquals(MyEnum.TWO, values.last()) + window.mouseClicked(Point(5.0, 5.0), MouseButton.RIGHT) + assertEquals(2, values.size) + assertEquals(MyEnum.ONE, values.last()) + } + + @Test + fun testMiddleClickDoesNotChangeValue() { + val values = mutableListOf() + window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = Rect(0.0, 0.0, 25.0, 25.0) + handler = { + values.add(it.value) + } + }) + + window.mouseClicked(Point(5.0, 5.0), MouseButton.MIDDLE) + assertEquals(1, values.size) + assertEquals(MyEnum.ONE, values.last()) + } + +} \ No newline at end of file