diff --git a/src/Gui.h b/src/Gui.h index 85d166b89..f95ed4bd9 100644 --- a/src/Gui.h +++ b/src/Gui.h @@ -190,6 +190,7 @@ enum GuiPriority { GUI_PRIORITY_TOUCH = 25, GUI_PRIORITY_INVENTORY = 20, GUI_PRIORITY_TABLIST = 17, + GUI_PRIORITY_CHATINPUT = 16, GUI_PRIORITY_CHAT = 15, GUI_PRIORITY_HUD = 10, GUI_PRIORITY_LOADING = 5 diff --git a/src/Input.c b/src/Input.c index 6edbb5dbe..3e0e02db6 100644 --- a/src/Input.c +++ b/src/Input.c @@ -944,7 +944,7 @@ static void HandleHotkeyDown(int key) { if (!(hkey->flags & HOTKEY_FLAG_STAYS_OPEN)) { Chat_Send(&text, false); } else if (!Gui.InputGrab) { - ChatScreen_OpenInput(&text); + ChatInputScreen_Open(&text); } } diff --git a/src/Menus.c b/src/Menus.c index c8abdde2a..650ab901a 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -3552,7 +3552,7 @@ static void UrlWarningOverlay_OpenUrl(void* screen, void* b) { static void UrlWarningOverlay_AppendUrl(void* screen, void* b) { struct UrlWarningOverlay* s = (struct UrlWarningOverlay*)screen; - if (Gui.ClickableChat) ChatScreen_AppendInput(&s->url); + if (Gui.ClickableChat) ChatInputScreen_Append(&s->url); Gui_Remove((struct Screen*)s); } diff --git a/src/Screens.c b/src/Screens.c index 23779ecdc..92e948c1d 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -41,23 +41,9 @@ int Screen_TPointer(void* s, int id, int x, int y) { return true; } void Screen_NullFunc(void* screen) { } void Screen_NullUpdate(void* screen, double delta) { } -/* TODO: Remove these */ -struct HUDScreen; -struct ChatScreen; -static struct HUDScreen* Gui_HUD; -static struct ChatScreen* Gui_Chat; - static cc_bool InventoryScreen_IsHotbarActive(void); -CC_NOINLINE static cc_bool IsOnlyChatActive(void) { - struct Screen* s; - int i; - - for (i = 0; i < Gui.ScreensCount; i++) { - s = Gui_Screens[i]; - if (s->grabsInput && s != (struct Screen*)Gui_Chat) return false; - } - return true; -} +static cc_bool ChatInputScreen_IsActive(void); +CC_NOINLINE static cc_bool IsOnlyChatActive(void); /*########################################################################################################################* @@ -74,7 +60,7 @@ static struct HUDScreen { float lastSpeed; int lastFov; struct HotbarWidget hotbar; -} HUDScreen_Instance; +} HUDScreen; #define HUD_MAX_VERTICES (TEXTWIDGET_MAX * 2) static void HUDScreen_RemakeLine1(struct HUDScreen* s) { @@ -199,7 +185,7 @@ static void HUDScreen_ContextRecreated(void* screen) { } static int HUDScreen_LayoutHotbar(void) { - struct HUDScreen* s = &HUDScreen_Instance; + struct HUDScreen* s = &HUDScreen; s->hotbar.scale = Gui_GetHotbarScale(); Widget_Layout(&s->hotbar); return s->hotbar.height; @@ -353,9 +339,8 @@ static const struct ScreenVTABLE HUDScreen_VTABLE = { HUDScreen_Layout, HUDScreen_ContextLost, HUDScreen_ContextRecreated }; void HUDScreen_Show(void) { - struct HUDScreen* s = &HUDScreen_Instance; + struct HUDScreen* s = &HUDScreen; s->VTABLE = &HUDScreen_VTABLE; - Gui_HUD = s; Gui_Add((struct Screen*)s, GUI_PRIORITY_HUD); } @@ -656,7 +641,7 @@ static int TabListOverlay_PointerDown(void* screen, int id, int x, int y) { cc_string player; int i; - if (!((struct Screen*)Gui_Chat)->grabsInput) return false; + if (!ChatInputScreen_IsActive()) return false; String_InitArray(text, textBuffer); for (i = 0; i < s->namesCount; i++) { @@ -666,7 +651,7 @@ static int TabListOverlay_PointerDown(void* screen, int id, int x, int y) { player = TabList_UNSAFE_GetPlayer(s->ids[i]); String_Format1(&text, "%s ", &player); - ChatScreen_AppendInput(&text); + ChatInputScreen_Append(&text); return TOUCH_TYPE_GUI; } return false; @@ -763,7 +748,7 @@ static const struct ScreenVTABLE TabListOverlay_VTABLE = { TabListOverlay_PointerDown, Screen_PointerUp, Screen_FPointer, Screen_FMouseScroll, TabListOverlay_Layout, TabListOverlay_ContextLost, TabListOverlay_ContextRecreated }; -void TabListOverlay_Show(void) { +static void TabListOverlay_Show(void) { struct TabListOverlay* s = &TabListOverlay_Instance; s->VTABLE = &TabListOverlay_VTABLE; s->staysOpen = false; @@ -777,15 +762,11 @@ void TabListOverlay_Show(void) { *#########################################################################################################################*/ static struct ChatScreen { Screen_Body - float chatAcc; - cc_bool suppressNextPress; int chatIndex, paddingX, paddingY; - int lastDownloadStatus; + int lastDownloadStatus, uiOffset; struct FontDesc chatFont, announcementFont, bigAnnouncementFont, smallAnnouncementFont; struct TextWidget announcement, bigAnnouncement, smallAnnouncement; - struct ChatInputWidget input; struct TextGroupWidget status, bottomRight, chat, clientStatus; - struct SpecialInputWidget altText; #ifdef CC_BUILD_TOUCH struct ButtonWidget send, cancel, more; #endif @@ -806,27 +787,15 @@ static struct Widget* chat_widgets[] = { }; -static void ChatScreen_UpdateChatYOffsets(struct ChatScreen* s) { - int pad, y; - /* Determining chat Y requires us to know hotbar's position */ - HUDScreen_LayoutHotbar(); - - y = min(s->input.base.y, Gui_HUD->hotbar.y); - y -= s->input.base.yOffset; /* add some padding */ - s->altText.yOffset = WindowInfo.Height - y; - Widget_Layout(&s->altText); +static void ChatScreen_UpdateChatYOffsets(void) { + struct ChatScreen* s = &ChatScreen_Instance; - pad = s->altText.active ? 5 : 10; - s->clientStatus.yOffset = WindowInfo.Height - s->altText.y + pad; + s->clientStatus.yOffset = s->uiOffset + 10; /* Max height of hotbar and chat input */ Widget_Layout(&s->clientStatus); s->chat.yOffset = s->clientStatus.yOffset + s->clientStatus.height; Widget_Layout(&s->chat); } -static void ChatScreen_OnInputTextChanged(void* elem) { - ChatScreen_UpdateChatYOffsets(&ChatScreen_Instance); -} - static cc_string ChatScreen_GetChat(int i) { i += ChatScreen_Instance.chatIndex; @@ -847,6 +816,7 @@ static void ChatScreen_FreeChatFonts(struct ChatScreen* s) { Font_Free(&s->smallAnnouncementFont); } +static void ChatInputScreen_OnFontChanged(void); static cc_bool ChatScreen_ChatUpdateFont(struct ChatScreen* s) { int size = (int)(8 * Gui_GetChatScale()); Math_Clamp(size, 8, 60); @@ -863,11 +833,12 @@ static cc_bool ChatScreen_ChatUpdateFont(struct ChatScreen* s) { Font_Make(&s->bigAnnouncementFont, size * 1.33, FONT_FLAGS_NONE); Font_Make(&s->smallAnnouncementFont, size * 0.67, FONT_FLAGS_NONE); - ChatInputWidget_SetFont(&s->input, &s->chatFont); TextGroupWidget_SetFont(&s->status, &s->chatFont); TextGroupWidget_SetFont(&s->bottomRight, &s->chatFont); TextGroupWidget_SetFont(&s->chat, &s->chatFont); TextGroupWidget_SetFont(&s->clientStatus, &s->chatFont); + + ChatInputScreen_OnFontChanged(); return true; } @@ -879,9 +850,6 @@ static void ChatScreen_Redraw(struct ChatScreen* s) { TextGroupWidget_RedrawAll(&s->status); TextGroupWidget_RedrawAll(&s->bottomRight); TextGroupWidget_RedrawAll(&s->clientStatus); - - if (s->grabsInput) InputWidget_UpdateText(&s->input.base); - SpecialInputWidget_Redraw(&s->altText); } static int ChatScreen_ClampChatIndex(int index) { @@ -891,7 +859,8 @@ static int ChatScreen_ClampChatIndex(int index) { return index; } -static void ChatScreen_ScrollChatBy(struct ChatScreen* s, int delta) { +static void ChatScreen_ScrollChatBy(int delta) { + struct ChatScreen* s = &ChatScreen_Instance; int newIndex = ChatScreen_ClampChatIndex(s->chatIndex + delta); delta = newIndex - s->chatIndex; @@ -908,44 +877,25 @@ static void ChatScreen_ScrollChatBy(struct ChatScreen* s, int delta) { } } -static void ChatScreen_EnterChatInput(struct ChatScreen* s, cc_bool close) { - struct InputWidget* input; - int defaultIndex; - - s->grabsInput = false; - Gui_UpdateInputGrab(); - Window_CloseKeyboard(); - if (close) InputWidget_Clear(&s->input.base); - - input = &s->input.base; - input->OnPressedEnter(input); - SpecialInputWidget_SetActive(&s->altText, false); - ChatScreen_UpdateChatYOffsets(s); - +static void ChatScreen_ResetScroll(void) { + struct ChatScreen* s = &ChatScreen_Instance; /* Reset chat when user has scrolled up in chat history */ - defaultIndex = Chat_Log.count - Gui.Chatlines; - if (s->chatIndex != defaultIndex) { - s->chatIndex = defaultIndex; - TextGroupWidget_RedrawAll(&s->chat); - } + int defaultIndex = Chat_Log.count - Gui.Chatlines; + if (s->chatIndex == defaultIndex) return; + + s->chatIndex = defaultIndex; + TextGroupWidget_RedrawAll(&s->chat); + s->dirty = true; } static void ChatScreen_ColCodeChanged(void* screen, int code) { struct ChatScreen* s = (struct ChatScreen*)screen; - double caretAcc; if (Gfx.LostContext) return; - SpecialInputWidget_UpdateCols(&s->altText); TextGroupWidget_RedrawAllWithCol(&s->chat, code); TextGroupWidget_RedrawAllWithCol(&s->status, code); TextGroupWidget_RedrawAllWithCol(&s->bottomRight, code); TextGroupWidget_RedrawAllWithCol(&s->clientStatus, code); - - /* Some servers have plugins that redefine colours constantly */ - /* Preserve caret accumulator so caret blinking stays consistent */ - caretAcc = s->input.base.caretAccumulator; - InputWidget_UpdateText(&s->input.base); - s->input.base.caretAccumulator = caretAcc; } static void ChatScreen_ChatReceived(void* screen, const cc_string* msg, int type) { @@ -972,7 +922,7 @@ static void ChatScreen_ChatReceived(void* screen, const cc_string* msg, int type TextWidget_Set(&s->smallAnnouncement, msg, &s->smallAnnouncementFont); } else if (type >= MSG_TYPE_CLIENTSTATUS_1 && type <= MSG_TYPE_CLIENTSTATUS_2) { TextGroupWidget_Redraw(&s->clientStatus, type - MSG_TYPE_CLIENTSTATUS_1); - ChatScreen_UpdateChatYOffsets(s); + ChatScreen_UpdateChatYOffsets(); } else if (type >= MSG_TYPE_EXTRASTATUS_1 && type <= MSG_TYPE_EXTRASTATUS_2) { /* Status[0] is for texture pack downloading message */ /* Status[1] is for reduced performance mode message */ @@ -1045,92 +995,25 @@ static void ChatScreen_DrawChatBackground(struct ChatScreen* s) { } } -static void ChatScreen_DrawChat(struct ChatScreen* s, double delta) { - struct Texture tex; - double now; - int i, logIdx; - - Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); - Gfx_BindDynamicVb(s->vb); - - if (!Game_PureClassic) { Widget_Render2(&s->status); } - Widget_Render2(&s->bottomRight); - Widget_Render2(&s->clientStatus); - - now = Game.Time; - if (s->grabsInput) { - Widget_Render2(&s->chat); - } else { - /* Only render recent chat */ - for (i = 0; i < s->chat.lines; i++) { - tex = s->chat.textures[i]; - logIdx = s->chatIndex + i; - if (!tex.ID) continue; - - if (logIdx < 0 || logIdx >= Chat_Log.count) continue; - if (Chat_GetLogTime(logIdx) + 10 < now) continue; - - Gfx_BindTexture(tex.ID); - Gfx_DrawVb_IndexedTris_Range(4, s->chat.offset + i * 4); - } - } - - Widget_Render2(&s->announcement); - Widget_Render2(&s->bigAnnouncement); - Widget_Render2(&s->smallAnnouncement); - - if (s->grabsInput) { - Elem_Render(&s->input.base, delta); - if (s->altText.active) { - Elem_Render(&s->altText, delta); - } - -#ifdef CC_BUILD_TOUCH - if (!Input_TouchMode) return; - Elem_Render(&s->more, delta); - Elem_Render(&s->send, delta); - Elem_Render(&s->cancel, delta); -#endif - } -} - static void ChatScreen_ContextLost(void* screen) { struct ChatScreen* s = (struct ChatScreen*)screen; ChatScreen_FreeChatFonts(s); Screen_ContextLost(s); Elem_Free(&s->chat); - Elem_Free(&s->input.base); - Elem_Free(&s->altText); Elem_Free(&s->status); Elem_Free(&s->bottomRight); Elem_Free(&s->clientStatus); Elem_Free(&s->announcement); Elem_Free(&s->bigAnnouncement); Elem_Free(&s->smallAnnouncement); - -#ifdef CC_BUILD_TOUCH - Elem_Free(&s->more); - Elem_Free(&s->send); - Elem_Free(&s->cancel); -#endif } static void ChatScreen_ContextRecreated(void* screen) { struct ChatScreen* s = (struct ChatScreen*)screen; - struct FontDesc font; ChatScreen_ChatUpdateFont(s); ChatScreen_Redraw(s); Screen_UpdateVb(s); - -#ifdef CC_BUILD_TOUCH - if (!Input_TouchMode) return; - Gui_MakeTitleFont(&font); - ButtonWidget_SetConst(&s->more, "More", &font); - ButtonWidget_SetConst(&s->send, "Send", &font); - ButtonWidget_SetConst(&s->cancel, "Cancel", &font); - Font_Free(&font); -#endif } static void ChatScreen_Layout(void* screen) { @@ -1140,13 +1023,11 @@ static void ChatScreen_Layout(void* screen) { s->paddingX = Display_ScaleX(5); s->paddingY = Display_ScaleY(5); - Widget_SetLocation(&s->input.base, ANCHOR_MIN, ANCHOR_MAX, 5, 5); - Widget_SetLocation(&s->altText, ANCHOR_MIN, ANCHOR_MAX, 5, 5); Widget_SetLocation(&s->status, ANCHOR_MAX, ANCHOR_MIN, 0, 0); Widget_SetLocation(&s->bottomRight, ANCHOR_MAX, ANCHOR_MAX, 0, 0); Widget_SetLocation(&s->chat, ANCHOR_MIN, ANCHOR_MAX, 10, 0); Widget_SetLocation(&s->clientStatus, ANCHOR_MIN, ANCHOR_MAX, 10, 0); - ChatScreen_UpdateChatYOffsets(s); + ChatScreen_UpdateChatYOffsets(); /* Can't use Widget_SetLocation because it DPI scales input */ s->bottomRight.yOffset = HUDScreen_LayoutHotbar() + Display_ScaleY(15); @@ -1163,81 +1044,20 @@ static void ChatScreen_Layout(void* screen) { Widget_SetLocation(&s->smallAnnouncement, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 0); s->smallAnnouncement.yOffset = WindowInfo.Height / 20; Widget_Layout(&s->smallAnnouncement); - -#ifdef CC_BUILD_TOUCH - if (WindowInfo.SoftKeyboard == SOFT_KEYBOARD_SHIFT) { - Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MAX, 10, 60); - Widget_SetLocation(&s->cancel, ANCHOR_MAX, ANCHOR_MAX, 10, 10); - Widget_SetLocation(&s->more, ANCHOR_MAX, ANCHOR_MAX, 10, 110); - } else { - Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MIN, 10, 10); - Widget_SetLocation(&s->cancel, ANCHOR_MAX, ANCHOR_MIN, 10, 60); - Widget_SetLocation(&s->more, ANCHOR_MAX, ANCHOR_MIN, 10, 110); - } -#endif -} - -static int ChatScreen_KeyPress(void* screen, char keyChar) { - struct ChatScreen* s = (struct ChatScreen*)screen; - if (!s->grabsInput) return false; - - if (s->suppressNextPress) { - s->suppressNextPress = false; - return false; - } - - InputWidget_Append(&s->input.base, keyChar); - return true; -} - -static int ChatScreen_TextChanged(void* screen, const cc_string* str) { -#ifdef CC_BUILD_TOUCH - struct ChatScreen* s = (struct ChatScreen*)screen; - if (!s->grabsInput) return false; - - InputWidget_SetText(&s->input.base, str); -#endif - return true; } static int ChatScreen_KeyDown(void* screen, int key) { static const cc_string slash = String_FromConst("/"); struct ChatScreen* s = (struct ChatScreen*)screen; - int playerListKey = KeyBinds[KEYBIND_TABLIST]; - cc_bool handlesList = playerListKey != KEY_TAB || !Gui.TabAutocomplete || !s->grabsInput; - if (key == playerListKey && handlesList) { + if (key == KeyBinds[KEYBIND_TABLIST]) { if (!TabListOverlay_Instance.active && !Server.IsSinglePlayer) { - TabListOverlay_Show(); + TabListOverlay_Show(); /* TODO return true*/ } - return true; - } - - s->suppressNextPress = false; - /* Handle chat text input */ - if (s->grabsInput) { -#ifdef CC_BUILD_WEB - /* See reason for this in HandleInputUp */ - if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == KEY_KP_ENTER) { - ChatScreen_EnterChatInput(s, false); -#else - if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == KEY_KP_ENTER || key == KEY_ESCAPE) { - ChatScreen_EnterChatInput(s, key == KEY_ESCAPE); -#endif - } else if (key == KEY_PAGEUP) { - ChatScreen_ScrollChatBy(s, -Gui.Chatlines); - } else if (key == KEY_PAGEDOWN) { - ChatScreen_ScrollChatBy(s, +Gui.Chatlines); - } else { - Elem_HandlesKeyDown(&s->input.base, key); - } - return key < KEY_F1 || key > KEY_F24; - } - - if (key == KeyBinds[KEYBIND_CHAT]) { - ChatScreen_OpenInput(&String_Empty); + } else if (key == KeyBinds[KEYBIND_CHAT]) { + ChatInputScreen_Open(&String_Empty); } else if (key == KEY_SLASH) { - ChatScreen_OpenInput(&slash); + ChatInputScreen_Open(&slash); } else if (key == KeyBinds[KEYBIND_INVENTORY]) { InventoryScreen_Show(); } else { @@ -1246,99 +1066,26 @@ static int ChatScreen_KeyDown(void* screen, int key) { return true; } -static void ChatScreen_ToggleAltInput(struct ChatScreen* s) { - SpecialInputWidget_SetActive(&s->altText, !s->altText.active); - ChatScreen_UpdateChatYOffsets(s); -} - -static void ChatScreen_KeyUp(void* screen, int key) { - struct ChatScreen* s = (struct ChatScreen*)screen; - if (!s->grabsInput || (struct Screen*)s != Gui.InputGrab) return; - -#ifdef CC_BUILD_WEB - /* See reason for this in HandleInputUp */ - if (key == KEY_ESCAPE) ChatScreen_EnterChatInput(s, true); -#endif - - if (Server.SupportsFullCP437 && key == KeyBinds[KEYBIND_EXT_INPUT]) { - if (!WindowInfo.Focused) return; - ChatScreen_ToggleAltInput(s); - } -} - -static int ChatScreen_MouseScroll(void* screen, float delta) { - struct ChatScreen* s = (struct ChatScreen*)screen; - int steps; - if (!s->grabsInput) return false; - - steps = Utils_AccumulateWheelDelta(&s->chatAcc, delta); - ChatScreen_ScrollChatBy(s, -steps); - return true; -} - static int ChatScreen_PointerDown(void* screen, int id, int x, int y) { cc_string text; char textBuffer[STRING_SIZE * 4]; struct ChatScreen* s = (struct ChatScreen*)screen; - int height, chatY, i; + int i; if (Game_HideGui) return false; - if (!s->grabsInput) { - if (!Input_TouchMode) return false; - String_InitArray(text, textBuffer); - - /* Should be able to click on links with touch */ - i = TextGroupWidget_GetSelected(&s->chat, &text, x, y); - if (!Utils_IsUrlPrefix(&text)) return false; - - if (Chat_GetLogTime(s->chatIndex + i) + 10 < Game.Time) return false; - UrlWarningOverlay_Show(&text); return TOUCH_TYPE_GUI; - } - -#ifdef CC_BUILD_TOUCH - if (Input_TouchMode) { - if (Widget_Contains(&s->send, x, y)) { - ChatScreen_EnterChatInput(s, false); return TOUCH_TYPE_GUI; - } - if (Widget_Contains(&s->cancel, x, y)) { - ChatScreen_EnterChatInput(s, true); return TOUCH_TYPE_GUI; - } - if (Widget_Contains(&s->more, x, y)) { - ChatScreen_ToggleAltInput(s); return TOUCH_TYPE_GUI; - } - } -#endif - - if (!Widget_Contains(&s->chat, x, y)) { - if (s->altText.active && Widget_Contains(&s->altText, x, y)) { - Elem_HandlesPointerDown(&s->altText, id, x, y); - ChatScreen_UpdateChatYOffsets(s); - return TOUCH_TYPE_GUI; - } - Elem_HandlesPointerDown(&s->input.base, id, x, y); - return TOUCH_TYPE_GUI; - } - - height = TextGroupWidget_UsedHeight(&s->chat); - chatY = s->chat.y + s->chat.height - height; - if (!Gui_Contains(s->chat.x, chatY, s->chat.width, height, x, y)) return false; - + if (!Input_TouchMode) return false; String_InitArray(text, textBuffer); - TextGroupWidget_GetSelected(&s->chat, &text, x, y); - if (!text.length) return false; - if (Utils_IsUrlPrefix(&text)) { - UrlWarningOverlay_Show(&text); - } else if (Gui.ClickableChat) { - ChatScreen_AppendInput(&text); - } + /* Should be able to click on links with touch */ + i = TextGroupWidget_GetSelected(&s->chat, &text, x, y); + if (!Utils_IsUrlPrefix(&text)) return false; + + if (Chat_GetLogTime(s->chatIndex + i) + 10 < Game.Time) return false; + UrlWarningOverlay_Show(&text); return TOUCH_TYPE_GUI; } static void ChatScreen_Init(void* screen) { struct ChatScreen* s = (struct ChatScreen*)screen; - ChatInputWidget_Create(&s->input); - s->input.base.OnTextChanged = ChatScreen_OnInputTextChanged; - SpecialInputWidget_Create(&s->altText, &s->chatFont, &s->input.base); TextGroupWidget_Create(&s->status, CHAT_MAX_STATUS, s->statusTextures, ChatScreen_GetStatus); @@ -1374,18 +1121,49 @@ static void ChatScreen_Init(void* screen) { #endif } +static void ChatScreen_DrawChat(struct ChatScreen* s, double delta) { + struct Texture tex; + double now; + int i, logIdx; + + Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); + Gfx_BindDynamicVb(s->vb); + + if (!Game_PureClassic) { Widget_Render2(&s->status); } + Widget_Render2(&s->bottomRight); + Widget_Render2(&s->clientStatus); + + now = Game.Time; + if (ChatInputScreen_IsActive()) { + Widget_Render2(&s->chat); + } else { + /* Only render recent chat */ + for (i = 0; i < s->chat.lines; i++) { + tex = s->chat.textures[i]; + logIdx = s->chatIndex + i; + if (!tex.ID) continue; + + if (logIdx < 0 || logIdx >= Chat_Log.count) continue; + if (Chat_GetLogTime(logIdx) + 10 < now) continue; + + Gfx_BindTexture(tex.ID); + Gfx_DrawVb_IndexedTris_Range(4, s->chat.offset + i * 4); + } + } + + Widget_Render2(&s->announcement); + Widget_Render2(&s->bigAnnouncement); + Widget_Render2(&s->smallAnnouncement); +} + static void ChatScreen_Render(void* screen, double delta) { struct ChatScreen* s = (struct ChatScreen*)screen; - - if (Game_HideGui && s->grabsInput) { - Elem_Render(&s->input.base, delta); - } if (Game_HideGui) return; if (!TabListOverlay_Instance.active && !Gui_GetBlocksWorld()) { ChatScreen_DrawCrosshairs(); } - if (s->grabsInput && !Gui.ClassicChat) { + if (ChatInputScreen_IsActive() && !Gui.ClassicChat) { ChatScreen_DrawChatBackground(s); } @@ -1401,8 +1179,8 @@ static void ChatScreen_Free(void* screen) { static const struct ScreenVTABLE ChatScreen_VTABLE = { ChatScreen_Init, ChatScreen_Update, ChatScreen_Free, ChatScreen_Render, Screen_BuildMesh, - ChatScreen_KeyDown, ChatScreen_KeyUp, ChatScreen_KeyPress, ChatScreen_TextChanged, - ChatScreen_PointerDown, Screen_PointerUp, Screen_FPointer, ChatScreen_MouseScroll, + ChatScreen_KeyDown, Screen_FInput, Screen_FKeyPress, Screen_FText, + ChatScreen_PointerDown, Screen_PointerUp, Screen_FPointer, Screen_FMouseScroll, ChatScreen_Layout, ChatScreen_ContextLost, ChatScreen_ContextRecreated }; void ChatScreen_Show(void) { @@ -1410,38 +1188,369 @@ void ChatScreen_Show(void) { s->lastDownloadStatus = HTTP_PROGRESS_NOT_WORKING_ON; s->VTABLE = &ChatScreen_VTABLE; - Gui_Chat = s; Gui_Add((struct Screen*)s, GUI_PRIORITY_CHAT); } -void ChatScreen_OpenInput(const cc_string* text) { - struct ChatScreen* s = &ChatScreen_Instance; - struct OpenKeyboardArgs args; - s->suppressNextPress = true; - s->grabsInput = true; - - Gui_UpdateInputGrab(); - OpenKeyboardArgs_Init(&args, text, KEYBOARD_TYPE_TEXT | KEYBOARD_FLAG_SEND); - args.placeholder = "Enter chat"; - args.multiline = true; - Window_OpenKeyboard(&args); - s->input.base.disabled = args.opaque; - - String_Copy(&s->input.base.text, text); - InputWidget_UpdateText(&s->input.base); -} - -void ChatScreen_AppendInput(const cc_string* text) { - struct ChatScreen* s = &ChatScreen_Instance; - InputWidget_AppendText(&s->input.base, text); -} - void ChatScreen_SetChatlines(int lines) { struct ChatScreen* s = &ChatScreen_Instance; Elem_Free(&s->chat); s->chatIndex += s->chat.lines - lines; s->chat.lines = lines; + TextGroupWidget_RedrawAll(&s->chat); + s->dirty = true; +} + + + +/*########################################################################################################################* +*-----------------------------------------------------ChatInputScreen-----------------------------------------------------* +*#########################################################################################################################*/ +static struct ChatInputScreen { + Screen_Body + float chatAcc; + cc_bool suppressNextPress, active; + struct ChatInputWidget input; + struct SpecialInputWidget altText; +#ifdef CC_BUILD_TOUCH + struct ButtonWidget send, cancel, more; +#endif +} ChatInputScreen; + +static struct Widget* chatinput_widgets[] = { + (struct Widget*)&ChatInputScreen.input, (struct Widget*)&ChatInputScreen.altText, +#ifdef CC_BUILD_TOUCH + (struct Widget*)&ChatInputScreen.send, (struct Widget*)&ChatInputScreen.cancel, + (struct Widget*)&ChatInputScreen.more +#endif +}; +#define CHATINPUT_MAX_VERTICES MENUINPUTWIDGET_MAX + 4 /* TODO replace.. */ + +static cc_bool ChatInputScreen_IsActive(void) { return ChatInputScreen.active; } +static cc_bool IsOnlyChatActive(void) { + struct Screen* s; + int i; + + for (i = 0; i < Gui.ScreensCount; i++) { + s = Gui_Screens[i]; + if (s->grabsInput && s != (struct Screen*)&ChatInputScreen) return false; + } + return true; +} + +static void ChatInputScreen_UpdateYOffsets(void) { + struct ChatInputScreen* s = &ChatInputScreen; + int y; + /* Determining input Y requires us to know hotbar's position */ + HUDScreen_LayoutHotbar(); + + y = min(s->input.base.y, HUDScreen.hotbar.y); + y -= s->input.base.yOffset; /* add some padding */ + s->altText.yOffset = WindowInfo.Height - y; + Widget_Layout(&s->altText); + + ChatScreen_Instance.uiOffset = WindowInfo.Height - s->altText.y; + ChatScreen_UpdateChatYOffsets(); +} + +static void ChatInputScreen_OnInputTextChanged(void* elem) { + ChatInputScreen_UpdateYOffsets(); +} + +static void ChatInputScreen_OnFontChanged(void) { + struct ChatInputScreen* s = &ChatInputScreen; + if (!s->altText.font) return; /* Chat input never created */ + + ChatInputWidget_SetFont(&s->input, &ChatScreen_Instance.chatFont); + InputWidget_UpdateText(&s->input.base); + SpecialInputWidget_Redraw(&s->altText); + + ChatInputScreen_UpdateYOffsets(); +} + +static void ChatInputScreen_EnterInput(struct ChatInputScreen* s, cc_bool close) { + struct InputWidget* input; + + Gui_UpdateInputGrab(); + Window_CloseKeyboard(); + if (close) InputWidget_Clear(&s->input.base); + + input = &s->input.base; + input->OnPressedEnter(input); + SpecialInputWidget_SetActive(&s->altText, false); + ChatInputScreen_UpdateYOffsets(); + + ChatScreen_ResetScroll(); + Gui_Remove((struct Screen*)s); +} + +static void ChatInputScreen_ColorCodeChanged(void* screen, int code) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + double caretAcc; + if (Gfx.LostContext) return; + SpecialInputWidget_UpdateCols(&s->altText); + + /* Some servers have plugins that redefine colours constantly */ + /* Preserve caret accumulator so caret blinking stays consistent */ + caretAcc = s->input.base.caretAccumulator; + InputWidget_UpdateText(&s->input.base); + s->input.base.caretAccumulator = caretAcc; +} + +static void ChatInputScreen_ContextLost(void* screen) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + Screen_ContextLost(s); + Elem_Free(&s->input.base); + Elem_Free(&s->altText); + +#ifdef CC_BUILD_TOUCH + Elem_Free(&s->more); + Elem_Free(&s->send); + Elem_Free(&s->cancel); +#endif +} + +static void ChatInputScreen_ContextRecreated(void* screen) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + struct FontDesc font; + ChatInputScreen_OnFontChanged(); + Screen_UpdateVb(s); + +#ifdef CC_BUILD_TOUCH + if (!Input_TouchMode) return; + Gui_MakeTitleFont(&font); + ButtonWidget_SetConst(&s->more, "More", &font); + ButtonWidget_SetConst(&s->send, "Send", &font); + ButtonWidget_SetConst(&s->cancel, "Cancel", &font); + Font_Free(&font); +#endif +} + +static void ChatInputScreen_Layout(void* screen) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + Widget_SetLocation(&s->input.base, ANCHOR_MIN, ANCHOR_MAX, 5, 5); + Widget_SetLocation(&s->altText, ANCHOR_MIN, ANCHOR_MAX, 5, 5); + ChatInputScreen_UpdateYOffsets(); + +#ifdef CC_BUILD_TOUCH + if (WindowInfo.SoftKeyboard == SOFT_KEYBOARD_SHIFT) { + Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MAX, 10, 60); + Widget_SetLocation(&s->cancel, ANCHOR_MAX, ANCHOR_MAX, 10, 10); + Widget_SetLocation(&s->more, ANCHOR_MAX, ANCHOR_MAX, 10, 110); + } else { + Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MIN, 10, 10); + Widget_SetLocation(&s->cancel, ANCHOR_MAX, ANCHOR_MIN, 10, 60); + Widget_SetLocation(&s->more, ANCHOR_MAX, ANCHOR_MIN, 10, 110); + } +#endif +} + +static int ChatInputScreen_KeyPress(void* screen, char keyChar) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + if (s->suppressNextPress) { + s->suppressNextPress = false; + return false; + } + + InputWidget_Append(&s->input.base, keyChar); + return true; +} + +static int ChatInputScreen_TextChanged(void* screen, const cc_string* str) { +#ifdef CC_BUILD_TOUCH + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + InputWidget_SetText(&s->input.base, str); +#endif + return true; +} + +static int ChatInputScreen_KeyDown(void* screen, int key) { + static const cc_string slash = String_FromConst("/"); + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + int playerListKey = KeyBinds[KEYBIND_TABLIST]; + cc_bool handlesList = playerListKey != KEY_TAB || !Gui.TabAutocomplete; + + if (key == playerListKey && handlesList) { + if (!TabListOverlay_Instance.active && !Server.IsSinglePlayer) { + TabListOverlay_Show(); + } + return true; + } + + s->suppressNextPress = false; + /* Handle chat text input */ +#ifdef CC_BUILD_WEB + /* See reason for this in HandleInputUp */ + if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == KEY_KP_ENTER) { + ChatInputScreen_EnterChatInput(s, false); +#else + if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == KEY_KP_ENTER || key == KEY_ESCAPE) { + ChatInputScreen_EnterInput(s, key == KEY_ESCAPE); +#endif + } else if (key == KEY_PAGEUP) { + ChatScreen_ScrollChatBy(-Gui.Chatlines); + } else if (key == KEY_PAGEDOWN) { + ChatScreen_ScrollChatBy(+Gui.Chatlines); + } else { + Elem_HandlesKeyDown(&s->input.base, key); + } + return key < KEY_F1 || key > KEY_F24; +} + +static void ChatInputScreen_KeyUp(void* screen, int key) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + if ((struct Screen*)s != Gui.InputGrab) return; + +#ifdef CC_BUILD_WEB + /* See reason for this in HandleInputUp */ + if (key == KEY_ESCAPE) ChatInputScreen_EnterChatInput(s, true); +#endif + + if (Server.SupportsFullCP437 && key == KeyBinds[KEYBIND_EXT_INPUT]) { + if (!WindowInfo.Focused) return; + + SpecialInputWidget_SetActive(&s->altText, !s->altText.active); + ChatInputScreen_UpdateYOffsets(); + } +} + +static int ChatInputScreen_MouseScroll(void* screen, float delta) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + int steps = Utils_AccumulateWheelDelta(&s->chatAcc, delta); + ChatScreen_ScrollChatBy(-steps); + return true; +} + +static int ChatInputScreen_PointerDown(void* screen, int id, int x, int y) { + cc_string text; char textBuffer[STRING_SIZE * 4]; + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + struct TextGroupWidget* chat = &ChatScreen_Instance.chat; + int height, chatY; + if (Game_HideGui) return false; + +#ifdef CC_BUILD_TOUCH + if (Input_TouchMode) { + if (Widget_Contains(&s->send, x, y)) { + ChatInputScreen_EnterChatInput(s, false); return TOUCH_TYPE_GUI; + } + if (Widget_Contains(&s->cancel, x, y)) { + ChatInputScreen_EnterChatInput(s, true); return TOUCH_TYPE_GUI; + } + if (Widget_Contains(&s->more, x, y)) { + ChatInputScreen_ToggleAltInput(s); return TOUCH_TYPE_GUI; + } + } +#endif + + if (!Widget_Contains(chat, x, y)) { + if (s->altText.active && Widget_Contains(&s->altText, x, y)) { + Elem_HandlesPointerDown(&s->altText, id, x, y); + ChatInputScreen_UpdateYOffsets(); + return TOUCH_TYPE_GUI; + } + Elem_HandlesPointerDown(&s->input.base, id, x, y); + return TOUCH_TYPE_GUI; + } + + height = TextGroupWidget_UsedHeight(chat); + chatY = chat->y + chat->height - height; + if (!Gui_Contains(chat->x, chatY, chat->width, height, x, y)) return false; + + String_InitArray(text, textBuffer); + TextGroupWidget_GetSelected(chat, &text, x, y); + if (!text.length) return false; + + if (Utils_IsUrlPrefix(&text)) { + UrlWarningOverlay_Show(&text); + } else if (Gui.ClickableChat) { + ChatInputScreen_Append(&text); + } + return TOUCH_TYPE_GUI; +} + +static void ChatInputScreen_Init(void* screen) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + ChatInputWidget_Create(&s->input); + s->input.base.OnTextChanged = ChatInputScreen_OnInputTextChanged; + SpecialInputWidget_Create(&s->altText, &ChatScreen_Instance.chatFont, &s->input.base); + + Event_Register_(&ChatEvents.ColCodeChanged, s, ChatInputScreen_ColorCodeChanged); + s->active = true; + + s->maxVertices = CHATINPUT_MAX_VERTICES; + s->widgets = chatinput_widgets; + s->numWidgets = Array_Elems(chatinput_widgets); + +#ifdef CC_BUILD_TOUCH + ButtonWidget_Init(&s->send, 100, NULL); + ButtonWidget_Init(&s->cancel, 100, NULL); + ButtonWidget_Init(&s->more, 100, NULL); +#endif +} + +static void ChatInputScreen_Update(void* screen, double delta) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + s->input.base.caretAccumulator += delta; + + if (s->altText.active && s->altText.pendingRedraw) { + SpecialInputWidget_Redraw(&s->altText); + s->dirty = true; + } +} + +static void ChatInputScreen_Render(void* screen, double delta) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + ChatInputWidget_RenderBackground(&s->input); + Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); + Gfx_BindDynamicVb(s->vb); + + Widget_Render2(&s->input.base); + if (Game_HideGui) return; + if (s->altText.active) Widget_Render2(&s->altText); + +#ifdef CC_BUILD_TOUCH + if (!Input_TouchMode) return; + Widget_Render2(&s->more); + Widget_Render2(&s->send); + Widget_Render2(&s->cancel); +#endif +} + +static void ChatInputScreen_Free(void* screen) { + struct ChatInputScreen* s = (struct ChatInputScreen*)screen; + Event_Unregister_(&ChatEvents.ColCodeChanged, s, ChatInputScreen_ColorCodeChanged); + s->active = false; +} + +static const struct ScreenVTABLE ChatInputScreen_VTABLE = { + ChatInputScreen_Init, ChatInputScreen_Update, ChatInputScreen_Free, + ChatInputScreen_Render, Screen_BuildMesh, + ChatInputScreen_KeyDown, ChatInputScreen_KeyUp, ChatInputScreen_KeyPress, ChatInputScreen_TextChanged, + ChatInputScreen_PointerDown, Screen_PointerUp, Screen_FPointer, ChatInputScreen_MouseScroll, + ChatInputScreen_Layout, ChatInputScreen_ContextLost, ChatInputScreen_ContextRecreated +}; +void ChatInputScreen_Open(const cc_string* text) { + struct ChatInputScreen* s = &ChatInputScreen; + struct OpenKeyboardArgs args; + s->VTABLE = &ChatInputScreen_VTABLE; + + OpenKeyboardArgs_Init(&args, text, KEYBOARD_TYPE_TEXT | KEYBOARD_FLAG_SEND); + args.placeholder = "Enter chat"; + args.multiline = true; + Window_OpenKeyboard(&args); + + s->suppressNextPress = true; + s->grabsInput = true; + Gui_Add((struct Screen*)s, GUI_PRIORITY_CHATINPUT); + + s->input.base.disabled = args.opaque; + String_Copy(&s->input.base.text, text); + InputWidget_UpdateText(&s->input.base); +} + +void ChatInputScreen_Append(const cc_string* text) { + struct ChatInputScreen* s = &ChatInputScreen; + InputWidget_AppendText(&s->input.base, text); } @@ -1571,7 +1680,7 @@ static int InventoryScreen_KeyDown(void* screen, int key) { Gui_Remove((struct Screen*)s); } else if (Elem_HandlesKeyDown(table, key)) { } else { - return Elem_HandlesKeyDown(&HUDScreen_Instance.hotbar, key); + return Elem_HandlesKeyDown(&HUDScreen.hotbar, key); } return true; } @@ -1593,7 +1702,7 @@ static int InventoryScreen_PointerDown(void* screen, int id, int x, int y) { cc_bool handled, hotbar; if (table->scroll.draggingId == id) return TOUCH_TYPE_GUI; - if (HUDscreen_PointerDown(Gui_HUD, id, x, y)) return TOUCH_TYPE_GUI; + if (HUDscreen_PointerDown(&HUDScreen, id, x, y)) return TOUCH_TYPE_GUI; handled = Elem_HandlesPointerDown(table, id, x, y); if (!handled || table->pendingClose) { diff --git a/src/Screens.h b/src/Screens.h index bb8fba7f7..ef0f3e8d1 100644 --- a/src/Screens.h +++ b/src/Screens.h @@ -35,9 +35,9 @@ void TouchScreen_Show(void); #endif /* Opens chat input for the HUD with the given initial text. */ -void ChatScreen_OpenInput(const cc_string* text); +void ChatInputScreen_Open(const cc_string* text); /* Appends text to the chat input in the HUD. */ -void ChatScreen_AppendInput(const cc_string* text); +void ChatInputScreen_Append(const cc_string* text); /* Sets number of visible lines in the main chat widget. */ void ChatScreen_SetChatlines(int lines); #endif diff --git a/src/Widgets.c b/src/Widgets.c index 0fc992aab..76029c803 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -125,42 +125,6 @@ static void ButtonWidget_Reposition(void* widget) { w->tex.Y = w->y + (w->height / 2 - w->tex.Height / 2); } -static void ButtonWidget_Render(void* widget, double delta) { - struct Texture back; - PackedCol color; - float scale; - struct ButtonWidget* w = (struct ButtonWidget*)widget; - - back = w->active ? btnSelectedTex : btnShadowTex; - if (w->disabled) back = btnDisabledTex; - - back.ID = Gui.ClassicTexture ? Gui.GuiClassicTex : Gui.GuiTex; - back.X = w->x; back.Width = w->width; - back.Y = w->y; back.Height = w->height; - - /* TODO: Does this 400 need to take DPI into account */ - if (w->width >= 400) { - /* Button can be drawn normally */ - Texture_Render(&back); - } else { - /* Split button down the middle */ - scale = (w->width / 400.0f) / (2 * DisplayInfo.ScaleX); - Gfx_BindTexture(back.ID); /* avoid bind twice */ - - back.Width = (w->width / 2); - back.uv.U1 = 0.0f; back.uv.U2 = BUTTON_uWIDTH * scale; - Gfx_Draw2DTexture(&back, w->color); - - back.X += (w->width / 2); - back.uv.U1 = BUTTON_uWIDTH * (1.0f - scale); back.uv.U2 = BUTTON_uWIDTH; - Gfx_Draw2DTexture(&back, w->color); - } - - if (!w->tex.ID) return; - color = w->disabled ? BTN_DISABLED_COLOR : (w->active ? BTN_ACTIVE_COLOR : BTN_NORMAL_COLOR); - Texture_RenderShaded(&w->tex, color); -} - static struct VertexTextured* ButtonWidget_BuildMesh(void* widget, struct VertexTextured* vertices, struct VertexTextured* beg) { struct Texture back; @@ -202,14 +166,13 @@ static void ButtonWidget_Render2(void* widget) { /* TODO: Does this 400 need to take DPI into account */ Gfx_DrawVb_IndexedTris_Range(w->width >= 400 ? 4 : 8, w->offset); - if (w->tex.ID) { - Gfx_BindTexture(w->tex.ID); - Gfx_DrawVb_IndexedTris_Range(4, w->offset + 8); - } + if (!w->tex.ID) return; + Gfx_BindTexture(w->tex.ID); + Gfx_DrawVb_IndexedTris_Range(4, w->offset + 8); } static const struct WidgetVTABLE ButtonWidget_VTABLE = { - ButtonWidget_Render, ButtonWidget_Free, ButtonWidget_Reposition, + NULL, ButtonWidget_Free, ButtonWidget_Reposition, Widget_InputDown, Widget_InputUp, Widget_MouseScroll, Widget_Pointer, Widget_PointerUp, Widget_PointerMove, ButtonWidget_BuildMesh, ButtonWidget_Render2 @@ -997,7 +960,7 @@ static void InputWidget_CalculateLineSizes(struct InputWidget* w) { } } -static char InputWidget_GetLastCol(struct InputWidget* w, int x, int y) { +static char InputWidget_GetLastColor(struct InputWidget* w, int x, int y) { cc_string line; char lineBuffer[STRING_SIZE]; char col; String_InitArray(line, lineBuffer); @@ -1055,7 +1018,7 @@ static void InputWidget_UpdateCaret(struct InputWidget* w) { w->caretTex.X = w->x + w->padding + lineWidth; w->caretTex.Y = (w->inputTex.Y + w->caretOffset) + w->caretY * w->lineHeight; - colCode = InputWidget_GetLastCol(w, w->caretX, w->caretY); + colCode = InputWidget_GetLastColor(w, w->caretX, w->caretY); if (colCode) { col = Drawer2D_GetColor(colCode); @@ -1067,15 +1030,6 @@ static void InputWidget_UpdateCaret(struct InputWidget* w) { } } -static void InputWidget_RenderCaret(struct InputWidget* w, double delta) { - float second; - if (!w->showCaret) return; - w->caretAccumulator += delta; - - second = Math_Mod1((float)w->caretAccumulator); - if (second < 0.5f) Texture_RenderShaded(&w->caretTex, w->caretCol); -} - static void InputWidget_OnPressedEnter(void* widget) { struct InputWidget* w = (struct InputWidget*)widget; InputWidget_Clear(w); @@ -1470,12 +1424,6 @@ const struct MenuInputVTABLE StringInput_VTABLE = { /*########################################################################################################################* *-----------------------------------------------------TextInputWidget-----------------------------------------------------* *#########################################################################################################################*/ -static void TextInputWidget_Render(void* widget, double delta) { - struct InputWidget* w = (struct InputWidget*)widget; - Texture_Render(&w->inputTex); - InputWidget_RenderCaret(w, delta); -} - static struct VertexTextured* TextInputWidget_BuildMesh(void* widget, struct VertexTextured* vertices, struct VertexTextured* beg) { struct InputWidget* w = (struct InputWidget*)widget; @@ -1581,7 +1529,7 @@ static int TextInputWidget_PointerDown(void* widget, int id, int x, int y) { static int TextInputWidget_GetMaxLines(void) { return 1; } static const struct WidgetVTABLE TextInputWidget_VTABLE = { - TextInputWidget_Render, InputWidget_Free, InputWidget_Reposition, + NULL, InputWidget_Free, InputWidget_Reposition, InputWidget_KeyDown, Widget_InputUp, Widget_MouseScroll, TextInputWidget_PointerDown, Widget_PointerUp, Widget_PointerMove, TextInputWidget_BuildMesh, TextInputWidget_Render2 @@ -1621,6 +1569,28 @@ void TextInputWidget_SetFont(struct TextInputWidget* w, struct FontDesc* font) { *#########################################################################################################################*/ static const cc_string chatInputPrefix = String_FromConst("> "); +static struct VertexTextured* ChatInputWidget_BuildMesh(void* widget, + struct VertexTextured* vertices, struct VertexTextured* beg) { + struct InputWidget* w = (struct InputWidget*)widget; + w->offset = Widget_CalcVertexOffset(vertices, beg); + + Gfx_Make2DQuad(&w->inputTex, PACKEDCOL_WHITE, vertices + 0); + Gfx_Make2DQuad(&w->caretTex, w->caretCol, vertices + 4); + return vertices + 8; +} + +static void ChatInputWidget_Render2(void* widget) { + struct InputWidget* w = (struct InputWidget*)widget; + Gfx_BindTexture(w->inputTex.ID); + Gfx_DrawVb_IndexedTris_Range(4, w->offset); + + if (w->showCaret && Math_Mod1((float)w->caretAccumulator) < 0.5f) { + Gfx_BindTexture(w->caretTex.ID); + Gfx_DrawVb_IndexedTris_Range(4, w->offset + 4); + } +} + + static void ChatInputWidget_MakeTexture(struct InputWidget* w, int width, int height) { cc_string line; char lineBuffer[STRING_SIZE + 2]; struct DrawTextArgs args; @@ -1639,7 +1609,7 @@ static void ChatInputWidget_MakeTexture(struct InputWidget* w, int width, int he line.length = 0; /* Color code continues in next line */ - lastCol = InputWidget_GetLastCol(w, 0, i); + lastCol = InputWidget_GetLastColor(w, 0, i); if (!Drawer2D_IsWhiteColor(lastCol)) { String_Append(&line, '&'); String_Append(&line, lastCol); } @@ -1684,7 +1654,7 @@ static void ChatInputWidget_RemakeTexture(void* widget) { w->inputTex.Y = w->y; } -static void ChatInputWidget_Render(void* widget, double delta) { +void ChatInputWidget_RenderBackground(void* widget) { struct InputWidget* w = (struct InputWidget*)widget; PackedCol backColor = PackedCol_Make(0, 0, 0, 127); int x = w->x, y = w->y; @@ -1703,9 +1673,6 @@ static void ChatInputWidget_Render(void* widget, double delta) { Gfx_Draw2DFlat(x, y, width + w->padding * 2, w->lineHeight, backColor); y += w->lineHeight; } - - Texture_Render(&w->inputTex); - InputWidget_RenderCaret(w, delta); } static void ChatInputWidget_OnPressedEnter(void* widget) { @@ -1856,9 +1823,10 @@ static int ChatInputWidget_GetMaxLines(void) { } static const struct WidgetVTABLE ChatInputWidget_VTABLE = { - ChatInputWidget_Render, InputWidget_Free, InputWidget_Reposition, - ChatInputWidget_KeyDown, Widget_InputUp, Widget_MouseScroll, - InputWidget_PointerDown, Widget_PointerUp, Widget_PointerMove + NULL, InputWidget_Free, InputWidget_Reposition, + ChatInputWidget_KeyDown, Widget_InputUp, Widget_MouseScroll, + InputWidget_PointerDown, Widget_PointerUp, Widget_PointerMove, + ChatInputWidget_BuildMesh, ChatInputWidget_Render2 }; void ChatInputWidget_Create(struct ChatInputWidget* w) { InputWidget_Reset(&w->base); @@ -2531,14 +2499,28 @@ static int SpecialInputWidget_PointerDown(void* widget, int id, int x, int y) { return TOUCH_TYPE_GUI; } +static struct VertexTextured* SpecialInputWidget_BuildMesh(void* widget, + struct VertexTextured* vertices, struct VertexTextured* beg) { + struct SpecialInputWidget* w = (struct SpecialInputWidget*)widget; + w->offset = Widget_CalcVertexOffset(vertices, beg); + + Gfx_Make2DQuad(&w->tex, PACKEDCOL_WHITE, vertices); + return vertices + 8; +} + +static void SpecialInputWidget_Render2(void* widget) { + struct SpecialInputWidget* w = (struct SpecialInputWidget*)widget; + Gfx_BindTexture(w->tex.ID); + Gfx_DrawVb_IndexedTris_Range(4, w->offset); +} + void SpecialInputWidget_UpdateCols(struct SpecialInputWidget* w) { SpecialInputWidget_UpdateColString(w); w->tabs[0].contents = w->colString; if (w->selectedIndex != 0) return; - /* defer updating colours tab until visible */ - if (!w->active) { w->pendingRedraw = true; return; } - SpecialInputWidget_Redraw(w); + /* Currently displaying colours tab */ + if (w->active) w->pendingRedraw = true; } void SpecialInputWidget_SetActive(struct SpecialInputWidget* w, cc_bool active) { @@ -2548,9 +2530,10 @@ void SpecialInputWidget_SetActive(struct SpecialInputWidget* w, cc_bool active) } static const struct WidgetVTABLE SpecialInputWidget_VTABLE = { - SpecialInputWidget_Render, SpecialInputWidget_Free, SpecialInputWidget_Reposition, + NULL, SpecialInputWidget_Free, SpecialInputWidget_Reposition, Widget_InputDown, Widget_InputUp, Widget_MouseScroll, - SpecialInputWidget_PointerDown, Widget_PointerUp, Widget_PointerMove + SpecialInputWidget_PointerDown, Widget_PointerUp, Widget_PointerMove, + SpecialInputWidget_BuildMesh, SpecialInputWidget_Render2 }; void SpecialInputWidget_Create(struct SpecialInputWidget* w, struct FontDesc* font, struct InputWidget* target) { Widget_Reset(w); diff --git a/src/Widgets.h b/src/Widgets.h index db0e12d33..d0ce629da 100644 --- a/src/Widgets.h +++ b/src/Widgets.h @@ -221,6 +221,7 @@ struct ChatInputWidget { char _origBuffer[INPUTWIDGET_MAX_LINES * INPUTWIDGET_LEN]; }; +CC_NOINLINE void ChatInputWidget_RenderBackground(void* widget); CC_NOINLINE void ChatInputWidget_Create(struct ChatInputWidget* w); CC_NOINLINE void ChatInputWidget_SetFont(struct ChatInputWidget* w, struct FontDesc* font);