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