ref: ba9a38b8266fd42f2bc327b7e6e60866812cbb92
dir: /src/pt2_askbox.c/
#include <stdint.h> #include <stdbool.h> #include "pt2_textout.h" #include "pt2_visuals.h" #include "pt2_mouse.h" #include "pt2_structs.h" #include "pt2_visuals_sync.h" #include "pt2_keyboard.h" #include "pt2_diskop.h" #include "pt2_mod2wav.h" #include "pt2_pat2smp.h" #include "pt2_askbox.h" #define INIT_BUTTONS(num, abortRetVal, defRetVal) \ d.numButtons = num; \ d.abortReturnValue = abortRetVal; \ d.defaultReturnValue = defRetVal; #define SET_DIALOG(xx, yy, ww, hh) \ d.x = xx; \ d.y = yy; \ d.w = ww; \ d.h = hh; #define SET_BUTTON(i, invert, label, key, retVal, xx1, xx2, yy1, yy2) \ strcpy(d.buttons[i].text, label); \ d.buttons[i].repeat = false; \ d.buttons[i].inverted = invert; \ d.buttons[i].callback = NULL; \ d.buttons[i].keyBinding = key; \ d.buttons[i].returnValue = retVal; \ d.buttons[i].clickableWidth = 0; \ d.buttons[i].x1 = xx1; \ d.buttons[i].x2 = xx2; \ d.buttons[i].y1 = yy1; \ d.buttons[i].y2 = yy2; #define SET_CALLBACK_BUTTON(i, label, func, clickWidth, xx1, xx2, yy1, yy2, doRepeat) \ strcpy(d.buttons[i].text, label); \ d.buttons[i].repeat = true; \ d.buttons[i].inverted = false; \ d.buttons[i].callback = func; \ d.buttons[i].clickableWidth = clickWidth; \ d.buttons[i].x1 = xx1; \ d.buttons[i].x2 = xx2; \ d.buttons[i].y1 = yy1; \ d.buttons[i].y2 = yy2; typedef struct choice_t { void (*callback)(void); bool inverted, repeat; int16_t x1, y1, x2, y2, clickableWidth; SDL_Keycode keyBinding; int16_t returnValue; char text[32]; } button_t; typedef struct dialog_t { bool bigDialog; int16_t x, y, w, h, numButtons, defaultReturnValue, abortReturnValue; button_t buttons[16]; } dialog_t; typedef struct askBoxData_t // for thread-safe version of askBox() { volatile bool active; uint32_t dialogType, returnValue; const char *statusText; } askBoxData_t; static int32_t buttonToRepeat = -1; static askBoxData_t askBoxData; static void drawDialog(dialog_t *d) { // render dialog drawFramework3(d->x, d->y, d->w, d->h); // render buttons for (int32_t i = 0; i < d->numButtons; i++) { button_t *b = &d->buttons[i]; if (b->inverted) drawButton2(b->x1, b->y1, (b->x2 - b->x1) + 1, (b->y2 - b->y1) + 1, b->text); else drawButton1(b->x1, b->y1, (b->x2 - b->x1) + 1, (b->y2 - b->y1) + 1, b->text); } } void removeAskBox(void) { ui.disableVisualizer = false; ui.askBoxShown = false; if (ui.diskOpScreenShown) { renderDiskOpScreen(); // also sets update flags updateDiskOp(); // redraw requested updates } else if (ui.posEdScreenShown) { renderPosEdScreen(); // also sets update flags updatePosEd(); // redraw requested updates } else if (ui.editOpScreenShown) { renderEditOpScreen(); // also sets update flags updateEditOp(); // redraw requested updates } else if (ui.aboutScreenShown) { renderAboutScreen(); } else { if (ui.visualizerMode == VISUAL_QUADRASCOPE) renderQuadrascopeBg(); else if (ui.visualizerMode == VISUAL_SPECTRUM) renderSpectrumAnalyzerBg(); updateVisualizer(); // will draw one frame of the visualizer in use } } void handleThreadedAskBox(void) // rain from main input/video loop { if (askBoxData.active) { askBoxData.returnValue = askBox(askBoxData.dialogType, askBoxData.statusText); askBoxData.active = false; } } uint32_t askBoxThreadSafe(uint32_t dialogType, const char *statusText) { if (!editor.mainLoopOngoing) return 0; // main loop was not even started yet, bail out. // block multiple calls before they are completed (for safety) while (askBoxData.active) SDL_Delay(1000 / VBLANK_HZ); // accuracy is not important here askBoxData.dialogType = dialogType; askBoxData.statusText = statusText; askBoxData.active = true; while (askBoxData.active) SDL_Delay(1000 / VBLANK_HZ); // accuracy is not important here return askBoxData.returnValue; } uint32_t askBox(uint32_t dialogType, const char *statusText) { uint32_t returnValue = 0; dialog_t d; assert(dialogType < ASKBOX_NUM); if (dialogType >= ASKBOX_NUM) return ASKBOX_NO; editor.errorMsgActive = false; editor.errorMsgBlock = false; editor.errorMsgCounter = 0; editor.blockMarkFlag = false; ui.introTextShown = false; // kludge :-) ui.disableVisualizer = true; ui.askBoxShown = true; SDL_EventState(SDL_DROPFILE, SDL_DISABLE); // setup dialog based on type switch (dialogType) { default: case ASKBOX_YES_NO: { // input: x, y, width, height SET_DIALOG(160, 51, 104, 39); // input: number of buttons, abort return-value (esc / right mouse button), default return-value (enter/return) INIT_BUTTONS(2, ASKBOX_NO, ASKBOX_YES); // input: button number, inverted type, keybinding, return-value, x1, x2, y1, y2 SET_BUTTON(0, true, "YES", SDLK_y, ASKBOX_YES, 171, 196, 71, 81); SET_BUTTON(1, true, "NO", SDLK_n, ASKBOX_NO, 234, 252, 71, 81); drawDialog(&d); textOut2(166, 59, "ARE YOU SURE?"); } break; case ASKBOX_CLEAR: { SET_DIALOG(160, 51, 104, 39); INIT_BUTTONS(4, ASKBOX_CLEAR_CANCEL, ASKBOX_CLEAR_CANCEL); SET_BUTTON(0, true, "SONG", SDLK_o, ASKBOX_CLEAR_SONG, 166, 198, 57, 67); SET_BUTTON(1, true, "SAMPLES", SDLK_s, ASKBOX_CLEAR_SAMPLES, 204, 257, 57, 67); SET_BUTTON(2, true, "ALL", SDLK_a, ASKBOX_CLEAR_ALL, 166, 198, 73, 83); SET_BUTTON(3, true, "CANCEL", SDLK_c, ASKBOX_CLEAR_CANCEL, 204, 257, 73, 83); drawDialog(&d); } break; case ASKBOX_PAT2SMP: { SET_DIALOG(120, 44, 200, 55); INIT_BUTTONS(10, 0, 1); SET_BUTTON(0, false, "RENDER TO SAMPLE", SDLK_r, 1, 124, 246, 84, 94); SET_BUTTON(1, false, "EXIT", SDLK_e, 0, 258, 315, 84, 94); // input: button number, text, keybinding, return-value, x1, x2, y1, y2, repeat button SET_CALLBACK_BUTTON(2, ARROW_UP_STR, pat2SmpNoteUp, 0, 191, 201, 48, 58, true); SET_CALLBACK_BUTTON(3, ARROW_DOWN_STR, pat2SmpNoteDown, 0, 202, 212, 48, 58, true); SET_CALLBACK_BUTTON(4, ARROW_UP_STR, pat2SmpStartRowUp, 0, 294, 304, 48, 58, true); SET_CALLBACK_BUTTON(5, ARROW_DOWN_STR, pat2SmpStartRowDown, 0, 305, 315, 48, 58, true); SET_CALLBACK_BUTTON(6, ARROW_UP_STR, pat2SmpFinetuneUp, 0, 191, 201, 59, 69, true); SET_CALLBACK_BUTTON(7, ARROW_DOWN_STR, pat2SmpFinetuneDown, 0, 202, 212, 59, 69, true); SET_CALLBACK_BUTTON(8, ARROW_UP_STR, pat2SmpRowsUp, 0, 294, 304, 59, 69, true); SET_CALLBACK_BUTTON(9, ARROW_DOWN_STR, pat2SmpRowsDown, 0, 305, 315, 59, 69, true); drawDialog(&d); drawFramework1(163, 48, 28, 11); drawFramework1(274, 48, 20, 11); drawFramework1(163, 59, 28, 11); drawFramework1(274, 59, 20, 11); pat2SmpDrawNote(); pat2SmpDrawStartRow(); pat2SmpDrawRows(); pat2SmpDrawFinetune(); pat2SmpCalculateFreq(); textOut2(127, 50, "NOTE"); textOut2(217, 50, "ROW BEG."); textOut2(124, 61, "FTUNE"); textOut2(223, 61, "# ROWS"); textOut2(124, 74, "FREQ."); } break; case ASKBOX_DOWNSAMPLE: // sample loader (AIFF/WAV w/ rate >22kHz) { SET_DIALOG(120, 44, 200, 55); INIT_BUTTONS(2, ASKBOX_NO, ASKBOX_YES); SET_BUTTON(0, true, "YES", SDLK_y, ASKBOX_YES, 179, 204, 83, 93); SET_BUTTON(1, true, "NO", SDLK_n, ASKBOX_NO, 242, 260, 83, 93); drawDialog(&d); textOut2(133, 49, "THE SAMPLE'S FREQUENCY IS"); textOut2(154, 57, "HIGH (ABOVE 22KHZ)."); textOut2(133, 65, "DO YOU WANT TO DOWNSAMPLE"); textOut2(156, 73, "BEFORE LOADING IT?"); } break; case ASKBOX_MOD2WAV: { SET_DIALOG(138, 44, 165, 55); INIT_BUTTONS(7, ASKBOX_NO, ASKBOX_YES); SET_BUTTON(0, false, "RENDER TO WAV", SDLK_r, ASKBOX_YES, 142, 246, 84, 94); SET_BUTTON(1, false, "EXIT", SDLK_e, ASKBOX_NO, 257, 298, 84, 94); SET_CALLBACK_BUTTON(2, " ", toggleMod2WavFadeout, 152, 142, 151, 48, 56, false); SET_CALLBACK_BUTTON(3, ARROW_UP_STR, mod2WavFadeoutUp, 0, 277, 287, 59, 69, true); SET_CALLBACK_BUTTON(4, ARROW_DOWN_STR, mod2WavFadeoutDown, 0, 288, 298, 59, 69, true); SET_CALLBACK_BUTTON(5, ARROW_UP_STR, mod2WavLoopCountUp, 0, 277, 287, 70, 80, true); SET_CALLBACK_BUTTON(6, ARROW_DOWN_STR, mod2WavLoopCountDown, 0, 288, 298, 70, 80, true); drawDialog(&d); drawFramework1(257, 59, 20, 11); drawFramework1(257, 70, 20, 11); textOut2(154, 50, "FADE OUT END OF SONG"); textOut2(142, 62, "FADEOUT SECONDS"); textOut2(142, 73, "SONG LOOP COUNT"); mod2WavDrawFadeoutToggle(); mod2WavDrawFadeoutSeconds(); mod2WavDrawLoopCount(); } } pointerSetMode(POINTER_MODE_MSG1, NO_CARRY); if (statusText != NULL) setStatusMessage(statusText, NO_CARRY); mouse.leftButtonPressed = false; mouse.buttonWaiting = false; mouse.buttonWaitCounter = 0; mouse.repeatCounter = 0; // main loop here // XXX: if you change anything in the main rendering loop, make sure it goes in here too (if needed) bool loopRunning = true; while (loopRunning) { SDL_Event event; sinkVisualizerBars(); updateChannelSyncBuffer(); readMouseXY(); while (SDL_PollEvent(&event)) { if (event.type == SDL_WINDOWEVENT) { if (event.window.event == SDL_WINDOWEVENT_HIDDEN) video.windowHidden = true; else if (event.window.event == SDL_WINDOWEVENT_SHOWN) video.windowHidden = false; // reset vblank end time if we minimize window if (event.window.event == SDL_WINDOWEVENT_MINIMIZED || event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) hpc_ResetCounters(&video.vblankHpc); } else if (event.type == SDL_KEYDOWN) { SDL_Keycode key = event.key.keysym.sym; // abort (escape key) if (key == SDLK_ESCAPE) { returnValue = d.abortReturnValue; loopRunning = false; break; } // default action (return/enter key) if (key == SDLK_RETURN || key == SDLK_KP_ENTER) { returnValue = d.defaultReturnValue; loopRunning = false; break; } // test keybindings for (int32_t i = 0; i < d.numButtons; i++) { button_t *b = &d.buttons[i]; if (b->callback == NULL && key == b->keyBinding) { returnValue = b->returnValue; loopRunning = false; break; } } } else if (event.type == SDL_MOUSEBUTTONDOWN) { if (event.button.button == SDL_BUTTON_LEFT) { mouse.leftButtonPressed = true; mouse.buttonWaiting = true; mouse.repeatCounter = 0; } // abort (right mouse button) if (event.button.button == SDL_BUTTON_RIGHT) { returnValue = d.abortReturnValue; loopRunning = false; break; } // test buttons if (event.button.button == SDL_BUTTON_LEFT) { for (int32_t i = 0; i < d.numButtons; i++) { button_t *b = &d.buttons[i]; const int32_t x2 = (b->clickableWidth > 0) ? (b->x1 + b->clickableWidth) : b->x2; if (mouse.x >= b->x1 && mouse.x <= x2 && mouse.y >= b->y1 && mouse.y <= b->y2) { if (b->callback != NULL) { b->callback(); if (b->repeat) { buttonToRepeat = i; } } else { returnValue = b->returnValue; loopRunning = false; break; } } } } } else if (event.type == SDL_MOUSEBUTTONUP) { mouse.buttonWaitCounter = 0; mouse.buttonWaiting = false; buttonToRepeat = -1; if (event.button.button == SDL_BUTTON_LEFT) mouse.leftButtonPressed = false; } } if (!mouse.buttonWaiting && buttonToRepeat > -1) { button_t *b = &d.buttons[buttonToRepeat]; if (++mouse.repeatCounter >= 3) { const int32_t x2 = (b->clickableWidth > 0) ? (b->x1 + b->clickableWidth) : b->x2; if (mouse.x >= b->x1 && mouse.x <= x2 && mouse.y >= b->y1 && mouse.y <= b->y2) { if (b->callback != NULL) b->callback(); } mouse.repeatCounter = 0; } } updateMouseCounters(); renderFrame2(); flipFrame(); } mouse.leftButtonPressed = false; mouse.buttonWaiting = false; mouse.buttonWaitCounter = 0; mouse.repeatCounter = 0; removeAskBox(); pointerSetPreviousMode(); setPrevStatusMessage(); SDL_EventState(SDL_DROPFILE, SDL_ENABLE); return returnValue; }