Fix /client model being broken

This commit is contained in:
UnknownShadow200 2018-12-02 23:52:28 +11:00
parent 1513a20cd3
commit 40cadd9316
10 changed files with 563 additions and 16 deletions

View File

@ -129,7 +129,11 @@ namespace ClassicalSharp.Commands {
} }
public override void Execute(string[] args) { public override void Execute(string[] args) {
foreach (IGameComponent comp in game.Components) { comp.Dispose(); } if (args.Length == 1) {
game.Chat.Add("&e/client model: &cYou didn't specify a model name.");
} else {
game.LocalPlayer.SetModel(args[1]);
}
} }
} }

View File

@ -210,6 +210,8 @@
<ClInclude Include="Gui.h" /> <ClInclude Include="Gui.h" />
<ClInclude Include="HeldBlockRenderer.h" /> <ClInclude Include="HeldBlockRenderer.h" />
<ClInclude Include="Launcher.h" /> <ClInclude Include="Launcher.h" />
<ClInclude Include="LScreens.h" />
<ClInclude Include="LWeb.h" />
<ClInclude Include="LWidgets.h" /> <ClInclude Include="LWidgets.h" />
<ClInclude Include="Model.h" /> <ClInclude Include="Model.h" />
<ClInclude Include="Input.h" /> <ClInclude Include="Input.h" />
@ -273,6 +275,8 @@
<ClCompile Include="InputHandler.c" /> <ClCompile Include="InputHandler.c" />
<ClCompile Include="Inventory.c" /> <ClCompile Include="Inventory.c" />
<ClCompile Include="Launcher.c" /> <ClCompile Include="Launcher.c" />
<ClCompile Include="LScreens.c" />
<ClCompile Include="LWeb.c" />
<ClCompile Include="LWidgets.c" /> <ClCompile Include="LWidgets.c" />
<ClCompile Include="MapGenerator.c" /> <ClCompile Include="MapGenerator.c" />
<ClCompile Include="Deflate.c" /> <ClCompile Include="Deflate.c" />

View File

@ -312,6 +312,12 @@
<ClInclude Include="LWidgets.h"> <ClInclude Include="LWidgets.h">
<Filter>Header Files\Launcher</Filter> <Filter>Header Files\Launcher</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="LWeb.h">
<Filter>Header Files\Launcher</Filter>
</ClInclude>
<ClInclude Include="LScreens.h">
<Filter>Header Files\Launcher</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="String.c"> <ClCompile Include="String.c">
@ -557,5 +563,11 @@
<ClCompile Include="LWidgets.c"> <ClCompile Include="LWidgets.c">
<Filter>Source Files\Launcher</Filter> <Filter>Source Files\Launcher</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="LWeb.c">
<Filter>Source Files\Launcher</Filter>
</ClCompile>
<ClCompile Include="LScreens.c">
<Filter>Source Files\Launcher</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

149
src/LScreens.c Normal file
View File

@ -0,0 +1,149 @@
#include "LScreens.h"
#include "LWidgets.h"
#include "Launcher.h"
#include "Gui.h"
static void LScreen_NullFunc(struct LScreen* s) { }
static void LScreen_DrawAll(struct LScreen* s) {
struct LWidget* widget;
int i;
for (i = 0; i < s->NumWidgets; i++) {
widget = s->Widgets[i];
widget->VTABLE->Redraw(widget);
}
}
static void LScreen_HoverWidget(struct LScreen* s, struct LWidget* w) {
if (!w) return;
w->Hovered = true;
if (w->VTABLE->OnHover) w->VTABLE->OnHover(w);
}
static void LScreen_UnhoverWidget(struct LScreen* s, struct LWidget* w) {
if (!w) return;
w->Hovered = false;
if (w->VTABLE->OnUnhover) w->VTABLE->OnUnhover(w);
}
CC_NOINLINE static void LScreen_Reset(struct LScreen* s) {
int i;
s->Init = NULL; /* screens should always override this */
s->Free = LScreen_NullFunc;
s->DrawAll = LScreen_DrawAll;
s->Tick = LScreen_NullFunc;
s->OnDisplay = LScreen_NullFunc;
s->HoverWidget = LScreen_HoverWidget;
s->UnhoverWidget = LScreen_UnhoverWidget;
/* reset all widgets to unselected */
for (i = 0; i < s->NumWidgets; i++) {
s->Widgets[i]->Hovered = false;
}
}
/*########################################################################################################################*
*---------------------------------------------------------Widget init-----------------------------------------------------*
*#########################################################################################################################*/
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) {
String str = String_FromReadonly(text);
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);
}
CC_NOINLINE static void LScreen_Label(struct LScreen* s, struct LLabel* w, const char* text,
uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
String str = String_FromReadonly(text);
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_Slider(struct LScreen* s, struct LSlider* w, int width, int height,
int initValue, int maxValue, BitmapCol progressCol,
uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
LSlider_Init(w, width, height);
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);
}
/*########################################################################################################################*
*--------------------------------------------------------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 SettingsScreen_InitWidgets(struct SettingsScreen* s) {
struct LScreen* s_ = (struct LScreen*)s;
LScreen_Button(s_, &s->BtnUpdates, 110, 35, "Updates",
ANCHOR_CENTRE, ANCHOR_CENTRE, -135, -120);
LScreen_Label(s_, &s->LblUpdates, "&eGet the latest stuff",
ANCHOR_CENTRE, ANCHOR_CENTRE, 10, -120);
LScreen_Button(s_, &s->BtnMode, 110, 35, "Mode",
ANCHOR_CENTRE, ANCHOR_CENTRE, -135, -70);
LScreen_Label(s_, &s->LblMode, "&eChange the enabled features",
ANCHOR_CENTRE, ANCHOR_CENTRE, 55, -70);
LScreen_Button(s_, &s->BtnColours, 110, 35, "Colours",
ANCHOR_CENTRE, ANCHOR_CENTRE, -135, -20);
LScreen_Label(s_, &s->LblColours, "&eChange how the launcher looks",
ANCHOR_CENTRE, ANCHOR_CENTRE, 65, -20);
LScreen_Button(s_, &s->BtnBack, 80, 35, "Back",
ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 170);
}
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_Init(struct LScreen* s_) {
struct SettingsScreen* s = (struct SettingsScreen*)s_;
if (!s->NumWidgets) SettingsScreen_InitWidgets(s);
s->BtnColours.Hidden = Launcher_ClassicBackground;
s->LblColours.Hidden = Launcher_ClassicBackground;
s->BtnMode.OnClick = SwitchToChooseMode;
s->BtnUpdates.OnClick = SwitchToUpdates;
s->BtnColours.OnClick = SwitchToColours;
s->BtnBack.OnClick = SwitchToMain;
s->DrawAll(s);
}
struct LScreen* SettingsScreen_MakeInstance(void) {
struct SettingsScreen* s = &SettingsScreen_Instance;
LScreen_Reset((struct LScreen*)s);
s->Init = SettingsScreen_Init;
return (struct LScreen*)s;
}
*/

41
src/LScreens.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef CC_LSCREENS_H
#define CC_LSCREENS_H
#include "AsyncDownloader.h"
#include "String.h"
/* Implements screens/menus for the launcher.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
*/
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. */ \
LScreen_Func Free; /* Cleans up all native resources. */ \
LScreen_Func DrawAll; /* Redraws all widgets. */ \
LScreen_Func Tick; /* Repeatedly called multiple times every second. */ \
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* HoveredWidget; /* Widget the mouse is currently hovering over. */ \
int NumWidgets; /* Number of widgets actually used. */
struct LScreen {
LScreen_Layout
/* All widgets in the screen. */
/* NOTE: This is vriable sized, so must be the last member. */
/* (e.g. derived screens might use: struct LWidget* Widgets[10];) */
struct LWidget** Widgets;
};
struct LScreen* ChooseModeScreen_MakeInstance(void);
struct LScreen* ColoursScreen_MakeInstance(void);
struct LScreen* DirectConnectScreen_MakeInstance(void);
struct LScreen* MainScreen_MakeInstance(void);
struct LScreen* ResourcesScreen_MakeInstance(void);
struct LScreen* ServersScreen_MakeInstance(void);
struct LScreen* SettingsScreen_MakeInstance(void);
struct LScreen* UpdateScreen_MakeInstance(void);
#endif

277
src/LWeb.c Normal file
View File

@ -0,0 +1,277 @@
#include "LWeb.h"
#include "Platform.h"
static void LWebTask_Reset(struct LWebTask* task) {
task->Completed = false;
task->Success = false;
task->Start = DateTime_CurrentUTC_MS();
}
void LWebTask_StartAsync(struct LWebTask* task) {
LWebTask_Reset(task);
task->Begin(task);
}
void LWebTask_Tick(struct LWebTask* task) {
struct AsyncRequest req;
int delta;
if (task->Completed) return;
if (!AsyncDownloader_Get(&task->Identifier, &req)) return;
delta = (int)(DateTime_CurrentUTC_MS() - task->Start);
Platform_Log2("%s took %i", &task->Identifier, &delta);
task->Completed = true;
task->Success = req.ResultData && req.ResultSize;
if (task->Success) task->Handle(task, req.ResultData, req.ResultSize);
}
static void LWebTask_DefaultBegin(struct LWebTask* task) {
AsyncDownloader_GetData(&task->URL, false, &task->Identifier);
}
/*protected static JsonObject ParseJson(Request req) {
JsonContext ctx = new JsonContext();
ctx.Val = (string)req.Data;
return (JsonObject)Json.ParseStream(ctx);
}
public sealed class GetCSRFTokenTask : WebTask {
public GetCSRFTokenTask() {
identifier = "CC get login";
uri = "https://www.classicube.net/api/login/";
}
public string Token;
protected override void Handle(Request req) {
JsonObject data = ParseJson(req);
Token = (string)data["token"];
}
}
public sealed class SignInTask : WebTask {
public SignInTask() {
identifier = "CC post login";
uri = "https://www.classicube.net/api/login/";
}
public string Username, Password, Token, Error;
protected override void Begin() {
string data = String.Format(
"username={0}&password={1}&token={2}",
Uri.EscapeDataString(Username),
Uri.EscapeDataString(Password),
Uri.EscapeDataString(Token)
);
Game.Downloader.AsyncPostString(uri, false, identifier, data);
}
protected override void Handle(Request req) {
JsonObject data = ParseJson(req);
Error = GetLoginError(data);
Username = (string)data["username"];
}
static string GetLoginError(JsonObject obj) {
List<object> errors = (List<object>)obj["errors"];
if (errors.Count == 0) return null;
string err = (string)errors[0];
if (err == "username" || err == "password") return "Wrong username or password";
if (err == "verification") return "Account verification required";
return "Unknown error occurred";
}
}
public class ServerListEntry {
public string Hash, Name, Players, MaxPlayers, Flag;
public string Uptime, IPAddress, Port, Mppass, Software;
public bool Featured;
}
public sealed class FetchServerTask : WebTask {
public FetchServerTask(string user, string hash) {
Username = user;
identifier = "CC get servers";
uri = "https://www.classicube.net/api/server/" + hash;
}
public static ServerListEntry ParseEntry(JsonObject obj) {
ServerListEntry entry = new ServerListEntry();
entry.Hash = (string)obj["hash"];
entry.Name = (string)obj["name"];
entry.Players = (string)obj["players"];
entry.MaxPlayers = (string)obj["maxplayers"];
entry.Uptime = (string)obj["uptime"];
entry.Mppass = (string)obj["mppass"];
entry.IPAddress = (string)obj["ip"];
entry.Port = (string)obj["port"];
entry.Software = (string)obj["software"];
if (obj.ContainsKey("featured")) {
entry.Featured = (bool)obj["featured"];
}
if (obj.ContainsKey("country_abbr")) {
entry.Flag = Utils.ToLower((string)obj["country_abbr"]);
}
return entry;
}
public string Username;
public ClientStartData Info;
protected override void Handle(Request req) {
JsonObject root = ParseJson(req);
List<object> list = (List<object>)root["servers"];
JsonObject obj = (JsonObject)list[0];
ServerListEntry entry = ParseEntry(obj);
Info = new ClientStartData(Username, entry.Mppass, entry.IPAddress, entry.Port, entry.Name);
}
}
public sealed class FetchServersTask : WebTask {
public FetchServersTask() {
identifier = "CC get servers";
uri = "https://www.classicube.net/api/servers";
}
public List<ServerListEntry> Servers;
protected override void Reset() {
base.Reset();
Servers = new List<ServerListEntry>();
}
protected override void Handle(Request req) {
JsonObject root = ParseJson(req);
List<object> list = (List<object>)root["servers"];
for (int i = 0; i < list.Count; i++) {
JsonObject obj = (JsonObject)list[i];
ServerListEntry entry = FetchServerTask.ParseEntry(obj);
Servers.Add(entry);
}
}
}
public class Build {
public DateTime TimeBuilt;
public string DirectXPath, OpenGLPath;
public int DirectXSize, OpenGLSize;
public string Version;
}
public sealed class UpdateCheckTask : WebTask {
public UpdateCheckTask() {
identifier = "CC update check";
uri = "http://cs.classicube.net/builds.json";
}
public Build LatestDev, LatestStable;
protected override void Handle(Request req) {
JsonObject data = ParseJson(req);
JsonObject latest = (JsonObject)data["latest"];
LatestDev = MakeBuild(latest, false);
JsonObject releases = (JsonObject)data["releases"];
DateTime releaseTime = DateTime.MinValue;
foreach(KeyValuePair<string, object> pair in releases) {
Build build = MakeBuild((JsonObject)pair.Value, true);
if (build.TimeBuilt < releaseTime) continue;
LatestStable = build;
releaseTime = build.TimeBuilt;
}
}
static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
Build MakeBuild(JsonObject obj, bool release) {
Build build = new Build();
string timeKey = release ? "release_ts" : "ts";
double rawTime = Double.Parse((string)obj[timeKey], CultureInfo.InvariantCulture);
build.TimeBuilt = epoch.AddSeconds(rawTime).ToLocalTime();
build.DirectXSize = Int32.Parse((string)obj["dx_size"]);
build.DirectXPath = (string)obj["dx_file"];
build.OpenGLSize = Int32.Parse((string)obj["ogl_size"]);
build.OpenGLPath = (string)obj["ogl_file"];
if (obj.ContainsKey("version"))
build.Version = (string)obj["version"];
return build;
}
}
public sealed class UpdateDownloadTask : WebTask {
public UpdateDownloadTask(string dir) {
identifier = "CC update download";
uri = "http://cs.classicube.net/" + dir;
}
public byte[] ZipFile;
protected override void Begin() {
Game.Downloader.AsyncGetData(uri, false, identifier);
}
protected override void Handle(Request req) {
ZipFile = (byte[])req.Data;
}
}
public sealed class UpdateCClientTask : WebTask {
public UpdateCClientTask(string file) {
identifier = "CC CClient download";
uri = "http://cs.classicube.net/c_client/latest/" + file;
}
public byte[] File;
protected override void Begin() {
Game.Downloader.AsyncGetData(uri, false, identifier);
}
protected override void Handle(Request req) {
File = (byte[])req.Data;
}
}
public sealed class FetchFlagsTask : WebTask {
public FetchFlagsTask() {
identifier = "CC get flag";
}
public bool PendingRedraw;
public static int DownloadedCount;
public static List<string> Flags = new List<string>();
public static List<FastBitmap> Bitmaps = new List<FastBitmap>();
public void AsyncGetFlag(string flag) {
for (int i = 0; i < Flags.Count; i++) {
if (Flags[i] == flag) return;
}
Flags.Add(flag);
}
protected override void Begin() {
if (Flags.Count == DownloadedCount) return;
uri = "http://static.classicube.net/img/flags/" + Flags[DownloadedCount] + ".png";
Game.Downloader.AsyncGetImage(uri, false, identifier);
}
protected override void Handle(Request req) {
Bitmap bmp = (Bitmap)req.Data;
FastBitmap fast = new FastBitmap(bmp, true, true);
Bitmaps.Add(fast);
DownloadedCount++;
PendingRedraw = true;
Reset();
Begin();
}
}
}*/

30
src/LWeb.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef CC_LWEB_H
#define CC_LWEB_H
#include "AsyncDownloader.h"
#include "String.h"
/* Implements asynchronous web tasks for the launcher.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
*/
struct LWebTask;
struct LWebTask {
/* Whether the task has finished executing. */
bool Completed;
/* Whether the task completed successfully. */
bool Success;
ReturnCode Res;
/* Unique identifier for this web task. */
String Identifier;
/* URL this task is downloading from/uploading to. */
String URL;
/* Point in time this task was started at. */
TimeMS Start;
/* Function called to begin downloading/uploading. */
void (*Begin)(struct LWebTask* task);
/* Called when task successfully downloaded/uploaded data. */
void (*Handle)(struct LWebTask* task, uint8_t* data, uint32_t len);
};
void LWebTask_StartAsync(struct LWebTask* task);
void LWebTask_Tick(struct LWebTask* task);
#endif

View File

@ -20,7 +20,7 @@ void LWidget_CalcPosition(void* widget) {
void LWidget_Reset(void* widget) { void LWidget_Reset(void* widget) {
struct LWidget* w = widget; struct LWidget* w = widget;
w->Active = false; w->Hovered = false;
w->Hidden = false; w->Hidden = false;
w->X = 0; w->Y = 0; w->X = 0; w->Y = 0;
w->Width = 0; w->Height = 0; w->Width = 0; w->Height = 0;
@ -30,7 +30,7 @@ void LWidget_Reset(void* widget) {
w->TabSelectable = false; w->TabSelectable = false;
w->OnClick = NULL; w->OnClick = NULL;
w->Redraw = NULL; w->VTABLE = NULL;
} }
@ -52,12 +52,12 @@ static void LButton_DrawBackground(struct LButton* w) {
BitmapCol col; BitmapCol col;
if (Launcher_ClassicBackground) { if (Launcher_ClassicBackground) {
col = w->Active ? activeCol : inactiveCol; col = w->Hovered ? activeCol : inactiveCol;
Gradient_Noise(&Launcher_Framebuffer, col, 8, Gradient_Noise(&Launcher_Framebuffer, col, 8,
w->X + BTN_BORDER, w->Y + BTN_BORDER, w->X + BTN_BORDER, w->Y + BTN_BORDER,
w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER); w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER);
} else { } else {
col = w->Active ? Launcher_ButtonForeActiveCol : Launcher_ButtonForeCol; col = w->Hovered ? Launcher_ButtonForeActiveCol : Launcher_ButtonForeCol;
Gradient_Vertical(&Launcher_Framebuffer, LButton_Expand(col, 8), LButton_Expand(col, -8), Gradient_Vertical(&Launcher_Framebuffer, LButton_Expand(col, 8), LButton_Expand(col, -8),
w->X + BTN_BORDER, w->Y + BTN_BORDER, w->X + BTN_BORDER, w->Y + BTN_BORDER,
w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER); w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER);
@ -88,14 +88,14 @@ static void LButton_DrawHighlight(struct LButton* w) {
BitmapCol highlightCol; BitmapCol highlightCol;
if (Launcher_ClassicBackground) { if (Launcher_ClassicBackground) {
highlightCol = w->Active ? activeCol : inactiveCol; highlightCol = w->Hovered ? activeCol : inactiveCol;
Drawer2D_Clear(&Launcher_Framebuffer, highlightCol, Drawer2D_Clear(&Launcher_Framebuffer, highlightCol,
w->X + BTN_BORDER * 2, w->Y + BTN_BORDER, w->X + BTN_BORDER * 2, w->Y + BTN_BORDER,
w->Width - BTN_BORDER * 4, BTN_BORDER); w->Width - BTN_BORDER * 4, BTN_BORDER);
Drawer2D_Clear(&Launcher_Framebuffer, highlightCol, Drawer2D_Clear(&Launcher_Framebuffer, highlightCol,
w->X + BTN_BORDER, w->Y + BTN_BORDER * 2, w->X + BTN_BORDER, w->Y + BTN_BORDER * 2,
BTN_BORDER, w->Height - BTN_BORDER * 4); BTN_BORDER, w->Height - BTN_BORDER * 4);
} else if (!w->Active) { } else if (!w->Hovered) {
Drawer2D_Clear(&Launcher_Framebuffer, Launcher_ButtonHighlightCol, Drawer2D_Clear(&Launcher_Framebuffer, Launcher_ButtonHighlightCol,
w->X + BTN_BORDER * 2, w->Y + BTN_BORDER, w->X + BTN_BORDER * 2, w->Y + BTN_BORDER,
w->Width - BTN_BORDER * 4, BTN_BORDER); w->Width - BTN_BORDER * 4, BTN_BORDER);
@ -116,17 +116,22 @@ static void LButton_Redraw(void* widget) {
LButton_DrawBorder(w); LButton_DrawBorder(w);
LButton_DrawHighlight(w); LButton_DrawHighlight(w);
if (!w->Active) Drawer2D_Cols['f'] = Drawer2D_Cols['7']; if (!w->Hovered) Drawer2D_Cols['f'] = Drawer2D_Cols['7'];
Drawer2D_DrawText(&Launcher_Framebuffer, &args, Drawer2D_DrawText(&Launcher_Framebuffer, &args,
w->X + xOffset / 2, w->Y + yOffset / 2); w->X + xOffset / 2, w->Y + yOffset / 2);
if (!w->Active) Drawer2D_Cols['f'] = Drawer2D_Cols['F'];
if (!w->Hovered) Drawer2D_Cols['f'] = Drawer2D_Cols['F'];
Launcher_Dirty = true;
} }
static struct LWidgetVTABLE lbutton_VTABLE = {
LButton_Redraw, LButton_Redraw, LButton_Redraw, NULL, NULL
};
void LButton_Init(struct LButton* w, int width, int height) { void LButton_Init(struct LButton* w, int width, int height) {
Widget_Reset(w); Widget_Reset(w);
w->VTABLE = &lbutton_VTABLE;
w->TabSelectable = true; w->TabSelectable = true;
w->Width = width; w->Height = height; w->Width = width; w->Height = height;
w->Redraw = LButton_Redraw;
String_InitArray(w->Text, w->__TextBuffer); String_InitArray(w->Text, w->__TextBuffer);
} }
@ -186,7 +191,7 @@ bool LInput_Backspace(struct LInput* w) {
if (w->CaretPos == -1) w->CaretPos = 0; if (w->CaretPos == -1) w->CaretPos = 0;
} }
if (w->TextChanged) TextChanged(w); if (w->TextChanged) w->TextChanged(w);
if (w->CaretPos >= w->Text.length) w->CaretPos = -1; if (w->CaretPos >= w->Text.length) w->CaretPos = -1;
return true; return true;
} }
@ -225,11 +230,15 @@ static void LLabel_Redraw(void* widget) {
DrawTextArgs_Make(&args, &w->Text, &w->Font, true); DrawTextArgs_Make(&args, &w->Text, &w->Font, true);
Drawer2D_DrawText(&Launcher_Framebuffer, &args, w->X, w->Y); Drawer2D_DrawText(&Launcher_Framebuffer, &args, w->X, w->Y);
Launcher_Dirty = true;
} }
static struct LWidgetVTABLE llabel_VTABLE = {
LLabel_Redraw, NULL, NULL, NULL, NULL
};
void LLabel_Init(struct LLabel* w) { void LLabel_Init(struct LLabel* w) {
Widget_Reset(w); Widget_Reset(w);
w->Redraw = LLabel_Redraw; w->VTABLE = &llabel_VTABLE;
String_InitArray(w->Text, w->__TextBuffer); String_InitArray(w->Text, w->__TextBuffer);
} }
@ -287,11 +296,15 @@ static void LSlider_Redraw(void* widget) {
Drawer2D_Clear(&Launcher_Framebuffer, w->ProgressCol, Drawer2D_Clear(&Launcher_Framebuffer, w->ProgressCol,
w->X, w->Y, (int)(w->Width * w->Value / w->MaxValue), w->Height); w->X, w->Y, (int)(w->Width * w->Value / w->MaxValue), w->Height);
Launcher_Dirty = true;
} }
static struct LWidgetVTABLE lslider_VTABLE = {
LSlider_Redraw, NULL, NULL, NULL, NULL
};
void LSlider_Init(struct LSlider* w, int width, int height) { void LSlider_Init(struct LSlider* w, int width, int height) {
Widget_Reset(w); Widget_Reset(w);
w->VTABLE = &lslider_VTABLE;
w->Width = width; w->Height = height; w->Width = width; w->Height = height;
w->Redraw = LSlider_Redraw;
w->MaxValue = 100; w->MaxValue = 100;
} }

View File

@ -7,15 +7,30 @@
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
*/ */
struct LWidgetVTABLE {
/* Called to redraw contents of this widget */
void (*Redraw)(void* widget);
/* Called when mouse hovers over this widget. */
void (*OnHover)(void* widget);
/* Called when mouse moves away from this widget. */
void (*OnUnhover)(void* widget);
/* Called when mouse clicks on this widget. */
/* NOTE: This function is just for general widget behaviour. */
/* OnClick callback is for per-widget instance behaviour. */
void (*OnSelected)(void* widget);
/* Called when mouse clicks on another widget. */
void (*OnUnselected)(void* widget);
};
#define LWidget_Layout \ #define LWidget_Layout \
struct LWidgetVTABLE* VTABLE; /* General widget functions */ \
int X, Y, Width, Height; /* Top left corner, and dimensions, of this widget */ \ int X, Y, Width, Height; /* Top left corner, and dimensions, of this widget */ \
bool Active; /* Whether this widget is currently being moused over*/ \ bool Hovered; /* Whether this widget is currently being moused over*/ \
bool Hidden; /* Whether this widget is hidden from view */ \ bool Hidden; /* Whether this widget is hidden from view */ \
bool TabSelectable; /* Whether this widget gets selected when pressing tab */ \ bool TabSelectable; /* Whether this widget gets selected when pressing tab */ \
uint8_t HorAnchor, VerAnchor; /* Specifies the reference point for when this widget is resized */ \ uint8_t HorAnchor, VerAnchor; /* Specifies the reference point for when this widget is resized */ \
int XOffset, YOffset; /* Offset from the reference point */ \ int XOffset, YOffset; /* Offset from the reference point */ \
void (*OnClick)(void* widget, int x, int y); /* Called when widget is clicked */ \ void (*OnClick)(void* widget, int x, int y); /* Called when widget is clicked */ \
void (*Redraw)(void* widget); /* Called to redraw contents of this widget */
/* Represents an individual 2D gui component in the launcher. */ /* Represents an individual 2D gui component in the launcher. */
struct LWidget { LWidget_Layout }; struct LWidget { LWidget_Layout };

View File

@ -17,6 +17,8 @@ extern Rect2D Launcher_DirtyArea;
extern Bitmap Launcher_Framebuffer; extern Bitmap Launcher_Framebuffer;
/* Whether to use stone tile background like minecraft.net. */ /* Whether to use stone tile background like minecraft.net. */
extern bool Launcher_ClassicBackground; extern bool Launcher_ClassicBackground;
/* Default font for buttons and labels. */
extern FontDesc Launcher_TitleFont, Launcher_TextFont;
/* Whether at the next tick, the launcher window should proceed to stop displaying frames and subsequently exit. */ /* Whether at the next tick, the launcher window should proceed to stop displaying frames and subsequently exit. */
extern bool Launcher_ShouldExit; extern bool Launcher_ShouldExit;