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