Move widgets to base Screen and move away from using Recreate method

Also fix texture pack screen messing up after resize
This commit is contained in:
UnknownShadow200 2019-08-17 09:34:31 +10:00
parent 2a4fb3208a
commit 5006716c4c
5 changed files with 96 additions and 108 deletions

View File

@ -17,6 +17,7 @@ enum GuiAnchor {
struct IGameComponent;
struct GuiElem;
struct Widget;
extern struct IGameComponent Gui_Component;
/* Whether vanilla Minecraft Classic gui texture is used. */
@ -51,7 +52,6 @@ struct GuiElemVTABLE { GuiElemVTABLE_Layout() };
struct GuiElem { struct GuiElemVTABLE* VTABLE; };
void Gui_DefaultRecreate(void* elem);
struct ScreenVTABLE {
GuiElemVTABLE_Layout()
void (*OnResize)(void* elem);
@ -62,13 +62,13 @@ struct ScreenVTABLE {
bool grabsInput; /* Whether this screen grabs input. Causes the cursor to become visible. */ \
bool blocksWorld; /* Whether this screen completely and opaquely covers the game world behind it. */ \
bool hidden; /* Whether this screen is prevented from rendering. */ \
bool closable; /* Whether this screen is automatically closed when pressing Escape */
bool closable; /* Whether this screen is automatically closed when pressing Escape */ \
struct Widget** widgets; int numWidgets;
/* Represents a container of widgets and other 2D elements. May cover entire window. */
struct Screen { Screen_Layout };
typedef void (*Widget_LeftClick)(void* screen, void* widget);
struct Widget;
struct WidgetVTABLE {
GuiElemVTABLE_Layout()
void (*Reposition)(void* elem);

View File

@ -29,10 +29,7 @@
#include "Builder.h"
#include "Logger.h"
#define MenuBase_Layout Screen_Layout struct Widget** widgets; int widgetsCount;
struct Menu { MenuBase_Layout };
#define MenuScreen_Layout MenuBase_Layout FontDesc titleFont, textFont;
#define MenuScreen_Layout Screen_Layout FontDesc titleFont, textFont;
struct MenuScreen { MenuScreen_Layout };
/* Describes a menu option button */
@ -51,22 +48,20 @@ struct SimpleButtonDesc { int x, y; const char* title; Widget_LeftClick onClick;
static void Menu_Button(void* s, int i, struct ButtonWidget* btn, int width, const String* text, const FontDesc* font, Widget_LeftClick onClick, int horAnchor, int verAnchor, int x, int y) {
ButtonWidget_Make(btn, width, onClick, horAnchor, verAnchor, x, y);
ButtonWidget_Set(btn, text, font);
((struct Menu*)s)->widgets[i] = (struct Widget*)btn;
((struct Screen*)s)->widgets[i] = (struct Widget*)btn;
}
static void Menu_Label(void* s, int i, struct TextWidget* label, const String* text, const FontDesc* font, int horAnchor, int verAnchor, int x, int y) {
TextWidget_Make(label, horAnchor, verAnchor, x, y);
TextWidget_Set(label, text, font);
((struct Menu*)s)->widgets[i] = (struct Widget*)label;
((struct Screen*)s)->widgets[i] = (struct Widget*)label;
}
static void Menu_Input(void* s, int i, struct MenuInputWidget* input, int width, const String* text, FontDesc* font, struct MenuInputDesc* desc, int horAnchor, int verAnchor, int x, int y) {
struct Menu* menu = (struct Menu*)s;
MenuInputWidget_Create(input, width, 30, text, font, desc);
menu->widgets[i] = (struct Widget*)input;
Widget_SetLocation(menu->widgets[i], horAnchor, verAnchor, x, y);
Widget_SetLocation(input, horAnchor, verAnchor, x, y);
input->base.showCaret = true;
((struct Screen*)s)->widgets[i] = (struct Widget*)input;
}
static void Menu_Back(void* s, int i, struct ButtonWidget* btn, const char* label, const FontDesc* font, Widget_LeftClick onClick) {
@ -90,36 +85,33 @@ CC_NOINLINE static void Menu_MakeBodyFont(FontDesc* font) {
static void Menu_ContextLost(void* screen) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i;
if (!widgets) return;
for (i = 0; i < s->widgetsCount; i++) {
for (i = 0; i < s->numWidgets; i++) {
if (!widgets[i]) continue;
Elem_Free(widgets[i]);
}
}
static void Menu_OnResize(void* screen) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i;
if (!widgets) return;
for (i = 0; i < s->widgetsCount; i++) {
for (i = 0; i < s->numWidgets; i++) {
if (!widgets[i]) continue;
Widget_Reposition(widgets[i]);
}
}
static void Menu_RenderWidgets(void* screen, double delta) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i;
if (!widgets) return;
for (i = 0; i < s->widgetsCount; i++) {
for (i = 0; i < s->numWidgets; i++) {
if (!widgets[i]) continue;
Elem_Render(widgets[i], delta);
}
@ -135,9 +127,9 @@ static void Menu_RenderBounds(void) {
}
static int Menu_DoMouseDown(void* screen, int x, int y, MouseButton btn) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i, count = s->widgetsCount;
int i, count = s->numWidgets;
/* iterate backwards (because last elements rendered are shown over others) */
for (i = count - 1; i >= 0; i--) {
@ -159,9 +151,9 @@ static bool Menu_MouseDown(void* screen, int x, int y, MouseButton btn) {
}
static int Menu_DoMouseMove(void* screen, int x, int y) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i, count = s->widgetsCount;
int i, count = s->numWidgets;
for (i = 0; i < count; i++) {
struct Widget* w = widgets[i];
@ -191,19 +183,19 @@ static bool Menu_KeyUp(void* screen, Key key) { return true; }
*------------------------------------------------------Menu utilities-----------------------------------------------------*
*#########################################################################################################################*/
static int Menu_Index(void* screen, void* widget) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i;
struct Widget* w = (struct Widget*)widget;
for (i = 0; i < s->widgetsCount; i++) {
for (i = 0; i < s->numWidgets; i++) {
if (widgets[i] == w) return i;
}
return -1;
}
static void Menu_Remove(void* screen, int i) {
struct Menu* s = (struct Menu*)screen;
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
if (widgets[i]) { Elem_TryFree(widgets[i]); }
@ -255,7 +247,7 @@ struct ListScreen;
#define LIST_SCREEN_EMPTY "-----"
static struct ListScreen {
MenuBase_Layout
Screen_Layout
struct ButtonWidget buttons[LIST_SCREEN_ITEMS];
struct ButtonWidget left, right, done;
FontDesc font;
@ -405,9 +397,9 @@ static void ListScreen_Init(void* screen) {
struct ListScreen* s = (struct ListScreen*)screen;
int i;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->wheelAcc = 0.0f;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->wheelAcc = 0.0f;
s->currentIndex = 0;
for (i = 0; i < LIST_SCREEN_ITEMS; i++) {
@ -584,10 +576,10 @@ void PauseScreen_Show(void) {
static struct Widget* widgets[8];
struct PauseScreen* s = &PauseScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->VTABLE = &PauseScreen_VTABLE;
Gui_Replace((struct Screen*)s, GUI_PRIORITY_MENU);
@ -659,9 +651,9 @@ static void OptionsGroupScreen_Init(void* screen) {
MenuScreen_Init(s);
Event_RegisterVoid(&UserEvents.HackPermissionsChanged, s, OptionsGroupScreen_CheckHacksAllowed);
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->selectedI = -1;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->selectedI = -1;
for (i = 0; i < Array_Elems(optsGroup_btns); i++) {
ButtonWidget_Make(&s->buttons[i], 300, optsGroup_btns[i].onClick,
@ -913,13 +905,13 @@ struct Screen* EditHotkeyScreen_MakeInstance(struct HotkeyData original) {
static struct Widget* widgets[7];
struct EditHotkeyScreen* s = &EditHotkeyScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->VTABLE = &EditHotkeyScreen_VTABLE;
s->selectedI = -1;
s->VTABLE = &EditHotkeyScreen_VTABLE;
s->selectedI = -1;
s->origHotkey = original;
s->curHotkey = original;
return (struct Screen*)s;
@ -1079,10 +1071,10 @@ void GenLevelScreen_Show(void) {
static struct Widget* widgets[12];
struct GenLevelScreen* s = &GenLevelScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->VTABLE = &GenLevelScreen_VTABLE;
Gui_Replace((struct Screen*)s, GUI_PRIORITY_MENU);
@ -1134,10 +1126,10 @@ void ClassicGenScreen_Show(void) {
static struct Widget* widgets[4];
struct ClassicGenScreen* s = &ClassicGenScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->VTABLE = &ClassicGenScreen_VTABLE;
Gui_Replace((struct Screen*)s, GUI_PRIORITY_MENU);
@ -1293,10 +1285,10 @@ void SaveLevelScreen_Show(void) {
static struct Widget* widgets[6];
struct SaveLevelScreen* s = &SaveLevelScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->VTABLE = &SaveLevelScreen_VTABLE;
Gui_Replace((struct Screen*)s, GUI_PRIORITY_MENU);
@ -1310,20 +1302,15 @@ static void TexturePackScreen_EntryClick(void* screen, void* widget) {
String path; char pathBuffer[FILENAME_SIZE];
struct ListScreen* s = (struct ListScreen*)screen;
String filename;
int idx;
filename = ListScreen_UNSAFE_GetCur(s, widget);
String_InitArray(path, pathBuffer);
String_Format1(&path, "texpacks/%s", &filename);
if (!File_Exists(&path)) return;
idx = s->currentIndex;
Game_SetDefaultTexturePack(&filename);
World_TextureUrl.length = 0;
TexturePack_ExtractCurrent(true);
Elem_Recreate(s);
ListScreen_SetCurrentIndex(s, idx);
}
static void TexturePackScreen_FilterFiles(const String* path, void* obj) {
@ -1661,10 +1648,10 @@ static struct KeyBindingsScreen* KeyBindingsScreen_Make(int bindsCount, uint8_t*
static struct Widget* widgets[12 + 4]; /* 12 buttons + </> buttons + 2 widgets used by MouseKeyBindings */
struct KeyBindingsScreen* s = &KeyBindingsScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = bindsCount + 4;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = bindsCount + 4;
s->VTABLE = &KeyBindingsScreen_VTABLE;
s->VTABLE->ContextRecreated = contextRecreated;
@ -1795,7 +1782,7 @@ struct Screen* MouseKeyBindingsScreen_MakeInstance(void) {
struct KeyBindingsScreen* s = KeyBindingsScreen_Make(Array_Elems(binds), binds, descs, MouseKeyBindingsScreen_ContextRecreated);
s->leftPage = Menu_SwitchKeysOther;
s->widgetsCount++; /* Extra text widget for 'right click' message */
s->numWidgets++; /* Extra text widget for 'right click' message */
return (struct Screen*)s;
}
@ -1895,7 +1882,7 @@ static void MenuOptionsScreen_FreeInput(struct MenuOptionsScreen* s) {
int i;
if (s->activeI == -1) return;
for (i = s->widgetsCount - 3; i < s->widgetsCount; i++) {
for (i = s->numWidgets - 3; i < s->numWidgets; i++) {
if (!s->widgets[i]) continue;
Elem_TryFree(s->widgets[i]);
s->widgets[i] = NULL;
@ -2085,7 +2072,7 @@ static void MenuOptionsScreen_Input(void* screen, void* widget) {
String_InitArray(value, valueBuffer);
btn->GetValue(&value);
i = s->widgetsCount;
i = s->numWidgets;
Menu_Input(s, i - 1, &s->input, 400, &value, &s->textFont, &s->descs[s->activeI],
ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 110);
@ -2105,10 +2092,10 @@ struct Screen* MenuOptionsScreen_MakeInstance(int count, Event_Void_Callback con
static struct Widget* widgets[11 + 3]; /* max buttons + 3 widgets for input */
struct MenuOptionsScreen* s = &MenuOptionsScreen_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = count;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = count;
s->extHelp.lines = 0;
s->VTABLE = &MenuOptionsScreen_VTABLE;
@ -2572,7 +2559,7 @@ static void HacksSettingsScreen_CheckHacksAllowed(void* screen) {
bool disabled;
int i;
for (i = 0; i < s->widgetsCount; i++) {
for (i = 0; i < s->numWidgets; i++) {
if (!widgets[i]) continue;
widgets[i]->disabled = false;
}
@ -3004,10 +2991,10 @@ void TexIdsOverlay_Show(void) {
static struct Widget* widgets[1];
struct TexIdsOverlay* s = &TexIdsOverlay_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
s->VTABLE = &TexIdsOverlay_VTABLE;
Gui_Replace((struct Screen*)s, GUI_PRIORITY_TEXIDS);
@ -3073,10 +3060,10 @@ void UrlWarningOverlay_Show(const String* url) {
static struct Widget* widgets[6];
struct UrlWarningOverlay* s = &UrlWarningOverlay_Instance;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
String_InitArray(s->url, s->_urlBuffer);
String_Copy(&s->url, url);
@ -3206,7 +3193,7 @@ static void TexPackOverlay_ContextRecreated(void* screen) {
} else {
TexPackOverlay_MakeNormalElements(s);
}
s->widgetsCount = s->showingDeny ? 6 : 8;
s->numWidgets = s->showingDeny ? 6 : 8;
}
static struct ScreenVTABLE TexPackOverlay_VTABLE = {
@ -3219,11 +3206,11 @@ void TexPackOverlay_Show(const String* url) {
static struct Widget* widgets[8];
struct TexPackOverlay* s = &TexPackOverlay_Instance;
s->showingDeny = false;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->widgetsCount = Array_Elems(widgets);
s->showingDeny = false;
s->grabsInput = true;
s->closable = true;
s->widgets = widgets;
s->numWidgets = Array_Elems(widgets);
String_InitArray(s->identifier, s->_identifierBuffer);
String_Format1(&s->identifier, "CL_%s", url);

View File

@ -87,13 +87,13 @@ static void InventoryScreen_ContextLost(void* screen) {
static void InventoryScreen_ContextRecreated(void* screen) {
struct InventoryScreen* s = (struct InventoryScreen*)screen;
Drawer2D_MakeFont(&s->font, 16, FONT_STYLE_NORMAL);
Elem_Recreate(&s->table);
TableWidget_Recreate(&s->table);
}
static void InventoryScreen_MoveToSelected(struct InventoryScreen* s) {
struct TableWidget* table = &s->table;
TableWidget_SetBlockTo(table, Inventory_SelectedBlock);
Elem_Recreate(table);
TableWidget_Recreate(table);
s->deferredSelect = false;
/* User is holding invalid block */
@ -851,7 +851,7 @@ static void HUDScreen_ColCodeChanged(void* screen, int code) {
/* Some servers have plugins that redefine colours constantly */
/* Preserve caret accumulator so caret blinking stays consistent */
caretAcc = s->input.base.caretAccumulator;
Elem_Recreate(&s->input.base);
InputWidget_UpdateText(&s->input.base);
s->input.base.caretAccumulator = caretAcc;
}
@ -1008,7 +1008,7 @@ static void HUDScreen_OnResize(void* screen) {
struct HUDScreen* s = (struct HUDScreen*)screen;
/* TODO: Kill this awful hack with fire */
bool active = s->altText.active;
Elem_Recreate(s);
Gui_DefaultRecreate(s);
SpecialInputWidget_SetActive(&s->altText, active);
Widget_Reposition(&s->hotbar);
@ -1233,7 +1233,7 @@ void HUDScreen_OpenInput(const String* text) {
Camera_CheckFocus();
String_Copy(&s->input.base.text, text);
Elem_Recreate(&s->input.base);
InputWidget_UpdateText(&s->input.base);
}
void HUDScreen_AppendInput(const String* text) {

View File

@ -699,8 +699,7 @@ static void TableWidget_Free(void* widget) {
w->lastCreatedIndex = -1000;
}
static void TableWidget_Recreate(void* widget) {
struct TableWidget* w = (struct TableWidget*)widget;
void TableWidget_Recreate(struct TableWidget* w) {
Elem_TryFree(w);
w->vb = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FT2FC4B, TABLE_MAX_VERTICES);
TableWidget_RecreateDescTex(w);
@ -820,7 +819,7 @@ static bool TableWidget_KeyDown(void* widget, Key key) {
}
static struct WidgetVTABLE TableWidget_VTABLE = {
TableWidget_Init, TableWidget_Render, TableWidget_Free, TableWidget_Recreate,
TableWidget_Init, TableWidget_Render, TableWidget_Free, Gui_DefaultRecreate,
TableWidget_KeyDown, Widget_Key, Widget_KeyPress,
TableWidget_MouseDown, TableWidget_MouseUp, TableWidget_MouseMove, TableWidget_MouseScroll,
TableWidget_Reposition,
@ -1023,12 +1022,12 @@ void InputWidget_AppendString(struct InputWidget* w, const String* text) {
}
if (!appended) return;
Elem_Recreate(w);
InputWidget_UpdateText(w);
}
void InputWidget_Append(struct InputWidget* w, char c) {
if (!InputWidget_TryAppendChar(w, c)) return;
Elem_Recreate(w);
InputWidget_UpdateText(w);
}
static void InputWidget_DeleteChar(struct InputWidget* w) {
@ -1072,7 +1071,7 @@ static void InputWidget_BackspaceKey(struct InputWidget* w) {
} else if (w->caretPos >= 0 && w->text.buffer[w->caretPos] != ' ') {
String_InsertAt(&w->text, w->caretPos, ' ');
}
Elem_Recreate(w);
InputWidget_UpdateText(w);
} else if (w->text.length > 0 && w->caretPos != 0) {
int index = w->caretPos == -1 ? w->text.length - 1 : w->caretPos;
if (InputWidget_CheckCol(w, index - 1)) {
@ -1083,7 +1082,7 @@ static void InputWidget_BackspaceKey(struct InputWidget* w) {
}
InputWidget_DeleteChar(w);
Elem_Recreate(w);
InputWidget_UpdateText(w);
}
}
@ -1091,7 +1090,7 @@ static void InputWidget_DeleteKey(struct InputWidget* w) {
if (w->text.length > 0 && w->caretPos != -1) {
String_DeleteAt(&w->text, w->caretPos);
if (w->caretPos >= w->text.length) { w->caretPos = -1; }
Elem_Recreate(w);
InputWidget_UpdateText(w);
}
}
@ -1177,8 +1176,7 @@ static void InputWidget_Free(void* widget) {
Gfx_DeleteTexture(&w->caretTex.ID);
}
static void InputWidget_Recreate(void* widget) {
struct InputWidget* w = (struct InputWidget*)widget;
void InputWidget_UpdateText(struct InputWidget* w) {
Gfx_DeleteTexture(&w->inputTex.ID);
InputWidget_Init(w);
}
@ -1493,7 +1491,7 @@ static bool MenuInputWidget_AllowedChar(void* widget, char c) {
static int MenuInputWidget_GetMaxLines(void) { return 1; }
static struct WidgetVTABLE MenuInputWidget_VTABLE = {
InputWidget_Init, MenuInputWidget_Render, InputWidget_Free, InputWidget_Recreate,
InputWidget_Init, MenuInputWidget_Render, InputWidget_Free, Gui_DefaultRecreate,
InputWidget_KeyDown, InputWidget_KeyUp, InputWidget_KeyPress,
InputWidget_MouseDown, Widget_Mouse, Widget_MouseMove, Widget_MouseScroll,
InputWidget_Reposition,
@ -1639,7 +1637,7 @@ static void ChatInputWidget_UpKey(struct InputWidget* w) {
String_AppendString(&w->text, &prevInput);
w->caretPos = -1;
Elem_Recreate(w);
InputWidget_UpdateText(w);
}
static void ChatInputWidget_DownKey(struct InputWidget* w) {
@ -1668,7 +1666,7 @@ static void ChatInputWidget_DownKey(struct InputWidget* w) {
}
w->caretPos = -1;
Elem_Recreate(w);
InputWidget_UpdateText(w);
}
static bool ChatInputWidget_IsNameChar(char c) {
@ -1746,7 +1744,7 @@ static int ChatInputWidget_GetMaxLines(void) {
}
static struct WidgetVTABLE ChatInputWidget_VTABLE = {
InputWidget_Init, ChatInputWidget_Render, InputWidget_Free, InputWidget_Recreate,
InputWidget_Init, ChatInputWidget_Render, InputWidget_Free, Gui_DefaultRecreate,
ChatInputWidget_KeyDown, InputWidget_KeyUp, InputWidget_KeyPress,
InputWidget_MouseDown, Widget_Mouse, Widget_MouseMove, Widget_MouseScroll,
InputWidget_Reposition,

View File

@ -92,6 +92,7 @@ CC_NOINLINE void TableWidget_Create(struct TableWidget* w);
CC_NOINLINE void TableWidget_SetBlockTo(struct TableWidget* w, BlockID block);
CC_NOINLINE void TableWidget_OnInventoryChanged(struct TableWidget* w);
CC_NOINLINE void TableWidget_MakeDescTex(struct TableWidget* w, BlockID block);
CC_NOINLINE void TableWidget_Recreate(struct TableWidget* w);
#define INPUTWIDGET_MAX_LINES 3
@ -128,6 +129,8 @@ CC_NOINLINE void InputWidget_Clear(struct InputWidget* w);
CC_NOINLINE void InputWidget_AppendString(struct InputWidget* w, const String* text);
/* Tries appending the given character, then updates the input texture. */
CC_NOINLINE void InputWidget_Append(struct InputWidget* w, char c);
/* Redraws text and recalculates associated state. */
CC_NOINLINE void InputWidget_UpdateText(struct InputWidget* w);
struct MenuInputDesc;