mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 10:35:11 -04:00
Merge pull request #759 from UnknownShadow200/UploadingStuff
Add upload support for maps/texture packs to webclient
This commit is contained in:
commit
52032a5a21
@ -64,7 +64,9 @@ void Map_LoadFrom(const cc_string* path) {
|
||||
if (res) { Logger_SysWarn2(res, "opening", path); return; }
|
||||
|
||||
importer = Map_FindImporter(path);
|
||||
if ((res = importer(&stream))) {
|
||||
if (!importer) {
|
||||
Logger_SysWarn2(ERR_NOT_SUPPORTED, "decoding", path);
|
||||
} else if ((res = importer(&stream))) {
|
||||
World_Reset();
|
||||
Logger_SysWarn2(res, "decoding", path);
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ void Game_TakeScreenshot(void) {
|
||||
String_Format3(&filename, "-%p2-%p2-%p2.png", &now.hour, &now.minute, &now.second);
|
||||
|
||||
#ifdef CC_BUILD_WEB
|
||||
Platform_ConvertString(str, &filename);
|
||||
Platform_EncodeString(str, &filename);
|
||||
EM_ASM_({
|
||||
var name = UTF8ToString($0);
|
||||
var canvas = Module['canvas'];
|
||||
|
@ -380,7 +380,7 @@ static void Http_DownloadAsync(struct HttpRequest* req) {
|
||||
|
||||
String_InitArray(url, urlBuffer);
|
||||
Http_BeginRequest(req, &url);
|
||||
Platform_ConvertString(urlStr, &url);
|
||||
Platform_EncodeString(urlStr, &url);
|
||||
|
||||
/* TODO: SET requestHeaders!!! */
|
||||
emscripten_fetch(&attr, urlStr);
|
||||
@ -605,7 +605,7 @@ static cc_result Http_BackendDo(struct HttpRequest* req, cc_string* url) {
|
||||
_curl_easy_setopt(curl, CURLOPT_HTTPHEADER, req->meta);
|
||||
|
||||
Http_SetCurlOpts(req);
|
||||
Platform_ConvertString(urlStr, url);
|
||||
Platform_EncodeString(urlStr, url);
|
||||
_curl_easy_setopt(curl, CURLOPT_URL, urlStr);
|
||||
|
||||
if (req->requestType == REQUEST_TYPE_HEAD) {
|
||||
|
81
src/Menus.c
81
src/Menus.c
@ -175,11 +175,11 @@ struct ListScreen;
|
||||
static struct ListScreen {
|
||||
Screen_Body
|
||||
struct ButtonWidget btns[LIST_SCREEN_ITEMS];
|
||||
struct ButtonWidget left, right, done;
|
||||
struct ButtonWidget left, right, done, upload;
|
||||
struct FontDesc font;
|
||||
float wheelAcc;
|
||||
int currentIndex;
|
||||
Widget_LeftClick EntryClick, DoneClick;
|
||||
Widget_LeftClick EntryClick, DoneClick, UploadClick;
|
||||
void (*LoadEntries)(struct ListScreen* s);
|
||||
void (*UpdateEntry)(struct ListScreen* s, struct ButtonWidget* btn, const cc_string* text);
|
||||
const char* titleText;
|
||||
@ -187,14 +187,14 @@ static struct ListScreen {
|
||||
struct StringsBuffer entries;
|
||||
} ListScreen;
|
||||
|
||||
static struct Widget* list_widgets[9] = {
|
||||
static struct Widget* list_widgets[10] = {
|
||||
(struct Widget*)&ListScreen.btns[0], (struct Widget*)&ListScreen.btns[1],
|
||||
(struct Widget*)&ListScreen.btns[2], (struct Widget*)&ListScreen.btns[3],
|
||||
(struct Widget*)&ListScreen.btns[4], (struct Widget*)&ListScreen.left,
|
||||
(struct Widget*)&ListScreen.right, (struct Widget*)&ListScreen.title,
|
||||
(struct Widget*)&ListScreen.done
|
||||
(struct Widget*)&ListScreen.done, NULL
|
||||
};
|
||||
#define LIST_MAX_VERTICES (8 * BUTTONWIDGET_MAX + TEXTWIDGET_MAX)
|
||||
#define LIST_MAX_VERTICES (9 * BUTTONWIDGET_MAX + TEXTWIDGET_MAX)
|
||||
#define LISTSCREEN_EMPTY "-----"
|
||||
|
||||
static void ListScreen_Layout(void* screen) {
|
||||
@ -204,7 +204,13 @@ static void ListScreen_Layout(void* screen) {
|
||||
Widget_SetLocation(&s->btns[i],
|
||||
ANCHOR_CENTRE, ANCHOR_CENTRE, 0, (i - 2) * 50);
|
||||
}
|
||||
Menu_LayoutBack(&s->done);
|
||||
|
||||
if (s->UploadClick) {
|
||||
Widget_SetLocation(&s->done, ANCHOR_CENTRE_MIN, ANCHOR_MAX, -150, 25);
|
||||
Widget_SetLocation(&s->upload, ANCHOR_CENTRE_MAX, ANCHOR_MAX, -150, 25);
|
||||
} else {
|
||||
Menu_LayoutBack(&s->done);
|
||||
}
|
||||
|
||||
Widget_SetLocation(&s->left, ANCHOR_CENTRE, ANCHOR_CENTRE, -220, 0);
|
||||
Widget_SetLocation(&s->right, ANCHOR_CENTRE, ANCHOR_CENTRE, 220, 0);
|
||||
@ -355,11 +361,20 @@ static void ListScreen_Init(void* screen) {
|
||||
for (i = 0; i < LIST_SCREEN_ITEMS; i++) {
|
||||
ButtonWidget_Init(&s->btns[i], 300, s->EntryClick);
|
||||
}
|
||||
if (Game_ClassicMode) s->UploadClick = NULL;
|
||||
|
||||
if (s->UploadClick) {
|
||||
ButtonWidget_Init(&s->done, 140, s->DoneClick);
|
||||
ButtonWidget_Init(&s->upload, 140, s->UploadClick);
|
||||
s->widgets[9] = (struct Widget*)&s->upload;
|
||||
} else {
|
||||
Menu_InitBack(&s->done, s->DoneClick);
|
||||
s->widgets[9] = NULL;
|
||||
}
|
||||
|
||||
ButtonWidget_Init(&s->left, 40, ListScreen_MoveBackwards);
|
||||
ButtonWidget_Init(&s->right, 40, ListScreen_MoveForwards);
|
||||
TextWidget_Init(&s->title);
|
||||
Menu_InitBack(&s->done, s->DoneClick);
|
||||
s->LoadEntries(s);
|
||||
}
|
||||
|
||||
@ -391,6 +406,9 @@ static void ListScreen_ContextRecreated(void* screen) {
|
||||
ButtonWidget_SetConst(&s->right, ">", &s->font);
|
||||
ButtonWidget_SetConst(&s->done, "Done", &s->font);
|
||||
ListScreen_UpdatePage(s);
|
||||
|
||||
if (!s->UploadClick) return;
|
||||
ButtonWidget_SetConst(&s->upload, "Upload", &s->font);
|
||||
}
|
||||
|
||||
static const struct ScreenVTABLE ListScreen_VTABLE = {
|
||||
@ -1261,13 +1279,13 @@ static void DownloadMap(const cc_string* path) {
|
||||
char strFile[NATIVE_STR_LEN];
|
||||
cc_string file;
|
||||
cc_result res;
|
||||
Platform_ConvertString(strPath, path);
|
||||
Platform_EncodeString(strPath, path);
|
||||
|
||||
/* maps/aaa.schematic -> aaa.cw */
|
||||
file = *path; Utils_UNSAFE_GetFilename(&file);
|
||||
file.length = String_LastIndexOf(&file, '.');
|
||||
String_AppendConst(&file, ".cw");
|
||||
Platform_ConvertString(strFile, &file);
|
||||
Platform_EncodeString(strFile, &file);
|
||||
|
||||
res = EM_ASM_({
|
||||
try {
|
||||
@ -1508,19 +1526,50 @@ static void TexturePackScreen_FilterFiles(const cc_string* path, void* obj) {
|
||||
cc_string relPath = *path;
|
||||
if (!String_CaselessEnds(path, &zip)) return;
|
||||
|
||||
#ifdef CC_BUILD_WEB
|
||||
/* Web client texture pack dir starts with /, so need to get rid of that */
|
||||
if (relPath.buffer[0] == '/') { relPath.buffer++; relPath.length--; }
|
||||
#endif
|
||||
|
||||
Utils_UNSAFE_TrimFirstDirectory(&relPath);
|
||||
StringsBuffer_Add((struct StringsBuffer*)obj, &relPath);
|
||||
}
|
||||
|
||||
static void TexturePackScreen_LoadEntries(struct ListScreen* s) {
|
||||
static const cc_string path = String_FromConst("texpacks");
|
||||
static const cc_string path = String_FromConst(TEXPACKS_DIR);
|
||||
Directory_Enum(&path, &s->entries, TexturePackScreen_FilterFiles);
|
||||
ListScreen_Sort(s);
|
||||
}
|
||||
|
||||
#ifdef CC_BUILD_WEB
|
||||
#include <emscripten.h>
|
||||
static void TexturePackScreen_UploadCallback(const cc_string* path) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_EncodeString(str, path);
|
||||
|
||||
/* Move from temp into texpacks folder */
|
||||
/* TODO: This is pretty awful and should be rewritten */
|
||||
EM_ASM_({
|
||||
var name = UTF8ToString($0);;
|
||||
var data = FS.readFile(name);
|
||||
FS.writeFile('/texpacks/' + name.substring(1), data);
|
||||
}, str);
|
||||
TexturePackScreen_Show();
|
||||
TexturePack_SetDefault(path);
|
||||
TexturePack_ExtractCurrent(true);
|
||||
}
|
||||
|
||||
static void TexturePackScreen_UploadFunc(void* s, void* w) {
|
||||
Window_OpenFileDialog(".zip", TexturePackScreen_UploadCallback);
|
||||
}
|
||||
#else
|
||||
#define TexturePackScreen_UploadFunc NULL
|
||||
#endif
|
||||
|
||||
void TexturePackScreen_Show(void) {
|
||||
struct ListScreen* s = &ListScreen;
|
||||
s->titleText = "Select a texture pack";
|
||||
s->UploadClick = TexturePackScreen_UploadFunc;
|
||||
s->LoadEntries = TexturePackScreen_LoadEntries;
|
||||
s->EntryClick = TexturePackScreen_EntryClick;
|
||||
s->DoneClick = Menu_SwitchPause;
|
||||
@ -1568,6 +1617,7 @@ static void FontListScreen_LoadEntries(struct ListScreen* s) {
|
||||
void FontListScreen_Show(void) {
|
||||
struct ListScreen* s = &ListScreen;
|
||||
s->titleText = "Select a font";
|
||||
s->UploadClick = NULL;
|
||||
s->LoadEntries = FontListScreen_LoadEntries;
|
||||
s->EntryClick = FontListScreen_EntryClick;
|
||||
s->DoneClick = Menu_SwitchGui;
|
||||
@ -1640,6 +1690,7 @@ static void HotkeyListScreen_LoadEntries(struct ListScreen* s) {
|
||||
void HotkeyListScreen_Show(void) {
|
||||
struct ListScreen* s = &ListScreen;
|
||||
s->titleText = "Modify hotkeys";
|
||||
s->UploadClick = NULL;
|
||||
s->LoadEntries = HotkeyListScreen_LoadEntries;
|
||||
s->EntryClick = HotkeyListScreen_EntryClick;
|
||||
s->DoneClick = Menu_SwitchPause;
|
||||
@ -1679,9 +1730,19 @@ static void LoadLevelScreen_LoadEntries(struct ListScreen* s) {
|
||||
ListScreen_Sort(s);
|
||||
}
|
||||
|
||||
#ifdef CC_BUILD_WEB
|
||||
static void LoadLevelScreen_UploadCallback(const cc_string* path) { Map_LoadFrom(path); }
|
||||
static void LoadLevelScreen_UploadFunc(void* s, void* w) {
|
||||
Window_OpenFileDialog(".cw", LoadLevelScreen_UploadCallback);
|
||||
}
|
||||
#else
|
||||
#define LoadLevelScreen_UploadFunc NULL
|
||||
#endif
|
||||
|
||||
void LoadLevelScreen_Show(void) {
|
||||
struct ListScreen* s = &ListScreen;
|
||||
s->titleText = "Select a level";
|
||||
s->UploadClick = LoadLevelScreen_UploadFunc;
|
||||
s->LoadEntries = LoadLevelScreen_LoadEntries;
|
||||
s->EntryClick = LoadLevelScreen_EntryClick;
|
||||
s->DoneClick = Menu_SwitchPause;
|
||||
|
@ -19,12 +19,6 @@
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE
|
||||
#define Platform_DecodeString(dst, src, len) String_AppendUtf16(dst, (cc_unichar*)(src), (len) * 2)
|
||||
#else
|
||||
#define Platform_DecodeString(dst, src, len) String_DecodeCP1252(dst, (cc_uint8*)(src), len)
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
@ -59,9 +53,7 @@ const cc_result ReturnCode_SocketWouldBlock = WSAEWOULDBLOCK;
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define Platform_DecodeString(dst, src, len) String_AppendUtf8(dst, (cc_uint8*)(src), len)
|
||||
#define Socket__Error() errno
|
||||
|
||||
static char* defaultDirectory;
|
||||
const cc_result ReturnCode_FileShareViolation = 1000000000; /* TODO: not used apparently */
|
||||
const cc_result ReturnCode_FileNotFound = ENOENT;
|
||||
@ -332,7 +324,7 @@ int Directory_Exists(const cc_string* path) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
DWORD attribs;
|
||||
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
attribs = GetFileAttributes(str);
|
||||
return attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
@ -341,7 +333,7 @@ cc_result Directory_Create(const cc_string* path) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
BOOL success;
|
||||
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
success = CreateDirectory(str, NULL);
|
||||
return success ? 0 : GetLastError();
|
||||
}
|
||||
@ -350,7 +342,7 @@ int File_Exists(const cc_string* path) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
DWORD attribs;
|
||||
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
attribs = GetFileAttributes(str);
|
||||
return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
@ -367,7 +359,7 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall
|
||||
/* Need to append \* to search for files in directory */
|
||||
String_InitArray(path, pathBuffer);
|
||||
String_Format1(&path, "%s\\*", dirPath);
|
||||
Platform_ConvertString(str, &path);
|
||||
Platform_EncodeString(str, &path);
|
||||
|
||||
find = FindFirstFile(str, &entry);
|
||||
if (find == INVALID_HANDLE_VALUE) return GetLastError();
|
||||
@ -401,7 +393,7 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall
|
||||
|
||||
static cc_result File_Do(cc_file* file, const cc_string* path, DWORD access, DWORD createMode) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
*file = CreateFile(str, access, FILE_SHARE_READ, NULL, createMode, 0, NULL);
|
||||
return *file != INVALID_HANDLE_VALUE ? 0 : GetLastError();
|
||||
}
|
||||
@ -449,13 +441,13 @@ cc_result File_Length(cc_file file, cc_uint32* len) {
|
||||
int Directory_Exists(const cc_string* path) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
struct stat sb;
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
return stat(str, &sb) == 0 && S_ISDIR(sb.st_mode);
|
||||
}
|
||||
|
||||
cc_result Directory_Create(const cc_string* path) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
/* read/write/search permissions for owner and group, and with read/search permissions for others. */
|
||||
/* TODO: Is the default mode in all cases */
|
||||
return mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1 ? errno : 0;
|
||||
@ -464,7 +456,7 @@ cc_result Directory_Create(const cc_string* path) {
|
||||
int File_Exists(const cc_string* path) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
struct stat sb;
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
return stat(str, &sb) == 0 && S_ISREG(sb.st_mode);
|
||||
}
|
||||
|
||||
@ -476,7 +468,7 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall
|
||||
char* src;
|
||||
int len, res;
|
||||
|
||||
Platform_ConvertString(str, dirPath);
|
||||
Platform_EncodeString(str, dirPath);
|
||||
dirPtr = opendir(str);
|
||||
if (!dirPtr) return errno;
|
||||
|
||||
@ -514,7 +506,7 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall
|
||||
|
||||
static cc_result File_Do(cc_file* file, const cc_string* path, int mode) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
*file = open(str, mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
return *file == -1 ? errno : 0;
|
||||
}
|
||||
@ -1049,14 +1041,14 @@ cc_result Process_StartGame(const cc_string* args) {
|
||||
|
||||
String_InitArray(argv, argvBuffer);
|
||||
String_Format1(&argv, "ClassiCube.exe %s", args);
|
||||
Platform_ConvertString(raw, &argv);
|
||||
Platform_EncodeString(raw, &argv);
|
||||
return Process_RawStart(path, raw);
|
||||
}
|
||||
void Process_Exit(cc_result code) { ExitProcess(code); }
|
||||
|
||||
void Process_StartOpen(const cc_string* args) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, args);
|
||||
Platform_EncodeString(str, args);
|
||||
ShellExecute(NULL, NULL, str, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
#elif defined CC_BUILD_WEB
|
||||
@ -1065,7 +1057,7 @@ void Process_Exit(cc_result code) { exit(code); }
|
||||
|
||||
void Process_StartOpen(const cc_string* args) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, args);
|
||||
Platform_EncodeString(str, args);
|
||||
EM_ASM_({ window.open(UTF8ToString($0)); }, str);
|
||||
}
|
||||
#elif defined CC_BUILD_ANDROID
|
||||
@ -1108,7 +1100,7 @@ cc_result Process_StartGame(const cc_string* args) {
|
||||
if (res) return res;
|
||||
path[len] = '\0';
|
||||
|
||||
Platform_ConvertString(raw, args);
|
||||
Platform_EncodeString(raw, args);
|
||||
argv[0] = path; argv[1] = raw;
|
||||
|
||||
/* need to null-terminate multiple arguments */
|
||||
@ -1134,7 +1126,7 @@ void Process_StartOpen(const cc_string* args) {
|
||||
CFURLRef urlCF;
|
||||
int len;
|
||||
|
||||
len = Platform_ConvertString(str, args);
|
||||
len = Platform_EncodeString(str, args);
|
||||
urlCF = CFURLCreateWithBytes(kCFAllocatorDefault, str, len, kCFStringEncodingUTF8, NULL);
|
||||
LSOpenCFURLRef(urlCF, NULL);
|
||||
CFRelease(urlCF);
|
||||
@ -1143,7 +1135,7 @@ void Process_StartOpen(const cc_string* args) {
|
||||
void Process_StartOpen(const cc_string* args) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
char* cmd[3];
|
||||
Platform_ConvertString(str, args);
|
||||
Platform_EncodeString(str, args);
|
||||
|
||||
cmd[0] = "open"; cmd[1] = str; cmd[2] = NULL;
|
||||
Process_RawStart("open", cmd);
|
||||
@ -1152,7 +1144,7 @@ void Process_StartOpen(const cc_string* args) {
|
||||
void Process_StartOpen(const cc_string* args) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
char* cmd[3];
|
||||
Platform_ConvertString(str, args);
|
||||
Platform_EncodeString(str, args);
|
||||
|
||||
/* TODO: Can xdg-open be used on original Solaris, or is it just an OpenIndiana thing */
|
||||
cmd[0] = "xdg-open"; cmd[1] = str; cmd[2] = NULL;
|
||||
@ -1431,7 +1423,7 @@ const cc_string DynamicLib_Ext = String_FromConst(".dll");
|
||||
|
||||
void* DynamicLib_Load2(const cc_string* path) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
return LoadLibrary(str);
|
||||
}
|
||||
|
||||
@ -1455,7 +1447,7 @@ const cc_string DynamicLib_Ext = String_FromConst(".dylib");
|
||||
|
||||
void* DynamicLib_Load2(const cc_string* path) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
return NSAddImage(str, NSADDIMAGE_OPTION_WITH_SEARCHING |
|
||||
NSADDIMAGE_OPTION_RETURN_ON_ERROR);
|
||||
}
|
||||
@ -1497,7 +1489,7 @@ const cc_string DynamicLib_Ext = String_FromConst(".so");
|
||||
|
||||
void* DynamicLib_Load2(const cc_string* path) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, path);
|
||||
Platform_EncodeString(str, path);
|
||||
return dlopen(str, RTLD_NOW);
|
||||
}
|
||||
|
||||
@ -1539,7 +1531,7 @@ cc_bool DynamicLib_GetAll(void* lib, const struct DynamicLibSym* syms, int count
|
||||
*--------------------------------------------------------Platform---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#if defined CC_BUILD_WIN
|
||||
int Platform_ConvertString(void* data, const cc_string* src) {
|
||||
int Platform_EncodeString(void* data, const cc_string* src) {
|
||||
TCHAR* dst = (TCHAR*)data;
|
||||
int i;
|
||||
if (src->length > FILENAME_SIZE) Logger_Abort("String too long to expand");
|
||||
@ -1551,6 +1543,14 @@ int Platform_ConvertString(void* data, const cc_string* src) {
|
||||
return src->length * 2;
|
||||
}
|
||||
|
||||
void Platform_DecodeString(cc_string* dst, const void* data, int len) {
|
||||
#ifdef UNICODE
|
||||
String_AppendUtf16(dst, (const cc_unichar*)data, len * 2);
|
||||
#else
|
||||
String_DecodeCP1252(dst, (const cc_uint8*)data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void Platform_InitStopwatch(void) {
|
||||
LARGE_INTEGER freq;
|
||||
sw_highRes = QueryPerformanceFrequency(&freq);
|
||||
@ -1639,7 +1639,7 @@ cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
|
||||
return Platform_DescribeErrorExt(res, dst, NULL);
|
||||
}
|
||||
#elif defined CC_BUILD_POSIX
|
||||
int Platform_ConvertString(void* data, const cc_string* src) {
|
||||
int Platform_EncodeString(void* data, const cc_string* src) {
|
||||
cc_uint8* dst = (cc_uint8*)data;
|
||||
cc_uint8* cur;
|
||||
int i, len = 0;
|
||||
@ -1653,6 +1653,10 @@ int Platform_ConvertString(void* data, const cc_string* src) {
|
||||
return len;
|
||||
}
|
||||
|
||||
void Platform_DecodeString(cc_string* dst, const void* data, int len) {
|
||||
String_AppendUtf8(dst, (const cc_uint8*)data, len);
|
||||
}
|
||||
|
||||
static void Platform_InitPosix(void) {
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
/* So writing to closed socket doesn't raise SIGPIPE */
|
||||
|
@ -33,7 +33,9 @@ extern const cc_result ReturnCode_SocketWouldBlock;
|
||||
/* Encodes a string in platform specific format. (e.g. unicode on windows, UTF8 on linux) */
|
||||
/* NOTE: Only useful for platform specific function calls - do NOT try to interpret the data. */
|
||||
/* Returns the number of bytes written, excluding trailing NULL terminator. */
|
||||
CC_API int Platform_ConvertString(void* data, const cc_string* src);
|
||||
int Platform_EncodeString(void* data, const cc_string* src);
|
||||
/* Attempts to append all characters from the platform specific encoded data to the given string. */
|
||||
void Platform_DecodeString(cc_string* dst, const void* data, int len);
|
||||
|
||||
/* Initialises the platform specific state. */
|
||||
void Platform_Init(void);
|
||||
|
@ -338,13 +338,7 @@ static void ExtractFromFile(const cc_string* filename) {
|
||||
cc_result res;
|
||||
|
||||
String_InitArray(path, pathBuffer);
|
||||
#ifdef CC_BUILD_WEB
|
||||
/* texpacks/default.zip must be read from memory */
|
||||
/* instead of the default filesystem */
|
||||
String_Format1(&path, "/texpacks/%s", filename);
|
||||
#else
|
||||
String_Format1(&path, "texpacks/%s", filename);
|
||||
#endif
|
||||
String_Format1(&path, TEXPACKS_DIR "/%s", filename);
|
||||
|
||||
res = Stream_OpenFile(&stream, &path);
|
||||
if (res) { Logger_SysWarn2(res, "opening", &path); return; }
|
||||
|
@ -49,7 +49,14 @@ CC_VAR extern struct _Atlas1DData {
|
||||
/* Textures for each 1D atlas. Only Atlas1D_Count of these are valid. */
|
||||
GfxResourceID TexIds[ATLAS1D_MAX_ATLASES];
|
||||
} Atlas1D;
|
||||
|
||||
extern cc_string TexturePack_Url;
|
||||
#ifdef CC_BUILD_WEB
|
||||
/* texpacks must be read from memory instead of the normal filesystem */
|
||||
#define TEXPACKS_DIR "/texpacks"
|
||||
#else
|
||||
#define TEXPACKS_DIR "texpacks"
|
||||
#endif
|
||||
|
||||
#define Atlas2D_TileX(texLoc) ((texLoc) & ATLAS2D_MASK) /* texLoc % ATLAS2D_TILES_PER_ROW */
|
||||
#define Atlas2D_TileY(texLoc) ((texLoc) >> ATLAS2D_SHIFT) /* texLoc / ATLAS2D_TILES_PER_ROW */
|
||||
|
85
src/Window.c
85
src/Window.c
@ -158,7 +158,7 @@ void Window_Create(int width, int height) {
|
||||
|
||||
void Window_SetTitle(const cc_string* title) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, title);
|
||||
Platform_EncodeString(str, title);
|
||||
SDL_SetWindowTitle(win_handle, str);
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ void Clipboard_GetText(cc_string* value) {
|
||||
|
||||
void Clipboard_SetText(const cc_string* value) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, value);
|
||||
Platform_EncodeString(str, value);
|
||||
SDL_SetClipboardText(str);
|
||||
}
|
||||
|
||||
@ -724,7 +724,7 @@ void Window_Create(int width, int height) {
|
||||
|
||||
void Window_SetTitle(const cc_string* title) {
|
||||
TCHAR str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, title);
|
||||
Platform_EncodeString(str, title);
|
||||
SetWindowText(win_handle, str);
|
||||
}
|
||||
|
||||
@ -1261,7 +1261,7 @@ void Window_Create(int width, int height) {
|
||||
|
||||
void Window_SetTitle(const cc_string* title) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, title);
|
||||
Platform_EncodeString(str, title);
|
||||
XStoreName(win_display, win_handle, str);
|
||||
}
|
||||
|
||||
@ -1562,7 +1562,7 @@ void Window_ProcessEvents(void) {
|
||||
if (e.xselectionrequest.selection == xa_clipboard && e.xselectionrequest.target == xa_utf8_string && clipboard_copy_text.length) {
|
||||
reply.xselection.property = Window_GetSelectionProperty(&e);
|
||||
char str[800];
|
||||
int len = Platform_ConvertString(str, &clipboard_copy_text);
|
||||
int len = Platform_EncodeString(str, &clipboard_copy_text);
|
||||
|
||||
XChangeProperty(win_display, reply.xselection.requestor, reply.xselection.property, xa_utf8_string, 8,
|
||||
PropModeReplace, (unsigned char*)str, len);
|
||||
@ -2085,7 +2085,7 @@ void Clipboard_SetText(const cc_string* value) {
|
||||
if (err) Logger_Abort2(err, "Clearing Pasteboard");
|
||||
PasteboardSynchronize(pbRef);
|
||||
|
||||
len = Platform_ConvertString(str, value);
|
||||
len = Platform_EncodeString(str, value);
|
||||
cfData = CFDataCreate(NULL, str, len);
|
||||
if (!cfData) Logger_Abort("CFDataCreate() returned null pointer");
|
||||
|
||||
@ -2482,7 +2482,7 @@ void Window_SetTitle(const cc_string* title) {
|
||||
int len;
|
||||
|
||||
/* TODO: This leaks memory, old title isn't released */
|
||||
len = Platform_ConvertString(str, title);
|
||||
len = Platform_EncodeString(str, title);
|
||||
titleCF = CFStringCreateWithBytes(kCFAllocatorDefault, str, len, kCFStringEncodingUTF8, false);
|
||||
SetWindowTitleWithCFString(win_handle, titleCF);
|
||||
}
|
||||
@ -2861,7 +2861,7 @@ void Window_SetTitle(const cc_string* title) {
|
||||
int len;
|
||||
|
||||
/* TODO: This leaks memory, old title isn't released */
|
||||
len = Platform_ConvertString(str, title);
|
||||
len = Platform_EncodeString(str, title);
|
||||
titleCF = CFStringCreateWithBytes(kCFAllocatorDefault, str, len, kCFStringEncodingUTF8, false);
|
||||
objc_msgSend(winHandle, sel_registerName("setTitle:"), titleCF);
|
||||
}
|
||||
@ -3501,7 +3501,7 @@ void Window_Create(int width, int height) {
|
||||
|
||||
void Window_SetTitle(const cc_string* title) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, title);
|
||||
Platform_EncodeString(str, title);
|
||||
EM_ASM_({ document.title = UTF8ToString($0); }, str);
|
||||
}
|
||||
|
||||
@ -3510,13 +3510,10 @@ static void* clipboard_obj;
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Window_GotClipboardText(char* src) {
|
||||
cc_string str; char strBuffer[512];
|
||||
int len;
|
||||
if (!clipboard_func) return;
|
||||
|
||||
String_InitArray(str, strBuffer);
|
||||
len = String_CalcLen(src, 2048);
|
||||
String_AppendUtf8(&str, (const cc_uint8*)src, len);
|
||||
|
||||
Platform_DecodeString(&str, src, String_CalcLen(src, 2048));
|
||||
clipboard_func(&str, clipboard_obj);
|
||||
clipboard_func = NULL;
|
||||
}
|
||||
@ -3524,7 +3521,7 @@ EMSCRIPTEN_KEEPALIVE void Window_GotClipboardText(char* src) {
|
||||
void Clipboard_GetText(cc_string* value) { }
|
||||
void Clipboard_SetText(const cc_string* value) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
Platform_ConvertString(str, value);
|
||||
Platform_EncodeString(str, value);
|
||||
|
||||
/* For IE11, use window.clipboardData to set the clipboard */
|
||||
/* For other browsers, instead use the window.copy events */
|
||||
@ -3648,25 +3645,69 @@ static void ShowDialogCore(const char* title, const char* msg) {
|
||||
EM_ASM_({ alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1)); }, title, msg);
|
||||
}
|
||||
|
||||
static OpenFileDialogCallback uploadCallback;
|
||||
EMSCRIPTEN_KEEPALIVE void Window_OnFileUploaded(const char* src) {
|
||||
cc_string file; char buffer[FILENAME_SIZE];
|
||||
String_InitArray(file, buffer);
|
||||
|
||||
Platform_DecodeString(&file, src, String_Length(src));
|
||||
uploadCallback(&file);
|
||||
uploadCallback = NULL;
|
||||
}
|
||||
|
||||
cc_result Window_OpenFileDialog(const char* filter, OpenFileDialogCallback callback) {
|
||||
uploadCallback = callback;
|
||||
EM_ASM_({
|
||||
var elem = window.cc_uploadElem;
|
||||
if (!elem) {
|
||||
elem = document.createElement('input');
|
||||
elem.setAttribute('type', 'file');
|
||||
elem.setAttribute('style', 'display: none');
|
||||
elem.accept = UTF8ToString($0);
|
||||
|
||||
elem.addEventListener('change',
|
||||
function(ev) {
|
||||
var files = ev.target.files;
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var reader = new FileReader();
|
||||
var name = files[i].name;
|
||||
|
||||
reader.onload = function(e) {
|
||||
var data = new Uint8Array(e.target.result);
|
||||
FS.createDataFile('/', name, data, true, true, true);
|
||||
ccall('Window_OnFileUploaded', 'void', ['string'], ['/' + name]);
|
||||
FS.unlink('/' + name);
|
||||
};
|
||||
reader.readAsArrayBuffer(files[i]);
|
||||
}
|
||||
window.cc_container.removeChild(window.cc_uploadElem);
|
||||
window.cc_uploadElem = null;
|
||||
}, false);
|
||||
window.cc_uploadElem = elem;
|
||||
window.cc_container.appendChild(elem);
|
||||
}
|
||||
elem.click();
|
||||
}, filter);
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void Window_AllocFramebuffer(struct Bitmap* bmp) { }
|
||||
void Window_DrawFramebuffer(Rect2D r) { }
|
||||
void Window_FreeFramebuffer(struct Bitmap* bmp) { }
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Window_OnTextChanged(const char* src) {
|
||||
cc_string str; char buffer[800];
|
||||
int len;
|
||||
|
||||
String_InitArray(str, buffer);
|
||||
len = String_CalcLen(src, 800);
|
||||
String_AppendUtf8(&str, (const cc_uint8*)src, len);
|
||||
|
||||
Platform_DecodeString(&str, src, String_CalcLen(src, 3200));
|
||||
Event_RaiseString(&InputEvents.TextChanged, &str);
|
||||
}
|
||||
|
||||
void Window_OpenKeyboard(const cc_string* text, int type) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
keyboardOpen = true;
|
||||
if (!Input_TouchMode) return;
|
||||
Platform_ConvertString(str, text);
|
||||
keyboardOpen = true;
|
||||
if (!Input_TouchMode) return;
|
||||
Platform_EncodeString(str, text);
|
||||
Platform_LogConst("OPEN SESAME");
|
||||
|
||||
EM_ASM_({
|
||||
@ -3701,7 +3742,7 @@ void Window_OpenKeyboard(const cc_string* text, int type) {
|
||||
void Window_SetKeyboardText(const cc_string* text) {
|
||||
char str[NATIVE_STR_LEN];
|
||||
if (!Input_TouchMode) return;
|
||||
Platform_ConvertString(str, text);
|
||||
Platform_EncodeString(str, text);
|
||||
|
||||
EM_ASM_({
|
||||
if (!window.cc_inputElem) return;
|
||||
|
@ -120,6 +120,10 @@ void Cursor_SetVisible(cc_bool visible);
|
||||
|
||||
/* Shows a dialog box window. */
|
||||
CC_API void Window_ShowDialog(const char* title, const char* msg);
|
||||
typedef void (*OpenFileDialogCallback)(const cc_string* path);
|
||||
/* Shows an 'load file' dialog window. */
|
||||
cc_result Window_OpenFileDialog(const char* filter, OpenFileDialogCallback callback);
|
||||
|
||||
/* Allocates a framebuffer that can be drawn/transferred to the window. */
|
||||
/* NOTE: Do NOT free bmp->Scan0, use Window_FreeFramebuffer. */
|
||||
/* NOTE: This MUST be called whenever the window is resized. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user