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 <time.h>
8 #include "ft2_header.h"
9 #include "ft2_config.h"
10 #include "ft2_about.h"
11 #include "ft2_mouse.h"
12 #include "ft2_nibbles.h"
13 #include "ft2_gui.h"
14 #include "ft2_pattern_ed.h"
15 #include "scopes/ft2_scopes.h"
16 #include "ft2_help.h"
17 #include "ft2_sample_ed.h"
18 #include "ft2_inst_ed.h"
19 #include "ft2_diskop.h"
20 #include "ft2_wav_renderer.h"
21 #include "ft2_trim.h"
22 #include "ft2_video.h"
23 #include "ft2_tables.h"
24 #include "ft2_bmp.h"
25 #include "ft2_structs.h"
26 
releaseMouseStates(void)27 static void releaseMouseStates(void)
28 {
29 	mouse.lastUsedObjectID = OBJECT_ID_NONE;
30 	mouse.lastUsedObjectType = OBJECT_NONE;
31 	mouse.leftButtonPressed = false;
32 	mouse.leftButtonReleased = false;
33 	mouse.rightButtonPressed = false;
34 	mouse.rightButtonReleased = false;
35 	mouse.firstTimePressingButton = false;
36 	mouse.buttonCounter = 0;
37 	mouse.lastX = 0;
38 	mouse.lastY = 0;
39 	ui.sampleDataOrLoopDrag = -1;
40 	ui.leftLoopPinMoving = false;
41 	ui.rightLoopPinMoving = false;
42 }
43 
unstuckLastUsedGUIElement(void)44 void unstuckLastUsedGUIElement(void)
45 {
46 	if (mouse.lastUsedObjectID == OBJECT_ID_NONE)
47 	{
48 		/* If last object ID is OBJECT_ID_NONE, check if we moved the
49 		** sample data loop pins, and unstuck them if so
50 		*/
51 
52 		if (ui.leftLoopPinMoving)
53 		{
54 			setLeftLoopPinState(false);
55 			ui.leftLoopPinMoving = false;
56 		}
57 
58 		if (ui.rightLoopPinMoving)
59 		{
60 			setRightLoopPinState(false);
61 			ui.rightLoopPinMoving = false;
62 		}
63 
64 		releaseMouseStates();
65 		return;
66 	}
67 
68 	switch (mouse.lastUsedObjectType)
69 	{
70 		default: break;
71 
72 		case OBJECT_PUSHBUTTON:
73 		{
74 			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_PUSHBUTTONS);
75 			pushButton_t *p = &pushButtons[mouse.lastUsedObjectID];
76 			if (p->state == PUSHBUTTON_PRESSED)
77 			{
78 				p->state = PUSHBUTTON_UNPRESSED;
79 				if (p->visible)
80 					drawPushButton(mouse.lastUsedObjectID);
81 			}
82 		}
83 		break;
84 
85 		case OBJECT_RADIOBUTTON:
86 		{
87 			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_RADIOBUTTONS);
88 			radioButton_t *r = &radioButtons[mouse.lastUsedObjectID];
89 			if (r->state == RADIOBUTTON_PRESSED)
90 			{
91 				r->state = RADIOBUTTON_UNCHECKED;
92 				if (r->visible)
93 					drawRadioButton(mouse.lastUsedObjectID);
94 			}
95 		}
96 		break;
97 
98 		case OBJECT_CHECKBOX:
99 		{
100 			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_CHECKBOXES);
101 			checkBox_t *c = &checkBoxes[mouse.lastUsedObjectID];
102 			if (c->state == CHECKBOX_PRESSED)
103 			{
104 				c->state = CHECKBOX_UNPRESSED;
105 				if (c->visible)
106 					drawCheckBox(mouse.lastUsedObjectID);
107 			}
108 		}
109 		break;
110 
111 		case OBJECT_SCROLLBAR:
112 		{
113 			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_SCROLLBARS);
114 			scrollBar_t *s = &scrollBars[mouse.lastUsedObjectID];
115 			if (s->state == SCROLLBAR_PRESSED)
116 			{
117 				s->state = SCROLLBAR_UNPRESSED;
118 				if (s->visible)
119 					drawScrollBar(mouse.lastUsedObjectID);
120 			}
121 		}
122 		break;
123 	}
124 
125 	releaseMouseStates();
126 }
127 
setupGUI(void)128 bool setupGUI(void)
129 {
130 	// all memory will be NULL-tested and free'd if we return false somewhere in this function
131 
132 	editor.tmpFilenameU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
133 	editor.tmpInstrFilenameU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
134 
135 	if (editor.tmpFilenameU == NULL || editor.tmpInstrFilenameU == NULL)
136 		goto setupGUI_OOM;
137 
138 	editor.tmpFilenameU[0] = 0;
139 	editor.tmpInstrFilenameU[0] = 0;
140 
141 	// set uninitialized GUI struct entries
142 
143 	textBox_t *t = &textBoxes[1]; // skip first entry, it's reserved for inputBox())
144 	for (int32_t i = 1; i < NUM_TEXTBOXES; i++, t++)
145 	{
146 		t->visible = false;
147 		t->bufOffset = 0;
148 		t->cursorPos = 0;
149 		t->textPtr = NULL;
150 		t->renderBufW = (9 + 1) * t->maxChars; // 9 = max character/glyph width possible
151 		t->renderBufH = 10; // 10 = max character height possible
152 		t->renderW = t->w - (t->tx * 2);
153 
154 		t->renderBuf = (uint8_t *)malloc(t->renderBufW * t->renderBufH * sizeof (int8_t));
155 		if (t->renderBuf == NULL)
156 			goto setupGUI_OOM;
157 	}
158 
159 	pushButton_t *p = pushButtons;
160 	for (int32_t i = 0; i < NUM_PUSHBUTTONS; i++, p++)
161 	{
162 		p->state = 0;
163 		p->visible = false;
164 
165 		if (i == PB_LOGO || i == PB_BADGE)
166 		{
167 			p->bitmapFlag = true;
168 		}
169 		else
170 		{
171 			p->bitmapFlag = false;
172 			p->bitmapUnpressed = NULL;
173 			p->bitmapPressed = NULL;
174 		}
175 	}
176 
177 	checkBox_t *c = checkBoxes;
178 	for (int32_t i = 0; i < NUM_CHECKBOXES; i++, c++)
179 	{
180 		c->state = 0;
181 		c->checked = false;
182 		c->visible = false;
183 	}
184 
185 	radioButton_t *r = radioButtons;
186 	for (int32_t i = 0; i < NUM_RADIOBUTTONS; i++, r++)
187 	{
188 		r->state = 0;
189 		r->visible = false;
190 	}
191 
192 	scrollBar_t *s = scrollBars;
193 	for (int32_t i = 0; i < NUM_SCROLLBARS; i++, s++)
194 	{
195 		s->visible = false;
196 		s->state = 0;
197 		s->pos = 0;
198 		s->page = 0;
199 		s->end  = 0;
200 		s->thumbX = 0;
201 		s->thumbY = 0;
202 		s->thumbW = 0;
203 		s->thumbH = 0;
204 	}
205 
206 	setPal16(palTable[config.cfg_StdPalNum], false);
207 	seedAboutScreenRandom((uint32_t)time(NULL));
208 	setupInitialTextBoxPointers();
209 	setInitialTrimFlags();
210 	initializeScrollBars();
211 	setMouseMode(MOUSE_MODE_NORMAL);
212 	updateTextBoxPointers();
213 	drawGUIOnRunTime();
214 	updateSampleEditorSample();
215 	updatePatternWidth();
216 	initFTHelp();
217 
218 	return true;
219 
220 setupGUI_OOM:
221 	showErrorMsgBox("Not enough memory!");
222 	return false;
223 }
224 
225 // TEXT ROUTINES
226 
227 // returns full pixel width of a char/glyph
charWidth(char ch)228 uint8_t charWidth(char ch)
229 {
230 	return font1Widths[ch & 0x7F];
231 }
232 
233 // returns full pixel width of a char/glyph (big font)
charWidth16(char ch)234 uint8_t charWidth16(char ch)
235 {
236 	return font2Widths[ch & 0x7F];
237 }
238 
239 // return full pixel width of a text string
textWidth(const char * textPtr)240 uint16_t textWidth(const char *textPtr)
241 {
242 	assert(textPtr != NULL);
243 
244 	uint16_t textWidth = 0;
245 	while (*textPtr != '\0')
246 		textWidth += charWidth(*textPtr++);
247 
248 	// there will be a pixel spacer at the end of the last char/glyph, remove it
249 	if (textWidth > 0)
250 		textWidth--;
251 
252 	return textWidth;
253 }
254 
textNWidth(const char * textPtr,int32_t length)255 uint16_t textNWidth(const char *textPtr, int32_t length)
256 {
257 	assert(textPtr != NULL);
258 
259 	uint16_t textWidth = 0;
260 	for (int32_t i = 0; i < length; i++)
261 	{
262 		const char ch = textPtr[i];
263 		if (ch == '\0')
264 			break;
265 
266 		textWidth += charWidth(ch);
267 	}
268 
269 	// there will be a pixel spacer at the end of the last char/glyph, remove it
270 	if (textWidth > 0)
271 		textWidth--;
272 
273 	return textWidth;
274 }
275 
276 // return full pixel width of a text string (big font)
textWidth16(const char * textPtr)277 uint16_t textWidth16(const char *textPtr)
278 {
279 	assert(textPtr != NULL);
280 
281 	uint16_t textWidth = 0;
282 	while (*textPtr != '\0')
283 		textWidth += charWidth(*textPtr++);
284 
285 	// there will be a pixel spacer at the end of the last char/glyph, remove it
286 	if (textWidth > 0)
287 		textWidth--;
288 
289 	return textWidth;
290 }
291 
textOutTiny(int32_t xPos,int32_t yPos,char * str,uint32_t color)292 void textOutTiny(int32_t xPos, int32_t yPos, char *str, uint32_t color) // A..Z/a..z and 0..9
293 {
294 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
295 	while (*str != '\0')
296 	{
297 		char chr = *str++;
298 
299 		if (chr >= '0' && chr <= '9')
300 		{
301 			chr -= '0';
302 		}
303 		else if (chr >= 'a' && chr <= 'z')
304 		{
305 			chr -= 'a';
306 			chr += 10;
307 		}
308 		else if (chr >= 'A' && chr <= 'Z')
309 		{
310 			chr -= 'A';
311 			chr += 10;
312 		}
313 		else
314 		{
315 			dstPtr += FONT3_CHAR_W;
316 			continue;
317 		}
318 
319 		const uint8_t *srcPtr = &bmp.font3[chr * FONT3_CHAR_W];
320 		for (int32_t y = 0; y < FONT3_CHAR_H; y++)
321 		{
322 			for (int32_t x = 0; x < FONT3_CHAR_W; x++)
323 			{
324 #ifdef __arm__
325 				if (srcPtr[x] != 0)
326 					dstPtr[x] = color;
327 #else
328 				// carefully written like this to generate conditional move instructions (font data is hard to predict)
329 				uint32_t tmp = dstPtr[x];
330 				if (srcPtr[x] != 0) tmp = color;
331 				dstPtr[x] = tmp;
332 #endif
333 			}
334 
335 			srcPtr += FONT3_WIDTH;
336 			dstPtr += SCREEN_W;
337 		}
338 
339 		dstPtr -= (SCREEN_W * FONT3_CHAR_H) - FONT3_CHAR_W;
340 	}
341 }
342 
textOutTinyOutline(int32_t xPos,int32_t yPos,char * str)343 void textOutTinyOutline(int32_t xPos, int32_t yPos, char *str) // A..Z/a..z and 0..9
344 {
345 	const uint32_t bgColor = video.palette[PAL_BCKGRND];
346 	const uint32_t fgColor = video.palette[PAL_FORGRND];
347 
348 	textOutTiny(xPos-1, yPos,   str, bgColor);
349 	textOutTiny(xPos,   yPos-1, str, bgColor);
350 	textOutTiny(xPos+1, yPos,   str, bgColor);
351 	textOutTiny(xPos,   yPos+1, str, bgColor);
352 
353 	textOutTiny(xPos, yPos, str, fgColor);
354 }
355 
charOut(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,char chr)356 void charOut(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr)
357 {
358 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
359 
360 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
361 	if (chr == ' ')
362 		return;
363 
364 	const uint32_t pixVal = video.palette[paletteIndex];
365 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];
366 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
367 
368 	for (uint32_t y = 0; y < FONT1_CHAR_H; y++)
369 	{
370 		for (uint32_t x = 0; x < FONT1_CHAR_W; x++)
371 		{
372 #ifdef __arm__
373 			if (srcPtr[x] != 0)
374 				dstPtr[x] = pixVal;
375 #else
376 			// carefully written like this to generate conditional move instructions (font data is hard to predict)
377 			uint32_t tmp = dstPtr[x];
378 			if (srcPtr[x] != 0) tmp = pixVal;
379 			dstPtr[x] = tmp;
380 #endif
381 		}
382 
383 		srcPtr += FONT1_WIDTH;
384 		dstPtr += SCREEN_W;
385 	}
386 }
387 
charOutFade(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,char chr,int32_t fade)388 static void charOutFade(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, int32_t fade) // for about screen
389 {
390 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
391 
392 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
393 	if (chr == ' ')
394 		return;
395 
396 	const uint32_t pixVal = video.palette[paletteIndex];
397 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];
398 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
399 
400 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)
401 	{
402 		for (int32_t x = 0; x < FONT1_CHAR_W; x++)
403 		{
404 			if (srcPtr[x] != 0)
405 			{
406 				const int32_t r = (RGB32_R(pixVal) * fade) >> 8;
407 				const int32_t g = (RGB32_G(pixVal) * fade) >> 8;
408 				const int32_t b = (RGB32_B(pixVal) * fade) >> 8;
409 
410 				dstPtr[x] = RGB32(r, g, b) | 0xFF000000;
411 			}
412 		}
413 
414 		srcPtr += FONT1_WIDTH;
415 		dstPtr += SCREEN_W;
416 	}
417 }
418 
charOutBg(uint16_t xPos,uint16_t yPos,uint8_t fgPalette,uint8_t bgPalette,char chr)419 void charOutBg(uint16_t xPos, uint16_t yPos, uint8_t fgPalette, uint8_t bgPalette, char chr)
420 {
421 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
422 
423 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
424 	if (chr == ' ')
425 		return;
426 
427 	const uint32_t fg = video.palette[fgPalette];
428 	const uint32_t bg = video.palette[bgPalette];
429 
430 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];
431 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
432 
433 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)
434 	{
435 		for (int32_t x = 0; x < FONT1_CHAR_W-1; x++)
436 			dstPtr[x] = srcPtr[x] ? fg : bg; // compiles nicely into conditional move instructions
437 
438 		srcPtr += FONT1_WIDTH;
439 		dstPtr += SCREEN_W;
440 	}
441 }
442 
charOutOutlined(uint16_t x,uint16_t y,uint8_t paletteIndex,char chr)443 void charOutOutlined(uint16_t x, uint16_t y, uint8_t paletteIndex, char chr)
444 {
445 	charOut(x - 1, y,     PAL_BCKGRND, chr);
446 	charOut(x + 1, y,     PAL_BCKGRND, chr);
447 	charOut(x,     y - 1, PAL_BCKGRND, chr);
448 	charOut(x,     y + 1, PAL_BCKGRND, chr);
449 
450 	charOut(x, y, paletteIndex, chr);
451 }
452 
charOutShadow(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,uint8_t shadowPaletteIndex,char chr)453 void charOutShadow(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, uint8_t shadowPaletteIndex, char chr)
454 {
455 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
456 
457 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
458 	if (chr == ' ')
459 		return;
460 
461 	const uint32_t pixVal1 = video.palette[paletteIndex];
462 	const uint32_t pixVal2 = video.palette[shadowPaletteIndex];
463 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];
464 	uint32_t *dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
465 	uint32_t *dstPtr2 = dstPtr1 + (SCREEN_W+1);
466 
467 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)
468 	{
469 		for (int32_t x = 0; x < FONT1_CHAR_W; x++)
470 		{
471 #ifdef __arm__
472 			if (srcPtr[x] != 0)
473 			{
474 				dstPtr2[x] = pixVal2;
475 				dstPtr1[x] = pixVal1;
476 			}
477 #else
478 			// carefully written like this to generate conditional move instructions (font data is hard to predict)
479 			uint32_t tmp = dstPtr2[x];
480 			if (srcPtr[x] != 0) tmp = pixVal2;
481 			dstPtr2[x] = tmp;
482 
483 			tmp = dstPtr1[x];
484 			if (srcPtr[x] != 0) tmp = pixVal1;
485 			dstPtr1[x] = tmp;
486 #endif
487 		}
488 
489 		srcPtr += FONT1_WIDTH;
490 		dstPtr1 += SCREEN_W;
491 		dstPtr2 += SCREEN_W;
492 	}
493 }
494 
charOutClipX(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,char chr,uint16_t clipX)495 void charOutClipX(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, uint16_t clipX)
496 {
497 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
498 
499 	if (xPos > clipX)
500 		return;
501 
502 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
503 	if (chr == ' ')
504 		return;
505 
506 	const uint32_t pixVal = video.palette[paletteIndex];
507 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];
508 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
509 
510 	int32_t width = FONT1_CHAR_W;
511 	if (xPos+width > clipX)
512 		width = FONT1_CHAR_W - ((xPos + width) - clipX);
513 
514 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)
515 	{
516 		for (int32_t x = 0; x < width; x++)
517 		{
518 #ifdef __arm__
519 			if (srcPtr[x] != 0)
520 				dstPtr[x] = pixVal;
521 #else
522 			// carefully written like this to generate conditional move instructions (font data is hard to predict)
523 			uint32_t tmp = dstPtr[x];
524 			if (srcPtr[x] != 0) tmp = pixVal;
525 			dstPtr[x] = tmp;
526 #endif
527 		}
528 
529 		srcPtr += FONT1_WIDTH;
530 		dstPtr += SCREEN_W;
531 	}
532 }
533 
bigCharOut(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,char chr)534 void bigCharOut(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr)
535 {
536 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
537 
538 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
539 	if (chr == ' ')
540 		return;
541 
542 	const uint8_t *srcPtr = &bmp.font2[chr * FONT2_CHAR_W];
543 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
544 	const uint32_t pixVal = video.palette[paletteIndex];
545 
546 	for (int32_t y = 0; y < FONT2_CHAR_H; y++)
547 	{
548 		for (int32_t x = 0; x < FONT2_CHAR_W; x++)
549 		{
550 #ifdef __arm__
551 			if (srcPtr[x] != 0)
552 				dstPtr[x] = pixVal;
553 #else
554 			// carefully written like this to generate conditional move instructions (font data is hard to predict)
555 			uint32_t tmp = dstPtr[x];
556 			if (srcPtr[x] != 0) tmp = pixVal;
557 			dstPtr[x] = tmp;
558 #endif
559 		}
560 
561 		srcPtr += FONT2_WIDTH;
562 		dstPtr += SCREEN_W;
563 	}
564 }
565 
bigCharOutShadow(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,uint8_t shadowPaletteIndex,char chr)566 static void bigCharOutShadow(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, uint8_t shadowPaletteIndex, char chr)
567 {
568 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
569 
570 	chr &= 0x7F; // this is important to get the nordic glyphs in the font
571 	if (chr == ' ')
572 		return;
573 
574 	const uint32_t pixVal1 = video.palette[paletteIndex];
575 	const uint32_t pixVal2 = video.palette[shadowPaletteIndex];
576 	const uint8_t *srcPtr = &bmp.font2[chr * FONT2_CHAR_W];
577 	uint32_t *dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
578 	uint32_t *dstPtr2 = dstPtr1 + (SCREEN_W+1);
579 
580 	for (int32_t y = 0; y < FONT2_CHAR_H; y++)
581 	{
582 		for (int32_t x = 0; x < FONT2_CHAR_W; x++)
583 		{
584 #ifdef __arm__
585 			if (srcPtr[x] != 0)
586 			{
587 				dstPtr2[x] = pixVal2;
588 				dstPtr1[x] = pixVal1;
589 			}
590 #else
591 			// carefully written like this to generate conditional move instructions (font data is hard to predict)
592 			uint32_t tmp = dstPtr2[x];
593 			if (srcPtr[x] != 0) tmp = pixVal2;
594 			dstPtr2[x] = tmp;
595 
596 			tmp = dstPtr1[x];
597 			if (srcPtr[x] != 0) tmp = pixVal1;
598 			dstPtr1[x] = tmp;
599 #endif
600 		}
601 
602 		srcPtr += FONT2_WIDTH;
603 		dstPtr1 += SCREEN_W;
604 		dstPtr2 += SCREEN_W;
605 	}
606 }
607 
textOut(uint16_t x,uint16_t y,uint8_t paletteIndex,const char * textPtr)608 void textOut(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr)
609 {
610 	assert(textPtr != NULL);
611 
612 	uint16_t currX = x;
613 	while (true)
614 	{
615 		const char chr = *textPtr++;
616 		if (chr == '\0')
617 			break;
618 
619 		charOut(currX, y, paletteIndex, chr);
620 		currX += charWidth(chr);
621 	}
622 }
623 
textOutFade(uint16_t x,uint16_t y,uint8_t paletteIndex,const char * textPtr,int32_t fade)624 void textOutFade(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr, int32_t fade) // for about screen
625 {
626 	char chr;
627 	uint16_t currX;
628 
629 	assert(textPtr != NULL);
630 
631 	currX = x;
632 	while (true)
633 	{
634 		chr = *textPtr++;
635 		if (chr == '\0')
636 			break;
637 
638 		charOutFade(currX, y, paletteIndex, chr, fade);
639 		currX += charWidth(chr);
640 	}
641 }
642 
textOutBorder(uint16_t x,uint16_t y,uint8_t paletteIndex,uint8_t borderPaletteIndex,const char * textPtr)643 void textOutBorder(uint16_t x, uint16_t y, uint8_t paletteIndex, uint8_t borderPaletteIndex, const char *textPtr)
644 {
645 	textOut(x,   y-1, borderPaletteIndex, textPtr); // top
646 	textOut(x+1, y,   borderPaletteIndex, textPtr); // right
647 	textOut(x,   y+1, borderPaletteIndex, textPtr); // bottom
648 	textOut(x-1, y,   borderPaletteIndex, textPtr); // left
649 
650 	textOut(x, y, paletteIndex, textPtr);
651 }
652 
653 // fixed width
textOutFixed(uint16_t x,uint16_t y,uint8_t fgPaltete,uint8_t bgPalette,const char * textPtr)654 void textOutFixed(uint16_t x, uint16_t y, uint8_t fgPaltete, uint8_t bgPalette, const char *textPtr)
655 {
656 	assert(textPtr != NULL);
657 
658 	uint16_t currX = x;
659 	while (true)
660 	{
661 		const char chr = *textPtr++;
662 		if (chr == '\0')
663 			break;
664 
665 		charOutBg(currX, y, fgPaltete, bgPalette, chr);
666 		currX += FONT1_CHAR_W-1;
667 	}
668 }
669 
textOutShadow(uint16_t x,uint16_t y,uint8_t paletteIndex,uint8_t shadowPaletteIndex,const char * textPtr)670 void textOutShadow(uint16_t x, uint16_t y, uint8_t paletteIndex, uint8_t shadowPaletteIndex, const char *textPtr)
671 {
672 	assert(textPtr != NULL);
673 
674 	uint16_t currX = x;
675 	while (true)
676 	{
677 		const char chr = *textPtr++;
678 		if (chr == '\0')
679 			break;
680 
681 		charOutShadow(currX, y, paletteIndex, shadowPaletteIndex, chr);
682 		currX += charWidth(chr);
683 	}
684 }
685 
bigTextOut(uint16_t x,uint16_t y,uint8_t paletteIndex,const char * textPtr)686 void bigTextOut(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr)
687 {
688 	assert(textPtr != NULL);
689 
690 	uint16_t currX = x;
691 	while (true)
692 	{
693 		const char chr = *textPtr++;
694 		if (chr == '\0')
695 			break;
696 
697 		bigCharOut(currX, y, paletteIndex, chr);
698 		currX += charWidth16(chr);
699 	}
700 }
701 
bigTextOutShadow(uint16_t x,uint16_t y,uint8_t paletteIndex,uint8_t shadowPaletteIndex,const char * textPtr)702 void bigTextOutShadow(uint16_t x, uint16_t y, uint8_t paletteIndex, uint8_t shadowPaletteIndex, const char *textPtr)
703 {
704 	assert(textPtr != NULL);
705 
706 	uint16_t currX = x;
707 	while (true)
708 	{
709 		const char chr = *textPtr++;
710 		if (chr == '\0')
711 			break;
712 
713 		bigCharOutShadow(currX, y, paletteIndex, shadowPaletteIndex, chr);
714 		currX += charWidth16(chr);
715 	}
716 }
717 
textOutClipX(uint16_t x,uint16_t y,uint8_t paletteIndex,const char * textPtr,uint16_t clipX)718 void textOutClipX(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr, uint16_t clipX)
719 {
720 	assert(textPtr != NULL);
721 
722 	uint16_t currX = x;
723 	while (true)
724 	{
725 		const char chr = *textPtr++;
726 		if (chr == '\0')
727 			break;
728 
729 		charOutClipX(currX, y, paletteIndex, chr, clipX);
730 
731 		currX += charWidth(chr);
732 		if (currX >= clipX)
733 			break;
734 	}
735 }
736 
hexOut(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,uint32_t val,uint8_t numDigits)737 void hexOut(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, uint32_t val, uint8_t numDigits)
738 {
739 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
740 
741 	const uint32_t pixVal = video.palette[paletteIndex];
742 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
743 
744 	for (int32_t i = numDigits-1; i >= 0; i--)
745 	{
746 		const uint8_t *srcPtr = &bmp.font6[((val >> (i * 4)) & 15) * FONT6_CHAR_W];
747 
748 		// render glyph
749 		for (int32_t y = 0; y < FONT6_CHAR_H; y++)
750 		{
751 			for (int32_t x = 0; x < FONT6_CHAR_W; x++)
752 			{
753 #ifdef __arm__
754 				if (srcPtr[x] != 0)
755 					dstPtr[x] = pixVal;
756 #else
757 				// carefully written like this to generate conditional move instructions (font data is hard to predict)
758 				uint32_t tmp = dstPtr[x];
759 				if (srcPtr[x] != 0) tmp = pixVal;
760 				dstPtr[x] = tmp;
761 #endif
762 			}
763 
764 			srcPtr += FONT6_WIDTH;
765 			dstPtr += SCREEN_W;
766 		}
767 
768 		dstPtr -= (SCREEN_W * FONT6_CHAR_H) - FONT6_CHAR_W; // xpos += FONT6_CHAR_W
769 	}
770 }
771 
hexOutBg(uint16_t xPos,uint16_t yPos,uint8_t fgPalette,uint8_t bgPalette,uint32_t val,uint8_t numDigits)772 void hexOutBg(uint16_t xPos, uint16_t yPos, uint8_t fgPalette, uint8_t bgPalette, uint32_t val, uint8_t numDigits)
773 {
774 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
775 
776 	const uint32_t fg = video.palette[fgPalette];
777 	const uint32_t bg = video.palette[bgPalette];
778 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
779 
780 	for (int32_t i = numDigits-1; i >= 0; i--)
781 	{
782 		// extract current nybble and set pointer to glyph
783 		const uint8_t *srcPtr = &bmp.font6[((val >> (i * 4)) & 15) * FONT6_CHAR_W];
784 
785 		// render glyph
786 		for (int32_t y = 0; y < FONT6_CHAR_H; y++)
787 		{
788 			for (int32_t x = 0; x < FONT6_CHAR_W; x++)
789 				dstPtr[x] = srcPtr[x] ? fg : bg; // compiles nicely into conditional move instructions
790 
791 			srcPtr += FONT6_WIDTH;
792 			dstPtr += SCREEN_W;
793 		}
794 
795 		dstPtr -= (SCREEN_W * FONT6_CHAR_H) - FONT6_CHAR_W; // xpos += FONT6_CHAR_W
796 	}
797 }
798 
hexOutShadow(uint16_t xPos,uint16_t yPos,uint8_t paletteIndex,uint8_t shadowPaletteIndex,uint32_t val,uint8_t numDigits)799 void hexOutShadow(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, uint8_t shadowPaletteIndex, uint32_t val, uint8_t numDigits)
800 {
801 	hexOut(xPos + 1, yPos + 1, shadowPaletteIndex, val, numDigits);
802 	hexOut(xPos + 0, yPos + 0,       paletteIndex, val, numDigits);
803 }
804 
805 // FILL ROUTINES
806 
clearRect(uint16_t xPos,uint16_t yPos,uint16_t w,uint16_t h)807 void clearRect(uint16_t xPos, uint16_t yPos, uint16_t w, uint16_t h)
808 {
809 	assert(xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
810 
811 	const uint32_t width = w * sizeof (int32_t);
812 
813 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
814 	for (int32_t y = 0; y < h; y++)
815 	{
816 		memset(dstPtr, 0, width);
817 		dstPtr += SCREEN_W;
818 	}
819 }
820 
fillRect(uint16_t xPos,uint16_t yPos,uint16_t w,uint16_t h,uint8_t paletteIndex)821 void fillRect(uint16_t xPos, uint16_t yPos, uint16_t w, uint16_t h, uint8_t paletteIndex)
822 {
823 	assert(xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
824 
825 	const uint32_t pixVal = video.palette[paletteIndex];
826 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
827 
828 	for (int32_t y = 0; y < h; y++)
829 	{
830 		for (int32_t x = 0; x < w; x++)
831 			dstPtr[x] = pixVal;
832 
833 		dstPtr += SCREEN_W;
834 	}
835 }
836 
blit32(uint16_t xPos,uint16_t yPos,const uint32_t * srcPtr,uint16_t w,uint16_t h)837 void blit32(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h)
838 {
839 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
840 
841 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
842 	for (int32_t y = 0; y < h; y++)
843 	{
844 		for (int32_t x = 0; x < w; x++)
845 		{
846 			if (srcPtr[x] != 0x00FF00)
847 				dstPtr[x] = srcPtr[x] | 0xFF000000; // most significant 8 bits = palette number. 0xFF because no true palette
848 		}
849 
850 		srcPtr += w;
851 		dstPtr += SCREEN_W;
852 	}
853 }
854 
blit32Fade(uint16_t xPos,uint16_t yPos,const uint32_t * srcPtr,uint16_t w,uint16_t h,int32_t fade)855 void blit32Fade(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h, int32_t fade) // for about screen
856 {
857 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
858 
859 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
860 	for (int32_t y = 0; y < h; y++)
861 	{
862 		for (int32_t x = 0; x < w; x++)
863 		{
864 			const uint32_t pixel = srcPtr[x];
865 			if (pixel != 0x00FF00)
866 			{
867 				const int32_t r = (RGB32_R(pixel) * fade) >> 8;
868 				const int32_t g = (RGB32_G(pixel) * fade) >> 8;
869 				const int32_t b = (RGB32_B(pixel) * fade) >> 8;
870 
871 				dstPtr[x] = RGB32(r, g, b) | 0xFF000000; // most significant 8 bits = palette number. 0xFF because no true palette
872 			}
873 		}
874 
875 		srcPtr += w;
876 		dstPtr += SCREEN_W;
877 	}
878 }
879 
blit(uint16_t xPos,uint16_t yPos,const uint8_t * srcPtr,uint16_t w,uint16_t h)880 void blit(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h)
881 {
882 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
883 
884 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
885 	for (int32_t y = 0; y < h; y++)
886 	{
887 		for (int32_t x = 0; x < w; x++)
888 		{
889 			const uint32_t pixel = srcPtr[x];
890 			if (pixel != PAL_TRANSPR)
891 				dstPtr[x] = video.palette[pixel];
892 		}
893 
894 		srcPtr += w;
895 		dstPtr += SCREEN_W;
896 	}
897 }
898 
blitClipX(uint16_t xPos,uint16_t yPos,const uint8_t * srcPtr,uint16_t w,uint16_t h,uint16_t clipX)899 void blitClipX(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h, uint16_t clipX)
900 {
901 	if (clipX > w)
902 		clipX = w;
903 
904 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + clipX) <= SCREEN_W && (yPos + h) <= SCREEN_H);
905 
906 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
907 	for (int32_t y = 0; y < h; y++)
908 	{
909 		for (int32_t x = 0; x < clipX; x++)
910 		{
911 			const uint32_t pixel = srcPtr[x];
912 			if (pixel != PAL_TRANSPR)
913 				dstPtr[x] = video.palette[pixel];
914 		}
915 
916 		srcPtr += w;
917 		dstPtr += SCREEN_W;
918 	}
919 }
920 
blitFast(uint16_t xPos,uint16_t yPos,const uint8_t * srcPtr,uint16_t w,uint16_t h)921 void blitFast(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h) // no transparency/colorkey
922 {
923 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
924 
925 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
926 	for (int32_t y = 0; y < h; y++)
927 	{
928 		for (int32_t x = 0; x < w; x++)
929 			dstPtr[x] = video.palette[srcPtr[x]];
930 
931 		srcPtr += w;
932 		dstPtr += SCREEN_W;
933 	}
934 }
935 
blitFastClipX(uint16_t xPos,uint16_t yPos,const uint8_t * srcPtr,uint16_t w,uint16_t h,uint16_t clipX)936 void blitFastClipX(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h, uint16_t clipX) // no transparency/colorkey
937 {
938 	if (clipX > w)
939 		clipX = w;
940 
941 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + clipX) <= SCREEN_W && (yPos + h) <= SCREEN_H);
942 
943 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
944 	for (int32_t y = 0; y < h; y++)
945 	{
946 		for (int32_t x = 0; x < clipX; x++)
947 			dstPtr[x] = video.palette[srcPtr[x]];
948 
949 		srcPtr += w;
950 		dstPtr += SCREEN_W;
951 	}
952 }
953 
954 // LINE ROUTINES
955 
hLine(uint16_t x,uint16_t y,uint16_t w,uint8_t paletteIndex)956 void hLine(uint16_t x, uint16_t y, uint16_t w, uint8_t paletteIndex)
957 {
958 	assert(x < SCREEN_W && y < SCREEN_H && (x + w) <= SCREEN_W);
959 
960 	const uint32_t pixVal = video.palette[paletteIndex];
961 
962 	uint32_t *dstPtr = &video.frameBuffer[(y * SCREEN_W) + x];
963 	for (int32_t i = 0; i < w; i++)
964 		dstPtr[i] = pixVal;
965 }
966 
vLine(uint16_t x,uint16_t y,uint16_t h,uint8_t paletteIndex)967 void vLine(uint16_t x, uint16_t y, uint16_t h, uint8_t paletteIndex)
968 {
969 	assert(x < SCREEN_W && y < SCREEN_H && (y + h) <= SCREEN_W);
970 
971 	const uint32_t pixVal = video.palette[paletteIndex];
972 
973 	uint32_t *dstPtr = &video.frameBuffer[(y * SCREEN_W) + x];
974 	for (int32_t i = 0; i < h; i++)
975 	{
976 		*dstPtr = pixVal;
977 		 dstPtr += SCREEN_W;
978 	}
979 }
980 
hLineDouble(uint16_t x,uint16_t y,uint16_t w,uint8_t paletteIndex)981 void hLineDouble(uint16_t x, uint16_t y, uint16_t w, uint8_t paletteIndex)
982 {
983 	hLine(x, y, w, paletteIndex);
984 	hLine(x, y+1, w, paletteIndex);
985 }
986 
vLineDouble(uint16_t x,uint16_t y,uint16_t h,uint8_t paletteIndex)987 void vLineDouble(uint16_t x, uint16_t y, uint16_t h, uint8_t paletteIndex)
988 {
989 	vLine(x, y, h, paletteIndex);
990 	vLine(x+1, y, h, paletteIndex);
991 }
992 
line(int16_t x1,int16_t x2,int16_t y1,int16_t y2,uint8_t paletteIndex)993 void line(int16_t x1, int16_t x2, int16_t y1, int16_t y2, uint8_t paletteIndex)
994 {
995 	const int16_t dx = x2 - x1;
996 	const uint16_t ax = ABS(dx) * 2;
997 	const int16_t sx = SGN(dx);
998 	const int16_t dy = y2 - y1;
999 	const uint16_t ay = ABS(dy) * 2;
1000 	const int16_t sy = SGN(dy);
1001 	int16_t x = x1;
1002 	int16_t y  = y1;
1003 
1004 	uint32_t pixVal = video.palette[paletteIndex];
1005 	const int32_t pitch  = sy * SCREEN_W;
1006 	uint32_t *dst32  = &video.frameBuffer[(y * SCREEN_W) + x];
1007 
1008 	// draw line
1009 	if (ax > ay)
1010 	{
1011 		int16_t d = ay - (ax >> 1);
1012 		while (true)
1013 		{
1014 			*dst32 = pixVal;
1015 			if (x == x2)
1016 				break;
1017 
1018 			if (d >= 0)
1019 			{
1020 				d -= ax;
1021 				dst32 += pitch;
1022 			}
1023 
1024 			x += sx;
1025 			d += ay;
1026 			dst32 += sx;
1027 		}
1028 	}
1029 	else
1030 	{
1031 		int16_t d = ax - (ay >> 1);
1032 		while (true)
1033 		{
1034 			*dst32 = pixVal;
1035 			if (y == y2)
1036 				break;
1037 
1038 			if (d >= 0)
1039 			{
1040 				d -= ay;
1041 				dst32 += sx;
1042 			}
1043 
1044 			y += sy;
1045 			d += ax;
1046 			dst32 += pitch;
1047 		}
1048 	}
1049 }
1050 
drawFramework(uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint8_t type)1051 void drawFramework(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t type)
1052 {
1053 	assert(x < SCREEN_W && y < SCREEN_H && w >= 2 && h >= h);
1054 
1055 	h--;
1056 	w--;
1057 
1058 	if (type == FRAMEWORK_TYPE1)
1059 	{
1060 		// top left corner
1061 		hLine(x, y,     w,     PAL_DSKTOP1);
1062 		vLine(x, y + 1, h - 1, PAL_DSKTOP1);
1063 
1064 		// bottom right corner
1065 		hLine(x,     y + h, w,     PAL_DSKTOP2);
1066 		vLine(x + w, y,     h + 1, PAL_DSKTOP2);
1067 
1068 		// fill background
1069 		fillRect(x + 1, y + 1, w - 1, h - 1, PAL_DESKTOP);
1070 	}
1071 	else
1072 	{
1073 		// top left corner
1074 		hLine(x, y,     w + 1, PAL_DSKTOP2);
1075 		vLine(x, y + 1, h,     PAL_DSKTOP2);
1076 
1077 		// bottom right corner
1078 		hLine(x + 1, y + h, w,     PAL_DSKTOP1);
1079 		vLine(x + w, y + 1, h - 1, PAL_DSKTOP1);
1080 
1081 		// clear background
1082 		clearRect(x + 1, y + 1, w - 1, h - 1);
1083 	}
1084 }
1085 
1086 // GUI FUNCTIONS
1087 
showTopLeftMainScreen(bool restoreScreens)1088 void showTopLeftMainScreen(bool restoreScreens)
1089 {
1090 	ui.diskOpShown = false;
1091 	ui.sampleEditorExtShown = false;
1092 	ui.instEditorExtShown = false;
1093 	ui.transposeShown = false;
1094 	ui.advEditShown = false;
1095 	ui.wavRendererShown = false;
1096 	ui.trimScreenShown = false;
1097 
1098 	ui.scopesShown = true;
1099 	if (restoreScreens)
1100 	{
1101 		switch (ui.oldTopLeftScreen)
1102 		{
1103 			default: break;
1104 			case 1: ui.diskOpShown = true; break;
1105 			case 2: ui.sampleEditorExtShown = true; break;
1106 			case 3: ui.instEditorExtShown = true; break;
1107 			case 4: ui.transposeShown = true; break;
1108 			case 5: ui.advEditShown = true; break;
1109 			case 6: ui.wavRendererShown = true; break;
1110 			case 7: ui.trimScreenShown = true; break;
1111 		}
1112 
1113 		if (ui.oldTopLeftScreen > 0)
1114 			ui.scopesShown = false;
1115 	}
1116 
1117 	ui.oldTopLeftScreen = 0;
1118 
1119 	if (ui.diskOpShown)
1120 	{
1121 		showDiskOpScreen();
1122 	}
1123 	else
1124 	{
1125 		// pos ed.
1126 		drawFramework(0, 0, 112, 77, FRAMEWORK_TYPE1);
1127 		drawFramework(2, 2,  51, 19, FRAMEWORK_TYPE2);
1128 		drawFramework(2,30,  51, 19, FRAMEWORK_TYPE2);
1129 		showScrollBar(SB_POS_ED);
1130 		showPushButton(PB_POSED_POS_UP);
1131 		showPushButton(PB_POSED_POS_DOWN);
1132 		showPushButton(PB_POSED_INS);
1133 		showPushButton(PB_POSED_PATT_UP);
1134 		showPushButton(PB_POSED_PATT_DOWN);
1135 		showPushButton(PB_POSED_DEL);
1136 		showPushButton(PB_POSED_LEN_UP);
1137 		showPushButton(PB_POSED_LEN_DOWN);
1138 		showPushButton(PB_POSED_REP_UP);
1139 		showPushButton(PB_POSED_REP_DOWN);
1140 		textOutShadow(4, 52, PAL_FORGRND, PAL_DSKTOP2, "Songlen.");
1141 		textOutShadow(4, 64, PAL_FORGRND, PAL_DSKTOP2, "Repstart");
1142 		drawPosEdNums(song.songPos);
1143 		drawSongLength();
1144 		drawSongLoopStart();
1145 
1146 		// logo button
1147 		showPushButton(PB_LOGO);
1148 		showPushButton(PB_BADGE);
1149 
1150 		// left menu
1151 		drawFramework(291, 0, 65, 173, FRAMEWORK_TYPE1);
1152 		showPushButton(PB_ABOUT);
1153 		showPushButton(PB_NIBBLES);
1154 		showPushButton(PB_KILL);
1155 		showPushButton(PB_TRIM);
1156 		showPushButton(PB_EXTEND_VIEW);
1157 		showPushButton(PB_TRANSPOSE);
1158 		showPushButton(PB_INST_ED_EXT);
1159 		showPushButton(PB_SMP_ED_EXT);
1160 		showPushButton(PB_ADV_EDIT);
1161 		showPushButton(PB_ADD_CHANNELS);
1162 		showPushButton(PB_SUB_CHANNELS);
1163 
1164 		// song/pattern
1165 		drawFramework(112, 32, 94, 45, FRAMEWORK_TYPE1);
1166 		drawFramework(206, 32, 85, 45, FRAMEWORK_TYPE1);
1167 		showPushButton(PB_BPM_UP);
1168 		showPushButton(PB_BPM_DOWN);
1169 		showPushButton(PB_SPEED_UP);
1170 		showPushButton(PB_SPEED_DOWN);
1171 		showPushButton(PB_EDITADD_UP);
1172 		showPushButton(PB_EDITADD_DOWN);
1173 		showPushButton(PB_PATT_UP);
1174 		showPushButton(PB_PATT_DOWN);
1175 		showPushButton(PB_PATTLEN_UP);
1176 		showPushButton(PB_PATTLEN_DOWN);
1177 		showPushButton(PB_PATT_EXPAND);
1178 		showPushButton(PB_PATT_SHRINK);
1179 		textOutShadow(116, 36, PAL_FORGRND, PAL_DSKTOP2, "BPM");
1180 		textOutShadow(116, 50, PAL_FORGRND, PAL_DSKTOP2, "Spd.");
1181 		textOutShadow(116, 64, PAL_FORGRND, PAL_DSKTOP2, "Add.");
1182 		textOutShadow(210, 36, PAL_FORGRND, PAL_DSKTOP2, "Ptn.");
1183 		textOutShadow(210, 50, PAL_FORGRND, PAL_DSKTOP2, "Ln.");
1184 		drawSongBPM(song.BPM);
1185 		drawSongSpeed(song.speed);
1186 		drawEditPattern(editor.editPattern);
1187 		drawPatternLength(editor.editPattern);
1188 		drawIDAdd();
1189 
1190 		// status bar
1191 		drawFramework(0, 77, 291, 15, FRAMEWORK_TYPE1);
1192 		textOutShadow(4, 80, PAL_FORGRND, PAL_DSKTOP2, "Global volume");
1193 		drawGlobalVol(song.globalVolume);
1194 
1195 		ui.updatePosSections = true;
1196 
1197 		textOutShadow(204, 80, PAL_FORGRND, PAL_DSKTOP2, "Time");
1198 		charOutShadow(250, 80, PAL_FORGRND, PAL_DSKTOP2, ':');
1199 		charOutShadow(270, 80, PAL_FORGRND, PAL_DSKTOP2, ':');
1200 
1201 		drawPlaybackTime();
1202 
1203 		     if (ui.sampleEditorExtShown) drawSampleEditorExt();
1204 		else if (ui.instEditorExtShown)   drawInstEditorExt();
1205 		else if (ui.transposeShown)       drawTranspose();
1206 		else if (ui.advEditShown)         drawAdvEdit();
1207 		else if (ui.wavRendererShown)     drawWavRenderer();
1208 		else if (ui.trimScreenShown)      drawTrimScreen();
1209 
1210 		if (ui.scopesShown)
1211 			drawScopeFramework();
1212 	}
1213 }
1214 
hideTopLeftMainScreen(void)1215 void hideTopLeftMainScreen(void)
1216 {
1217 	hideDiskOpScreen();
1218 	hideInstEditorExt();
1219 	hideSampleEditorExt();
1220 	hideTranspose();
1221 	hideAdvEdit();
1222 	hideWavRenderer();
1223 	hideTrimScreen();
1224 
1225 	ui.scopesShown = false;
1226 
1227 	// position editor
1228 	hideScrollBar(SB_POS_ED);
1229 
1230 	hidePushButton(PB_POSED_POS_UP);
1231 	hidePushButton(PB_POSED_POS_DOWN);
1232 	hidePushButton(PB_POSED_INS);
1233 	hidePushButton(PB_POSED_PATT_UP);
1234 	hidePushButton(PB_POSED_PATT_DOWN);
1235 	hidePushButton(PB_POSED_DEL);
1236 	hidePushButton(PB_POSED_LEN_UP);
1237 	hidePushButton(PB_POSED_LEN_DOWN);
1238 	hidePushButton(PB_POSED_REP_UP);
1239 	hidePushButton(PB_POSED_REP_DOWN);
1240 
1241 	// logo button
1242 	hidePushButton(PB_LOGO);
1243 	hidePushButton(PB_BADGE);
1244 
1245 	// left menu
1246 	hidePushButton(PB_ABOUT);
1247 	hidePushButton(PB_NIBBLES);
1248 	hidePushButton(PB_KILL);
1249 	hidePushButton(PB_TRIM);
1250 	hidePushButton(PB_EXTEND_VIEW);
1251 	hidePushButton(PB_TRANSPOSE);
1252 	hidePushButton(PB_INST_ED_EXT);
1253 	hidePushButton(PB_SMP_ED_EXT);
1254 	hidePushButton(PB_ADV_EDIT);
1255 	hidePushButton(PB_ADD_CHANNELS);
1256 	hidePushButton(PB_SUB_CHANNELS);
1257 
1258 	// song/pattern
1259 	hidePushButton(PB_BPM_UP);
1260 	hidePushButton(PB_BPM_DOWN);
1261 	hidePushButton(PB_SPEED_UP);
1262 	hidePushButton(PB_SPEED_DOWN);
1263 	hidePushButton(PB_EDITADD_UP);
1264 	hidePushButton(PB_EDITADD_DOWN);
1265 	hidePushButton(PB_PATT_UP);
1266 	hidePushButton(PB_PATT_DOWN);
1267 	hidePushButton(PB_PATTLEN_UP);
1268 	hidePushButton(PB_PATTLEN_DOWN);
1269 	hidePushButton(PB_PATT_EXPAND);
1270 	hidePushButton(PB_PATT_SHRINK);
1271 }
1272 
showTopRightMainScreen(void)1273 void showTopRightMainScreen(void)
1274 {
1275 	// right menu
1276 	drawFramework(356, 0, 65, 173, FRAMEWORK_TYPE1);
1277 	showPushButton(PB_PLAY_SONG);
1278 	showPushButton(PB_PLAY_PATT);
1279 	showPushButton(PB_STOP);
1280 	showPushButton(PB_RECORD_SONG);
1281 	showPushButton(PB_RECORD_PATT);
1282 	showPushButton(PB_DISK_OP);
1283 	showPushButton(PB_INST_ED);
1284 	showPushButton(PB_SMP_ED);
1285 	showPushButton(PB_CONFIG);
1286 	showPushButton(PB_HELP);
1287 
1288 	// instrument switcher
1289 	ui.instrSwitcherShown = true;
1290 	showInstrumentSwitcher();
1291 
1292 	// song name
1293 	showTextBox(TB_SONG_NAME);
1294 	drawSongName();
1295 }
1296 
hideTopRightMainScreen(void)1297 void hideTopRightMainScreen(void)
1298 {
1299 	// right menu
1300 	hidePushButton(PB_PLAY_SONG);
1301 	hidePushButton(PB_PLAY_PATT);
1302 	hidePushButton(PB_STOP);
1303 	hidePushButton(PB_RECORD_SONG);
1304 	hidePushButton(PB_RECORD_PATT);
1305 	hidePushButton(PB_DISK_OP);
1306 	hidePushButton(PB_INST_ED);
1307 	hidePushButton(PB_SMP_ED);
1308 	hidePushButton(PB_CONFIG);
1309 	hidePushButton(PB_HELP);
1310 
1311 	// instrument switcher
1312 	hideInstrumentSwitcher();
1313 	ui.instrSwitcherShown = false;
1314 
1315 	hideTextBox(TB_SONG_NAME);
1316 }
1317 
1318 // BOTTOM STUFF
1319 
setOldTopLeftScreenFlag(void)1320 void setOldTopLeftScreenFlag(void)
1321 {
1322 	     if (ui.diskOpShown)          ui.oldTopLeftScreen = 1;
1323 	else if (ui.sampleEditorExtShown) ui.oldTopLeftScreen = 2;
1324 	else if (ui.instEditorExtShown)   ui.oldTopLeftScreen = 3;
1325 	else if (ui.transposeShown)       ui.oldTopLeftScreen = 4;
1326 	else if (ui.advEditShown)         ui.oldTopLeftScreen = 5;
1327 	else if (ui.wavRendererShown)     ui.oldTopLeftScreen = 6;
1328 	else if (ui.trimScreenShown)      ui.oldTopLeftScreen = 7;
1329 }
1330 
hideTopLeftScreen(void)1331 void hideTopLeftScreen(void)
1332 {
1333 	setOldTopLeftScreenFlag();
1334 
1335 	hideTopLeftMainScreen();
1336 	hideNibblesScreen();
1337 	hideConfigScreen();
1338 	hideAboutScreen();
1339 	hideHelpScreen();
1340 }
1341 
hideTopScreen(void)1342 void hideTopScreen(void)
1343 {
1344 	setOldTopLeftScreenFlag();
1345 
1346 	hideTopLeftMainScreen();
1347 	hideTopRightMainScreen();
1348 	hideNibblesScreen();
1349 	hideConfigScreen();
1350 	hideAboutScreen();
1351 	hideHelpScreen();
1352 
1353 	ui.instrSwitcherShown = false;
1354 	ui.scopesShown = false;
1355 }
1356 
showTopScreen(bool restoreScreens)1357 void showTopScreen(bool restoreScreens)
1358 {
1359 	ui.scopesShown = false;
1360 
1361 	if (ui.aboutScreenShown)
1362 	{
1363 		showAboutScreen();
1364 	}
1365 	else if (ui.configScreenShown)
1366 	{
1367 		showConfigScreen();
1368 	}
1369 	else if (ui.helpScreenShown)
1370 	{
1371 		showHelpScreen();
1372 	}
1373 	else if (ui.nibblesShown)
1374 	{
1375 		showNibblesScreen();
1376 	}
1377 	else
1378 	{
1379 		showTopLeftMainScreen(restoreScreens); // updates ui.scopesShown
1380 		showTopRightMainScreen();
1381 	}
1382 }
1383 
showBottomScreen(void)1384 void showBottomScreen(void)
1385 {
1386 	if (ui.extended || ui.patternEditorShown)
1387 		showPatternEditor();
1388 	else if (ui.instEditorShown)
1389 		showInstEditor();
1390 	else if (ui.sampleEditorShown)
1391 		showSampleEditor();
1392 }
1393 
drawGUIOnRunTime(void)1394 void drawGUIOnRunTime(void)
1395 {
1396 	setScrollBarPos(SB_POS_ED, 0, false);
1397 
1398 	showTopScreen(false); // false = don't restore screens
1399 	showPatternEditor();
1400 
1401 	ui.updatePosSections = true;
1402 }
1403