summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2025-03-21 23:19:14 -0300
committerSoniEx2 <endermoneymod@gmail.com>2025-03-21 23:19:14 -0300
commit8f4da9a630ee4cb549c75a85b7e6ac842ef874f1 (patch)
tree0f93e56e26eacbe97f6dd0be6f89f2f3947e3763
parent32f4966e8d3e824619fabbd225ee8e74b62be7c7 (diff)
Improve GUI accessibility
-rw-r--r--gradle.properties2
-rw-r--r--gui/radio-receiver.c83
-rw-r--r--src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt157
3 files changed, 161 insertions, 81 deletions
diff --git a/gradle.properties b/gradle.properties
index 080b6d9..6b1ab26 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -10,7 +10,7 @@ loader_version=0.16.10
 fabric_kotlin_version=1.13.1+kotlin.2.1.10
 
 # Mod Properties
-mod_version=1.0.4
+mod_version=1.0.5
 maven_group=space.autistic.radio
 archives_base_name=pirate-radio
 
diff --git a/gui/radio-receiver.c b/gui/radio-receiver.c
index defd419..de879a2 100644
--- a/gui/radio-receiver.c
+++ b/gui/radio-receiver.c
@@ -51,20 +51,12 @@ extern int screen_get_width();
 [[clang::import_module("screen")]] [[clang::import_name("get-height")]]
 extern int screen_get_height();
 
-[[clang::import_module("volume-plus-widget")]] [[clang::import_name("set-dimensions")]]
-extern void vp_set_dimensions(int x, int y, int width, int height);
-[[clang::import_module("volume-minus-widget")]] [[clang::import_name("set-dimensions")]]
-extern void vm_set_dimensions(int x, int y, int width, int height);
-[[clang::import_module("frequency-plus-widget")]] [[clang::import_name("set-dimensions")]]
-extern void fp_set_dimensions(int x, int y, int width, int height);
-[[clang::import_module("frequency-minus-widget")]] [[clang::import_name("set-dimensions")]]
-extern void fm_set_dimensions(int x, int y, int width, int height);
-[[clang::import_module("toggle-widget")]] [[clang::import_name("set-dimensions")]]
-extern void mode_set_dimensions(int x, int y, int width, int height);
-[[clang::import_module("audio-device-widget")]] [[clang::import_name("set-dimensions")]]
-extern void audio_device_set_dimensions(int x, int y, int width, int height);
+[[clang::import_module("buttons")]] [[clang::import_name("set-dimensions")]]
+extern int buttons_set_dimensions(int button, int x, int y, int width, int height);
+[[clang::import_module("buttons")]] [[clang::import_name("set-base-layout")]]
+extern void buttons_set_base_layout(int layout);
 
-#define BACKGROUND_WIDTH 200
+#define BACKGROUND_WIDTH 320
 #define BACKGROUND_HEIGHT 100
 
 void init() {
@@ -72,70 +64,17 @@ void init() {
 	logger_log_message("placeholder radio skin.");
 	set_background_size(BACKGROUND_WIDTH, BACKGROUND_HEIGHT);
 
+	buttons_set_base_layout(1);
+
 	int width = screen_get_width();
 	int height = screen_get_height();
 	int base_x = (width - BACKGROUND_WIDTH) / 2;
 	int base_y = (height - BACKGROUND_HEIGHT) / 2;
-	fp_set_dimensions(base_x + 100 - 40, base_y, 20, 20);
-	fm_set_dimensions(base_x + 120 - 40, base_y, 20, 20);
-	vp_set_dimensions(base_x + 100 - 40, base_y + 20, 20, 20);
-	vm_set_dimensions(base_x + 120 - 40, base_y + 20, 20, 20);
-	mode_set_dimensions(base_x + 100 - 100, base_y + 40, 100, 20);
-	audio_device_set_dimensions(base_x, base_y + 60, 200, 20);
+	buttons_set_dimensions(0, base_x, base_y + 0, 320, 20);
+	buttons_set_dimensions(1, base_x, base_y + 20, 320, 20);
+	buttons_set_dimensions(2, base_x, base_y + 40, 320, 20);
+	buttons_set_dimensions(3, base_x, base_y + 60, 320, 20);
 }
 
 void render(int mouseX, int mouseY, float delta) {
-	int width = screen_get_width();
-	int height = screen_get_height();
-	int base_x = (width - BACKGROUND_WIDTH) / 2 + 100;
-	int base_y = (height - BACKGROUND_HEIGHT) / 2 + (20 - 9) / 2;
-	int t1;
-	switch (simulator_get_mode()) {
-		case SIMULATOR_FAST:
-			{
-				t1 = text_translatable("pirate-radio.mode.fast");
-				break;
-			}
-		case SIMULATOR_DEAF:
-			{
-				t1 = text_translatable("pirate-radio.mode.deaf");
-				break;
-			}
-		default:
-			{
-				t1 = text_translatable("pirate-radio.mode.full");
-			}
-	}
-	int t2 = text_arguments("pirate-radio.mode.selected", 1, &t1);
-	render_text_object(t2, base_x, base_y + 40, -1, true);
-	text_free(t1);
-	text_free(t2);
-
-	int volume = simulator_get_volume();
-	if (volume == 0) {
-		t1 = text_translatable("pirate-radio.volume.off");
-	} else {
-		char volume_text[30];
-		sprintf(volume_text, "%d", volume);
-		t1 = text_literal(volume_text);
-	}
-	t2 = text_arguments("pirate-radio.volume.selected", 1, &t1);
-	render_text_object(t2, base_x, base_y + 20, -1, true);
-	text_free(t1);
-	text_free(t2);
-
-	int frequency = simulator_get_frequency();
-	int freq_mhz = frequency/10;
-	int freq_step = frequency%10;
-	char freq_text[30];
-	sprintf(freq_text, "%d", freq_mhz);
-	t1 = text_literal(freq_text);
-	sprintf(freq_text, "%d", freq_step);
-	t2 = text_literal(freq_text);
-	int freq_args[2] = {t1, t2};
-	int t3 = text_arguments("pirate-radio.frequency.selected", 2, freq_args);
-	render_text_object(t3, base_x, base_y + 0, -1, true);
-	text_free(t1);
-	text_free(t2);
-	text_free(t3);
 }
diff --git a/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt b/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt
index e4ea8ea..8886498 100644
--- a/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt
+++ b/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt
@@ -15,12 +15,15 @@ import net.minecraft.client.gui.screen.Screen
 import net.minecraft.client.gui.widget.ButtonWidget
 import net.minecraft.client.gui.widget.ClickableWidget
 import net.minecraft.client.gui.widget.CyclingButtonWidget
+import net.minecraft.client.gui.widget.SliderWidget
 import net.minecraft.client.render.GameRenderer
 import net.minecraft.client.util.InputUtil
+import net.minecraft.screen.ScreenTexts
 import net.minecraft.text.StringVisitable
 import net.minecraft.text.Text
 import net.minecraft.util.Colors
 import net.minecraft.util.Identifier
+import net.minecraft.util.math.MathHelper
 import org.lwjgl.glfw.GLFW
 import org.slf4j.LoggerFactory
 import org.slf4j.event.Level
@@ -33,7 +36,6 @@ import java.lang.invoke.MethodHandles
 import java.util.*
 import javax.sound.sampled.AudioSystem
 import javax.sound.sampled.Mixer
-import kotlin.collections.ArrayList
 import kotlin.math.max
 import kotlin.reflect.jvm.javaMethod
 
@@ -94,12 +96,106 @@ class FmReceiverScreen : Screen(Text.translatable("pirate-radio.fm-receiver")) {
     }.dimensions(20, 20, 20, 20)
         .narrationSupplier { ButtonWidget.getNarrationMessage(Text.translatable("pirate-radio.volume.minus.narrated")) }
         .build()
+    private var frequencySlider = makeFrequencySlider(0, 0, 320, 20)
+    private fun makeFrequencySlider(x: Int, y: Int, width: Int, height: Int) = object : SliderWidget(
+        x, y, width, height, ScreenTexts.EMPTY, (PirateRadioClient.frequency - 768).toDouble() / (1080.0 - 768.0)
+    ) {
+        init {
+            updateMessage()
+        }
+
+        override fun updateMessage() {
+            message = Text.translatable(
+                "pirate-radio.frequency.selected", PirateRadioClient.frequency / 10, PirateRadioClient.frequency % 10
+            )
+        }
+
+        override fun applyValue() {
+            PirateRadioClient.frequency = MathHelper.clampedLerp(768.0, 1080.0, value).toInt()
+        }
+
+        override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
+            val oldValue = this.value
+            val oldFrequency = PirateRadioClient.frequency
+            val changed = super.keyPressed(keyCode, scanCode, modifiers)
+            val bl = keyCode == GLFW.GLFW_KEY_LEFT
+            if (bl || keyCode == GLFW.GLFW_KEY_RIGHT) {
+                if (changed) {
+                    val delta = if (bl) -1 else 1
+                    val newValue = (oldFrequency + delta - 768).toDouble() / (1080.0 - 768.0)
+                    this.value = MathHelper.clamp(newValue, 0.0, 1.0)
+                    if (oldValue != this.value) {
+                        this.applyValue()
+                    }
+
+                    this.updateMessage()
+                }
+            }
+            return changed
+        }
+    }
+
+    private var volumeSlider = makeVolumeSlider(0, 20, 320, 20)
+    private fun makeVolumeSlider(x: Int, y: Int, width: Int, height: Int) = object : SliderWidget(
+        x, y, width, height, ScreenTexts.EMPTY, PirateRadioClient.volume.toDouble() / 10.0
+    ) {
+        init {
+            updateMessage()
+        }
+
+        override fun updateMessage() {
+            message = if (PirateRadioClient.volume == 0) {
+                Text.translatable("pirate-radio.volume.selected", Text.translatable("pirate-radio.volume.off"))
+            } else {
+                Text.translatable("pirate-radio.volume.selected", PirateRadioClient.volume)
+            }
+        }
+
+        override fun applyValue() {
+            PirateRadioClient.volume = MathHelper.clampedLerp(0.0, 10.0, value).toInt()
+        }
+
+
+        override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
+            val oldValue = this.value
+            val oldVolume = PirateRadioClient.volume
+            val changed = super.keyPressed(keyCode, scanCode, modifiers)
+            val bl = keyCode == GLFW.GLFW_KEY_LEFT
+            if (bl || keyCode == GLFW.GLFW_KEY_RIGHT) {
+                if (changed) {
+                    val delta = if (bl) -1 else 1
+                    val newValue = (oldVolume + delta).toDouble() / 10.0
+                    this.value = MathHelper.clamp(newValue, 0.0, 1.0)
+                    if (oldValue != this.value) {
+                        this.applyValue()
+                    }
+
+                    this.updateMessage()
+                }
+            }
+            return changed
+        }
+    }
+
     private val toggleModes = ButtonWidget.builder(Text.translatable("pirate-radio.mode")) {
         PirateRadioClient.mode = when (PirateRadioClient.mode) {
             FmSimulatorMode.FULL -> FmSimulatorMode.FAST
             else -> FmSimulatorMode.FULL
         }
     }.position(0, 40).build()
+    private val cycleModes = CyclingButtonWidget.builder { info: FmSimulatorMode ->
+        when (info) {
+            FmSimulatorMode.FAST -> Text.translatable("pirate-radio.mode.fast")
+            FmSimulatorMode.FULL -> Text.translatable("pirate-radio.mode.full")
+            FmSimulatorMode.DEAF -> Text.translatable("pirate-radio.mode.deaf")
+        }
+    }.values(
+        listOf(
+            FmSimulatorMode.FULL, FmSimulatorMode.FAST
+        )
+    ).initially(PirateRadioClient.mode).build(0, 40, 320, 20, Text.translatable("pirate-radio.mode")) { _, it ->
+        PirateRadioClient.mode = it
+    }
     private val audioDevice = CyclingButtonWidget.builder { info: Mixer.Info ->
         when (info) {
             PirateRadioClient.minecraftAudioDevice -> Text.translatable("pirate-radio.device.system-matching-minecraft")
@@ -119,7 +215,7 @@ class FmReceiverScreen : Screen(Text.translatable("pirate-radio.fm-receiver")) {
             PirateRadioClient.audioDevice = it
         }
 
-    private val buttons = arrayOf(
+    private val buttons = arrayListOf<ClickableWidget>(
         frequencyPlusWidget, frequencyMinusWidget, volumePlusWidget, volumeMinusWidget, toggleModes, audioDevice
     )
 
@@ -134,13 +230,8 @@ class FmReceiverScreen : Screen(Text.translatable("pirate-radio.fm-receiver")) {
         }
         if (failure == null) {
             try {
+                setBaseLayout(0)
                 instance!!.export("init").apply()
-                addDrawableChild(frequencyPlusWidget)
-                addDrawableChild(frequencyMinusWidget)
-                addDrawableChild(volumePlusWidget)
-                addDrawableChild(volumeMinusWidget)
-                addDrawableChild(toggleModes)
-                addDrawableChild(audioDevice)
             } catch (e: ChicoryException) {
                 failure = WasmScreenException("Skin failed to initialize", e)
                 logger.error("Failed to initialize.", failure)
@@ -342,6 +433,51 @@ class FmReceiverScreen : Screen(Text.translatable("pirate-radio.fm-receiver")) {
 
     private fun getHeight(): Int = height
 
+    private fun setBaseLayout(layout: Int) {
+        when (layout) {
+            0 -> {
+                clearChildren()
+                addDrawableChild(frequencyPlusWidget)
+                addDrawableChild(frequencyMinusWidget)
+                addDrawableChild(volumePlusWidget)
+                addDrawableChild(volumeMinusWidget)
+                addDrawableChild(toggleModes)
+                addDrawableChild(audioDevice)
+                buttons.clear()
+                buttons.addAll(
+                    listOf(
+                        frequencyPlusWidget,
+                        frequencyMinusWidget,
+                        volumePlusWidget,
+                        volumeMinusWidget,
+                        toggleModes,
+                        audioDevice
+                    )
+                )
+            }
+
+            1 -> {
+                clearChildren()
+                frequencySlider = makeFrequencySlider(
+                    frequencySlider.x,
+                    frequencySlider.y,
+                    frequencySlider.width,
+                    frequencySlider.height
+                )
+                volumeSlider = makeVolumeSlider(volumeSlider.x, volumeSlider.y, volumeSlider.width, volumeSlider.height)
+                addDrawableChild(frequencySlider)
+                addDrawableChild(volumeSlider)
+                addDrawableChild(cycleModes)
+                addDrawableChild(audioDevice)
+                cycleModes.value = PirateRadioClient.mode
+                buttons.clear()
+                buttons.addAll(listOf(frequencySlider, volumeSlider, cycleModes, audioDevice))
+            }
+
+            else -> throw WasmScreenException("Invalid base layout: $layout", null)
+        }
+    }
+
     // useful for drawing the stereo pilot, not that it's implemented
     private fun drawImage(
         red: Float, green: Float, blue: Float, alpha: Float, x: Int, y: Int, u: Float, v: Float, w: Int, h: Int
@@ -478,6 +614,11 @@ class FmReceiverScreen : Screen(Text.translatable("pirate-radio.fm-receiver")) {
         )
         importValues.addFunction(
             bindFunc(
+                "buttons", "set-base-layout", lookup, this::setBaseLayout.javaMethod!!, this
+            )
+        )
+        importValues.addFunction(
+            bindFunc(
                 "simulator", "get-frequency", lookup, this::getFrequency.javaMethod!!, this
             )
         )