Maelstrom: Fixed controls panel after adding brake control

From a4ab20e6898d817dc6615b65f7908f48003cf504 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 30 Mar 2026 10:07:16 -0700
Subject: [PATCH] Fixed controls panel after adding brake control

---
 Data/UI/controls.xml |  23 ++++++---
 game/controls.cpp    | 111 ++++++++++++++++++++++++++++++++++++++++---
 game/controls.h      |   9 ++++
 3 files changed, 130 insertions(+), 13 deletions(-)

diff --git a/Data/UI/controls.xml b/Data/UI/controls.xml
index 8486206d..8113765d 100644
--- a/Data/UI/controls.xml
+++ b/Data/UI/controls.xml
@@ -47,30 +47,39 @@
 		<DialogLabel name="control7">
 			<Anchor anchor="control7_box"/>
 		</DialogLabel>
+		<Rectangle name="control8_box" template="ControlKeyBox">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="BOTTOMLEFT" anchor="control7_box" y="3"/>
+		</Rectangle>
+		<DialogLabel name="control8">
+			<Anchor anchor="control8_box"/>
+		</DialogLabel>
 
 		<DialogRadioGroup name="controlsRadioGroup">
 			<Elements>
-				<DialogRadioButton text="Fire" id="1">
+				<DialogRadioButton name="label1" id="1">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control1_box"/>
 				</DialogRadioButton>
-				<DialogRadioButton text="Thrust" id="2">
+				<DialogRadioButton name="label2" id="2">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control2_box"/>
 				</DialogRadioButton>
-				<DialogRadioButton text="Shield" id="3">
+				<DialogRadioButton name="label3" id="3">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control3_box"/>
 				</DialogRadioButton>
-				<DialogRadioButton text="Turn Clockwise" id="4">
+				<DialogRadioButton name="label4" id="4">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control4_box"/>
 				</DialogRadioButton>
-				<DialogRadioButton text="Turn Counter-Clockwise" id="5">
+				<DialogRadioButton name="label5" id="5">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control5_box"/>
 				</DialogRadioButton>
-				<DialogRadioButton text="Pause" id="6">
+				<DialogRadioButton name="label6" id="6">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control6_box"/>
 				</DialogRadioButton>
-				<DialogRadioButton text="Abort Game" id="7">
+				<DialogRadioButton name="label7" id="7">
 					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control7_box"/>
 				</DialogRadioButton>
+				<DialogRadioButton name="label8" id="8">
+					<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="control8_box"/>
+				</DialogRadioButton>
 			</Elements>
 		</DialogRadioGroup>
 
diff --git a/game/controls.cpp b/game/controls.cpp
index c07ddbb6..a69c3510 100644
--- a/game/controls.cpp
+++ b/game/controls.cpp
@@ -19,7 +19,7 @@
   3. This notice may not be removed or altered from any source distribution.
 */
 
-/* This file handles the controls configuration and updating the keystrokes 
+/* This file handles the controls configuration and updating the keystrokes
 */
 
 #include "Maelstrom_Globals.h"
@@ -77,21 +77,47 @@ ControlsDialogDelegate::OnLoad()
 {
 	char name[32];
 
-	for (int i = 0; (unsigned)i < SDL_arraysize(m_controlKeys); ++i) {
+	for (unsigned int i = 0; i < SDL_arraysize(m_controlKeys); ++i) {
+		SDL_snprintf(name, sizeof(name), "control%d_box", 1+i);
+		m_controlBoxes[i] = m_panel->GetElement<UIElement>(name);
+		if (!m_controlBoxes[i]) {
+			error("Warning: Couldn't find control '%s'\n", name);
+			return false;
+		}
+	}
+
+	for (unsigned int i = 0; i < SDL_arraysize(m_controlKeys); ++i) {
 		SDL_snprintf(name, sizeof(name), "control%d", 1+i);
 		m_controlKeys[i] = m_panel->GetElement<UIElement>(name);
 		if (!m_controlKeys[i]) {
-			fprintf(stderr, "Warning: Couldn't find control key label '%s'\n", name);
+			error("Warning: Couldn't find control '%s'\n", name);
 			return false;
 		}
 	}
 
 	m_radioGroup = m_panel->GetElement<UIElementRadioGroup>("controlsRadioGroup");
 	if (!m_radioGroup) {
-		fprintf(stderr, "Warning: Couldn't find 'controlsRadioGroup'\n");
+		error("Warning: Couldn't find 'controlsRadioGroup'\n");
 		return false;
 	}
 
+	for (unsigned int i = 0; i < SDL_arraysize(m_controlLabels); ++i) {
+		SDL_snprintf(name, sizeof(name), "label%d", 1+i);
+		m_controlLabels[i] = m_panel->GetElement<UIElement>(name);
+		if (!m_controlLabels[i]) {
+			error("Warning: Couldn't find control '%s'\n", name);
+			return false;
+		}
+	}
+
+	unsigned int num_controls = SDL_arraysize(m_controlKeys);
+	if (!gControlBrakes) {
+		--num_controls;
+		m_controlBoxes[num_controls]->Hide();
+		m_controlKeys[num_controls]->Hide();
+		m_controlLabels[num_controls]->Hide();
+	}
+
 	return true;
 }
 
@@ -112,6 +138,7 @@ ControlsDialogDelegate::OnShow()
 	m_controls = controls;
 
 	ShowKeyLabels();
+	ShowControlLabels();
 }
 
 void
@@ -164,6 +191,78 @@ ControlsDialogDelegate::HandleEvent(const SDL_Event &event)
 	return false;
 }
 
+int
+ControlsDialogDelegate::TranslateIndex(int index)
+{
+	static int s_arrBrakeEnabled[] = {
+		FIRE_CTL,
+		THRUST_CTL,
+		BRAKE_CTL,
+		SHIELD_CTL,
+		TURNR_CTL,
+		TURNL_CTL,
+		PAUSE_CTL,
+		QUIT_CTL
+	};
+	static int s_arrBrakeDisabled[] = {
+		FIRE_CTL,
+		THRUST_CTL,
+		SHIELD_CTL,
+		TURNR_CTL,
+		TURNL_CTL,
+		PAUSE_CTL,
+		QUIT_CTL
+	};
+
+	if (gControlBrakes) {
+		if (index < SDL_arraysize(s_arrBrakeEnabled)) {
+			return s_arrBrakeEnabled[index];
+		}
+	} else {
+		if (index < SDL_arraysize(s_arrBrakeDisabled)) {
+			return s_arrBrakeDisabled[index];
+		}
+	}
+	return NUM_CTLS;
+}
+
+void
+ControlsDialogDelegate::ShowControlLabel(int index)
+{
+	const char *text;
+
+	switch (TranslateIndex(index)) {
+		case FIRE_CTL:
+			text = "Fire";
+			break;
+		case THRUST_CTL:
+			text = "Thrust";
+			break;
+		case BRAKE_CTL:
+			text = "Brake";
+			break;
+		case SHIELD_CTL:
+			text = "Shield";
+			break;
+		case TURNR_CTL:
+			text = "Turn Clockwise";
+			break;
+		case TURNL_CTL:
+			text = "Turn Counter-Clockwise";
+			break;
+		case PAUSE_CTL:
+			text = "Pause";
+			break;
+		case QUIT_CTL:
+			text = "Abort Game";
+			break;
+		default:
+			text = "";
+			break;
+	}
+	m_controlLabels[index]->SetText(text);
+}
+
 void
 ControlsDialogDelegate::ShowKeyLabel(int index)
 {
@@ -180,7 +279,7 @@ ControlsDialogDelegate::ShowKeyLabel(int index)
 SDL_Keycode
 ControlsDialogDelegate::GetKeycode(int index)
 {
-	switch (index) {
+	switch (TranslateIndex(index)) {
 		case FIRE_CTL:
 			return m_controls.gFireControl;
 		case THRUST_CTL:
@@ -205,7 +304,7 @@ ControlsDialogDelegate::GetKeycode(int index)
 void
 ControlsDialogDelegate::SetKeycode(int index, SDL_Keycode keycode)
 {
-	switch (index) {
+	switch (TranslateIndex(index)) {
 		case FIRE_CTL:
 			m_controls.gFireControl = keycode;
 			break;
diff --git a/game/controls.h b/game/controls.h
index 88cdd37f..caa1a549 100644
--- a/game/controls.h
+++ b/game/controls.h
@@ -80,6 +80,12 @@ class ControlsDialogDelegate : public UIDialogDelegate
 	virtual bool HandleEvent(const SDL_Event &event);
 
 protected:
+	void ShowControlLabel(int index);
+	void ShowControlLabels() {
+		for (int i = 0; i < NUM_CTLS; ++i) {
+			ShowControlLabel(i);
+		}
+	}
 	void ShowKeyLabel(int index);
 	void ShowKeyLabels() {
 		for (int i = 0; i < NUM_CTLS; ++i) {
@@ -87,6 +93,7 @@ class ControlsDialogDelegate : public UIDialogDelegate
 		}
 	}
 
+	int TranslateIndex(int index);
 	SDL_Keycode GetKeycode(int index);
 	void SetKeycode(int index, SDL_Keycode keycode);
 
@@ -104,7 +111,9 @@ class ControlsDialogDelegate : public UIDialogDelegate
 	};
 
 	Controls m_controls;
+	UIElement *m_controlBoxes[NUM_CTLS];
 	UIElement *m_controlKeys[NUM_CTLS];
+	UIElement *m_controlLabels[NUM_CTLS];
 	UIElementRadioGroup *m_radioGroup;
 	Uint64 m_keyinuseTimers[NUM_CTLS];
 };