/** * Copyright (c) 2022 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "textbox.h" char TEXTBOX_TEXTS[TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW]; uint8_t TEXTBOX_ROW_COUNT; uint8_t TEXTBOX_ROW_CURRENT; uint8_t TEXTBOX_STATE; uint8_t TEXTBOX_SCROLL; inline void conversationTextboxInit() { uint8_t i; uint8_t TEXTBOX_TILES[TEXTBOX_TILES_MAX]; // Reset textbox state TEXTBOX_STATE = 0; // Setup window data move_win(7, SCREENHEIGHT - (TEXTBOX_HEIGHT_IN_TILES * 8)); set_win_data(FONT_DATA_POSITION, FONT_IMAGE_TILES, FONT_IMAGE); set_win_data(BORDER_DATA_POSITION, BORDER_IMAGE_TILES, BORDER_IMAGE); // Corners TEXTBOX_TILES[0] = BORDER_TILE_TOP_LEFT; TEXTBOX_TILES[TEXTBOX_WIDTH_IN_TILES-1] = BORDER_TILE_TOP_RIGHT; TEXTBOX_TILES[TEXTBOX_TILES_MAX-1] = BORDER_TILE_BOTTOM_RIGHT; TEXTBOX_TILES[TEXTBOX_TILES_MAX-TEXTBOX_WIDTH_IN_TILES] = BORDER_TILE_BOTTOM_LEFT; // Edges for(i = 1; i < TEXTBOX_WIDTH_IN_TILES - 1; i++) { TEXTBOX_TILES[i] = BORDER_TILE_TOP_CENTER; TEXTBOX_TILES[TEXTBOX_TILES_MAX - 1 - i] = BORDER_TILE_BOTTOM_CENTER; } for(i = 1; i < TEXTBOX_HEIGHT_IN_TILES - 1; i++) { TEXTBOX_TILES[TEXTBOX_WIDTH_IN_TILES * i] = BORDER_TILE_CENTER_LEFT; TEXTBOX_TILES[TEXTBOX_WIDTH_IN_TILES * (i+1) - 1] = BORDER_TILE_CENTER_RIGHT; } set_win_tiles( 0x00, 0x00, TEXTBOX_WIDTH_IN_TILES, TEXTBOX_HEIGHT_IN_TILES, TEXTBOX_TILES ); } void conversationTextboxSetText(char *text) { uint8_t i, j, k, rowStart, stateFlags; char c, c2; // Begin by filling the textbox text chars with whitespace to begin. // TODO: I'm pretty sure I can move this lower and optimize. for(i = 0; i < TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW; i++) { TEXTBOX_TEXTS[i] = ' '; } // Reset textbox state TEXTBOX_STATE = TEXTBOX_STATE_VISIBLE; TEXTBOX_SCROLL = 0; TEXTBOX_ROW_COUNT = 0; TEXTBOX_ROW_CURRENT = 0; TEXTBOX_ROW_COUNT = 1; // Copy source text to buffer, also determine wordwrapping here. i = 0, j = 0, rowStart = 0, stateFlags = 0; while((c = text[i]) != '\0') {// "For each char in string" if(c == ' ') { // Scan ahead and look at how many chars remain to the next space. k = i + 1; while( (c2 = text[k]) != '\0' && c2 != '\n' && c2 != ' ' && (k - rowStart) < TEXTBOX_CHARS_PER_ROW ) k++; // IF that number is less than the remaining chars on the current row, // then treat this space like a newline. if(k >= (rowStart + TEXTBOX_CHARS_PER_ROW - 1)) { stateFlags |= 1 << 0; } } else if(c == '\n') { stateFlags |= 1 << 0; } // Do we need to insert newline where we are currently? if((stateFlags & (1 << 0)) != 0) { stateFlags &= ~(1 << 0);// Remove newline flag i++; rowStart = i;// Update the row start (Should this be i+1?) //TODO: can I optimize the next line by using rowStart somehow? j = ((j / TEXTBOX_CHARS_PER_ROW) + 1) * TEXTBOX_CHARS_PER_ROW;// Update destination character position. TEXTBOX_ROW_COUNT++; continue; } // Insert the character TEXTBOX_TEXTS[j] = c; i++; j++; } // Now we have organized the string nicely we can prep for rendering. Fill the // tiles with blank chars. textboxFillBlank(); // Show the window layer. SHOW_WIN; } inline void textboxFillBlank() { uint8_t i, j; uint8_t TEXTBOX_TILES[TEXTBOX_CHAR_ROWS * TEXTBOX_CHARS_PER_ROW]; for(j = 0; j < TEXTBOX_CHAR_ROWS; j++) { for(i = 0; i < TEXTBOX_CHARS_PER_ROW ; i++) { TEXTBOX_TILES[i + (j * TEXTBOX_CHARS_PER_ROW)] = TEXTBOX_TILE_BLANK; } } set_win_tiles( 0x01, 0x01, TEXTBOX_WIDTH_IN_TILES - 0x02, TEXTBOX_HEIGHT_IN_TILES - 0x02, TEXTBOX_TILES ); } inline void conversationTextboxUpdate() { uint8_t i; char c; uint8_t tiles[1]; // Is the textbox visible? if((TEXTBOX_STATE & TEXTBOX_STATE_VISIBLE) == 0) return; // Have we finished scrolling? if(TEXTBOX_STATE & TEXTBOX_STATE_SCROLLED) { // Is the user trying to go to the next line? if(INPUT_STATE & J_A) { // First, lets figure out if there's any more text to reveal or not. if((TEXTBOX_ROW_COUNT - TEXTBOX_ROW_CURRENT) < TEXTBOX_TILES_ROWS) { TEXTBOX_STATE &= ~TEXTBOX_STATE_VISIBLE; HIDE_WIN; conversationQueueNext(); return; } TEXTBOX_STATE &= ~TEXTBOX_STATE_SCROLLED; TEXTBOX_SCROLL = 0; TEXTBOX_ROW_CURRENT += TEXTBOX_TILES_ROWS; textboxFillBlank(); } return; } // Move to the next character. i = TEXTBOX_ROW_CURRENT * TEXTBOX_CHARS_PER_ROW; c = TEXTBOX_TEXTS[i+TEXTBOX_SCROLL]; if(TEXTBOX_SCROLL == TEXTBOX_CHARS_MAX) { TEXTBOX_STATE |= TEXTBOX_STATE_SCROLLED; } else { tiles[0] = c - TEXTBOX_FONT_START + FONT_DATA_POSITION; set_win_tiles( 0x01 + (TEXTBOX_SCROLL % TEXTBOX_CHARS_PER_ROW), 0x01 + (TEXTBOX_SCROLL / TEXTBOX_CHARS_PER_ROW), 1, 1, tiles ); TEXTBOX_SCROLL++; } }