// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdint.h>#include <stdbool.h>#include "ft2_header.h"#include "ft2_gui.h"#include "ft2_video.h"#include "ft2_config.h"#include "ft2_diskop.h"#include "ft2_keyboard.h"#include "ft2_mouse.h"#include "ft2_bmp.h"#include "ft2_structs.h" textBox_t textBoxes[NUM_TEXTBOXES] ={ // ------ RESERVED TEXTBOXES ------ { 0 }, /* ** -- STRUCT INFO: -- ** x = x position ** y = y position ** w = width ** h = height ** tx = left padding for text ** ty = top padding for text ** maxc = max characters in box string ** rmb = can only be triggered with right mouse button (f.ex. tracker instrument texts) ** cmc = change mouse cursor when hovering over it */ // ------ INSTRUMENT/SAMPLE/SONG NAME TEXTBOXES ------ // x, y, w, h, tx,ty, maxc, rmb, cmc { 446, 5, 140, 10, 1, 0, 22, true, false }, { 446, 16, 140, 10, 1, 0, 22, true, false }, { 446, 27, 140, 10, 1, 0, 22, true, false }, { 446, 38, 140, 10, 1, 0, 22, true, false }, { 446, 49, 140, 10, 1, 0, 22, true, false }, { 446, 60, 140, 10, 1, 0, 22, true, false }, { 446, 71, 140, 10, 1, 0, 22, true, false }, { 446, 82, 140, 10, 1, 0, 22, true, false }, { 446, 99, 116, 10, 1, 0, 22, true, false }, { 446, 110, 116, 10, 1, 0, 22, true, false }, { 446, 121, 116, 10, 1, 0, 22, true, false }, { 446, 132, 116, 10, 1, 0, 22, true, false }, { 446, 143, 116, 10, 1, 0, 22, true, false }, { 424, 158, 160, 12, 2, 1, 20, false, true }, // ------ DISK OP. TEXTBOXES ------ // x, y, w, h, tx,ty, maxc, rmb, cmc { 31, 158, 134, 12, 2, 1, PATH_MAX, false, true }, // ------ CONFIG TEXTBOXES ------ // x, y, w, h, tx,ty, maxc, rmb, cmc { 486, 16, 143, 12, 2, 1, 80, false, true }, { 486, 31, 143, 12, 2, 1, 80, false, true }, { 486, 46, 143, 12, 2, 1, 80, false, true }, { 486, 61, 143, 12, 2, 1, 80, false, true }, { 486, 76, 143, 12, 2, 1, 80, false, true }}; static int16_t markX1, markX2;static uint16_t oldCursorPos;static int32_t oldMouseX; static void moveTextCursorLeft(int16_t i, bool updateTextBox);static void moveTextCursorRight(int16_t i, bool updateTextBox); static void setSongModifiedFlagIfNeeded(void) // called during keystrokes in text boxes{ if (mouse.lastEditBox == TB_SONG_NAME || (mouse.lastEditBox >= TB_INST1 && mouse.lastEditBox <= TB_INST8) || (mouse.lastEditBox >= TB_SAMP1 && mouse.lastEditBox <= TB_SAMP5)) { setSongModifiedFlag(); }} bool textIsMarked(void){ if (markX1 == markX2) return false; return true;} static void removeTextMarking(void){ markX1 = 0; markX2 = 0;} static int16_t getTextMarkStart(void){ if (markX2 < markX1) return markX2; return markX1;} static int16_t getTextMarkEnd(void){ if (markX1 > markX2) return markX1; return markX2;} static int16_t getTextLength(textBox_t *t, uint16_t offset){ uint16_t i; if (t->textPtr == NULL || offset >= t->maxChars) return 0; // count number of characters in text for (i = offset; i < t->maxChars; i++) { if (t->textPtr[i] == '\0') break; } i -= offset; // i now contains string length assert(i <= t->maxChars); return i;} static void deleteMarkedText(textBox_t *t){ if (!textIsMarked()) return; const int16_t start = getTextMarkStart(); const int16_t end = getTextMarkEnd(); assert(start < t->maxChars && end <= t->maxChars); // calculate pixel width of string to delete int32_t deleteTextWidth = 0; for (int32_t i = start; i < end; i++) deleteTextWidth += charWidth(t->textPtr[i]); // copy markEnd part to markStart, and add null termination const int32_t length = (int32_t)strlen(&t->textPtr[end]); if (length > 0) memcpy(&t->textPtr[start], &t->textPtr[end], length); t->textPtr[start+length] = '\0'; // scroll buffer offset to the left if we are scrolled if (t->bufOffset >= deleteTextWidth) t->bufOffset -= deleteTextWidth; else t->bufOffset = 0; // set text cursor to markStart t->cursorPos = start; setSongModifiedFlagIfNeeded();} static void setCursorToMarkStart(textBox_t *t){ if (!textIsMarked()) return; const int16_t start = getTextMarkStart(); assert(start < t->maxChars); t->cursorPos = start; int32_t startXPos = 0; for (int32_t i = 0; i < start; i++) { const char ch = t->textPtr[i]; if (ch == '\0') break; startXPos += charWidth(ch); } // change buffer offset, if needed if (startXPos < t->bufOffset) t->bufOffset = startXPos;} static void setCursorToMarkEnd(textBox_t *t){ if (!textIsMarked()) return; const int16_t end = getTextMarkEnd(); assert(end <= t->maxChars); t->cursorPos = end; int32_t endXPos = 0; for (int32_t i = 0; i < end; i++) { const char ch = t->textPtr[i]; if (ch == '\0') break; endXPos += charWidth(ch); } // change buffer offset, if needed if (endXPos > t->bufOffset+t->renderW) t->bufOffset = endXPos - t->renderW;} static void copyMarkedText(textBox_t *t){ if (!textIsMarked()) return; const int32_t start = getTextMarkStart(); const int32_t end = getTextMarkEnd(); assert(start < t->maxChars && end <= t->maxChars); const int32_t length = end - start; if (length < 1) return; /* Change mark-end character to NUL so that we ** we only copy the marked section of the string. ** There's always room for a NUL at the end of ** the text box string, so this is safe. **/ const char oldChar = t->textPtr[end]; t->textPtr[end] = '\0'; char *utf8Text = cp437ToUtf8(&t->textPtr[start]); if (utf8Text != NULL) { SDL_SetClipboardText(utf8Text); free(utf8Text); } t->textPtr[end] = oldChar; // set back original character} static void cutMarkedText(textBox_t *t){ if (!textIsMarked()) return; copyMarkedText(t); deleteMarkedText(t); removeTextMarking(); drawTextBox(mouse.lastEditBox);} static void pasteText(textBox_t *t){ char *endPart; if (!SDL_HasClipboardText()) return; // if we've marked text, delete it and remove text marking if (textIsMarked()) { deleteMarkedText(t); removeTextMarking(); } if (t->cursorPos >= t->maxChars) return; const int32_t textLength = getTextLength(t, 0); const int32_t roomLeft = t->maxChars - textLength; if (roomLeft <= 0) return; // no more room! char *copiedTextUtf8 = SDL_GetClipboardText(); char *copiedText = utf8ToCp437(copiedTextUtf8, true); if (copiedText == NULL) return; int32_t copiedTextLength = (int32_t)strlen(copiedText); if (copiedTextLength > roomLeft) copiedTextLength = roomLeft; const uint16_t endOffset = t->cursorPos; endPart = NULL; // prevent false compiler warning const int32_t endPartLength = getTextLength(t, endOffset); if (endPartLength > 0) { endPart = (char *)malloc(endPartLength+1); if (endPart == NULL) { free(copiedText); okBox(0, "System message", "Not enough memory!"); return; } } // make a copy of end data if (endPartLength > 0) { memcpy(endPart, &t->textPtr[endOffset], endPartLength); endPart[endPartLength] = '\0'; } // paste copied data memcpy(&t->textPtr[endOffset], copiedText, copiedTextLength); t->textPtr[endOffset+copiedTextLength] = '\0'; free(copiedText); // append end data if (endPartLength > 0) { strcat(&t->textPtr[endOffset+copiedTextLength], endPart); free(endPart); } for (int32_t i = 0; i < copiedTextLength; i++) moveTextCursorRight(mouse.lastEditBox, TEXTBOX_NO_UPDATE); drawTextBox(mouse.lastEditBox); setSongModifiedFlagIfNeeded();} void exitTextEditing(void){ if (!editor.editTextFlag) return; if (mouse.lastEditBox >= 0 && mouse.lastEditBox < NUM_TEXTBOXES) { textBoxes[mouse.lastEditBox].bufOffset = 0; removeTextMarking(); drawTextBox(mouse.lastEditBox); } if (mouse.lastEditBox == TB_DISKOP_FILENAME && getDiskOpItem() == DISKOP_ITEM_MODULE) { updateCurrSongFilename(); // for window title updateWindowTitle(true); } keyb.ignoreCurrKeyUp = true; // prevent a note being played (on enter key) editor.editTextFlag = false; hideSprite(SPRITE_TEXT_CURSOR); SDL_StopTextInput();} static int16_t cursorPosToX(textBox_t *t){ assert(t->textPtr != NULL); int32_t x = -1; // cursor starts one pixel before character for (int16_t i = 0; i < t->cursorPos; i++) x += charWidth(t->textPtr[i]); x -= t->bufOffset; // subtract by buffer offset to get real X position return (int16_t)x;} int16_t getTextCursorX(textBox_t *t){ return t->x + t->tx + cursorPosToX(t);} int16_t getTextCursorY(textBox_t *t){ return t->y + t->ty;} static void scrollTextBufferLeft(textBox_t *t){ // scroll buffer and clamp t->bufOffset -= TEXT_SCROLL_VALUE; if (t->bufOffset < 0) t->bufOffset = 0;} static void scrollTextBufferRight(textBox_t *t, uint16_t numCharsInText){ assert(numCharsInText <= t->maxChars); // get end of text position int32_t textEnd = 0; for (uint16_t j = 0; j < numCharsInText; j++) textEnd += charWidth(t->textPtr[j]); // subtract by text box width and clamp to 0 textEnd -= t->renderW; if (textEnd < 0) textEnd = 0; // scroll buffer and clamp t->bufOffset += TEXT_SCROLL_VALUE; if (t->bufOffset > textEnd) t->bufOffset = textEnd;} static void moveTextCursorToMouseX(uint16_t textBoxID){ int16_t i; textBox_t *t = &textBoxes[textBoxID]; if ((mouse.x == t->x && t->bufOffset == 0) || t->textPtr == NULL || t->textPtr[0] == '\0') { t->cursorPos = 0; return; } int16_t numChars = getTextLength(t, 0); // find out what character we are clicking at, and set cursor to that character const int32_t mx = t->bufOffset + mouse.x; int32_t tx = (t->x + t->tx) - 1; int32_t cw = -1; for (i = 0; i < numChars; i++) { cw = charWidth(t->textPtr[i]); const int32_t tx2 = tx + cw; if (mx >= tx && mx < tx2) { t->cursorPos = i; break; } tx += cw; } // set to last character if we clicked outside the end of the text if (i == numChars && mx >= tx) t->cursorPos = numChars; if (cw != -1) { const int16_t cursorPos = cursorPosToX(t); // scroll buffer to the right if needed if (cursorPos+cw > t->renderW) scrollTextBufferRight(t, numChars); // scroll buffer to the left if needed else if (cursorPos < 0-1) scrollTextBufferLeft(t); } editor.textCursorBlinkCounter = 0;} static void textOutBuf(uint8_t *dstBuffer, uint32_t dstWidth, uint8_t paletteIndex, char *text, uint32_t maxTextLen){ assert(text != NULL); if (*text == '\0') return; // empty string uint16_t currX = 0; for (uint32_t i = 0; i < maxTextLen; i++) { const char chr = *text++ & 0x7F; if (chr == '\0') break; if (chr != ' ') { const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W]; uint8_t *dstPtr = &dstBuffer[currX]; for (uint32_t y = 0; y < FONT1_CHAR_H; y++) { for (uint32_t x = 0; x < FONT1_CHAR_W; x++) { if (srcPtr[x]) dstPtr[x] = paletteIndex; } srcPtr += FONT1_WIDTH; dstPtr += dstWidth; } } currX += charWidth(chr); }} // a lot of filling here, but textboxes are small so no problem...void drawTextBox(uint16_t textBoxID){ int8_t cw; uint8_t pal; Lines 1–500 of 1201. Load more
// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdint.h> #include <stdbool.h> #include "ft2_header.h" #include "ft2_gui.h" #include "ft2_video.h" #include "ft2_config.h" #include "ft2_diskop.h" #include "ft2_keyboard.h" #include "ft2_mouse.h" #include "ft2_bmp.h" #include "ft2_structs.h" textBox_t textBoxes[NUM_TEXTBOXES] = { // ------ RESERVED TEXTBOXES ------ { 0 }, /* ** -- STRUCT INFO: -- ** x = x position ** y = y position ** w = width ** h = height ** tx = left padding for text ** ty = top padding for text ** maxc = max characters in box string ** rmb = can only be triggered with right mouse button (f.ex. tracker instrument texts) ** cmc = change mouse cursor when hovering over it */ // ------ INSTRUMENT/SAMPLE/SONG NAME TEXTBOXES ------ // x, y, w, h, tx,ty, maxc, rmb, cmc { 446, 5, 140, 10, 1, 0, 22, true, false }, { 446, 16, 140, 10, 1, 0, 22, true, false }, { 446, 27, 140, 10, 1, 0, 22, true, false }, { 446, 38, 140, 10, 1, 0, 22, true, false }, { 446, 49, 140, 10, 1, 0, 22, true, false }, { 446, 60, 140, 10, 1, 0, 22, true, false }, { 446, 71, 140, 10, 1, 0, 22, true, false }, { 446, 82, 140, 10, 1, 0, 22, true, false }, { 446, 99, 116, 10, 1, 0, 22, true, false }, { 446, 110, 116, 10, 1, 0, 22, true, false }, { 446, 121, 116, 10, 1, 0, 22, true, false }, { 446, 132, 116, 10, 1, 0, 22, true, false }, { 446, 143, 116, 10, 1, 0, 22, true, false }, { 424, 158, 160, 12, 2, 1, 20, false, true }, // ------ DISK OP. TEXTBOXES ------ // x, y, w, h, tx,ty, maxc, rmb, cmc { 31, 158, 134, 12, 2, 1, PATH_MAX, false, true }, // ------ CONFIG TEXTBOXES ------ // x, y, w, h, tx,ty, maxc, rmb, cmc { 486, 16, 143, 12, 2, 1, 80, false, true }, { 486, 31, 143, 12, 2, 1, 80, false, true }, { 486, 46, 143, 12, 2, 1, 80, false, true }, { 486, 61, 143, 12, 2, 1, 80, false, true }, { 486, 76, 143, 12, 2, 1, 80, false, true } }; static int16_t markX1, markX2; static uint16_t oldCursorPos; static int32_t oldMouseX; static void moveTextCursorLeft(int16_t i, bool updateTextBox); static void moveTextCursorRight(int16_t i, bool updateTextBox); static void setSongModifiedFlagIfNeeded(void) // called during keystrokes in text boxes { if (mouse.lastEditBox == TB_SONG_NAME || (mouse.lastEditBox >= TB_INST1 && mouse.lastEditBox <= TB_INST8) || (mouse.lastEditBox >= TB_SAMP1 && mouse.lastEditBox <= TB_SAMP5)) { setSongModifiedFlag(); } } bool textIsMarked(void) { if (markX1 == markX2) return false; return true; } static void removeTextMarking(void) { markX1 = 0; markX2 = 0; } static int16_t getTextMarkStart(void) { if (markX2 < markX1) return markX2; return markX1; } static int16_t getTextMarkEnd(void) { if (markX1 > markX2) return markX1; return markX2; } static int16_t getTextLength(textBox_t *t, uint16_t offset) { uint16_t i; if (t->textPtr == NULL || offset >= t->maxChars) return 0; // count number of characters in text for (i = offset; i < t->maxChars; i++) { if (t->textPtr[i] == '\0') break; } i -= offset; // i now contains string length assert(i <= t->maxChars); return i; } static void deleteMarkedText(textBox_t *t) { if (!textIsMarked()) return; const int16_t start = getTextMarkStart(); const int16_t end = getTextMarkEnd(); assert(start < t->maxChars && end <= t->maxChars); // calculate pixel width of string to delete int32_t deleteTextWidth = 0; for (int32_t i = start; i < end; i++) deleteTextWidth += charWidth(t->textPtr[i]); // copy markEnd part to markStart, and add null termination const int32_t length = (int32_t)strlen(&t->textPtr[end]); if (length > 0) memcpy(&t->textPtr[start], &t->textPtr[end], length); t->textPtr[start+length] = '\0'; // scroll buffer offset to the left if we are scrolled if (t->bufOffset >= deleteTextWidth) t->bufOffset -= deleteTextWidth; else t->bufOffset = 0; // set text cursor to markStart t->cursorPos = start; setSongModifiedFlagIfNeeded(); } static void setCursorToMarkStart(textBox_t *t) { if (!textIsMarked()) return; const int16_t start = getTextMarkStart(); assert(start < t->maxChars); t->cursorPos = start; int32_t startXPos = 0; for (int32_t i = 0; i < start; i++) { const char ch = t->textPtr[i]; if (ch == '\0') break; startXPos += charWidth(ch); } // change buffer offset, if needed if (startXPos < t->bufOffset) t->bufOffset = startXPos; } static void setCursorToMarkEnd(textBox_t *t) { if (!textIsMarked()) return; const int16_t end = getTextMarkEnd(); assert(end <= t->maxChars); t->cursorPos = end; int32_t endXPos = 0; for (int32_t i = 0; i < end; i++) { const char ch = t->textPtr[i]; if (ch == '\0') break; endXPos += charWidth(ch); } // change buffer offset, if needed if (endXPos > t->bufOffset+t->renderW) t->bufOffset = endXPos - t->renderW; } static void copyMarkedText(textBox_t *t) { if (!textIsMarked()) return; const int32_t start = getTextMarkStart(); const int32_t end = getTextMarkEnd(); assert(start < t->maxChars && end <= t->maxChars); const int32_t length = end - start; if (length < 1) return; /* Change mark-end character to NUL so that we ** we only copy the marked section of the string. ** There's always room for a NUL at the end of ** the text box string, so this is safe. **/ const char oldChar = t->textPtr[end]; t->textPtr[end] = '\0'; char *utf8Text = cp437ToUtf8(&t->textPtr[start]); if (utf8Text != NULL) { SDL_SetClipboardText(utf8Text); free(utf8Text); } t->textPtr[end] = oldChar; // set back original character } static void cutMarkedText(textBox_t *t) { if (!textIsMarked()) return; copyMarkedText(t); deleteMarkedText(t); removeTextMarking(); drawTextBox(mouse.lastEditBox); } static void pasteText(textBox_t *t) { char *endPart; if (!SDL_HasClipboardText()) return; // if we've marked text, delete it and remove text marking if (textIsMarked()) { deleteMarkedText(t); removeTextMarking(); } if (t->cursorPos >= t->maxChars) return; const int32_t textLength = getTextLength(t, 0); const int32_t roomLeft = t->maxChars - textLength; if (roomLeft <= 0) return; // no more room! char *copiedTextUtf8 = SDL_GetClipboardText(); char *copiedText = utf8ToCp437(copiedTextUtf8, true); if (copiedText == NULL) return; int32_t copiedTextLength = (int32_t)strlen(copiedText); if (copiedTextLength > roomLeft) copiedTextLength = roomLeft; const uint16_t endOffset = t->cursorPos; endPart = NULL; // prevent false compiler warning const int32_t endPartLength = getTextLength(t, endOffset); if (endPartLength > 0) { endPart = (char *)malloc(endPartLength+1); if (endPart == NULL) { free(copiedText); okBox(0, "System message", "Not enough memory!"); return; } } // make a copy of end data if (endPartLength > 0) { memcpy(endPart, &t->textPtr[endOffset], endPartLength); endPart[endPartLength] = '\0'; } // paste copied data memcpy(&t->textPtr[endOffset], copiedText, copiedTextLength); t->textPtr[endOffset+copiedTextLength] = '\0'; free(copiedText); // append end data if (endPartLength > 0) { strcat(&t->textPtr[endOffset+copiedTextLength], endPart); free(endPart); } for (int32_t i = 0; i < copiedTextLength; i++) moveTextCursorRight(mouse.lastEditBox, TEXTBOX_NO_UPDATE); drawTextBox(mouse.lastEditBox); setSongModifiedFlagIfNeeded(); } void exitTextEditing(void) { if (!editor.editTextFlag) return; if (mouse.lastEditBox >= 0 && mouse.lastEditBox < NUM_TEXTBOXES) { textBoxes[mouse.lastEditBox].bufOffset = 0; removeTextMarking(); drawTextBox(mouse.lastEditBox); } if (mouse.lastEditBox == TB_DISKOP_FILENAME && getDiskOpItem() == DISKOP_ITEM_MODULE) { updateCurrSongFilename(); // for window title updateWindowTitle(true); } keyb.ignoreCurrKeyUp = true; // prevent a note being played (on enter key) editor.editTextFlag = false; hideSprite(SPRITE_TEXT_CURSOR); SDL_StopTextInput(); } static int16_t cursorPosToX(textBox_t *t) { assert(t->textPtr != NULL); int32_t x = -1; // cursor starts one pixel before character for (int16_t i = 0; i < t->cursorPos; i++) x += charWidth(t->textPtr[i]); x -= t->bufOffset; // subtract by buffer offset to get real X position return (int16_t)x; } int16_t getTextCursorX(textBox_t *t) { return t->x + t->tx + cursorPosToX(t); } int16_t getTextCursorY(textBox_t *t) { return t->y + t->ty; } static void scrollTextBufferLeft(textBox_t *t) { // scroll buffer and clamp t->bufOffset -= TEXT_SCROLL_VALUE; if (t->bufOffset < 0) t->bufOffset = 0; } static void scrollTextBufferRight(textBox_t *t, uint16_t numCharsInText) { assert(numCharsInText <= t->maxChars); // get end of text position int32_t textEnd = 0; for (uint16_t j = 0; j < numCharsInText; j++) textEnd += charWidth(t->textPtr[j]); // subtract by text box width and clamp to 0 textEnd -= t->renderW; if (textEnd < 0) textEnd = 0; // scroll buffer and clamp t->bufOffset += TEXT_SCROLL_VALUE; if (t->bufOffset > textEnd) t->bufOffset = textEnd; } static void moveTextCursorToMouseX(uint16_t textBoxID) { int16_t i; textBox_t *t = &textBoxes[textBoxID]; if ((mouse.x == t->x && t->bufOffset == 0) || t->textPtr == NULL || t->textPtr[0] == '\0') { t->cursorPos = 0; return; } int16_t numChars = getTextLength(t, 0); // find out what character we are clicking at, and set cursor to that character const int32_t mx = t->bufOffset + mouse.x; int32_t tx = (t->x + t->tx) - 1; int32_t cw = -1; for (i = 0; i < numChars; i++) { cw = charWidth(t->textPtr[i]); const int32_t tx2 = tx + cw; if (mx >= tx && mx < tx2) { t->cursorPos = i; break; } tx += cw; } // set to last character if we clicked outside the end of the text if (i == numChars && mx >= tx) t->cursorPos = numChars; if (cw != -1) { const int16_t cursorPos = cursorPosToX(t); // scroll buffer to the right if needed if (cursorPos+cw > t->renderW) scrollTextBufferRight(t, numChars); // scroll buffer to the left if needed else if (cursorPos < 0-1) scrollTextBufferLeft(t); } editor.textCursorBlinkCounter = 0; } static void textOutBuf(uint8_t *dstBuffer, uint32_t dstWidth, uint8_t paletteIndex, char *text, uint32_t maxTextLen) { assert(text != NULL); if (*text == '\0') return; // empty string uint16_t currX = 0; for (uint32_t i = 0; i < maxTextLen; i++) { const char chr = *text++ & 0x7F; if (chr == '\0') break; if (chr != ' ') { const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W]; uint8_t *dstPtr = &dstBuffer[currX]; for (uint32_t y = 0; y < FONT1_CHAR_H; y++) { for (uint32_t x = 0; x < FONT1_CHAR_W; x++) { if (srcPtr[x]) dstPtr[x] = paletteIndex; } srcPtr += FONT1_WIDTH; dstPtr += dstWidth; } } currX += charWidth(chr); } } // a lot of filling here, but textboxes are small so no problem... void drawTextBox(uint16_t textBoxID) { int8_t cw; uint8_t pal;