diff --git a/src/game.c b/src/game.c index 046564a308..c150845b25 100644 --- a/src/game.c +++ b/src/game.c @@ -611,40 +611,6 @@ static void game_load_or_quit(int *eax, int *ebx, int *ecx, int *edx, int *esi, *ebx = 0; } -/** - * - * rct2: 0x00674F40 - */ -static int open_landscape_file_dialog() -{ - int result; - format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, STR_LOAD_LANDSCAPE_DIALOG_TITLE, 0); - safe_strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_LANDSCAPES_PATH, MAX_PATH); - format_string((char*)0x0141EE68, STR_RCT2_LANDSCAPE_FILE, 0); - audio_pause_sounds(); - result = platform_open_common_file_dialog(FD_OPEN, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68); - audio_unpause_sounds(); - // window_proc - return result; -} - -/** - * - * rct2: 0x00674EB6 - */ -static int open_load_game_dialog() -{ - int result; - format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, STR_LOAD_GAME_DIALOG_TITLE, 0); - safe_strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH, MAX_PATH); - format_string((char*)0x0141EE68, STR_RCT2_SAVED_GAME, 0); - audio_pause_sounds(); - result = platform_open_common_file_dialog(FD_OPEN, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68); - audio_unpause_sounds(); - // window_proc - return result; -} - /** * * rct2: 0x0066DC0F @@ -1025,32 +991,6 @@ void reset_all_sprite_quadrant_placements() sprite_move(spr->unknown.x, spr->unknown.y, spr->unknown.z, spr); } -/** - * - * rct2: 0x006750E9 - */ -static int show_save_game_dialog(char *resultPath) -{ - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - - int result; - char title[256]; - char filename[MAX_PATH]; - char filterName[256]; - - format_string(title, STR_SAVE_GAME_1040, NULL); - safe_strcpy(filename, RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char), MAX_PATH); - format_string(filterName, STR_RCT2_SAVED_GAME, NULL); - - audio_pause_sounds(); - result = platform_open_common_file_dialog(FD_SAVE, title, filename, "*.SV6", filterName); - audio_unpause_sounds(); - - if (result) - safe_strcpy(resultPath, filename, MAX_PATH); - return result; -} - void save_game() { if (!gFirstTimeSave) { diff --git a/src/platform/platform.h b/src/platform/platform.h index 1e158f8109..9a82d6cd60 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -88,6 +88,16 @@ enum { typedef enum {FD_OPEN, FD_SAVE} filedialog_type; +typedef struct { + uint8 type; + const utf8 *title; + const utf8 *initial_directory; + const utf8 *default_filename; + struct { + const utf8 *name; // E.g. "Image Files" + const utf8 *pattern; // E.g. "*.png;*.jpg;*.gif" + } filters[8]; +} file_dialog_desc; extern openrct2_cursor gCursorState; extern const unsigned char *gKeysState; @@ -164,7 +174,7 @@ void platform_get_openrct_data_path(utf8 *outPath); void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory); utf8* platform_get_username(); void platform_show_messagebox(utf8 *message); -int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName); +bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc); utf8 *platform_open_directory_browser(utf8 *title); uint8 platform_get_locale_currency(); uint8 platform_get_currency_value(const char *currencyCode); diff --git a/src/platform/windows.c b/src/platform/windows.c index 163cbc4d46..0c5761dc13 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -580,76 +580,79 @@ void platform_show_messagebox(char *message) * * rct2: 0x004080EA */ -int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) { - wchar_t wctitle[256], wcfilename[MAX_PATH], wcfilterPattern[256], wcfilterName[256]; - wchar_t initialDirectory[MAX_PATH], *dotAddress, *slashAddress; OPENFILENAMEW openFileName; - BOOL result; - int tmp; - DWORD commonFlags; + wchar_t wcFilename[MAX_PATH]; - MultiByteToWideChar(CP_UTF8, 0, title, -1, wctitle, countof(wctitle)); - MultiByteToWideChar(CP_UTF8, 0, filename, -1, wcfilename, countof(wcfilename)); - MultiByteToWideChar(CP_UTF8, 0, filterPattern, -1, wcfilterPattern, countof(wcfilterPattern)); - MultiByteToWideChar(CP_UTF8, 0, filterName, -1, wcfilterName, countof(wcfilterName)); - - // Get directory path from given filename - lstrcpyW(initialDirectory, wcfilename); - dotAddress = wcsrchr(initialDirectory, '.'); - if (dotAddress != NULL) { - slashAddress = wcsrchr(initialDirectory, '\\'); - if (slashAddress < dotAddress) - *(slashAddress + 1) = 0; + // Copy default filename to result filename buffer + if (desc->default_filename == NULL) { + wcFilename[0] = 0; + } else { + wchar_t *wcDefaultFilename = utf8_to_widechar(desc->default_filename); + lstrcpyW(wcFilename, wcDefaultFilename); + free(wcDefaultFilename); } - // Clear filename - if (type != FD_SAVE) - wcfilename[0] = 0; - // Set open file name options memset(&openFileName, 0, sizeof(OPENFILENAMEW)); openFileName.lStructSize = sizeof(OPENFILENAMEW); openFileName.hwndOwner = windows_get_window_handle(); - openFileName.lpstrFile = wcfilename; openFileName.nMaxFile = MAX_PATH; - openFileName.lpstrInitialDir = initialDirectory; - openFileName.lpstrTitle = wctitle; + openFileName.lpstrTitle = utf8_to_widechar(desc->title); + openFileName.lpstrInitialDir = utf8_to_widechar(desc->initial_directory); + openFileName.lpstrFile = wcFilename; - // Copy filter name - lstrcpyW((wchar_t*)0x01423800, wcfilterName); - - // Copy filter pattern - int wcfilterNameLength = lstrlenW(wcfilterName); - int wcfilterPatternLength = lstrlenW(wcfilterPattern); - - lstrcpyW((wchar_t*)0x01423800 + wcfilterNameLength + 1, wcfilterPattern); - *((wchar_t*)((wchar_t*)0x01423800 + wcfilterNameLength + 1 + wcfilterPatternLength + 1)) = 0; - openFileName.lpstrFilter = (wchar_t*)0x01423800; - - // - tmp = RCT2_GLOBAL(0x009E2C74, uint32); - if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1) - RCT2_GLOBAL(0x009E2C74, uint32) = 1; - - // Open dialog - commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; - if (type == FD_SAVE) { - wchar_t *defaultExtension = wcsrchr(wcfilterPattern, '.'); - if (defaultExtension != NULL) { - openFileName.lpstrDefExt = defaultExtension + 1; + utf8 filters[256]; + utf8 *ch = filters; + for (int i = 0; i < countof(desc->filters); i++) { + if (desc->filters[i].name != NULL) { + strcpy(ch, desc->filters[i].name); + ch = strchr(ch, 0) + 1; + strcpy(ch, desc->filters[i].pattern); + ch = strchr(ch, 0) + 1; + } + } + *ch = 0; + + // HACK: Replace all null terminators with 0x01 so that we convert the entire string + size_t fullLength = (size_t)(ch - filters); + for (size_t i = 0; i < fullLength; i++) { + if (filters[i] == '\0') { + filters[i] = 1; + } + } + wchar_t *wcFilter = utf8_to_widechar(filters); + fullLength = lstrlenW(wcFilter); + for (size_t i = 0; i < fullLength; i++) { + if (wcFilter[i] == 1) { + wcFilter[i] = '\0'; } - openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; - result = GetSaveFileNameW(&openFileName); - } else if (type == FD_OPEN) { - openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST; - result = GetOpenFileNameW(&openFileName); } - // - RCT2_GLOBAL(0x009E2C74, uint32) = tmp; + openFileName.lpstrFilter = wcFilter; - WideCharToMultiByte(CP_UTF8, 0, wcfilename, countof(wcfilename), filename, MAX_PATH, NULL, NULL); + // Open dialog + BOOL result; + DWORD commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + if (desc->type == FD_OPEN) { + openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST; + result = GetOpenFileNameW(&openFileName); + } else if (desc->type == FD_SAVE) { + openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; + result = GetSaveFileNameW(&openFileName); + } + + // Clean up + free((void*)openFileName.lpstrTitle); + free((void*)openFileName.lpstrInitialDir); + free((void*)openFileName.lpstrFilter); + + if (result) { + utf8 *resultFilename = widechar_to_utf8(openFileName.lpstrFile); + strcpy(outFilename, resultFilename); + free(resultFilename); + } return result; } diff --git a/src/ride/track.c b/src/ride/track.c index f58c0544e6..3052a33cca 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -3073,18 +3073,32 @@ int save_track_design(uint8 rideIndex){ // Track design files format_string(RCT2_ADDRESS(0x141EE68, char), 2305, NULL); + // Show save dialog + utf8 initialDirectory[MAX_PATH]; + { + strcpy(initialDirectory, path); + utf8 *a = strrchr(initialDirectory, '/'); + utf8 *b = strrchr(initialDirectory, '\\'); + utf8 *c = max(a, b); + if (c != NULL) { + *c = '\0'; + } + } + + file_dialog_desc desc; + memset(&desc, 0, sizeof(desc)); + desc.type = FD_SAVE; + desc.title = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, utf8); + desc.initial_directory = initialDirectory; + desc.default_filename = path; + desc.filters[0].name = "OpenRCT2 Track Designs"; + desc.filters[0].pattern = "*.td6"; + audio_pause_sounds(); - - int result = platform_open_common_file_dialog( - FD_SAVE, - RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char), - path, - "*.TD?", - RCT2_ADDRESS(0x141EE68, char)); - + bool result = platform_open_common_file_dialog(path, &desc); audio_unpause_sounds(); - if (result == 0){ + if (!result) { ride_list_item item = { .type = 0xFD, .entry_index = 0 }; track_load_list(item); return 1; diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index 261998c07b..ec420f64d7 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -318,34 +318,6 @@ void window_editor_bottom_toolbar_jump_forward_to_objective_selection() { gfx_invalidate_screen(); } -/** - * - * rct2: 0x00675181 - */ -static int show_save_scenario_dialog(char *resultPath) -{ - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - - int result; - char title[256]; - char filename[MAX_PATH]; - char filterName[256]; - - - format_string(title, STR_SAVE_SCENARIO, NULL); - substitute_path(filename, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), s6Info->name); - strcat(filename, ".SC6"); - format_string(filterName, STR_RCT2_SCENARIO_FILE, NULL); - - audio_pause_sounds(); - result = platform_open_common_file_dialog(FD_SAVE, title, filename, "*.SC6", filterName); - audio_unpause_sounds(); - - if (result) - safe_strcpy(resultPath, filename, MAX_PATH); - return result; -} - /** * * rct2: 0x0066F7C0 @@ -353,8 +325,6 @@ static int show_save_scenario_dialog(char *resultPath) void window_editor_bottom_toolbar_jump_forward_to_save_scenario() { rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - int parkFlagsBackup, success; - char path[256]; if (!scenario_prepare_for_save()) { window_error_open(STR_UNABLE_TO_SAVE_SCENARIO_FILE, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); @@ -363,37 +333,7 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() } window_close_all(); - window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO, s6Info->name); - return; - - if (!show_save_scenario_dialog(path)) { - gfx_invalidate_screen(); - return; - } - - // - s6Info->editor_step = 255; - - // Ensure path has .SC6 extension - path_append_extension(path, ".SC6"); - - // Save the scenario - parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); - RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; - SDL_RWops* rw = SDL_RWFromFile(path, "wb+"); - if (rw != NULL) { - success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); - SDL_RWclose(rw); - } - RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; - - if (success) { - title_load(); - } else { - window_error_open(STR_SCENARIO_SAVE_FAILED, -1); - s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; - } } /** diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 49ceb25f0d..6c01e0e9b9 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -302,27 +302,53 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex) safe_strcpy(filter, "*", MAX_PATH); strncat(filter, _extension, MAX_PATH - strnlen(filter, MAX_PATH) - 1); + file_dialog_desc desc; + memset(&desc, 0, sizeof(desc)); + desc.initial_directory = _directory; + if (_type & LOADSAVETYPE_SAVE) { + desc.default_filename = path; + } + switch (_type) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : - result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(STR_LOAD_GAME), path, filter, _extension); + desc.type = FD_OPEN; + desc.title = language_get_string(STR_LOAD_GAME); + desc.filters[0].name = "Supported Saved Games"; + desc.filters[0].pattern = "*.sv4;*.sv6"; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : - result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_GAME), path, filter, _extension); + desc.type = FD_SAVE; + desc.title = language_get_string(STR_SAVE_GAME); + desc.filters[0].name = "OpenRCT2 Saved Games"; + desc.filters[0].pattern = "*.sv6"; break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : - result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(STR_LOAD_LANDSCAPE), path, filter, _extension); + desc.type = FD_OPEN; + desc.title = language_get_string(STR_LOAD_LANDSCAPE); + desc.filters[0].name = "Supported Landscapes"; + desc.filters[0].pattern = "*.sc4;*.sv4;*.sc6;*.sv6"; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : - result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_LANDSCAPE), path, filter, _extension); + desc.type = FD_SAVE; + desc.title = language_get_string(STR_SAVE_LANDSCAPE); + desc.filters[0].name = "OpenRCT2 Landscapes"; + desc.filters[0].pattern = "*.sc6"; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : - result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_SCENARIO), path, filter, _extension); + desc.type = FD_SAVE; + desc.title = language_get_string(STR_SAVE_SCENARIO); + desc.filters[0].name = "OpenRCT2 Scenarios"; + desc.filters[0].pattern = "*.sc6"; break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : - result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(1039), path, filter, _extension); + desc.type = FD_OPEN; + desc.title = language_get_string(1039); + desc.filters[0].name = "Supported Track Designs"; + desc.filters[0].pattern = "*.td4;*.td6"; break; } + result = platform_open_common_file_dialog(path, &desc); if (result) { window_loadsave_select(w, path); }