Launcher: Cleanup and more modular input widget, hovering

This commit is contained in:
UnknownShadow200 2022-04-07 21:34:08 +10:00
parent 7812483682
commit f89baa5d8f
7 changed files with 233 additions and 214 deletions

View file

@ -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--------------------------------------------------------*
*#########################################################################################################################*/

View file

@ -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);

View file

@ -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(&regUrl);
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_;

View file

@ -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. */ \

View file

@ -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) {

View file

@ -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);

View file

@ -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--------------------------------------------------------*