diff --git a/Launcher2/Gui/Screens/Screen.cs b/Launcher2/Gui/Screens/Screen.cs index b94776ced..392882e5d 100644 --- a/Launcher2/Gui/Screens/Screen.cs +++ b/Launcher2/Gui/Screens/Screen.cs @@ -23,7 +23,6 @@ namespace Launcher.Gui.Screens { Mouse.Move += MouseMove; Mouse.ButtonDown += MouseButtonDown; Keyboard.KeyDown += KeyDown; - Keyboard.KeyUp += KeyUp; } /// Function that is repeatedly called multiple times every second. @@ -37,7 +36,6 @@ namespace Launcher.Gui.Screens { Mouse.Move -= MouseMove; Mouse.ButtonDown -= MouseButtonDown; Keyboard.KeyDown -= KeyDown; - Keyboard.KeyUp -= KeyUp; } /// Function called when the pixels from the framebuffer @@ -148,22 +146,14 @@ namespace Launcher.Gui.Screens { } } - protected virtual void KeyUp(Key key) { - if (key == Key.Tab) - tabDown = false; - } - protected int IndexOfWidget(Widget w) { for (int i = 0; i < widgets.Length; i++) { if (widgets[i] == w) return i; } return -1; } - - protected bool tabDown = false; + protected void HandleTab() { - if (tabDown) return; - tabDown = true; bool shiftDown = game.IsKeyDown(Key.ShiftLeft) || game.IsKeyDown(Key.ShiftRight); diff --git a/src/LScreens.c b/src/LScreens.c index 1b03c5897..834b2fb96 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -4,6 +4,9 @@ #include "Gui.h" #include "Game.h" +/*########################################################################################################################* +*---------------------------------------------------------Screen base-----------------------------------------------------* +*#########################################################################################################################*/ static void LScreen_NullFunc(struct LScreen* s) { } static void LScreen_DrawAll(struct LScreen* s) { struct LWidget* widget; @@ -38,15 +41,19 @@ CC_NOINLINE static void LScreen_Reset(struct LScreen* s) { s->HoverWidget = LScreen_HoverWidget; s->UnhoverWidget = LScreen_UnhoverWidget; - /* reset all widgets to unselected */ + /* reset all widgets mouse state */ for (i = 0; i < s->NumWidgets; i++) { - s->Widgets[i]->Hovered = false; + s->Widgets[i]->Hovered = false; + s->Widgets[i]->Selected = false; } + + s->OnEnterWidget = NULL; + s->HoveredWidget = NULL; } /*########################################################################################################################* -*---------------------------------------------------------Widget init-----------------------------------------------------* +*--------------------------------------------------------Widget helpers---------------------------------------------------* *#########################################################################################################################*/ CC_NOINLINE static void LScreen_Button(struct LScreen* s, struct LButton* w, int width, int height, const char* text, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) { @@ -54,7 +61,6 @@ CC_NOINLINE static void LScreen_Button(struct LScreen* s, struct LButton* w, int LButton_Init(w, width, height); LButton_SetText(w, &str, &Launcher_TitleFont); - w->Hovered = false; s->Widgets[s->NumWidgets++] = (struct LWidget*)w; LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset); } @@ -65,7 +71,15 @@ CC_NOINLINE static void LScreen_Label(struct LScreen* s, struct LLabel* w, const LLabel_Init(w); LLabel_SetText(w, &str, &Launcher_TextFont); - w->Hovered = false; + s->Widgets[s->NumWidgets++] = (struct LWidget*)w; + LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset); +} + +CC_NOINLINE static void LScreen_Input(struct LScreen* s, struct LInput* w, int width, bool password, const char* hintText, + uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) { + LInput_Init(w, width, 30, hintText, &Launcher_HintFont); + w->Password = password; + s->Widgets[s->NumWidgets++] = (struct LWidget*)w; LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset); } @@ -77,15 +91,39 @@ CC_NOINLINE static void LScreen_Slider(struct LScreen* s, struct LSlider* w, int w->Value = initValue; w->MaxValue = maxValue; w->ProgressCol = progressCol; - w->Hovered = false; s->Widgets[s->NumWidgets++] = (struct LWidget*)w; LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset); } +CC_NOINLINE static int LScreen_IndexOf(struct LScreen* s, void* w) { + int i; + for (i = 0; i < s->NumWidgets; i++) { + if (s->Widgets[i] == w) return i; + } + return -1; +} + +static void SwitchToChooseMode(void* w, int x, int y) { + Launcher_SetScreen(ChooseModeScreen_MakeInstance(false)); +} +static void SwitchToColours(void* w, int x, int y) { + Launcher_SetScreen(ColoursScreen_MakeInstance()); +} +static void SwitchToMain(void* w, int x, int y) { + Launcher_SetScreen(MainScreen_MakeInstance()); +} +static void SwitchToSettings(void* w, int x, int y) { + Launcher_SetScreen(SettingsScreen_MakeInstance()); +} +static void SwitchToUpdates(void* w, int x, int y) { + Launcher_SetScreen(UpdatesScreen_MakeInstance()); +} + + /*########################################################################################################################* *-------------------------------------------------------ChooseModeScreen--------------------------------------------------* *#########################################################################################################################*/ -/*static struct ChooseModeScreen { +static struct ChooseModeScreen { LScreen_Layout struct LWidget* Widgets[12]; struct LButton BtnEnhanced, BtnClassicHax, BtnClassic, BtnBack; @@ -93,7 +131,7 @@ CC_NOINLINE static void LScreen_Slider(struct LScreen* s, struct LSlider* w, int bool FirstTime; } ChooseModeScreen_Instance; -static void ChooseMode_Click(bool classic, bool classicHacks) { +CC_NOINLINE static void ChooseMode_Click(bool classic, bool classicHacks) { Launcher_ClassicBackground = classic; Options_Load(); Options_SetBool(OPT_CLASSIC_MODE, classic); @@ -110,18 +148,9 @@ static void ChooseMode_Click(bool classic, bool classicHacks) { Launcher_SetScreen(MainScreen_MakeInstance()); } -static void UseModeEnhanced(void* w, int x, int y) { - Launcher_SetScreen(ChooseModeScreen_MakeInstance(false)); -} -static void UseModeClassicHax(void* w, int x, int y) { - Launcher_SetScreen(UpdatesScreen_MakeInstance()); -} -static void UseModeClassic(void* w, int x, int y) { - Launcher_SetScreen(ColoursScreen_MakeInstance()); -} -static void SwitchToSettings(void* w, int x, int y) { - Launcher_SetScreen(SettingsScreen_MakeInstance()); -} +static void UseModeEnhanced(void* w, int x, int y) { ChooseMode_Click(false, false); } +static void UseModeClassicHax(void* w, int x, int y) { ChooseMode_Click(true, true); } +static void UseModeClassic(void* w, int x, int y) { ChooseMode_Click(true, false); } static void ChooseModeScreenScreen_InitWidgets(struct ChooseModeScreen* s) { struct LScreen* s_ = (struct LScreen*)s; @@ -168,7 +197,7 @@ static void ChooseModeScreen_Init(struct LScreen* s_) { s->LblHelp.Hidden = !s->FirstTime; s->BtnBack.Hidden = s->FirstTime; - s->DrawAll(s); + s->DrawAll(s_); } struct LScreen* ChooseModeScreen_MakeInstance(bool firstTime) { @@ -177,32 +206,145 @@ struct LScreen* ChooseModeScreen_MakeInstance(bool firstTime) { s->Init = ChooseModeScreen_Init; s->FirstTime = firstTime; return (struct LScreen*)s; -}*/ +} + + +/*########################################################################################################################* +*------------------------------------------------------DirectConnectScreen------------------------------------------------* +*#########################################################################################################################*/ +static struct DirectConnectScreen { + LScreen_Layout + struct LWidget* Widgets[6]; + struct LButton BtnConnect, BtnBack; + struct LInput IptUsername, IptAddress, IptMppass; + struct LLabel LblStatus; + bool FirstTime; +} DirectConnectScreen_Instance; + +CC_NOINLINE static void DirectConnectScreen_SetStatus(const char* msg) { + String str = String_FromReadonly(msg); + struct LLabel* w = &DirectConnectScreen_Instance.LblStatus; + Launcher_ResetArea(w->X, w->Y, w->Width, w->Height); + + LLabel_SetText(w, &str, &Launcher_TextFont); + w->VTABLE->Redraw(w); +} + +static void DirectConnectScreen_Load(struct DirectConnectScreen* s) { + String addr; char addrBuffer[STRING_SIZE]; + String mppass; char mppassBuffer[STRING_SIZE]; + String user, ip, port; + Options_Load(); + + Options_UNSAFE_Get("launcher-dc-username", &user); + Options_UNSAFE_Get("launcher-dc-ip", &ip); + Options_UNSAFE_Get("launcher-dc-port", &port); + + String_InitArray(mppass, mppassBuffer); + Launcher_LoadSecureOpt("launcher-dc-mppass", &mppass, &user); + String_InitArray(addr, addrBuffer); + String_Format2(&addr, "%s:%s", &ip, &port); + + LInput_SetText(&s->IptUsername, &user, &Launcher_TextFont); + LInput_SetText(&s->IptAddress, &addr, &Launcher_TextFont); + LInput_SetText(&s->IptMppass, &mppass, &Launcher_TextFont); +} + +static void DirectConnectScreen_Save(const String* user, const String* mppass, const String* ip, const String* port) { + Options_Load(); + Options_Set("launcher-dc-username", user); + Options_Set("launcher-dc-ip", ip); + Options_Set("launcher-dc-port", port); + Launcher_SaveSecureOpt("launcher-dc-mppass", mppass, user); + Options_Save(); +} + +static void StartClient(void* w, int x, int y) { + static String loopbackIp = String_FromConst("127.0.0.1"); + static String defMppass = String_FromConst("(none)"); + String* user = &DirectConnectScreen_Instance.IptUsername.Text; + String* addr = &DirectConnectScreen_Instance.IptAddress.Text; + String* mppass = &DirectConnectScreen_Instance.IptMppass.Text; + + String ip, port; + uint8_t raw_ip[4]; + uint16_t raw_port; + + int index = String_LastIndexOf(addr, ':'); + if (index <= 0 || index == addr->length - 1) { + DirectConnectScreen_SetStatus("&eInvalid address"); return; + } + + ip = String_UNSAFE_Substring(addr, 0, index); + port = String_UNSAFE_SubstringAt(addr, index + 1); + if (String_CaselessEqualsConst(&ip, "localhost")) ip = loopbackIp; + + if (!user->length) { + DirectConnectScreen_SetStatus("&eUsername required"); return; + } + if (!Utils_ParseIP(&ip, raw_ip)) { + DirectConnectScreen_SetStatus("&eInvalid ip"); return; + } + if (!Convert_TryParseUInt16(&port, &raw_port)) { + DirectConnectScreen_SetStatus("&eInvalid port"); return; + } + if (!mppass->length) mppass = &defMppass; + + DirectConnectScreen_Save(user, mppass, &ip, &port); + DirectConnectScreen_SetStatus(""); + Launcher_StartGame(user, mppass, &ip, &port, &String_Empty); +} + +static void DirectConnectScreen_InitWidgets(struct DirectConnectScreen* s) { + struct LScreen* s_ = (struct LScreen*)s; + + LScreen_Input(s_, &s->IptUsername, 330, false, "&gUsername..", + ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -120); + LScreen_Input(s_, &s->IptAddress, 330, false, "&gIP address:Port number..", + ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -75); + LScreen_Input(s_, &s->IptMppass, 330, false, "&gMppass..", + ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -30); + + LScreen_Button(s_, &s->BtnConnect, 110, 35, "Connect", + ANCHOR_CENTRE, ANCHOR_CENTRE, -110, 20); + LScreen_Button(s_, &s->BtnBack, 80, 35, "Back", + ANCHOR_CENTRE, ANCHOR_CENTRE, 125, 20); + LScreen_Label(s_, &s->LblStatus, "", + ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 70); + + s->BtnConnect.OnClick = StartClient; + s->BtnBack.OnClick = SwitchToMain; + + /* Init input text from options */ + DirectConnectScreen_Load(s); +} + +static void DirectConnectScreen_Init(struct LScreen* s_) { + struct DirectConnectScreen* s = (struct DirectConnectScreen*)s_; + if (!s->NumWidgets) DirectConnectScreen_InitWidgets(s); + + s->DrawAll(s_); +} + +struct LScreen* DirectConnectScreen_MakeInstance(void) { + struct DirectConnectScreen* s = &DirectConnectScreen_Instance; + LScreen_Reset((struct LScreen*)s); + s->Init = DirectConnectScreen_Init; + s->OnEnterWidget = (struct LWidget*)&s->BtnConnect; + return (struct LScreen*)s; +} /*########################################################################################################################* *--------------------------------------------------------SettingsScreen---------------------------------------------------* *#########################################################################################################################*/ -/*static struct SettingsScreen { +static struct SettingsScreen { LScreen_Layout struct LWidget* Widgets[7]; struct LButton BtnUpdates, BtnMode, BtnColours, BtnBack; struct LLabel LblUpdates, LblMode, LblColours; } SettingsScreen_Instance; -static void SwitchToChooseMode(void* w, int x, int y) { - Launcher_SetScreen(ChooseModeScreen_MakeInstance(false)); -} -static void SwitchToUpdates(void* w, int x, int y) { - Launcher_SetScreen(UpdatesScreen_MakeInstance()); -} -static void SwitchToColours(void* w, int x, int y) { - Launcher_SetScreen(ColoursScreen_MakeInstance()); -} -static void SwitchToMain(void* w, int x, int y) { - Launcher_SetScreen(MainScreen_MakeInstance()); -} - static void SettingsScreen_InitWidgets(struct SettingsScreen* s) { struct LScreen* s_ = (struct LScreen*)s; @@ -236,7 +378,7 @@ static void SettingsScreen_Init(struct LScreen* s_) { s->BtnColours.Hidden = Launcher_ClassicBackground; s->LblColours.Hidden = Launcher_ClassicBackground; - s->DrawAll(s); + s->DrawAll(s_); } struct LScreen* SettingsScreen_MakeInstance(void) { @@ -245,4 +387,3 @@ struct LScreen* SettingsScreen_MakeInstance(void) { s->Init = SettingsScreen_Init; return (struct LScreen*)s; } -*/ \ No newline at end of file diff --git a/src/LScreens.h b/src/LScreens.h index 48c651508..f2d9a7b42 100644 --- a/src/LScreens.h +++ b/src/LScreens.h @@ -19,6 +19,7 @@ typedef void (*LWidget_Func)(struct LScreen* s, struct LWidget* w); LScreen_Func OnDisplay; /* Called when framebuffer is about to be displayed. */ \ 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. */ \ int NumWidgets; /* Number of widgets actually used. */ diff --git a/src/LWidgets.c b/src/LWidgets.c index 18fc81169..ddfd7989c 100644 --- a/src/LWidgets.c +++ b/src/LWidgets.c @@ -4,6 +4,10 @@ #include "Drawer2D.h" #include "Launcher.h" #include "ExtMath.h" +#include "Window.h" +#include "Funcs.h" + +#define BORDER 1 void LWidget_SetLocation(void* widget, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) { struct Widget* w = widget; @@ -21,6 +25,7 @@ void LWidget_CalcPosition(void* widget) { void LWidget_Reset(void* widget) { struct LWidget* w = widget; w->Hovered = false; + w->Selected = false; w->Hidden = false; w->X = 0; w->Y = 0; w->Width = 0; w->Height = 0; @@ -37,7 +42,6 @@ void LWidget_Reset(void* widget) { /*########################################################################################################################* *------------------------------------------------------ButtonWidget-------------------------------------------------------* *#########################################################################################################################*/ -#define BTN_BORDER 1 static BitmapCol LButton_Expand(BitmapCol a, int amount) { int r, g, b; r = a.R + amount; Math_Clamp(r, 0, 255); a.R = r; @@ -54,13 +58,13 @@ static void LButton_DrawBackground(struct LButton* w) { if (Launcher_ClassicBackground) { col = w->Hovered ? activeCol : inactiveCol; Gradient_Noise(&Launcher_Framebuffer, col, 8, - w->X + BTN_BORDER, w->Y + BTN_BORDER, - w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER); + w->X + BORDER, w->Y + BORDER, + w->Width - 2 * BORDER, w->Height - 2 * BORDER); } else { col = w->Hovered ? Launcher_ButtonForeActiveCol : Launcher_ButtonForeCol; Gradient_Vertical(&Launcher_Framebuffer, LButton_Expand(col, 8), LButton_Expand(col, -8), - w->X + BTN_BORDER, w->Y + BTN_BORDER, - w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER); + w->X + BORDER, w->Y + BORDER, + w->Width - 2 * BORDER, w->Height - 2 * BORDER); } } @@ -69,17 +73,17 @@ static void LButton_DrawBorder(struct LButton* w) { BitmapCol backCol = Launcher_ClassicBackground ? black : Launcher_ButtonBorderCol; Drawer2D_Clear(&Launcher_Framebuffer, backCol, - w->X + BTN_BORDER, w->Y, - w->Width - 2 * BTN_BORDER, BTN_BORDER); + w->X + BORDER, w->Y, + w->Width - 2 * BORDER, BORDER); Drawer2D_Clear(&Launcher_Framebuffer, backCol, - w->X + BTN_BORDER, w->Y + w->Height - BTN_BORDER, - w->Width - 2 * BTN_BORDER, BTN_BORDER); + w->X + BORDER, w->Y + w->Height - BORDER, + w->Width - 2 * BORDER, BORDER); Drawer2D_Clear(&Launcher_Framebuffer, backCol, - w->X, w->Y + BTN_BORDER, - BTN_BORDER, w->Height - 2 * BTN_BORDER); + w->X, w->Y + BORDER, + BORDER, w->Height - 2 * BORDER); Drawer2D_Clear(&Launcher_Framebuffer, backCol, - w->X + w->Width - BTN_BORDER, w->Y + BTN_BORDER, - BTN_BORDER, w->Height - 2 * BTN_BORDER); + w->X + w->Width - BORDER, w->Y + BORDER, + BORDER, w->Height - 2 * BORDER); } static void LButton_DrawHighlight(struct LButton* w) { @@ -90,15 +94,15 @@ static void LButton_DrawHighlight(struct LButton* w) { if (Launcher_ClassicBackground) { highlightCol = w->Hovered ? activeCol : inactiveCol; Drawer2D_Clear(&Launcher_Framebuffer, highlightCol, - w->X + BTN_BORDER * 2, w->Y + BTN_BORDER, - w->Width - BTN_BORDER * 4, BTN_BORDER); + w->X + BORDER * 2, w->Y + BORDER, + w->Width - BORDER * 4, BORDER); Drawer2D_Clear(&Launcher_Framebuffer, highlightCol, - w->X + BTN_BORDER, w->Y + BTN_BORDER * 2, - BTN_BORDER, w->Height - BTN_BORDER * 4); + w->X + BORDER, w->Y + BORDER * 2, + BORDER, w->Height - BORDER * 4); } else if (!w->Hovered) { Drawer2D_Clear(&Launcher_Framebuffer, Launcher_ButtonHighlightCol, - w->X + BTN_BORDER * 2, w->Y + BTN_BORDER, - w->Width - BTN_BORDER * 4, BTN_BORDER); + w->X + BORDER * 2, w->Y + BORDER, + w->Width - BORDER * 4, BORDER); } } @@ -108,8 +112,8 @@ static void LButton_Redraw(void* widget) { int xOffset, yOffset; if (w->Hidden) return; - xOffset = w->Width - w->__TextSize.Width; - yOffset = w->Height - w->__TextSize.Height; + xOffset = w->Width - w->_TextSize.Width; + yOffset = w->Height - w->_TextSize.Height; DrawTextArgs_Make(&args, &w->Text, &w->Font, true); LButton_DrawBackground(w); @@ -132,7 +136,7 @@ void LButton_Init(struct LButton* w, int width, int height) { w->VTABLE = &lbutton_VTABLE; w->TabSelectable = true; w->Width = width; w->Height = height; - String_InitArray(w->Text, w->__TextBuffer); + String_InitArray(w->Text, w->_TextBuffer); } void LButton_SetText(struct LButton* w, const String* text, const FontDesc* font) { @@ -141,7 +145,7 @@ void LButton_SetText(struct LButton* w, const String* text, const FontDesc* font String_Copy(&w->Text, text); DrawTextArgs_Make(&args, text, font, true); - w->__TextSize = Drawer2D_MeasureText(&args); + w->_TextSize = Drawer2D_MeasureText(&args); } @@ -157,9 +161,172 @@ CC_NOINLINE static void LInput_GetText(struct LInput* w, String* text) { } } -CC_NOINLINE void LInput_Init(struct LInput* w, int width, int height, const char* hintText, const FontDesc* hintFont); -CC_NOINLINE void LInput_SetText(struct LInput* w, const String* text, const FontDesc* font); -CC_NOINLINE Rect2D LInput_MeasureCaret(struct LInput* w); +static void LInput_DrawOuterBorder(struct LInput* w) { + BitmapCol col = BITMAPCOL_CONST(97, 81, 110, 255); + int width = w->_RealWidth; + + if (w->Selected) { + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X, w->Y, + width, BORDER); + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X, w->Y + w->Height - BORDER, + width, BORDER); + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X, w->Y, + BORDER, w->Height); + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X + width - BORDER, w->Y, + BORDER, w->Height); + } else { + Launcher_ResetArea(w->X, w->Y, + width, BORDER); + Launcher_ResetArea(w->X, w->Y + w->Height - BORDER, + width, BORDER); + Launcher_ResetArea(w->X, w->Y, + BORDER, w->Height); + Launcher_ResetArea(w->X + width - BORDER, w->Y, + BORDER, w->Height); + } +} + +static void LInput_DrawInnerBorder(struct LInput* w) { + BitmapCol col = BITMAPCOL_CONST(165, 142, 168, 255); + int width = w->_RealWidth; + + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X + BORDER, w->Y + BORDER, + width - BORDER * 2, BORDER); + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X + BORDER, w->Y + w->Height - BORDER * 2, + width - BORDER * 2, BORDER); + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X + BORDER, w->Y + BORDER, + BORDER, w->Height - BORDER * 2); + Drawer2D_Clear(&Launcher_Framebuffer, col, + w->X + width - BORDER * 2, w->Y + BORDER, + BORDER, w->Height - BORDER * 2); +} + +static void LInput_BlendBoxTop(struct LInput* w) { + BitmapCol col = BITMAPCOL_CONST(0, 0, 0, 255); + int width = w->_RealWidth; + + Gradient_Blend(&Launcher_Framebuffer, col, 75, + w->X + BORDER, w->Y + BORDER * 1, + width - BORDER * 2, BORDER); + Gradient_Blend(&Launcher_Framebuffer, col, 50, + w->X + BORDER, w->Y + BORDER * 2, + width - BORDER * 2, BORDER); + Gradient_Blend(&Launcher_Framebuffer, col, 25, + w->X + BORDER, w->Y + BORDER * 3, + width - BORDER * 2, BORDER); +} + +static void LInput_DrawText(struct LInput* w, struct DrawTextArgs* args) { + int hintHeight, y; + + if (w->Text.length || !w->HintText) { + y = w->Y + (w->Height - w->_TextHeight) / 2; + Drawer2D_DrawText(&Launcher_Framebuffer, args, w->X + 5, y + 2); + } else { + args->Text = String_FromReadonly(w->HintText); + args->Font = w->HintFont; + + hintHeight = Drawer2D_MeasureText(args).Height; + y = w->Y + (w->Height - hintHeight) / 2; + Drawer2D_DrawText(&Launcher_Framebuffer, args, w->X + 5, y); + } +} + +static void LInput_Redraw(void* widget) { + String text; char textBuffer[STRING_SIZE]; + struct DrawTextArgs args; + Size2D size; + + BitmapCol white = BITMAPCOL_CONST(255, 255, 255, 255); + struct LInput* w = widget; + if (w->Hidden) return; + + String_InitArray(text, textBuffer); + LInput_GetText(w, &text); + DrawTextArgs_Make(&args, &text, &w->Font, false); + + size = Drawer2D_MeasureText(&args); + w->_RealWidth = max(w->BaseWidth, size.Width + 20); + w->_TextHeight = size.Height; + + LInput_DrawOuterBorder(w); + LInput_DrawInnerBorder(w); + Drawer2D_Clear(&Launcher_Framebuffer, white, + w->X + 2, w->Y + 2, w->_RealWidth - 4, w->Height - 4); + LInput_BlendBoxTop(w); + + Drawer2D_Cols['f'] = Drawer2D_Cols['0']; + LInput_DrawText(w, &args); + Drawer2D_Cols['f'] = Drawer2D_Cols['F']; + Launcher_Dirty = true; +} + +static struct LWidgetVTABLE linput_VTABLE = { + LInput_Redraw, NULL, NULL, + /* TODO: Don't redraw whole thing, just the outer border */ + LInput_Redraw, LInput_Redraw +}; +void LInput_Init(struct LInput* w, int width, int height, const char* hintText, const FontDesc* hintFont) { + Widget_Reset(w); + w->VTABLE = &linput_VTABLE; + String_InitArray(w->Text, w->_TextBuffer); + + w->BaseWidth = width; + w->Width = width; w->Height = height; + LWidget_CalcPosition(w); + + w->HintFont = *hintFont; + w->HintText = hintText; +} + +void LInput_SetText(struct LInput* w, const String* text_, const FontDesc* font) { + String text; char textBuffer[STRING_SIZE]; + struct DrawTextArgs args; + Size2D size; + + String_Copy(&w->Text, text_); + w->Font = *font; + + String_InitArray(text, textBuffer); + LInput_GetText(w, &text); + DrawTextArgs_Make(&args, &text, &w->Font, true); + + size = Drawer2D_MeasureText(&args); + w->_RealWidth = max(w->BaseWidth, size.Width + 15); + w->_TextHeight = size.Height; +} + +Rect2D LInput_MeasureCaret(struct LInput* w) { + String text; char textBuffer[STRING_SIZE]; + struct DrawTextArgs args; + Rect2D r; + + String_InitArray(text, textBuffer); + LInput_GetText(w, &text); + DrawTextArgs_Make(&args, &text, &w->Font, true); + + r.X = w->X + 5; + r.Y = w->Y + w->Height - 5; r.Height = 2; + + if (w->CaretPos == -1) { + r.X += Drawer2D_MeasureText(&args).Width; + r.Width = 10; + } else { + args.Text = String_UNSAFE_Substring(&text, 0, w->CaretPos); + r.X += Drawer2D_MeasureText(&args).Width; + + args.Text = String_UNSAFE_Substring(&text, w->CaretPos, 1); + r.Width = Drawer2D_MeasureText(&args).Width; + } + return r; +} void LInput_AdvanceCaretPos(struct LInput* w, bool forwards) { if (forwards && w->CaretPos == -1) return; @@ -249,8 +416,22 @@ bool LInput_Clear(struct LInput* w) { return true; } -/* Sets the currently entered text to the contents of the system clipboard. */ -CC_NOINLINE bool LInput_CopyFromClipboard(struct LInput* w, const String* text); +bool LInput_CopyFromClipboard(struct LInput* w) { + String text; char textBuffer[256]; + String_InitArray(text, textBuffer); + + Window_GetClipboardText(&text); + String_UNSAFE_TrimStart(&text); + String_UNSAFE_TrimEnd(&text); + + if (w->Text.length >= w->Text.capacity) return false; + if (!text.length) return false; + if (w->ClipboardFilter) w->ClipboardFilter(&text); + + String_AppendString(&w->Text, &text); + if (w->TextChanged) w->TextChanged(w); + return true; +} /*########################################################################################################################* @@ -272,7 +453,7 @@ static struct LWidgetVTABLE llabel_VTABLE = { void LLabel_Init(struct LLabel* w) { Widget_Reset(w); w->VTABLE = &llabel_VTABLE; - String_InitArray(w->Text, w->__TextBuffer); + String_InitArray(w->Text, w->_TextBuffer); } void LLabel_SetText(struct LLabel* w, const String* text, const FontDesc* font) { @@ -291,25 +472,24 @@ void LLabel_SetText(struct LLabel* w, const String* text, const FontDesc* font) /*########################################################################################################################* *------------------------------------------------------SliderWidget-------------------------------------------------------* *#########################################################################################################################*/ -#define SDR_BORDER 1 static void LSlider_DrawBoxBounds(struct LSlider* w) { BitmapCol boundsTop = BITMAPCOL_CONST(119, 100, 132, 255); BitmapCol boundsBottom = BITMAPCOL_CONST(150, 130, 165, 255); /* TODO: Check these are actually right */ Drawer2D_Clear(&Launcher_Framebuffer, boundsTop, - w->X - SDR_BORDER, w->Y - SDR_BORDER, - w->Width + 2 * SDR_BORDER, SDR_BORDER); + w->X - BORDER, w->Y - BORDER, + w->Width + 2 * BORDER, BORDER); Drawer2D_Clear(&Launcher_Framebuffer, boundsBottom, - w->X - SDR_BORDER, w->Y + w->Height, - w->Width + 2 * SDR_BORDER, SDR_BORDER); + w->X - BORDER, w->Y + w->Height, + w->Width + 2 * BORDER, BORDER); Gradient_Vertical(&Launcher_Framebuffer, boundsTop, boundsBottom, - w->X - SDR_BORDER, w->Y - SDR_BORDER, - SDR_BORDER, w->Height + SDR_BORDER); + w->X - BORDER, w->Y - BORDER, + BORDER, w->Height + BORDER); Gradient_Vertical(&Launcher_Framebuffer, boundsTop, boundsBottom, - w->X + w->Width, w->Y - SDR_BORDER, - SDR_BORDER, w->Height + SDR_BORDER); + w->X + w->Width, w->Y - BORDER, + BORDER, w->Height + BORDER); } static void LSlider_DrawBox(struct LSlider* w) { diff --git a/src/LWidgets.h b/src/LWidgets.h index f3fe8b9b2..3cbd604ed 100644 --- a/src/LWidgets.h +++ b/src/LWidgets.h @@ -25,7 +25,8 @@ struct LWidgetVTABLE { #define LWidget_Layout \ struct LWidgetVTABLE* VTABLE; /* General widget functions */ \ int X, Y, Width, Height; /* Top left corner, and dimensions, of this widget */ \ - bool Hovered; /* Whether this widget is currently being moused over*/ \ + bool Hovered; /* Whether this widget is currently being moused over */ \ + bool Selected; /* Whether this widget is last widget to be clicked on */ \ bool Hidden; /* Whether this widget is hidden from view */ \ bool TabSelectable; /* Whether this widget gets selected when pressing tab */ \ uint8_t HorAnchor, VerAnchor; /* Specifies the reference point for when this widget is resized */ \ @@ -42,8 +43,8 @@ struct LButton { LWidget_Layout String Text; FontDesc Font; - Size2D __TextSize; - char __TextBuffer[STRING_SIZE]; + Size2D _TextSize; + char _TextBuffer[STRING_SIZE]; }; CC_NOINLINE void LButton_Init(struct LButton* w, int width, int height); CC_NOINLINE void LButton_SetText(struct LButton* w, const String* text, const FontDesc* font); @@ -51,7 +52,7 @@ CC_NOINLINE void LButton_SetText(struct LButton* w, const String* text, const Fo struct LInput; struct LInput { LWidget_Layout - int BaseWidth, RealWidth; + int BaseWidth, _RealWidth; /* Text displayed when the user has not entered anything in the text field. */ const char* HintText; /* Whether all characters should be rendered as *. */ @@ -67,8 +68,8 @@ struct LInput { int CaretPos; FontDesc Font, HintFont; String Text; - int __TextHeight; - char __TextBuffer[STRING_SIZE]; + int _TextHeight; + char _TextBuffer[STRING_SIZE]; }; CC_NOINLINE void LInput_Init(struct LInput* w, int width, int height, const char* hintText, const FontDesc* hintFont); CC_NOINLINE void LInput_SetText(struct LInput* w, const String* text, const FontDesc* font); @@ -84,15 +85,15 @@ CC_NOINLINE bool LInput_Backspace(struct LInput* w); CC_NOINLINE bool LInput_Delete(struct LInput* w); /* Resets the currently entered text to an empty string. */ CC_NOINLINE bool LInput_Clear(struct LInput* w); -/* Sets the currently entered text to the contents of the system clipboard. */ -CC_NOINLINE bool LInput_CopyFromClipboard(struct LInput* w, const String* text); +/* Appends the contents of the system clipboard to the currently entered text. */ +CC_NOINLINE bool LInput_CopyFromClipboard(struct LInput* w); struct LLabel { LWidget_Layout FontDesc Font; String Text; - Size2D __TextSize; - char __TextBuffer[STRING_SIZE]; + Size2D _TextSize; + char _TextBuffer[STRING_SIZE]; }; CC_NOINLINE void LLabel_Init(struct LLabel* w); CC_NOINLINE void LLabel_SetText(struct LLabel* w, const String* text, const FontDesc* font); diff --git a/src/Launcher.c b/src/Launcher.c index 3f7b50b18..1885a5aef 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -10,6 +10,7 @@ #include "Window.h" #include "GameStructs.h" #include "Event.h" +#include "AsyncDownloader.h" struct LScreen* Launcher_Screen; bool Launcher_Dirty; @@ -17,6 +18,7 @@ Rect2D Launcher_DirtyArea; Bitmap Launcher_Framebuffer; bool Launcher_ClassicBackground; FontDesc Launcher_TitleFont, Launcher_TextFont; +FontDesc Launcher_InputHintFont; bool Launcher_ShouldExit, Launcher_ShouldUpdate; TimeMS Launcher_PatchTime; @@ -33,33 +35,31 @@ void Launcher_ShowError(ReturnCode res, const char* place) { } /* TODO: FIX THESE STUBS!!! */ -void Launcher_SecureSetOpt(const char* opt, const String* data, const String* key) { } -/* TODO: FIX */ -/* internal UpdateCheckTask checkTask; */ +//void Launcher_SecureSetOpt(const char* opt, const String* data, const String* key) { } +internal UpdateCheckTask checkTask; static bool fullRedraw, pendingRedraw; static FontDesc logoFont; -static void Launcher_RedrawAll(void) { +static void Launcher_RedrawAll(void* obj) { Launcher_ResetPixels(); if (Launcher_Screen) Launcher_Screen->DrawAll(Launcher_Screen); fullRedraw = true; } -static void Launcher_ReqeustRedraw(void) { +static void Launcher_ReqeustRedraw(void* obj) { /* We may get multiple Redraw events in short timespan */ /* So we just request a redraw at next launcher tick */ pendingRedraw = true; Launcher_Dirty = true; } -/* updates window state on resize and redraws contents. */ -static void Launcher_OnResize(void) { +static void Launcher_OnResize(void* obj) { Game_UpdateClientSize(); Launcher_Framebuffer.Width = Game_Width; Launcher_Framebuffer.Height = Game_Height; Window_InitRaw(&Launcher_Framebuffer); - Launcher_RedrawAll(); + Launcher_RedrawAll(NULL); } void Launcher_SetScreen(struct LScreen* screen) { @@ -69,24 +69,22 @@ void Launcher_SetScreen(struct LScreen* screen) { screen->Init(screen); /* for hovering over active button etc */ - /* TODO: FIX */ - /* screen->MouseMove(screen, 0, 0); */ + screen->MouseMove(screen, 0, 0); } -/* TODO FIX */ -/* static void Launcher_Init(void) { BitmapCol col = BITMAPCOL_CONST(125, 125, 125, 255); Event_RegisterVoid(&WindowEvents_Resized, NULL, Launcher_OnResize); Event_RegisterVoid(&WindowEvents_StateChanged, NULL, Launcher_OnResize); - Window.FocusedChanged += RedrawAll; - Window.Redraw += RedrawPending; + Event_RegisterVoid(&WindowEvents_FocusChanged, NULL, Launcher_RedrawAll); + Event_RegisterVoid(&WindowEvents_Redraw, NULL, Launcher_ReqeustRedraw); Keyboard.KeyDown += KeyDown; Font_Make(&logoFont, &Drawer2D_FontName, 32, FONT_STYLE_NORMAL); Font_Make(&Launcher_TitleFont, &Drawer2D_FontName, 16, FONT_STYLE_BOLD); Font_Make(&Launcher_TextFont, &Drawer2D_FontName, 14, FONT_STYLE_NORMAL); + Font_Make(&Launcher_HintFont, &Drawer2D_FontName, 12, FONT_STYLE_ITALIC); Drawer2D_Cols['g'] = col; Utils_EnsureDirectory("texpacks"); @@ -96,9 +94,8 @@ static void Launcher_Init(void) { void Dispose() { Event_UnregisterVoid(&WindowEvents_Resized, NULL, Launcher_OnResize); Event_UnregisterVoid(&WindowEvents_StateChanged, NULL, Launcher_OnResize); - - Window.FocusedChanged -= RedrawAll; - Window.Redraw -= RedrawPending; + Event_UnregisterVoid(&WindowEvents_FocusChanged, NULL, Launcher_RedrawAll); + Event_UnregisterVoid(&WindowEvents_Redraw, NULL, Launcher_ReqeustRedraw); Keyboard.KeyDown -= KeyDown; List bitmaps = FetchFlagsTask.Bitmaps; @@ -110,6 +107,7 @@ void Dispose() { Font_Free(&logoFont); Font_Free(&Launcher_TitleFont); Font_Free(&Launcher_TextFont); + Font_Free(&Launcher_HintFont); } void Run() { @@ -128,8 +126,7 @@ void Run() { Launcher_Framebuffer.Height = Game_Height; Window_InitRaw(&Launcher_Framebuffer); - Downloader = new AsyncDownloader(Drawer); - Downloader.Init(""); + AsyncDownloader_Component.Init(); Downloader.Cookies = new CookieContainer(); Downloader.KeepAlive = true; @@ -187,7 +184,7 @@ void Display() { Window_DrawRaw(rec); DirtyArea = Rectangle.Empty; fullRedraw = false; -}*/ +} static bool Launcher_IsShutdown(Key key) { if (key == KEY_F4 && Key_IsAltPressed()) return true; @@ -428,7 +425,7 @@ bool Launcher_StartGame(const String* user, const String* mppass, const String* Options_Set("launcher-username", user); Options_Set("launcher-ip", ip); Options_Set("launcher-port", port); - Launcher_SecureSetOpt("launcher-mppass", mppass, user); + Launcher_SaveSecureOpt("launcher-mppass", mppass, user); Options_Save(); } diff --git a/src/Launcher.h b/src/Launcher.h index 1263dffff..bc530a2f1 100644 --- a/src/Launcher.h +++ b/src/Launcher.h @@ -19,6 +19,8 @@ extern Bitmap Launcher_Framebuffer; extern bool Launcher_ClassicBackground; /* Default font for buttons and labels. */ extern FontDesc Launcher_TitleFont, Launcher_TextFont; +/* Default font for input widget hints. */ +extern FontDesc Launcher_HintFont; /* Whether at the next tick, the launcher window should proceed to stop displaying frames and subsequently exit. */ extern bool Launcher_ShouldExit; @@ -77,7 +79,10 @@ void Launcher_Run(void); void Launcher_ShowError(ReturnCode res, const char* place); /* Attempts to securely encode an option. */ /* NOTE: Not all platforms support secure saving, DO NOT rely on this being secure. */ -void Launcher_SecureSetOpt(const char* opt, const String* data, const String* key); +void Launcher_SaveSecureOpt(const char* opt, const String* data, const String* key); +/* Attempts to securely decode an option. */ +/* NOTE: Not all platforms support secure saving, DO NOT rely on this being secure. */ +void Launcher_LoadSecureOpt(const char* opt, String* data, const String* key); /* Starts the game from the given arguments. */ bool Launcher_StartGame(const String* user, const String* mppass, const String* ip, const String* port, const String* server); diff --git a/src/Screens.c b/src/Screens.c index 108e20e13..3f840ba20 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -1093,12 +1093,6 @@ static void ChatScreen_ContextRecreated(void* screen) { struct ChatScreen* s = screen; ChatScreen_ConstructWidgets(s); ChatScreen_SetInitialMessages(s); -} - -static void ChatScreen_FontChanged(void* screen) { - struct ChatScreen* s = screen; - if (!Drawer2D_BitmappedText) return; - Elem_Recreate(s); ChatScreen_UpdateChatYOffset(s, true); } @@ -1123,9 +1117,8 @@ static void ChatScreen_Init(void* screen) { Drawer2D_MakeFont(&s->AnnouncementFont, largeSize, FONT_STYLE_NORMAL); Screen_CommonInit(s); - Event_RegisterChat(&ChatEvents_ChatReceived, s, ChatScreen_ChatReceived); - Event_RegisterVoid(&ChatEvents_FontChanged, s, ChatScreen_FontChanged); - Event_RegisterInt(&ChatEvents_ColCodeChanged, s, ChatScreen_ColCodeChanged); + Event_RegisterChat(&ChatEvents_ChatReceived, s, ChatScreen_ChatReceived); + Event_RegisterInt(&ChatEvents_ColCodeChanged, s, ChatScreen_ColCodeChanged); } static void ChatScreen_Render(void* screen, double delta) { @@ -1183,9 +1176,8 @@ static void ChatScreen_Free(void* screen) { Font_Free(&s->AnnouncementFont); Screen_CommonFree(s); - Event_UnregisterChat(&ChatEvents_ChatReceived, s, ChatScreen_ChatReceived); - Event_UnregisterVoid(&ChatEvents_FontChanged, s, ChatScreen_FontChanged); - Event_UnregisterInt(&ChatEvents_ColCodeChanged, s, ChatScreen_ColCodeChanged); + Event_UnregisterChat(&ChatEvents_ChatReceived, s, ChatScreen_ChatReceived); + Event_UnregisterInt(&ChatEvents_ColCodeChanged, s, ChatScreen_ColCodeChanged); } static struct ScreenVTABLE ChatScreen_VTABLE = {