From 633454f0dd29c842cf6da1d8628ea8cba3ba63e7 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 14 Mar 2011 19:03:17 +0000 Subject: [PATCH] (svn r22252) [1.1] -Backport from trunk: - Fix: Do not resort town, industry and signs list directly in OnInvalidateData(). There might be a scheduled rebuild which needs execution first. So, only set a trigger for resorting [FS#4546] (r22249, r22248, r22247, r22246, r22245, r22244, r22243, r22242, r22241, r22236, r22228, r22227, r22226) --- src/ai/ai_gui.cpp | 39 ++++++++++++++++++---- src/ai/api/ai_log.cpp | 2 +- src/autoreplace_gui.cpp | 8 ++++- src/build_vehicle_gui.cpp | 8 ++++- src/company_gui.cpp | 8 ++++- src/depot_gui.cpp | 7 +++- src/dock_gui.cpp | 8 ++++- src/fios_gui.cpp | 9 ++++- src/genworld_gui.cpp | 8 ++++- src/graph_gui.cpp | 38 +++++++++++++++++---- src/group_gui.cpp | 9 ++++- src/industry_gui.cpp | 39 ++++++++++++++++++---- src/intro_gui.cpp | 8 ++++- src/main_gui.cpp | 8 ++++- src/misc_gui.cpp | 15 +++++++-- src/music_gui.cpp | 16 +++++++-- src/network/network_chat_gui.cpp | 7 +++- src/network/network_content_gui.cpp | 8 ++++- src/network/network_gui.cpp | 7 +++- src/newgrf_debug_gui.cpp | 8 ++++- src/newgrf_gui.cpp | 15 +++++++-- src/news_gui.cpp | 24 +++++++++++-- src/order_gui.cpp | 20 ++++++++--- src/osk_gui.cpp | 8 ++++- src/rail_gui.cpp | 8 ++++- src/road_gui.cpp | 8 ++++- src/settings_gui.cpp | 16 +++++++-- src/signs_gui.cpp | 36 ++++++++++++++------ src/smallmap_gui.cpp | 7 ++-- src/station_gui.cpp | 16 +++++++-- src/statusbar_gui.cpp | 8 ++++- src/subsidy_gui.cpp | 8 ++++- src/timetable_gui.cpp | 12 +++++-- src/toolbar_gui.cpp | 16 +++++++-- src/town_gui.cpp | 31 ++++++++++++++--- src/train_cmd.cpp | 4 +-- src/transparency_gui.cpp | 8 ++++- src/tree_gui.cpp | 8 ++++- src/vehicle.cpp | 2 +- src/vehicle_gui.cpp | 52 +++++++++++++++++++++++++---- src/viewport_gui.cpp | 8 ++++- src/waypoint_gui.cpp | 8 ++++- src/window.cpp | 49 +++++++++++++++++---------- src/window_func.h | 4 +-- src/window_gui.h | 26 ++++++--------- 45 files changed, 533 insertions(+), 129 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 1bc7ad9de9..edbd9652c9 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -182,13 +182,20 @@ struct AIListWindow : public Window { nwi->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) { delete this; return; } + if (!gui_scope) return; + this->vscroll->SetCount((int)this->ai_info_list->size() + 1); /* selected goes from -1 .. length of ai list - 1. */ @@ -437,7 +444,12 @@ struct AISettingsWindow : public Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) delete this; } @@ -692,12 +704,19 @@ struct AIConfigWindow : public Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (!IsEditable(this->selected_slot)) { this->selected_slot = INVALID_COMPANY; } + if (!gui_scope) return; + this->SetWidgetDisabledState(AIC_WIDGET_DECREASE, GetGameSettings().difficulty.max_no_competitors == 0); this->SetWidgetDisabledState(AIC_WIDGET_INCREASE, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES - 1); this->SetWidgetDisabledState(AIC_WIDGET_CHANGE, this->selected_slot == INVALID_COMPANY); @@ -1032,11 +1051,16 @@ struct AIDebugWindow : public QueryStringBaseWindow { return state; } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == -1 || ai_debug_company == data) this->SetDirty(); - if (data == -2) { + if (gui_scope && data == -2) { /* The continue button should be disabled when the game is unpaused and * it was previously paused by the break string ( = a line in the log * was highlighted )*/ @@ -1048,8 +1072,9 @@ struct AIDebugWindow : public QueryStringBaseWindow { } } - /* If the log message is related to the active company tab, check the break string */ - if (data == ai_debug_company && this->break_check_enabled && !StrEmpty(this->edit_str_buf)) { + /* If the log message is related to the active company tab, check the break string. + * This needs to be done in gameloop-scope, so the AI is suspended immediately. */ + if (!gui_scope && data == ai_debug_company && this->break_check_enabled && !StrEmpty(this->edit_str_buf)) { /* Get the log instance of the active company */ Backup cur_company(_current_company, ai_debug_company, FILE_LINE); AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer(); diff --git a/src/ai/api/ai_log.cpp b/src/ai/api/ai_log.cpp index af2295df1b..7a269030d3 100644 --- a/src/ai/api/ai_log.cpp +++ b/src/ai/api/ai_log.cpp @@ -75,7 +75,7 @@ /* Also still print to debug window */ DEBUG(ai, level, "[%d] [%c] %s", (uint)_current_company, logc, log->lines[log->pos]); - InvalidateWindowData(WC_AI_DEBUG, 0, _current_company, true); // breakpoint handling needs calling Invalidate immediately. + InvalidateWindowData(WC_AI_DEBUG, 0, _current_company); } /* static */ void AILog::FreeLogPointer() diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index af75dec1b9..2f38fa10b3 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -491,9 +491,15 @@ public: this->GetWidget(RVW_WIDGET_RIGHT_MATRIX)->widget_data = (this->vscroll[0]->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data != 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->engines[0].ForceRebuild(); } else { this->engines[1].ForceRebuild(); diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index dd3d8731d8..2caa42d9dd 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1218,8 +1218,14 @@ struct BuildVehicleWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ if (this->vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 8471ccfe3d..7c45f3fed3 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -800,8 +800,14 @@ public: } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetWidgetsDisabledState(true, SCLW_WIDGET_CLASS_RAIL, SCLW_WIDGET_CLASS_ROAD, SCLW_WIDGET_CLASS_SHIP, SCLW_WIDGET_CLASS_AIRCRAFT, WIDGET_LIST_END); bool current_class_valid = this->livery_class == LC_OTHER; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index d3866af425..6779b9b836 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -635,7 +635,12 @@ struct DepotWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { this->generate_list = true; } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 8e667ec3c0..f7c50fc6af 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -119,8 +119,14 @@ struct BuildDocksToolbarWindow : Window { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } - void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), DTW_DEPOT, DTW_STATION, diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index c9bc284f54..3b97b420b2 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -659,17 +659,24 @@ public: this->vscroll->SetCapacityFromWidget(this, SLWW_DRIVES_DIRECTORIES_LIST); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { switch (data) { case 0: /* Rescan files */ this->selected = NULL; _load_check_data.Clear(); + if (!gui_scope) break; BuildFileList(); /* FALL THROUGH */ case 1: /* Selection changes */ + if (!gui_scope) break; if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) { this->SetWidgetDisabledState(SLWW_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors() || !(_load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs())); diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index e8d983fd1f..58bd97f5c5 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -425,8 +425,14 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* Update the climate buttons */ this->SetWidgetLoweredState(GLAND_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); this->SetWidgetLoweredState(GLAND_ARCTIC, _settings_newgame.game_creation.landscape == LT_ARCTIC); diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 28ccf2bed7..3c1047b431 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -91,8 +91,14 @@ struct GraphLegendWindow : Window { InvalidateWindowData(WC_COMPANY_VALUE, 0); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (Company::IsValidID(data)) return; SetBit(_legend_excluded_companies, data); @@ -543,8 +549,14 @@ public: this->UpdateStatistics(false); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->UpdateStatistics(true); } @@ -1013,8 +1025,14 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { /* Override default OnTick */ } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->OnHundredthTick(); } @@ -1247,9 +1265,15 @@ public: } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->companies.ForceRebuild(); } else { this->companies.ForceResort(); @@ -1488,11 +1512,13 @@ struct PerformanceRatingDetailWindow : Window { } /** - * Invalidate the data of this window. + * Some data on this window has become invalid. * @param data the company ID of the company that is going to be removed + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. */ - virtual void OnInvalidateData(int data) + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* Disable the companies who are not active */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { this->SetWidgetDisabledState(i + PRW_COMPANY_FIRST, !Company::IsValidID(i)); diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 1c1453bcf6..6cbd89920c 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -253,9 +253,15 @@ public: } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->vehicles.ForceRebuild(); this->groups.ForceRebuild(); } else { @@ -263,6 +269,7 @@ public: this->groups.ForceResort(); } + /* Process ID-invalidation in command-scope as well */ if (this->group_rename != INVALID_GROUP && !Group::IsValidID(this->group_rename)) { DeleteWindowByClass(WC_QUERY_STRING); this->group_rename = INVALID_GROUP; diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index f3e2c2b1c3..ab1cfe28fd 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -597,8 +597,14 @@ public: this->RaiseButtons(); } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetupArrays(); const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); @@ -947,8 +953,14 @@ public: this->SetDirty(); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; const Industry *i = Industry::Get(this->window_number); if (IsProductionAlterable(i)) { const IndustrySpec *ind = GetIndustrySpec(i->type); @@ -1334,20 +1346,31 @@ public: this->vscroll->SetCapacityFromWidget(this, IDW_INDUSTRY_LIST); } + virtual void OnPaint() + { + if (this->industries.NeedRebuild()) this->BuildSortIndustriesList(); + this->DrawWidgets(); + } + virtual void OnHundredthTick() { this->industries.ForceResort(); this->BuildSortIndustriesList(); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->industries.ForceRebuild(); } else { this->industries.ForceResort(); } - this->BuildSortIndustriesList(); } }; @@ -2386,13 +2409,15 @@ struct IndustryCargoesWindow : public Window { } /** - * Notify the window about external events. + * Some data on this window has become invalid. + * @param data Information about the changed data. * - data = 0 .. NUM_INDUSTRYTYPES - 1: Display the chain around the given industry. * - data = NUM_INDUSTRYTYPES: Stop sending updates to the smallmap window. - * @param data The event. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. */ - virtual void OnInvalidateData(int data) + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (data == NUM_INDUSTRYTYPES) { if (this->IsWidgetLowered(ICW_NOTIFY)) { this->RaiseWidget(ICW_NOTIFY); diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 8f8458cbb5..1f5692d422 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -55,8 +55,14 @@ struct SelectGameWindow : public Window { this->OnInvalidateData(); } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetWidgetLoweredState(SGI_TEMPERATE_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); this->SetWidgetLoweredState(SGI_ARCTIC_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_ARCTIC); this->SetWidgetLoweredState(SGI_TROPIC_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TROPIC); diff --git a/src/main_gui.cpp b/src/main_gui.cpp index ed85860da5..45f2d7ebb5 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -432,8 +432,14 @@ struct MainWindow : Window } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* Forward the message to the appropiate toolbar (ingame or scenario editor) */ InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true); } diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 7d7aa37faa..ce6619cd5f 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -331,8 +331,14 @@ public: ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; switch (data) { case 1: /* ReInit, "debug" sprite might have changed */ @@ -638,7 +644,12 @@ public: return pt; } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { /* If company gets shut down, while displaying an error about it, remove the error message. */ if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) delete this; diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 7c19c406b1..5a823aa2dd 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -312,8 +312,14 @@ struct MusicTrackSelectionWindow : public Window { } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; for (int i = 0; i < 6; i++) { this->SetWidgetLoweredState(MTSW_ALL + i, i == _msf.playlist); } @@ -637,8 +643,14 @@ struct MusicWindow : public Window { } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; for (int i = 0; i < 6; i++) { this->SetWidgetLoweredState(MW_ALL + i, i == _msf.playlist); } diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index e610f9cbf4..6a2c768aaf 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -531,7 +531,12 @@ struct NetworkChatWindow : public QueryStringBaseWindow { ShowOnScreenKeyboard(this, wid, NWCW_CLOSE, NWCW_SENDBUTTON); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == this->dest) delete this; } diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index ee3a325d9f..13e0b5d59c 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -751,8 +751,14 @@ public: this->InvalidateData(); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (this->content.NeedRebuild()) this->BuildContentList(); /* To sum all the bytes we intend to download */ diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index e62f2bcaee..0eb99ce7fb 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -794,7 +794,12 @@ public: if (this->field == NGWW_CLIENT) this->HandleEditBox(NGWW_CLIENT); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == 1) { this->server = NULL; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index b96ecbd7f8..40581b9b2d 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -772,8 +772,14 @@ struct SpriteAlignerWindow : Window { this->SetDirty(); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (data == 1) { /* Sprite picker finished */ this->RaiseWidget(SAW_PICKER); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 2034ae6abe..a1e45e3cc2 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -379,8 +379,14 @@ struct NewGRFParametersWindow : public Window { nwi->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (!this->action14present) { this->SetWidgetDisabledState(GRFPAR_WIDGET_NUMPAR_DEC, this->grf_config->num_params == 0); this->SetWidgetDisabledState(GRFPAR_WIDGET_NUMPAR_INC, this->grf_config->num_params >= this->grf_config->num_valid_params); @@ -1025,15 +1031,18 @@ struct NewGRFWindow : public QueryStringBaseWindow { } /** - * Calback to update internal data. + * Some data on this window has become invalid. + * @param data Information about the changed data. * - 0: (optionally) build availables, update button status. * - 1: build availables, Add newly found grfs, update button status. * - 2: (optionally) build availables, Reset preset, + 3 * - 3: (optionally) build availables, Update active scrollbar, update button status. * - 4: Force a rebuild of the availables, + 2 + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. */ - virtual void OnInvalidateData(int data = 0) + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; switch (data) { default: NOT_REACHED(); case 0: diff --git a/src/news_gui.cpp b/src/news_gui.cpp index a958e63926..4289285fc5 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -498,8 +498,14 @@ struct NewsWindow : Window { return ES_NOT_HANDLED; } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* The chatbar has notified us that is was either created or closed */ int newtop = this->top + this->chat_height - data; this->chat_height = data; @@ -1035,8 +1041,14 @@ struct MessageHistoryWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->vscroll->SetCount(_total_news); } @@ -1201,8 +1213,14 @@ struct MessageOptionsWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* Update the dropdown value for 'set all categories'. */ this->GetWidget(WIDGET_NEWSOPT_DROP_SUMMARY)->widget_data = this->message_opt[this->state]; diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 6c40f98527..b1889a5116 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -805,13 +805,18 @@ public: } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { - VehicleOrderID from = GB(data, 0, 8); - VehicleOrderID to = GB(data, 8, 8); + VehicleOrderID from = INVALID_VEH_ORDER_ID; + VehicleOrderID to = INVALID_VEH_ORDER_ID; switch (data) { - case 0: + case -666: /* Autoreplace replaced the vehicle */ this->vehicle = Vehicle::Get(this->window_number); break; @@ -830,6 +835,11 @@ public: break; default: + if (data < 0) break; + + if (gui_scope) break; // only do this once; from command scope + from = GB(data, 0, 8); + to = GB(data, 8, 8); /* Moving an order. If one of these is INVALID_VEH_ORDER_ID, then * the order is being created / removed */ if (this->selected_order == -1) break; @@ -859,7 +869,7 @@ public: } this->vscroll->SetCount(this->vehicle->GetNumOrders() + 1); - this->UpdateButtonState(); + if (gui_scope) this->UpdateButtonState(); /* Scroll to the new order. */ if (from == INVALID_VEH_ORDER_ID && to != INVALID_VEH_ORDER_ID && !this->vscroll->IsVisible(to)) { diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index 0edb2eea3f..cd323b362c 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -247,8 +247,14 @@ struct OskWindow : public Window { this->parent->SetWidgetDirty(this->text_btn); } - virtual void OnInvalidateData(int) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetWidgetDirty(OSK_WIDGET_TEXT); } }; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 2b391218b6..36576a3ca2 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1617,8 +1617,14 @@ public: this->InvalidateData(); } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type); this->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button); diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 0a99513143..9637240f33 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -341,8 +341,14 @@ struct BuildRoadToolbarWindow : Window { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } - void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD), RTW_DEPOT, RTW_BUS_STATION, diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index e5056457cc..0656ed60f4 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -460,8 +460,14 @@ struct GameOptionsWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->SetWidgetLoweredState(GOW_FULLSCREEN_BUTTON, _fullscreen); bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; @@ -724,8 +730,14 @@ public: } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; uint i; const SettingDesc *sd = GetSettingFromName("difficulty.max_no_competitors", &i); for (i = 0; i < GAME_DIFFICULTY_NUM; i++, sd++) { diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 7cdc1151c3..40039c3cfa 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -164,9 +164,7 @@ struct SignListWindow : QueryStringBaseWindow, SignList { /* Create initial list. */ this->signs.ForceRebuild(); this->signs.ForceResort(); - this->BuildSignsList(); - this->SortSignsList(); - this->vscroll->SetCount(this->signs.Length()); + this->BuildSortSignList(); } /** @@ -214,6 +212,7 @@ struct SignListWindow : QueryStringBaseWindow, SignList { virtual void OnPaint() { + if (this->signs.NeedRebuild()) this->BuildSortSignList(); this->DrawWidgets(); if (!this->IsShaded()) this->DrawEditBox(SLW_FILTER_TEXT); } @@ -352,23 +351,38 @@ struct SignListWindow : QueryStringBaseWindow, SignList { this->HandleEditBox(SLW_FILTER_TEXT); } + void BuildSortSignList() + { + if (this->signs.NeedRebuild()) { + this->BuildSignsList(); + this->vscroll->SetCount(this->signs.Length()); + this->SetWidgetDirty(SLW_CAPTION); + } + this->SortSignsList(); + } - virtual void OnInvalidateData(int data) + virtual void OnHundredthTick() + { + this->BuildSortSignList(); + this->SetDirty(); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { /* When there is a filter string, we always need to rebuild the list even if * the amount of signs in total is unchanged, as the subset of signs that is - * accepted by the filter might has changed. - */ + * accepted by the filter might has changed. */ if (data == 0 || !StrEmpty(this->filter_string)) { // New or deleted sign, or there is a filter string + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->signs.ForceRebuild(); - this->BuildSignsList(); - this->SetWidgetDirty(SLW_CAPTION); - this->vscroll->SetCount(this->signs.Length()); } else { // Change of sign contents while there is no filter string this->signs.ForceResort(); } - - this->SortSignsList(); } static Hotkey signlist_hotkeys[]; diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index b7bcd9c20c..2fd86623dc 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1423,12 +1423,15 @@ public: } /** - * Notifications for the smallmap window. + * Some data on this window has become invalid. + * @param data Information about the changed data. * - data = 0: Displayed industries at the industry chain window have changed. * - data = 1: Companies have changed. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. */ - virtual void OnInvalidateData(int data) + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; switch (data) { case 1: /* The owner legend has already been rebuilt. */ diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 433ab12bba..e55c03226c 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -687,9 +687,15 @@ public: this->vscroll->SetCapacityFromWidget(this, SLW_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->stations.ForceRebuild(); } else { this->stations.ForceResort(); @@ -1448,8 +1454,14 @@ struct SelectStationWindow : Window { this->vscroll->SetCapacityFromWidget(this, JSW_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; FindStationsNearby(this->area, true); this->vscroll->SetCount(_stations_nearby_list.Length() + 1); this->SetDirty(); diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index 4c11843367..82ffeb2393 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -183,8 +183,14 @@ struct StatusBarWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; switch (data) { default: NOT_REACHED(); case SBI_SAVELOAD_START: this->saving = true; break; diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp index 0b9182fdd2..9e31fb970d 100644 --- a/src/subsidy_gui.cpp +++ b/src/subsidy_gui.cpp @@ -215,8 +215,14 @@ struct SubsidyListWindow : Window { this->vscroll->SetCapacityFromWidget(this, SLW_PANEL); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->vscroll->SetCount(this->CountLines()); } }; diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index dc807fe77b..7abe4f4f0b 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -243,10 +243,15 @@ struct TimetableWindow : Window { return (sel < v->GetNumOrders() * 2 && sel >= 0) ? sel : INVALID_ORDER; } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { switch (data) { - case 0: + case -666: /* Autoreplace replaced the vehicle */ this->vehicle = Vehicle::Get(this->window_number); break; @@ -260,11 +265,14 @@ struct TimetableWindow : Window { break; case -2: + if (!gui_scope) break; this->UpdateSelectionStates(); this->ReInit(); break; default: { + if (gui_scope) break; // only do this once; from command scope + /* Moving an order. If one of these is INVALID_VEH_ORDER_ID, then * the order is being created / removed */ if (this->sel_index == -1) break; diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index e57b2f101b..711b738467 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1482,8 +1482,14 @@ struct MainToolbarWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, TBN_ZOOMIN, TBN_ZOOMOUT); } @@ -1792,8 +1798,14 @@ struct ScenarioEditorToolbarWindow : Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, TBSE_ZOOMIN, TBSE_ZOOMOUT); } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index fce2a8ce6c..c2a8909a63 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -523,8 +523,14 @@ public: } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* Called when setting station noise or required cargos have changed, in order to resize the window */ this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading this->ResizeWindowAsNeeded(); @@ -846,6 +852,12 @@ public: } } + virtual void OnPaint() + { + if (this->towns.NeedRebuild()) this->BuildSortTownList(); + this->DrawWidgets(); + } + virtual void OnHundredthTick() { this->BuildSortTownList(); @@ -857,14 +869,19 @@ public: this->vscroll->SetCapacityFromWidget(this, TDW_CENTERTOWN); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->towns.ForceRebuild(); } else { this->towns.ForceResort(); } - this->BuildSortTownList(); } }; @@ -1157,8 +1174,14 @@ public: this->UpdateButtons(false); } - virtual void OnInvalidateData(int) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->UpdateButtons(true); } }; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index f62063aba8..ed59fb4d53 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -264,7 +264,7 @@ void Train::ConsistChanged(bool same_length) if (this->IsFrontEngine()) { this->UpdateAcceleration(); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); - InvalidateWindowData(WC_VEHICLE_REFIT, this->index); // Important, do not invalidate immediately. The refit window tests commands. + InvalidateWindowData(WC_VEHICLE_REFIT, this->index); } } @@ -1092,7 +1092,7 @@ static void NormaliseTrainHead(Train *head) if (!head->IsFrontEngine()) return; /* Update the refit button and window */ - InvalidateWindowData(WC_VEHICLE_REFIT, head->index); // Important, do not invalidate immediately. The refit window tests commands. + InvalidateWindowData(WC_VEHICLE_REFIT, head->index); SetWindowWidgetDirty(WC_VEHICLE_VIEW, head->index, VVW_WIDGET_REFIT_VEH); /* If we don't have a unit number yet, set one. */ diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp index 30b70cae03..95b84ae039 100644 --- a/src/transparency_gui.cpp +++ b/src/transparency_gui.cpp @@ -125,8 +125,14 @@ public: return pt; } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; for (uint i = TTW_WIDGET_BEGIN; i < TTW_WIDGET_END; i++) { this->SetWidgetLoweredState(i, IsTransparencySet((TransparencyOption)(i - TTW_WIDGET_BEGIN))); } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index ebbd2d1895..8623a3ff5b 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -144,8 +144,14 @@ public: } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; this->base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; this->count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index d2feacc075..ec78d8f428 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2270,7 +2270,7 @@ void Vehicle::RemoveFromShared() } else if (were_first) { /* If we were the first one, update to the new first one. * Note: FirstShared() is already the new first */ - InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31), true); + InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31)); } this->next_shared = NULL; diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 6efbecf533..324a4d9797 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -683,9 +683,15 @@ struct RefitWindow : public Window { } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { switch (data) { + case -666: // Autoreplace replaced the vehicle; selected_vehicle became invalid. case 0: { // The consist has changed; rebuild the entire list. /* Clear the selection. */ Vehicle *v = Vehicle::Get(this->window_number); @@ -695,6 +701,7 @@ struct RefitWindow : public Window { } case 2: { // The vehicle selection has changed; rebuild the entire list. + if (!gui_scope) break; this->BuildRefitList(); /* The vehicle width has changed too. */ @@ -720,6 +727,7 @@ struct RefitWindow : public Window { } case 1: // A new cargo has been selected. + if (!gui_scope) break; this->cargo = GetRefitOption(); break; } @@ -1120,8 +1128,8 @@ static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_ _thd.window_number = to_index; } - /* Notify the window immediately, without scheduling. */ - w->InvalidateData(); + /* Notify the window. */ + w->InvalidateData(-666, false); } } @@ -1594,9 +1602,15 @@ public: this->GetWidget(VLW_WIDGET_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { - if (HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) { + if (!gui_scope && HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) { + /* Needs to be done in command-scope, so everything stays valid */ this->vli.index = GB(data, 0, 20); this->window_number = this->vli.Pack(); this->vehicles.ForceRebuild(); @@ -1604,6 +1618,7 @@ public: } if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->vehicles.ForceRebuild(); } else { this->vehicles.ForceResort(); @@ -1778,8 +1793,19 @@ struct VehicleDetailsWindow : Window { this->tab = TDW_TAB_CARGO; } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (data == -666) { + /* Autoreplace replaced the vehicle. + * Nothing to do for this window. */ + return; + } + if (!gui_scope) return; const Vehicle *v = Vehicle::Get(this->window_number); if (v->type == VEH_ROAD) { const NWidgetBase *nwid_info = this->GetWidget(VLD_WIDGET_MIDDLE_DETAILS); @@ -2581,6 +2607,20 @@ public: } } + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data == -666) { + /* Autoreplace replaced the vehicle. + * Nothing to do for this window. */ + return; + } + } + virtual bool IsNewGRFInspectable() const { return ::IsNewGRFInspectable(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); diff --git a/src/viewport_gui.cpp b/src/viewport_gui.cpp index 1a85311b6d..103b27cb28 100644 --- a/src/viewport_gui.cpp +++ b/src/viewport_gui.cpp @@ -148,8 +148,14 @@ public: } } - virtual void OnInvalidateData(int data = 0) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */ HandleZoomMessage(this, this->viewport, EVW_ZOOMIN, EVW_ZOOMOUT); } diff --git a/src/waypoint_gui.cpp b/src/waypoint_gui.cpp index 23c9781e33..af126f3ae5 100644 --- a/src/waypoint_gui.cpp +++ b/src/waypoint_gui.cpp @@ -114,8 +114,14 @@ public: } } - virtual void OnInvalidateData(int data) + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { + if (!gui_scope) return; /* You can only change your own waypoints */ this->SetWidgetDisabledState(WAYPVW_RENAME, !this->wp->IsInUse() || (this->wp->owner != _local_company && this->wp->owner != OWNER_NONE)); /* Disable the widget for waypoints with no use */ diff --git a/src/window.cpp b/src/window.cpp index 57c753c52c..fdf8811170 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2403,6 +2403,11 @@ void InputLoop() void UpdateWindows() { Window *w; + + FOR_ALL_WINDOWS_FROM_FRONT(w) { + w->ProcessScheduledInvalidations(); + } + static int we4_timer = 0; int t = we4_timer + 1; @@ -2420,7 +2425,6 @@ void UpdateWindows() if (!(w->flags4 & WF_WHITE_BORDER_MASK)) w->SetDirty(); } - w->ProcessScheduledInvalidations(); } DrawDirtyBlocks(); @@ -2477,46 +2481,55 @@ void SetWindowClassesDirty(WindowClass cls) /** * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) - * Note that by default the invalidation is not executed immediately but is scheduled till the next redraw. + * + * Note that by default the invalidation is not considered to be called from GUI scope. + * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw. * The asynchronous execution is important to prevent GUI code being executed from command scope. + * When not in GUI-scope: + * - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of + * the command which triggered the invalidation. (town rating and such) + * - OnInvalidateData() may not rely on _current_company == _local_company. + * This implies that no NewGRF callbacks may be run. + * + * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled + * invalidations may be called with invalidation-data, which is already invalid at the point of execution. + * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command + * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state + * when the invalidation was scheduled; passed IDs may have got invalid in the mean time. + * + * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice. + * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice. + * * @param cls Window class * @param number Window number within the class * @param data The data to invalidate with - * @param immediately If true then do not schedule the event, but execute immediately. + * @param gui_scope Whether the call is done from GUI scope */ -void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool immediately) +void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls && w->window_number == number) { - if (immediately) { - w->InvalidateData(data); - } else { - w->ScheduleInvalidateData(data); - } + w->InvalidateData(data, gui_scope); } } } /** * Mark window data of all windows of a given class as invalid (in need of re-computing) - * Note that by default the invalidation is not executed immediately but is scheduled till the next redraw. - * The asynchronous execution is important to prevent GUI code being executed from command scope. + * Note that by default the invalidation is not considered to be called from GUI scope. + * See InvalidateWindowData() for details on GUI-scope vs. command-scope. * @param cls Window class * @param data The data to invalidate with - * @param immediately If true then do not schedule the event, but execute immediately. + * @param gui_scope Whether the call is done from GUI scope */ -void InvalidateWindowClassesData(WindowClass cls, int data, bool immediately) +void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls) { - if (immediately) { - w->InvalidateData(data); - } else { - w->ScheduleInvalidateData(data); - } + w->InvalidateData(data, gui_scope); } } } diff --git a/src/window_func.h b/src/window_func.h index 43f50111d4..604cb1d98a 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -34,8 +34,8 @@ void ResetWindowSystem(); void SetupColoursAndInitialWindow(); void InputLoop(); -void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool immediately = false); -void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool immediately = false); +void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool gui_scope = false); +void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = false); void DeleteNonVitalWindows(); void DeleteAllNonVitalWindows(); diff --git a/src/window_gui.h b/src/window_gui.h index 3254ee8c4c..0ec585e34a 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -434,22 +434,16 @@ public: /** * Mark this window's data as invalid (in need of re-computing) * @param data The data to invalidate with + * @param gui_scope Whether the funtion is called from GUI scope. */ - void InvalidateData(int data = 0) + void InvalidateData(int data = 0, bool gui_scope = true) { this->SetDirty(); - this->OnInvalidateData(data); - } - - /** - * Schedule a invalidation call for next redraw. - * Important for asynchronous invalidation from commands. - * @param data The data to invalidate with - */ - void ScheduleInvalidateData(int data = 0) - { - this->SetDirty(); - *this->scheduled_invalidation_data.Append() = data; + if (!gui_scope) { + /* Schedule GUI-scope invalidation for next redraw. */ + *this->scheduled_invalidation_data.Append() = data; + } + this->OnInvalidateData(data, gui_scope); } /** @@ -458,7 +452,7 @@ public: void ProcessScheduledInvalidations() { for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { - this->OnInvalidateData(*data); + this->OnInvalidateData(*data, true); } this->scheduled_invalidation_data.Clear(); } @@ -651,9 +645,9 @@ public: /** * Some data on this window has become invalid. * @param data information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. */ - virtual void OnInvalidateData(int data = 0) {} - + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) {} /** * The user clicked some place on the map when a tile highlight mode