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/interface/window.h b/src/interface/window.h index 8156787fa1..a101157dc9 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -487,8 +487,6 @@ enum { LOADSAVETYPE_LANDSCAPE = 1 << 1, LOADSAVETYPE_SCENARIO = 2 << 1, LOADSAVETYPE_TRACK = 3 << 1, - - LOADSAVETYPE_NETWORK = 1 << 4, }; enum { diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 878c07142b..56916784be 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -280,18 +280,22 @@ enum { STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND = 1033, STR_CAN_ONLY_BUILD_THIS_ON_LAND = 1034, STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT = 1035, - STR_LOAD_GAME_DIALOG_TITLE = 1036, - STR_LOAD_LANDSCAPE_DIALOG_TITLE = 1037, - STR_CONVERT_SAVED_GAME_TO_SCENARIO_1038 = 1038, - - STR_SAVE_GAME_1040 = 1040, - STR_SAVE_SCENARIO = 1041, - - STR_RCT2_SAVED_GAME = 1043, - STR_RCT2_SCENARIO_FILE = 1044, - STR_RCT2_LANDSCAPE_FILE = 1045, + STR_FILE_DIALOG_TITLE_LOAD_GAME = 1036, + STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE = 1037, + STR_FILE_DIALOG_TITLE_CONVERT_SAVED_GAME_TO_SCENARIO = 1038, + STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN = 1039, + STR_FILE_DIALOG_TITLE_SAVE_GAME = 1040, + STR_FILE_DIALOG_TITLE_SAVE_SCENARIO = 1041, + STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE = 1042, + STR_OPENRCT2_SAVED_GAME = 1043, + STR_OPENRCT2_SCENARIO_FILE = 1044, + STR_OPENRCT2_LANDSCAPE_FILE = 1045, + STR_OPENRCT2_TRACK_DESIGN_FILE = 1046, + STR_GAME_SAVE_FAILED = 1047, STR_SCENARIO_SAVE_FAILED = 1048, + STR_LANDSCAPE_SAVE_FAILED = 1049, + STR_FAILED_TO_LOAD_FILE_CONTAINS_INVALID_DATA = 1050, STR_INVISIBLE_SUPPORTS = 1051, STR_INVISIBLE_PEOPLE = 1052, diff --git a/src/platform/linux.c b/src/platform/linux.c index d134a44b28..994610c648 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -163,13 +163,18 @@ void execute_cmd(char *command, int *exit_value, char *buf, size_t *buf_size) { if (buf && buf_size) { n_chars = fread(buf, 1, *buf_size, f); + // some commands may return a new-line terminated result, trim that… + if (n_chars > 0 && buf[n_chars - 1] == '\n') { + buf[n_chars - 1] = '\0'; + } // make sure string is null-terminated if (n_chars == *buf_size) { n_chars--; } buf[n_chars] = '\0'; - *buf_size = n_chars; + // account for null terminator + *buf_size = n_chars + 1; } else { fflush(f); } @@ -212,7 +217,7 @@ dialog_type get_dialog_app(char *cmd, size_t *cmd_size) { return dtype; } -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) { int exit_value; char executable[MAX_PATH]; char cmd[MAX_PATH]; @@ -221,16 +226,17 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi dialog_type dtype; char *action; char *flags; - char *filter = NULL; + char filter[MAX_PATH] = { 0 }; char filterPatternRegex[64]; char *allFilesPatternDescription; + int allFilesPatternLength = 0; size = MAX_PATH; dtype = get_dialog_app(executable, &size); switch (dtype) { case DT_KDIALOG: - switch (type) { + switch (desc->type) { case FD_OPEN: action = "--getopenfilename"; break; @@ -239,16 +245,44 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi break; } - if (filterPattern && filterName) { - filter = (char*) malloc(1 + strlen(filterPattern) + 3 + strlen(filterName) + 1); - sprintf(filter, "\"%s | %s\"", filterPattern, filterName); + { + bool first = true; + for (int j = 0; j < countof(desc->filters); j++) { + if (desc->filters[j].pattern && desc->filters[j].name) { + char filterTemp[100] = { 0 }; + if (first) { + snprintf(filterTemp, countof(filterTemp), "%s | %s", desc->filters[j].pattern, desc->filters[j].name); + first = false; + } else { + snprintf(filterTemp, countof(filterTemp), "\\n%s | %s", desc->filters[j].pattern, desc->filters[j].name); + } + safe_strcat(filter, filterTemp, countof(filter)); + } + } + char filterTemp[100] = { 0 }; + if (first) { + snprintf(filterTemp, countof(filterTemp), "*|%s", (char *)language_get_string(STR_ALL_FILES)); + } else { + snprintf(filterTemp, countof(filterTemp), "\\n*|%s", (char *)language_get_string(STR_ALL_FILES)); + } + safe_strcat(filter, filterTemp, countof(filter)); + + // kdialog wants filters space-delimited and we don't expect ';' anywhere else, + // this is much easier and quicker to do than being overly careful about replacing + // it only where truly needed. + int filterSize = strlen(filter); + for (int i = 0; i < filterSize + 3; i++) { + if (filter[i] == ';') { + filter[i] = ' '; + } + } } - snprintf(cmd, MAX_PATH, "%s --title \"%s\" %s ~ %s", executable, title, action, filter?filter:""); + snprintf(cmd, MAX_PATH, "%s --title \"%s\" %s ~ \"%s\"", executable, desc->title, action, filter); break; case DT_ZENITY: action = "--file-selection"; - switch (type) { + switch (desc->type) { case FD_SAVE: flags = "--confirm-overwrite --save"; break; @@ -258,29 +292,37 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi } // Zenity seems to be case sensitive, while Kdialog isn't. - if (filterPattern && filterName) { - int regexIterator = 0; - for(int i = 0; i <= sizeof(filterPattern); i++) { - if (isalpha(filterPattern[i])) { - filterPatternRegex[regexIterator+0] = '['; - filterPatternRegex[regexIterator+1] = (char)toupper(filterPattern[i]); - filterPatternRegex[regexIterator+2] = (char)tolower(filterPattern[i]); - filterPatternRegex[regexIterator+3] = ']'; - regexIterator += 3; + for (int j = 0; j < countof(desc->filters); j++) { + if (desc->filters[j].pattern && desc->filters[j].name) { + int regexIterator = 0; + for(int i = 0; i <= strlen(desc->filters[j].pattern); i++) { + if (isalpha(desc->filters[j].pattern[i])) { + filterPatternRegex[regexIterator+0] = '['; + filterPatternRegex[regexIterator+1] = (char)toupper(desc->filters[j].pattern[i]); + filterPatternRegex[regexIterator+2] = (char)tolower(desc->filters[j].pattern[i]); + filterPatternRegex[regexIterator+3] = ']'; + regexIterator += 3; + } + else if(desc->filters[j].pattern[i] == ';') { + filterPatternRegex[regexIterator] = ' '; + } + else { + filterPatternRegex[regexIterator] = (char)desc->filters[j].pattern[i]; + } + regexIterator++; } - else { - filterPatternRegex[regexIterator] = (char)filterPattern[i]; - } - regexIterator++; + filterPatternRegex[regexIterator+1] = 0; + + char filterTemp[100] = { 0 }; + snprintf(filterTemp, countof(filterTemp), " --file-filter=\"%s | %s\"", desc->filters[j].name, filterPatternRegex); + safe_strcat(filter, filterTemp, countof(filter)); } - filterPatternRegex[regexIterator+1] = 0; - - allFilesPatternDescription = (char *)language_get_string(STR_ALL_FILES); - filter = (char*) malloc(strlen("--file-filter=\"") + strlen(filterPatternRegex) + 3 + strlen(filterName) + 2 + strlen(" --file-filter=\"") + strlen(allFilesPatternDescription) + strlen(" | *\"")); - sprintf(filter, "--file-filter=\"%s | %s\" --file-filter=\"%s | *\"", filterName, filterPatternRegex, allFilesPatternDescription); } + char filterTemp[100] = { 0 }; + snprintf(filterTemp, countof(filterTemp), " --file-filter=\"%s | *\"", (char *)language_get_string(STR_ALL_FILES)); + safe_strcat(filter, filterTemp, countof(filter)); - snprintf(cmd, MAX_PATH, "%s %s %s --title=\"%s\" / %s", executable, action, flags, title, filter?filter:""); + snprintf(cmd, MAX_PATH, "%s %s %s --title=\"%s\" / %s", executable, action, flags, desc->title, filter); break; default: return 0; } @@ -289,40 +331,32 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi execute_cmd(cmd, &exit_value, result, &size); if (exit_value != 0) { - free(filter); return 0; } result[size-1] = '\0'; log_verbose("filename = %s", result); - if (type == FD_OPEN && access(result, F_OK) == -1) { + if (desc->type == FD_OPEN && access(result, F_OK) == -1) { char msg[MAX_PATH]; snprintf(msg, MAX_PATH, "\"%s\" not found: %s, please choose another file\n", result, strerror(errno)); platform_show_messagebox(msg); - if (filter != NULL) - free(filter); - return platform_open_common_file_dialog(type, title, filename, filterPattern, filterName); + return platform_open_common_file_dialog(outFilename, desc); } else - if (type == FD_SAVE && access(result, F_OK) != -1 && dtype == DT_KDIALOG) { + if (desc->type == FD_SAVE && access(result, F_OK) != -1 && dtype == DT_KDIALOG) { snprintf(cmd, MAX_PATH, "%s --yesno \"Overwrite %s?\"", executable, result); size = MAX_PATH; execute_cmd(cmd, &exit_value, 0, 0); if (exit_value != 0) { - if (filter != NULL) - free(filter); return 0; } } - strncpy(filename, result, MAX_PATH); - - if (filter != NULL) - free(filter); + strncpy(outFilename, result, MAX_PATH); return 1; } diff --git a/src/platform/osx.m b/src/platform/osx.m index fb2f7f9916..7257a90626 100644 --- a/src/platform/osx.m +++ b/src/platform/osx.m @@ -131,25 +131,29 @@ utf8 *platform_open_directory_browser(utf8 *title) } } -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) { @autoreleasepool { - NSString *fillPatternNS = [NSString stringWithUTF8String:filterPattern]; - fillPatternNS = [fillPatternNS stringByReplacingOccurrencesOfString:@"*." withString:@""]; - NSArray *extensions = [fillPatternNS componentsSeparatedByString:@";"]; + NSMutableArray *extensions = [NSMutableArray new]; + for (int i=0; i < countof(desc->filters); ++i) { + if (desc->filters[i].pattern != NULL) { + NSString *fp = [NSString stringWithUTF8String:desc->filters[i].pattern]; + fp = [fp stringByReplacingOccurrencesOfString:@"*." withString:@""]; + [extensions addObjectsFromArray:[fp componentsSeparatedByString:@";"]]; + } + } - NSString *filePath = [NSString stringWithUTF8String:filename]; + NSString *filePath = [NSString stringWithUTF8String:desc->default_filename]; NSString *directory = filePath.stringByDeletingLastPathComponent; NSString *basename = filePath.lastPathComponent; NSSavePanel *panel; - if (type == FD_SAVE) + if (desc->type == FD_SAVE) { panel = [NSSavePanel savePanel]; panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject]; } - else if (type == FD_OPEN) + else if (desc->type == FD_OPEN) { NSOpenPanel *open = [NSOpenPanel openPanel]; open.canChooseDirectories = false; @@ -157,19 +161,19 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi open.allowsMultipleSelection = false; panel = open; } else { - return 0; + return false; } - panel.title = [NSString stringWithUTF8String:title]; + panel.title = [NSString stringWithUTF8String:desc->title]; panel.allowedFileTypes = extensions; panel.directoryURL = [NSURL fileURLWithPath:directory]; if ([panel runModal] == NSFileHandlingPanelCancelButton){ SDL_RaiseWindow(gWindow); - return 0; + return false; } else { - strcpy(filename, panel.URL.path.UTF8String); + strcpy(outFilename, panel.URL.path.UTF8String); SDL_RaiseWindow(gWindow); - return 1; + return true; } } } 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..b594395bab 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -580,76 +580,95 @@ 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; + } + } + assert(ch != filters); + *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); + + // If there is no extension, append the pattern + const utf8 *outFilenameExtension = path_get_extension(outFilename); + if (str_is_null_or_empty(outFilenameExtension)) { + int filterIndex = openFileName.nFilterIndex - 1; + + assert(filterIndex >= 0); + assert(filterIndex < countof(desc->filters)); + + const utf8 *pattern = desc->filters[filterIndex].pattern; + const utf8 *patternExtension = path_get_extension(pattern); + if (!str_is_null_or_empty(patternExtension)) { + strcat(outFilename, patternExtension); + } + } + } return result; } diff --git a/src/ride/track.c b/src/ride/track.c index f58c0544e6..32e1a4df1e 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -3073,25 +3073,37 @@ 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 = language_get_string(STR_OPENRCT2_TRACK_DESIGN_FILE); + 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; } - path_append_extension(path, "TD6"); - save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); ride_list_item item = { .type = 0xFC, .entry_index = 0 }; 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..7f802dec40 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -71,7 +71,6 @@ static rct_widget window_loadsave_widgets[] = { static void window_loadsave_close(rct_window *w); static void window_loadsave_mouseup(rct_window *w, int widgetIndex); -static void window_loadsave_update(rct_window *w); static void window_loadsave_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); static void window_loadsave_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); static void window_loadsave_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); @@ -173,23 +172,26 @@ rct_window *window_loadsave_open(int type, char *defaultName) _loadsaveType = type; switch (type & 0x0F) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME): - w->widgets[WIDX_TITLE].image = STR_LOAD_GAME; + w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_GAME; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : - w->widgets[WIDX_TITLE].image = STR_SAVE_GAME; + w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_GAME; break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : - w->widgets[WIDX_TITLE].image = STR_LOAD_LANDSCAPE; + w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : - w->widgets[WIDX_TITLE].image = STR_SAVE_LANDSCAPE; + w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : - w->widgets[WIDX_TITLE].image = STR_SAVE_SCENARIO; + w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO; break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : - w->widgets[WIDX_TITLE].image = 1039; + w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN; break; + default: + log_error("Unsupported load / save type: %d", type & 0x0F); + return NULL; } w->no_list_items = 0; @@ -302,27 +304,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_FILE_DIALOG_TITLE_LOAD_GAME); + desc.filters[0].name = language_get_string(STR_OPENRCT2_SAVED_GAME); + 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_FILE_DIALOG_TITLE_SAVE_GAME); + desc.filters[0].name = language_get_string(STR_OPENRCT2_SAVED_GAME); + 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_FILE_DIALOG_TITLE_LOAD_LANDSCAPE); + desc.filters[0].name = language_get_string(STR_OPENRCT2_LANDSCAPE_FILE); + 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_FILE_DIALOG_TITLE_SAVE_LANDSCAPE); + desc.filters[0].name = language_get_string(STR_OPENRCT2_LANDSCAPE_FILE); + 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_FILE_DIALOG_TITLE_SAVE_SCENARIO); + desc.filters[0].name = language_get_string(STR_OPENRCT2_SCENARIO_FILE); + 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(STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN); + desc.filters[0].name = language_get_string(STR_OPENRCT2_TRACK_DESIGN_FILE); + desc.filters[0].pattern = "*.td4;*.td6"; break; } + result = platform_open_common_file_dialog(path, &desc); if (result) { window_loadsave_select(w, path); } @@ -702,10 +730,6 @@ static void window_loadsave_select(rct_window *w, const char *path) } window_loadsave_invoke_callback(MODAL_RESULT_OK); } else if (game_load_save(path)) { - if (_loadsaveType & LOADSAVETYPE_NETWORK) { - network_begin_server(gConfigNetwork.default_port); - } - safe_strcpy(gScenarioSavePath, path, MAX_PATH); gFirstTimeSave = 0; @@ -789,7 +813,7 @@ static void window_loadsave_select(rct_window *w, const char *path) window_loadsave_invoke_callback(MODAL_RESULT_OK); title_load(); } else { - window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); + window_error_open(STR_FILE_DIALOG_TITLE_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; window_loadsave_invoke_callback(MODAL_RESULT_FAIL); } diff --git a/src/windows/server_start.c b/src/windows/server_start.c index 63eee8ea44..2c78733f8a 100644 --- a/src/windows/server_start.c +++ b/src/windows/server_start.c @@ -160,6 +160,13 @@ static void window_server_start_scenarioselect_callback(const utf8 *path) } } +static void window_server_start_loadsave_callback(int result) +{ + if (result == MODAL_RESULT_OK) { + network_begin_server(gConfigNetwork.default_port); + } +} + static void window_server_start_mouseup(rct_window *w, int widgetIndex) { switch (widgetIndex) { @@ -199,7 +206,8 @@ static void window_server_start_mouseup(rct_window *w, int widgetIndex) break; case WIDX_LOAD_SERVER: network_set_password(_password); - window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME | LOADSAVETYPE_NETWORK, NULL); + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME, NULL); + gLoadSaveCallback = window_server_start_loadsave_callback; break; } }