diff --git a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt index 03c2d12..7fdbfee 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt @@ -13,6 +13,7 @@ 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 +import net.shadowfacts.cacao.view.button.ToggleButton /** * @author shadowfacts @@ -35,9 +36,9 @@ class TestCacaoScreen: CacaoScreen() { intrinsicContentSize = Size(50.0, 50.0) backgroundColor = Color(0x0000ff) }) - val purple = blue.addSubview(EnumButton(RedstoneMode.HIGH, RedstoneMode.Companion::localize).apply { + val purple = blue.addSubview(ToggleButton(false).apply { handler = { - println("enum button clicked, new value: ${it.value}") + println("enum button clicked, new value: ${it.state}") } }) @@ -47,7 +48,7 @@ class TestCacaoScreen: CacaoScreen() { stack.rightAnchor equalTo 150 purple.centerXAnchor equalTo blue.centerXAnchor purple.centerYAnchor equalTo blue.centerYAnchor - purple.widthAnchor equalTo 50 +// purple.widthAnchor equalTo 50 } layout() diff --git a/src/main/kotlin/net/shadowfacts/cacao/util/MouseButton.kt b/src/main/kotlin/net/shadowfacts/cacao/util/MouseButton.kt index b52e5a7..52c54cc 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/util/MouseButton.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/util/MouseButton.kt @@ -4,14 +4,15 @@ package net.shadowfacts.cacao.util * @author shadowfacts */ enum class MouseButton { - LEFT, RIGHT, MIDDLE; + LEFT, RIGHT, MIDDLE, UNKNOWN; companion object { fun fromMC(button: Int): MouseButton { return when (button) { + 0 -> LEFT 1 -> RIGHT 2 -> MIDDLE - else -> LEFT + else -> UNKNOWN } } } diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/TextureView.kt b/src/main/kotlin/net/shadowfacts/cacao/view/TextureView.kt index 21f114c..155f29a 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/view/TextureView.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/view/TextureView.kt @@ -10,7 +10,7 @@ import net.shadowfacts.cacao.util.Texture * * @author shadowfacts */ -class TextureView(val texture: Texture): View() { +class TextureView(var texture: Texture): View() { override fun drawContent(mouse: Point, delta: Float) { RenderHelper.draw(bounds, texture) diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt b/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt index d250fef..ffd93b8 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/view/button/EnumButton.kt @@ -15,7 +15,7 @@ import net.shadowfacts.cacao.view.Label * @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) { +class EnumButton>(initialValue: E, val localizer: (E) -> String): AbstractButton>(Label(localizer(initialValue))) { private val label: Label get() = content as Label diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/button/ToggleButton.kt b/src/main/kotlin/net/shadowfacts/cacao/view/button/ToggleButton.kt new file mode 100644 index 0000000..1769a77 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/cacao/view/button/ToggleButton.kt @@ -0,0 +1,46 @@ +package net.shadowfacts.cacao.view.button + +import net.minecraft.util.Identifier +import net.shadowfacts.cacao.geometry.Point +import net.shadowfacts.cacao.geometry.Size +import net.shadowfacts.cacao.util.MouseButton +import net.shadowfacts.cacao.util.Texture +import net.shadowfacts.cacao.view.TextureView + +/** + * A button for toggling between on/off states. + * + * @author shadowfacts + * @param initialState Whether the button starts as on or off. + */ +class ToggleButton(initialState: Boolean): AbstractButton(TextureView(if (initialState) ON else OFF).apply { + intrinsicContentSize = Size(19.0, 19.0) +}, padding = 0.0) { + + companion object { + val ON = Texture(Identifier("asmr", "textures/gui/toggle.png"), 0, 0) + val OFF = Texture(Identifier("asmr", "textures/gui/toggle.png"), 0, 19) + } + + private val textureView: TextureView + get() = content as TextureView + + /** + * The button's current on/off state. + * Updating this property updates the button's texture. + */ + var state: Boolean = initialState + set(value) { + field = value + textureView.texture = if (value) ON else OFF + } + + override fun mouseClicked(point: Point, mouseButton: MouseButton) { + if (!disabled && (mouseButton == MouseButton.LEFT || mouseButton == MouseButton.RIGHT)) { + state = !state + } + + super.mouseClicked(point, mouseButton) + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/asmr/textures/gui/toggle.png b/src/main/resources/assets/asmr/textures/gui/toggle.png new file mode 100644 index 0000000..32ca9da Binary files /dev/null and b/src/main/resources/assets/asmr/textures/gui/toggle.png differ diff --git a/src/test/kotlin/net/shadowfacts/cacao/view/button/EnumButtonTests.kt b/src/test/kotlin/net/shadowfacts/cacao/view/button/EnumButtonTests.kt index aa05945..4448b3d 100644 --- a/src/test/kotlin/net/shadowfacts/cacao/view/button/EnumButtonTests.kt +++ b/src/test/kotlin/net/shadowfacts/cacao/view/button/EnumButtonTests.kt @@ -5,9 +5,11 @@ import net.shadowfacts.cacao.geometry.Point import net.shadowfacts.cacao.geometry.Rect import net.shadowfacts.cacao.util.MouseButton import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import java.util.concurrent.CompletableFuture /** * @author shadowfacts @@ -34,60 +36,58 @@ class EnumButtonTests { } @Test - fun testCyclesValues() { - val values = mutableListOf() - window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + fun testHandlerCalled() { + val called = CompletableFuture() + val button = 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) + content.frame = bounds handler = { - values.add(it.value) + called.complete(true) } }) window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) - assertEquals(1, values.size) - assertEquals(MyEnum.TWO, values.last()) + assertTrue(called.getNow(false)) + assertEquals(MyEnum.TWO, button.value) + } + + @Test + fun testCyclesValues() { + val button = window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = bounds + }) + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) - assertEquals(2, values.size) - assertEquals(MyEnum.THREE, values.last()) + assertEquals(MyEnum.TWO, button.value) window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) - assertEquals(3, values.size) - assertEquals(MyEnum.ONE, values.last()) + assertEquals(MyEnum.THREE, button.value) + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertEquals(MyEnum.ONE, button.value) } @Test fun testCyclesValuesBackwards() { - val values = mutableListOf() - window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + val button = 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()) + assertEquals(MyEnum.TWO, button.value) window.mouseClicked(Point(5.0, 5.0), MouseButton.RIGHT) - assertEquals(2, values.size) - assertEquals(MyEnum.ONE, values.last()) + assertEquals(MyEnum.ONE, button.value) } @Test fun testMiddleClickDoesNotChangeValue() { - val values = mutableListOf() - window.addView(EnumButton(MyEnum.ONE, MyEnum::name).apply { + val button = 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()) + assertEquals(MyEnum.ONE, button.value) } } \ No newline at end of file diff --git a/src/test/kotlin/net/shadowfacts/cacao/view/button/ToggleButtonTests.kt b/src/test/kotlin/net/shadowfacts/cacao/view/button/ToggleButtonTests.kt new file mode 100644 index 0000000..a3e06c0 --- /dev/null +++ b/src/test/kotlin/net/shadowfacts/cacao/view/button/ToggleButtonTests.kt @@ -0,0 +1,72 @@ +package net.shadowfacts.cacao.view.button + +import net.shadowfacts.cacao.Window +import net.shadowfacts.cacao.geometry.Point +import net.shadowfacts.cacao.geometry.Rect +import net.shadowfacts.cacao.util.MouseButton +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import java.util.concurrent.CompletableFuture + +/** + * @author shadowfacts + */ +class ToggleButtonTests { + + companion object { + @BeforeAll + @JvmStatic + fun setupAll() { + System.setProperty("cacao.drawing.disabled", "true") + } + } + + lateinit var window: Window + + @BeforeEach + fun setup() { + window = Window() + } + + @Test + fun testHandlerCalled() { + val called = CompletableFuture() + val button = window.addView(ToggleButton(false).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = bounds + handler = { + called.complete(true) + } + }) + + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertTrue(called.getNow(false)) + } + + @Test + fun testTogglesValues() { + val button = window.addView(ToggleButton(false).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = bounds + }) + + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertTrue(button.state) + window.mouseClicked(Point(5.0, 5.0), MouseButton.LEFT) + assertFalse(button.state) + } + + @Test + fun testMiddleClickDoesNotChangeValue() { + val button = window.addView(ToggleButton(false).apply { + frame = Rect(0.0, 0.0, 25.0, 25.0) + content.frame = bounds + }) + + window.mouseClicked(Point(5.0, 5.0), MouseButton.MIDDLE) + assertFalse(button.state) + } + +} \ No newline at end of file