mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-22 17:12:25 -05:00
Launcher: Cleanup and more modular input widget, hovering
This commit is contained in:
parent
7812483682
commit
f89baa5d8f
7 changed files with 233 additions and 214 deletions
134
src/LBackend.c
134
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--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
|
|
|
@ -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);
|
||||
|
|
149
src/LScreens.c
149
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_;
|
||||
|
|
|
@ -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. */ \
|
||||
|
|
138
src/LWidgets.c
138
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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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--------------------------------------------------------*
|
||||
|
|
Loading…
Reference in a new issue