ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

ft2_gui.c (30440B)


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