diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index e03df7ca19..c62aa451c0 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -4205,6 +4205,7 @@ STR_5893 :Exchange Rate STR_5894 :Enter the exchange rate STR_5895 :Save Track STR_5896 :Track save failed! +STR_5897 :Window limit: ############# # Scenarios # diff --git a/src/config.c b/src/config.c index d06fb4be47..a9af40948e 100644 --- a/src/config.c +++ b/src/config.c @@ -226,6 +226,8 @@ config_property_definition _generalDefinitions[] = { { offsetof(general_configuration, last_save_landscape_directory), "last_landscape_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, { offsetof(general_configuration, last_save_scenario_directory), "last_scenario_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, { offsetof(general_configuration, last_save_track_directory), "last_track_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, + { offsetof(general_configuration, window_limit), "window_limit", CONFIG_VALUE_TYPE_UINT8, MAX_WINDOW_COUNT, NULL }, + }; config_property_definition _interfaceDefinitions[] = { diff --git a/src/config.h b/src/config.h index 628a2b381f..12ab76b984 100644 --- a/src/config.h +++ b/src/config.h @@ -196,6 +196,7 @@ typedef struct general_configuration { utf8string last_save_landscape_directory; utf8string last_save_scenario_directory; utf8string last_save_track_directory; + uint8 window_limit; } general_configuration; typedef struct interface_configuration { diff --git a/src/interface/console.c b/src/interface/console.c index 87e54f729b..bba0c36f1c 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -671,6 +671,9 @@ static int cc_get(const utf8 **argv, int argc) else if (strcmp(argv[0], "paint_segments") == 0) { console_printf("paint_segments %d", gShowSupportSegmentHeights); } + else if (strcmp(argv[0], "window_limit") == 0) { + console_printf("window_limit %d", gConfigGeneral.window_limit); + } else { console_writeline_warning("Invalid variable."); } @@ -844,6 +847,10 @@ static int cc_set(const utf8 **argv, int argc) gfx_invalidate_screen(); console_execute_silent("get paint_segments"); } + else if (strcmp(argv[0], "window_limit") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + window_set_window_limit(int_valid[0]); + console_execute_silent("get window_limit"); + } else if (invalidArgs) { console_writeline_error("Invalid arguments."); } @@ -1032,6 +1039,7 @@ utf8* console_variable_table[] = { "location", "window_scale", "paint_segments", + "window_limit", }; utf8* console_window_table[] = { "object_selection", diff --git a/src/interface/window.c b/src/interface/window.c index e72b51bbef..cb6dfef597 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -29,6 +29,7 @@ #include "viewport.h" #include "widget.h" #include "window.h" +#include "../config.h" #define RCT2_FIRST_WINDOW (g_window_list) #define RCT2_LAST_WINDOW (gWindowNextSlot - 1) @@ -348,6 +349,49 @@ static void window_all_wheel_input() return; } +void window_close_surplus(int cap, sint8 avoid_classification) +{ + int count, i, diff; + //find the amount of windows that are currently open + for (i = 0; i < MAX_WINDOW_COUNT; i++) { + if (&g_window_list[i] == RCT2_NEW_WINDOW) { + count = i; + break; + } + } + //difference between amount open and cap = amount to close + diff = count - cap; + for (i = 0; i < diff; i++) { + rct_window *w = NULL; + //iterates through the list until it finds the newest window, or a window that can be closed + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) { + if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE))) + break; + } + //skip window if window matches specified rct_windowclass (as user may be modifying via options) + if (avoid_classification != -1 && w != NULL && w->classification == avoid_classification) { + continue; + } + window_close(w); + } +} + +/* + * Changes the maximum amount of windows allowed + */ +void window_set_window_limit(int value) +{ + int prev = gConfigGeneral.window_limit; + int val = clamp(value, MIN_WINDOW_COUNT, MAX_WINDOW_COUNT); + gConfigGeneral.window_limit = val; + config_save_default(); + // Checks if value decreases and then closes surplus + // windows if one sets a limit lower than the number of windows open + if (val < prev) { + window_close_surplus(val, WC_OPTIONS); + } +} + /** * Opens a new window. * rct2: 0x006EACA4 @@ -363,7 +407,7 @@ static void window_all_wheel_input() rct_window *window_create(int x, int y, int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags) { // Check if there are any window slots left - if (RCT2_NEW_WINDOW >= &(g_window_list[MAX_WINDOW_COUNT])) { + if (RCT2_NEW_WINDOW >= &(g_window_list[gConfigGeneral.window_limit])) { rct_window *w = NULL; // Close least recently used window for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) @@ -775,7 +819,8 @@ void window_close_top() * * rct2: 0x006EE927 */ -void window_close_all() { +void window_close_all() +{ rct_window* w; window_close_by_class(WC_DROPDOWN); @@ -788,7 +833,8 @@ void window_close_all() { } } -void window_close_all_except_class(rct_windowclass cls) { +void window_close_all_except_class(rct_windowclass cls) +{ rct_window* w; window_close_by_class(WC_DROPDOWN); @@ -1224,7 +1270,6 @@ void window_push_others_below(rct_window *w1) } } - /** * * rct2: 0x006EE2E4 diff --git a/src/interface/window.h b/src/interface/window.h index 4b41b57b00..773c9b4368 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -515,6 +515,7 @@ extern modal_callback gLoadSaveCallback; typedef void (*close_callback)(); +#define MIN_WINDOW_COUNT 8 #define MAX_WINDOW_COUNT 64 // rct2: 0x01420078 @@ -532,6 +533,9 @@ extern uint16 gWindowMapFlashingFlags; void window_dispatch_update_all(); void window_update_all_viewports(); void window_update_all(); + +void window_set_window_limit(int value); + rct_window *window_create(int x, int y, int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags); rct_window *window_create_auto_pos(int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags); rct_window *window_create_centred(int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags); diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index df872b8c01..c3092e5c99 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -1129,7 +1129,7 @@ enum { STR_NUMBER_OF_ROTATIONS = 1869, STR_NUMBER_OF_ROTATIONS_TIP = 1870, STR_ARG18_COMMA16 = 1871, // Should probably be in RIDE domain - STR_COMMA16 = 1872, // Unused + STR_COMMA16 = 1872, STR_INCOME_PER_HOUR = 1873, STR_PROFIT_PER_HOUR = 1874, STR_GUEST_ITEM_FORMAT = 1875, @@ -3329,6 +3329,8 @@ enum { STR_FILE_DIALOG_TITLE_SAVE_TRACK = 5895, STR_TRACK_SAVE_FAILED = 5896, + STR_WINDOW_LIMIT = 5897, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/windows/options.c b/src/windows/options.c index b434d41524..25618e4368 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -161,6 +161,9 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_AUTO_OPEN_SHOPS, WIDX_DEFAULT_INSPECTION_INTERVAL, WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN, + WIDX_WINDOW_LIMIT, + WIDX_WINDOW_LIMIT_UP, + WIDX_WINDOW_LIMIT_DOWN, // Twitch WIDX_CHANNEL_BUTTON = WIDX_PAGE_START, @@ -308,6 +311,9 @@ static rct_widget window_options_misc_widgets[] = { { WWT_CHECKBOX, 2, 10, 299, 219, 230, STR_AUTO_OPEN_SHOPS, STR_AUTO_OPEN_SHOPS_TIP }, // Automatically open shops & stalls { WWT_DROPDOWN, 1, 155, 299, 234, 245, STR_NONE, STR_NONE }, // Default inspection time dropdown { WWT_DROPDOWN_BUTTON, 1, 288, 298, 235, 244, STR_DROPDOWN_GLYPH, STR_DEFAULT_INSPECTION_INTERVAL_TIP }, // Default inspection time dropdown button + { WWT_SPINNER, 1, 155, 299, 249, 260, STR_NONE, STR_NONE }, // Window limit + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 250, 254, STR_NUMERIC_UP, STR_NONE }, // Window limit up + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 255, 259, STR_NUMERIC_DOWN, STR_NONE }, // Window limit down { WIDGETS_END }, }; @@ -514,7 +520,10 @@ static uint32 window_options_page_enabled_widgets[] = { (1 << WIDX_STAY_CONNECTED_AFTER_DESYNC) | (1 << WIDX_AUTO_OPEN_SHOPS) | (1 << WIDX_DEFAULT_INSPECTION_INTERVAL) | - (1 << WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN), + (1 << WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN) | + (1 << WIDX_WINDOW_LIMIT) | + (1 << WIDX_WINDOW_LIMIT_UP) | + (1 << WIDX_WINDOW_LIMIT_DOWN), MAIN_OPTIONS_ENABLED_WIDGETS | (1 << WIDX_CHANNEL_BUTTON) | @@ -781,6 +790,7 @@ static void window_options_mouseup(rct_window *w, int widgetIndex) gConfigGeneral.auto_open_shops = !gConfigGeneral.auto_open_shops; config_save_default(); window_invalidate(w); + break; } break; @@ -1121,6 +1131,20 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, 7); dropdown_set_checked(gConfigGeneral.default_inspection_interval, true); break; + case WIDX_WINDOW_LIMIT_UP: + i = gConfigGeneral.window_limit; + if (i < MAX_WINDOW_COUNT) { + window_set_window_limit(++i); + } + window_invalidate(w); + break; + case WIDX_WINDOW_LIMIT_DOWN: + i = gConfigGeneral.window_limit; + if (i > MIN_WINDOW_COUNT) { + window_set_window_limit(--i); + } + window_invalidate(w); + break; } break; @@ -1564,6 +1588,8 @@ static void window_options_invalidate(rct_window *w) if (gParkFlags & PARK_FLAGS_LOCK_REAL_NAMES_OPTION) w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); + w->hold_down_widgets |= (1 << WIDX_WINDOW_LIMIT_UP) | (1 << WIDX_WINDOW_LIMIT_DOWN); + // save plugin data checkbox: visible or not window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; @@ -1593,6 +1619,9 @@ static void window_options_invalidate(rct_window *w) window_options_misc_widgets[WIDX_AUTO_OPEN_SHOPS].type = WWT_CHECKBOX; window_options_misc_widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].type = WWT_DROPDOWN; window_options_misc_widgets[WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_misc_widgets[WIDX_WINDOW_LIMIT].type = WWT_SPINNER; + window_options_misc_widgets[WIDX_WINDOW_LIMIT_UP].type = WWT_DROPDOWN_BUTTON; + window_options_misc_widgets[WIDX_WINDOW_LIMIT_DOWN].type = WWT_DROPDOWN_BUTTON; break; case WINDOW_OPTIONS_PAGE_TWITCH: @@ -1790,6 +1819,15 @@ static void window_options_paint(rct_window *w, rct_drawpixelinfo *dpi) w->x + window_options_misc_widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].left + 1, w->y + window_options_misc_widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].top ); + gfx_draw_string_left(dpi, STR_WINDOW_LIMIT, w, w->colours[1], w->x + 10, w->y + window_options_misc_widgets[WIDX_WINDOW_LIMIT].top + 1); + gfx_draw_string_left( + dpi, + STR_COMMA16, + &gConfigGeneral.window_limit, + w->colours[1], + w->x + window_options_misc_widgets[WIDX_WINDOW_LIMIT].left + 1, + w->y + window_options_misc_widgets[WIDX_WINDOW_LIMIT].top + ); break; } }