mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-16 19:15:14 -04:00
Fix more crashes and start working on JSON port
This commit is contained in:
parent
eb1e69b86b
commit
35b6fadc95
@ -24,7 +24,7 @@ CC_NOINLINE static struct LWidget* LScreen_WidgetAt(struct LScreen* s, int x, in
|
||||
w = s->Widgets[i];
|
||||
if (w->Hidden) continue;
|
||||
|
||||
if (Gui_Contains(w->X, w->Y, w->Width, w->Height, w->X, w->Y)) return w;
|
||||
if (Gui_Contains(w->X, w->Y, w->Width, w->Height, x, y)) return w;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -143,8 +143,10 @@ CC_NOINLINE static void LScreen_Reset(struct LScreen* s) {
|
||||
s->MouseDown = LScreen_MouseDown;
|
||||
s->MouseUp = LScreen_MouseUp;
|
||||
s->MouseMove = LScreen_MouseMove;
|
||||
s->HoverWidget = LScreen_HoverWidget;
|
||||
s->UnhoverWidget = LScreen_UnhoverWidget;
|
||||
s->HoverWidget = LScreen_HoverWidget;
|
||||
s->UnhoverWidget = LScreen_UnhoverWidget;
|
||||
s->SelectWidget = LScreen_SelectWidget;
|
||||
s->UnselectWidget = LScreen_UnselectWidget;
|
||||
|
||||
/* reset all widgets mouse state */
|
||||
for (i = 0; i < s->NumWidgets; i++) {
|
||||
|
@ -29,7 +29,7 @@ typedef void(*LWidget_Func)(struct LScreen* s, struct LWidget* w);
|
||||
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. */ \
|
||||
int NumWidgets; /* Number of widgets actually used. */ \
|
||||
int NumWidgets; /* Number of widgets actually used. */ \
|
||||
struct LWidget** Widgets; /* Array of pointers to all widgets in the screen. */
|
||||
|
||||
struct LScreen { LScreen_Layout };
|
||||
|
162
src/LWeb.c
162
src/LWeb.c
@ -1,6 +1,168 @@
|
||||
#include "LWeb.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#define TOKEN_NONE 0
|
||||
#define TOKEN_NUM 1
|
||||
#define TOKEN_TRUE 2
|
||||
#define TOKEN_FALSE 3
|
||||
#define TOKEN_NULL 4
|
||||
|
||||
struct JsonContext {
|
||||
/* Pointer to current character in JSON stream being inspected. */
|
||||
char* Cur;
|
||||
/* Number of characters left to be inspected. */
|
||||
int Left;
|
||||
/* Whether there was an error parsing the JSON. */
|
||||
bool Failed;
|
||||
/* Callback function invoked on each token read. */
|
||||
void (*OnToken)(char token);
|
||||
/* Callback function invoked on each member of an object or array. */
|
||||
/* NOTE: This only works for 'simple' key-value pairs. */ newarray
|
||||
void (*OnValue)(char token, String* value);
|
||||
};
|
||||
/* new array, new object functions?? */
|
||||
/* need to push/pop 'CurrentKey' */
|
||||
/* Consumes n characters from the JSON stream */
|
||||
#define JsonContext_Consume(ctx, n) ctx->Cur += n; ctx->Left -= n;
|
||||
|
||||
static String strTrue = String_FromConst("true");
|
||||
static String strFalse = String_FromConst("false");
|
||||
static String strNull = String_FromConst("null");
|
||||
|
||||
static bool Json_IsWhitespace(char c) {
|
||||
return c == '\r' || c == '\n' || c == '\t' || c == ' ';
|
||||
}
|
||||
|
||||
static bool Json_IsNumber(char c) {
|
||||
return c == '-' || c == '.' || (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static bool Json_ConsumeConstant(struct JsonContext* ctx, String* value) {
|
||||
int i;
|
||||
if (value->length > ctx->Left) return false;
|
||||
|
||||
for (i = 0; i < value->length; i++) {
|
||||
if (ctx->Cur[i] != value->buffer[i]) return false;
|
||||
}
|
||||
|
||||
JsonContext_Consume(ctx, value->length);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Json_ConsumeToken(struct JsonContext* ctx) {
|
||||
for (; ctx->Left && Json_IsWhitespace(*ctx->Cur); ) { JsonContext_Consume(ctx, 1); }
|
||||
if (!ctx->Left) return TOKEN_NONE;
|
||||
|
||||
char c = *ctx->Cur;
|
||||
if (c == '{' || c == '}' || c == '[' || c == ']' || c == ',' || c == '"' || c == ':') {
|
||||
JsonContext_Consume(ctx, 1); return c;
|
||||
}
|
||||
|
||||
/* number token forms part of value, don't consume it */
|
||||
if (Json_IsNumber(c)) return TOKEN_NUM;
|
||||
|
||||
if (Json_ConsumeConstant(ctx, &strTrue)) return TOKEN_TRUE;
|
||||
if (Json_ConsumeConstant(ctx, &strFalse)) return TOKEN_FALSE;
|
||||
if (Json_ConsumeConstant(ctx, &strNull)) return TOKEN_NULL;
|
||||
|
||||
/* invalid token */
|
||||
JsonContext_Consume(ctx, 1);
|
||||
return TOKEN_NONE;
|
||||
}
|
||||
|
||||
static String Json_ConsumeNumber(struct JsonContext* ctx) {
|
||||
int len = 0;
|
||||
for (; ctx->Left && Json_IsNumber(*ctx->Cur); len++) { JsonContext_Consume(ctx, 1); }
|
||||
return String_Init(ctx->Cur - len, len, len);
|
||||
}
|
||||
|
||||
static void Json_ConsumeObject(struct JsonContext* ctx) {
|
||||
int token; /* push and pop cur key */
|
||||
|
||||
while (true) {
|
||||
token = Json_ConsumeToken(ctx);
|
||||
if (token == ',') continue;
|
||||
if (token == '}') return;
|
||||
|
||||
if (token != '"') { ctx->Failed = true; return; }
|
||||
string key = ParseString(ctx);
|
||||
|
||||
token = Json_ConsumeToken(ctx);
|
||||
if (token != ':') { ctx->Failed = true; return; }
|
||||
|
||||
token = Json_ConsumeToken(ctx);
|
||||
if (token == TOKEN_NONE) { ctx->Failed = true; return; }
|
||||
|
||||
members[key] = ParseValue(token, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void Json_ConsumeArray(struct JsonContext* ctx) {
|
||||
int token;
|
||||
|
||||
while (true) {
|
||||
token = NextToken(ctx);
|
||||
if (token == ',') continue;
|
||||
if (token == ']') return;
|
||||
|
||||
if (token == TOKEN_NONE) { ctx->Failed = true; return; }
|
||||
elements.Add(ParseValue(token, ctx));
|
||||
}
|
||||
}
|
||||
|
||||
static string ParseString(struct JsonContext* ctx) {
|
||||
int codepoint, h[4];
|
||||
char c;
|
||||
StringBuilder s = ctx.strBuffer; s.Length = 0;
|
||||
|
||||
for (; ctx->Left;) {
|
||||
c = *ctx->Cur; JsonContext_Consume(ctx, 1);
|
||||
if (c == '"') return s.ToString();
|
||||
if (c != '\\') { s.Append(c); continue; }
|
||||
|
||||
/* form of \X */
|
||||
if (!ctx->Left) break;
|
||||
c = *ctx->Cur; JsonContext_Consume(ctx, 1);
|
||||
if (c == '/' || c == '\\' || c == '"') { s.Append(c); continue; }
|
||||
|
||||
/* form of \uYYYY */
|
||||
if (c != 'u' || ctx->Left < 4) break;
|
||||
|
||||
if (!PackedCol_Unhex(ctx->Cur[0], &h[0])) break;
|
||||
if (!PackedCol_Unhex(ctx->Cur[1], &h[1])) break;
|
||||
if (!PackedCol_Unhex(ctx->Cur[2], &h[2])) break;
|
||||
if (!PackedCol_Unhex(ctx->Cur[3], &h[3])) break;
|
||||
|
||||
codepoint = (h[0] << 12) | (h[1] << 8) | (h[2] << 4) | h[3];
|
||||
/* don't want control characters in names/software */
|
||||
if (codepoint >= 32) s.Append((char)codepoint);
|
||||
JsonContext_Consume(ctx, 4);
|
||||
}
|
||||
|
||||
ctx->Failed = true; return null;
|
||||
}
|
||||
|
||||
static String Json_ConsumeValue(int token, struct JsonContext* ctx) {
|
||||
switch (token) {
|
||||
case '{': return ParseObject(ctx);
|
||||
case '[': return ParseArray(ctx);
|
||||
case '"': return ParseString(ctx);
|
||||
|
||||
case TOKEN_NUM: return Json_ConsumeNumber(ctx);
|
||||
case TOKEN_TRUE: return strTrue;
|
||||
case TOKEN_FALSE: return strFalse;
|
||||
case TOKEN_NULL: break;
|
||||
}
|
||||
return String_Empty;
|
||||
}
|
||||
|
||||
|
||||
static object ParseStream(struct JsonContext* ctx) {
|
||||
return ParseValue(NextToken(ctx), ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void LWebTask_Reset(struct LWebTask* task) {
|
||||
task->Completed = false;
|
||||
task->Working = true;
|
||||
|
@ -10,7 +10,7 @@
|
||||
#define BORDER 1
|
||||
|
||||
void LWidget_SetLocation(void* widget, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
|
||||
struct Widget* w = widget;
|
||||
struct LWidget* w = widget;
|
||||
w->HorAnchor = horAnchor; w->VerAnchor = verAnchor;
|
||||
w->XOffset = xOffset; w->YOffset = yOffset;
|
||||
LWidget_CalcPosition(widget);
|
||||
|
@ -335,7 +335,6 @@ static void Launcher_ProcessZipEntry(const String* path, struct Stream* data, st
|
||||
if (res) {
|
||||
Launcher_ShowError(res, "decoding terrain.png"); return;
|
||||
} else {
|
||||
Drawer2D_SetFontBitmap(&bmp);
|
||||
Launcher_LoadTextures(&bmp);
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ ReturnCode Socket_Select(SocketHandle socket, int selectMode, bool* success);
|
||||
/* Initalises the platform specific http library state. */
|
||||
void Http_Init(void);
|
||||
/* Performs a http request, setting progress as data is received. */
|
||||
/* NOTE: NOT thread safe - you should always use AsyncDownloader for making requests. */
|
||||
/* NOTE: NOT thread safe - you should ALWAYS use AsyncDownloader for making requests. */
|
||||
ReturnCode Http_Do(struct AsyncRequest* req, volatile int* progress);
|
||||
/* Frees the platform specific http library state. */
|
||||
ReturnCode Http_Free(void);
|
||||
|
@ -88,7 +88,7 @@ void ServerConnection_CheckAsyncResources(void) {
|
||||
Chat_Add1("&cError %i when trying to download texture pack", &item.Result);
|
||||
} else {
|
||||
int status = item.StatusCode;
|
||||
if (status == 0 || status == 304) return;
|
||||
if (status == 200 || status == 304) return;
|
||||
Chat_Add1("&c%i error when trying to download texture pack", &status);
|
||||
}
|
||||
}
|
||||
|
14
src/Window.h
14
src/Window.h
@ -2,7 +2,7 @@
|
||||
#define CC_WINDOW_H
|
||||
#include "String.h"
|
||||
#include "Bitmap.h"
|
||||
/* Abstracts creating and managing a native window.
|
||||
/* Abstracts creating and managing the native window.
|
||||
Copyright 2017 ClassicalSharp | Licensed under BSD-3 | Based on OpenTK code
|
||||
*/
|
||||
|
||||
@ -31,23 +31,23 @@
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The states a window can be in. */
|
||||
/* The states the window can be in. */
|
||||
typedef enum WindowState_ {
|
||||
WINDOW_STATE_NORMAL, WINDOW_STATE_MINIMISED, WINDOW_STATE_MAXIMISED, WINDOW_STATE_FULLSCREEN
|
||||
} WindowState;
|
||||
struct GraphicsMode;
|
||||
|
||||
/* Creates a new window of the given size at centre of the screen, with default graphics mode. */
|
||||
/* Creates the window as the given size at centre of the screen, with default graphics mode. */
|
||||
void Window_CreateSimple(int width, int height);
|
||||
/* Creates a new window of the given size at the given position on screen. */
|
||||
/* Creates the window as the given size at the given position on screen. */
|
||||
void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mode);
|
||||
/* Sets the text of the titlebar above the window. */
|
||||
void Window_SetTitle(const String* title);
|
||||
/* Gets the text currently on the clipboard. */
|
||||
/* NOTE: You must have created a window beforehand. (necessary for X11) */
|
||||
/* NOTE: You MUST have created the window beforehand. (necessary for X11) */
|
||||
void Window_GetClipboardText(String* value);
|
||||
/* Sets the text currently on the clipboard. */
|
||||
/* NOTE: You must have created a window beforehand. (necessary for X11) */
|
||||
/* NOTE: You MUST have created the window beforehand. (necessary for X11) */
|
||||
void Window_SetClipboardText(const String* value);
|
||||
/* TODO: IMPLEMENT void Window_SetIcon(Bitmap* bmp); */
|
||||
|
||||
@ -100,7 +100,7 @@ void Window_SetScreenCursorPos(int x, int y);
|
||||
/* Whether the cursor is visible when over this window. */
|
||||
bool Window_GetCursorVisible(void);
|
||||
/* Sets whether the cursor is visible when over this window. */
|
||||
/* NOTE: You must be careful with this! OS typically uses a counter for visibility,
|
||||
/* NOTE: You MUST BE VERY CAREFUL with this! OS typically uses a counter for visibility,
|
||||
so setting invisible multiple times means you must then set visible multiple times. */
|
||||
void Window_SetCursorVisible(bool visible);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user