OpenTTD Source  20241120-master-g6d3adc6169
settings_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "currency.h"
12 #include "error.h"
13 #include "settings_gui.h"
14 #include "textbuf_gui.h"
15 #include "command_func.h"
16 #include "network/network.h"
18 #include "town.h"
19 #include "settings_internal.h"
20 #include "strings_func.h"
21 #include "window_func.h"
22 #include "string_func.h"
23 #include "dropdown_type.h"
24 #include "dropdown_func.h"
25 #include "dropdown_common_type.h"
26 #include "slider_func.h"
27 #include "highscore.h"
28 #include "base_media_base.h"
29 #include "company_base.h"
30 #include "company_func.h"
31 #include "viewport_func.h"
32 #include "core/geometry_func.hpp"
33 #include "ai/ai.hpp"
34 #include "blitter/factory.hpp"
35 #include "language.h"
36 #include "textfile_gui.h"
37 #include "stringfilter_type.h"
38 #include "querystring_gui.h"
39 #include "fontcache.h"
40 #include "zoom_func.h"
41 #include "rev.h"
42 #include "video/video_driver.hpp"
43 #include "music/music_driver.hpp"
44 #include "gui.h"
45 #include "mixer.h"
46 #include "newgrf_config.h"
47 #include "network/core/config.h"
48 #include "network/network_gui.h"
49 #include "network/network_survey.h"
50 #include "video/video_driver.hpp"
51 #include "social_integration.h"
52 #include "sound_func.h"
53 
54 #include "safeguards.h"
55 
56 
57 #if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
58 # define HAS_TRUETYPE_FONT
59 #endif
60 
61 static const StringID _autosave_dropdown[] = {
62  STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF,
63  STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_10_MINUTES,
64  STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_30_MINUTES,
65  STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_60_MINUTES,
66  STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_120_MINUTES,
68 };
69 
71 static const uint32_t _autosave_dropdown_to_minutes[] = {
72  0,
73  10,
74  30,
75  60,
76  120,
77 };
78 
80 
81 static const void *ResolveObject(const GameSettings *settings_ptr, const IntSettingDesc *sd);
82 
88 {
89  auto it = std::find(_resolutions.begin(), _resolutions.end(), Dimension(_screen.width, _screen.height));
90  return std::distance(_resolutions.begin(), it);
91 }
92 
93 static void ShowCustCurrency();
94 
97  const std::string name;
99 
101  {
102  this->ConstructWindow();
103  this->LoadTextfile(textfile, BASESET_DIR);
104  }
105 
106  void SetStringParameters(WidgetID widget) const override
107  {
108  if (widget == WID_TF_CAPTION) {
110  SetDParamStr(1, this->name);
111  }
112  }
113 };
114 
121 template <class TBaseSet>
122 void ShowBaseSetTextfileWindow(TextfileType file_type, const TBaseSet *baseset, StringID content_type)
123 {
124  CloseWindowById(WC_TEXTFILE, file_type);
125  new BaseSetTextfileWindow(file_type, baseset->name, *baseset->GetTextfile(file_type), content_type);
126 }
127 
128 template <class T>
129 DropDownList BuildSetDropDownList(int *selected_index)
130 {
131  int n = T::GetNumSets();
132  *selected_index = T::GetIndexOfUsedSet();
133  DropDownList list;
134  for (int i = 0; i < n; i++) {
135  list.push_back(MakeDropDownListStringItem(T::GetSet(i)->GetListLabel(), i));
136  }
137  return list;
138 }
139 
140 std::set<int> _refresh_rates = { 30, 60, 75, 90, 100, 120, 144, 240 };
141 
147 {
148  /* Add the refresh rate as selected in the config. */
149  _refresh_rates.insert(_settings_client.gui.refresh_rate);
150 
151  /* Add all the refresh rates of all monitors connected to the machine. */
152  std::vector<int> monitorRates = VideoDriver::GetInstance()->GetListOfMonitorRefreshRates();
153  std::copy(monitorRates.begin(), monitorRates.end(), std::inserter(_refresh_rates, _refresh_rates.end()));
154 }
155 
156 static const int SCALE_NMARKS = (MAX_INTERFACE_SCALE - MIN_INTERFACE_SCALE) / 25 + 1; // Show marks at 25% increments
157 static const int VOLUME_NMARKS = 9; // Show 5 values and 4 empty marks.
158 
159 static StringID ScaleMarkFunc(int, int, int value)
160 {
161  /* Label only every 100% mark. */
162  if (value % 100 != 0) return STR_NULL;
163 
164  SetDParam(0, value / 100);
165  SetDParam(1, 0);
166  return STR_GAME_OPTIONS_GUI_SCALE_MARK;
167 }
168 
169 static StringID VolumeMarkFunc(int, int mark, int value)
170 {
171  /* Label only every other mark. */
172  if (mark % 2 != 0) return STR_NULL;
173 
174  SetDParam(0, value / 31 * 25); // 0-127 does not map nicely to 0-100. Dividing first gives us nice round numbers.
175  return STR_GAME_OPTIONS_VOLUME_MARK;
176 }
177 
178 static constexpr NWidgetPart _nested_social_plugins_widgets[] = {
180  NWidget(WWT_FRAME, COLOUR_GREY, WID_GO_SOCIAL_PLUGIN_TITLE), SetDataTip(STR_JUST_STRING2, STR_NULL),
182  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM, STR_NULL),
183  NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_SOCIAL_PLUGIN_PLATFORM), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_NULL), SetAlignment(SA_RIGHT),
184  EndContainer(),
186  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE, STR_NULL),
187  NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_SOCIAL_PLUGIN_STATE), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING1, STR_NULL), SetAlignment(SA_RIGHT),
188  EndContainer(),
189  EndContainer(),
190  EndContainer(),
191 };
192 
193 static constexpr NWidgetPart _nested_social_plugins_none_widgets[] = {
195  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE, STR_NULL),
196  EndContainer(),
197 };
198 
200 public:
202  {
203  this->plugins = SocialIntegration::GetPlugins();
204 
205  if (this->plugins.empty()) {
206  auto widget = MakeNWidgets(_nested_social_plugins_none_widgets, nullptr);
207  this->Add(std::move(widget));
208  } else {
209  for (size_t i = 0; i < this->plugins.size(); i++) {
210  auto widget = MakeNWidgets(_nested_social_plugins_widgets, nullptr);
211  this->Add(std::move(widget));
212  }
213  }
214 
215  this->SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0);
216  }
217 
218  void FillWidgetLookup(WidgetLookup &widget_lookup) override
219  {
220  widget_lookup[WID_GO_SOCIAL_PLUGINS] = this;
221  NWidgetVertical::FillWidgetLookup(widget_lookup);
222  }
223 
224  void SetupSmallestSize(Window *w) override
225  {
226  this->current_index = -1;
228  }
229 
236  template <typename T>
237  std::string &GetWidestPlugin(T SocialIntegrationPlugin::*member) const
238  {
239  std::string *longest = &(this->plugins[0]->*member);
240  int longest_length = 0;
241 
242  for (auto *plugin : this->plugins) {
243  int length = GetStringBoundingBox(plugin->*member).width;
244  if (length > longest_length) {
245  longest_length = length;
246  longest = &(plugin->*member);
247  }
248  }
249 
250  return *longest;
251  }
252 
253  void SetStringParameters(int widget) const
254  {
255  switch (widget) {
257  /* For SetupSmallestSize, use the longest string we have. */
258  if (this->current_index < 0) {
259  SetDParam(0, STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE);
262  break;
263  }
264 
265  if (this->plugins[this->current_index]->name.empty()) {
266  SetDParam(0, STR_JUST_RAW_STRING);
267  SetDParamStr(1, this->plugins[this->current_index]->basepath);
268  } else {
269  SetDParam(0, STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE);
270  SetDParamStr(1, this->plugins[this->current_index]->name);
271  SetDParamStr(2, this->plugins[this->current_index]->version);
272  }
273  break;
274 
276  /* For SetupSmallestSize, use the longest string we have. */
277  if (this->current_index < 0) {
279  break;
280  }
281 
282  SetDParamStr(0, this->plugins[this->current_index]->social_platform);
283  break;
284 
286  static const std::pair<SocialIntegrationPlugin::State, StringID> state_to_string[] = {
287  { SocialIntegrationPlugin::RUNNING, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_RUNNING },
288  { SocialIntegrationPlugin::FAILED, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_FAILED },
289  { SocialIntegrationPlugin::PLATFORM_NOT_RUNNING, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_PLATFORM_NOT_RUNNING },
290  { SocialIntegrationPlugin::UNLOADED, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_UNLOADED },
291  { SocialIntegrationPlugin::DUPLICATE, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_DUPLICATE },
292  { SocialIntegrationPlugin::UNSUPPORTED_API, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_UNSUPPORTED_API },
293  { SocialIntegrationPlugin::INVALID_SIGNATURE, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_INVALID_SIGNATURE },
294  };
295 
296  /* For SetupSmallestSize, use the longest string we have. */
297  if (this->current_index < 0) {
299 
300  /* Set the longest plugin when looking for the longest status. */
301  SetDParamStr(0, longest_plugin);
302 
303  StringID longest = STR_NULL;
304  int longest_length = 0;
305  for (auto state : state_to_string) {
306  int length = GetStringBoundingBox(state.second).width;
307  if (length > longest_length) {
308  longest_length = length;
309  longest = state.second;
310  }
311  }
312 
313  SetDParam(0, longest);
314  SetDParamStr(1, longest_plugin);
315  break;
316  }
317 
318  auto plugin = this->plugins[this->current_index];
319 
320  /* Default string, in case no state matches. */
321  SetDParam(0, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_FAILED);
322  SetDParamStr(1, plugin->social_platform);
323 
324  /* Find the string for the state. */
325  for (auto state : state_to_string) {
326  if (plugin->state == state.first) {
327  SetDParam(0, state.second);
328  break;
329  }
330  }
331  }
332  break;
333  }
334  }
335 
336  void Draw(const Window *w) override
337  {
338  this->current_index = 0;
339 
340  for (auto &wid : this->children) {
341  wid->Draw(w);
342  this->current_index++;
343  }
344  }
345 
346 private:
347  int current_index = -1;
348  std::vector<SocialIntegrationPlugin *> plugins;
349 };
350 
352 std::unique_ptr<NWidgetBase> MakeNWidgetSocialPlugins()
353 {
354  return std::make_unique<NWidgetSocialPlugins>();
355 }
356 
358  GameSettings *opt;
359  bool reload;
360  int gui_scale;
361  static inline WidgetID active_tab = WID_GO_TAB_GENERAL;
362 
363  GameOptionsWindow(WindowDesc &desc) : Window(desc)
364  {
365  this->opt = &GetGameSettings();
366  this->reload = false;
367  this->gui_scale = _gui_scale;
368 
370 
372  this->OnInvalidateData(0);
373 
374  this->SetTab(GameOptionsWindow::active_tab);
375 
376  if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) this->GetWidget<NWidgetStacked>(WID_GO_SURVEY_SEL)->SetDisplayedPlane(SZSP_NONE);
377  }
378 
379  void Close([[maybe_unused]] int data = 0) override
380  {
383  if (this->reload) _switch_mode = SM_MENU;
384  this->Window::Close();
385  }
386 
393  DropDownList BuildDropDownList(WidgetID widget, int *selected_index) const
394  {
395  DropDownList list;
396  switch (widget) {
397  case WID_GO_CURRENCY_DROPDOWN: { // Setup currencies dropdown
398  *selected_index = this->opt->locale.currency;
399  uint64_t disabled = _game_mode == GM_MENU ? 0LL : ~GetMaskOfAllowedCurrencies();
400 
401  /* Add non-custom currencies; sorted naturally */
402  for (const CurrencySpec &currency : _currency_specs) {
403  int i = &currency - _currency_specs.data();
404  if (i == CURRENCY_CUSTOM) continue;
405  if (currency.code.empty()) {
406  list.push_back(MakeDropDownListStringItem(currency.name, i, HasBit(disabled, i)));
407  } else {
408  SetDParam(0, currency.name);
409  SetDParamStr(1, currency.code);
410  list.push_back(MakeDropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CODE, i, HasBit(disabled, i)));
411  }
412  }
413  std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc);
414 
415  /* Append custom currency at the end */
416  list.push_back(MakeDropDownListDividerItem()); // separator line
417  list.push_back(MakeDropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, CURRENCY_CUSTOM, HasBit(disabled, CURRENCY_CUSTOM)));
418  break;
419  }
420 
421  case WID_GO_AUTOSAVE_DROPDOWN: { // Setup autosave dropdown
422  int index = 0;
423  for (auto &minutes : _autosave_dropdown_to_minutes) {
424  index++;
425  if (_settings_client.gui.autosave_interval <= minutes) break;
426  }
427  *selected_index = index - 1;
428 
429  const StringID *items = _autosave_dropdown;
430  for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) {
431  list.push_back(MakeDropDownListStringItem(*items, i));
432  }
433  break;
434  }
435 
436  case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown
437  for (uint i = 0; i < _languages.size(); i++) {
438  bool hide_language = IsReleasedVersion() && !_languages[i].IsReasonablyFinished();
439  if (hide_language) continue;
440  bool hide_percentage = IsReleasedVersion() || _languages[i].missing < _settings_client.gui.missing_strings_threshold;
441  if (&_languages[i] == _current_language) {
442  *selected_index = i;
443  SetDParamStr(0, _languages[i].own_name);
444  } else {
445  /* Especially with sprite-fonts, not all localized
446  * names can be rendered. So instead, we use the
447  * international names for anything but the current
448  * selected language. This avoids showing a few ????
449  * entries in the dropdown list. */
450  SetDParamStr(0, _languages[i].name);
451  }
452  SetDParam(1, (LANGUAGE_TOTAL_STRINGS - _languages[i].missing) * 100 / LANGUAGE_TOTAL_STRINGS);
453  list.push_back(MakeDropDownListStringItem(hide_percentage ? STR_JUST_RAW_STRING : STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE, i));
454  }
455  std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc);
456  break;
457  }
458 
459  case WID_GO_RESOLUTION_DROPDOWN: // Setup resolution dropdown
460  if (_resolutions.empty()) break;
461 
462  *selected_index = GetCurrentResolutionIndex();
463  for (uint i = 0; i < _resolutions.size(); i++) {
466  list.push_back(MakeDropDownListStringItem(STR_GAME_OPTIONS_RESOLUTION_ITEM, i));
467  }
468  break;
469 
470  case WID_GO_REFRESH_RATE_DROPDOWN: // Setup refresh rate dropdown
471  for (auto it = _refresh_rates.begin(); it != _refresh_rates.end(); it++) {
472  auto i = std::distance(_refresh_rates.begin(), it);
473  if (*it == _settings_client.gui.refresh_rate) *selected_index = i;
474  SetDParam(0, *it);
475  list.push_back(MakeDropDownListStringItem(STR_GAME_OPTIONS_REFRESH_RATE_ITEM, i));
476  }
477  break;
478 
480  list = BuildSetDropDownList<BaseGraphics>(selected_index);
481  break;
482 
484  list = BuildSetDropDownList<BaseSounds>(selected_index);
485  break;
486 
488  list = BuildSetDropDownList<BaseMusic>(selected_index);
489  break;
490  }
491 
492  return list;
493  }
494 
495  void SetStringParameters(WidgetID widget) const override
496  {
497  switch (widget) {
499  const CurrencySpec &currency = _currency_specs[this->opt->locale.currency];
500  if (currency.code.empty()) {
501  SetDParam(0, currency.name);
502  } else {
503  SetDParam(0, STR_GAME_OPTIONS_CURRENCY_CODE);
504  SetDParam(1, currency.name);
505  SetDParamStr(2, currency.code);
506  }
507  break;
508  }
510  int index = 0;
511  for (auto &minutes : _autosave_dropdown_to_minutes) {
512  index++;
513  if (_settings_client.gui.autosave_interval <= minutes) break;
514  }
515  SetDParam(0, _autosave_dropdown[index - 1]);
516  break;
517  }
519  case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->GetListLabel()); break;
520  case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->GetListLabel()); break;
521  case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->GetListLabel()); break;
524  auto current_resolution = GetCurrentResolutionIndex();
525 
526  if (current_resolution == _resolutions.size()) {
527  SetDParam(0, STR_GAME_OPTIONS_RESOLUTION_OTHER);
528  } else {
529  SetDParam(0, STR_GAME_OPTIONS_RESOLUTION_ITEM);
530  SetDParam(1, _resolutions[current_resolution].width);
531  SetDParam(2, _resolutions[current_resolution].height);
532  }
533  break;
534  }
535 
539  const NWidgetSocialPlugins *plugin = this->GetWidget<NWidgetSocialPlugins>(WID_GO_SOCIAL_PLUGINS);
540  assert(plugin != nullptr);
541 
542  plugin->SetStringParameters(widget);
543  break;
544  }
545  }
546  }
547 
548  void DrawWidget(const Rect &r, WidgetID widget) const override
549  {
550  switch (widget) {
553  DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK);
554  break;
555 
558  DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK);
559  break;
560 
563  DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK);
564  break;
565 
566  case WID_GO_GUI_SCALE:
567  DrawSliderWidget(r, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, SCALE_NMARKS, this->gui_scale, ScaleMarkFunc);
568  break;
569 
571  SetDParamStr(0, std::string{VideoDriver::GetInstance()->GetInfoString()});
572  DrawStringMultiLine(r, STR_GAME_OPTIONS_VIDEO_DRIVER_INFO);
573  break;
574 
576  DrawSliderWidget(r, 0, INT8_MAX, VOLUME_NMARKS, _settings_client.music.effect_vol, VolumeMarkFunc);
577  break;
578 
580  DrawSliderWidget(r, 0, INT8_MAX, VOLUME_NMARKS, _settings_client.music.music_vol, VolumeMarkFunc);
581  break;
582  }
583  }
584 
585  void SetTab(WidgetID widget)
586  {
588  this->LowerWidget(widget);
589  GameOptionsWindow::active_tab = widget;
590 
591  int pane;
592  switch (widget) {
593  case WID_GO_TAB_GENERAL: pane = 0; break;
594  case WID_GO_TAB_GRAPHICS: pane = 1; break;
595  case WID_GO_TAB_SOUND: pane = 2; break;
596  case WID_GO_TAB_SOCIAL: pane = 3; break;
597  default: NOT_REACHED();
598  }
599 
600  this->GetWidget<NWidgetStacked>(WID_GO_TAB_SELECTION)->SetDisplayedPlane(pane);
601  this->SetDirty();
602  }
603 
604  void OnResize() override
605  {
606  bool changed = false;
607 
608  NWidgetResizeBase *wid = this->GetWidget<NWidgetResizeBase>(WID_GO_BASE_GRF_DESCRIPTION);
609  int y = 0;
610  for (int i = 0; i < BaseGraphics::GetNumSets(); i++) {
612  y = std::max(y, GetStringHeight(STR_JUST_RAW_STRING, wid->current_x));
613  }
614  changed |= wid->UpdateVerticalSize(y);
615 
616  wid = this->GetWidget<NWidgetResizeBase>(WID_GO_BASE_SFX_DESCRIPTION);
617  y = 0;
618  for (int i = 0; i < BaseSounds::GetNumSets(); i++) {
620  y = std::max(y, GetStringHeight(STR_JUST_RAW_STRING, wid->current_x));
621  }
622  changed |= wid->UpdateVerticalSize(y);
623 
624  wid = this->GetWidget<NWidgetResizeBase>(WID_GO_BASE_MUSIC_DESCRIPTION);
625  y = 0;
626  for (int i = 0; i < BaseMusic::GetNumSets(); i++) {
627  SetDParamStr(0, BaseMusic::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode()));
628  y = std::max(y, GetStringHeight(STR_JUST_RAW_STRING, wid->current_x));
629  }
630  changed |= wid->UpdateVerticalSize(y);
631 
632  wid = this->GetWidget<NWidgetResizeBase>(WID_GO_VIDEO_DRIVER_INFO);
633  SetDParamStr(0, std::string{VideoDriver::GetInstance()->GetInfoString()});
634  y = GetStringHeight(STR_GAME_OPTIONS_VIDEO_DRIVER_INFO, wid->current_x);
635  changed |= wid->UpdateVerticalSize(y);
636 
637  if (changed) this->ReInit(0, 0, this->flags & WF_CENTERED);
638  }
639 
640  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
641  {
642  switch (widget) {
645  Dimension d = maxdim(GetStringBoundingBox(STR_GAME_OPTIONS_SFX_VOLUME), GetStringBoundingBox(STR_GAME_OPTIONS_MUSIC_VOLUME));
646  d.width += padding.width;
647  d.height += padding.height;
648  size = maxdim(size, d);
649  break;
650  }
651 
660  int selected;
661  size.width = std::max(size.width, GetDropDownListDimension(this->BuildDropDownList(widget, &selected)).width + padding.width);
662  break;
663  }
664  }
665  }
666 
667  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
668  {
669  if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_CONTENT_END) {
670  if (BaseGraphics::GetUsedSet() == nullptr) return;
671 
672  ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_GRF_TEXTFILE), BaseGraphics::GetUsedSet(), STR_CONTENT_TYPE_BASE_GRAPHICS);
673  return;
674  }
675  if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_CONTENT_END) {
676  if (BaseSounds::GetUsedSet() == nullptr) return;
677 
678  ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_SFX_TEXTFILE), BaseSounds::GetUsedSet(), STR_CONTENT_TYPE_BASE_SOUNDS);
679  return;
680  }
681  if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_CONTENT_END) {
682  if (BaseMusic::GetUsedSet() == nullptr) return;
683 
684  ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_MUSIC_TEXTFILE), BaseMusic::GetUsedSet(), STR_CONTENT_TYPE_BASE_MUSIC);
685  return;
686  }
687  switch (widget) {
688  case WID_GO_TAB_GENERAL:
689  case WID_GO_TAB_GRAPHICS:
690  case WID_GO_TAB_SOUND:
691  case WID_GO_TAB_SOCIAL:
692  this->SetTab(widget);
693  break;
694 
697  case PS_ASK:
698  case PS_NO:
700  break;
701 
702  case PS_YES:
704  break;
705  }
706 
709  break;
710 
712  OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
713  break;
714 
716  ShowSurveyResultTextfileWindow();
717  break;
718 
719  case WID_GO_FULLSCREEN_BUTTON: // Click fullscreen on/off
720  /* try to toggle full-screen on/off */
721  if (!ToggleFullScreen(!_fullscreen)) {
722  ShowErrorMessage(STR_ERROR_FULLSCREEN_FAILED, INVALID_STRING_ID, WL_ERROR);
723  }
726  break;
727 
730  ShowErrorMessage(STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART, INVALID_STRING_ID, WL_INFO);
733 #ifndef __APPLE__
737 #endif
738  break;
739 
741  if (!_video_hw_accel) break;
742 
745 
750  break;
751 
754 
756  this->SetDirty();
757 
759  ReInitAllWindows(true);
760  break;
761  }
762 
763 #ifdef HAS_TRUETYPE_FONT
765  _fcsettings.prefer_sprite = !_fcsettings.prefer_sprite;
766 
769  this->SetDirty();
770 
771  InitFontCache(false);
772  InitFontCache(true);
773  ClearFontCache();
777  ReInitAllWindows(true);
778  break;
779 
780  case WID_GO_GUI_FONT_AA:
781  _fcsettings.global_aa = !_fcsettings.global_aa;
782 
785 
786  ClearFontCache();
787  break;
788 #endif /* HAS_TRUETYPE_FONT */
789 
790  case WID_GO_GUI_SCALE:
791  if (ClickSliderWidget(this->GetWidget<NWidgetBase>(widget)->GetCurrentRect(), pt, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, _ctrl_pressed ? 0 : SCALE_NMARKS, this->gui_scale)) {
792  this->SetWidgetDirty(widget);
793  }
794 
795  if (click_count > 0) this->mouse_capture_widget = widget;
796  break;
797 
799  {
800  if (_gui_scale_cfg == -1) {
803  } else {
804  _gui_scale_cfg = -1;
806  if (AdjustGUIZoom(false)) ReInitAllWindows(true);
807  this->gui_scale = _gui_scale;
808  }
809  this->SetWidgetDirty(widget);
810  break;
811  }
812 
814  auto *used_set = BaseGraphics::GetUsedSet();
815  if (used_set == nullptr || !used_set->IsConfigurable()) break;
816  GRFConfig &extra_cfg = used_set->GetOrCreateExtraConfig();
817  if (extra_cfg.num_params == 0) extra_cfg.SetParameterDefaults();
818  OpenGRFParameterWindow(true, &extra_cfg, _game_mode == GM_MENU);
819  if (_game_mode == GM_MENU) this->reload = true;
820  break;
821  }
822 
826  if (ClickSliderWidget(this->GetWidget<NWidgetBase>(widget)->GetCurrentRect(), pt, 0, INT8_MAX, 0, vol)) {
827  if (widget == WID_GO_BASE_MUSIC_VOLUME) {
829  } else {
830  SetEffectVolume(vol);
831  }
832  this->SetWidgetDirty(widget);
834  }
835 
836  if (click_count > 0) this->mouse_capture_widget = widget;
837  break;
838  }
839 
841  ShowMusicWindow();
842  break;
843  }
844 
846  if (BaseGraphics::GetUsedSet() == nullptr || BaseGraphics::GetUsedSet()->url.empty()) return;
847  OpenBrowser(BaseGraphics::GetUsedSet()->url);
848  break;
849 
851  if (BaseSounds::GetUsedSet() == nullptr || BaseSounds::GetUsedSet()->url.empty()) return;
852  OpenBrowser(BaseSounds::GetUsedSet()->url);
853  break;
854 
856  if (BaseMusic::GetUsedSet() == nullptr || BaseMusic::GetUsedSet()->url.empty()) return;
857  OpenBrowser(BaseMusic::GetUsedSet()->url);
858  break;
859 
862  break;
863 
866  break;
867 
870  break;
871 
880  int selected;
881  DropDownList list = this->BuildDropDownList(widget, &selected);
882  if (!list.empty()) {
883  ShowDropDownList(this, std::move(list), selected, widget);
884  } else {
885  if (widget == WID_GO_RESOLUTION_DROPDOWN) ShowErrorMessage(STR_ERROR_RESOLUTION_LIST_FAILED, INVALID_STRING_ID, WL_ERROR);
886  }
887  break;
888  }
889  }
890  }
891 
892  void OnMouseLoop() override
893  {
894  if (_left_button_down || this->gui_scale == _gui_scale) return;
895 
896  _gui_scale_cfg = this->gui_scale;
897 
898  if (AdjustGUIZoom(false)) {
899  ReInitAllWindows(true);
901  this->SetDirty();
902  }
903  }
904 
905  void OnDropdownSelect(WidgetID widget, int index) override
906  {
907  switch (widget) {
908  case WID_GO_CURRENCY_DROPDOWN: // Currency
909  if (index == CURRENCY_CUSTOM) ShowCustCurrency();
910  this->opt->locale.currency = index;
911  ReInitAllWindows(false);
912  break;
913 
914  case WID_GO_AUTOSAVE_DROPDOWN: // Autosave options
917  this->SetDirty();
918  break;
919 
920  case WID_GO_LANG_DROPDOWN: // Change interface language
921  ReadLanguagePack(&_languages[index]);
924  ClearAllCachedNames();
926  CheckBlitter();
927  ReInitAllWindows(false);
928  break;
929 
930  case WID_GO_RESOLUTION_DROPDOWN: // Change resolution
931  if ((uint)index < _resolutions.size() && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) {
932  this->SetDirty();
933  }
934  break;
935 
937  _settings_client.gui.refresh_rate = *std::next(_refresh_rates.begin(), index);
938  if (_settings_client.gui.refresh_rate > 60) {
939  /* Show warning to the user that this refresh rate might not be suitable on
940  * larger maps with many NewGRFs and vehicles. */
941  ShowErrorMessage(STR_GAME_OPTIONS_REFRESH_RATE_WARNING, INVALID_STRING_ID, WL_INFO);
942  }
943  break;
944  }
945 
947  if (_game_mode == GM_MENU) {
949  auto set = BaseGraphics::GetSet(index);
951  this->reload = true;
952  this->InvalidateData();
953  }
954  break;
955 
957  ChangeSoundSet(index);
958  break;
959 
961  ChangeMusicSet(index);
962  break;
963  }
964  }
965 
971  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
972  {
973  if (!gui_scope) return;
978 
979 #ifndef __APPLE__
982 #endif
983 
986 #ifdef HAS_TRUETYPE_FONT
990 #endif /* HAS_TRUETYPE_FONT */
991 
992  this->SetWidgetDisabledState(WID_GO_BASE_GRF_DROPDOWN, _game_mode != GM_MENU);
993 
995 
999 
1000  for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
1004  }
1005 
1007  }
1008 };
1009 
1010 static constexpr NWidgetPart _nested_game_options_widgets[] = {
1012  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1013  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1014  EndContainer(),
1015  NWidget(WWT_PANEL, COLOUR_GREY),
1017  NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_GENERAL), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_GENERAL, STR_GAME_OPTIONS_TAB_GENERAL_TT), SetFill(1, 0),
1018  NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_GRAPHICS), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_GRAPHICS, STR_GAME_OPTIONS_TAB_GRAPHICS_TT), SetFill(1, 0),
1019  NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_SOUND), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_SOUND, STR_GAME_OPTIONS_TAB_SOUND_TT), SetFill(1, 0),
1020  NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_SOCIAL), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_SOCIAL, STR_GAME_OPTIONS_TAB_SOCIAL_TT), SetFill(1, 0),
1021  EndContainer(),
1022  EndContainer(),
1023  NWidget(WWT_PANEL, COLOUR_GREY),
1024  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GO_TAB_SELECTION),
1025  /* General tab */
1027  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_LANGUAGE, STR_NULL),
1028  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_LANG_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_GAME_OPTIONS_LANGUAGE_TOOLTIP), SetFill(1, 0),
1029  EndContainer(),
1030 
1031  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL),
1032  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0),
1033  EndContainer(),
1034 
1035  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME, STR_NULL),
1036  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_CURRENCY_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING2, STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP), SetFill(1, 0),
1037  EndContainer(),
1038 
1039  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GO_SURVEY_SEL),
1040  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
1042  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY, STR_NULL),
1043  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_SURVEY_PARTICIPATE_BUTTON), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP),
1044  EndContainer(),
1046  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_SURVEY_PREVIEW_BUTTON), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW, STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP),
1047  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_SURVEY_LINK_BUTTON), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK, STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP),
1048  EndContainer(),
1049  EndContainer(),
1050  EndContainer(),
1051  EndContainer(),
1052 
1053  /* Graphics tab */
1055  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_FRAME, STR_NULL),
1057  NWidget(WWT_EMPTY, COLOUR_GREY, WID_GO_GUI_SCALE), SetMinimalSize(67, 0), SetMinimalTextLines(1, 12 + WidgetDimensions::unscaled.vsep_normal, FS_SMALL), SetFill(0, 0), SetDataTip(0x0, STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP),
1059  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_AUTO, STR_NULL),
1060  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_AUTO), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP),
1061  EndContainer(),
1063  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_BEVELS, STR_NULL),
1064  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_BEVEL_BUTTON), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP),
1065  EndContainer(),
1066 #ifdef HAS_TRUETYPE_FONT
1068  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_FONT_SPRITE, STR_NULL),
1069  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_FONT_SPRITE), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP),
1070  EndContainer(),
1072  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_FONT_AA, STR_NULL),
1073  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_FONT_AA), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP),
1074  EndContainer(),
1075 #endif /* HAS_TRUETYPE_FONT */
1076  EndContainer(),
1077  EndContainer(),
1078 
1079  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_GRAPHICS, STR_NULL),
1082  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL),
1083  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING2, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP),
1084  EndContainer(),
1086  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_REFRESH_RATE, STR_NULL),
1087  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_REFRESH_RATE_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_GAME_OPTIONS_REFRESH_RATE_ITEM, STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP),
1088  EndContainer(),
1090  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL),
1091  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP),
1092  EndContainer(),
1094  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_VIDEO_ACCELERATION, STR_NULL),
1095  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_VIDEO_ACCEL_BUTTON), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP),
1096  EndContainer(),
1097 #ifndef __APPLE__
1099  NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_VIDEO_VSYNC, STR_NULL),
1100  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_VIDEO_VSYNC_BUTTON), SetAspect(WidgetDimensions::ASPECT_SETTINGS_BUTTON), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP),
1101  EndContainer(),
1102 #endif
1104  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GO_VIDEO_DRIVER_INFO), SetMinimalTextLines(1, 0), SetFill(1, 0),
1105  EndContainer(),
1106  EndContainer(),
1107  EndContainer(),
1108 
1109  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0), SetFill(1, 0),
1111  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), SetFill(1, 0),
1112  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_PARAMETERS), SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL),
1113  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_CONTENT_DOWNLOAD), SetDataTip(STR_GAME_OPTIONS_ONLINE_CONTENT, STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP),
1114  EndContainer(),
1115  NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(200, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0),
1118  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1119  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1120  EndContainer(),
1122  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1123  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1124  EndContainer(),
1125  EndContainer(),
1126  EndContainer(),
1127  EndContainer(),
1128 
1129  /* Sound/Music tab */
1131  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_VOLUME, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1133  NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_TEXT_SFX_VOLUME), SetMinimalSize(0, 12), SetDataTip(STR_GAME_OPTIONS_SFX_VOLUME, STR_NULL),
1134  NWidget(WWT_EMPTY, COLOUR_GREY, WID_GO_BASE_SFX_VOLUME), SetMinimalSize(67, 0), SetMinimalTextLines(1, 12 + WidgetDimensions::unscaled.vsep_normal, FS_SMALL), SetFill(1, 0), SetDataTip(0x0, STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
1135  EndContainer(),
1137  NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_TEXT_MUSIC_VOLUME), SetMinimalSize(0, 12), SetDataTip(STR_GAME_OPTIONS_MUSIC_VOLUME, STR_NULL),
1138  NWidget(WWT_EMPTY, COLOUR_GREY, WID_GO_BASE_MUSIC_VOLUME), SetMinimalSize(67, 0), SetMinimalTextLines(1, 12 + WidgetDimensions::unscaled.vsep_normal, FS_SMALL), SetFill(1, 0), SetDataTip(0x0, STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
1139  EndContainer(),
1140  EndContainer(),
1141 
1142  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
1144  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), SetFill(1, 0),
1145  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_CONTENT_DOWNLOAD), SetDataTip(STR_GAME_OPTIONS_ONLINE_CONTENT, STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP),
1146  EndContainer(),
1147  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(200, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_NULL, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0),
1150  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1151  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1152  EndContainer(),
1154  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1155  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1156  EndContainer(),
1157  EndContainer(),
1158  EndContainer(),
1159 
1160  NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
1162  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), SetFill(1, 0),
1163  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_CONTENT_DOWNLOAD), SetDataTip(STR_GAME_OPTIONS_ONLINE_CONTENT, STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP),
1164  EndContainer(),
1166  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(200, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_NULL, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0),
1167  NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1),
1168  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_JUKEBOX), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
1169  EndContainer(),
1170  EndContainer(),
1173  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1174  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1175  EndContainer(),
1177  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1178  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1179  EndContainer(),
1180  EndContainer(),
1181  EndContainer(),
1182  EndContainer(),
1183 
1184  /* Social tab */
1187  EndContainer(),
1188  EndContainer(),
1189  EndContainer(),
1190 };
1191 
1192 static WindowDesc _game_options_desc(
1193  WDP_CENTER, nullptr, 0, 0,
1195  0,
1196  _nested_game_options_widgets
1197 );
1198 
1201 {
1203  new GameOptionsWindow(_game_options_desc);
1204 }
1205 
1206 static int SETTING_HEIGHT = 11;
1207 
1216 
1218  SEF_FILTERED = 0x08,
1219 };
1220 
1229 };
1231 
1232 
1236  bool type_hides;
1239 };
1240 
1243  uint8_t flags;
1244  uint8_t level;
1245 
1246  BaseSettingEntry() : flags(0), level(0) {}
1247  virtual ~BaseSettingEntry() = default;
1248 
1249  virtual void Init(uint8_t level = 0);
1250  virtual void FoldAll() {}
1251  virtual void UnFoldAll() {}
1252  virtual void ResetAll() = 0;
1253 
1258  void SetLastField(bool last_field) { if (last_field) SETBITS(this->flags, SEF_LAST_FIELD); else CLRBITS(this->flags, SEF_LAST_FIELD); }
1259 
1260  virtual uint Length() const = 0;
1261  virtual void GetFoldingState([[maybe_unused]] bool &all_folded, [[maybe_unused]] bool &all_unfolded) const {}
1262  virtual bool IsVisible(const BaseSettingEntry *item) const;
1263  virtual BaseSettingEntry *FindEntry(uint row, uint *cur_row);
1264  virtual uint GetMaxHelpHeight([[maybe_unused]] int maxw) { return 0; }
1265 
1270  bool IsFiltered() const { return (this->flags & SEF_FILTERED) != 0; }
1271 
1272  virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible) = 0;
1273 
1274  virtual uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const;
1275 
1276 protected:
1277  virtual void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const = 0;
1278 };
1279 
1282  const char *name;
1284 
1285  SettingEntry(const char *name);
1286 
1287  void Init(uint8_t level = 0) override;
1288  void ResetAll() override;
1289  uint Length() const override;
1290  uint GetMaxHelpHeight(int maxw) override;
1291  bool UpdateFilterState(SettingFilter &filter, bool force_visible) override;
1292 
1293  void SetButtons(uint8_t new_val);
1294 
1295 protected:
1296  void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const override;
1297 
1298 private:
1300 };
1301 
1304  typedef std::vector<BaseSettingEntry*> EntryVector;
1305  EntryVector entries;
1306 
1307  template<typename T>
1308  T *Add(T *item)
1309  {
1310  this->entries.push_back(item);
1311  return item;
1312  }
1313 
1314  void Init(uint8_t level = 0);
1315  void ResetAll();
1316  void FoldAll();
1317  void UnFoldAll();
1318 
1319  uint Length() const;
1320  void GetFoldingState(bool &all_folded, bool &all_unfolded) const;
1321  bool IsVisible(const BaseSettingEntry *item) const;
1322  BaseSettingEntry *FindEntry(uint row, uint *cur_row);
1323  uint GetMaxHelpHeight(int maxw);
1324 
1325  bool UpdateFilterState(SettingFilter &filter, bool force_visible);
1326 
1327  uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const;
1328 };
1329 
1333  bool folded;
1334 
1336 
1337  void Init(uint8_t level = 0) override;
1338  void ResetAll() override;
1339  void FoldAll() override;
1340  void UnFoldAll() override;
1341 
1342  uint Length() const override;
1343  void GetFoldingState(bool &all_folded, bool &all_unfolded) const override;
1344  bool IsVisible(const BaseSettingEntry *item) const override;
1345  BaseSettingEntry *FindEntry(uint row, uint *cur_row) override;
1346  uint GetMaxHelpHeight(int maxw) override { return SettingsContainer::GetMaxHelpHeight(maxw); }
1347 
1348  bool UpdateFilterState(SettingFilter &filter, bool force_visible) override;
1349 
1350  uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const override;
1351 
1352 protected:
1353  void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const override;
1354 };
1355 
1356 /* == BaseSettingEntry methods == */
1357 
1362 void BaseSettingEntry::Init(uint8_t level)
1363 {
1364  this->level = level;
1365 }
1366 
1374 {
1375  if (this->IsFiltered()) return false;
1376  return this == item;
1377 }
1378 
1385 BaseSettingEntry *BaseSettingEntry::FindEntry(uint row_num, uint *cur_row)
1386 {
1387  if (this->IsFiltered()) return nullptr;
1388  if (row_num == *cur_row) return this;
1389  (*cur_row)++;
1390  return nullptr;
1391 }
1392 
1422 uint BaseSettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row, uint parent_last) const
1423 {
1424  if (this->IsFiltered()) return cur_row;
1425  if (cur_row >= max_row) return cur_row;
1426 
1427  bool rtl = _current_text_dir == TD_RTL;
1428  int offset = (rtl ? -(int)_circle_size.width : (int)_circle_size.width) / 2;
1430 
1431  int x = rtl ? right : left;
1432  if (cur_row >= first_row) {
1433  int colour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
1434  y += (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position
1435 
1436  /* Draw vertical for parent nesting levels */
1437  for (uint lvl = 0; lvl < this->level; lvl++) {
1438  if (!HasBit(parent_last, lvl)) GfxDrawLine(x + offset, y, x + offset, y + SETTING_HEIGHT - 1, colour);
1439  x += level_width;
1440  }
1441  /* draw own |- prefix */
1442  int halfway_y = y + SETTING_HEIGHT / 2;
1443  int bottom_y = (flags & SEF_LAST_FIELD) ? halfway_y : y + SETTING_HEIGHT - 1;
1444  GfxDrawLine(x + offset, y, x + offset, bottom_y, colour);
1445  /* Small horizontal line from the last vertical line */
1446  GfxDrawLine(x + offset, halfway_y, x + level_width - (rtl ? -WidgetDimensions::scaled.hsep_normal : WidgetDimensions::scaled.hsep_normal), halfway_y, colour);
1447  x += level_width;
1448 
1449  this->DrawSetting(settings_ptr, rtl ? left : x, rtl ? x : right, y, this == selected);
1450  }
1451  cur_row++;
1452 
1453  return cur_row;
1454 }
1455 
1456 /* == SettingEntry methods == */
1457 
1463 {
1464  this->name = name;
1465  this->setting = nullptr;
1466 }
1467 
1472 void SettingEntry::Init(uint8_t level)
1473 {
1475  this->setting = GetSettingFromName(this->name)->AsIntSetting();
1476 }
1477 
1478 /* Sets the given setting entry to its default value */
1479 void SettingEntry::ResetAll()
1480 {
1481  SetSettingValue(this->setting, this->setting->def);
1482 }
1483 
1489 void SettingEntry::SetButtons(uint8_t new_val)
1490 {
1491  assert((new_val & ~SEF_BUTTONS_MASK) == 0); // Should not touch any flags outside the buttons
1492  this->flags = (this->flags & ~SEF_BUTTONS_MASK) | new_val;
1493 }
1494 
1497 {
1498  return this->IsFiltered() ? 0 : 1;
1499 }
1500 
1507 {
1508  return GetStringHeight(this->setting->GetHelp(), maxw);
1509 }
1510 
1517 {
1518  /* There shall not be any restriction, i.e. all settings shall be visible. */
1519  if (mode == RM_ALL) return true;
1520 
1521  const IntSettingDesc *sd = this->setting;
1522 
1523  if (mode == RM_BASIC) return (this->setting->cat & SC_BASIC_LIST) != 0;
1524  if (mode == RM_ADVANCED) return (this->setting->cat & SC_ADVANCED_LIST) != 0;
1525 
1526  /* Read the current value. */
1527  const void *object = ResolveObject(&GetGameSettings(), sd);
1528  int64_t current_value = sd->Read(object);
1529  int64_t filter_value;
1530 
1531  if (mode == RM_CHANGED_AGAINST_DEFAULT) {
1532  /* This entry shall only be visible, if the value deviates from its default value. */
1533 
1534  /* Read the default value. */
1535  filter_value = sd->def;
1536  } else {
1537  assert(mode == RM_CHANGED_AGAINST_NEW);
1538  /* This entry shall only be visible, if the value deviates from
1539  * its value is used when starting a new game. */
1540 
1541  /* Make sure we're not comparing the new game settings against itself. */
1542  assert(&GetGameSettings() != &_settings_newgame);
1543 
1544  /* Read the new game's value. */
1545  filter_value = sd->Read(ResolveObject(&_settings_newgame, sd));
1546  }
1547 
1548  return current_value != filter_value;
1549 }
1550 
1557 bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible)
1558 {
1559  CLRBITS(this->flags, SEF_FILTERED);
1560 
1561  bool visible = true;
1562 
1563  const IntSettingDesc *sd = this->setting;
1564  if (!force_visible && !filter.string.IsEmpty()) {
1565  /* Process the search text filter for this item. */
1566  filter.string.ResetState();
1567 
1568  SetDParam(0, STR_EMPTY);
1569  filter.string.AddLine(sd->GetTitle());
1570  filter.string.AddLine(sd->GetHelp());
1571 
1572  visible = filter.string.GetState();
1573  }
1574 
1575  if (visible) {
1576  if (filter.type != ST_ALL && sd->GetType() != filter.type) {
1577  filter.type_hides = true;
1578  visible = false;
1579  }
1580  if (!this->IsVisibleByRestrictionMode(filter.mode)) {
1581  while (filter.min_cat < RM_ALL && (filter.min_cat == filter.mode || !this->IsVisibleByRestrictionMode(filter.min_cat))) filter.min_cat++;
1582  visible = false;
1583  }
1584  }
1585 
1586  if (!visible) SETBITS(this->flags, SEF_FILTERED);
1587  return visible;
1588 }
1589 
1590 static const void *ResolveObject(const GameSettings *settings_ptr, const IntSettingDesc *sd)
1591 {
1592  if ((sd->flags & SF_PER_COMPANY) != 0) {
1593  if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1594  return &Company::Get(_local_company)->settings;
1595  }
1596  return &_settings_client.company;
1597  }
1598  return settings_ptr;
1599 }
1600 
1609 void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const
1610 {
1611  const IntSettingDesc *sd = this->setting;
1612  int state = this->flags & SEF_BUTTONS_MASK;
1613 
1614  bool rtl = _current_text_dir == TD_RTL;
1615  uint buttons_left = rtl ? right + 1 - SETTING_BUTTON_WIDTH : left;
1616  uint text_left = left + (rtl ? 0 : SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide);
1617  uint text_right = right - (rtl ? SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide : 0);
1618  uint button_y = y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2;
1619 
1620  /* We do not allow changes of some items when we are a client in a networkgame */
1621  bool editable = sd->IsEditable();
1622 
1623  SetDParam(0, STR_CONFIG_SETTING_VALUE);
1624  int32_t value = sd->Read(ResolveObject(settings_ptr, sd));
1625  if (sd->IsBoolSetting()) {
1626  /* Draw checkbox for boolean-value either on/off */
1627  DrawBoolButton(buttons_left, button_y, value != 0, editable);
1628  } else if ((sd->flags & SF_GUI_DROPDOWN) != 0) {
1629  /* Draw [v] button for settings of an enum-type */
1630  DrawDropDownButton(buttons_left, button_y, COLOUR_YELLOW, state != 0, editable);
1631  } else {
1632  /* Draw [<][>] boxes for settings of an integer-type */
1633  DrawArrowButtons(buttons_left, button_y, COLOUR_YELLOW, state,
1634  editable && value != (sd->flags & SF_GUI_0_IS_SPECIAL ? 0 : sd->min), editable && (uint32_t)value != sd->max);
1635  }
1636  sd->SetValueDParams(1, value);
1637  DrawString(text_left, text_right, y + (SETTING_HEIGHT - GetCharacterHeight(FS_NORMAL)) / 2, sd->GetTitle(), highlight ? TC_WHITE : TC_LIGHT_BLUE);
1638 }
1639 
1640 /* == SettingsContainer methods == */
1641 
1646 void SettingsContainer::Init(uint8_t level)
1647 {
1648  for (auto &it : this->entries) {
1649  it->Init(level);
1650  }
1651 }
1652 
1655 {
1656  for (auto settings_entry : this->entries) {
1657  settings_entry->ResetAll();
1658  }
1659 }
1660 
1663 {
1664  for (auto &it : this->entries) {
1665  it->FoldAll();
1666  }
1667 }
1668 
1671 {
1672  for (auto &it : this->entries) {
1673  it->UnFoldAll();
1674  }
1675 }
1676 
1682 void SettingsContainer::GetFoldingState(bool &all_folded, bool &all_unfolded) const
1683 {
1684  for (auto &it : this->entries) {
1685  it->GetFoldingState(all_folded, all_unfolded);
1686  }
1687 }
1688 
1695 bool SettingsContainer::UpdateFilterState(SettingFilter &filter, bool force_visible)
1696 {
1697  bool visible = false;
1698  bool first_visible = true;
1699  for (EntryVector::reverse_iterator it = this->entries.rbegin(); it != this->entries.rend(); ++it) {
1700  visible |= (*it)->UpdateFilterState(filter, force_visible);
1701  (*it)->SetLastField(first_visible);
1702  if (visible && first_visible) first_visible = false;
1703  }
1704  return visible;
1705 }
1706 
1707 
1715 {
1716  for (const auto &it : this->entries) {
1717  if (it->IsVisible(item)) return true;
1718  }
1719  return false;
1720 }
1721 
1724 {
1725  uint length = 0;
1726  for (const auto &it : this->entries) {
1727  length += it->Length();
1728  }
1729  return length;
1730 }
1731 
1738 BaseSettingEntry *SettingsContainer::FindEntry(uint row_num, uint *cur_row)
1739 {
1740  BaseSettingEntry *pe = nullptr;
1741  for (const auto &it : this->entries) {
1742  pe = it->FindEntry(row_num, cur_row);
1743  if (pe != nullptr) {
1744  break;
1745  }
1746  }
1747  return pe;
1748 }
1749 
1756 {
1757  uint biggest = 0;
1758  for (const auto &it : this->entries) {
1759  biggest = std::max(biggest, it->GetMaxHelpHeight(maxw));
1760  }
1761  return biggest;
1762 }
1763 
1764 
1779 uint SettingsContainer::Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row, uint parent_last) const
1780 {
1781  for (const auto &it : this->entries) {
1782  cur_row = it->Draw(settings_ptr, left, right, y, first_row, max_row, selected, cur_row, parent_last);
1783  if (cur_row >= max_row) break;
1784  }
1785  return cur_row;
1786 }
1787 
1788 /* == SettingsPage methods == */
1789 
1795 {
1796  this->title = title;
1797  this->folded = true;
1798 }
1799 
1804 void SettingsPage::Init(uint8_t level)
1805 {
1808 }
1809 
1812 {
1813  for (auto settings_entry : this->entries) {
1814  settings_entry->ResetAll();
1815  }
1816 }
1817 
1820 {
1821  if (this->IsFiltered()) return;
1822  this->folded = true;
1823 
1825 }
1826 
1829 {
1830  if (this->IsFiltered()) return;
1831  this->folded = false;
1832 
1834 }
1835 
1841 void SettingsPage::GetFoldingState(bool &all_folded, bool &all_unfolded) const
1842 {
1843  if (this->IsFiltered()) return;
1844 
1845  if (this->folded) {
1846  all_unfolded = false;
1847  } else {
1848  all_folded = false;
1849  }
1850 
1851  SettingsContainer::GetFoldingState(all_folded, all_unfolded);
1852 }
1853 
1860 bool SettingsPage::UpdateFilterState(SettingFilter &filter, bool force_visible)
1861 {
1862  if (!force_visible && !filter.string.IsEmpty()) {
1863  filter.string.ResetState();
1864  filter.string.AddLine(this->title);
1865  force_visible = filter.string.GetState();
1866  }
1867 
1868  bool visible = SettingsContainer::UpdateFilterState(filter, force_visible);
1869  if (visible) {
1870  CLRBITS(this->flags, SEF_FILTERED);
1871  } else {
1872  SETBITS(this->flags, SEF_FILTERED);
1873  }
1874  return visible;
1875 }
1876 
1884 {
1885  if (this->IsFiltered()) return false;
1886  if (this == item) return true;
1887  if (this->folded) return false;
1888 
1889  return SettingsContainer::IsVisible(item);
1890 }
1891 
1894 {
1895  if (this->IsFiltered()) return 0;
1896  if (this->folded) return 1; // Only displaying the title
1897 
1898  return 1 + SettingsContainer::Length();
1899 }
1900 
1907 BaseSettingEntry *SettingsPage::FindEntry(uint row_num, uint *cur_row)
1908 {
1909  if (this->IsFiltered()) return nullptr;
1910  if (row_num == *cur_row) return this;
1911  (*cur_row)++;
1912  if (this->folded) return nullptr;
1913 
1914  return SettingsContainer::FindEntry(row_num, cur_row);
1915 }
1916 
1931 uint SettingsPage::Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row, uint parent_last) const
1932 {
1933  if (this->IsFiltered()) return cur_row;
1934  if (cur_row >= max_row) return cur_row;
1935 
1936  cur_row = BaseSettingEntry::Draw(settings_ptr, left, right, y, first_row, max_row, selected, cur_row, parent_last);
1937 
1938  if (!this->folded) {
1939  if (this->flags & SEF_LAST_FIELD) {
1940  assert(this->level < 8 * sizeof(parent_last));
1941  SetBit(parent_last, this->level); // Add own last-field state
1942  }
1943 
1944  cur_row = SettingsContainer::Draw(settings_ptr, left, right, y, first_row, max_row, selected, cur_row, parent_last);
1945  }
1946 
1947  return cur_row;
1948 }
1949 
1956 void SettingsPage::DrawSetting(GameSettings *, int left, int right, int y, bool) const
1957 {
1958  bool rtl = _current_text_dir == TD_RTL;
1959  DrawSprite((this->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? right - _circle_size.width : left, y + (SETTING_HEIGHT - _circle_size.height) / 2);
1960  DrawString(rtl ? left : left + _circle_size.width + WidgetDimensions::scaled.hsep_normal, rtl ? right - _circle_size.width - WidgetDimensions::scaled.hsep_normal : right, y + (SETTING_HEIGHT - GetCharacterHeight(FS_NORMAL)) / 2, this->title, TC_ORANGE);
1961 }
1962 
1965 {
1966  static SettingsContainer *main = nullptr;
1967 
1968  if (main == nullptr)
1969  {
1970  /* Build up the dynamic settings-array only once per OpenTTD session */
1971  main = new SettingsContainer();
1972 
1973  SettingsPage *localisation = main->Add(new SettingsPage(STR_CONFIG_SETTING_LOCALISATION));
1974  {
1975  localisation->Add(new SettingEntry("locale.units_velocity"));
1976  localisation->Add(new SettingEntry("locale.units_velocity_nautical"));
1977  localisation->Add(new SettingEntry("locale.units_power"));
1978  localisation->Add(new SettingEntry("locale.units_weight"));
1979  localisation->Add(new SettingEntry("locale.units_volume"));
1980  localisation->Add(new SettingEntry("locale.units_force"));
1981  localisation->Add(new SettingEntry("locale.units_height"));
1982  localisation->Add(new SettingEntry("gui.date_format_in_default_names"));
1983  }
1984 
1985  SettingsPage *graphics = main->Add(new SettingsPage(STR_CONFIG_SETTING_GRAPHICS));
1986  {
1987  graphics->Add(new SettingEntry("gui.zoom_min"));
1988  graphics->Add(new SettingEntry("gui.zoom_max"));
1989  graphics->Add(new SettingEntry("gui.sprite_zoom_min"));
1990  graphics->Add(new SettingEntry("gui.smallmap_land_colour"));
1991  graphics->Add(new SettingEntry("gui.linkgraph_colours"));
1992  graphics->Add(new SettingEntry("gui.graph_line_thickness"));
1993  }
1994 
1995  SettingsPage *sound = main->Add(new SettingsPage(STR_CONFIG_SETTING_SOUND));
1996  {
1997  sound->Add(new SettingEntry("sound.click_beep"));
1998  sound->Add(new SettingEntry("sound.confirm"));
1999  sound->Add(new SettingEntry("sound.news_ticker"));
2000  sound->Add(new SettingEntry("sound.news_full"));
2001  sound->Add(new SettingEntry("sound.new_year"));
2002  sound->Add(new SettingEntry("sound.disaster"));
2003  sound->Add(new SettingEntry("sound.vehicle"));
2004  sound->Add(new SettingEntry("sound.ambient"));
2005  }
2006 
2007  SettingsPage *interface = main->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE));
2008  {
2009  SettingsPage *general = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_GENERAL));
2010  {
2011  general->Add(new SettingEntry("gui.osk_activation"));
2012  general->Add(new SettingEntry("gui.hover_delay_ms"));
2013  general->Add(new SettingEntry("gui.errmsg_duration"));
2014  general->Add(new SettingEntry("gui.window_snap_radius"));
2015  general->Add(new SettingEntry("gui.window_soft_limit"));
2016  general->Add(new SettingEntry("gui.right_click_wnd_close"));
2017  }
2018 
2019  SettingsPage *viewports = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_VIEWPORTS));
2020  {
2021  viewports->Add(new SettingEntry("gui.auto_scrolling"));
2022  viewports->Add(new SettingEntry("gui.scroll_mode"));
2023  viewports->Add(new SettingEntry("gui.smooth_scroll"));
2024  /* While the horizontal scrollwheel scrolling is written as general code, only
2025  * the cocoa (OSX) driver generates input for it.
2026  * Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */
2027  viewports->Add(new SettingEntry("gui.scrollwheel_scrolling"));
2028  viewports->Add(new SettingEntry("gui.scrollwheel_multiplier"));
2029 #ifdef __APPLE__
2030  /* We might need to emulate a right mouse button on mac */
2031  viewports->Add(new SettingEntry("gui.right_mouse_btn_emulation"));
2032 #endif
2033  viewports->Add(new SettingEntry("gui.population_in_label"));
2034  viewports->Add(new SettingEntry("gui.liveries"));
2035  viewports->Add(new SettingEntry("construction.train_signal_side"));
2036  viewports->Add(new SettingEntry("gui.measure_tooltip"));
2037  viewports->Add(new SettingEntry("gui.loading_indicators"));
2038  viewports->Add(new SettingEntry("gui.show_track_reservation"));
2039  }
2040 
2041  SettingsPage *construction = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION));
2042  {
2043  construction->Add(new SettingEntry("gui.link_terraform_toolbar"));
2044  construction->Add(new SettingEntry("gui.persistent_buildingtools"));
2045  construction->Add(new SettingEntry("gui.default_rail_type"));
2046  construction->Add(new SettingEntry("gui.semaphore_build_before"));
2047  construction->Add(new SettingEntry("gui.signal_gui_mode"));
2048  construction->Add(new SettingEntry("gui.cycle_signal_types"));
2049  construction->Add(new SettingEntry("gui.drag_signals_fixed_distance"));
2050  construction->Add(new SettingEntry("gui.auto_remove_signals"));
2051  }
2052 
2053  interface->Add(new SettingEntry("gui.toolbar_pos"));
2054  interface->Add(new SettingEntry("gui.statusbar_pos"));
2055  interface->Add(new SettingEntry("gui.prefer_teamchat"));
2056  interface->Add(new SettingEntry("gui.advanced_vehicle_list"));
2057  interface->Add(new SettingEntry("gui.timetable_mode"));
2058  interface->Add(new SettingEntry("gui.timetable_arrival_departure"));
2059  interface->Add(new SettingEntry("gui.show_newgrf_name"));
2060  interface->Add(new SettingEntry("gui.show_cargo_in_vehicle_lists"));
2061  }
2062 
2063  SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS));
2064  {
2065  advisors->Add(new SettingEntry("gui.coloured_news_year"));
2066  advisors->Add(new SettingEntry("news_display.general"));
2067  advisors->Add(new SettingEntry("news_display.new_vehicles"));
2068  advisors->Add(new SettingEntry("news_display.accident"));
2069  advisors->Add(new SettingEntry("news_display.accident_other"));
2070  advisors->Add(new SettingEntry("news_display.company_info"));
2071  advisors->Add(new SettingEntry("news_display.acceptance"));
2072  advisors->Add(new SettingEntry("news_display.arrival_player"));
2073  advisors->Add(new SettingEntry("news_display.arrival_other"));
2074  advisors->Add(new SettingEntry("news_display.advice"));
2075  advisors->Add(new SettingEntry("gui.order_review_system"));
2076  advisors->Add(new SettingEntry("gui.vehicle_income_warn"));
2077  advisors->Add(new SettingEntry("gui.lost_vehicle_warn"));
2078  advisors->Add(new SettingEntry("gui.old_vehicle_warn"));
2079  advisors->Add(new SettingEntry("gui.show_finances"));
2080  advisors->Add(new SettingEntry("news_display.economy"));
2081  advisors->Add(new SettingEntry("news_display.subsidies"));
2082  advisors->Add(new SettingEntry("news_display.open"));
2083  advisors->Add(new SettingEntry("news_display.close"));
2084  advisors->Add(new SettingEntry("news_display.production_player"));
2085  advisors->Add(new SettingEntry("news_display.production_other"));
2086  advisors->Add(new SettingEntry("news_display.production_nobody"));
2087  }
2088 
2089  SettingsPage *company = main->Add(new SettingsPage(STR_CONFIG_SETTING_COMPANY));
2090  {
2091  company->Add(new SettingEntry("gui.starting_colour"));
2092  company->Add(new SettingEntry("gui.starting_colour_secondary"));
2093  company->Add(new SettingEntry("company.engine_renew"));
2094  company->Add(new SettingEntry("company.engine_renew_months"));
2095  company->Add(new SettingEntry("company.engine_renew_money"));
2096  company->Add(new SettingEntry("vehicle.servint_ispercent"));
2097  company->Add(new SettingEntry("vehicle.servint_trains"));
2098  company->Add(new SettingEntry("vehicle.servint_roadveh"));
2099  company->Add(new SettingEntry("vehicle.servint_ships"));
2100  company->Add(new SettingEntry("vehicle.servint_aircraft"));
2101  }
2102 
2103  SettingsPage *accounting = main->Add(new SettingsPage(STR_CONFIG_SETTING_ACCOUNTING));
2104  {
2105  accounting->Add(new SettingEntry("difficulty.infinite_money"));
2106  accounting->Add(new SettingEntry("economy.inflation"));
2107  accounting->Add(new SettingEntry("difficulty.initial_interest"));
2108  accounting->Add(new SettingEntry("difficulty.max_loan"));
2109  accounting->Add(new SettingEntry("difficulty.subsidy_multiplier"));
2110  accounting->Add(new SettingEntry("difficulty.subsidy_duration"));
2111  accounting->Add(new SettingEntry("economy.feeder_payment_share"));
2112  accounting->Add(new SettingEntry("economy.infrastructure_maintenance"));
2113  accounting->Add(new SettingEntry("difficulty.vehicle_costs"));
2114  accounting->Add(new SettingEntry("difficulty.construction_cost"));
2115  }
2116 
2117  SettingsPage *vehicles = main->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES));
2118  {
2119  SettingsPage *physics = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_PHYSICS));
2120  {
2121  physics->Add(new SettingEntry("vehicle.train_acceleration_model"));
2122  physics->Add(new SettingEntry("vehicle.train_slope_steepness"));
2123  physics->Add(new SettingEntry("vehicle.wagon_speed_limits"));
2124  physics->Add(new SettingEntry("vehicle.freight_trains"));
2125  physics->Add(new SettingEntry("vehicle.roadveh_acceleration_model"));
2126  physics->Add(new SettingEntry("vehicle.roadveh_slope_steepness"));
2127  physics->Add(new SettingEntry("vehicle.smoke_amount"));
2128  physics->Add(new SettingEntry("vehicle.plane_speed"));
2129  }
2130 
2131  SettingsPage *routing = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_ROUTING));
2132  {
2133  routing->Add(new SettingEntry("vehicle.road_side"));
2134  routing->Add(new SettingEntry("difficulty.line_reverse_mode"));
2135  routing->Add(new SettingEntry("pf.reverse_at_signals"));
2136  routing->Add(new SettingEntry("pf.forbid_90_deg"));
2137  }
2138 
2139  SettingsPage *orders = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_ORDERS));
2140  {
2141  orders->Add(new SettingEntry("gui.new_nonstop"));
2142  orders->Add(new SettingEntry("gui.quick_goto"));
2143  orders->Add(new SettingEntry("gui.stop_location"));
2144  }
2145  }
2146 
2147  SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS));
2148  {
2149  limitations->Add(new SettingEntry("construction.command_pause_level"));
2150  limitations->Add(new SettingEntry("construction.autoslope"));
2151  limitations->Add(new SettingEntry("construction.extra_dynamite"));
2152  limitations->Add(new SettingEntry("construction.map_height_limit"));
2153  limitations->Add(new SettingEntry("construction.max_bridge_length"));
2154  limitations->Add(new SettingEntry("construction.max_bridge_height"));
2155  limitations->Add(new SettingEntry("construction.max_tunnel_length"));
2156  limitations->Add(new SettingEntry("station.never_expire_airports"));
2157  limitations->Add(new SettingEntry("vehicle.never_expire_vehicles"));
2158  limitations->Add(new SettingEntry("vehicle.max_trains"));
2159  limitations->Add(new SettingEntry("vehicle.max_roadveh"));
2160  limitations->Add(new SettingEntry("vehicle.max_aircraft"));
2161  limitations->Add(new SettingEntry("vehicle.max_ships"));
2162  limitations->Add(new SettingEntry("vehicle.max_train_length"));
2163  limitations->Add(new SettingEntry("station.station_spread"));
2164  limitations->Add(new SettingEntry("station.distant_join_stations"));
2165  limitations->Add(new SettingEntry("station.modified_catchment"));
2166  limitations->Add(new SettingEntry("construction.road_stop_on_town_road"));
2167  limitations->Add(new SettingEntry("construction.road_stop_on_competitor_road"));
2168  limitations->Add(new SettingEntry("construction.crossing_with_competitor"));
2169  limitations->Add(new SettingEntry("vehicle.disable_elrails"));
2170  limitations->Add(new SettingEntry("order.station_length_loading_penalty"));
2171  }
2172 
2173  SettingsPage *disasters = main->Add(new SettingsPage(STR_CONFIG_SETTING_ACCIDENTS));
2174  {
2175  disasters->Add(new SettingEntry("difficulty.disasters"));
2176  disasters->Add(new SettingEntry("difficulty.economy"));
2177  disasters->Add(new SettingEntry("vehicle.plane_crashes"));
2178  disasters->Add(new SettingEntry("difficulty.vehicle_breakdowns"));
2179  disasters->Add(new SettingEntry("order.no_servicing_if_no_breakdowns"));
2180  disasters->Add(new SettingEntry("order.serviceathelipad"));
2181  }
2182 
2183  SettingsPage *genworld = main->Add(new SettingsPage(STR_CONFIG_SETTING_GENWORLD));
2184  {
2185  genworld->Add(new SettingEntry("game_creation.landscape"));
2186  genworld->Add(new SettingEntry("game_creation.land_generator"));
2187  genworld->Add(new SettingEntry("difficulty.terrain_type"));
2188  genworld->Add(new SettingEntry("game_creation.tgen_smoothness"));
2189  genworld->Add(new SettingEntry("game_creation.variety"));
2190  genworld->Add(new SettingEntry("game_creation.snow_coverage"));
2191  genworld->Add(new SettingEntry("game_creation.snow_line_height"));
2192  genworld->Add(new SettingEntry("game_creation.desert_coverage"));
2193  genworld->Add(new SettingEntry("game_creation.amount_of_rivers"));
2194  }
2195 
2196  SettingsPage *environment = main->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT));
2197  {
2198  SettingsPage *time = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TIME));
2199  {
2200  time->Add(new SettingEntry("economy.timekeeping_units"));
2201  time->Add(new SettingEntry("economy.minutes_per_calendar_year"));
2202  time->Add(new SettingEntry("game_creation.ending_year"));
2203  time->Add(new SettingEntry("gui.pause_on_newgame"));
2204  time->Add(new SettingEntry("gui.fast_forward_speed_limit"));
2205  }
2206 
2207  SettingsPage *authorities = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES));
2208  {
2209  authorities->Add(new SettingEntry("difficulty.town_council_tolerance"));
2210  authorities->Add(new SettingEntry("economy.bribe"));
2211  authorities->Add(new SettingEntry("economy.exclusive_rights"));
2212  authorities->Add(new SettingEntry("economy.fund_roads"));
2213  authorities->Add(new SettingEntry("economy.fund_buildings"));
2214  authorities->Add(new SettingEntry("economy.station_noise_level"));
2215  }
2216 
2217  SettingsPage *towns = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TOWNS));
2218  {
2219  towns->Add(new SettingEntry("economy.town_cargo_scale"));
2220  towns->Add(new SettingEntry("economy.town_growth_rate"));
2221  towns->Add(new SettingEntry("economy.allow_town_roads"));
2222  towns->Add(new SettingEntry("economy.allow_town_level_crossings"));
2223  towns->Add(new SettingEntry("economy.found_town"));
2224  towns->Add(new SettingEntry("economy.town_layout"));
2225  towns->Add(new SettingEntry("economy.larger_towns"));
2226  towns->Add(new SettingEntry("economy.initial_city_size"));
2227  towns->Add(new SettingEntry("economy.town_cargogen_mode"));
2228  }
2229 
2230  SettingsPage *industries = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES));
2231  {
2232  industries->Add(new SettingEntry("economy.industry_cargo_scale"));
2233  industries->Add(new SettingEntry("difficulty.industry_density"));
2234  industries->Add(new SettingEntry("construction.raw_industry_construction"));
2235  industries->Add(new SettingEntry("construction.industry_platform"));
2236  industries->Add(new SettingEntry("economy.multiple_industry_per_town"));
2237  industries->Add(new SettingEntry("game_creation.oil_refinery_limit"));
2238  industries->Add(new SettingEntry("economy.type"));
2239  industries->Add(new SettingEntry("station.serve_neutral_industries"));
2240  }
2241 
2242  SettingsPage *cdist = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST));
2243  {
2244  cdist->Add(new SettingEntry("linkgraph.recalc_time"));
2245  cdist->Add(new SettingEntry("linkgraph.recalc_interval"));
2246  cdist->Add(new SettingEntry("linkgraph.distribution_pax"));
2247  cdist->Add(new SettingEntry("linkgraph.distribution_mail"));
2248  cdist->Add(new SettingEntry("linkgraph.distribution_armoured"));
2249  cdist->Add(new SettingEntry("linkgraph.distribution_default"));
2250  cdist->Add(new SettingEntry("linkgraph.accuracy"));
2251  cdist->Add(new SettingEntry("linkgraph.demand_distance"));
2252  cdist->Add(new SettingEntry("linkgraph.demand_size"));
2253  cdist->Add(new SettingEntry("linkgraph.short_path_saturation"));
2254  }
2255 
2256  SettingsPage *trees = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TREES));
2257  {
2258  trees->Add(new SettingEntry("game_creation.tree_placer"));
2259  trees->Add(new SettingEntry("construction.extra_tree_placement"));
2260  }
2261  }
2262 
2263  SettingsPage *ai = main->Add(new SettingsPage(STR_CONFIG_SETTING_AI));
2264  {
2265  SettingsPage *npc = ai->Add(new SettingsPage(STR_CONFIG_SETTING_AI_NPC));
2266  {
2267  npc->Add(new SettingEntry("script.script_max_opcode_till_suspend"));
2268  npc->Add(new SettingEntry("script.script_max_memory_megabytes"));
2269  npc->Add(new SettingEntry("difficulty.competitor_speed"));
2270  npc->Add(new SettingEntry("ai.ai_in_multiplayer"));
2271  npc->Add(new SettingEntry("ai.ai_disable_veh_train"));
2272  npc->Add(new SettingEntry("ai.ai_disable_veh_roadveh"));
2273  npc->Add(new SettingEntry("ai.ai_disable_veh_aircraft"));
2274  npc->Add(new SettingEntry("ai.ai_disable_veh_ship"));
2275  }
2276 
2277  ai->Add(new SettingEntry("economy.give_money"));
2278  }
2279 
2280  SettingsPage *network = main->Add(new SettingsPage(STR_CONFIG_SETTING_NETWORK));
2281  {
2282  network->Add(new SettingEntry("network.use_relay_service"));
2283  }
2284 
2285  main->Init();
2286  }
2287  return *main;
2288 }
2289 
2290 static const StringID _game_settings_restrict_dropdown[] = {
2291  STR_CONFIG_SETTING_RESTRICT_BASIC, // RM_BASIC
2292  STR_CONFIG_SETTING_RESTRICT_ADVANCED, // RM_ADVANCED
2293  STR_CONFIG_SETTING_RESTRICT_ALL, // RM_ALL
2294  STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT, // RM_CHANGED_AGAINST_DEFAULT
2295  STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW, // RM_CHANGED_AGAINST_NEW
2296 };
2297 static_assert(lengthof(_game_settings_restrict_dropdown) == RM_END);
2298 
2305 };
2306 
2312 static void ResetAllSettingsConfirmationCallback(Window *w, bool confirmed)
2313 {
2314  if (confirmed) {
2317  w->InvalidateData();
2318  }
2319 }
2320 
2324 
2330 
2336 
2337  Scrollbar *vscroll;
2338 
2340  {
2341  this->warn_missing = WHR_NONE;
2342  this->warn_lines = 0;
2344  this->filter.min_cat = RM_ALL;
2345  this->filter.type = ST_ALL;
2346  this->filter.type_hides = false;
2347  this->settings_ptr = &GetGameSettings();
2348 
2349  GetSettingsTree().FoldAll(); // Close all sub-pages
2350 
2351  this->valuewindow_entry = nullptr; // No setting entry for which a entry window is opened
2352  this->clicked_entry = nullptr; // No numeric setting buttons are depressed
2353  this->last_clicked = nullptr;
2354  this->valuedropdown_entry = nullptr;
2355  this->closing_dropdown = false;
2356  this->manually_changed_folding = false;
2357 
2358  this->CreateNestedTree();
2359  this->vscroll = this->GetScrollbar(WID_GS_SCROLLBAR);
2361 
2362  this->querystrings[WID_GS_FILTER] = &this->filter_editbox;
2363  this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
2365 
2366  this->InvalidateData();
2367  }
2368 
2369  void OnInit() override
2370  {
2371  _circle_size = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED));
2372  }
2373 
2374  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2375  {
2376  switch (widget) {
2377  case WID_GS_OPTIONSPANEL:
2379  resize.width = 1;
2380 
2381  size.height = 5 * resize.height + WidgetDimensions::scaled.framerect.Vertical();
2382  break;
2383 
2384  case WID_GS_HELP_TEXT: {
2385  static const StringID setting_types[] = {
2386  STR_CONFIG_SETTING_TYPE_CLIENT,
2387  STR_CONFIG_SETTING_TYPE_COMPANY_MENU, STR_CONFIG_SETTING_TYPE_COMPANY_INGAME,
2388  STR_CONFIG_SETTING_TYPE_GAME_MENU, STR_CONFIG_SETTING_TYPE_GAME_INGAME,
2389  };
2390  for (const auto &setting_type : setting_types) {
2391  SetDParam(0, setting_type);
2392  size.width = std::max(size.width, GetStringBoundingBox(STR_CONFIG_SETTING_TYPE).width + padding.width);
2393  }
2395  std::max(size.height, GetSettingsTree().GetMaxHelpHeight(size.width));
2396  break;
2397  }
2398 
2400  case WID_GS_RESTRICT_TYPE:
2401  size.width = std::max(GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_CATEGORY).width, GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_TYPE).width);
2402  break;
2403 
2404  default:
2405  break;
2406  }
2407  }
2408 
2409  void OnPaint() override
2410  {
2411  if (this->closing_dropdown) {
2412  this->closing_dropdown = false;
2413  assert(this->valuedropdown_entry != nullptr);
2414  this->valuedropdown_entry->SetButtons(0);
2415  this->valuedropdown_entry = nullptr;
2416  }
2417 
2418  /* Reserve the correct number of lines for the 'some search results are hidden' notice in the central settings display panel. */
2419  const Rect panel = this->GetWidget<NWidgetBase>(WID_GS_OPTIONSPANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext);
2420  StringID warn_str = STR_CONFIG_SETTING_CATEGORY_HIDES - 1 + this->warn_missing;
2421  int new_warn_lines;
2422  if (this->warn_missing == WHR_NONE) {
2423  new_warn_lines = 0;
2424  } else {
2425  SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]);
2426  new_warn_lines = GetStringLineCount(warn_str, panel.Width());
2427  }
2428  if (this->warn_lines != new_warn_lines) {
2429  this->vscroll->SetCount(this->vscroll->GetCount() - this->warn_lines + new_warn_lines);
2430  this->warn_lines = new_warn_lines;
2431  }
2432 
2433  this->DrawWidgets();
2434 
2435  /* Draw the 'some search results are hidden' notice. */
2436  if (this->warn_missing != WHR_NONE) {
2437  SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]);
2438  DrawStringMultiLine(panel.WithHeight(this->warn_lines * GetCharacterHeight(FS_NORMAL)), warn_str, TC_FROMSTRING, SA_CENTER);
2439  }
2440  }
2441 
2442  void SetStringParameters(WidgetID widget) const override
2443  {
2444  switch (widget) {
2446  SetDParam(0, _game_settings_restrict_dropdown[this->filter.mode]);
2447  break;
2448 
2449  case WID_GS_TYPE_DROPDOWN:
2450  switch (this->filter.type) {
2451  case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME); break;
2452  case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME); break;
2453  case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT); break;
2454  default: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL); break;
2455  }
2456  break;
2457  }
2458  }
2459 
2460  DropDownList BuildDropDownList(WidgetID widget) const
2461  {
2462  DropDownList list;
2463  switch (widget) {
2465  for (int mode = 0; mode != RM_END; mode++) {
2466  /* If we are in adv. settings screen for the new game's settings,
2467  * we don't want to allow comparing with new game's settings. */
2468  bool disabled = mode == RM_CHANGED_AGAINST_NEW && settings_ptr == &_settings_newgame;
2469 
2470  list.push_back(MakeDropDownListStringItem(_game_settings_restrict_dropdown[mode], mode, disabled));
2471  }
2472  break;
2473 
2474  case WID_GS_TYPE_DROPDOWN:
2475  list.push_back(MakeDropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL, ST_ALL));
2476  list.push_back(MakeDropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME, ST_GAME));
2477  list.push_back(MakeDropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME, ST_COMPANY));
2478  list.push_back(MakeDropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT, ST_CLIENT));
2479  break;
2480  }
2481  return list;
2482  }
2483 
2484  void DrawWidget(const Rect &r, WidgetID widget) const override
2485  {
2486  switch (widget) {
2487  case WID_GS_OPTIONSPANEL: {
2488  Rect tr = r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect);
2489  tr.top += this->warn_lines * SETTING_HEIGHT;
2490  uint last_row = this->vscroll->GetPosition() + this->vscroll->GetCapacity() - this->warn_lines;
2491  int next_row = GetSettingsTree().Draw(settings_ptr, tr.left, tr.right, tr.top,
2492  this->vscroll->GetPosition(), last_row, this->last_clicked);
2493  if (next_row == 0) DrawString(tr, STR_CONFIG_SETTINGS_NONE);
2494  break;
2495  }
2496 
2497  case WID_GS_HELP_TEXT:
2498  if (this->last_clicked != nullptr) {
2499  const IntSettingDesc *sd = this->last_clicked->setting;
2500 
2501  Rect tr = r;
2502  switch (sd->GetType()) {
2503  case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_COMPANY_INGAME); break;
2504  case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_CLIENT); break;
2505  case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_GAME_MENU : STR_CONFIG_SETTING_TYPE_GAME_INGAME); break;
2506  default: NOT_REACHED();
2507  }
2508  DrawString(tr, STR_CONFIG_SETTING_TYPE);
2509  tr.top += GetCharacterHeight(FS_NORMAL);
2510 
2511  int32_t def_val = sd->get_def_cb != nullptr ? sd->get_def_cb() : sd->def;
2512  sd->SetValueDParams(0, def_val);
2513  DrawString(tr, STR_CONFIG_SETTING_DEFAULT_VALUE);
2515 
2516  DrawStringMultiLine(tr, sd->GetHelp(), TC_WHITE);
2517  }
2518  break;
2519 
2520  default:
2521  break;
2522  }
2523  }
2524 
2530  {
2531  if (this->last_clicked != pe) this->SetDirty();
2532  this->last_clicked = pe;
2533  }
2534 
2535  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2536  {
2537  switch (widget) {
2538  case WID_GS_EXPAND_ALL:
2539  this->manually_changed_folding = true;
2541  this->InvalidateData();
2542  break;
2543 
2544  case WID_GS_COLLAPSE_ALL:
2545  this->manually_changed_folding = true;
2547  this->InvalidateData();
2548  break;
2549 
2550  case WID_GS_RESET_ALL:
2551  ShowQuery(
2552  STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION,
2553  STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT,
2554  this,
2556  );
2557  break;
2558 
2559  case WID_GS_RESTRICT_DROPDOWN: {
2560  DropDownList list = this->BuildDropDownList(widget);
2561  if (!list.empty()) {
2562  ShowDropDownList(this, std::move(list), this->filter.mode, widget);
2563  }
2564  break;
2565  }
2566 
2567  case WID_GS_TYPE_DROPDOWN: {
2568  DropDownList list = this->BuildDropDownList(widget);
2569  if (!list.empty()) {
2570  ShowDropDownList(this, std::move(list), this->filter.type, widget);
2571  }
2572  break;
2573  }
2574  }
2575 
2576  if (widget != WID_GS_OPTIONSPANEL) return;
2577 
2578  int32_t btn = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GS_OPTIONSPANEL, WidgetDimensions::scaled.framerect.top);
2579  if (btn == INT32_MAX || btn < this->warn_lines) return;
2580  btn -= this->warn_lines;
2581 
2582  uint cur_row = 0;
2584 
2585  if (clicked_entry == nullptr) return; // Clicked below the last setting of the page
2586 
2587  int x = (_current_text_dir == TD_RTL ? this->width - 1 - pt.x : pt.x) - WidgetDimensions::scaled.frametext.left - (clicked_entry->level + 1) * WidgetDimensions::scaled.hsep_indent; // Shift x coordinate
2588  if (x < 0) return; // Clicked left of the entry
2589 
2590  SettingsPage *clicked_page = dynamic_cast<SettingsPage*>(clicked_entry);
2591  if (clicked_page != nullptr) {
2592  this->SetDisplayedHelpText(nullptr);
2593  clicked_page->folded = !clicked_page->folded; // Flip 'folded'-ness of the sub-page
2594 
2595  this->manually_changed_folding = true;
2596 
2597  this->InvalidateData();
2598  return;
2599  }
2600 
2601  SettingEntry *pe = dynamic_cast<SettingEntry*>(clicked_entry);
2602  assert(pe != nullptr);
2603  const IntSettingDesc *sd = pe->setting;
2604 
2605  /* return if action is only active in network, or only settable by server */
2606  if (!sd->IsEditable()) {
2607  this->SetDisplayedHelpText(pe);
2608  return;
2609  }
2610 
2611  int32_t value = sd->Read(ResolveObject(settings_ptr, sd));
2612 
2613  /* clicked on the icon on the left side. Either scroller, bool on/off or dropdown */
2614  if (x < SETTING_BUTTON_WIDTH && (sd->flags & SF_GUI_DROPDOWN)) {
2615  this->SetDisplayedHelpText(pe);
2616 
2617  if (this->valuedropdown_entry == pe) {
2618  /* unclick the dropdown */
2620  this->closing_dropdown = false;
2621  this->valuedropdown_entry->SetButtons(0);
2622  this->valuedropdown_entry = nullptr;
2623  } else {
2624  if (this->valuedropdown_entry != nullptr) this->valuedropdown_entry->SetButtons(0);
2625  this->closing_dropdown = false;
2626 
2627  const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_GS_OPTIONSPANEL);
2628  int rel_y = (pt.y - wid->pos_y - WidgetDimensions::scaled.framerect.top) % wid->resize_y;
2629 
2630  Rect wi_rect;
2631  wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x);
2632  wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1;
2633  wi_rect.top = pt.y - rel_y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2;
2634  wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1;
2635 
2636  /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */
2637  if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) {
2638  this->valuedropdown_entry = pe;
2639  this->valuedropdown_entry->SetButtons(SEF_LEFT_DEPRESSED);
2640 
2641  DropDownList list;
2642  for (int i = sd->min; i <= (int)sd->max; i++) {
2643  sd->SetValueDParams(0, i);
2644  list.push_back(MakeDropDownListStringItem(STR_JUST_STRING2, i));
2645  }
2646 
2647  ShowDropDownListAt(this, std::move(list), value, WID_GS_SETTING_DROPDOWN, wi_rect, COLOUR_ORANGE);
2648  }
2649  }
2650  this->SetDirty();
2651  } else if (x < SETTING_BUTTON_WIDTH) {
2652  this->SetDisplayedHelpText(pe);
2653  int32_t oldvalue = value;
2654 
2655  if (sd->IsBoolSetting()) {
2656  value ^= 1;
2657  } else {
2658  /* Add a dynamic step-size to the scroller. In a maximum of
2659  * 50-steps you should be able to get from min to max,
2660  * unless specified otherwise in the 'interval' variable
2661  * of the current setting. */
2662  uint32_t step = (sd->interval == 0) ? ((sd->max - sd->min) / 50) : sd->interval;
2663  if (step == 0) step = 1;
2664 
2665  /* don't allow too fast scrolling */
2666  if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) {
2667  _left_button_clicked = false;
2668  return;
2669  }
2670 
2671  /* Increase or decrease the value and clamp it to extremes */
2672  if (x >= SETTING_BUTTON_WIDTH / 2) {
2673  value += step;
2674  if (sd->min < 0) {
2675  assert((int32_t)sd->max >= 0);
2676  if (value > (int32_t)sd->max) value = (int32_t)sd->max;
2677  } else {
2678  if ((uint32_t)value > sd->max) value = (int32_t)sd->max;
2679  }
2680  if (value < sd->min) value = sd->min; // skip between "disabled" and minimum
2681  } else {
2682  value -= step;
2683  if (value < sd->min) value = (sd->flags & SF_GUI_0_IS_SPECIAL) ? 0 : sd->min;
2684  }
2685 
2686  /* Set up scroller timeout for numeric values */
2687  if (value != oldvalue) {
2688  if (this->clicked_entry != nullptr) { // Release previous buttons if any
2689  this->clicked_entry->SetButtons(0);
2690  }
2691  this->clicked_entry = pe;
2692  this->clicked_entry->SetButtons((x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? SEF_RIGHT_DEPRESSED : SEF_LEFT_DEPRESSED);
2693  this->SetTimeout();
2694  _left_button_clicked = false;
2695  }
2696  }
2697 
2698  if (value != oldvalue) {
2699  SetSettingValue(sd, value);
2700  this->SetDirty();
2701  }
2702  } else {
2703  /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */
2704  if (this->last_clicked == pe && !sd->IsBoolSetting() && !(sd->flags & SF_GUI_DROPDOWN)) {
2705  int64_t value64 = value;
2706  /* Show the correct currency-translated value */
2707  if (sd->flags & SF_GUI_CURRENCY) value64 *= GetCurrency().rate;
2708 
2709  CharSetFilter charset_filter = CS_NUMERAL; //default, only numeric input allowed
2710  if (sd->min < 0) charset_filter = CS_NUMERAL_SIGNED; // special case, also allow '-' sign for negative input
2711 
2712  this->valuewindow_entry = pe;
2713  SetDParam(0, value64);
2714  /* Limit string length to 14 so that MAX_INT32 * max currency rate doesn't exceed MAX_INT64. */
2715  ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 15, this, charset_filter, QSF_ENABLE_DEFAULT);
2716  }
2717  this->SetDisplayedHelpText(pe);
2718  }
2719  }
2720 
2721  void OnTimeout() override
2722  {
2723  if (this->clicked_entry != nullptr) { // On timeout, release any depressed buttons
2724  this->clicked_entry->SetButtons(0);
2725  this->clicked_entry = nullptr;
2726  this->SetDirty();
2727  }
2728  }
2729 
2730  void OnQueryTextFinished(std::optional<std::string> str) override
2731  {
2732  /* The user pressed cancel */
2733  if (!str.has_value()) return;
2734 
2735  assert(this->valuewindow_entry != nullptr);
2736  const IntSettingDesc *sd = this->valuewindow_entry->setting;
2737 
2738  int32_t value;
2739  if (!str->empty()) {
2740  long long llvalue = atoll(str->c_str());
2741 
2742  /* Save the correct currency-translated value */
2743  if (sd->flags & SF_GUI_CURRENCY) llvalue /= GetCurrency().rate;
2744 
2745  value = ClampTo<int32_t>(llvalue);
2746  } else if (sd->get_def_cb != nullptr) {
2747  value = sd->get_def_cb();
2748  } else {
2749  value = sd->def;
2750  }
2751 
2752  SetSettingValue(this->valuewindow_entry->setting, value);
2753  this->SetDirty();
2754  }
2755 
2756  void OnDropdownSelect(WidgetID widget, int index) override
2757  {
2758  switch (widget) {
2760  this->filter.mode = (RestrictionMode)index;
2761  if (this->filter.mode == RM_CHANGED_AGAINST_DEFAULT ||
2762  this->filter.mode == RM_CHANGED_AGAINST_NEW) {
2763 
2764  if (!this->manually_changed_folding) {
2765  /* Expand all when selecting 'changes'. Update the filter state first, in case it becomes less restrictive in some cases. */
2766  GetSettingsTree().UpdateFilterState(this->filter, false);
2768  }
2769  } else {
2770  /* Non-'changes' filter. Save as default. */
2772  }
2773  this->InvalidateData();
2774  break;
2775 
2776  case WID_GS_TYPE_DROPDOWN:
2777  this->filter.type = (SettingType)index;
2778  this->InvalidateData();
2779  break;
2780 
2782  /* Deal with drop down boxes on the panel. */
2783  assert(this->valuedropdown_entry != nullptr);
2784  const IntSettingDesc *sd = this->valuedropdown_entry->setting;
2785  assert(sd->flags & SF_GUI_DROPDOWN);
2786 
2787  SetSettingValue(sd, index);
2788  this->SetDirty();
2789  break;
2790  }
2791  }
2792 
2793  void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
2794  {
2795  if (widget != WID_GS_SETTING_DROPDOWN) {
2796  /* Normally the default implementation of OnDropdownClose() takes care of
2797  * a few things. We want that behaviour here too, but only for
2798  * "normal" dropdown boxes. The special dropdown boxes added for every
2799  * setting that needs one can't have this call. */
2800  Window::OnDropdownClose(pt, widget, index, instant_close);
2801  } else {
2802  /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
2803  * the same dropdown button was clicked again, and then not open the dropdown again.
2804  * So, we only remember that it was closed, and process it on the next OnPaint, which is
2805  * after OnClick. */
2806  assert(this->valuedropdown_entry != nullptr);
2807  this->closing_dropdown = true;
2808  this->SetDirty();
2809  }
2810  }
2811 
2812  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2813  {
2814  if (!gui_scope) return;
2815 
2816  /* Update which settings are to be visible. */
2817  RestrictionMode min_level = (this->filter.mode <= RM_ALL) ? this->filter.mode : RM_BASIC;
2818  this->filter.min_cat = min_level;
2819  this->filter.type_hides = false;
2820  GetSettingsTree().UpdateFilterState(this->filter, false);
2821 
2822  if (this->filter.string.IsEmpty()) {
2823  this->warn_missing = WHR_NONE;
2824  } else if (min_level < this->filter.min_cat) {
2825  this->warn_missing = this->filter.type_hides ? WHR_CATEGORY_TYPE : WHR_CATEGORY;
2826  } else {
2827  this->warn_missing = this->filter.type_hides ? WHR_TYPE : WHR_NONE;
2828  }
2829  this->vscroll->SetCount(GetSettingsTree().Length() + this->warn_lines);
2830 
2831  if (this->last_clicked != nullptr && !GetSettingsTree().IsVisible(this->last_clicked)) {
2832  this->SetDisplayedHelpText(nullptr);
2833  }
2834 
2835  bool all_folded = true;
2836  bool all_unfolded = true;
2837  GetSettingsTree().GetFoldingState(all_folded, all_unfolded);
2838  this->SetWidgetDisabledState(WID_GS_EXPAND_ALL, all_unfolded);
2839  this->SetWidgetDisabledState(WID_GS_COLLAPSE_ALL, all_folded);
2840  }
2841 
2842  void OnEditboxChanged(WidgetID wid) override
2843  {
2844  if (wid == WID_GS_FILTER) {
2845  this->filter.string.SetFilterTerm(this->filter_editbox.text.buf);
2846  if (!this->filter.string.IsEmpty() && !this->manually_changed_folding) {
2847  /* User never expanded/collapsed single pages and entered a filter term.
2848  * Expand everything, to save weird expand clicks, */
2850  }
2851  this->InvalidateData();
2852  }
2853  }
2854 
2855  void OnResize() override
2856  {
2857  this->vscroll->SetCapacityFromWidget(this, WID_GS_OPTIONSPANEL, WidgetDimensions::scaled.framerect.Vertical());
2858  }
2859 };
2860 
2862 
2863 static constexpr NWidgetPart _nested_settings_selection_widgets[] = {
2865  NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
2866  NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_CONFIG_SETTING_TREE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2867  NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
2868  EndContainer(),
2869  NWidget(WWT_PANEL, COLOUR_MAUVE),
2872  NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_CATEGORY), SetDataTip(STR_CONFIG_SETTING_RESTRICT_CATEGORY, STR_NULL),
2873  NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_RESTRICT_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING, STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0),
2874  EndContainer(),
2876  NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_TYPE), SetDataTip(STR_CONFIG_SETTING_RESTRICT_TYPE, STR_NULL),
2877  NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_TYPE_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING, STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0),
2878  EndContainer(),
2880  NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_CONFIG_SETTING_FILTER_TITLE, STR_NULL),
2881  NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_GS_FILTER), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2882  EndContainer(),
2883  EndContainer(),
2884  EndContainer(),
2887  NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_GS_SCROLLBAR),
2888  EndContainer(),
2889  NWidget(WWT_PANEL, COLOUR_MAUVE),
2890  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GS_HELP_TEXT), SetMinimalSize(300, 25), SetFill(1, 1), SetResize(1, 0),
2892  EndContainer(),
2894  NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_EXPAND_ALL), SetDataTip(STR_CONFIG_SETTING_EXPAND_ALL, STR_NULL),
2895  NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_COLLAPSE_ALL), SetDataTip(STR_CONFIG_SETTING_COLLAPSE_ALL, STR_NULL),
2896  NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_RESET_ALL), SetDataTip(STR_CONFIG_SETTING_RESET_ALL, STR_NULL),
2897  NWidget(WWT_PANEL, COLOUR_MAUVE), SetFill(1, 0), SetResize(1, 0),
2898  EndContainer(),
2899  NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
2900  EndContainer(),
2901 };
2902 
2903 static WindowDesc _settings_selection_desc(
2904  WDP_CENTER, "settings", 510, 450,
2906  0,
2907  _nested_settings_selection_widgets
2908 );
2909 
2912 {
2914  new GameSettingsWindow(_settings_selection_desc);
2915 }
2916 
2917 
2927 void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
2928 {
2929  int colour = GetColourGradient(button_colour, SHADE_DARKER);
2930  Dimension dim = NWidgetScrollbar::GetHorizontalDimension();
2931 
2932  Rect lr = {x, y, x + (int)dim.width - 1, y + (int)dim.height - 1};
2933  Rect rr = {x + (int)dim.width, y, x + (int)dim.width * 2 - 1, y + (int)dim.height - 1};
2934 
2935  DrawFrameRect(lr, button_colour, (state == 1) ? FR_LOWERED : FR_NONE);
2936  DrawFrameRect(rr, button_colour, (state == 2) ? FR_LOWERED : FR_NONE);
2937  DrawSpriteIgnorePadding(SPR_ARROW_LEFT, PAL_NONE, lr, SA_CENTER);
2938  DrawSpriteIgnorePadding(SPR_ARROW_RIGHT, PAL_NONE, rr, SA_CENTER);
2939 
2940  /* Grey out the buttons that aren't clickable */
2941  bool rtl = _current_text_dir == TD_RTL;
2942  if (rtl ? !clickable_right : !clickable_left) {
2944  }
2945  if (rtl ? !clickable_left : !clickable_right) {
2947  }
2948 }
2949 
2958 void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable)
2959 {
2960  int colour = GetColourGradient(button_colour, SHADE_DARKER);
2961 
2962  Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
2963 
2964  DrawFrameRect(r, button_colour, state ? FR_LOWERED : FR_NONE);
2965  DrawSpriteIgnorePadding(SPR_ARROW_DOWN, PAL_NONE, r, SA_CENTER);
2966 
2967  if (!clickable) {
2969  }
2970 }
2971 
2979 void DrawBoolButton(int x, int y, bool state, bool clickable)
2980 {
2981  static const Colours _bool_ctabs[2][2] = {{COLOUR_CREAM, COLOUR_RED}, {COLOUR_DARK_GREEN, COLOUR_GREEN}};
2982 
2983  Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
2984  DrawFrameRect(r, _bool_ctabs[state][clickable], state ? FR_LOWERED : FR_NONE);
2985 }
2986 
2988  int query_widget;
2989 
2990  CustomCurrencyWindow(WindowDesc &desc) : Window(desc)
2991  {
2992  this->InitNested();
2993 
2994  SetButtonState();
2995  }
2996 
2997  void SetButtonState()
2998  {
3000  this->SetWidgetDisabledState(WID_CC_RATE_UP, GetCustomCurrency().rate == UINT16_MAX);
3003  }
3004 
3005  void SetStringParameters(WidgetID widget) const override
3006  {
3007  switch (widget) {
3008  case WID_CC_RATE: SetDParam(0, 1); SetDParam(1, 1); break;
3009  case WID_CC_SEPARATOR: SetDParamStr(0, GetCustomCurrency().separator); break;
3010  case WID_CC_PREFIX: SetDParamStr(0, GetCustomCurrency().prefix); break;
3011  case WID_CC_SUFFIX: SetDParamStr(0, GetCustomCurrency().suffix); break;
3012  case WID_CC_YEAR:
3013  SetDParam(0, (GetCustomCurrency().to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER);
3014  SetDParam(1, GetCustomCurrency().to_euro);
3015  break;
3016 
3017  case WID_CC_PREVIEW:
3018  SetDParam(0, 10000);
3019  break;
3020  }
3021  }
3022 
3023  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
3024  {
3025  switch (widget) {
3026  /* Set the appropriate width for the up/down buttons. */
3027  case WID_CC_RATE_DOWN:
3028  case WID_CC_RATE_UP:
3029  case WID_CC_YEAR_DOWN:
3030  case WID_CC_YEAR_UP:
3031  size = maxdim(size, {(uint)SETTING_BUTTON_WIDTH / 2, (uint)SETTING_BUTTON_HEIGHT});
3032  break;
3033 
3034  /* Set the appropriate width for the edit buttons. */
3035  case WID_CC_SEPARATOR_EDIT:
3036  case WID_CC_PREFIX_EDIT:
3037  case WID_CC_SUFFIX_EDIT:
3038  size = maxdim(size, {(uint)SETTING_BUTTON_WIDTH, (uint)SETTING_BUTTON_HEIGHT});
3039  break;
3040 
3041  /* Make sure the window is wide enough for the widest exchange rate */
3042  case WID_CC_RATE:
3043  SetDParam(0, 1);
3044  SetDParam(1, INT32_MAX);
3045  size = GetStringBoundingBox(STR_CURRENCY_EXCHANGE_RATE);
3046  break;
3047  }
3048  }
3049 
3050  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
3051  {
3052  int line = 0;
3053  int len = 0;
3054  StringID str = 0;
3055  CharSetFilter afilter = CS_ALPHANUMERAL;
3056 
3057  switch (widget) {
3058  case WID_CC_RATE_DOWN:
3059  if (GetCustomCurrency().rate > 1) GetCustomCurrency().rate--;
3060  if (GetCustomCurrency().rate == 1) this->DisableWidget(WID_CC_RATE_DOWN);
3062  break;
3063 
3064  case WID_CC_RATE_UP:
3065  if (GetCustomCurrency().rate < UINT16_MAX) GetCustomCurrency().rate++;
3066  if (GetCustomCurrency().rate == UINT16_MAX) this->DisableWidget(WID_CC_RATE_UP);
3068  break;
3069 
3070  case WID_CC_RATE:
3071  SetDParam(0, GetCustomCurrency().rate);
3072  str = STR_JUST_INT;
3073  len = 5;
3074  line = WID_CC_RATE;
3075  afilter = CS_NUMERAL;
3076  break;
3077 
3078  case WID_CC_SEPARATOR_EDIT:
3079  case WID_CC_SEPARATOR:
3080  SetDParamStr(0, GetCustomCurrency().separator);
3081  str = STR_JUST_RAW_STRING;
3082  len = 7;
3083  line = WID_CC_SEPARATOR;
3084  break;
3085 
3086  case WID_CC_PREFIX_EDIT:
3087  case WID_CC_PREFIX:
3088  SetDParamStr(0, GetCustomCurrency().prefix);
3089  str = STR_JUST_RAW_STRING;
3090  len = 15;
3091  line = WID_CC_PREFIX;
3092  break;
3093 
3094  case WID_CC_SUFFIX_EDIT:
3095  case WID_CC_SUFFIX:
3096  SetDParamStr(0, GetCustomCurrency().suffix);
3097  str = STR_JUST_RAW_STRING;
3098  len = 15;
3099  line = WID_CC_SUFFIX;
3100  break;
3101 
3102  case WID_CC_YEAR_DOWN:
3106  break;
3107 
3108  case WID_CC_YEAR_UP:
3112  break;
3113 
3114  case WID_CC_YEAR:
3115  SetDParam(0, GetCustomCurrency().to_euro);
3116  str = STR_JUST_INT;
3117  len = 7;
3118  line = WID_CC_YEAR;
3119  afilter = CS_NUMERAL;
3120  break;
3121  }
3122 
3123  if (len != 0) {
3124  this->query_widget = line;
3125  ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, this, afilter, QSF_NONE);
3126  }
3127 
3128  this->SetTimeout();
3129  this->SetDirty();
3130  }
3131 
3132  void OnQueryTextFinished(std::optional<std::string> str) override
3133  {
3134  if (!str.has_value()) return;
3135 
3136  switch (this->query_widget) {
3137  case WID_CC_RATE:
3138  GetCustomCurrency().rate = Clamp(atoi(str->c_str()), 1, UINT16_MAX);
3139  break;
3140 
3141  case WID_CC_SEPARATOR: // Thousands separator
3142  GetCustomCurrency().separator = std::move(*str);
3143  break;
3144 
3145  case WID_CC_PREFIX:
3146  GetCustomCurrency().prefix = std::move(*str);
3147  break;
3148 
3149  case WID_CC_SUFFIX:
3150  GetCustomCurrency().suffix = std::move(*str);
3151  break;
3152 
3153  case WID_CC_YEAR: { // Year to switch to euro
3154  TimerGameCalendar::Year val = atoi(str->c_str());
3155 
3157  break;
3158  }
3159  }
3161  SetButtonState();
3162  }
3163 
3164  void OnTimeout() override
3165  {
3166  this->SetDirty();
3167  }
3168 };
3169 
3170 static constexpr NWidgetPart _nested_cust_currency_widgets[] = {
3172  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
3173  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CURRENCY_WINDOW, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
3174  EndContainer(),
3175  NWidget(WWT_PANEL, COLOUR_GREY),
3180  NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP),
3181  NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP),
3182  EndContainer(),
3183  NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_RATE), SetDataTip(STR_CURRENCY_EXCHANGE_RATE, STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP), SetFill(1, 0),
3184  EndContainer(),
3186  NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SEPARATOR_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(0, 1),
3187  NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SEPARATOR), SetDataTip(STR_CURRENCY_SEPARATOR, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(1, 0),
3188  EndContainer(),
3190  NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_PREFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(0, 1),
3191  NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_PREFIX), SetDataTip(STR_CURRENCY_PREFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(1, 0),
3192  EndContainer(),
3194  NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SUFFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(0, 1),
3195  NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SUFFIX), SetDataTip(STR_CURRENCY_SUFFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(1, 0),
3196  EndContainer(),
3199  NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP),
3200  NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP),
3201  EndContainer(),
3202  NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_YEAR), SetDataTip(STR_JUST_STRING1, STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), SetFill(1, 0),
3203  EndContainer(),
3204  EndContainer(),
3205  NWidget(WWT_LABEL, COLOUR_BLUE, WID_CC_PREVIEW),
3206  SetDataTip(STR_CURRENCY_PREVIEW, STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP),
3207  EndContainer(),
3208  EndContainer(),
3209 };
3210 
3211 static WindowDesc _cust_currency_desc(
3212  WDP_CENTER, nullptr, 0, 0,
3214  0,
3215  _nested_cust_currency_widgets
3216 );
3217 
3219 static void ShowCustCurrency()
3220 {
3222  new CustomCurrencyWindow(_cust_currency_desc);
3223 }
void UpdateAllVirtCoords()
Update the viewport coordinates of all signs.
Definition: afterload.cpp:223
Base functions for all AIs.
Generic functions for replacing base data (graphics, sounds).
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
#define CLRBITS(x, y)
Clears several bits in a variable.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
#define SETBITS(x, y)
Sets several bits in a variable.
static const GraphicsSet * GetUsedSet()
Return the used set.
static int GetNumSets()
Count the number of available graphics sets.
static const GraphicsSet * GetSet(int index)
Get the name of the graphics set at the specified index.
static bool SetSet(const GraphicsSet *set)
Set the set to be used.
static bool NatSortFunc(std::unique_ptr< const DropDownListItem > const &first, std::unique_ptr< const DropDownListItem > const &second)
Natural sorting comparator function for DropDownList::sort().
static MusicDriver * GetInstance()
Get the currently active instance of the music driver.
virtual void SetVolume(uint8_t vol)=0
Set the volume, if possible.
Baseclass for nested widgets.
Definition: widget_type.h:144
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:243
int pos_y
Vertical position of top-left corner of the widget in the window.
Definition: widget_type.h:249
uint resize_y
Vertical resize step (0 means not resizable).
Definition: widget_type.h:236
void Add(std::unique_ptr< NWidgetBase > &&wid)
Append widget wid to container.
Definition: widget.cpp:1197
void FillWidgetLookup(WidgetLookup &widget_lookup) override
Fill the Window::widget_lookup with pointers to nested widgets in the tree.
Definition: widget.cpp:1204
std::vector< std::unique_ptr< NWidgetBase > > children
Child widgets in contaier.
Definition: widget_type.h:476
void SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post)
Set additional pre/inter/post space for the container.
Definition: widget.cpp:1373
Base class for a resizable nested widget.
Definition: widget_type.h:303
bool UpdateVerticalSize(uint min_y)
Set absolute (post-scaling) minimal size of the widget.
Definition: widget.cpp:1092
void FillWidgetLookup(WidgetLookup &widget_lookup) override
Fill the Window::widget_lookup with pointers to nested widgets in the tree.
void Draw(const Window *w) override
Draw the widgets of the tree.
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
std::string & GetWidestPlugin(T SocialIntegrationPlugin::*member) const
Find of all the plugins the one where the member is the widest (in pixels).
Vertical container.
Definition: widget_type.h:581
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
Definition: widget.cpp:1599
Scrollbar data structure.
Definition: widget_type.h:694
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:731
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:2320
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition: widget.cpp:2394
size_type GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:722
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:740
@ PLATFORM_NOT_RUNNING
The plugin failed to initialize because the Social Platform is not running.
@ UNSUPPORTED_API
The plugin does not support the current API version.
@ RUNNING
The plugin is successfully loaded and running.
@ FAILED
The plugin failed to initialize.
@ DUPLICATE
Another plugin of the same Social Platform is already loaded.
@ INVALID_SIGNATURE
The signature of the plugin is invalid.
@ UNLOADED
The plugin is unloaded upon request.
std::string social_platform
Social platform this plugin is for.
std::string name
Name of the plugin.
std::string version
Version of the plugin.
static std::vector< SocialIntegrationPlugin * > GetPlugins()
Get the list of loaded social integration plugins.
static constexpr TimerGame< struct Calendar >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
virtual std::vector< int > GetListOfMonitorRefreshRates()
Get a list of refresh rates of each available monitor.
virtual void ToggleVsync([[maybe_unused]] bool vsync)
Change the vsync setting.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
RectPadding framerect
Standard padding inside many panels.
Definition: window_gui.h:42
RectPadding frametext
Padding inside frame with text.
Definition: window_gui.h:43
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
int vsep_normal
Normal vertical spacing.
Definition: window_gui.h:60
int hsep_wide
Wide horizontal spacing.
Definition: window_gui.h:64
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
int hsep_normal
Normal horizontal spacing.
Definition: window_gui.h:63
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
int hsep_indent
Width of identation for tree layouts.
Definition: window_gui.h:65
Functions related to commands.
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
Functions related to companies.
Configuration options of the network stuff.
static const std::string NETWORK_SURVEY_DETAILS_LINK
Link with more details & privacy statement of the survey.
Definition: config.h:30
uint64_t GetMaskOfAllowedCurrencies()
get a mask of the allowed currencies depending on the year
Definition: currency.cpp:125
std::array< CurrencySpec, CURRENCY_END > _currency_specs
Array of currencies used by the system.
Definition: currency.cpp:77
Functions to handle different currencies.
static constexpr TimerGameCalendar::Year MIN_EURO_YEAR
The earliest year custom currencies may switch to the Euro.
Definition: currency.h:19
const CurrencySpec & GetCurrency()
Get the currently selected currency.
Definition: currency.h:117
CurrencySpec & GetCustomCurrency()
Get the custom currency.
Definition: currency.h:108
static constexpr TimerGameCalendar::Year CF_NOEURO
Currency never switches to the Euro (as far as known).
Definition: currency.h:17
@ CURRENCY_CUSTOM
Custom currency.
Definition: currency.h:58
std::vector< Dimension > _resolutions
List of resolutions.
Definition: driver.cpp:25
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition: dropdown.cpp:404
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition: dropdown.cpp:363
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, bool instant_close, bool persist)
Show a drop down list.
Definition: dropdown.cpp:386
Common drop down list components.
Functions related to the drop down widget.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
Definition: dropdown_type.h:50
#define DECLARE_POSTFIX_INCREMENT(enum_type)
Some enums need to have allowed incrementing (i.e.
Definition: enum_type.hpp:18
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_ERROR
Errors (eg. saving/loading failed)
Definition: error.h:26
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition: error.h:24
Factory to 'query' all available blitters.
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
Definition: fileio_type.h:123
void InitFontCache(bool monospace)
(Re)initialize the font cache related things, i.e.
Definition: fontcache.cpp:218
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
Functions to read fonts from files and cache them.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:704
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
bool _left_button_down
Is left mouse button pressed?
Definition: gfx.cpp:41
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:851
int GetStringLineCount(StringID str, int maxw)
Calculates number of lines of string.
Definition: gfx.cpp:728
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:38
bool _left_button_clicked
Is left mouse button clicked?
Definition: gfx.cpp:42
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition: gfx.cpp:114
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
int _gui_scale_cfg
GUI scale in config.
Definition: gfx.cpp:64
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:774
SwitchMode _switch_mode
The next mainloop command.
Definition: gfx.cpp:49
bool AdjustGUIZoom(bool automatic)
Resolve GUI zoom level and adjust GUI to new zoom, if auto-suggestion is requested.
Definition: gfx.cpp:1793
int _gui_scale
GUI scale, 100 is 100%.
Definition: gfx.cpp:63
void CheckBlitter()
Check whether we still use the right blitter, or use another (better) one.
Definition: gfxinit.cpp:313
@ SA_RIGHT
Right align the text (must be a single bit).
Definition: gfx_type.h:345
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_type.h:353
@ FS_SMALL
Index of the small font in the font tables.
Definition: gfx_type.h:210
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition: gfx_type.h:299
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
Definition: widget_type.h:1330
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1181
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1260
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
Definition: widget_type.h:1228
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
std::unique_ptr< NWidgetBase > MakeNWidgets(std::span< const NWidgetPart > nwid_parts, std::unique_ptr< NWidgetBase > &&container)
Construct a nested widget tree from an array of parts.
Definition: widget.cpp:3239
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
Definition: widget_type.h:1149
constexpr NWidgetPart SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
Definition: widget_type.h:1170
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlags::ResizeX)
Widget part function for setting the aspect ratio.
Definition: widget_type.h:1295
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
Definition: widget_type.h:1272
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition: gfx.cpp:1529
GUI functions that shouldn't be here.
Declaration of functions and types defined in highscore.h and highscore_gui.h.
Information about languages and their files.
LanguageList _languages
The actual list of language meta data.
Definition: strings.cpp:53
const LanguageMetadata * _current_language
The currently loaded language.
Definition: strings.cpp:54
bool ReadLanguagePack(const LanguageMetadata *lang)
Read a particular language.
Definition: strings.cpp:1912
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback, bool focus)
Show a confirmation window with standard 'yes' and 'no' buttons The window is aligned to the centre o...
Definition: misc_gui.cpp:1223
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1079
@ WID_TF_CAPTION
The caption of the window.
Definition: misc_widget.h:50
Functions to mix sound samples.
Base for all music playback.
void ChangeMusicSet(int index)
Change the configured music set and reset playback.
Definition: music_gui.cpp:463
bool _network_available
is network mode available?
Definition: network.cpp:67
Basic functions/variables used all over the place.
Part of the network protocol handling content distribution.
void ShowNetworkContentListWindow(ContentVector *cv=nullptr, ContentType type1=CONTENT_TYPE_END, ContentType type2=CONTENT_TYPE_END)
Show the content list window with a given set of content.
GUIs related to networking.
Part of the network protocol handling opt-in survey.
Functions to find and configure NewGRFs.
void ChangeAutosaveFrequency(bool reset)
Reset the interval of the autosave.
Definition: openttd.cpp:1318
@ SM_MENU
Switch to game intro menu.
Definition: openttd.h:33
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition: palette.cpp:314
Base for the GUIs that have an edit box in them.
declaration of OTTD revision dependent variables
A number of safeguards to prevent using unsafe methods.
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
Definition: settings.cpp:1616
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
Definition: settings.cpp:1744
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition: settings.cpp:58
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
WarnHiddenResult
Warnings about hidden search results.
@ WHR_CATEGORY_TYPE
Both category and type settings filtered matches away.
@ WHR_CATEGORY
Category setting filtered matches away.
@ WHR_NONE
Nothing was filtering matches away.
@ WHR_TYPE
Type setting filtered matches away.
void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
Draw [<][>] boxes.
static void ResetAllSettingsConfirmationCallback(Window *w, bool confirmed)
Callback function for the reset all settings button.
static const uint32_t _autosave_dropdown_to_minutes[]
Available settings for autosave intervals.
static void AddCustomRefreshRates()
Add the refresh rate from the config and the refresh rates from all the monitors to our list of refre...
SettingEntryFlags
Flags for SettingEntry.
@ SEF_FILTERED
Entry is hidden by the string filter.
@ SEF_BUTTONS_MASK
Bit-mask for button flags.
@ SEF_LEFT_DEPRESSED
Of a numeric setting entry, the left button is depressed.
@ SEF_LAST_FIELD
This entry is the last one in a (sub-)page.
@ SEF_RIGHT_DEPRESSED
Of a numeric setting entry, the right button is depressed.
RestrictionMode
How the list of advanced settings is filtered.
@ RM_CHANGED_AGAINST_DEFAULT
Show only settings which are different compared to default values.
@ RM_ADVANCED
Display settings associated to the "advanced" list.
@ RM_ALL
List all settings regardless of the default/newgame/... values.
@ RM_CHANGED_AGAINST_NEW
Show only settings which are different compared to the user's new game setting values.
@ RM_END
End for iteration.
@ RM_BASIC
Display settings associated to the "basic" list.
void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable)
Draw a dropdown button.
static SettingsContainer & GetSettingsTree()
Construct settings tree.
void ShowBaseSetTextfileWindow(TextfileType file_type, const TBaseSet *baseset, StringID content_type)
Open the BaseSet version of the textfile window.
static int SETTING_HEIGHT
Height of a single setting in the tree view in pixels.
void ShowGameSettings()
Open advanced settings window.
static uint GetCurrentResolutionIndex()
Get index of the current screen resolution.
std::unique_ptr< NWidgetBase > MakeNWidgetSocialPlugins()
Construct nested container widget for managing the list of social plugins.
void DrawBoolButton(int x, int y, bool state, bool clickable)
Draw a toggle button.
static void ShowCustCurrency()
Open custom currency window.
void ShowGameOptions()
Open the game options window.
static Dimension _circle_size
Dimension of the circle +/- icon. This is here as not all users are within the class of the settings ...
Functions for setting GUIs.
#define SETTING_BUTTON_WIDTH
Width of setting buttons.
Definition: settings_gui.h:17
#define SETTING_BUTTON_HEIGHT
Height of setting buttons.
Definition: settings_gui.h:19
Functions and types used internally for the settings configurations.
SettingType
Type of settings for filtering.
@ ST_CLIENT
Client setting.
@ ST_ALL
Used in setting filter to match all types.
@ ST_GAME
Game setting.
@ ST_COMPANY
Company setting.
@ SF_GUI_DROPDOWN
The value represents a limited number of string-options (internally integer) presented as dropdown.
@ SF_PER_COMPANY
This setting can be different for each company (saved in company struct).
@ SF_GUI_CURRENCY
The number represents money, so when reading value multiply by exchange rate.
@ SF_GUI_0_IS_SPECIAL
A value of zero is possible and has a custom string (the one after "strval").
@ SC_ADVANCED_LIST
Settings displayed in the list of advanced settings.
@ SC_BASIC_LIST
Settings displayed in the list of basic settings.
GameSettings & GetGameSettings()
Get the settings-object applicable for the current situation: the newgame settings when we're in the ...
@ WID_GS_TYPE_DROPDOWN
The drop down box to choose client/game/company/all settings.
@ WID_GS_SETTING_DROPDOWN
Dynamically created dropdown for changing setting value.
@ WID_GS_EXPAND_ALL
Expand all button.
@ WID_GS_OPTIONSPANEL
Panel widget containing the option lists.
@ WID_GS_RESTRICT_CATEGORY
Label upfront to the category drop-down box to restrict the list of settings to show.
@ WID_GS_HELP_TEXT
Information area to display help text of the selected option.
@ WID_GS_RESTRICT_DROPDOWN
The drop down box to restrict the list of settings.
@ WID_GS_RESTRICT_TYPE
Label upfront to the type drop-down box to restrict the list of settings to show.
@ WID_GS_RESET_ALL
Reset all button.
@ WID_GS_SCROLLBAR
Scrollbar.
@ WID_GS_COLLAPSE_ALL
Collapse all button.
@ WID_GS_FILTER
Text filter.
@ WID_GO_BASE_SFX_OPEN_URL
Open base SFX URL.
@ WID_GO_BASE_MUSIC_DESCRIPTION
Description of selected base music set.
@ WID_GO_BASE_MUSIC_CONTENT_DOWNLOAD
'Get Content' button for base music.
@ WID_GO_RESOLUTION_DROPDOWN
Dropdown for the resolution.
@ WID_GO_CURRENCY_DROPDOWN
Currency dropdown.
@ WID_GO_BASE_GRF_DESCRIPTION
Description of selected base GRF.
@ WID_GO_BASE_SFX_DESCRIPTION
Description of selected base SFX.
@ WID_GO_GUI_SCALE_BEVEL_BUTTON
Toggle for chunky bevels.
@ WID_GO_GUI_SCALE
GUI Scale slider.
@ WID_GO_BASE_SFX_TEXTFILE
Open base SFX readme, changelog (+1) or license (+2).
@ WID_GO_GUI_FONT_SPRITE
Toggle whether to prefer the sprite font over TTF fonts.
@ WID_GO_GUI_SCALE_AUTO
Autodetect GUI scale button.
@ WID_GO_SOCIAL_PLUGINS
Main widget handling the social plugins.
@ WID_GO_BASE_GRF_CONTENT_DOWNLOAD
'Get Content' button for base GRF.
@ WID_GO_BASE_GRF_TEXTFILE
Open base GRF readme, changelog (+1) or license (+2).
@ WID_GO_TAB_GENERAL
General tab.
@ WID_GO_BASE_GRF_DROPDOWN
Use to select a base GRF.
@ WID_GO_BASE_MUSIC_VOLUME
Change music volume.
@ WID_GO_BASE_SFX_VOLUME
Change sound effects volume.
@ WID_GO_BASE_GRF_PARAMETERS
Base GRF parameters.
@ WID_GO_LANG_DROPDOWN
Language dropdown.
@ WID_GO_GUI_FONT_AA
Toggle whether to anti-alias fonts.
@ WID_GO_VIDEO_VSYNC_BUTTON
Toggle for video vsync.
@ WID_GO_SURVEY_LINK_BUTTON
Button to open browser to go to the survey website.
@ WID_GO_TAB_SELECTION
Background of the tab selection.
@ WID_GO_SURVEY_PARTICIPATE_BUTTON
Toggle for participating in the automated survey.
@ WID_GO_AUTOSAVE_DROPDOWN
Dropdown to say how often to autosave.
@ WID_GO_TAB_GRAPHICS
Graphics tab.
@ WID_GO_TEXT_MUSIC_VOLUME
Music volume label.
@ WID_GO_BASE_MUSIC_JUKEBOX
Open the jukebox.
@ WID_GO_SOCIAL_PLUGIN_STATE
State of the social plugin.
@ WID_GO_SURVEY_SEL
Selection to hide survey if no JSON library is compiled in.
@ WID_GO_REFRESH_RATE_DROPDOWN
Dropdown for all available refresh rates.
@ WID_GO_SOCIAL_PLUGIN_TITLE
Title of the frame of the social plugin.
@ WID_GO_BASE_GRF_OPEN_URL
Open base GRF URL.
@ WID_GO_BASE_MUSIC_TEXTFILE
Open base music readme, changelog (+1) or license (+2).
@ WID_GO_VIDEO_ACCEL_BUTTON
Toggle for video acceleration.
@ WID_GO_TAB_SOCIAL
Social tab.
@ WID_GO_SURVEY_PREVIEW_BUTTON
Button to open a preview window with the survey results.
@ WID_GO_BASE_SFX_CONTENT_DOWNLOAD
'Get Content' button for base SFX.
@ WID_GO_SOCIAL_PLUGIN_PLATFORM
Platform of the social plugin.
@ WID_GO_BASE_MUSIC_DROPDOWN
Use to select a base music set.
@ WID_GO_BASE_MUSIC_OPEN_URL
Open base music URL.
@ WID_GO_FULLSCREEN_BUTTON
Toggle fullscreen.
@ WID_GO_TAB_SOUND
Sound tab.
@ WID_GO_BASE_SFX_DROPDOWN
Use to select a base SFX.
@ WID_GO_TEXT_SFX_VOLUME
Sound effects volume label.
@ WID_GO_VIDEO_DRIVER_INFO
Label showing details about the current video driver.
@ WID_CC_YEAR_DOWN
Down button.
@ WID_CC_YEAR
Year of introduction.
@ WID_CC_SUFFIX_EDIT
Suffix edit button.
@ WID_CC_SEPARATOR_EDIT
Separator edit button.
@ WID_CC_RATE_DOWN
Down button.
@ WID_CC_RATE_UP
Up button.
@ WID_CC_PREVIEW
Preview.
@ WID_CC_PREFIX
Current prefix.
@ WID_CC_PREFIX_EDIT
Prefix edit button.
@ WID_CC_SUFFIX
Current suffix.
@ WID_CC_YEAR_UP
Up button.
@ WID_CC_SEPARATOR
Current separator.
@ WID_CC_RATE
Rate of currency.
int CDECL main(int argc, char *argv[])
And the main program (what else?)
void DrawSliderWidget(Rect r, int min_value, int max_value, int nmarks, int value, SliderMarkFunc *mark_func)
Draw a slider widget with knob at given value.
Definition: slider.cpp:31
bool ClickSliderWidget(Rect r, Point pt, int min_value, int max_value, int nmarks, int &value)
Handle click on a slider widget to change the value.
Definition: slider.cpp:91
Interface definitions for game to report/respond to social integration.
void ChangeSoundSet(int index)
Change the configured sound set and reset sounds.
Definition: sound.cpp:241
Functions related to sound.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:280
Functions related to low-level strings.
CharSetFilter
Valid filter types for IsValidChar.
Definition: string_type.h:24
@ CS_NUMERAL
Only numeric ones.
Definition: string_type.h:26
@ CS_NUMERAL_SIGNED
Only numbers and '-' for negative values.
Definition: string_type.h:28
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:25
Searching and filtering using a stringterm.
void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition: strings.cpp:2265
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
const char * GetCurrentLanguageIsoCode()
Get the ISO language code of the currently loaded language.
Definition: strings.cpp:2157
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:357
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Window for displaying the textfile of a BaseSet.
const std::string name
Name of the content.
const StringID content_type
STR_CONTENT_TYPE_xxx for title.
Data structure describing a single setting in a tab.
void SetLastField(bool last_field)
Set whether this is the last visible entry of the parent node.
bool IsFiltered() const
Check whether an entry is hidden due to filters.
virtual BaseSettingEntry * FindEntry(uint row, uint *cur_row)
Find setting entry at row row_num.
virtual void Init(uint8_t level=0)
Initialization of a setting entry.
virtual uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row=0, uint parent_last=0) const
Draw a row in the settings panel.
uint8_t flags
Flags of the setting entry.
virtual bool IsVisible(const BaseSettingEntry *item) const
Check whether an entry is visible and not folded or filtered away.
uint8_t level
Nesting level of this setting entry.
CompanySettings company
default values for per-company settings
MusicSettings music
settings related to music/sound
NetworkSettings network
settings related to the network
GUISettings gui
settings related to the GUI
Specification of a currency.
Definition: currency.h:75
std::string separator
The thousands separator for this currency.
Definition: currency.h:77
std::string prefix
Prefix to apply when formatting money in this currency.
Definition: currency.h:79
TimerGameCalendar::Year to_euro
Year of switching to the Euro. May also be CF_NOEURO or CF_ISEURO.
Definition: currency.h:78
std::string suffix
Suffix to apply when formatting money in this currency.
Definition: currency.h:80
std::string code
3 letter untranslated code to identify the currency.
Definition: currency.h:81
uint16_t rate
The conversion rate compared to the base currency.
Definition: currency.h:76
void OnTimeout() override
Called when this window's timeout has been reached.
Dimensions (a width and height) of a rectangle in 2D.
bool prefer_sprite
Whether to prefer the built-in sprite font over resizable fonts.
Definition: fontcache.h:205
bool global_aa
Whether to anti alias all font sizes.
Definition: fontcache.h:206
Information about GRF, used in the game and (part of it) in savegames.
void SetParameterDefaults()
Set the default value for all parameters as specified by action14.
uint8_t num_params
Number of used parameters.
uint8_t settings_restriction_mode
selected restriction mode in adv. settings GUI.
uint16_t refresh_rate
How often we refresh the screen (time between draw-ticks).
uint32_t autosave_interval
how often should we do autosaves?
uint8_t missing_strings_threshold
the number of missing strings before showing the warning
bool scale_bevels
bevels are scaled with GUI scale.
void OnResize() override
Called after the window got resized.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.
DropDownList BuildDropDownList(WidgetID widget, int *selected_index) const
Build the dropdown list for a specific widget.
Window to edit settings of the game.
bool manually_changed_folding
Whether the user expanded/collapsed something manually.
SettingEntry * valuewindow_entry
If non-nullptr, pointer to setting for which a value-entering window has been opened.
SettingEntry * clicked_entry
If non-nullptr, pointer to a clicked numeric setting (with a depressed left or right button).
void OnTimeout() override
Called when this window's timeout has been reached.
QueryString filter_editbox
Filter editbox;.
SettingEntry * valuedropdown_entry
If non-nullptr, pointer to the value for which a dropdown window is currently opened.
bool closing_dropdown
True, if the dropdown list is currently closing.
void OnInit() override
Notification that the nested widget tree gets initialized.
SettingFilter filter
Filter for the list.
void SetDisplayedHelpText(SettingEntry *pe)
Set the entry that should have its help text displayed, and mark the window dirty so it gets repainte...
void OnResize() override
Called after the window got resized.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
SettingEntry * last_clicked
If non-nullptr, pointer to the last clicked setting.
void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
A dropdown window associated to this window has been closed.
WarnHiddenResult warn_missing
Whether and how to warn about missing search results.
void OnPaint() override
The window must be repainted.
static GameSettings * settings_ptr
Pointer to the game settings being displayed and modified.
int warn_lines
Number of lines used for warning about missing search results.
All settings together for the game.
LocaleSettings locale
settings related to used currency/unit system in the current game
Base integer type, including boolean, settings.
void SetValueDParams(uint first_param, int32_t value) const
Set the DParams for drawing the value of the setting.
Definition: settings.cpp:460
int32_t def
default value given when none is present
SettingCategory cat
assigned categories of the setting
StringID GetTitle() const
Get the title of the setting.
Definition: settings.cpp:441
uint32_t max
maximum values
GetDefaultValueCallback * get_def_cb
Callback to set the correct default value.
int32_t min
minimum values
StringID GetHelp() const
Get the help text of the setting.
Definition: settings.cpp:450
virtual bool IsBoolSetting() const
Check whether this setting is a boolean type setting.
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition: settings.cpp:561
int32_t interval
the interval to use between settings in the 'settings' window. If interval is '0' the interval is dyn...
char own_name[32]
the localized name of this language
Definition: language.h:30
uint8_t currency
currency we currently use
uint8_t effect_vol
The requested effects volume.
uint8_t music_vol
The requested music volume.
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
ParticipateSurvey participate_survey
Participate in the automated survey.
Coordinates of a point in 2D.
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
bool IsEditable(bool do_command=false) const
Check whether the setting is editable in the current gamemode.
Definition: settings.cpp:883
SettingType GetType() const
Return the type of the setting.
Definition: settings.cpp:900
const struct IntSettingDesc * AsIntSetting() const
Get the setting description of this setting as an integer setting.
Definition: settings.cpp:910
SettingFlag flags
Handles how a setting would show up in the GUI (text/currency, etc.).
Standard setting.
uint Length() const override
Return number of rows needed to display the (filtered) entry.
void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const override
Function to draw setting value (button + text + current value)
bool IsVisibleByRestrictionMode(RestrictionMode mode) const
Checks whether an entry shall be made visible based on the restriction mode.
void SetButtons(uint8_t new_val)
Set the button-depressed flags (SEF_LEFT_DEPRESSED and SEF_RIGHT_DEPRESSED) to a specified value.
uint GetMaxHelpHeight(int maxw) override
Get the biggest height of the help text(s), if the width is at least maxw.
void Init(uint8_t level=0) override
Initialization of a setting entry.
const IntSettingDesc * setting
Setting description of the setting.
SettingEntry(const char *name)
Constructor for a single setting in the 'advanced settings' window.
bool UpdateFilterState(SettingFilter &filter, bool force_visible) override
Update the filter state.
const char * name
Name of the setting.
Filter for settings list.
SettingType type
Filter based on type.
bool type_hides
Whether the type hides filtered strings.
RestrictionMode mode
Filter based on category.
RestrictionMode min_cat
Minimum category needed to display all filtered strings (RM_BASIC, RM_ADVANCED, or RM_ALL).
StringFilter string
Filter string.
Containers for BaseSettingEntry.
bool UpdateFilterState(SettingFilter &filter, bool force_visible)
Update the filter state.
void GetFoldingState(bool &all_folded, bool &all_unfolded) const
Recursively accumulate the folding state of the tree.
uint GetMaxHelpHeight(int maxw)
Get the biggest height of the help texts, if the width is at least maxw.
void ResetAll()
Resets all settings to their default values.
bool IsVisible(const BaseSettingEntry *item) const
Check whether an entry is visible and not folded or filtered away.
void FoldAll()
Recursively close all folds of sub-pages.
void UnFoldAll()
Recursively open all folds of sub-pages.
BaseSettingEntry * FindEntry(uint row, uint *cur_row)
Find the setting entry at row number row_num.
EntryVector entries
Settings on this page.
uint Length() const
Return number of rows needed to display the whole page.
uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row=0, uint parent_last=0) const
Draw a row in the settings panel.
void Init(uint8_t level=0)
Initialization of an entire setting page.
Data structure describing one page of settings in the settings window.
StringID title
Title of the sub-page.
bool IsVisible(const BaseSettingEntry *item) const override
Check whether an entry is visible and not folded or filtered away.
SettingsPage(StringID title)
Constructor for a sub-page in the 'advanced settings' window.
void UnFoldAll() override
Recursively open all (filtered) folds of sub-pages.
void FoldAll() override
Recursively close all (filtered) folds of sub-pages.
uint Length() const override
Return number of rows needed to display the (filtered) entry.
BaseSettingEntry * FindEntry(uint row, uint *cur_row) override
Find setting entry at row row_num.
uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row=0, uint parent_last=0) const override
Draw a row in the settings panel.
void Init(uint8_t level=0) override
Initialization of an entire setting page.
void GetFoldingState(bool &all_folded, bool &all_unfolded) const override
Recursively accumulate the folding state of the (filtered) tree.
void ResetAll() override
Resets all settings to their default values.
bool folded
Sub-page is folded (not visible except for its title)
bool UpdateFilterState(SettingFilter &filter, bool force_visible) override
Update the filter state.
void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const override
Function to draw setting value (button + text + current value)
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(const char *str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
bool GetState() const
Get the matching state of the current item.
Templated helper to make a type-safe 'typedef' representing a single POD value.
char *const buf
buffer in which text is saved
Definition: textbuf_type.h:32
Window for displaying a textfile.
Definition: textfile_gui.h:21
TextfileType file_type
Type of textfile to view.
Definition: textfile_gui.h:22
virtual void LoadTextfile(const std::string &textfile, Subdirectory dir)
Loads the textfile text from file and setup lines.
High level window description.
Definition: window_gui.h:159
Data structure for an opened window.
Definition: window_gui.h:273
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition: window.cpp:952
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:1047
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition: window_gui.h:320
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition: window.cpp:3151
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:551
uint8_t timeout_timer
Timer value of the WF_TIMEOUT for flags.
Definition: window_gui.h:306
WidgetID mouse_capture_widget
ID of current mouse capture widget (e.g. dragged scrollbar). -1 if no widget has mouse capture.
Definition: window_gui.h:326
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition: window.cpp:1035
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
void DisableWidget(WidgetID widget_index)
Sets a widget to disabled.
Definition: window_gui.h:397
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition: window_gui.h:521
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1723
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition: window.cpp:486
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close)
A dropdown window associated to this window has been closed.
Definition: window.cpp:287
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition: window_gui.h:532
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:447
void EnableWidget(WidgetID widget_index)
Sets a widget to Enabled.
Definition: window_gui.h:406
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition: window_gui.h:361
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1756
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition: window_gui.h:466
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
WindowFlags flags
Window flags.
Definition: window_gui.h:300
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:387
int height
Height of the window (number of pixels down in y direction)
Definition: window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:311
@ CONTENT_TYPE_BASE_SOUNDS
The content consists of base sounds.
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
@ CONTENT_TYPE_BASE_MUSIC
The content consists of base music.
Stuff related to the text buffer GUI.
@ QSF_ENABLE_DEFAULT
enable the 'Default' button ("\0" is returned)
Definition: textbuf_gui.h:21
std::optional< std::string > GetTextfile(TextfileType type, Subdirectory dir, const std::string &filename)
Search a textfile file next to the given content.
GUI functions related to textfiles.
TextfileType
Additional text files accompanying Tar archives.
Definition: textfile_type.h:14
@ TFT_LICENSE
Content license.
Definition: textfile_type.h:19
@ TFT_README
Content readme.
Definition: textfile_type.h:17
@ TFT_CHANGELOG
Content changelog.
Definition: textfile_type.h:18
Base of the town class.
bool _video_vsync
Whether we should use vsync (only if active video driver supports HW acceleration).
bool _video_hw_accel
Whether to consider hardware accelerated video drivers on startup.
Base of all video drivers.
Functions related to (drawing on) viewports.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:281
void SetupWidgetDimensions()
Set up pre-scaled versions of Widget Dimensions.
Definition: widget.cpp:66
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
Definition: widget_type.h:483
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition: widget_type.h:31
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition: widget_type.h:32
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:112
@ WWT_PUSHBTN
Normal push-button (no toggle button) with custom drawing.
Definition: widget_type.h:111
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
Definition: widget_type.h:113
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
Definition: widget_type.h:114
@ WWT_LABEL
Centered label.
Definition: widget_type.h:57
@ WWT_EDITBOX
a textbox for typing
Definition: widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ WWT_FRAME
Frame.
Definition: widget_type.h:60
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition: widget_type.h:48
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
@ WWT_DROPDOWN
Drop down list.
Definition: widget_type.h:70
@ WWT_TEXT
Pure simple text.
Definition: widget_type.h:58
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:80
std::map< WidgetID, class NWidgetBase * > WidgetLookup
Lookup between widget IDs and NWidget objects.
Definition: widget_type.h:136
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
Definition: window.cpp:3327
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition: window.cpp:1152
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3119
Window functions not directly related to making/drawing windows.
@ WF_TIMEOUT
Window timeout counter.
Definition: window_gui.h:228
@ WF_CENTERED
Window is centered and shall stay centered after ReInit.
Definition: window_gui.h:238
@ FR_LOWERED
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
Definition: window_gui.h:28
@ WDP_CENTER
Center the window.
Definition: window_gui.h:148
int WidgetID
Widget ID.
Definition: window_type.h:18
@ WN_GAME_OPTIONS_GAME_OPTIONS
Game options.
Definition: window_type.h:26
@ WN_GAME_OPTIONS_GAME_SETTINGS
Game settings.
Definition: window_type.h:27
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_MUSIC_WINDOW
Music window; Window numbers:
Definition: window_type.h:607
@ WC_CUSTOM_CURRENCY
Custom currency; Window numbers:
Definition: window_type.h:630
@ WC_GAME_OPTIONS
Game options window; Window numbers:
Definition: window_type.h:624
@ WC_TEXTFILE
textfile; Window numbers:
Definition: window_type.h:187
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
Definition: window_type.h:156
@ WC_QUERY_STRING
Query string window; Window numbers:
Definition: window_type.h:123
@ WC_GRF_PARAMETERS
NewGRF parameters; Window numbers:
Definition: window_type.h:181
Functions related to zooming.