From 9ebe0630e3dce56bf4c21c65256cd6c2f87417f3 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 22 Jun 2025 17:14:15 -0500 Subject: [PATCH] Somehow everything is working --- src/dusk/entity/npc.c | 7 +- src/dusk/main.c | 2 +- src/dusk/ui/font.h | 1 + src/dusk/ui/uitextbox.c | 162 +++++++++++++++++++-------- src/dusk/ui/uitextbox.h | 7 +- src/duskraylib/display/draw/drawui.c | 10 +- 6 files changed, 135 insertions(+), 54 deletions(-) diff --git a/src/dusk/entity/npc.c b/src/dusk/entity/npc.c index 162a811..0e4f74d 100644 --- a/src/dusk/entity/npc.c +++ b/src/dusk/entity/npc.c @@ -18,5 +18,10 @@ void npcUpdate(entity_t *entity) { } void npcInteract(entity_t *player, entity_t *self) { - uiTextboxSetText("Hello World"); + uiTextboxSetText( + "Hello World how are you today? Hope things are going well for you! I am " + "having a great day, hope you are too. Did I ever tell you about the tragedy " + "of Darth Plagueis the Wise? He was a dark lord of the Sith, " + "so powerful and so wise he could use the Force to influence the midichlorians" + ); } \ No newline at end of file diff --git a/src/dusk/main.c b/src/dusk/main.c index 0a73a98..e0542cc 100644 --- a/src/dusk/main.c +++ b/src/dusk/main.c @@ -27,10 +27,10 @@ void main(void) { while(!renderShouldExit()) { RENDER_FRAME++; renderDraw(); + uiTextboxUpdate(); overworldUpdate(); - uiTextboxUpdate(); // Update input for next frame. inputUpdate(); diff --git a/src/dusk/ui/font.h b/src/dusk/ui/font.h index cfdd11f..3b577a9 100644 --- a/src/dusk/ui/font.h +++ b/src/dusk/ui/font.h @@ -9,6 +9,7 @@ #include "dusk.h" #define FONT_HEIGHT 8 +#define FONT_WIDTH FONT_HEIGHT #define FONT_LINE_SPACING 1 #define FONT_LINE_HEIGHT ( \ diff --git a/src/dusk/ui/uitextbox.c b/src/dusk/ui/uitextbox.c index 398fc26..89829c1 100644 --- a/src/dusk/ui/uitextbox.c +++ b/src/dusk/ui/uitextbox.c @@ -21,7 +21,6 @@ void uiTextboxUpdate() { if(UI_TEXTBOX.charsRevealed < UI_TEXTBOX.pageChars[UI_TEXTBOX.page]) { if((RENDER_FRAME % 4) == 0) { - // printf("Revealing char\n"); UI_TEXTBOX.charsRevealed++; } else if(inputIsDown(INPUT_BIND_ACTION)) { UI_TEXTBOX.charsRevealed++; @@ -29,7 +28,7 @@ void uiTextboxUpdate() { } else { if(inputPressed(INPUT_BIND_ACTION)) { - if(UI_TEXTBOX.page <= UI_TEXTBOX.pageCount - 1) { + if(UI_TEXTBOX.page < UI_TEXTBOX.pageCount - 1) { uitextbox_t *textbox = &UI_TEXTBOX; printf("next page?\n"); UI_TEXTBOX.page++; @@ -46,83 +45,154 @@ void uiTextboxUpdate() { } void uiTextboxSetText(const char_t *text) { + uitextbox_t *textbox = &UI_TEXTBOX; + assertNotNull(text, "Text pointer cannot be NULL, call uiTextboxClose()"); memoryZero(UI_TEXTBOX.text, sizeof(UI_TEXTBOX.text)); memoryZero(UI_TEXTBOX.lineLengths, sizeof(UI_TEXTBOX.lineLengths)); memoryZero(UI_TEXTBOX.pageChars, sizeof(UI_TEXTBOX.pageChars)); - UI_TEXTBOX.pageCount = 0; + UI_TEXTBOX.pageCount = 1;// Always at least one page. UI_TEXTBOX.totalChars = 0; UI_TEXTBOX.page = 0; UI_TEXTBOX.charsRevealed = 0; UI_TEXTBOX.visible = true; - char_t c; - uint16_t i = 0; - uint16_t j = 0; - uint8_t line = 0; + char_t c;// current char + uint16_t i = 0;// Index of character we are pulling + uint16_t lastWordStart = 0;// Index of the last word start (in src string). + uint8_t line = 0;// Which line we are currently writing to. + uint8_t page = 0; + bool_t startOfLine = true;// Are we at the start of a line? + while((c = text[i++]) != '\0') { + // HARD disallowed characters. assertTrue(c != '\r', "Carriage return characters not allowed."); assertTrue(c != '\t', "Tab characters not allowed."); + + // Is this the beginning of a new line? + if(startOfLine) { + // Yes, we are at the start of a new line. + startOfLine = false; + // Is this the first line? + if(line == 0) { + // nothing to do, just continue. + } else { + // Yes, start of new line. Is this line the first line on a new page? + if((line % UI_TEXTBOX_LINES_PER_PAGE) == 0) { + // Yes, start a new page. + i--;// Rewind so that this character can go through the loop again. + goto newPage; + } + } + } + // Change what we do depending on the character. if(c == '\n') { goto newline; + } else if(c == ' ') { + goto whitespace; } else { goto character; } - newline: { - line++; - if(line >= UI_TEXTBOX_LINE_COUNT) { - goto newPage; + // Handle whitespace characters (not newlines) + whitespace: { + // Is this whitespace the last char of the line? + if(UI_TEXTBOX.lineLengths[line] == UI_TEXTBOX_CHARS_PER_LINE) { + goto newline; + } else if(UI_TEXTBOX.lineLengths[line] == 0) { + // If this is the first character of the line, we can just ignore it. + continue; } + + lastWordStart = i; + goto appendCharacter; + } + + // Handle regular characters + character: { + // Is this character going to cause a wrap to occur? + if(UI_TEXTBOX.lineLengths[line] == UI_TEXTBOX_CHARS_PER_LINE) { + // How long ago was the last whitespace? + uint16_t charsSinceLastSpace = i - lastWordStart; + + // Is the word longer than a line can possibly hold? + assertTrue( + charsSinceLastSpace < UI_TEXTBOX_CHARS_PER_LINE, + "Word longer than a line can hold." + ); + + // Undo appending of all characters since the last whitespace. + UI_TEXTBOX.totalChars -= charsSinceLastSpace; + UI_TEXTBOX.lineLengths[line] -= charsSinceLastSpace; + UI_TEXTBOX.pageChars[page] -= charsSinceLastSpace; + + // Rewind the loop so that printing will begin on the new line at the + // start of the last word. + i -= charsSinceLastSpace; + + // Newline. + goto newline; + } + + // Append the character to the textbox. + goto appendCharacter; + } + + // Handle newlines + newline: { + // Ensure we don't exceed the maximum number of lines. + assertTrue( + line < UI_TEXTBOX_LINE_COUNT, + "Exceeded maximum number of lines in textbox." + ); + + // Add a line to the textbox. + line++; + startOfLine = true;// Next iteration will be a start of line. + lastWordStart = i;// We also mark this as the last word start. continue; } - character: { - UI_TEXTBOX.text[j] = c; - UI_TEXTBOX.totalChars++; - UI_TEXTBOX.lineLengths[line]++; - UI_TEXTBOX.pageChars[UI_TEXTBOX.pageCount]++; - } - newPage: { + // Make sure we don't exceed the maximum number of pages. assertTrue( UI_TEXTBOX.pageCount < UI_TEXTBOX_PAGE_COUNT_MAX, "Exceeded maximum number of pages in textbox." ); UI_TEXTBOX.pageCount++; - line = 0; + page++; + continue; + } + + appendCharacter: { + assertTrue( + UI_TEXTBOX.totalChars < UI_TEXTBOX_CHARS_MAX, + "Exceeded maximum number of characters in textbox." + ); + assertTrue( + line < UI_TEXTBOX_LINE_COUNT, + "Exceeded maximum number of lines in textbox." + ); + assertTrue( + UI_TEXTBOX.lineLengths[line] < UI_TEXTBOX_CHARS_PER_LINE, + "Exceeded maximum number of chars per line in textbox." + ); + + // Push the character to the textbox. + UI_TEXTBOX.text[ + line * UI_TEXTBOX_CHARS_PER_LINE + UI_TEXTBOX.lineLengths[line] + ] = c; + + // Increment the line length and page character count. + UI_TEXTBOX.totalChars++; + UI_TEXTBOX.lineLengths[line]++; + UI_TEXTBOX.pageChars[page]++; continue; - // j = 0; // Reset character index for new page } assertUnreachable("Code should not reach here, all cases handled."); } - - - - - // Hard coded testing values - // char_t buffer[UI_TEXTBOX_CHARS_PER_LINE]; - // uint8_t line; - - // for(line = 0; line < UI_TEXTBOX_LINE_COUNT; line++) { - // // Set the text for each line - // sprintf(buffer, "HC Line %d", line); - // UI_TEXTBOX.lineLengths[line] = strlen(text); // Set line length for each line - // UI_TEXTBOX.totalChars += UI_TEXTBOX.lineLengths[line]; - // UI_TEXTBOX.pageChars[UI_TEXTBOX.pageCount] += UI_TEXTBOX.lineLengths[line]; - - // memoryCopy( - // UI_TEXTBOX.text + line * (UI_TEXTBOX_CHARS_PER_LINE), - // buffer, - // UI_TEXTBOX.lineLengths[line] - // ); - - // if(line == 3 || line == 7 || line == 11 || line == 15) { - // // Increment page count every 4 lines - // UI_TEXTBOX.pageCount++; - // } - // } + printf("test"); } \ No newline at end of file diff --git a/src/dusk/ui/uitextbox.h b/src/dusk/ui/uitextbox.h index 3330a4a..b4b75f4 100644 --- a/src/dusk/ui/uitextbox.h +++ b/src/dusk/ui/uitextbox.h @@ -28,8 +28,9 @@ (UI_TEXTBOX_PADDING_Y * 2) \ ) -#define UI_TEXTBOX_CHARS_PER_LINE UI_TEXTBOX_WIDTH_INNER -#define UI_TEXTBOX_PAGE_CHARS ( \ +// #define UI_TEXTBOX_CHARS_PER_LINE UI_TEXTBOX_WIDTH_INNER / FONT_WIDTH +#define UI_TEXTBOX_CHARS_PER_LINE 20 +#define UI_TEXTBOX_CHARS_PER_PAGE ( \ UI_TEXTBOX_CHARS_PER_LINE * UI_TEXTBOX_LINES_PER_PAGE \ ) #define UI_TEXTBOX_PAGE_COUNT_MAX 6 @@ -37,7 +38,7 @@ UI_TEXTBOX_LINES_PER_PAGE * UI_TEXTBOX_PAGE_COUNT_MAX \ ) #define UI_TEXTBOX_CHARS_MAX ( \ - UI_TEXTBOX_PAGE_CHARS * UI_TEXTBOX_PAGE_COUNT_MAX \ + UI_TEXTBOX_CHARS_PER_PAGE * UI_TEXTBOX_PAGE_COUNT_MAX \ ) typedef struct { diff --git a/src/duskraylib/display/draw/drawui.c b/src/duskraylib/display/draw/drawui.c index 0652f1f..5acbb3f 100644 --- a/src/duskraylib/display/draw/drawui.c +++ b/src/duskraylib/display/draw/drawui.c @@ -20,6 +20,8 @@ void drawUI() { void drawUITextbox() { if(!UI_TEXTBOX.visible) return; + uitextbox_t *textbox = &UI_TEXTBOX; + // Semi-transparent dark blue Color background = (Color){ 0, 0, 128, 128 }; DrawRectangle( @@ -33,11 +35,14 @@ void drawUITextbox() { if(UI_TEXTBOX.charsRevealed > 0) { char_t buffer[UI_TEXTBOX_CHARS_PER_LINE + 1];// +1 for null term uint8_t charsRendered = 0; + uitextbox_t *textbox = &UI_TEXTBOX; // For each line for(uint8_t i = 0; i < UI_TEXTBOX_LINES_PER_PAGE; i++) { // Get count of chars in the line - uint8_t lineLength = UI_TEXTBOX.lineLengths[i]; + uint8_t lineLength = UI_TEXTBOX.lineLengths[ + i + (UI_TEXTBOX.page * UI_TEXTBOX_LINES_PER_PAGE) + ]; if(lineLength == 0) continue; // Determine how many chars left to render @@ -50,11 +55,10 @@ void drawUITextbox() { // Update how many rendered charsRendered += lineChars; - // Copy string from VN Textbox... memoryCopy( buffer, - UI_TEXTBOX.text + (UI_TEXTBOX.page * UI_TEXTBOX_PAGE_CHARS) + + UI_TEXTBOX.text + (UI_TEXTBOX.page * UI_TEXTBOX_CHARS_PER_PAGE) + (i * UI_TEXTBOX_CHARS_PER_LINE), lineChars );