Merge pull request #7902 from AaronVanGeffen/windows/loadsave-native

Add option to always use system file browsing window
This commit is contained in:
Aaron van Geffen 2018-08-18 16:01:03 +02:00 committed by GitHub
commit 4feac44595
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 139 additions and 84 deletions

View File

@ -2039,7 +2039,7 @@ STR_2703 :Every 15 minutes
STR_2704 :Every 30 minutes
STR_2705 :Every hour
STR_2706 :Never
STR_2707 :Use system dialog window
STR_2707 :Use system file browser
STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}?
STR_2709 :Overwrite
STR_2710 :Type the name of the file.
@ -3724,6 +3724,8 @@ STR_6260 :Show blocked tiles
STR_6261 :Show wide paths
STR_6262 :Master volume
STR_6263 :{SMALLFONT}{BLACK}Toggle all sound on/off
STR_6264 :Always use system file browser
STR_6265 :{SMALLFONT}{BLACK}When enabled, your operating system's file browser will be used instead of OpenRCT2's.
#############
# Scenarios #

View File

@ -2,6 +2,7 @@
------------------------------------------------------------------------
- Feature: [#5993] Ride window prices can now be set via text input.
- Feature: [#6998] Guests now wait for passing vehicles before crossing railway tracks.
- Feature: [#7658] Add option to always use system file browsing window.
- Feature: [#7694] Debug option to visualize paths that the game detects as wide.
- Feature: [#7713] The virtual floor now takes land ownership rights into account.
- Feature: [#7771] Danish translation.

View File

@ -218,8 +218,7 @@ public:
uint32_t type = intent->GetUIntExtra(INTENT_EXTRA_LOADSAVE_TYPE);
std::string defaultName = intent->GetStringExtra(INTENT_EXTRA_PATH);
loadsave_callback callback = (loadsave_callback)intent->GetPointerExtra(INTENT_EXTRA_CALLBACK);
rct_window* w = window_loadsave_open(type, defaultName.c_str());
window_loadsave_set_loadsave_callback(callback);
rct_window* w = window_loadsave_open(type, defaultName.c_str(), callback);
return w;
}

View File

@ -161,17 +161,89 @@ static void window_loadsave_sort_list();
static rct_window* window_overwrite_prompt_open(const char* name, const char* path);
void window_loadsave_set_loadsave_callback(loadsave_callback cb)
static utf8* getLastDirectoryByType(int32_t type)
{
_loadSaveCallback = cb;
switch (type & 0x0E)
{
case LOADSAVETYPE_GAME:
return gConfigGeneral.last_save_game_directory;
case LOADSAVETYPE_LANDSCAPE:
return gConfigGeneral.last_save_landscape_directory;
case LOADSAVETYPE_SCENARIO:
return gConfigGeneral.last_save_scenario_directory;
case LOADSAVETYPE_TRACK:
return gConfigGeneral.last_save_track_directory;
default:
return nullptr;
}
}
static int32_t window_loadsave_get_dir(utf8* last_save, char* path, const char* subdir, size_t pathSize)
static void getInitialDirectoryByType(const int32_t type, char* path, size_t pathSize)
{
const char* subdir = nullptr;
switch (type & 0x0E)
{
case LOADSAVETYPE_GAME:
subdir = "save";
break;
case LOADSAVETYPE_LANDSCAPE:
subdir = "landscape";
break;
case LOADSAVETYPE_SCENARIO:
subdir = "scenario";
break;
case LOADSAVETYPE_TRACK:
subdir = "track";
break;
case LOADSAVETYPE_HEIGHTMAP:
subdir = "heightmap";
break;
}
platform_get_user_directory(path, subdir, pathSize);
}
static const char* getFilterPatternByType(const int32_t type, const bool isSave)
{
switch (type & 0x0E)
{
case LOADSAVETYPE_GAME:
return isSave ? "*.sv6" : "*.sv6;*.sc6;*.sc4;*.sv4;*.sv7";
case LOADSAVETYPE_LANDSCAPE:
return isSave ? "*.sc6" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7";
case LOADSAVETYPE_SCENARIO:
return "*.sc6";
case LOADSAVETYPE_TRACK:
return isSave ? "*.td6" : "*.td6;*.td4";
case LOADSAVETYPE_HEIGHTMAP:
return "*.bmp;*.png";
default:
openrct2_assert(true, "Unsupported load/save directory type.");
}
return "";
}
static int32_t window_loadsave_get_dir(const int32_t type, char* path, size_t pathSize)
{
const char* last_save = getLastDirectoryByType(type);
if (last_save && platform_ensure_directory_exists(last_save))
safe_strcpy(path, last_save, pathSize);
else
platform_get_user_directory(path, subdir, pathSize);
getInitialDirectoryByType(type, path, pathSize);
if (!platform_ensure_directory_exists(path))
{
@ -182,9 +254,11 @@ static int32_t window_loadsave_get_dir(utf8* last_save, char* path, const char*
return 1;
}
rct_window* window_loadsave_open(int32_t type, const char* defaultName)
static bool browse(bool isSave, char* path, size_t pathSize);
rct_window* window_loadsave_open(int32_t type, const char* defaultName, loadsave_callback callback)
{
_loadSaveCallback = nullptr;
_loadSaveCallback = callback;
_type = type;
_defaultName[0] = '\0';
@ -193,6 +267,22 @@ rct_window* window_loadsave_open(int32_t type, const char* defaultName)
safe_strcpy(_defaultName, defaultName, sizeof(_defaultName));
}
bool isSave = (type & 0x01) == LOADSAVETYPE_SAVE;
char path[MAX_PATH];
bool success = window_loadsave_get_dir(type, path, sizeof(path));
if (!success)
return nullptr;
// Bypass the lot?
if (gConfigGeneral.use_native_browse_dialog)
{
if (browse(isSave, path, sizeof(path)))
{
window_loadsave_select(nullptr, path);
}
return nullptr;
}
rct_window* w = window_bring_to_front_by_class(WC_LOADSAVE);
if (w == nullptr)
{
@ -207,73 +297,38 @@ rct_window* window_loadsave_open(int32_t type, const char* defaultName)
w->max_height = WH * 2;
}
w->no_list_items = 0;
window_loadsave_populate_list(w, false, path, getFilterPatternByType(type, isSave));
w->no_list_items = static_cast<uint16_t>(_listItems.size());
w->selected_list_item = -1;
bool isSave = (type & 0x01) == LOADSAVETYPE_SAVE;
bool success = false;
char path[MAX_PATH];
switch (type & 0x0E)
{
case LOADSAVETYPE_GAME:
w->widgets[WIDX_TITLE].text = isSave ? STR_FILE_DIALOG_TITLE_SAVE_GAME : STR_FILE_DIALOG_TITLE_LOAD_GAME;
if (window_loadsave_get_dir(gConfigGeneral.last_save_game_directory, path, "save", sizeof(path)))
{
window_loadsave_populate_list(w, isSave, path, isSave ? ".sv6" : ".sv6;.sc6;.sv4;.sc4;.sv7");
success = true;
}
break;
case LOADSAVETYPE_LANDSCAPE:
w->widgets[WIDX_TITLE].text = isSave ? STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE : STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE;
if (window_loadsave_get_dir(gConfigGeneral.last_save_landscape_directory, path, "landscape", sizeof(path)))
{
window_loadsave_populate_list(w, isSave, path, isSave ? ".sc6" : ".sc6;.sv6;.sc4;.sv4;.sv7");
success = true;
}
break;
case LOADSAVETYPE_SCENARIO:
w->widgets[WIDX_TITLE].text = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO;
if (window_loadsave_get_dir(gConfigGeneral.last_save_scenario_directory, path, "scenario", sizeof(path)))
{
window_loadsave_populate_list(w, isSave, path, ".sc6");
success = true;
}
break;
case LOADSAVETYPE_TRACK:
w->widgets[WIDX_TITLE].text = isSave ? STR_FILE_DIALOG_TITLE_SAVE_TRACK
: STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN;
if (window_loadsave_get_dir(gConfigGeneral.last_save_track_directory, path, "track", sizeof(path)))
{
window_loadsave_populate_list(w, isSave, path, isSave ? ".td6" : ".td6;.td4");
success = true;
}
break;
case LOADSAVETYPE_IMAGE:
case LOADSAVETYPE_HEIGHTMAP:
openrct2_assert(!isSave, "Cannot save images through loadsave window");
w->widgets[WIDX_TITLE].text = STR_FILE_DIALOG_TITLE_LOAD_HEIGHTMAP;
if (window_loadsave_get_dir(gConfigGeneral.last_save_track_directory, path, "", sizeof(path)))
{
window_loadsave_populate_list(w, false, path, ".bmp;.png");
success = true;
}
break;
default:
log_error("Unsupported load/save type: %d", type & 0x0F);
openrct2_assert(true, "Unsupported load/save type: %d", type & 0x0F);
}
if (!success)
{
window_close(w);
return nullptr;
}
w->no_list_items = static_cast<uint16_t>(_listItems.size());
window_init_scroll_widgets(w);
window_loadsave_compute_max_date_width();
@ -313,7 +368,7 @@ static bool browse(bool isSave, char* path, size_t pathSize)
fileType = FILE_EXTENSION_SV6;
title = isSave ? STR_FILE_DIALOG_TITLE_SAVE_GAME : STR_FILE_DIALOG_TITLE_LOAD_GAME;
desc.filters[0].name = language_get_string(STR_OPENRCT2_SAVED_GAME);
desc.filters[0].pattern = isSave ? "*.sv6" : "*.sv6;*.sc6;*.sv4;*.sc4;*.sv7";
desc.filters[0].pattern = getFilterPatternByType(_type, isSave);
break;
case LOADSAVETYPE_LANDSCAPE:
@ -321,7 +376,7 @@ static bool browse(bool isSave, char* path, size_t pathSize)
fileType = FILE_EXTENSION_SC6;
title = isSave ? STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE : STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE;
desc.filters[0].name = language_get_string(STR_OPENRCT2_LANDSCAPE_FILE);
desc.filters[0].pattern = isSave ? "*.sc6" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7";
desc.filters[0].pattern = getFilterPatternByType(_type, isSave);
break;
case LOADSAVETYPE_SCENARIO:
@ -329,7 +384,7 @@ static bool browse(bool isSave, char* path, size_t pathSize)
fileType = FILE_EXTENSION_SC6;
title = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO;
desc.filters[0].name = language_get_string(STR_OPENRCT2_SCENARIO_FILE);
desc.filters[0].pattern = "*.sc6";
desc.filters[0].pattern = getFilterPatternByType(_type, isSave);
break;
case LOADSAVETYPE_TRACK:
@ -337,13 +392,13 @@ static bool browse(bool isSave, char* path, size_t pathSize)
fileType = FILE_EXTENSION_TD6;
title = isSave ? STR_FILE_DIALOG_TITLE_SAVE_TRACK : STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN;
desc.filters[0].name = language_get_string(STR_OPENRCT2_TRACK_DESIGN_FILE);
desc.filters[0].pattern = isSave ? "*.td6" : "*.td6;*.td4";
desc.filters[0].pattern = getFilterPatternByType(_type, isSave);
break;
case LOADSAVETYPE_IMAGE:
case LOADSAVETYPE_HEIGHTMAP:
title = STR_FILE_DIALOG_TITLE_LOAD_HEIGHTMAP;
desc.filters[0].name = language_get_string(STR_OPENRCT2_HEIGHTMAP_FILE);
desc.filters[0].pattern = "*.jpg;*.png;*.bmp";
desc.filters[0].pattern = getFilterPatternByType(_type, isSave);
break;
}
@ -462,22 +517,7 @@ static void window_loadsave_mouseup(rct_window* w, rct_widgetindex widgetIndex)
break;
case WIDX_DEFAULT:
switch (_type & 0x0E)
{
case LOADSAVETYPE_GAME:
platform_get_user_directory(path, "save", sizeof(path));
break;
case LOADSAVETYPE_LANDSCAPE:
platform_get_user_directory(path, "landscape", sizeof(path));
break;
case LOADSAVETYPE_SCENARIO:
platform_get_user_directory(path, "scenario", sizeof(path));
break;
case LOADSAVETYPE_TRACK:
platform_get_user_directory(path, "track", sizeof(path));
break;
}
getInitialDirectoryByType(_type, path, sizeof(path));
window_loadsave_populate_list(w, isSave, path, _extension);
window_init_scroll_widgets(w);
w->no_list_items = static_cast<uint16_t>(_listItems.size());
@ -862,14 +902,12 @@ static void window_loadsave_populate_list(rct_window* w, int32_t includeNewItem,
char filter[MAX_PATH];
char extCopy[64];
safe_strcpy(extCopy, extension, Util::CountOf(extCopy));
char* extToken;
bool showExtension = false;
extToken = strtok(extCopy, ";");
char* extToken = strtok(extCopy, ";");
while (extToken != nullptr)
{
safe_strcpy(filter, directory, Util::CountOf(filter));
safe_strcat_path(filter, "*", Util::CountOf(filter));
path_append_extension(filter, extToken, Util::CountOf(filter));
safe_strcat_path(filter, extToken, Util::CountOf(filter));
auto scanner = std::unique_ptr<IFileScanner>(Path::ScanDirectory(filter, false));
while (scanner->Next())
@ -1065,7 +1103,7 @@ static void window_loadsave_select(rct_window* w, const char* path)
break;
}
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_IMAGE):
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_HEIGHTMAP):
window_close_by_class(WC_LOADSAVE);
window_loadsave_invoke_callback(MODAL_RESULT_OK, pathBuffer);
break;

View File

@ -1183,7 +1183,7 @@ static void window_mapgen_heightmap_mouseup(rct_window* w, rct_widgetindex widge
case WIDX_HEIGHTMAP_SELECT:
{
auto intent = Intent(WC_LOADSAVE);
intent.putExtra(INTENT_EXTRA_LOADSAVE_TYPE, LOADSAVETYPE_LOAD | LOADSAVETYPE_IMAGE);
intent.putExtra(INTENT_EXTRA_LOADSAVE_TYPE, LOADSAVETYPE_LOAD | LOADSAVETYPE_HEIGHTMAP);
intent.putExtra(INTENT_EXTRA_CALLBACK, (void*)window_mapgen_heightmap_loadsave_callback);
context_open_intent(&intent);
return;

View File

@ -175,6 +175,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX {
WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM,
WIDX_SAVE_PLUGIN_DATA_CHECKBOX,
WIDX_STAY_CONNECTED_AFTER_DESYNC,
WIDX_ALWAYS_NATIVE_LOADSAVE,
WIDX_AUTOSAVE,
WIDX_AUTOSAVE_DROPDOWN,
WIDX_PATH_TO_RCT1_TEXT,
@ -355,11 +356,12 @@ static rct_widget window_options_advanced_widgets[] = {
{ WWT_CHECKBOX, 2, 10, 299, 84, 95, STR_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, STR_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM_TIP }, // Allow loading with incorrect checksum
{ WWT_CHECKBOX, 2, 10, 299, 99, 110, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP }, // Export plug-in objects with saved games
{ WWT_CHECKBOX, 2, 10, 299, 114, 125, STR_STAY_CONNECTED_AFTER_DESYNC, STR_STAY_CONNECTED_AFTER_DESYNC_TIP }, // Do not disconnect after the client desynchronises with the server
{ WWT_DROPDOWN, 1, 165, 299, 130, 141, STR_NONE, STR_NONE }, // Autosave dropdown
{ WWT_BUTTON, 1, 288, 298, 131, 140, STR_DROPDOWN_GLYPH, STR_AUTOSAVE_FREQUENCY_TIP }, // Autosave dropdown button
{ WWT_LABEL, 1, 23, 298, 148, 159, STR_PATH_TO_RCT1, STR_PATH_TO_RCT1_TIP }, // RCT 1 path text
{ WWT_BUTTON, 1, 24, 289, 163, 176, STR_NONE, STR_STRING_TOOLTIP }, // RCT 1 path button
{ WWT_BUTTON, 1, 289, 299, 163, 176, STR_CLOSE_X, STR_PATH_TO_RCT1_CLEAR_TIP }, // RCT 1 path clear button
{ WWT_CHECKBOX, 1, 10, 299, 129, 140, STR_ALWAYS_NATIVE_LOADSAVE, STR_ALWAYS_NATIVE_LOADSAVE_TIP }, // Use native load/save window
{ WWT_DROPDOWN, 1, 165, 299, 145, 157, STR_NONE, STR_NONE }, // Autosave dropdown
{ WWT_BUTTON, 1, 288, 298, 146, 156, STR_DROPDOWN_GLYPH, STR_AUTOSAVE_FREQUENCY_TIP }, // Autosave dropdown button
{ WWT_LABEL, 1, 23, 298, 165, 176, STR_PATH_TO_RCT1, STR_PATH_TO_RCT1_TIP }, // RCT 1 path text
{ WWT_BUTTON, 1, 24, 289, 180, 193, STR_NONE, STR_STRING_TOOLTIP }, // RCT 1 path button
{ WWT_BUTTON, 1, 289, 299, 180, 193, STR_CLOSE_X, STR_PATH_TO_RCT1_CLEAR_TIP }, // RCT 1 path clear button
{ WIDGETS_END },
};
@ -594,6 +596,7 @@ static uint64_t window_options_page_enabled_widgets[] = {
(1 << WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM) |
(1 << WIDX_SAVE_PLUGIN_DATA_CHECKBOX) |
(1 << WIDX_STAY_CONNECTED_AFTER_DESYNC) |
(1 << WIDX_ALWAYS_NATIVE_LOADSAVE) |
(1 << WIDX_AUTOSAVE) |
(1 << WIDX_AUTOSAVE_DROPDOWN) |
(1 << WIDX_PATH_TO_RCT1_TEXT) |
@ -929,6 +932,11 @@ static void window_options_mouseup(rct_window* w, rct_widgetindex widgetIndex)
config_save_default();
window_invalidate(w);
break;
case WIDX_ALWAYS_NATIVE_LOADSAVE:
gConfigGeneral.use_native_browse_dialog = !gConfigGeneral.use_native_browse_dialog;
config_save_default();
window_invalidate(w);
break;
case WIDX_PATH_TO_RCT1_BUTTON:
{
utf8string rct1path = platform_open_directory_browser(language_get_string(STR_PATH_TO_RCT1_BROWSER));
@ -1888,6 +1896,7 @@ static void window_options_invalidate(rct_window* w)
w, WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, gConfigGeneral.allow_loading_with_incorrect_checksum);
widget_set_checkbox_value(w, WIDX_SAVE_PLUGIN_DATA_CHECKBOX, gConfigGeneral.save_plugin_data);
widget_set_checkbox_value(w, WIDX_STAY_CONNECTED_AFTER_DESYNC, gConfigNetwork.stay_connected);
widget_set_checkbox_value(w, WIDX_ALWAYS_NATIVE_LOADSAVE, gConfigGeneral.use_native_browse_dialog);
break;
case WINDOW_OPTIONS_PAGE_TWITCH:

View File

@ -88,8 +88,7 @@ rct_window* window_scenarioselect_open(scenarioselect_callback callback, bool ti
rct_window* window_error_open(rct_string_id title, rct_string_id message);
rct_window* window_loadsave_open(int32_t type, const char* defaultName);
void window_loadsave_set_loadsave_callback(loadsave_callback cb);
rct_window* window_loadsave_open(int32_t type, const char* defaultName, loadsave_callback callback);
rct_window* window_track_place_open(const struct track_design_file_ref* tdFileRef);
rct_window* window_track_manage_open(struct track_design_file_ref* tdFileRef);

View File

@ -202,6 +202,7 @@ namespace Config
model->last_save_landscape_directory = reader->GetCString("last_landscape_directory", nullptr);
model->last_save_scenario_directory = reader->GetCString("last_scenario_directory", nullptr);
model->last_save_track_directory = reader->GetCString("last_track_directory", nullptr);
model->use_native_browse_dialog = reader->GetBoolean("use_native_browse_dialog", false);
model->window_limit = reader->GetInt32("window_limit", WINDOW_LIMIT_MAX);
model->zoom_to_cursor = reader->GetBoolean("zoom_to_cursor", true);
model->render_weather_effects = reader->GetBoolean("render_weather_effects", true);
@ -273,6 +274,7 @@ namespace Config
writer->WriteString("last_landscape_directory", model->last_save_landscape_directory);
writer->WriteString("last_scenario_directory", model->last_save_scenario_directory);
writer->WriteString("last_track_directory", model->last_save_track_directory);
writer->WriteBoolean("use_native_browse_dialog", model->use_native_browse_dialog);
writer->WriteInt32("window_limit", model->window_limit);
writer->WriteBoolean("zoom_to_cursor", model->zoom_to_cursor);
writer->WriteBoolean("render_weather_effects", model->render_weather_effects);

View File

@ -83,6 +83,7 @@ struct GeneralConfiguration
bool show_real_names_of_guests;
bool allow_early_completion;
// Loading and saving
bool confirmation_prompt;
int32_t load_save_sort;
utf8* last_save_game_directory;
@ -90,6 +91,7 @@ struct GeneralConfiguration
utf8* last_save_scenario_directory;
utf8* last_save_track_directory;
utf8* last_run_version;
bool use_native_browse_dialog;
};
struct InterfaceConfiguration

View File

@ -511,7 +511,7 @@ enum
LOADSAVETYPE_LANDSCAPE = 1 << 1,
LOADSAVETYPE_SCENARIO = 2 << 1,
LOADSAVETYPE_TRACK = 3 << 1,
LOADSAVETYPE_IMAGE = 4 << 1,
LOADSAVETYPE_HEIGHTMAP = 4 << 1,
};
enum

View File

@ -3888,6 +3888,9 @@ enum
STR_MASTER_VOLUME = 6262,
STR_MASTER_VOLUME_TIP = 6263,
STR_ALWAYS_NATIVE_LOADSAVE = 6264,
STR_ALWAYS_NATIVE_LOADSAVE_TIP = 6265,
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
STR_COUNT = 32768
};