From df3523347c1910b384b776eeb1e59dd2a73b9e84 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 23 Jun 2019 22:21:59 -0400 Subject: [PATCH] Add ToggleButton --- .../net/shadowfacts/asmr/TestCacaoScreen.kt | 7 +- .../net/shadowfacts/cacao/util/MouseButton.kt | 5 +- .../net/shadowfacts/cacao/view/TextureView.kt | 2 +- .../cacao/view/button/EnumButton.kt | 2 +- .../cacao/view/button/ToggleButton.kt | 46 +++++++++++ .../assets/asmr/textures/gui/toggle.png | Bin 0 -> 1570 bytes .../cacao/view/button/EnumButtonTests.kt | 54 ++++++------- .../cacao/view/button/ToggleButtonTests.kt | 72 ++++++++++++++++++ 8 files changed, 154 insertions(+), 34 deletions(-) create mode 100644 src/main/kotlin/net/shadowfacts/cacao/view/button/ToggleButton.kt create mode 100644 src/main/resources/assets/asmr/textures/gui/toggle.png create mode 100644 src/test/kotlin/net/shadowfacts/cacao/view/button/ToggleButtonTests.kt 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 0000000000000000000000000000000000000000..32ca9daee49aaf9aa84d7acb4cb05ebf0073f422 GIT binary patch literal 1570 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&zE~)R&4Yzkn25lDE4H!+#K5uy^@npa^Gy zM`SSr1Gg{;GcwGYBLNg-FY)wsWq-uN!DlJ1uyl7JP>3fpB%;JQKQ}iuuLQ_tVA!*6 z(@X{i*6E%ujv*Dd-rjZ0YjTii2+Y~Ts(vx|@xA5>*6gVD4;*huZ{PLGaF5&DG>^we z3KzJs*5o^jTx=2j&+ZfmHV00~npT}yUn8=-`+dFbi|>pL#`$H8414B%bXNPHne zjlBjV!vdgcTOEd-C*>Ie7#JGt#2fBB*}wfTqXQ$*ZvhNlXP)fuy;uI#o4`^vIZe0m9R)m3J z!EsiFP?oUHuOI*a6=i@}B-RkaS?~@lo#4T$pvSoR!>yh5V7a_qZ!;U}C;vOSj)j30 z?i&n7+_4vzW_KUC{MW4Wym{&R_pA)JKAJc%R5(7))_#8R^?QSZ@=<NIS7 z{_gd8U1L>() - 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