From f89baa5d8fdc295d6bc56c78087b92368d8c44da Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 7 Apr 2022 21:34:08 +1000 Subject: [PATCH] Launcher: Cleanup and more modular input widget, hovering --- src/LBackend.c | 134 +++++++++++++++++++++++++++++++++++++++-- src/LBackend.h | 8 ++- src/LScreens.c | 149 +++++++++++++++++++++++----------------------- src/LScreens.h | 3 - src/LWidgets.c | 138 +++++------------------------------------- src/LWidgets.h | 5 +- src/interop_ios.m | 10 +++- 7 files changed, 233 insertions(+), 214 deletions(-) diff --git a/src/LBackend.c b/src/LBackend.c index 6d3270777..9ccde07e5 100644 --- a/src/LBackend.c +++ b/src/LBackend.c @@ -30,6 +30,7 @@ static int xBorder, xBorder2, xBorder3, xBorder4; static int yBorder, yBorder2, yBorder3, yBorder4; static int xInputOffset, yInputOffset, inputExpand; +static int caretOffset, caretWidth, caretHeight; void LBackend_Init(void) { xBorder = Display_ScaleX(1); xBorder2 = xBorder * 2; xBorder3 = xBorder * 3; xBorder4 = xBorder * 4; @@ -38,6 +39,10 @@ void LBackend_Init(void) { xInputOffset = Display_ScaleX(5); yInputOffset = Display_ScaleY(2); inputExpand = Display_ScaleX(20); + + caretOffset = Display_ScaleY(5); + caretWidth = Display_ScaleX(10); + caretHeight = Display_ScaleY(2); } static void DrawBoxBounds(BitmapCol col, int x, int y, int width, int height) { @@ -275,16 +280,24 @@ static void LInput_UpdateDimensions(struct LInput* w, const cc_string* text) { w->_textHeight = Drawer2D_TextHeight(&args); } -void LBackend_UpdateInput(struct LInput* w, const cc_string* text) { - LInput_UpdateDimensions(w, text); +void LBackend_UpdateInput(struct LInput* w) { + cc_string text; char textBuffer[STRING_SIZE]; + String_InitArray(text, textBuffer); + + LInput_UNSAFE_GetText(w, &text); + LInput_UpdateDimensions(w, &text); } -void LBackend_DrawInput(struct LInput* w, const cc_string* text) { +void LBackend_DrawInput(struct LInput* w) { + cc_string text; char textBuffer[STRING_SIZE]; struct DrawTextArgs args; - DrawTextArgs_Make(&args, text, &Launcher_TextFont, false); + + String_InitArray(text, textBuffer); + LInput_UNSAFE_GetText(w, &text); + DrawTextArgs_Make(&args, &text, &Launcher_TextFont, false); /* TODO shouldn't be recalcing size in draw.... */ - LInput_UpdateDimensions(w, text); + LInput_UpdateDimensions(w, &text); LInput_DrawOuterBorder(w); LInput_DrawInnerBorder(w); Drawer2D_Clear(&Launcher_Framebuffer, BITMAPCOL_WHITE, @@ -298,6 +311,117 @@ void LBackend_DrawInput(struct LInput* w, const cc_string* text) { } +static TimeMS caretStart; +static cc_bool lastCaretShow; +static Rect2D lastCaretRec; +#define Rect2D_Equals(a, b) a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height + +static Rect2D LInput_MeasureCaret(struct LInput* w) { + cc_string text; char textBuffer[STRING_SIZE]; + struct DrawTextArgs args; + Rect2D r; + + String_InitArray(text, textBuffer); + LInput_UNSAFE_GetText(w, &text); + DrawTextArgs_Make(&args, &text, &Launcher_TextFont, true); + + r.X = w->x + xInputOffset; + r.Y = w->y + w->height - caretOffset; r.Height = caretHeight; + + if (w->caretPos == -1) { + r.X += Drawer2D_TextWidth(&args); + r.Width = caretWidth; + } else { + args.text = String_UNSAFE_Substring(&text, 0, w->caretPos); + r.X += Drawer2D_TextWidth(&args); + + args.text = String_UNSAFE_Substring(&text, w->caretPos, 1); + r.Width = Drawer2D_TextWidth(&args); + } + return r; +} + +static void LInput_MoveCaretToCursor(struct LInput* w, int idx) { + cc_string text; char textBuffer[STRING_SIZE]; + int x = Pointers[idx].x, y = Pointers[idx].y; + struct DrawTextArgs args; + int i, charX, charWidth; + + /* Input widget may have been selected by pressing tab */ + /* In which case cursor is completely outside, so ignore */ + if (!Gui_Contains(w->x, w->y, w->width, w->height, x, y)) return; + lastCaretShow = false; + + String_InitArray(text, textBuffer); + LInput_UNSAFE_GetText(w, &text); + x -= w->x; y -= w->y; + + DrawTextArgs_Make(&args, &text, &Launcher_TextFont, true); + if (x >= Drawer2D_TextWidth(&args)) { + w->caretPos = -1; return; + } + + for (i = 0; i < text.length; i++) { + args.text = String_UNSAFE_Substring(&text, 0, i); + charX = Drawer2D_TextWidth(&args); + + args.text = String_UNSAFE_Substring(&text, i, 1); + charWidth = Drawer2D_TextWidth(&args); + if (x >= charX && x < charX + charWidth) { + w->caretPos = i; return; + } + } +} + +void LBackend_TickInput(struct LInput* w) { + int elapsed; + cc_bool caretShow; + Rect2D r; + + if (!caretStart) return; + elapsed = (int)(DateTime_CurrentUTC_MS() - caretStart); + + caretShow = (elapsed % 1000) < 500; + if (caretShow == lastCaretShow) return; + lastCaretShow = caretShow; + + LBackend_DrawInput(w); + r = LInput_MeasureCaret(w); + + if (caretShow) { + Drawer2D_Clear(&Launcher_Framebuffer, BITMAPCOL_BLACK, + r.X, r.Y, r.Width, r.Height); + } + + if (Rect2D_Equals(r, lastCaretRec)) { + /* Fast path, caret is blinking in same spot */ + Launcher_MarkDirty(r.X, r.Y, r.Width, r.Height); + } else { + Launcher_MarkDirty(w->x, w->y, w->width, w->height); + } + lastCaretRec = r; +} + +void LBackend_SelectInput(struct LInput* w, int idx, cc_bool wasSelected) { + struct OpenKeyboardArgs args; + caretStart = DateTime_CurrentUTC_MS(); + LInput_MoveCaretToCursor(w, idx); + /* TODO: Only draw outer border */ + if (wasSelected) return; + + LWidget_Draw(w); + OpenKeyboardArgs_Init(&args, &w->text, w->type); + Window_OpenKeyboard(&args); +} + +void LBackend_UnselectInput(struct LInput* w) { + caretStart = 0; + /* TODO: Only draw outer border */ + LWidget_Draw(w); + Window_CloseKeyboard(); +} + + /*########################################################################################################################* *------------------------------------------------------LabelWidget--------------------------------------------------------* *#########################################################################################################################*/ diff --git a/src/LBackend.h b/src/LBackend.h index db8a2df38..4c373a650 100644 --- a/src/LBackend.h +++ b/src/LBackend.h @@ -27,8 +27,12 @@ void LBackend_InitCheckbox(struct LCheckbox* w); void LBackend_DrawCheckbox(struct LCheckbox* w); void LBackend_InitInput(struct LInput* w, int width); -void LBackend_UpdateInput(struct LInput* w, const cc_string* text); -void LBackend_DrawInput(struct LInput* w, const cc_string* text); +void LBackend_UpdateInput(struct LInput* w); +void LBackend_DrawInput(struct LInput* w); + +void LBackend_TickInput(struct LInput* w); +void LBackend_SelectInput(struct LInput* w, int idx, cc_bool wasSelected); +void LBackend_UnselectInput(struct LInput* w); void LBackend_InitLabel(struct LLabel* w); void LBackend_UpdateLabel(struct LLabel* w); diff --git a/src/LScreens.c b/src/LScreens.c index 81effeeb3..6843bea8c 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -54,9 +54,6 @@ static void LScreen_Tick(struct LScreen* s) { if (w && w->VTABLE->Tick) w->VTABLE->Tick(w); } -static void LScreen_HoverWidget(struct LScreen* s, struct LWidget* w) { } -static void LScreen_UnhoverWidget(struct LScreen* s, struct LWidget* w) { } - CC_NOINLINE static void LScreen_SelectWidget(struct LScreen* s, int idx, struct LWidget* w, cc_bool was) { if (!w) return; w->selected = true; @@ -101,11 +98,11 @@ static void LScreen_KeyDown(struct LScreen* s, int key, cc_bool was) { if (was) return; if (s->selectedWidget && s->selectedWidget->OnClick) { - s->selectedWidget->OnClick(s->selectedWidget, 0); + s->selectedWidget->OnClick(s->selectedWidget); } else if (s->hoveredWidget && s->hoveredWidget->OnClick) { - s->hoveredWidget->OnClick(s->hoveredWidget, 0); + s->hoveredWidget->OnClick(s->hoveredWidget); } else if (s->onEnterWidget) { - s->onEnterWidget->OnClick(s->onEnterWidget, 0); + s->onEnterWidget->OnClick(s->onEnterWidget); } } else if (s->selectedWidget) { if (!s->selectedWidget->VTABLE->KeyDown) return; @@ -141,7 +138,7 @@ static void LScreen_MouseUp(struct LScreen* s, int idx) { if (over != prev) { LScreen_UnselectWidget(s, idx, prev); } else if (over && over->OnClick) { - over->OnClick(over, idx); + over->OnClick(over); } } @@ -153,16 +150,16 @@ static void LScreen_MouseMove(struct LScreen* s, int idx) { if (prev && !overSame) { prev->hovered = false; s->hoveredWidget = NULL; - s->UnhoverWidget(s, prev); + if (prev->OnUnhover) prev->OnUnhover(prev); if (prev->VTABLE->MouseLeft) prev->VTABLE->MouseLeft(prev); } if (over) { over->hovered = true; s->hoveredWidget = over; - s->HoverWidget(s, over); + if (over->OnHover) over->OnHover(over); if (!over->VTABLE->MouseMove) return; over->VTABLE->MouseMove(over, idx, overSame); } @@ -205,8 +202,6 @@ CC_NOINLINE static void LScreen_Reset(struct LScreen* s) { s->MouseUp = LScreen_MouseUp; s->MouseMove = LScreen_MouseMove; s->MouseWheel = LScreen_MouseWheel; - s->HoverWidget = LScreen_HoverWidget; - s->UnhoverWidget = LScreen_UnhoverWidget; s->TextChanged = LScreen_TextChanged; s->DrawBackground = LScreen_DrawBackground; @@ -221,13 +216,13 @@ CC_NOINLINE static void LScreen_Reset(struct LScreen* s) { s->selectedWidget = NULL; } -static void SwitchToChooseMode(void* w, int idx) { ChooseModeScreen_SetActive(false); } -static void SwitchToColours(void* w, int idx) { ColoursScreen_SetActive(); } -static void SwitchToDirectConnect(void* w, int idx) { DirectConnectScreen_SetActive(); } -static void SwitchToMain(void* w, int idx) { MainScreen_SetActive(); } -static void SwitchToSettings(void* w, int idx) { SettingsScreen_SetActive(); } -static void SwitchToThemes(void* w, int idx) { ThemesScreen_SetActive(); } -static void SwitchToUpdates(void* w, int idx) { UpdatesScreen_SetActive(); } +static void SwitchToChooseMode(void* w) { ChooseModeScreen_SetActive(false); } +static void SwitchToColours(void* w) { ColoursScreen_SetActive(); } +static void SwitchToDirectConnect(void* w) { DirectConnectScreen_SetActive(); } +static void SwitchToMain(void* w) { MainScreen_SetActive(); } +static void SwitchToSettings(void* w) { SettingsScreen_SetActive(); } +static void SwitchToThemes(void* w) { ThemesScreen_SetActive(); } +static void SwitchToUpdates(void* w) { UpdatesScreen_SetActive(); } /*########################################################################################################################* @@ -265,9 +260,9 @@ CC_NOINLINE static void ChooseMode_Click(cc_bool classic, cc_bool classicHacks) MainScreen_SetActive(); } -static void UseModeEnhanced(void* w, int idx) { ChooseMode_Click(false, false); } -static void UseModeClassicHax(void* w, int idx) { ChooseMode_Click(true, true); } -static void UseModeClassic(void* w, int idx) { ChooseMode_Click(true, false); } +static void UseModeEnhanced(void* w) { ChooseMode_Click(false, false); } +static void UseModeClassicHax(void* w) { ChooseMode_Click(true, true); } +static void UseModeClassic(void* w) { ChooseMode_Click(true, false); } static void ChooseModeScreen_Init(struct LScreen* s_) { struct ChooseModeScreen* s = (struct ChooseModeScreen*)s_; @@ -455,7 +450,7 @@ static void ColoursScreen_KeyDown(struct LScreen* s, int key, cc_bool was) { } } -static void ColoursScreen_ToggleBG(void* w, int idx) { +static void ColoursScreen_ToggleBG(void* w) { struct LCheckbox* cb = (struct LCheckbox*)w; Launcher_Theme.ClassicBackground = !Launcher_Theme.ClassicBackground; cb->value = Launcher_Theme.ClassicBackground; @@ -596,7 +591,7 @@ static void DirectConnectScreen_Load(struct DirectConnectScreen* s) { LInput_SetText(&s->iptMppass, &mppass); } -static void DirectConnectScreen_StartClient(void* w, int idx) { +static void DirectConnectScreen_StartClient(void* w) { static const cc_string defMppass = String_FromConst("(none)"); static const cc_string defPort = String_FromConst("25565"); const cc_string* user = &DirectConnectScreen.iptUsername.text; @@ -703,11 +698,11 @@ static struct LWidget* mfa_widgets[] = { }; static void MainScreen_DoLogin(void); -static void MFAScreen_SignIn(void* w, int idx) { +static void MFAScreen_SignIn(void* w) { MainScreen_SetActive(); MainScreen_DoLogin(); } -static void MFAScreen_Cancel(void* w, int idx) { +static void MFAScreen_Cancel(void* w) { MFAScreen.iptCode.text.length = 0; MainScreen_SetActive(); } @@ -836,15 +831,15 @@ static void MainScreen_DoLogin(void) { LWidget_Redraw(&s->lblStatus); s->signingIn = true; } -static void MainScreen_Login(void* w, int idx) { MainScreen_DoLogin(); } +static void MainScreen_Login(void* w) { MainScreen_DoLogin(); } -static void MainScreen_Register(void* w, int idx) { +static void MainScreen_Register(void* w) { static const cc_string regUrl = String_FromConst(REGISTERNEW_URL); cc_result res = Process_StartOpen(®Url); if (res) Logger_SimpleWarn(res, "opening register webpage in browser"); } -static void MainScreen_Resume(void* w, int idx) { +static void MainScreen_Resume(void* w) { struct ResumeInfo info; MainScreen_GetResume(&info, true); @@ -852,7 +847,7 @@ static void MainScreen_Resume(void* w, int idx) { Launcher_StartGame(&info.user, &info.mppass, &info.ip, &info.port, &info.server); } -static void MainScreen_Singleplayer(void* w, int idx) { +static void MainScreen_Singleplayer(void* w) { static const cc_string defUser = String_FromConst("Singleplayer"); const cc_string* user = &MainScreen.iptUsername.text; @@ -860,6 +855,36 @@ static void MainScreen_Singleplayer(void* w, int idx) { Launcher_StartGame(user, &String_Empty, &String_Empty, &String_Empty, &String_Empty); } +static void MainScreen_ResumeHover(void* w) { + cc_string str; char strBuffer[STRING_SIZE]; + struct MainScreen* s = &MainScreen; + struct ResumeInfo info; + if (s->signingIn) return; + + MainScreen_GetResume(&info, false); + if (!info.user.length) return; + String_InitArray(str, strBuffer); + + if (info.server.length && String_Equals(&info.user, &s->iptUsername.text)) { + String_Format1(&str, "&eResume to %s", &info.server); + } else if (info.server.length) { + String_Format2(&str, "&eResume as %s to %s", &info.user, &info.server); + } else { + String_Format3(&str, "&eResume as %s to %s:%s", &info.user, &info.ip, &info.port); + } + + LLabel_SetText(&s->lblStatus, &str); + LWidget_Redraw(&s->lblStatus); +} + +static void MainScreen_ResumeUnhover(void* w) { + struct MainScreen* s = &MainScreen; + if (s->signingIn) return; + + LLabel_SetConst(&s->lblStatus, ""); + LWidget_Redraw(&s->lblStatus); +} + static void MainScreen_Init(struct LScreen* s_) { cc_string user, pass; char passBuffer[STRING_SIZE]; struct MainScreen* s = (struct MainScreen*)s_; @@ -887,6 +912,10 @@ static void MainScreen_Init(struct LScreen* s_) { s->btnOptions.OnClick = SwitchToSettings; s->btnRegister.OnClick = MainScreen_Register; + + s->btnResume.OnHover = MainScreen_ResumeHover; + s->btnResume.OnUnhover = MainScreen_ResumeUnhover; + /* need to set text here for right size */ s->lblUpdate.font = &Launcher_HintFont; LLabel_SetConst(&s->lblUpdate, "&eChecking.."); @@ -927,36 +956,6 @@ static void MainScreen_Layout(struct LScreen* s_) { LWidget_SetLocation(&s->btnRegister, ANCHOR_MIN, ANCHOR_MAX, 6, 6); } -static void MainScreen_HoverWidget(struct LScreen* s_, struct LWidget* w) { - cc_string str; char strBuffer[STRING_SIZE]; - struct MainScreen* s = (struct MainScreen*)s_; - struct ResumeInfo info; - if (s->signingIn || w != (struct LWidget*)&s->btnResume) return; - - MainScreen_GetResume(&info, false); - if (!info.user.length) return; - String_InitArray(str, strBuffer); - - if (info.server.length && String_Equals(&info.user, &s->iptUsername.text)) { - String_Format1(&str, "&eResume to %s", &info.server); - } else if (info.server.length) { - String_Format2(&str, "&eResume as %s to %s", &info.user, &info.server); - } else { - String_Format3(&str, "&eResume as %s to %s:%s", &info.user, &info.ip, &info.port); - } - - LLabel_SetText(&s->lblStatus, &str); - LWidget_Redraw(&s->lblStatus); -} - -static void MainScreen_UnhoverWidget(struct LScreen* s_, struct LWidget* w) { - struct MainScreen* s = (struct MainScreen*)s_; - if (s->signingIn || w != (struct LWidget*)&s->btnResume) return; - - LLabel_SetConst(&s->lblStatus, ""); - LWidget_Redraw(&s->lblStatus); -} - CC_NOINLINE static cc_uint32 MainScreen_GetVersion(const cc_string* version) { cc_uint8 raw[4] = { 0, 0, 0, 0 }; cc_string parts[4]; @@ -1076,8 +1075,6 @@ void MainScreen_SetActive(void) { s->title_fore = "&fClassiCube"; s->title_back = "&0ClassiCube"; - s->HoverWidget = MainScreen_HoverWidget; - s->UnhoverWidget = MainScreen_UnhoverWidget; s->onEnterWidget = (struct LWidget*)&s->btnLogin; Launcher_SetScreen((struct LScreen*)s); } @@ -1098,8 +1095,8 @@ static struct LWidget* checkResources_widgets[] = { (struct LWidget*)&CheckResourcesScreen.btnNo }; -static void CheckResourcesScreen_Yes(void* w, int idx) { FetchResourcesScreen_SetActive(); } -static void CheckResourcesScreen_Next(void* w, int idx) { +static void CheckResourcesScreen_Yes(void* w) { FetchResourcesScreen_SetActive(); } +static void CheckResourcesScreen_Next(void* w) { Http_ClearPending(); if (Options_LoadResult != ReturnCode_FileNotFound) { MainScreen_SetActive(); @@ -1268,7 +1265,7 @@ static void FetchResourcesScreen_Tick(struct LScreen* s_) { if (Fetcher_Failed) { FetchResourcesScreen_Error(s); return; } Launcher_TryLoadTexturePack(); - CheckResourcesScreen_Next(NULL, 0); + CheckResourcesScreen_Next(NULL); } void FetchResourcesScreen_SetActive(void) { @@ -1301,7 +1298,7 @@ static struct LWidget* servers_widgets[] = { (struct LWidget*)&ServersScreen.btnRefresh, (struct LWidget*)&ServersScreen.table }; -static void ServersScreen_Connect(void* w, int idx) { +static void ServersScreen_Connect(void* w) { struct LTable* table = &ServersScreen.table; cc_string* hash = &ServersScreen.iptHash.text; @@ -1311,7 +1308,7 @@ static void ServersScreen_Connect(void* w, int idx) { Launcher_ConnectToServer(hash); } -static void ServersScreen_Refresh(void* w, int idx) { +static void ServersScreen_Refresh(void* w) { struct LButton* btn; if (FetchServersTask.Base.working) return; @@ -1516,7 +1513,7 @@ static struct LWidget* settings_classic[] = { }; #if defined CC_BUILD_MOBILE -static void SettingsScreen_LockOrientation(void* w, int idx) { +static void SettingsScreen_LockOrientation(void* w) { struct LCheckbox* cb = (struct LCheckbox*)w; cb->value = !cb->value; Options_SetBool(OPT_LANDSCAPE_MODE, cb->value); @@ -1524,14 +1521,14 @@ static void SettingsScreen_LockOrientation(void* w, int idx) { Launcher_Redraw(); } #else -static void SettingsScreen_AutoClose(void* w, int idx) { +static void SettingsScreen_AutoClose(void* w) { struct LCheckbox* cb = (struct LCheckbox*)w; cb->value = !cb->value; Options_SetBool(LOPT_AUTO_CLOSE, cb->value); LWidget_Redraw(cb); } #endif -static void SettingsScreen_ShowEmpty(void* w, int idx) { +static void SettingsScreen_ShowEmpty(void* w) { struct LCheckbox* cb = (struct LCheckbox*)w; cb->value = !cb->value; Launcher_ShowEmptyServers = cb->value; @@ -1642,13 +1639,13 @@ static void ThemesScreen_Set(const struct LauncherTheme* theme) { Launcher_Redraw(); } -static void ThemesScreen_Modern(void* w, int idx) { +static void ThemesScreen_Modern(void* w) { ThemesScreen_Set(&Launcher_ModernTheme); } -static void ThemesScreen_Classic(void* w, int idx) { +static void ThemesScreen_Classic(void* w) { ThemesScreen_Set(&Launcher_ClassicTheme); } -static void ThemesScreen_Nordic(void* w, int idx) { +static void ThemesScreen_Nordic(void* w) { ThemesScreen_Set(&Launcher_NordicTheme); } @@ -1843,10 +1840,10 @@ static void UpdatesScreen_FetchTick(struct UpdatesScreen* s) { } } -static void UpdatesScreen_Rel_0(void* w, int idx) { UpdatesScreen_Get(true, 0); } -static void UpdatesScreen_Rel_1(void* w, int idx) { UpdatesScreen_Get(true, 1); } -static void UpdatesScreen_Dev_0(void* w, int idx) { UpdatesScreen_Get(false, 0); } -static void UpdatesScreen_Dev_1(void* w, int idx) { UpdatesScreen_Get(false, 1); } +static void UpdatesScreen_Rel_0(void* w) { UpdatesScreen_Get(true, 0); } +static void UpdatesScreen_Rel_1(void* w) { UpdatesScreen_Get(true, 1); } +static void UpdatesScreen_Dev_0(void* w) { UpdatesScreen_Get(false, 0); } +static void UpdatesScreen_Dev_1(void* w) { UpdatesScreen_Get(false, 1); } static void UpdatesScreen_Init(struct LScreen* s_) { struct UpdatesScreen* s = (struct UpdatesScreen*)s_; diff --git a/src/LScreens.h b/src/LScreens.h index 4cfe59c46..c4b1982ad 100644 --- a/src/LScreens.h +++ b/src/LScreens.h @@ -9,7 +9,6 @@ struct LWidget; struct LScreen; typedef void (*LScreen_Func)(struct LScreen* s); -typedef void (*LWidget_Func)(struct LScreen* s, struct LWidget* w); #define LScreen_Layout \ LScreen_Func Init; /* Initialises widgets and other data. Only called once. */ \ @@ -26,8 +25,6 @@ typedef void (*LWidget_Func)(struct LScreen* s, struct LWidget* w); void (*MouseMove)(struct LScreen* s, int idx); \ void (*MouseWheel)(struct LScreen* s, float delta); \ void (*TextChanged)(struct LScreen* s, const cc_string* str); \ - LWidget_Func HoverWidget; /* Called when mouse is moved over a given widget. */ \ - LWidget_Func UnhoverWidget; /* Called when the mouse is moved away from a previously hovered widget. */ \ struct LWidget* onEnterWidget; /* Default widget to auto-click when Enter is pressed. Can be NULL. */ \ struct LWidget* hoveredWidget; /* Widget the mouse is currently hovering over. */ \ struct LWidget* selectedWidget; /* Widget mouse last clicked on. */ \ diff --git a/src/LWidgets.c b/src/LWidgets.c index 410a2edd9..432189348 100644 --- a/src/LWidgets.c +++ b/src/LWidgets.c @@ -15,7 +15,6 @@ #include "LBackend.h" static int xInputOffset; -static int caretOffset, caretWidth, caretHeight; static int scrollbarWidth, dragPad, gridlineWidth, gridlineHeight; static int hdrYOffset, hdrYPadding, rowYOffset, rowYPadding; static int cellXOffset, cellXPadding, cellMinWidth; @@ -29,10 +28,6 @@ void LWidget_CalcOffsets(void) { xInputOffset = Display_ScaleX(5); - caretOffset = Display_ScaleY(5); - caretWidth = Display_ScaleX(10); - caretHeight = Display_ScaleY(2); - scrollbarWidth = Display_ScaleX(10); dragPad = Display_ScaleX(8); gridlineWidth = Display_ScaleX(2); @@ -207,7 +202,7 @@ void LCheckbox_Init(struct LCheckbox* w, const char* text) { /*########################################################################################################################* *------------------------------------------------------InputWidget--------------------------------------------------------* *#########################################################################################################################*/ -CC_NOINLINE static void LInput_GetText(struct LInput* w, cc_string* text) { +void LInput_UNSAFE_GetText(struct LInput* w, cc_string* text) { int i; if (w->type != KEYBOARD_TYPE_PASSWORD) { *text = w->text; return; } @@ -218,71 +213,22 @@ CC_NOINLINE static void LInput_GetText(struct LInput* w, cc_string* text) { static void LInput_Draw(void* widget) { struct LInput* w = (struct LInput*)widget; - cc_string text; char textBuffer[STRING_SIZE]; - - String_InitArray(text, textBuffer); - LInput_GetText(w, &text); - LBackend_DrawInput(w, &text); + LBackend_DrawInput(w); } -static Rect2D LInput_MeasureCaret(struct LInput* w) { - cc_string text; char textBuffer[STRING_SIZE]; - struct DrawTextArgs args; - Rect2D r; - - String_InitArray(text, textBuffer); - LInput_GetText(w, &text); - DrawTextArgs_Make(&args, &text, &Launcher_TextFont, true); - - r.X = w->x + xInputOffset; - r.Y = w->y + w->height - caretOffset; r.Height = caretHeight; - - if (w->caretPos == -1) { - r.X += Drawer2D_TextWidth(&args); - r.Width = caretWidth; - } else { - args.text = String_UNSAFE_Substring(&text, 0, w->caretPos); - r.X += Drawer2D_TextWidth(&args); - - args.text = String_UNSAFE_Substring(&text, w->caretPos, 1); - r.Width = Drawer2D_TextWidth(&args); - } - return r; -} - -static TimeMS caretStart; -static cc_bool lastCaretShow; -static Rect2D lastCaretRec; -#define Rect2D_Equals(a, b) a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height - static void LInput_TickCaret(void* widget) { struct LInput* w = (struct LInput*)widget; - int elapsed; - cc_bool caretShow; - Rect2D r; + LBackend_TickInput(w); +} - if (!caretStart) return; - elapsed = (int)(DateTime_CurrentUTC_MS() - caretStart); +static void LInput_Select(void* widget, int idx, cc_bool wasSelected) { + struct LInput* w = (struct LInput*)widget; + LBackend_SelectInput(w, idx, wasSelected); +} - caretShow = (elapsed % 1000) < 500; - if (caretShow == lastCaretShow) return; - lastCaretShow = caretShow; - - LInput_Draw(w); - r = LInput_MeasureCaret(w); - - if (caretShow) { - Drawer2D_Clear(&Launcher_Framebuffer, BITMAPCOL_BLACK, - r.X, r.Y, r.Width, r.Height); - } - - if (Rect2D_Equals(r, lastCaretRec)) { - /* Fast path, caret is blinking in same spot */ - Launcher_MarkDirty(r.X, r.Y, r.Width, r.Height); - } else { - Launcher_MarkDirty(w->x, w->y, w->width, w->height); - } - lastCaretRec = r; +static void LInput_Unselect(void* widget, int idx) { + struct LInput* w = (struct LInput*)widget; + LBackend_UnselectInput(w); } static void LInput_AdvanceCaretPos(struct LInput* w, cc_bool forwards) { @@ -296,58 +242,6 @@ static void LInput_AdvanceCaretPos(struct LInput* w, cc_bool forwards) { LWidget_Redraw(w); } -static void LInput_MoveCaretToCursor(struct LInput* w, int idx) { - cc_string text; char textBuffer[STRING_SIZE]; - int x = Pointers[idx].x, y = Pointers[idx].y; - struct DrawTextArgs args; - int i, charX, charWidth; - - /* Input widget may have been selected by pressing tab */ - /* In which case cursor is completely outside, so ignore */ - if (!Gui_Contains(w->x, w->y, w->width, w->height, x, y)) return; - lastCaretShow = false; - - String_InitArray(text, textBuffer); - LInput_GetText(w, &text); - x -= w->x; y -= w->y; - - DrawTextArgs_Make(&args, &text, &Launcher_TextFont, true); - if (x >= Drawer2D_TextWidth(&args)) { - w->caretPos = -1; return; - } - - for (i = 0; i < text.length; i++) { - args.text = String_UNSAFE_Substring(&text, 0, i); - charX = Drawer2D_TextWidth(&args); - - args.text = String_UNSAFE_Substring(&text, i, 1); - charWidth = Drawer2D_TextWidth(&args); - if (x >= charX && x < charX + charWidth) { - w->caretPos = i; return; - } - } -} - -static void LInput_Select(void* widget, int idx, cc_bool wasSelected) { - struct LInput* w = (struct LInput*)widget; - struct OpenKeyboardArgs args; - caretStart = DateTime_CurrentUTC_MS(); - LInput_MoveCaretToCursor(w, idx); - /* TODO: Only draw outer border */ - if (wasSelected) return; - - LWidget_Draw(widget); - OpenKeyboardArgs_Init(&args, &w->text, w->type); - Window_OpenKeyboard(&args); -} - -static void LInput_Unselect(void* widget, int idx) { - caretStart = 0; - /* TODO: Only draw outer border */ - LWidget_Draw(widget); - Window_CloseKeyboard(); -} - static void LInput_CopyFromClipboard(struct LInput* w) { cc_string text; char textBuffer[2048]; String_InitArray(text, textBuffer); @@ -470,14 +364,10 @@ void LInput_Init(struct LInput* w, int width, const char* hintText) { w->minWidth = w->width; } -void LInput_SetText(struct LInput* w, const cc_string* text_) { - cc_string text; char textBuffer[STRING_SIZE]; - String_Copy(&w->text, text_); - String_InitArray(text, textBuffer); - +void LInput_SetText(struct LInput* w, const cc_string* text) { + String_Copy(&w->text, text); LInput_ClampCaret(w); - LInput_GetText(w, &text); - LBackend_UpdateInput(w, &text); + LBackend_UpdateInput(w); } void LInput_ClearText(struct LInput* w) { diff --git a/src/LWidgets.h b/src/LWidgets.h index f3b044e17..721768abd 100644 --- a/src/LWidgets.h +++ b/src/LWidgets.h @@ -40,7 +40,9 @@ struct LWidgetVTABLE { cc_bool tabSelectable; /* Whether this widget gets selected when pressing tab */ \ cc_uint8 horAnchor, verAnchor; /* Specifies the reference point for when this widget is resized */ \ int xOffset, yOffset; /* Offset from the reference point */ \ - void (*OnClick)(void* widget, int idx); /* Called when widget is clicked */ \ + void (*OnClick)(void* widget); /* Called when widget is clicked */ \ + void (*OnHover)(void* widget); /* Called when widget is hovered over */ \ + void (*OnUnhover)(void* widget);/*Called when widget is no longer hovered over */ \ Rect2D last; /* Widget's last drawn area */ \ void* meta; /* Backend specific data */ @@ -90,6 +92,7 @@ struct LInput { char _textBuffer[STRING_SIZE]; }; CC_NOINLINE void LInput_Init(struct LInput* w, int width, const char* hintText); +CC_NOINLINE void LInput_UNSAFE_GetText(struct LInput* w, cc_string* text); CC_NOINLINE void LInput_SetText(struct LInput* w, const cc_string* text); CC_NOINLINE void LInput_ClearText(struct LInput* w); diff --git a/src/interop_ios.m b/src/interop_ios.m index cca65b41d..5a9b43311 100644 --- a/src/interop_ios.m +++ b/src/interop_ios.m @@ -626,7 +626,7 @@ static void LBackend_HandleButton(id btn_obj) { if (w == NULL) return; struct LButton* btn = (struct LButton*)w; - btn->OnClick(btn, 0); + btn->OnClick(btn); } void LBackend_InitButton(struct LButton* w, int width, int height) { @@ -716,15 +716,19 @@ void LBackend_InitInput(struct LInput* w, int width) { UpdateWidgetDimensions(w); } -void LBackend_UpdateInput(struct LInput* w, const cc_string* text) { +void LBackend_UpdateInput(struct LInput* w) { UITextField* fld = (__bridge UITextField*)w->meta; fld.text = ToNSString(&w->text); UpdateWidgetDimensions(w); } -void LBackend_DrawInput(struct LInput* w, const cc_string* text) { +void LBackend_DrawInput(struct LInput* w) { } +void LBackend_TickInput(struct LInput* w) { } +void LBackend_SelectInput(struct LInput* w, int idx, cc_bool wasSelected) { } +void LBackend_UnselectInput(struct LInput* w) { } + /*########################################################################################################################* *------------------------------------------------------LabelWidget--------------------------------------------------------*