/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "uitextboxmain.h" #include "ui/focus/uifocus.h" #include "display/screen/screen.h" #include "display/text/text.h" #include "display/color.h" #include "display/spritebatch/spritebatch.h" #include "display/shader/shaderunlit.h" #include "ui/frame/uiframe.h" uitextboxmain_t UI_TEXTBOX_MAIN; static uifocusitem_t *focusItem = NULL; errorret_t uiTextboxMainInit(void) { uiTextboxInit( &UI_TEXTBOX_MAIN.box, UI_TEXTBOX_MAIN.text, UI_TEXTBOX_MAIN_TEXT_MAX, UI_TEXTBOX_MAIN.lines, UI_TEXTBOX_MAIN_LINES_MAX ); errorOk(); } void uiTextboxMainSetText(const char_t *text) { uiTextboxSetText(&UI_TEXTBOX_MAIN.box, text); if(focusItem != NULL) return; focusItem = uiFocusPush( 1, 1, uiTextboxMainFocusSelected, NULL, uiTextboxMainFocusClosed, NULL, NULL ); } errorret_t uiTextboxMainUpdate(void) { if(focusItem == NULL) errorOk(); return uiTextboxUpdate(&UI_TEXTBOX_MAIN.box); } errorret_t uiTextboxMainDraw(void) { if(focusItem == NULL) errorOk(); float_t fontH = (float_t)FONT_DEFAULT.tileset->tileHeight; float_t h = (float_t)UI_TEXTBOX_MAIN_LINES * fontH + (float_t)(UI_TEXTBOX_MAIN_LINES - 1) * UI_TEXTBOX_LINE_SPACING + 2.0f * (float_t)UI_FRAME_START_Y; float_t w = (float_t)SCREEN.scanWidth; float_t x = (float_t)SCREEN.scanX; float_t y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) - h; errorChain(uiTextboxDraw(&UI_TEXTBOX_MAIN.box, x, y, w, h)); if(!uiTextboxPageIsComplete(&UI_TEXTBOX_MAIN.box)) errorOk(); float_t fontW = (float_t)FONT_DEFAULT.tileset->tileWidth; float_t contentX = x + (float_t)UI_FRAME_START_X; float_t contentY = y + (float_t)UI_FRAME_START_Y; float_t contentW = w - 2.0f * (float_t)UI_FRAME_START_X; float_t contentH = h - 2.0f * (float_t)UI_FRAME_START_Y; shadermaterial_t material = { .unlit = { .color = COLOR_WHITE, .texture = FONT_DEFAULT.texture } }; spritebatchsprite_t caret = textGetSprite( (vec2){ contentX + contentW - fontW, contentY + contentH - fontH }, 'v', &FONT_DEFAULT ); errorChain(spriteBatchBuffer(&caret, 1, &SHADER_UNLIT, material)); errorOk(); } bool_t uiTextboxMainPageIsComplete(void) { return uiTextboxPageIsComplete(&UI_TEXTBOX_MAIN.box); } bool_t uiTextboxMainHasNextPage(void) { return uiTextboxHasNextPage(&UI_TEXTBOX_MAIN.box); } void uiTextboxMainNextPage(void) { uiTextboxNextPage(&UI_TEXTBOX_MAIN.box); } bool_t uiTextboxMainIsActive(void) { return focusItem != NULL; } bool_t uiTextboxMainFocusSelected(const uifocusitem_t *item) { if(!uiTextboxPageIsComplete(&UI_TEXTBOX_MAIN.box)) { UI_TEXTBOX_MAIN.box.scroll = uiTextboxGetPageCharCount(&UI_TEXTBOX_MAIN.box); return true; } if(uiTextboxHasNextPage(&UI_TEXTBOX_MAIN.box)) { uiTextboxNextPage(&UI_TEXTBOX_MAIN.box); return true; } uiFocusPopItem(focusItem); return true; } bool_t uiTextboxMainFocusClosed(const uifocusitem_t *item) { focusItem = NULL; return true; }