From 2bd5ed28d6a2779ba7a95d80b5af5ddaa4ffb28d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 9 Nov 2022 23:05:23 +1100 Subject: [PATCH] WIP on save file dialog support, that allows saving a map to anywhere on disc as either a .cw or a .schematic --- src/Menus.c | 36 ++++++++++++++------- src/Window.h | 11 +++++-- src/Window_Carbon.c | 4 +++ src/Window_SDL.c | 4 +++ src/Window_Win.c | 76 ++++++++++++++++++++++++++++++--------------- 5 files changed, 92 insertions(+), 39 deletions(-) diff --git a/src/Menus.c b/src/Menus.c index 5006344b8..6c56848c8 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -1279,15 +1279,15 @@ static struct SaveLevelScreen { struct FontDesc titleFont, textFont; struct ButtonWidget save, alt, cancel; struct TextInputWidget input; - struct TextWidget mcEdit, desc; + struct TextWidget desc; } SaveLevelScreen; -static struct Widget* save_widgets[6] = { +static struct Widget* save_widgets[] = { (struct Widget*)&SaveLevelScreen.save, (struct Widget*)&SaveLevelScreen.alt, - (struct Widget*)&SaveLevelScreen.mcEdit, (struct Widget*)&SaveLevelScreen.cancel, + (struct Widget*)&SaveLevelScreen.cancel, (struct Widget*)&SaveLevelScreen.input, (struct Widget*)&SaveLevelScreen.desc, }; -#define SAVE_MAX_VERTICES (3 * BUTTONWIDGET_MAX + MENUINPUTWIDGET_MAX + 2 * TEXTWIDGET_MAX) +#define SAVE_MAX_VERTICES (3 * BUTTONWIDGET_MAX + MENUINPUTWIDGET_MAX + TEXTWIDGET_MAX) static void SaveLevelScreen_UpdateSave(struct SaveLevelScreen* s) { ButtonWidget_SetConst(&s->save, @@ -1352,7 +1352,7 @@ static void SaveLevelScreen_SaveMap(struct SaveLevelScreen* s, const cc_string* res = Cw_Save(&compStream); #else if (String_CaselessEnds(path, &cw)) { - res = Cw_Save(&compStream); + res = Cw_Save(&compStream); /* TODO change to checking for schematic instead */ } else { res = Schematic_Save(&compStream); } @@ -1413,7 +1413,25 @@ static void SaveLevelScreen_Main(void* a, void* b) { SaveLevelScreen_Save(a, b, /* Use absolute path so data is written to memory filesystem instead of default filesystem */ static void SaveLevelScreen_Alt(void* a, void* b) { SaveLevelScreen_Save(a, b, "/%s.tmpmap"); } #else -static void SaveLevelScreen_Alt(void* a, void* b) { SaveLevelScreen_Save(a, b, "maps/%s.schematic"); } +static void SaveLevelScreen_UploadCallback(const cc_string* path) { + SaveLevelScreen_SaveMap(NULL, path); +} + +static void SaveLevelScreen_Alt(void* a, void* b) { + //SaveLevelScreen_Save(a, b, "maps/%s.schematic"); + static const char* const titles[] = { + "ClassiCube map", "MineCraft schematic", NULL + }; + static const char* const filters[] = { + ".cw", ".schematic", NULL + }; + static struct SaveFileDialogArgs args = { + filters, titles, SaveLevelScreen_UploadCallback + }; + + cc_result res = Window_SaveFileDialog(&args); + if (res) Logger_SimpleWarn(res, "showing save file dialog"); +} #endif static void SaveLevelScreen_Render(void* screen, double delta) { @@ -1468,9 +1486,6 @@ static void SaveLevelScreen_ContextRecreated(void* screen) { SaveLevelScreen_UpdateSave(s); SaveLevelScreen_UpdateAlt(s); -#ifndef CC_BUILD_WEB - TextWidget_SetConst(&s->mcEdit, "&eCan be imported into MCEdit", &s->textFont); -#endif TextInputWidget_SetFont(&s->input, &s->textFont); ButtonWidget_SetConst(&s->cancel, "Cancel", &s->titleFont); } @@ -1487,7 +1502,6 @@ static void SaveLevelScreen_Layout(void* screen) { Widget_SetLocation(&s->alt, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 70); #else Widget_SetLocation(&s->alt, ANCHOR_CENTRE, ANCHOR_CENTRE, -150, 120); - Widget_SetLocation(&s->mcEdit, ANCHOR_CENTRE, ANCHOR_CENTRE, 110, 120); #endif Menu_LayoutBack(&s->cancel); @@ -1511,10 +1525,8 @@ static void SaveLevelScreen_Init(void* screen) { ButtonWidget_Init(&s->save, 300, SaveLevelScreen_Main); #ifdef CC_BUILD_WEB ButtonWidget_Init(&s->alt, 300, SaveLevelScreen_Alt); - s->widgets[2] = NULL; /* null mcEdit widget */ #else ButtonWidget_Init(&s->alt, 200, SaveLevelScreen_Alt); - TextWidget_Init(&s->mcEdit); #endif ButtonWidget_Init(&s->cancel, 400, Menu_SwitchPause); diff --git a/src/Window.h b/src/Window.h index dc65baada..05134fdb2 100644 --- a/src/Window.h +++ b/src/Window.h @@ -131,17 +131,24 @@ CC_API void Window_ShowDialog(const char* title, const char* msg); #define OFD_UPLOAD_DELETE 0 /* (webclient) Deletes the uploaded file after invoking callback function */ #define OFD_UPLOAD_PERSIST 1 /* (webclient) Saves the uploded file into IndexedDB */ -typedef void (*OpenFileDialogCallback)(const cc_string* path); +typedef void (*FileDialogCallback)(const cc_string* path); +struct SaveFileDialogArgs { + const char* const* filters; /* File extensions to limit dialog to showing (e.g. ".zip", NULL) */ + const char* const* titles; /* Descriptions to show for each file extension */ + FileDialogCallback Callback; +}; struct OpenFileDialogArgs { const char* description; /* Describes the types of files supported (e.g. "Texture packs") */ const char* const* filters; /* File extensions to limit dialog to showing (e.g. ".zip", NULL) */ - OpenFileDialogCallback Callback; + FileDialogCallback Callback; int uploadAction; /* Action webclient takes after invoking callback function */ const char* uploadFolder; /* For webclient, folder to upload the file to */ }; /* Shows an 'load file' dialog window */ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args); +/* Shows an 'save file' dialog window */ +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args); /* Allocates a framebuffer that can be drawn/transferred to the window. */ /* NOTE: Do NOT free bmp->Scan0, use Window_FreeFramebuffer. */ diff --git a/src/Window_Carbon.c b/src/Window_Carbon.c index 3fedf74b1..a5f82dd16 100644 --- a/src/Window_Carbon.c +++ b/src/Window_Carbon.c @@ -595,6 +595,10 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { return ERR_NOT_SUPPORTED; } +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { + return ERR_NOT_SUPPORTED; +} + static CGrafPtr fb_port; static struct Bitmap fb_bmp; static CGColorSpaceRef colorSpace; diff --git a/src/Window_SDL.c b/src/Window_SDL.c index 377fa59d3..7f3ae54b1 100644 --- a/src/Window_SDL.c +++ b/src/Window_SDL.c @@ -281,6 +281,10 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { return ERR_NOT_SUPPORTED; } +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { + return ERR_NOT_SUPPORTED; +} + static SDL_Surface* win_surface; static SDL_Surface* blit_surface; diff --git a/src/Window_Win.c b/src/Window_Win.c index 2e278db8a..018b77f0c 100644 --- a/src/Window_Win.c +++ b/src/Window_Win.c @@ -551,52 +551,78 @@ static void ShowDialogCore(const char* title, const char* msg) { MessageBoxA(win_handle, msg, title, 0); } -cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { - const char* const* filters = args->filters; +static cc_result OpenSaveFileDialog(const cc_string* filters, FileDialogCallback callback, cc_bool load) { cc_string path; char pathBuffer[NATIVE_STR_LEN]; WCHAR str[MAX_PATH] = { 0 }; OPENFILENAMEW ofn = { 0 }; WCHAR filter[MAX_PATH]; + BOOL ok; int i; - /* Filter tokens are \0 separated - e.g. "Maps (*.cw;*.dat)\0*.cw;*.dat\0 */ - String_InitArray(path, pathBuffer); - String_Format1(&path, "%c (", args->description); - for (i = 0; filters[i]; i++) - { - if (i) String_Append(&path, ';'); - String_Format1(&path, "*%c", filters[i]); - } - String_Append(&path, ')'); - String_Append(&path, '\0'); - - for (i = 0; filters[i]; i++) - { - if (i) String_Append(&path, ';'); - String_Format1(&path, "*%c", filters[i]); - } - String_Append(&path, '\0'); - Platform_EncodeUtf16(filter, &path); - + Platform_EncodeUtf16(filter, filters); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = win_handle; ofn.lpstrFile = str; ofn.nMaxFile = MAX_PATH; ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + ofn.Flags = OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | (load ? OFN_FILEMUSTEXIST : OFN_OVERWRITEPROMPT); - if (!GetOpenFileNameW(&ofn)) - return CommDlgExtendedError(); + ok = load ? GetOpenFileNameW(&ofn) : GetSaveFileNameW(&ofn); + if (!ok) return CommDlgExtendedError(); String_InitArray(path, pathBuffer); for (i = 0; i < MAX_PATH && str[i]; i++) { String_Append(&path, Convert_CodepointToCP437(str[i])); } - args->Callback(&path); + callback(&path); return 0; } +cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { + const char* const* filters = args->filters; + cc_string str; char strBuffer[NATIVE_STR_LEN]; + int i; + + /* Filter tokens are \0 separated - e.g. "Maps (*.cw;*.dat)\0*.cw;*.dat\0 */ + String_InitArray(str, strBuffer); + String_Format1(&str, "%c (", args->description); + for (i = 0; filters[i]; i++) + { + if (i) String_Append(&str, ';'); + String_Format1(&str, "*%c", filters[i]); + } + String_Append(&str, ')'); + String_Append(&str, '\0'); + + for (i = 0; filters[i]; i++) + { + if (i) String_Append(&str, ';'); + String_Format1(&str, "*%c", filters[i]); + } + String_Append(&str, '\0'); + + return OpenSaveFileDialog(&str, args->Callback, true); +} + +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { + const char* const* titles = args->titles; + const char* const* filters = args->filters; + cc_string str; char strBuffer[NATIVE_STR_LEN]; + int i; + + /* Filter tokens are \0 separated - e.g. "Map (*.cw)\0*.cw\0 */ + String_InitArray(str, strBuffer); + for (i = 0; filters[i]; i++) + { + String_Format2(&str, "%c (*%c)", titles[i], filters[i]); + String_Append(&str, '\0'); + String_Format1(&str, "*%c", filters[i]); + String_Append(&str, '\0'); + } + return OpenSaveFileDialog(&str, args->Callback, false); +} + static HDC draw_DC; static HBITMAP draw_DIB; void Window_AllocFramebuffer(struct Bitmap* bmp) {