1 // for finding memory leaks in debug mode with Visual Studio
2 #if defined _DEBUG && defined _MSC_VER
3 #include <crtdbg.h>
4 #endif
5 
6 #include <stdint.h>
7 #include <stdbool.h>
8 #include "ft2_header.h"
9 #include "ft2_gui.h"
10 #include "ft2_config.h"
11 #include "ft2_help.h"
12 #include "ft2_sample_ed.h"
13 #include "ft2_nibbles.h"
14 #include "ft2_inst_ed.h"
15 #include "ft2_diskop.h"
16 #include "ft2_mouse.h"
17 #include "ft2_wav_renderer.h"
18 #include "ft2_bmp.h"
19 #include "ft2_structs.h"
20 
21 radioButton_t radioButtons[NUM_RADIOBUTTONS] =
22 {
23 	/*
24 	** -- STRUCT INFO: --
25 	**  x        = x position
26 	**  y        = y position
27 	**  w        = clickable width space, relative to x
28 	**  group    = what group the radiobutton belongs to
29 	**  funcOnUp = function to call when released
30 	*/
31 
32 	// ------ HELP SCREEN RADIOBUTTONS ------
33 	//x, y,   w,  group,         funcOnUp
34 	{ 5, 18,  69, RB_GROUP_HELP, rbHelpFeatures },
35 	{ 5, 34,  60, RB_GROUP_HELP, rbHelpEffects },
36 	{ 5, 50,  86, RB_GROUP_HELP, rbHelpKeybindings },
37 	{ 5, 66, 109, RB_GROUP_HELP, rbHelpHowToUseFT2 },
38 	{ 5, 82, 101, RB_GROUP_HELP, rbHelpFAQ },
39 	{ 5, 98,  86, RB_GROUP_HELP, rbHelpKnownBugs },
40 
41 	// ------ NIBBLES SCREEN RADIOBUTTONS ------
42 	//x, y,   w,   group,                       funcOnUp
43 	{  4, 105, 61, RB_GROUP_NIBBLES_PLAYERS,    nibblesSet1Player },
44 	{  4, 119, 68, RB_GROUP_NIBBLES_PLAYERS,    nibblesSet2Players },
45 	{ 79, 117, 55, RB_GROUP_NIBBLES_DIFFICULTY, nibblesSetNovice },
46 	{ 79, 131, 63, RB_GROUP_NIBBLES_DIFFICULTY, nibblesSetAverage },
47 	{ 79, 145, 34, RB_GROUP_NIBBLES_DIFFICULTY, nibblesSetPro },
48 	{ 79, 159, 50, RB_GROUP_NIBBLES_DIFFICULTY, nibblesSetTriton },
49 
50 	// ------ SAMPLER SCREEN RADIOBUTTONS ------
51 	//x,   y,   w,  group,                 funcOnUp
52 	{ 357, 351, 58, RB_GROUP_SAMPLE_LOOP,  rbSampleNoLoop },
53 	{ 357, 368, 62, RB_GROUP_SAMPLE_LOOP,  rbSampleForwardLoop },
54 	{ 357, 385, 67, RB_GROUP_SAMPLE_LOOP,  rbSamplePingpongLoop },
55 	{ 431, 368, 44, RB_GROUP_SAMPLE_DEPTH, rbSample8bit },
56 	{ 431, 383, 50, RB_GROUP_SAMPLE_DEPTH, rbSample16bit },
57 
58 	// ------ INSTRUMENT EDITOR SCREEN RADIOBUTTONS ------
59 	//x,   y,   w,  group,                  funcOnUp
60 	{ 442, 279, 25, RB_GROUP_INST_WAVEFORM, rbVibWaveSine },
61 	{ 472, 279, 25, RB_GROUP_INST_WAVEFORM, rbVibWaveSquare },
62 	{ 502, 279, 25, RB_GROUP_INST_WAVEFORM, rbVibWaveRampDown },
63 	{ 532, 279, 25, RB_GROUP_INST_WAVEFORM, rbVibWaveRampUp },
64 
65 	// ------ CONFIG SCREEN LEFT RADIOBUTTONS ------
66 	//x, y,  w,  group,                  funcOnUp
67 	{ 5, 18, 85, RB_GROUP_CONFIG_SELECT, rbConfigIODevices },
68 	{ 5, 34, 57, RB_GROUP_CONFIG_SELECT, rbConfigLayout },
69 	{ 5, 50, 97, RB_GROUP_CONFIG_SELECT, rbConfigMiscellaneous },
70 #ifdef HAS_MIDI
71 	{ 5, 66, 72, RB_GROUP_CONFIG_SELECT, rbConfigMidiInput },
72 #endif
73 
74 	// ------ CONFIG AUDIO ------
75 
76 	// audio buffer size
77 	//x,   y,  w,   group,                           funcOnUp
78 	{ 390, 16,  46, RB_GROUP_CONFIG_SOUND_BUFF_SIZE, rbConfigSbs512  },
79 	{ 390, 30, 113, RB_GROUP_CONFIG_SOUND_BUFF_SIZE, rbConfigSbs1024 },
80 	{ 390, 44,  50, RB_GROUP_CONFIG_SOUND_BUFF_SIZE, rbConfigSbs2048 },
81 
82 	// audio bit depth
83 	//x,   y,   w,  group,                           funcOnUp
84 	{ 390, 74, 107, RB_GROUP_CONFIG_AUDIO_BIT_DEPTH, rbConfigAudio16bit },
85 	{ 390, 88,  83, RB_GROUP_CONFIG_AUDIO_BIT_DEPTH, rbConfigAudio24bit },
86 
87 	// audio interpolation
88 	//x,   y,   w,   group,                               funcOnUp
89 	{ 390, 117,  46, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrpNone },
90 	{ 390, 131,  91, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrpLinear },
91 	{ 390, 145, 103, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrpSinc },
92 
93 	// audio output frequency
94 	//x,   y,   w,  group,                      funcOnUp
95 	{ 509, 16,  66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio44kHz },
96 	{ 509, 30, 121, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio48kHz },
97 #if CPU_64BIT
98 	{ 509, 44,  66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio96kHz },
99 	{ 509, 58,  73, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio192kHz },
100 #endif
101 
102 	// audio input frequency
103 	//x,   y,   w,  group,                            funcOnUp
104 	{ 180, 156, 60, RB_GROUP_CONFIG_AUDIO_INPUT_FREQ, rbConfigAudioInput44kHz },
105 	{ 251, 156, 60, RB_GROUP_CONFIG_AUDIO_INPUT_FREQ, rbConfigAudioInput48kHz },
106 	{ 322, 156, 60, RB_GROUP_CONFIG_AUDIO_INPUT_FREQ, rbConfigAudioInput96kHz },
107 
108 	// frequency table
109 	//x,   y,   w,   group,                      funcOnUp
110 	{ 509,  89, 114, RB_GROUP_CONFIG_FREQ_TABLE, rbConfigFreqTableAmiga  },
111 	{ 509, 103, 117, RB_GROUP_CONFIG_FREQ_TABLE, rbConfigFreqTableLinear },
112 
113 	// ------ CONFIG LAYOUT ------
114 
115 	// mouse shape
116 	//x,   y,   w,  group,                 funcOnUp
117 	{ 115, 120, 41, RB_GROUP_CONFIG_MOUSE, rbConfigMouseNice },
118 	{ 178, 120, 41, RB_GROUP_CONFIG_MOUSE, rbConfigMouseUgly },
119 	{ 115, 134, 47, RB_GROUP_CONFIG_MOUSE, rbConfigMouseAwful },
120 	{ 178, 134, 55, RB_GROUP_CONFIG_MOUSE, rbConfigMouseUsable },
121 
122 	// mouse busy shape
123 	//x,   y,   w,  group,                      funcOnUp
124 	{ 115, 159, 51, RB_GROUP_CONFIG_MOUSE_BUSY, rbConfigMouseBusyVogue },
125 	{ 178, 159, 45, RB_GROUP_CONFIG_MOUSE_BUSY, rbConfigMouseBusyMrH },
126 
127 	// scope style
128 	//x,   y,   w,  group,                 funcOnUp
129 	{ 305, 145, 37, RB_GROUP_CONFIG_SCOPE, rbConfigScopeStandard },
130 	{ 346, 145, 46, RB_GROUP_CONFIG_SCOPE, rbConfigScopeLined },
131 
132 	// visible pattern channels
133 	//x,   y,  w,  group,                        funcOnUp
134 	{ 257, 42, 78, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt4Chans },
135 	{ 257, 56, 78, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt6Chans },
136 	{ 257, 70, 78, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt8Chans },
137 	{ 257, 84, 85, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt12Chans },
138 
139 	// pattern font
140 	//x,   y,   w,  group,                funcOnUp
141 	{ 257, 114, 62, RB_GROUP_CONFIG_FONT, rbConfigFontCapitals },
142 	{ 323, 114, 68, RB_GROUP_CONFIG_FONT, rbConfigFontLowerCase },
143 	{ 257, 129, 54, RB_GROUP_CONFIG_FONT, rbConfigFontFuture },
144 	{ 323, 129, 40, RB_GROUP_CONFIG_FONT, rbConfigFontBold },
145 
146 	// palette entries
147 	//x,   y,  w,  group,                       funcOnUp
148 	{ 399, 2,  88, RB_GROUP_CONFIG_PAL_ENTRIES, rbConfigPalPatternText },
149 	{ 399, 16, 79, RB_GROUP_CONFIG_PAL_ENTRIES, rbConfigPalBlockMark },
150 	{ 399, 30, 97, RB_GROUP_CONFIG_PAL_ENTRIES, rbConfigPalTextOnBlock },
151 	{ 399, 44, 52, RB_GROUP_CONFIG_PAL_ENTRIES, rbConfigPalMouse },
152 	{ 399, 58, 63, RB_GROUP_CONFIG_PAL_ENTRIES, rbConfigPalDesktop },
153 	{ 399, 72, 61, RB_GROUP_CONFIG_PAL_ENTRIES, rbConfigPalButttons },
154 
155 	// palette presets
156 	//x,   y,   w,   group,                      funcOnUp
157 	{ 399,  89,  50, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalArctic },
158 	{ 512,  89,  81, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalLitheDark },
159 	{ 399, 103, 105, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalAuroraBorealis },
160 	{ 512, 103,  45, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalRose },
161 	{ 399, 117,  47, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalBlues },
162 	{ 512, 117,  77, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalDarkMode },
163 	{ 399, 131,  40, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalGold },
164 	{ 512, 131,  56, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalViolent },
165 	{ 399, 145,  87, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalHeavyMetal },
166 	{ 512, 145,  87, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalWhyColors },
167 	{ 399, 159,  54, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalJungle },
168 	{ 512, 159,  90, RB_GROUP_CONFIG_PAL_PRESET, rbConfigPalUserDefined },
169 
170 	// ------ CONFIG MISCELLANEOUS ------
171 
172 	// FILENAME SORTING
173 	//x,   y,  w,  group,                    funcOnUp
174 	{ 114, 15, 40, RB_GROUP_CONFIG_FILESORT, rbFileSortExt },
175 	{ 114, 29, 48, RB_GROUP_CONFIG_FILESORT, rbFileSortName },
176 
177 	// WINDOW SIZE
178 	//x,   y,  w,  group,                    funcOnUp
179 	{ 114, 58, 60, RB_GROUP_CONFIG_WIN_SIZE, rbWinSizeAuto },
180 	{ 114, 72, 31, RB_GROUP_CONFIG_WIN_SIZE, rbWinSize1x },
181 	{ 156, 72, 31, RB_GROUP_CONFIG_WIN_SIZE, rbWinSize3x },
182 	{ 114, 86, 31, RB_GROUP_CONFIG_WIN_SIZE, rbWinSize2x },
183 	{ 156, 86, 31, RB_GROUP_CONFIG_WIN_SIZE, rbWinSize4x },
184 
185 	// ------ DISK OP. ------
186 
187 	// FILENAME SORTING
188 	//x, y,  w,  group,                funcOnUp
189 	{ 4, 16, 55, RB_GROUP_DISKOP_ITEM, rbDiskOpModule },
190 	{ 4, 30, 45, RB_GROUP_DISKOP_ITEM, rbDiskOpInstr },
191 	{ 4, 44, 56, RB_GROUP_DISKOP_ITEM, rbDiskOpSample },
192 	{ 4, 58, 59, RB_GROUP_DISKOP_ITEM, rbDiskOpPattern },
193 	{ 4, 72, 50, RB_GROUP_DISKOP_ITEM, rbDiskOpTrack },
194 
195 	// MODULE SAVE AS FORMATS
196 	//x, y,  w,   group,                      funcOnUp
197 	{ 4, 100, 40, RB_GROUP_DISKOP_MOD_SAVEAS, rbDiskOpModSaveMod },
198 	{ 4, 114, 33, RB_GROUP_DISKOP_MOD_SAVEAS, rbDiskOpModSaveXm },
199 	{ 4, 128, 40, RB_GROUP_DISKOP_MOD_SAVEAS, rbDiskOpModSaveWav },
200 
201 	// INSTRUMENT SAVE AS FORMATS
202 	//x, y,   w,  group,                      funcOnUp
203 	{ 4, 100, 29, RB_GROUP_DISKOP_INS_SAVEAS, NULL },
204 
205 	// SAMPLE SAVE AS FORMATS
206 	//x, y,   w,  group,                      funcOnUp
207 	{ 4, 100, 40, RB_GROUP_DISKOP_SMP_SAVEAS, rbDiskOpSmpSaveRaw },
208 	{ 4, 114, 34, RB_GROUP_DISKOP_SMP_SAVEAS, rbDiskOpSmpSaveIff },
209 	{ 4, 128, 40, RB_GROUP_DISKOP_SMP_SAVEAS, rbDiskOpSmpSaveWav },
210 
211 	// PATTERN SAVE AS FORMATS
212 	//x, y,   w,  group,                      funcOnUp
213 	{ 4, 100, 33, RB_GROUP_DISKOP_PAT_SAVEAS, NULL },
214 
215 	// TRACK SAVE AS FORMATS
216 	//x, y,   w,  group,                      funcOnUp
217 	{ 4, 100, 31, RB_GROUP_DISKOP_TRK_SAVEAS, NULL },
218 
219 	// WAV RENDERER BITDEPTH
220 	//x,   y,  w,  group,                        funcOnUp
221 	{ 140, 95, 52, RB_GROUP_WAV_RENDER_BITDEPTH, rbWavRenderBitDepth16 },
222 	{ 205, 95, 83, RB_GROUP_WAV_RENDER_BITDEPTH, rbWavRenderBitDepth32 }
223 };
224 
drawRadioButton(uint16_t radioButtonID)225 void drawRadioButton(uint16_t radioButtonID)
226 {
227 	assert(radioButtonID < NUM_RADIOBUTTONS);
228 	radioButton_t *radioButton = &radioButtons[radioButtonID];
229 	if (!radioButton->visible)
230 		return;
231 
232 	assert(radioButton->x < SCREEN_W && radioButton->y < SCREEN_H);
233 
234 	const uint8_t *gfxPtr = &bmp.radiobuttonGfx[radioButton->state*(RADIOBUTTON_W*RADIOBUTTON_H)];
235 	blitFast(radioButton->x, radioButton->y, gfxPtr, RADIOBUTTON_W, RADIOBUTTON_H);
236 }
237 
showRadioButton(uint16_t radioButtonID)238 void showRadioButton(uint16_t radioButtonID)
239 {
240 	assert(radioButtonID < NUM_RADIOBUTTONS);
241 	radioButtons[radioButtonID].visible = true;
242 	drawRadioButton(radioButtonID);
243 }
244 
hideRadioButton(uint16_t radioButtonID)245 void hideRadioButton(uint16_t radioButtonID)
246 {
247 	assert(radioButtonID < NUM_RADIOBUTTONS);
248 	radioButtons[radioButtonID].state = 0;
249 	radioButtons[radioButtonID].visible = false;
250 }
251 
checkRadioButton(uint16_t radioButtonID)252 void checkRadioButton(uint16_t radioButtonID)
253 {
254 	assert(radioButtonID < NUM_RADIOBUTTONS);
255 	const uint16_t testGroup = radioButtons[radioButtonID].group;
256 
257 	radioButton_t *radioButton = radioButtons;
258 	for (uint16_t i = 0; i < NUM_RADIOBUTTONS; i++, radioButton++)
259 	{
260 		if (radioButton->group == testGroup && radioButton->state == RADIOBUTTON_CHECKED)
261 		{
262 			radioButton->state = RADIOBUTTON_UNCHECKED;
263 			drawRadioButton(i);
264 			break;
265 		}
266 	}
267 
268 	radioButtons[radioButtonID].state = RADIOBUTTON_CHECKED;
269 	drawRadioButton(radioButtonID);
270 }
271 
uncheckRadioButtonGroup(uint16_t radioButtonGroup)272 void uncheckRadioButtonGroup(uint16_t radioButtonGroup)
273 {
274 	radioButton_t *radioButton = radioButtons;
275 	for (uint16_t i = 0; i < NUM_RADIOBUTTONS; i++, radioButton++)
276 	{
277 		if (radioButton->group == radioButtonGroup)
278 			radioButton->state = RADIOBUTTON_UNCHECKED;
279 	}
280 }
281 
showRadioButtonGroup(uint16_t radioButtonGroup)282 void showRadioButtonGroup(uint16_t radioButtonGroup)
283 {
284 	radioButton_t *radioButton = radioButtons;
285 	for (uint16_t i = 0; i < NUM_RADIOBUTTONS; i++, radioButton++)
286 	{
287 		if (radioButton->group == radioButtonGroup)
288 			showRadioButton(i);
289 	}
290 }
291 
hideRadioButtonGroup(uint16_t radioButtonGroup)292 void hideRadioButtonGroup(uint16_t radioButtonGroup)
293 {
294 	radioButton_t *radioButton = radioButtons;
295 	for (uint16_t i = 0; i < NUM_RADIOBUTTONS; i++, radioButton++)
296 	{
297 		if (radioButton->group == radioButtonGroup)
298 			hideRadioButton(i);
299 	}
300 }
301 
handleRadioButtonsWhileMouseDown(void)302 void handleRadioButtonsWhileMouseDown(void)
303 {
304 	assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_RADIOBUTTONS);
305 	radioButton_t *radioButton = &radioButtons[mouse.lastUsedObjectID];
306 	if (!radioButton->visible || radioButton->state == RADIOBUTTON_CHECKED)
307 		return;
308 
309 	radioButton->state = RADIOBUTTON_UNCHECKED;
310 	if (mouse.x >= radioButton->x && mouse.x < radioButton->x+radioButton->clickAreaWidth &&
311 	    mouse.y >= radioButton->y && mouse.y < radioButton->y+(RADIOBUTTON_H+1))
312 	{
313 		radioButton->state = RADIOBUTTON_PRESSED;
314 	}
315 
316 	if (mouse.lastX != mouse.x || mouse.lastY != mouse.y)
317 	{
318 		mouse.lastX = mouse.x;
319 		mouse.lastY = mouse.y;
320 
321 		drawRadioButton(mouse.lastUsedObjectID);
322 	}
323 }
324 
testRadioButtonMouseDown(void)325 bool testRadioButtonMouseDown(void)
326 {
327 	if (ui.sysReqShown)
328 		return false;
329 
330 	const int32_t mx = mouse.x;
331 	const int32_t my = mouse.y;
332 
333 	radioButton_t *radioButton = radioButtons;
334 	for (uint16_t i = 0; i < NUM_RADIOBUTTONS; i++, radioButton++)
335 	{
336 		if (!radioButton->visible || radioButton->state == RADIOBUTTON_CHECKED)
337 			continue;
338 
339 		if (mx >= radioButton->x && mx < radioButton->x+radioButton->clickAreaWidth &&
340 		    my >= radioButton->y && my < radioButton->y+(RADIOBUTTON_H+1))
341 		{
342 			mouse.lastUsedObjectID = i;
343 			mouse.lastUsedObjectType = OBJECT_RADIOBUTTON;
344 			return true;
345 		}
346 	}
347 
348 	return false;
349 }
350 
testRadioButtonMouseRelease(void)351 void testRadioButtonMouseRelease(void)
352 {
353 	if (mouse.lastUsedObjectType != OBJECT_RADIOBUTTON || mouse.lastUsedObjectID == OBJECT_ID_NONE)
354 		return;
355 
356 	assert(mouse.lastUsedObjectID < NUM_RADIOBUTTONS);
357 	radioButton_t *radioButton = &radioButtons[mouse.lastUsedObjectID];
358 	if (!radioButton->visible || radioButton->state == RADIOBUTTON_CHECKED)
359 		return;
360 
361 	if (mouse.x >= radioButton->x && mouse.x < radioButton->x+radioButton->clickAreaWidth &&
362 	    mouse.y >= radioButton->y && mouse.y < radioButton->y+(RADIOBUTTON_H+1))
363 	{
364 		radioButton->state = RADIOBUTTON_UNCHECKED;
365 		drawRadioButton(mouse.lastUsedObjectID);
366 
367 		if (radioButton->callbackFunc != NULL)
368 			radioButton->callbackFunc();
369 	}
370 }
371