OpenTTD Source  20241120-master-g6d3adc6169
newgrf_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 "error.h"
12 #include "settings_gui.h"
13 #include "newgrf.h"
14 #include "strings_func.h"
15 #include "window_func.h"
16 #include "gamelog.h"
17 #include "settings_type.h"
18 #include "settings_func.h"
19 #include "dropdown_type.h"
20 #include "dropdown_func.h"
21 #include "network/network.h"
23 #include "sortlist_type.h"
24 #include "stringfilter_type.h"
25 #include "querystring_gui.h"
26 #include "core/geometry_func.hpp"
27 #include "newgrf_text.h"
28 #include "textfile_gui.h"
29 #include "tilehighlight_func.h"
30 #include "fios.h"
31 #include "timer/timer.h"
32 #include "timer/timer_window.h"
33 #include "zoom_func.h"
34 
35 #include "widgets/newgrf_widget.h"
36 #include "widgets/misc_widget.h"
37 
38 #include "table/sprites.h"
39 
40 #include "safeguards.h"
41 
46 {
47  /* Do not show errors when entering the main screen */
48  if (_game_mode == GM_MENU) return;
49 
50  for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
51  /* Only show Fatal and Error level messages */
52  if (!c->error.has_value() || (c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL && c->error->severity != STR_NEWGRF_ERROR_MSG_ERROR)) continue;
53 
54  SetDParamStr(0, c->GetName());
55  SetDParam (1, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING);
56  SetDParamStr(2, c->error->custom_message);
57  SetDParamStr(3, c->filename);
58  SetDParamStr(4, c->error->data);
59  for (uint i = 0; i < c->error->param_value.size(); i++) {
60  SetDParam(5 + i, c->error->param_value[i]);
61  }
62  if (c->error->severity == STR_NEWGRF_ERROR_MSG_FATAL) {
63  ShowErrorMessage(STR_NEWGRF_ERROR_FATAL_POPUP, INVALID_STRING_ID, WL_CRITICAL);
64  } else {
65  ShowErrorMessage(STR_NEWGRF_ERROR_POPUP, INVALID_STRING_ID, WL_ERROR);
66  }
67  break;
68  }
69 }
70 
71 static void ShowNewGRFInfo(const GRFConfig *c, const Rect &r, bool show_params)
72 {
73  Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
74  if (c->error.has_value()) {
75  SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages
76  SetDParamStr(1, c->filename);
77  SetDParamStr(2, c->error->data);
78  for (uint i = 0; i < c->error->param_value.size(); i++) {
79  SetDParam(3 + i, c->error->param_value[i]);
80  }
81 
82  SetDParamStr(0, GetString(c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING));
83  tr.top = DrawStringMultiLine(tr, c->error->severity);
84  }
85 
86  /* Draw filename or not if it is not known (GRF sent over internet) */
87  if (!c->filename.empty()) {
88  SetDParamStr(0, c->filename);
89  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_FILENAME);
90  }
91 
92  /* Prepare and draw GRF ID */
93  SetDParamStr(0, fmt::format("{:08X}", BSWAP32(c->ident.grfid)));
94  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_GRF_ID);
95 
97  SetDParam(0, c->version);
98  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_VERSION);
99  }
102  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_MIN_VERSION);
103  }
104 
105  /* Prepare and draw MD5 sum */
107  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_MD5SUM);
108 
109  /* Show GRF parameter list */
110  if (show_params) {
111  if (c->num_params > 0) {
112  SetDParam(0, STR_JUST_RAW_STRING);
114  } else {
115  SetDParam(0, STR_NEWGRF_SETTINGS_PARAMETER_NONE);
116  }
117  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_PARAMETER);
118 
119  /* Draw the palette of the NewGRF */
120  if (c->palette & GRFP_BLT_32BPP) {
121  SetDParam(0, (c->palette & GRFP_USE_WINDOWS) ? STR_NEWGRF_SETTINGS_PALETTE_LEGACY_32BPP : STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP);
122  } else {
123  SetDParam(0, (c->palette & GRFP_USE_WINDOWS) ? STR_NEWGRF_SETTINGS_PALETTE_LEGACY : STR_NEWGRF_SETTINGS_PALETTE_DEFAULT);
124  }
125  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_PALETTE);
126  }
127 
128  /* Show flags */
129  if (c->status == GCS_NOT_FOUND) tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_NOT_FOUND);
130  if (c->status == GCS_DISABLED) tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_DISABLED);
131  if (HasBit(c->flags, GCF_INVALID)) tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_INCOMPATIBLE);
132  if (HasBit(c->flags, GCF_COMPATIBLE)) tr.top = DrawStringMultiLine(tr, STR_NEWGRF_COMPATIBLE_LOADED);
133 
134  /* Draw GRF info if it exists */
135  if (!StrEmpty(c->GetDescription())) {
136  SetDParamStr(0, c->GetDescription());
137  tr.top = DrawStringMultiLine(tr, STR_JUST_RAW_STRING, TC_BLACK);
138  } else {
139  tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_NO_INFO);
140  }
141 }
142 
149  int32_t clicked_button;
153  int32_t clicked_row;
155  Scrollbar *vscroll;
157  bool editable;
158 
159  NewGRFParametersWindow(WindowDesc &desc, bool is_baseset, GRFConfig *c, bool editable) : Window(desc),
160  grf_config(c),
161  clicked_button(INT32_MAX),
162  clicked_dropdown(false),
163  closing_dropdown(false),
164  clicked_row(INT32_MAX),
166  {
167  this->action14present = (c->num_valid_params != c->param.size() || !c->param_info.empty());
168 
169  this->CreateNestedTree();
170  this->GetWidget<NWidgetCore>(WID_NP_CAPTION)->SetDataTip(is_baseset ? STR_BASEGRF_PARAMETERS_CAPTION : STR_NEWGRF_PARAMETERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
171  this->vscroll = this->GetScrollbar(WID_NP_SCROLLBAR);
172  this->GetWidget<NWidgetStacked>(WID_NP_SHOW_NUMPAR)->SetDisplayedPlane(this->action14present ? SZSP_HORIZONTAL : 0);
173  this->GetWidget<NWidgetStacked>(WID_NP_SHOW_DESCRIPTION)->SetDisplayedPlane(this->action14present ? 0 : SZSP_HORIZONTAL);
174  this->FinishInitNested(); // Initializes 'this->line_height' as side effect.
175 
176  this->SetWidgetDisabledState(WID_NP_RESET, !this->editable);
177 
178  this->InvalidateData();
179  }
180 
187  {
189  return dummy_parameter_info;
190  }
191 
197  bool HasParameterInfo(uint nr) const
198  {
199  return nr < this->grf_config->param_info.size() && this->grf_config->param_info[nr].has_value();
200  }
201 
209  {
210  return this->HasParameterInfo(nr) ? this->grf_config->param_info[nr].value() : GetDummyParameterInfo(nr);
211  }
212 
213  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
214  {
215  switch (widget) {
216  case WID_NP_NUMPAR_DEC:
217  case WID_NP_NUMPAR_INC: {
218  size.width = std::max(SETTING_BUTTON_WIDTH / 2, GetCharacterHeight(FS_NORMAL));
219  size.height = std::max(SETTING_BUTTON_HEIGHT, GetCharacterHeight(FS_NORMAL));
220  break;
221  }
222 
223  case WID_NP_NUMPAR: {
224  SetDParamMaxValue(0, this->grf_config->param.size());
225  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
226  d.width += padding.width;
227  d.height += padding.height;
228  size = maxdim(size, d);
229  break;
230  }
231 
232  case WID_NP_BACKGROUND:
233  this->line_height = std::max(SETTING_BUTTON_HEIGHT, GetCharacterHeight(FS_NORMAL)) + padding.height;
234 
235  resize.width = 1;
236  resize.height = this->line_height;
237  size.height = 5 * this->line_height;
238  break;
239 
240  case WID_NP_DESCRIPTION:
241  /* Minimum size of 4 lines. The 500 is the default size of the window. */
243  for (const auto &par_info : this->grf_config->param_info) {
244  if (!par_info.has_value()) continue;
245  const char *desc = GetGRFStringFromGRFText(par_info->desc);
246  if (desc == nullptr) continue;
247  Dimension d = GetStringMultiLineBoundingBox(desc, suggestion);
249  suggestion = maxdim(d, suggestion);
250  }
251  size.height = suggestion.height;
252  break;
253  }
254  }
255 
256  void SetStringParameters(WidgetID widget) const override
257  {
258  switch (widget) {
259  case WID_NP_NUMPAR:
260  SetDParam(0, this->vscroll->GetCount());
261  break;
262  }
263  }
264 
265  void DrawWidget(const Rect &r, WidgetID widget) const override
266  {
267  if (widget == WID_NP_DESCRIPTION) {
268  if (!this->HasParameterInfo(this->clicked_row)) return;
269  const GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
270  const char *desc = GetGRFStringFromGRFText(par_info.desc);
271  if (desc == nullptr) return;
273  return;
274  } else if (widget != WID_NP_BACKGROUND) {
275  return;
276  }
277 
278  Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
279  bool rtl = _current_text_dir == TD_RTL;
280  uint buttons_left = rtl ? ir.right - SETTING_BUTTON_WIDTH : ir.left;
281  Rect tr = ir.Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
282 
283  int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
284  int text_y_offset = (this->line_height - GetCharacterHeight(FS_NORMAL)) / 2;
285  for (int32_t i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) {
286  GRFParameterInfo &par_info = this->GetParameterInfo(i);
287  uint32_t current_value = par_info.GetValue(this->grf_config);
288  bool selected = (i == this->clicked_row);
289 
290  if (par_info.type == PTYPE_BOOL) {
291  DrawBoolButton(buttons_left, ir.top + button_y_offset, current_value != 0, this->editable);
292  SetDParam(2, par_info.GetValue(this->grf_config) == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON);
293  } else if (par_info.type == PTYPE_UINT_ENUM) {
294  if (par_info.complete_labels) {
295  DrawDropDownButton(buttons_left, ir.top + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && this->clicked_dropdown, this->editable);
296  } else {
297  DrawArrowButtons(buttons_left, ir.top + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, this->editable && current_value > par_info.min_value, this->editable && current_value < par_info.max_value);
298  }
299  SetDParam(2, STR_JUST_INT);
300  SetDParam(3, current_value);
301  auto it = par_info.value_names.find(current_value);
302  if (it != par_info.value_names.end()) {
303  const char *label = GetGRFStringFromGRFText(it->second);
304  if (label != nullptr) {
305  SetDParam(2, STR_JUST_RAW_STRING);
306  SetDParamStr(3, label);
307  }
308  }
309  }
310 
311  const char *name = GetGRFStringFromGRFText(par_info.name);
312  if (name != nullptr) {
313  SetDParam(0, STR_JUST_RAW_STRING);
314  SetDParamStr(1, name);
315  } else {
316  SetDParam(0, STR_NEWGRF_PARAMETERS_DEFAULT_NAME);
317  SetDParam(1, i + 1);
318  }
319 
320  DrawString(tr.left, tr.right, ir.top + text_y_offset, STR_NEWGRF_PARAMETERS_SETTING, selected ? TC_WHITE : TC_LIGHT_BLUE);
321  ir.top += this->line_height;
322  }
323  }
324 
325  void OnPaint() override
326  {
327  if (this->closing_dropdown) {
328  this->closing_dropdown = false;
329  this->clicked_dropdown = false;
330  }
331  this->DrawWidgets();
332  }
333 
334  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
335  {
336  switch (widget) {
337  case WID_NP_NUMPAR_DEC:
338  if (this->editable && !this->action14present && this->grf_config->num_params > 0) {
339  this->grf_config->num_params--;
340  this->InvalidateData();
342  }
343  break;
344 
345  case WID_NP_NUMPAR_INC: {
346  GRFConfig *c = this->grf_config;
347  if (this->editable && !this->action14present && c->num_params < c->num_valid_params) {
348  c->param[c->num_params++] = 0;
349  this->InvalidateData();
351  }
352  break;
353  }
354 
355  case WID_NP_BACKGROUND: {
356  if (!this->editable) break;
357  int32_t num = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NP_BACKGROUND);
358  if (num >= this->vscroll->GetCount()) break;
359 
360  if (this->clicked_row != num) {
363  this->clicked_row = num;
364  this->clicked_dropdown = false;
365  }
366 
367  Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
368  int x = pt.x - r.left;
369  if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x;
370 
371  GRFParameterInfo &par_info = this->GetParameterInfo(num);
372 
373  /* One of the arrows is clicked */
374  uint32_t old_val = par_info.GetValue(this->grf_config);
375  if (par_info.type != PTYPE_BOOL && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && par_info.complete_labels) {
376  if (this->clicked_dropdown) {
377  /* unclick the dropdown */
379  this->clicked_dropdown = false;
380  this->closing_dropdown = false;
381  } else {
382  int rel_y = (pt.y - r.top) % this->line_height;
383 
384  Rect wi_rect;
385  wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x);;
386  wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1;
387  wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
388  wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1;
389 
390  /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */
391  if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) {
392  this->clicked_dropdown = true;
393  this->closing_dropdown = false;
394 
395  DropDownList list;
396  for (uint32_t i = par_info.min_value; i <= par_info.max_value; i++) {
397  list.push_back(MakeDropDownListStringItem(GetGRFStringFromGRFText(par_info.value_names.find(i)->second), i));
398  }
399 
400  ShowDropDownListAt(this, std::move(list), old_val, WID_NP_SETTING_DROPDOWN, wi_rect, COLOUR_ORANGE);
401  }
402  }
403  } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) {
404  uint32_t val = old_val;
405  if (par_info.type == PTYPE_BOOL) {
406  val = !val;
407  } else {
408  if (x >= SETTING_BUTTON_WIDTH / 2) {
409  /* Increase button clicked */
410  if (val < par_info.max_value) val++;
411  this->clicked_increase = true;
412  } else {
413  /* Decrease button clicked */
414  if (val > par_info.min_value) val--;
415  this->clicked_increase = false;
416  }
417  }
418  if (val != old_val) {
419  par_info.SetValue(this->grf_config, val);
420 
421  this->clicked_button = num;
422  this->unclick_timeout.Reset();
423  }
424  } else if (par_info.type == PTYPE_UINT_ENUM && !par_info.complete_labels && click_count >= 2) {
425  /* Display a query box so users can enter a custom value. */
426  SetDParam(0, old_val);
427  ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE);
428  }
429  this->SetDirty();
430  break;
431  }
432 
433  case WID_NP_RESET:
434  if (!this->editable) break;
435  this->grf_config->SetParameterDefaults();
436  this->InvalidateData();
438  break;
439 
440  case WID_NP_ACCEPT:
441  this->Close();
442  break;
443  }
444  }
445 
446  void OnQueryTextFinished(std::optional<std::string> str) override
447  {
448  if (!str.has_value() || str->empty()) return;
449  int32_t value = atoi(str->c_str());
450  GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
451  uint32_t val = Clamp<uint32_t>(value, par_info.min_value, par_info.max_value);
452  par_info.SetValue(this->grf_config, val);
453  this->SetDirty();
454  }
455 
456  void OnDropdownSelect(WidgetID widget, int index) override
457  {
458  if (widget != WID_NP_SETTING_DROPDOWN) return;
459  assert(this->clicked_dropdown);
460  GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
461  par_info.SetValue(this->grf_config, index);
462  this->SetDirty();
463  }
464 
465  void OnDropdownClose(Point, WidgetID widget, int, bool) override
466  {
467  if (widget != WID_NP_SETTING_DROPDOWN) return;
468  /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
469  * the same dropdown button was clicked again, and then not open the dropdown again.
470  * So, we only remember that it was closed, and process it on the next OnPaint, which is
471  * after OnClick. */
472  assert(this->clicked_dropdown);
473  this->closing_dropdown = true;
474  this->SetDirty();
475  }
476 
477  void OnResize() override
478  {
479  this->vscroll->SetCapacityFromWidget(this, WID_NP_BACKGROUND);
480  }
481 
487  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
488  {
489  if (!gui_scope) return;
490  if (!this->action14present) {
491  this->SetWidgetDisabledState(WID_NP_NUMPAR_DEC, !this->editable || this->grf_config->num_params == 0);
492  this->SetWidgetDisabledState(WID_NP_NUMPAR_INC, !this->editable || this->grf_config->num_params >= this->grf_config->num_valid_params);
493  }
494 
495  this->vscroll->SetCount(this->action14present ? this->grf_config->num_valid_params : this->grf_config->num_params);
496  if (this->clicked_row != INT32_MAX && this->clicked_row >= this->vscroll->GetCount()) {
497  this->clicked_row = INT32_MAX;
499  }
500  }
501 
503  TimeoutTimer<TimerWindow> unclick_timeout = {std::chrono::milliseconds(150), [this]() {
504  this->clicked_button = INT32_MAX;
505  this->SetDirty();
506  }};
507 };
509 
510 
511 static constexpr NWidgetPart _nested_newgrf_parameter_widgets[] = {
513  NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
514  NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_NP_CAPTION),
515  NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
516  EndContainer(),
517  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_NUMPAR),
518  NWidget(WWT_PANEL, COLOUR_MAUVE), SetResize(1, 0), SetFill(1, 0), SetPIP(4, 0, 4),
519  NWidget(NWID_HORIZONTAL), SetPIP(4, 0, 4),
520  NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_NP_NUMPAR_DEC), SetMinimalSize(12, 12), SetDataTip(AWV_DECREASE, STR_NULL),
521  NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_NP_NUMPAR_INC), SetMinimalSize(12, 12), SetDataTip(AWV_INCREASE, STR_NULL),
522  NWidget(WWT_TEXT, COLOUR_MAUVE, WID_NP_NUMPAR), SetResize(1, 0), SetFill(1, 0), SetPadding(0, 0, 0, 4), SetDataTip(STR_NEWGRF_PARAMETERS_NUM_PARAM, STR_NULL),
523  EndContainer(),
524  EndContainer(),
525  EndContainer(),
527  NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_NP_BACKGROUND), SetMinimalSize(188, 182), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_NP_SCROLLBAR),
528  NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NP_SCROLLBAR),
529  EndContainer(),
531  NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NP_DESCRIPTION), SetResize(1, 0), SetFill(1, 0),
532  EndContainer(),
533  EndContainer(),
536  NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_CLOSE, STR_NULL),
537  NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_RESET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_RESET, STR_NEWGRF_PARAMETERS_RESET_TOOLTIP),
538  EndContainer(),
539  NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
540  EndContainer(),
541 };
542 
545  WDP_CENTER, "settings_newgrf_config", 500, 208,
547  0,
548  _nested_newgrf_parameter_widgets
549 );
550 
551 void OpenGRFParameterWindow(bool is_baseset, GRFConfig *c, bool editable)
552 {
554  new NewGRFParametersWindow(_newgrf_parameters_desc, is_baseset, c, editable);
555 }
556 
560 
562  {
563  this->ConstructWindow();
564 
565  auto textfile = this->grf_config->GetTextfile(file_type);
566  this->LoadTextfile(textfile.value(), NEWGRF_DIR);
567  }
568 
569  void SetStringParameters(WidgetID widget) const override
570  {
571  if (widget == WID_TF_CAPTION) {
572  SetDParam(0, STR_CONTENT_TYPE_NEWGRF);
573  SetDParamStr(1, this->grf_config->GetName());
574  }
575  }
576 };
577 
578 void ShowNewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c)
579 {
580  CloseWindowById(WC_TEXTFILE, file_type);
581  new NewGRFTextfileWindow(file_type, c);
582 }
583 
584 typedef std::map<uint32_t, const GRFConfig *> GrfIdMap;
585 
591 static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map)
592 {
593  while (c != nullptr) {
594  grfid_map->emplace(c->ident.grfid, c);
595  c = c->next;
596  }
597 }
598 
599 static void NewGRFConfirmationCallback(Window *w, bool confirmed);
600 static void ShowSavePresetWindow(const char *initial_text);
601 
607 
608  static const uint EDITBOX_MAX_SIZE = 50;
609 
612  static const std::initializer_list<GUIGRFConfigList::SortFunction * const> sorter_funcs;
613  static const std::initializer_list<GUIGRFConfigList::FilterFunction * const> filter_funcs;
614 
617  int avail_pos;
620 
622 
625 
627  bool editable;
628  bool show_params;
629  bool execute;
630  int preset;
632  bool modified;
633 
634  Scrollbar *vscroll;
635  Scrollbar *vscroll2;
636 
637  NewGRFWindow(WindowDesc &desc, bool editable, bool show_params, bool execute, GRFConfig **orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE)
638  {
639  this->avail_sel = nullptr;
640  this->avail_pos = -1;
641  this->active_sel = nullptr;
642  this->actives = nullptr;
643  this->orig_list = orig_list;
644  this->editable = editable;
645  this->execute = execute;
646  this->show_params = show_params;
647  this->preset = -1;
648  this->active_over = -1;
649 
650  CopyGRFConfigList(&this->actives, *orig_list, false);
651  this->grf_presets = GetGRFPresetList();
652 
653  this->CreateNestedTree();
654  this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR);
655  this->vscroll2 = this->GetScrollbar(WID_NS_SCROLL2BAR);
656 
657  this->GetWidget<NWidgetStacked>(WID_NS_SHOW_REMOVE)->SetDisplayedPlane(this->editable ? 0 : 1);
658  this->GetWidget<NWidgetStacked>(WID_NS_SHOW_APPLY)->SetDisplayedPlane(this->editable ? 0 : this->show_params ? 1 : SZSP_HORIZONTAL);
660 
661  this->querystrings[WID_NS_FILTER] = &this->filter_editbox;
662  this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
663  if (editable) {
665  } else {
667  }
668 
669  this->avails.SetListing(this->last_sorting);
670  this->avails.SetFiltering(this->last_filtering);
671  this->avails.SetSortFuncs(this->sorter_funcs);
672  this->avails.SetFilterFuncs(this->filter_funcs);
673  this->avails.ForceRebuild();
674 
676  }
677 
678  void Close([[maybe_unused]] int data = 0) override
679  {
683 
684  if (this->editable && this->modified && !this->execute && !_exit_game) {
685  CopyGRFConfigList(this->orig_list, this->actives, true);
686  ResetGRFConfig(false);
688  }
689 
690  this->Window::Close();
691  }
692 
693  ~NewGRFWindow()
694  {
695  /* Remove the temporary copy of grf-list used in window */
696  ClearGRFConfigList(&this->actives);
697  }
698 
704  {
705  GrfIdMap grfid_map;
706  FillGrfidMap(this->actives, &grfid_map);
707 
708  for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) {
709  GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid);
710  if (iter != grfid_map.end() && a->version > iter->second->version) return true;
711  }
712  return false;
713  }
714 
717  {
718  GrfIdMap grfid_map;
719  FillGrfidMap(this->actives, &grfid_map);
720 
721  for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) {
722  GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid);
723  if (iter == grfid_map.end() || iter->second->version >= a->version) continue;
724 
725  GRFConfig **c = &this->actives;
726  while (*c != iter->second) c = &(*c)->next;
727  GRFConfig *d = new GRFConfig(*a);
728  d->next = (*c)->next;
729  if (d->IsCompatible((*c)->version)) {
730  d->CopyParams(**c);
731  } else {
733  }
734  if (this->active_sel == *c) {
737  this->active_sel = nullptr;
738  }
739  delete *c;
740  *c = d;
741  iter->second = d;
742  }
743  }
744 
745  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
746  {
747  switch (widget) {
748  case WID_NS_FILE_LIST:
749  {
750  Dimension d = maxdim(GetScaledSpriteSize(SPR_SQUARE), GetScaledSpriteSize(SPR_WARNING_SIGN));
751  resize.height = std::max<uint>(d.height + 2U, GetCharacterHeight(FS_NORMAL));
752  size.height = std::max(size.height, padding.height + 6 * resize.height);
753  break;
754  }
755 
756  case WID_NS_AVAIL_LIST:
757  {
758  Dimension d = maxdim(GetScaledSpriteSize(SPR_SQUARE), GetScaledSpriteSize(SPR_WARNING_SIGN));
759  resize.height = std::max<uint>(d.height + 2U, GetCharacterHeight(FS_NORMAL));
760  size.height = std::max(size.height, padding.height + 8 * resize.height);
761  break;
762  }
763 
765  Dimension dim = GetStringBoundingBox(STR_NEWGRF_SETTINGS_INFO_TITLE);
766  size.height = std::max(size.height, dim.height + WidgetDimensions::scaled.frametext.Vertical());
767  size.width = std::max(size.width, dim.width + WidgetDimensions::scaled.frametext.Horizontal());
768  break;
769  }
770 
771  case WID_NS_NEWGRF_INFO:
772  size.height = std::max<uint>(size.height, WidgetDimensions::scaled.framerect.Vertical() + 10 * GetCharacterHeight(FS_NORMAL));
773  break;
774 
775  case WID_NS_PRESET_LIST: {
776  Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM);
777  for (const auto &i : this->grf_presets) {
778  SetDParamStr(0, i);
779  d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING));
780  }
781  d.width += padding.width;
782  size = maxdim(d, size);
783  break;
784  }
785 
788  Dimension d = GetStringBoundingBox(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON);
789  size = maxdim(d, GetStringBoundingBox(STR_INTRO_ONLINE_CONTENT));
790  size.width += padding.width;
791  size.height += padding.height;
792  break;
793  }
794  }
795  }
796 
797  void OnResize() override
798  {
799  this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.Vertical());
800  this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.Vertical());
801  }
802 
803  void SetStringParameters(WidgetID widget) const override
804  {
805  switch (widget) {
806  case WID_NS_PRESET_LIST:
807  if (this->preset == -1) {
808  SetDParam(0, STR_NUM_CUSTOM);
809  } else {
810  SetDParam(0, STR_JUST_RAW_STRING);
811  SetDParamStr(1, this->grf_presets[this->preset]);
812  }
813  break;
814  }
815  }
816 
822  inline PaletteID GetPalette(const GRFConfig *c) const
823  {
824  PaletteID pal;
825 
826  /* Pick a colour */
827  switch (c->status) {
828  case GCS_NOT_FOUND:
829  case GCS_DISABLED:
830  pal = PALETTE_TO_RED;
831  break;
832  case GCS_ACTIVATED:
833  pal = PALETTE_TO_GREEN;
834  break;
835  default:
836  pal = PALETTE_TO_BLUE;
837  break;
838  }
839 
840  /* Do not show a "not-failure" colour when it actually failed to load */
841  if (pal != PALETTE_TO_RED) {
842  if (HasBit(c->flags, GCF_STATIC)) {
843  pal = PALETTE_TO_GREY;
844  } else if (HasBit(c->flags, GCF_COMPATIBLE)) {
845  pal = PALETTE_TO_ORANGE;
846  }
847  }
848 
849  return pal;
850  }
851 
852  void DrawWidget(const Rect &r, WidgetID widget) const override
853  {
854  switch (widget) {
855  case WID_NS_FILE_LIST: {
856  const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
857  GfxFillRect(br, PC_BLACK);
858 
859  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
860  uint step_height = this->GetWidget<NWidgetBase>(WID_NS_FILE_LIST)->resize_y;
861  Dimension square = GetSpriteSize(SPR_SQUARE);
862  Dimension warning = GetSpriteSize(SPR_WARNING_SIGN);
863  int square_offset_y = (step_height - square.height) / 2;
864  int warning_offset_y = (step_height - warning.height) / 2;
865  int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
866 
867  bool rtl = _current_text_dir == TD_RTL;
868  uint text_left = rtl ? tr.left : tr.left + square.width + 13;
869  uint text_right = rtl ? tr.right - square.width - 13 : tr.right;
870  uint square_left = rtl ? tr.right - square.width - 3 : tr.left + 3;
871  uint warning_left = rtl ? tr.right - square.width - warning.width - 8 : tr.left + square.width + 8;
872 
873  int i = 0;
874  for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {
875  if (this->vscroll->IsVisible(i)) {
876  const char *text = c->GetName();
877  bool h = (this->active_sel == c);
878  PaletteID pal = this->GetPalette(c);
879 
880  if (h) {
881  GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
882  } else if (i == this->active_over) {
883  /* Get index of current selection. */
884  int active_sel_pos = 0;
885  for (GRFConfig *c = this->actives; c != nullptr && c != this->active_sel; c = c->next, active_sel_pos++) {}
886  if (active_sel_pos != this->active_over) {
887  uint top = this->active_over < active_sel_pos ? tr.top + 1 : tr.top + step_height - 2;
888  GfxFillRect(tr.left, top - 1, tr.right, top + 1, PC_GREY);
889  }
890  }
891  DrawSprite(SPR_SQUARE, pal, square_left, tr.top + square_offset_y);
892  if (c->error.has_value()) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, tr.top + warning_offset_y);
893  uint txtoffset = !c->error.has_value() ? 0 : warning.width;
894  DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), tr.top + offset_y, text, h ? TC_WHITE : TC_ORANGE);
895  tr.top += step_height;
896  }
897  }
898  if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry.
899  GfxFillRect(tr.left, tr.top, tr.right, tr.top + 2, PC_GREY);
900  }
901  break;
902  }
903 
904  case WID_NS_AVAIL_LIST: {
905  const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
906  GfxFillRect(br, this->active_over == -2 ? PC_DARK_GREY : PC_BLACK);
907 
908  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
909  uint step_height = this->GetWidget<NWidgetBase>(WID_NS_AVAIL_LIST)->resize_y;
910  int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
911 
912  auto [first, last] = this->vscroll2->GetVisibleRangeIterators(this->avails);
913  for (auto it = first; it != last; ++it) {
914  const GRFConfig *c = *it;
915  bool h = (c == this->avail_sel);
916  const char *text = c->GetName();
917 
918  if (h) GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
919  DrawString(tr.left, tr.right, tr.top + offset_y, text, h ? TC_WHITE : TC_SILVER);
920  tr.top += step_height;
921  }
922  break;
923  }
924 
926  /* Create the nice grayish rectangle at the details top. */
928  DrawString(r.left, r.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
929  break;
930  }
931 
932  case WID_NS_NEWGRF_INFO: {
933  const GRFConfig *selected = this->active_sel;
934  if (selected == nullptr) selected = this->avail_sel;
935  if (selected != nullptr) {
936  ShowNewGRFInfo(selected, r, this->show_params);
937  }
938  break;
939  }
940  }
941  }
942 
943  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
944  {
945  if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_CONTENT_END) {
946  if (this->active_sel == nullptr && this->avail_sel == nullptr) return;
947 
948  ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != nullptr ? this->active_sel : this->avail_sel);
949  return;
950  }
951 
952  switch (widget) {
953  case WID_NS_PRESET_LIST: {
954  DropDownList list;
955 
956  /* Add 'None' option for clearing list */
957  list.push_back(MakeDropDownListStringItem(STR_NONE, -1));
958 
959  for (uint i = 0; i < this->grf_presets.size(); i++) {
960  list.push_back(MakeDropDownListStringItem(this->grf_presets[i], i));
961  }
962 
963  this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
964  ShowDropDownList(this, std::move(list), this->preset, WID_NS_PRESET_LIST);
965  break;
966  }
967 
968  case WID_NS_OPEN_URL: {
969  const GRFConfig *c = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel;
970 
971  OpenBrowser(c->GetURL());
972  break;
973  }
974 
975  case WID_NS_PRESET_SAVE:
976  ShowSavePresetWindow((this->preset == -1) ? nullptr : this->grf_presets[this->preset].c_str());
977  break;
978 
980  if (this->preset == -1) return;
981 
982  DeleteGRFPresetFromConfig(this->grf_presets[this->preset].c_str());
983  this->grf_presets = GetGRFPresetList();
984  this->preset = -1;
985  this->InvalidateData();
986  this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
987  break;
988 
989  case WID_NS_MOVE_UP: { // Move GRF up
990  if (this->active_sel == nullptr || !this->editable) break;
991 
992  int pos = 0;
993  for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) {
994  GRFConfig *c = *pc;
995  if (c->next == this->active_sel) {
996  c->next = this->active_sel->next;
997  this->active_sel->next = c;
998  *pc = this->active_sel;
999  break;
1000  }
1001  }
1002  this->vscroll->ScrollTowards(pos);
1003  this->preset = -1;
1005  break;
1006  }
1007 
1008  case WID_NS_MOVE_DOWN: { // Move GRF down
1009  if (this->active_sel == nullptr || !this->editable) break;
1010 
1011  int pos = 1; // Start at 1 as we swap the selected newgrf with the next one
1012  for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) {
1013  GRFConfig *c = *pc;
1014  if (c == this->active_sel) {
1015  *pc = c->next;
1016  c->next = c->next->next;
1017  (*pc)->next = c;
1018  break;
1019  }
1020  }
1021  this->vscroll->ScrollTowards(pos);
1022  this->preset = -1;
1024  break;
1025  }
1026 
1027  case WID_NS_FILE_LIST: { // Select an active GRF.
1029 
1030  uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top);
1031 
1032  GRFConfig *c;
1033  for (c = this->actives; c != nullptr && i > 0; c = c->next, i--) {}
1034 
1035  if (this->active_sel != c) {
1038  }
1039  this->active_sel = c;
1040  this->avail_sel = nullptr;
1041  this->avail_pos = -1;
1042 
1043  this->InvalidateData();
1044  if (click_count == 1) {
1045  if (this->editable && this->active_sel != nullptr) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1046  break;
1047  }
1048  /* With double click, continue */
1049  [[fallthrough]];
1050  }
1051 
1052  case WID_NS_REMOVE: { // Remove GRF
1053  if (this->active_sel == nullptr || !this->editable) break;
1056 
1057  /* Choose the next GRF file to be the selected file. */
1058  GRFConfig *newsel = this->active_sel->next;
1059  for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next) {
1060  GRFConfig *c = *pc;
1061  /* If the new selection is empty (i.e. we're deleting the last item
1062  * in the list, pick the file just before the selected file */
1063  if (newsel == nullptr && c->next == this->active_sel) newsel = c;
1064 
1065  if (c == this->active_sel) {
1066  if (newsel == c) newsel = nullptr;
1067 
1068  *pc = c->next;
1069  delete c;
1070  break;
1071  }
1072  }
1073 
1074  this->active_sel = newsel;
1075  this->preset = -1;
1076  this->avail_pos = -1;
1077  this->avail_sel = nullptr;
1078  this->avails.ForceRebuild();
1080  break;
1081  }
1082 
1083  case WID_NS_UPGRADE: { // Upgrade GRF.
1084  if (!this->editable || this->actives == nullptr) break;
1085  UpgradeCurrent();
1087  break;
1088  }
1089 
1090  case WID_NS_AVAIL_LIST: { // Select a non-active GRF.
1092 
1093  auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.top);
1094  this->active_sel = nullptr;
1096  if (it != this->avails.end()) {
1097  if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE);
1098  this->avail_sel = *it;
1099  this->avail_pos = it - this->avails.begin();
1100  }
1101  this->InvalidateData();
1102  if (click_count == 1) {
1103  if (this->editable && this->avail_sel != nullptr && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1104  break;
1105  }
1106  /* With double click, continue */
1107  [[fallthrough]];
1108  }
1109 
1110  case WID_NS_ADD:
1111  if (this->avail_sel == nullptr || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break;
1112 
1113  this->AddGRFToActive();
1114  break;
1115 
1116  case WID_NS_APPLY_CHANGES: // Apply changes made to GRF list
1117  if (!this->editable) break;
1118  if (this->execute) {
1119  ShowQuery(
1120  STR_NEWGRF_POPUP_CAUTION_CAPTION,
1121  STR_NEWGRF_CONFIRMATION_TEXT,
1122  this,
1124  );
1125  } else {
1126  CopyGRFConfigList(this->orig_list, this->actives, true);
1127  ResetGRFConfig(false);
1128  ReloadNewGRFData();
1130  }
1131  this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1132  break;
1133 
1135  case WID_NS_SET_PARAMETERS: { // Edit parameters
1136  if (this->active_sel == nullptr || !this->show_params || this->active_sel->num_valid_params == 0) break;
1137 
1138  OpenGRFParameterWindow(false, this->active_sel, this->editable);
1140  break;
1141  }
1142 
1143  case WID_NS_TOGGLE_PALETTE:
1144  if (this->active_sel != nullptr && this->editable) {
1145  this->active_sel->palette ^= GRFP_USE_MASK;
1146  this->SetDirty();
1148  }
1149  break;
1150 
1153  if (!_network_available) {
1154  ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
1155  } else {
1156  this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1157 
1158  ShowMissingContentWindow(this->actives);
1159  }
1160  break;
1161 
1162  case WID_NS_RESCAN_FILES:
1163  case WID_NS_RESCAN_FILES2:
1164  RequestNewGRFScan(this);
1165  break;
1166  }
1167  }
1168 
1169  void OnNewGRFsScanned() override
1170  {
1171  if (this->active_sel == nullptr) CloseWindowByClass(WC_TEXTFILE);
1172  this->avail_sel = nullptr;
1173  this->avail_pos = -1;
1174  this->avails.ForceRebuild();
1175  this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1176  }
1177 
1178  void OnDropdownSelect(WidgetID widget, int index) override
1179  {
1180  if (widget != WID_NS_PRESET_LIST) return;
1181  if (!this->editable) return;
1182 
1183  ClearGRFConfigList(&this->actives);
1184  this->preset = index;
1185 
1186  if (index != -1) {
1187  this->actives = LoadGRFPresetFromConfig(this->grf_presets[index].c_str());
1188  }
1189  this->avails.ForceRebuild();
1190 
1194  this->active_sel = nullptr;
1196  }
1197 
1198  void OnQueryTextFinished(std::optional<std::string> str) override
1199  {
1200  if (!str.has_value()) return;
1201 
1202  SaveGRFPresetToConfig(str->c_str(), this->actives);
1203  this->grf_presets = GetGRFPresetList();
1204 
1205  /* Switch to this preset */
1206  for (uint i = 0; i < this->grf_presets.size(); i++) {
1207  if (this->grf_presets[i] == str) {
1208  this->preset = i;
1209  break;
1210  }
1211  }
1212 
1213  this->InvalidateData();
1214  }
1215 
1220  {
1221  /* Update scrollbars */
1222  int i = 0;
1223  for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {}
1224 
1225  this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling.
1226 
1227  if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos);
1228  }
1229 
1235  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1236  {
1237  if (!gui_scope) return;
1238  switch (data) {
1239  default:
1240  /* Nothing important to do */
1241  break;
1242 
1243  case GOID_NEWGRF_RESCANNED:
1244  /* Search the list for items that are now found and mark them as such. */
1245  for (GRFConfig **l = &this->actives; *l != nullptr; l = &(*l)->next) {
1246  GRFConfig *c = *l;
1247  bool compatible = HasBit(c->flags, GCF_COMPATIBLE);
1248  if (c->status != GCS_NOT_FOUND && !compatible) continue;
1249 
1250  const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum);
1251  if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue;
1252 
1253  *l = new GRFConfig(*f);
1254  (*l)->next = c->next;
1255 
1256  if (this->active_sel == c) this->active_sel = *l;
1257 
1258  delete c;
1259  }
1260 
1261  this->avails.ForceRebuild();
1262  [[fallthrough]];
1263 
1265  this->modified = false;
1266  UpdateScrollBars();
1267  break;
1268 
1270  this->preset = -1;
1271  [[fallthrough]];
1272 
1274  UpdateScrollBars();
1275 
1276  /* Changes have been made to the list of active NewGRFs */
1277  this->modified = true;
1278 
1279  break;
1280 
1282  /* No changes have been made to the list of active NewGRFs since the last time the changes got applied */
1283  this->modified = false;
1284  break;
1285  }
1286 
1287  this->BuildAvailables();
1288 
1289  this->SetWidgetDisabledState(WID_NS_APPLY_CHANGES, !((this->editable && this->modified) || _settings_client.gui.newgrf_developer_tools));
1290  this->SetWidgetsDisabledState(!this->editable,
1293  );
1294  this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == nullptr || HasBit(this->avail_sel->flags, GCF_INVALID));
1295  this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives == nullptr || !this->CanUpgradeCurrent());
1296 
1297  bool disable_all = this->active_sel == nullptr || !this->editable;
1298  this->SetWidgetsDisabledState(disable_all,
1299  WID_NS_REMOVE,
1302  );
1303 
1304  const GRFConfig *selected_config = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel;
1305  for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
1306  this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, selected_config == nullptr || !selected_config->GetTextfile(tft).has_value());
1307  }
1308  this->SetWidgetDisabledState(WID_NS_OPEN_URL, selected_config == nullptr || StrEmpty(selected_config->GetURL()));
1309 
1310  this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0);
1311  this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0);
1312  this->SetWidgetDisabledState(WID_NS_TOGGLE_PALETTE, disable_all ||
1314 
1315  if (!disable_all) {
1316  /* All widgets are now enabled, so disable widgets we can't use */
1317  if (this->active_sel == this->actives) this->DisableWidget(WID_NS_MOVE_UP);
1318  if (this->active_sel->next == nullptr) this->DisableWidget(WID_NS_MOVE_DOWN);
1319  }
1320 
1321  this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1);
1322 
1323  bool has_missing = false;
1324  bool has_compatible = false;
1325  for (const GRFConfig *c = this->actives; !has_missing && c != nullptr; c = c->next) {
1326  has_missing |= c->status == GCS_NOT_FOUND;
1327  has_compatible |= HasBit(c->flags, GCF_COMPATIBLE);
1328  }
1329  uint32_t widget_data;
1330  StringID tool_tip;
1331  if (has_missing || has_compatible) {
1332  widget_data = STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON;
1333  tool_tip = STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP;
1334  } else {
1335  widget_data = STR_INTRO_ONLINE_CONTENT;
1336  tool_tip = STR_INTRO_TOOLTIP_ONLINE_CONTENT;
1337  }
1338  this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->widget_data = widget_data;
1339  this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->tool_tip = tool_tip;
1340  this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->widget_data = widget_data;
1341  this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->tool_tip = tool_tip;
1342 
1343  this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing);
1344  }
1345 
1346  EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
1347  {
1348  if (!this->editable) return ES_NOT_HANDLED;
1349 
1350  if (this->vscroll2->UpdateListPositionOnKeyPress(this->avail_pos, keycode) == ES_NOT_HANDLED) return ES_NOT_HANDLED;
1351 
1352  if (this->avail_pos >= 0) {
1353  this->active_sel = nullptr;
1355  if (this->avail_sel != this->avails[this->avail_pos]) CloseWindowByClass(WC_TEXTFILE);
1356  this->avail_sel = this->avails[this->avail_pos];
1357  this->vscroll2->ScrollTowards(this->avail_pos);
1358  this->InvalidateData(0);
1359  }
1360 
1361  return ES_HANDLED;
1362  }
1363 
1364  void OnEditboxChanged(WidgetID widget) override
1365  {
1366  if (!this->editable) return;
1367 
1368  if (widget == WID_NS_FILTER) {
1369  string_filter.SetFilterTerm(this->filter_editbox.text.buf);
1370  this->avails.SetFilterState(!string_filter.IsEmpty());
1371  this->avails.ForceRebuild();
1372  this->InvalidateData(0);
1373  }
1374  }
1375 
1376  void OnDragDrop(Point pt, WidgetID widget) override
1377  {
1378  if (!this->editable) return;
1379 
1380  if (widget == WID_NS_FILE_LIST) {
1381  if (this->active_sel != nullptr) {
1382  /* Get pointer to the selected file in the active list. */
1383  int from_pos = 0;
1384  GRFConfig **from_prev;
1385  for (from_prev = &this->actives; *from_prev != this->active_sel; from_prev = &(*from_prev)->next, from_pos++) {}
1386 
1387  /* Gets the drag-and-drop destination offset. Ignore the last dummy line. */
1388  int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 2);
1389  if (to_pos != from_pos) { // Don't move NewGRF file over itself.
1390  /* Get pointer to destination position. */
1391  GRFConfig **to_prev = &this->actives;
1392  for (int i = from_pos < to_pos ? -1 : 0; *to_prev != nullptr && i < to_pos; to_prev = &(*to_prev)->next, i++) {}
1393 
1394  /* Detach NewGRF file from its original position. */
1395  *from_prev = this->active_sel->next;
1396 
1397  /* Attach NewGRF file to its new position. */
1398  this->active_sel->next = *to_prev;
1399  *to_prev = this->active_sel;
1400 
1401  this->vscroll->ScrollTowards(to_pos);
1402  this->preset = -1;
1403  this->InvalidateData();
1404  }
1405  } else if (this->avail_sel != nullptr) {
1406  int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 1);
1407  this->AddGRFToActive(to_pos);
1408  }
1409  } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) {
1410  /* Remove active NewGRF file by dragging it over available list. */
1411  Point dummy = {-1, -1};
1412  this->OnClick(dummy, WID_NS_REMOVE, 1);
1413  }
1414 
1416 
1417  if (this->active_over != -1) {
1418  /* End of drag-and-drop, hide dragged destination highlight. */
1419  this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
1420  this->active_over = -1;
1421  }
1422  }
1423 
1424  void OnMouseDrag(Point pt, WidgetID widget) override
1425  {
1426  if (!this->editable) return;
1427 
1428  if (widget == WID_NS_FILE_LIST && (this->active_sel != nullptr || this->avail_sel != nullptr)) {
1429  /* An NewGRF file is dragged over the active list. */
1430  int to_pos = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top);
1431  /* Skip the last dummy line if the source is from the active list. */
1432  to_pos = std::min(to_pos, this->vscroll->GetCount() - (this->active_sel != nullptr ? 2 : 1));
1433 
1434  if (to_pos != this->active_over) {
1435  this->active_over = to_pos;
1437  }
1438  } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) {
1439  this->active_over = -2;
1441  } else if (this->active_over != -1) {
1442  this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
1443  this->active_over = -1;
1444  }
1445  }
1446 
1447 private:
1449  static bool NameSorter(const GRFConfig * const &a, const GRFConfig * const &b)
1450  {
1451  int i = StrNaturalCompare(a->GetName(), b->GetName(), true); // Sort by name (natural sorting).
1452  if (i != 0) return i < 0;
1453 
1454  i = a->version - b->version;
1455  if (i != 0) return i < 0;
1456 
1457  return a->ident.md5sum < b->ident.md5sum;
1458  }
1459 
1461  static bool TagNameFilter(const GRFConfig * const *a, StringFilter &filter)
1462  {
1463  filter.ResetState();
1464  filter.AddLine((*a)->GetName());
1465  filter.AddLine((*a)->filename);
1466  filter.AddLine((*a)->GetDescription());
1467  return filter.GetState();;
1468  }
1469 
1470  void BuildAvailables()
1471  {
1472  if (!this->avails.NeedRebuild()) return;
1473 
1474  this->avails.clear();
1475 
1476  for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) {
1477  bool found = false;
1478  for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum);
1479  if (found) continue;
1480 
1482  this->avails.push_back(c);
1483  } else {
1485  /* Never triggers; FindGRFConfig returns either c, or a newer version of c. */
1486  assert(best != nullptr);
1487 
1488  /*
1489  * If the best version is 0, then all NewGRF with this GRF ID
1490  * have version 0, so for backward compatibility reasons we
1491  * want to show them all.
1492  * If we are the best version, then we definitely want to
1493  * show that NewGRF!.
1494  */
1495  if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) {
1496  this->avails.push_back(c);
1497  }
1498  }
1499  }
1500 
1501  this->avails.Filter(this->string_filter);
1502  this->avails.RebuildDone();
1503  this->avails.Sort();
1504 
1505  if (this->avail_sel != nullptr) {
1506  this->avail_pos = find_index(this->avails, this->avail_sel);
1507  if (this->avail_pos == -1) {
1508  this->avail_sel = nullptr;
1509  }
1510  }
1511 
1512  this->vscroll2->SetCount(this->avails.size()); // Update the scrollbar
1513  }
1514 
1520  bool AddGRFToActive(int ins_pos = -1)
1521  {
1522  if (this->avail_sel == nullptr || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) return false;
1523 
1525 
1526  uint count = 0;
1527  GRFConfig **entry = nullptr;
1528  GRFConfig **list;
1529  /* Find last entry in the list, checking for duplicate grfid on the way */
1530  for (list = &this->actives; *list != nullptr; list = &(*list)->next, ins_pos--) {
1531  if (ins_pos == 0) entry = list; // Insert position? Save.
1532  if ((*list)->ident.grfid == this->avail_sel->ident.grfid) {
1533  ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
1534  return false;
1535  }
1536  if (!HasBit((*list)->flags, GCF_STATIC)) count++;
1537  }
1538  if (entry == nullptr) entry = list;
1539  if (count >= NETWORK_MAX_GRF_COUNT) {
1540  ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO);
1541  return false;
1542  }
1543 
1544  GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list.
1545  c->SetParameterDefaults();
1546 
1547  /* Insert GRF config to configuration list. */
1548  c->next = *entry;
1549  *entry = c;
1550 
1551  /* Select next (or previous, if last one) item in the list. */
1552  int new_pos = this->avail_pos + 1;
1553  if (new_pos >= (int)this->avails.size()) new_pos = this->avail_pos - 1;
1554  this->avail_pos = new_pos;
1555  if (new_pos >= 0) this->avail_sel = this->avails[new_pos];
1556 
1557  this->avails.ForceRebuild();
1559  return true;
1560  }
1561 };
1562 
1568 {
1569  /* Only show the things in the current list, or everything when nothing's selected */
1570  ContentVector cv;
1571  for (const GRFConfig *c = list; c != nullptr; c = c->next) {
1572  if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue;
1573 
1574  ContentInfo *ci = new ContentInfo();
1575  ci->type = CONTENT_TYPE_NEWGRF;
1577  ci->name = c->GetName();
1578  ci->unique_id = BSWAP32(c->ident.grfid);
1580  cv.push_back(ci);
1581  }
1582  ShowNetworkContentListWindow(cv.empty() ? nullptr : &cv, CONTENT_TYPE_NEWGRF);
1583 }
1584 
1585 Listing NewGRFWindow::last_sorting = {false, 0};
1587 
1588 const std::initializer_list<NewGRFWindow::GUIGRFConfigList::SortFunction * const> NewGRFWindow::sorter_funcs = {
1589  &NameSorter,
1590 };
1591 
1592 const std::initializer_list<NewGRFWindow::GUIGRFConfigList::FilterFunction * const> NewGRFWindow::filter_funcs = {
1593  &TagNameFilter,
1594 };
1595 
1603 public:
1604  static const uint MAX_EXTRA_INFO_WIDTH;
1605  static const uint MIN_EXTRA_FOR_3_COLUMNS;
1606 
1607  std::unique_ptr<NWidgetBase> avs;
1608  std::unique_ptr<NWidgetBase> acs;
1609  std::unique_ptr<NWidgetBase> inf;
1610  bool editable;
1611 
1612  NWidgetNewGRFDisplay(std::unique_ptr<NWidgetBase> &&avs, std::unique_ptr<NWidgetBase> &&acs, std::unique_ptr<NWidgetBase> &&inf) : NWidgetBase(NWID_CUSTOM)
1613  , avs(std::move(avs))
1614  , acs(std::move(acs))
1615  , inf(std::move(inf))
1616  , editable(true) // Temporary setting, 'real' value is set in SetupSmallestSize().
1617  {
1618  }
1619 
1620  void SetupSmallestSize(Window *w) override
1621  {
1622  /* Copy state flag from the window. */
1623  assert(dynamic_cast<NewGRFWindow *>(w) != nullptr);
1624  NewGRFWindow *ngw = (NewGRFWindow *)w;
1625  this->editable = ngw->editable;
1626 
1627  this->avs->SetupSmallestSize(w);
1628  this->acs->SetupSmallestSize(w);
1629  this->inf->SetupSmallestSize(w);
1630 
1631  uint min_avs_width = this->avs->smallest_x + this->avs->padding.Horizontal();
1632  uint min_acs_width = this->acs->smallest_x + this->acs->padding.Horizontal();
1633  uint min_inf_width = this->inf->smallest_x + this->inf->padding.Horizontal();
1634 
1635  uint min_avs_height = this->avs->smallest_y + this->avs->padding.Vertical();
1636  uint min_acs_height = this->acs->smallest_y + this->acs->padding.Vertical();
1637  uint min_inf_height = this->inf->smallest_y + this->inf->padding.Vertical();
1638 
1639  /* Smallest window is in two column mode. */
1640  this->smallest_x = std::max(min_avs_width, min_acs_width) + WidgetDimensions::scaled.hsep_wide + min_inf_width;
1641  this->smallest_y = std::max(min_inf_height, min_acs_height + WidgetDimensions::scaled.vsep_wide + min_avs_height);
1642 
1643  /* Filling. */
1644  this->fill_x = std::lcm(this->avs->fill_x, this->acs->fill_x);
1645  if (this->inf->fill_x > 0 && (this->fill_x == 0 || this->fill_x > this->inf->fill_x)) this->fill_x = this->inf->fill_x;
1646 
1647  this->fill_y = this->avs->fill_y;
1648  if (this->acs->fill_y > 0 && (this->fill_y == 0 || this->fill_y > this->acs->fill_y)) this->fill_y = this->acs->fill_y;
1649  this->fill_y = std::lcm(this->fill_y, this->inf->fill_y);
1650 
1651  /* Resizing. */
1652  this->resize_x = std::lcm(this->avs->resize_x, this->acs->resize_x);
1653  if (this->inf->resize_x > 0 && (this->resize_x == 0 || this->resize_x > this->inf->resize_x)) this->resize_x = this->inf->resize_x;
1654 
1655  this->resize_y = this->avs->resize_y;
1656  if (this->acs->resize_y > 0 && (this->resize_y == 0 || this->resize_y > this->acs->resize_y)) this->resize_y = this->acs->resize_y;
1657  this->resize_y = std::lcm(this->resize_y, this->inf->resize_y);
1658 
1659  /* Make sure the height suits the 3 column (resp. not-editable) format; the 2 column format can easily fill space between the lists */
1660  this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y);
1661  }
1662 
1663  void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
1664  {
1665  this->StoreSizePosition(sizing, x, y, given_width, given_height);
1666 
1667  uint min_avs_width = this->avs->smallest_x + this->avs->padding.Horizontal();
1668  uint min_acs_width = this->acs->smallest_x + this->acs->padding.Horizontal();
1669  uint min_inf_width = this->inf->smallest_x + this->inf->padding.Horizontal();
1670 
1671  uint min_list_width = std::max(min_avs_width, min_acs_width); // Smallest width of the lists such that they have equal width (incl padding).
1672  uint avs_extra_width = min_list_width - min_avs_width; // Additional width needed for avs to reach min_list_width.
1673  uint acs_extra_width = min_list_width - min_acs_width; // Additional width needed for acs to reach min_list_width.
1674 
1675  /* Use 2 or 3 columns? */
1676  uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * WidgetDimensions::scaled.hsep_wide;
1677  uint min_two_columns = min_list_width + min_inf_width + WidgetDimensions::scaled.hsep_wide;
1678  bool use_three_columns = this->editable && (min_three_columns + ScaleGUITrad(MIN_EXTRA_FOR_3_COLUMNS) <= given_width);
1679 
1680  /* Info panel is a separate column in both modes. Compute its width first. */
1681  uint extra_width, inf_width;
1682  if (use_three_columns) {
1683  extra_width = given_width - min_three_columns;
1684  inf_width = std::min<uint>(ScaleGUITrad(MAX_EXTRA_INFO_WIDTH), extra_width / 2);
1685  } else {
1686  extra_width = given_width - min_two_columns;
1687  inf_width = std::min<uint>(ScaleGUITrad(MAX_EXTRA_INFO_WIDTH), extra_width / 2);
1688  }
1689  inf_width = ComputeMaxSize(this->inf->smallest_x, this->inf->smallest_x + inf_width, this->inf->GetHorizontalStepSize(sizing));
1690  extra_width -= inf_width - this->inf->smallest_x;
1691 
1692  uint inf_height = ComputeMaxSize(this->inf->smallest_y, given_height, this->inf->GetVerticalStepSize(sizing));
1693 
1694  if (use_three_columns) {
1695  /* Three column display, first make both lists equally wide, then divide whatever is left between both lists.
1696  * Only keep track of what avs gets, all other space goes to acs. */
1697  uint avs_width = std::min(avs_extra_width, extra_width);
1698  extra_width -= avs_width;
1699  extra_width -= std::min(acs_extra_width, extra_width);
1700  avs_width += extra_width / 2;
1701 
1702  avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_width, this->avs->GetHorizontalStepSize(sizing));
1703 
1704  uint acs_width = given_width - // Remaining space, including horizontal padding.
1705  inf_width - this->inf->padding.Horizontal() -
1706  avs_width - this->avs->padding.Horizontal() - 2 * WidgetDimensions::scaled.hsep_wide;
1707  acs_width = ComputeMaxSize(min_acs_width, acs_width, this->acs->GetHorizontalStepSize(sizing)) -
1708  this->acs->padding.Horizontal();
1709 
1710  /* Never use fill_y on these; the minimal size is chosen, so that the 3 column view looks nice */
1711  uint avs_height = ComputeMaxSize(this->avs->smallest_y, given_height, this->avs->resize_y);
1712  uint acs_height = ComputeMaxSize(this->acs->smallest_y, given_height, this->acs->resize_y);
1713 
1714  /* Assign size and position to the children. */
1715  if (rtl) {
1716  x += this->inf->padding.left;
1717  this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1718  x += inf_width + this->inf->padding.right + WidgetDimensions::scaled.hsep_wide;
1719  } else {
1720  x += this->avs->padding.left;
1721  this->avs->AssignSizePosition(sizing, x, y + this->avs->padding.top, avs_width, avs_height, rtl);
1722  x += avs_width + this->avs->padding.right + WidgetDimensions::scaled.hsep_wide;
1723  }
1724 
1725  x += this->acs->padding.left;
1726  this->acs->AssignSizePosition(sizing, x, y + this->acs->padding.top, acs_width, acs_height, rtl);
1727  x += acs_width + this->acs->padding.right + WidgetDimensions::scaled.hsep_wide;
1728 
1729  if (rtl) {
1730  x += this->avs->padding.left;
1731  this->avs->AssignSizePosition(sizing, x, y + this->avs->padding.top, avs_width, avs_height, rtl);
1732  } else {
1733  x += this->inf->padding.left;
1734  this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1735  }
1736  } else {
1737  /* Two columns, all space in extra_width goes to both lists. Since the lists are underneath each other,
1738  * the column is min_list_width wide at least. */
1739  uint avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_extra_width + extra_width,
1740  this->avs->GetHorizontalStepSize(sizing));
1741  uint acs_width = ComputeMaxSize(this->acs->smallest_x, this->acs->smallest_x + acs_extra_width + extra_width,
1742  this->acs->GetHorizontalStepSize(sizing));
1743 
1744  uint min_avs_height = (!this->editable) ? 0 : this->avs->smallest_y + this->avs->padding.Vertical() + WidgetDimensions::scaled.vsep_wide;
1745  uint min_acs_height = this->acs->smallest_y + this->acs->padding.Vertical();
1746  uint extra_height = given_height - min_acs_height - min_avs_height;
1747 
1748  /* Never use fill_y on these; instead use WidgetDimensions::scaled.vsep_wide as filler */
1749  uint avs_height = ComputeMaxSize(this->avs->smallest_y, this->avs->smallest_y + extra_height / 2, this->avs->resize_y);
1750  if (this->editable) extra_height -= avs_height - this->avs->smallest_y;
1751  uint acs_height = ComputeMaxSize(this->acs->smallest_y, this->acs->smallest_y + extra_height, this->acs->resize_y);
1752 
1753  /* Assign size and position to the children. */
1754  if (rtl) {
1755  x += this->inf->padding.left;
1756  this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1757  x += inf_width + this->inf->padding.right + WidgetDimensions::scaled.hsep_wide;
1758 
1759  this->acs->AssignSizePosition(sizing, x + this->acs->padding.left, y + this->acs->padding.top, acs_width, acs_height, rtl);
1760  if (this->editable) {
1761  this->avs->AssignSizePosition(sizing, x + this->avs->padding.left, y + given_height - avs_height - this->avs->padding.bottom, avs_width, avs_height, rtl);
1762  } else {
1763  this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
1764  }
1765  } else {
1766  this->acs->AssignSizePosition(sizing, x + this->acs->padding.left, y + this->acs->padding.top, acs_width, acs_height, rtl);
1767  if (this->editable) {
1768  this->avs->AssignSizePosition(sizing, x + this->avs->padding.left, y + given_height - avs_height - this->avs->padding.bottom, avs_width, avs_height, rtl);
1769  } else {
1770  this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
1771  }
1772  uint dx = this->acs->current_x + this->acs->padding.Horizontal();
1773  if (this->editable) {
1774  dx = std::max(dx, this->avs->current_x + this->avs->padding.Horizontal());
1775  }
1776  x += dx + WidgetDimensions::scaled.hsep_wide + this->inf->padding.left;
1777  this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1778  }
1779  }
1780  }
1781 
1782  void FillWidgetLookup(WidgetLookup &widget_lookup) override
1783  {
1784  this->avs->FillWidgetLookup(widget_lookup);
1785  this->acs->FillWidgetLookup(widget_lookup);
1786  this->inf->FillWidgetLookup(widget_lookup);
1787  }
1788 
1789  NWidgetCore *GetWidgetFromPos(int x, int y) override
1790  {
1791  if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
1792 
1793  NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : nullptr;
1794  if (nw == nullptr) nw = this->acs->GetWidgetFromPos(x, y);
1795  if (nw == nullptr) nw = this->inf->GetWidgetFromPos(x, y);
1796  return nw;
1797  }
1798 
1799  void Draw(const Window *w) override
1800  {
1801  if (this->editable) this->avs->Draw(w);
1802  this->acs->Draw(w);
1803  this->inf->Draw(w);
1804  }
1805 };
1806 
1809 
1810 static constexpr NWidgetPart _nested_newgrf_actives_widgets[] = {
1812  /* Left side, presets. */
1815  NWidget(WWT_TEXT, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_SELECT_PRESET, STR_NULL),
1816  SetPadding(0, WidgetDimensions::unscaled.hsep_wide, 0, 0),
1817  NWidget(WWT_DROPDOWN, COLOUR_YELLOW, WID_NS_PRESET_LIST), SetFill(1, 0), SetResize(1, 0),
1818  SetDataTip(STR_JUST_STRING1, STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP),
1819  EndContainer(),
1821  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_SAVE), SetFill(1, 0), SetResize(1, 0),
1822  SetDataTip(STR_NEWGRF_SETTINGS_PRESET_SAVE, STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP),
1823  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_DELETE), SetFill(1, 0), SetResize(1, 0),
1824  SetDataTip(STR_NEWGRF_SETTINGS_PRESET_DELETE, STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP),
1825  EndContainer(),
1826  EndContainer(),
1827 
1828  NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_ACTIVE_LIST, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1829  /* Left side, active grfs. */
1831  NWidget(WWT_PANEL, COLOUR_MAUVE),
1832  NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_FILE_LIST), SetMinimalSize(100, 1), SetPadding(2),
1833  SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLLBAR), SetDataTip(STR_NULL, STR_NEWGRF_SETTINGS_FILE_TOOLTIP),
1834  EndContainer(),
1835  EndContainer(),
1836  NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLLBAR),
1837  EndContainer(),
1838 
1839  /* Buttons. */
1840  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_REMOVE),
1842  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_REMOVE), SetFill(1, 0), SetResize(1, 0),
1843  SetDataTip(STR_NEWGRF_SETTINGS_REMOVE, STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP),
1845  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_UP), SetFill(1, 0), SetResize(1, 0),
1846  SetDataTip(STR_NEWGRF_SETTINGS_MOVEUP, STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP),
1847  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_DOWN), SetFill(1, 0), SetResize(1, 0),
1848  SetDataTip(STR_NEWGRF_SETTINGS_MOVEDOWN, STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP),
1849  EndContainer(),
1850  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_UPGRADE), SetFill(1, 0), SetResize(1, 0),
1851  SetDataTip(STR_NEWGRF_SETTINGS_UPGRADE, STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP),
1852  EndContainer(),
1853 
1855  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES2), SetFill(1, 0), SetResize(1, 0),
1856  SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
1857  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD2), SetFill(1, 0), SetResize(1, 0),
1858  SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
1859  EndContainer(),
1860  EndContainer(),
1861  EndContainer(),
1862  EndContainer(),
1863 };
1864 
1865 static constexpr NWidgetPart _nested_newgrf_availables_widgets[] = {
1866  NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_INACTIVE_LIST, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1867  /* Left side, available grfs, filter edit box. */
1869  NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_NEWGRF_FILTER_TITLE, STR_NULL),
1870  NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_NS_FILTER), SetFill(1, 0), SetResize(1, 0),
1871  SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
1872  EndContainer(),
1873 
1874  /* Left side, available grfs. */
1876  NWidget(WWT_PANEL, COLOUR_MAUVE),
1877  NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_AVAIL_LIST), SetMinimalSize(100, 1), SetPadding(2),
1879  EndContainer(),
1880  EndContainer(),
1881  NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLL2BAR),
1882  EndContainer(),
1883 
1884  /* Left side, available grfs, buttons. */
1886  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_ADD), SetFill(1, 0), SetResize(1, 0),
1887  SetDataTip(STR_NEWGRF_SETTINGS_ADD, STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP),
1889  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES), SetFill(1, 0), SetResize(1, 0),
1890  SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
1891  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD), SetFill(1, 0), SetResize(1, 0),
1892  SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
1893  EndContainer(),
1894  EndContainer(),
1895  EndContainer(),
1896 };
1897 
1898 static constexpr NWidgetPart _nested_newgrf_infopanel_widgets[] = {
1900  /* Right side, info panel. */
1901  NWidget(WWT_PANEL, COLOUR_MAUVE),
1902  NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0),
1903  NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(150, 100),
1904  EndContainer(),
1905 
1906  /* Right side, info buttons. */
1909  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_OPEN_URL), SetFill(1, 0), SetResize(1, 0),
1910  SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1911  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0),
1912  SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1913  EndContainer(),
1916  SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1917  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0),
1918  SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1919  EndContainer(),
1920  EndContainer(),
1921 
1922  /* Right side, config buttons. */
1923  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_APPLY),
1926  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
1927  SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL),
1928  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0),
1929  SetDataTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP),
1930  EndContainer(),
1931  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0),
1932  SetDataTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES, STR_NULL),
1933  EndContainer(),
1934  NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_VIEW_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
1935  SetDataTip(STR_NEWGRF_SETTINGS_SHOW_PARAMETERS, STR_NULL),
1936  EndContainer(),
1937  EndContainer(),
1938 };
1939 
1941 std::unique_ptr<NWidgetBase> NewGRFDisplay()
1942 {
1943  std::unique_ptr<NWidgetBase> avs = MakeNWidgets(_nested_newgrf_availables_widgets, nullptr);
1944  std::unique_ptr<NWidgetBase> acs = MakeNWidgets(_nested_newgrf_actives_widgets, nullptr);
1945  std::unique_ptr<NWidgetBase> inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, nullptr);
1946 
1947  return std::make_unique<NWidgetNewGRFDisplay>(std::move(avs), std::move(acs), std::move(inf));
1948 }
1949 
1950 /* Widget definition of the manage newgrfs window */
1951 static constexpr NWidgetPart _nested_newgrf_widgets[] = {
1953  NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
1954  NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1955  NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
1956  EndContainer(),
1957  NWidget(WWT_PANEL, COLOUR_MAUVE),
1959  /* Resize button. */
1961  NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1962  NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), SetDataTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1963  EndContainer(),
1964  EndContainer(),
1965 };
1966 
1967 /* Window definition of the manage newgrfs window */
1968 static WindowDesc _newgrf_desc(
1969  WDP_CENTER, "settings_newgrf", 300, 263,
1971  0,
1972  _nested_newgrf_widgets
1973 );
1974 
1980 static void NewGRFConfirmationCallback(Window *w, bool confirmed)
1981 {
1982  if (confirmed) {
1985  NewGRFWindow *nw = dynamic_cast<NewGRFWindow*>(w);
1986 
1988  _gamelog.GRFUpdate(_grfconfig, nw->actives); // log GRF changes
1989  CopyGRFConfigList(nw->orig_list, nw->actives, false);
1990  ReloadNewGRFData();
1991  _gamelog.StopAction();
1992 
1993  /* Show new, updated list */
1994  GRFConfig *c;
1995  int i = 0;
1996  for (c = nw->actives; c != nullptr && c != nw->active_sel; c = c->next, i++) {}
1997  CopyGRFConfigList(&nw->actives, *nw->orig_list, false);
1998  for (c = nw->actives; c != nullptr && i > 0; c = c->next, i--) {}
1999  nw->active_sel = c;
2000  nw->avails.ForceRebuild();
2001  nw->modified = false;
2002 
2003  w->InvalidateData();
2004 
2005  ReInitAllWindows(false);
2007  }
2008 }
2009 
2010 
2011 
2020 void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
2021 {
2023  new NewGRFWindow(_newgrf_desc, editable, show_params, exec_changes, config);
2024 }
2025 
2029  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2030  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_SAVE_PRESET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2031  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
2032  EndContainer(),
2033  NWidget(WWT_PANEL, COLOUR_GREY),
2035  NWidget(WWT_INSET, COLOUR_GREY, WID_SVP_PRESET_LIST), SetPadding(2, 1, 2, 2),
2036  SetDataTip(0x0, STR_SAVE_PRESET_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SVP_SCROLLBAR), EndContainer(),
2037  NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SVP_SCROLLBAR),
2038  EndContainer(),
2039  EndContainer(),
2040  NWidget(WWT_PANEL, COLOUR_GREY),
2041  NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SVP_EDITBOX), SetPadding(2, 2, 2, 2), SetFill(1, 0), SetResize(1, 0),
2042  SetDataTip(STR_SAVE_PRESET_TITLE, STR_SAVE_PRESET_EDITBOX_TOOLTIP),
2043  EndContainer(),
2045  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_CANCEL), SetDataTip(STR_SAVE_PRESET_CANCEL, STR_SAVE_PRESET_CANCEL_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2046  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_SAVE), SetDataTip(STR_SAVE_PRESET_SAVE, STR_SAVE_PRESET_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2047  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
2048  EndContainer(),
2049 };
2050 
2053  WDP_CENTER, "save_preset", 140, 110,
2055  WDF_MODAL,
2057 );
2058 
2060 struct SavePresetWindow : public Window {
2064  int selected;
2065 
2071  {
2072  this->presets = GetGRFPresetList();
2073  this->selected = -1;
2074  if (initial_text != nullptr) {
2075  for (uint i = 0; i < this->presets.size(); i++) {
2076  if (this->presets[i] == initial_text) {
2077  this->selected = i;
2078  break;
2079  }
2080  }
2081  }
2082 
2084  this->presetname_editbox.ok_button = WID_SVP_SAVE;
2085  this->presetname_editbox.cancel_button = WID_SVP_CANCEL;
2086 
2087  this->CreateNestedTree();
2088  this->vscroll = this->GetScrollbar(WID_SVP_SCROLLBAR);
2089  this->FinishInitNested(0);
2090 
2091  this->vscroll->SetCount(this->presets.size());
2093  if (initial_text != nullptr) this->presetname_editbox.text.Assign(initial_text);
2094  }
2095 
2096  ~SavePresetWindow()
2097  {
2098  }
2099 
2100  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2101  {
2102  switch (widget) {
2103  case WID_SVP_PRESET_LIST: {
2105  size.height = 0;
2106  for (uint i = 0; i < this->presets.size(); i++) {
2107  Dimension d = GetStringBoundingBox(this->presets[i]);
2108  size.width = std::max(size.width, d.width + padding.width);
2109  resize.height = std::max(resize.height, d.height);
2110  }
2111  size.height = ClampU((uint)this->presets.size(), 5, 20) * resize.height + padding.height;
2112  break;
2113  }
2114  }
2115  }
2116 
2117  void DrawWidget(const Rect &r, WidgetID widget) const override
2118  {
2119  switch (widget) {
2120  case WID_SVP_PRESET_LIST: {
2121  const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
2122  GfxFillRect(br, PC_BLACK);
2123 
2124  uint step_height = this->GetWidget<NWidgetBase>(WID_SVP_PRESET_LIST)->resize_y;
2125  int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
2126  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2127 
2128  auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->presets);
2129  for (auto it = first; it != last; ++it) {
2130  int row = static_cast<int>(std::distance(std::begin(this->presets), it));
2131  if (row == this->selected) GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
2132 
2133  DrawString(tr.left, tr.right, tr.top + offset_y, *it, (row == this->selected) ? TC_WHITE : TC_SILVER);
2134  tr.top += step_height;
2135  }
2136  break;
2137  }
2138  }
2139  }
2140 
2141  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2142  {
2143  switch (widget) {
2144  case WID_SVP_PRESET_LIST: {
2145  auto it = this->vscroll->GetScrolledItemFromWidget(this->presets, pt.y, this, WID_SVP_PRESET_LIST);
2146  if (it != this->presets.end()) {
2147  this->selected = it - this->presets.begin();
2148  this->presetname_editbox.text.Assign(*it);
2151  }
2152  break;
2153  }
2154 
2155  case WID_SVP_CANCEL:
2156  this->Close();
2157  break;
2158 
2159  case WID_SVP_SAVE: {
2161  if (w != nullptr && !StrEmpty(this->presetname_editbox.text.buf)) w->OnQueryTextFinished(this->presetname_editbox.text.buf);
2162  this->Close();
2163  break;
2164  }
2165  }
2166  }
2167 
2168  void OnResize() override
2169  {
2170  this->vscroll->SetCapacityFromWidget(this, WID_SVP_PRESET_LIST, WidgetDimensions::scaled.framerect.Vertical());
2171  }
2172 };
2173 
2178 static void ShowSavePresetWindow(const char *initial_text)
2179 {
2181  new SavePresetWindow(initial_text);
2182 }
2183 
2186  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NEWGRF_SCAN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2187  NWidget(WWT_PANEL, COLOUR_GREY),
2189  NWidget(WWT_LABEL, INVALID_COLOUR), SetDataTip(STR_NEWGRF_SCAN_MESSAGE, STR_NULL), SetFill(1, 0),
2190  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_BAR), SetFill(1, 0),
2191  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(400, 0),
2192  EndContainer(),
2193  EndContainer(),
2194 };
2195 
2198  WDP_CENTER, nullptr, 0, 0,
2200  0,
2202 );
2203 
2205 struct ScanProgressWindow : public Window {
2206  std::string last_name;
2207  int scanned;
2208 
2211  {
2212  this->InitNested(1);
2213  }
2214 
2215  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2216  {
2217  switch (widget) {
2218  case WID_SP_PROGRESS_BAR: {
2219  SetDParamMaxValue(0, 100);
2220  size = GetStringBoundingBox(STR_GENERATION_PROGRESS);
2221  /* We need some spacing for the 'border' */
2224  break;
2225  }
2226 
2227  case WID_SP_PROGRESS_TEXT:
2228  SetDParamMaxDigits(0, 4);
2229  SetDParamMaxDigits(1, 4);
2230  /* We really don't know the width. We could determine it by scanning the NewGRFs,
2231  * but this is the status window for scanning them... */
2232  size.width = std::max<uint>(size.width, GetStringBoundingBox(STR_NEWGRF_SCAN_STATUS).width + padding.width);
2234  break;
2235  }
2236  }
2237 
2238  void DrawWidget(const Rect &r, WidgetID widget) const override
2239  {
2240  switch (widget) {
2241  case WID_SP_PROGRESS_BAR: {
2242  /* Draw the % complete with a bar and a text */
2243  DrawFrameRect(r, COLOUR_GREY, FR_BORDERONLY | FR_LOWERED);
2244  Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
2245  uint percent = scanned * 100 / std::max(1U, _settings_client.gui.last_newgrf_count);
2246  DrawFrameRect(ir.WithWidth(ir.Width() * percent / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, FR_NONE);
2247  SetDParam(0, percent);
2248  DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_GENERATION_PROGRESS, TC_FROMSTRING, SA_HOR_CENTER);
2249  break;
2250  }
2251 
2252  case WID_SP_PROGRESS_TEXT:
2253  SetDParam(0, this->scanned);
2255  DrawString(r.left, r.right, r.top, STR_NEWGRF_SCAN_STATUS, TC_FROMSTRING, SA_HOR_CENTER);
2256 
2257  DrawString(r.left, r.right, r.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal, this->last_name, TC_BLACK, SA_HOR_CENTER);
2258  break;
2259  }
2260  }
2261 
2267  void UpdateNewGRFScanStatus(uint num, const char *name)
2268  {
2269  if (name == nullptr) {
2270  this->last_name = GetString(STR_NEWGRF_SCAN_ARCHIVES);
2271  } else {
2272  this->last_name = name;
2273  }
2274  this->scanned = num;
2276 
2277  this->SetDirty();
2278  }
2279 };
2280 
2286 void UpdateNewGRFScanStatus(uint num, const char *name)
2287 {
2289  if (w == nullptr) w = new ScanProgressWindow();
2290  w->UpdateNewGRFScanStatus(num, name);
2291 }
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetFiltering(Filtering f)
Import filter conditions.
void SetListing(Listing l)
Import sort conditions.
void SetFilterState(bool state)
Enable or disable the filter.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
void StartAction(GamelogActionType at)
Stores information about new action, but doesn't allocate it Action is allocated only when there is a...
Definition: gamelog.cpp:65
void GRFUpdate(const GRFConfig *oldg, const GRFConfig *newg)
Compares two NewGRF lists and logs any change.
Definition: gamelog.cpp:606
void StopAction()
Stops logging of any changes.
Definition: gamelog.cpp:74
Baseclass for nested widgets.
Definition: widget_type.h:144
void StoreSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height)
Store size and position.
Definition: widget_type.h:286
uint resize_x
Horizontal resize step (0 means not resizable).
Definition: widget_type.h:235
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
Definition: widget_type.h:233
uint smallest_x
Smallest horizontal size of the widget in a filled window.
Definition: widget_type.h:240
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
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:248
uint smallest_y
Smallest vertical size of the widget in a filled window.
Definition: widget_type.h:241
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
Definition: widget_type.h:234
uint resize_y
Vertical resize step (0 means not resizable).
Definition: widget_type.h:236
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:244
Base class for a 'real' widget.
Definition: widget_type.h:370
NWidgetCore * GetWidgetFromPos(int x, int y) override
Retrieve a widget by its position.
Definition: widget.cpp:1170
Custom nested widget container for the NewGRF gui.
bool editable
Editable status of the parent NewGRF window (if false, drop all widgets that make the window editable...
void FillWidgetLookup(WidgetLookup &widget_lookup) override
Fill the Window::widget_lookup with pointers to nested widgets in the tree.
std::unique_ptr< NWidgetBase > acs
Widget with the active grfs list and buttons.
static const uint MAX_EXTRA_INFO_WIDTH
Maximal additional width given to the panel.
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
NWidgetCore * GetWidgetFromPos(int x, int y) override
Retrieve a widget by its position.
void Draw(const Window *w) override
Draw the widgets of the tree.
std::unique_ptr< NWidgetBase > inf
Info panel.
static const uint MIN_EXTRA_FOR_3_COLUMNS
Minimal additional width needed before switching to 3 columns.
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
std::unique_ptr< NWidgetBase > avs
Widget with the available grfs list and buttons.
Scrollbar data structure.
Definition: widget_type.h:694
bool IsVisible(size_type item) const
Checks whether given current item is visible in the list.
Definition: widget_type.h:750
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
Definition: widget_type.h:879
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
EventState UpdateListPositionOnKeyPress(int &list_position, uint16_t keycode) const
Update the given list position as if it were on this scroll bar when the given keycode was pressed.
Definition: widget.cpp:2341
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
Definition: widget_type.h:841
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition: widget_type.h:860
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:740
void Reset()
Reset the timer, so it will fire again after the timeout.
Definition: timer.h:140
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 vsep_wide
Wide vertical spacing.
Definition: window_gui.h:62
int hsep_wide
Wide horizontal spacing.
Definition: window_gui.h:64
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
static const uint NETWORK_MAX_GRF_COUNT
Maximum number of GRFs that can be sent.
Definition: config.h:90
int find_index(Container const &container, typename Container::const_reference item)
Helper function to get the index of an item Consider using std::set, std::unordered_set or std::flat_...
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
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
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
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_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition: error.h:27
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition: error.h:24
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
Definition: fileio_type.h:124
Declarations for savegames operations.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
Gamelog _gamelog
Gamelog instance.
Definition: gamelog.cpp:31
Functions to be called to log fundamental changes to the game.
@ GLAT_GRF
GRF changed.
Definition: gamelog.h:19
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:851
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
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
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition: gfx.cpp:740
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
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition: widget.cpp:54
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition: gfx_func.h:166
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_type.h:344
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
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 SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1214
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Definition: math_func.hpp:252
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
Definition: math_func.hpp:150
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition: math_func.hpp:268
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
Types related to the misc widgets.
@ WID_TF_CAPTION
The caption of the window.
Definition: misc_widget.h:50
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.
std::vector< ContentInfo * > ContentVector
Vector with content info.
Base for the NewGRF implementation.
void ReloadNewGRFData()
Reload all NewGRF files during a running game.
Definition: afterload.cpp:3364
GRFConfig * _all_grfs
First item in list of all scanned NewGRFs.
std::string GRFBuildParamList(const GRFConfig *c)
Build a string containing space separated parameter values, and terminate.
void ClearGRFConfigList(GRFConfig **config)
Clear a GRF Config list, freeing all nodes.
GRFConfig * _grfconfig
First item in list of current GRF set up.
void ResetGRFConfig(bool defaults)
Reset the current GRF Config to either blank or newgame settings.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
GRFConfig ** CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only)
Copy a GRF Config list.
@ GRFP_GRF_UNSET
The NewGRF provided no information.
Definition: newgrf_config.h:69
@ GRFP_USE_WINDOWS
The palette state is set to use the Windows palette.
Definition: newgrf_config.h:66
@ GRFP_BLT_32BPP
The NewGRF prefers a 32 bpp blitter.
Definition: newgrf_config.h:76
@ GRFP_USE_MASK
Bitmask to get only the use palette use states.
Definition: newgrf_config.h:67
@ GRFP_GRF_MASK
Bitmask to get only the NewGRF supplied information.
Definition: newgrf_config.h:73
@ GCF_INVALID
GRF is unusable with this version of OpenTTD.
Definition: newgrf_config.h:29
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
Definition: newgrf_config.h:24
@ GCF_COMPATIBLE
GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches)
Definition: newgrf_config.h:25
@ PTYPE_UINT_ENUM
The parameter allows a range of numbers, each of which can have a special name.
@ PTYPE_BOOL
The parameter is either 0 or 1.
@ GCS_DISABLED
GRF file is disabled.
Definition: newgrf_config.h:35
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
Definition: newgrf_config.h:36
@ GCS_ACTIVATED
GRF file has been activated.
Definition: newgrf_config.h:38
@ FGCM_NEWEST
Find newest Grf.
@ FGCM_NEWEST_VALID
Find newest Grf, ignoring Grfs with GCF_INVALID set.
@ FGCM_EXACT
Only find Grfs matching md5sum.
std::map< uint32_t, const GRFConfig * > GrfIdMap
Map of grfid to the grf config.
Definition: newgrf_gui.cpp:584
void UpdateNewGRFScanStatus(uint num, const char *name)
Update the NewGRF scan status.
static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map)
Add all grf configs from c into the map.
Definition: newgrf_gui.cpp:591
static WindowDesc _newgrf_parameters_desc(WDP_CENTER, "settings_newgrf_config", 500, 208, WC_GRF_PARAMETERS, WC_NONE, 0, _nested_newgrf_parameter_widgets)
Window definition for the change grf parameters window.
static void NewGRFConfirmationCallback(Window *w, bool confirmed)
Callback function for the newgrf 'apply changes' confirmation window.
static void ShowSavePresetWindow(const char *initial_text)
Open the window for saving a preset.
static constexpr NWidgetPart _nested_scan_progress_widgets[]
Widgets for the progress window.
void ShowMissingContentWindow(const GRFConfig *list)
Show the content list window with all missing grfs from the given list.
static WindowDesc _scan_progress_desc(WDP_CENTER, nullptr, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, _nested_scan_progress_widgets)
Description of the widgets and other settings of the window.
static constexpr NWidgetPart _nested_save_preset_widgets[]
Widget parts of the save preset window.
static WindowDesc _save_preset_desc(WDP_CENTER, "save_preset", 140, 110, WC_SAVE_PRESET, WC_GAME_OPTIONS, WDF_MODAL, _nested_save_preset_widgets)
Window description of the preset save window.
void ShowNewGRFError()
Show the first NewGRF error we can find.
Definition: newgrf_gui.cpp:45
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
Setup the NewGRF gui.
std::unique_ptr< NWidgetBase > NewGRFDisplay()
Construct nested container widget for managing the lists and the info panel of the NewGRF GUI.
const char * GetGRFStringFromGRFText(const GRFTextList &text_list)
Get a C-string from a GRFText-list.
Header of Action 04 "universal holder" structure and functions.
Types related to the newgrf widgets.
@ WID_NS_VIEW_PARAMETERS
Open Parameters Window for selected NewGRF for viewing parameters.
Definition: newgrf_widget.h:54
@ WID_NS_APPLY_CHANGES
Apply changes to NewGRF config.
Definition: newgrf_widget.h:56
@ WID_NS_OPEN_URL
Open URL of NewGRF.
Definition: newgrf_widget.h:51
@ WID_NS_CONTENT_DOWNLOAD2
Open content download (active NewGRFs).
Definition: newgrf_widget.h:60
@ WID_NS_RESCAN_FILES
Rescan files (available NewGRFs).
Definition: newgrf_widget.h:57
@ WID_NS_CONTENT_DOWNLOAD
Open content download (available NewGRFs).
Definition: newgrf_widget.h:59
@ WID_NS_MOVE_UP
Move NewGRF up in active list.
Definition: newgrf_widget.h:41
@ WID_NS_SHOW_REMOVE
Select active list buttons (0 = normal, 1 = simple layout).
Definition: newgrf_widget.h:61
@ WID_NS_NEWGRF_INFO
Panel for Info on selected NewGRF.
Definition: newgrf_widget.h:50
@ WID_NS_NEWGRF_TEXTFILE
Open NewGRF readme, changelog (+1) or license (+2).
Definition: newgrf_widget.h:52
@ WID_NS_SET_PARAMETERS
Open Parameters Window for selected NewGRF for editing parameters.
Definition: newgrf_widget.h:53
@ WID_NS_ADD
Add NewGRF to active list.
Definition: newgrf_widget.h:39
@ WID_NS_MOVE_DOWN
Move NewGRF down in active list.
Definition: newgrf_widget.h:42
@ WID_NS_SCROLL2BAR
Scrollbar for available NewGRF list.
Definition: newgrf_widget.h:48
@ WID_NS_UPGRADE
Upgrade NewGRFs that have a newer version available.
Definition: newgrf_widget.h:43
@ WID_NS_PRESET_SAVE
Save list of active NewGRFs as presets.
Definition: newgrf_widget.h:37
@ WID_NS_FILTER
Filter list of available NewGRFs.
Definition: newgrf_widget.h:44
@ WID_NS_FILE_LIST
List window of active NewGRFs.
Definition: newgrf_widget.h:45
@ WID_NS_SHOW_APPLY
Select display of the buttons below the 'details'.
Definition: newgrf_widget.h:62
@ WID_NS_SCROLLBAR
Scrollbar for active NewGRF list.
Definition: newgrf_widget.h:46
@ WID_NS_PRESET_DELETE
Delete active preset.
Definition: newgrf_widget.h:38
@ WID_NS_TOGGLE_PALETTE
Toggle Palette of selected, active NewGRF.
Definition: newgrf_widget.h:55
@ WID_NS_RESCAN_FILES2
Rescan files (active NewGRFs).
Definition: newgrf_widget.h:58
@ WID_NS_NEWGRF_INFO_TITLE
Title for Info on selected NewGRF.
Definition: newgrf_widget.h:49
@ WID_NS_REMOVE
Remove NewGRF from active list.
Definition: newgrf_widget.h:40
@ WID_NS_PRESET_LIST
Active NewGRF preset.
Definition: newgrf_widget.h:36
@ WID_NS_AVAIL_LIST
List window of available NewGRFs.
Definition: newgrf_widget.h:47
@ WID_SP_PROGRESS_BAR
Simple progress bar.
Definition: newgrf_widget.h:76
@ WID_SP_PROGRESS_TEXT
Text explaining what is happening.
Definition: newgrf_widget.h:77
@ WID_NP_NUMPAR_INC
Button to increase number of parameters.
Definition: newgrf_widget.h:21
@ WID_NP_RESET
Reset button.
Definition: newgrf_widget.h:27
@ WID_NP_NUMPAR_DEC
Button to decrease number of parameters.
Definition: newgrf_widget.h:20
@ WID_NP_SCROLLBAR
Scrollbar to scroll through all settings.
Definition: newgrf_widget.h:25
@ WID_NP_CAPTION
Caption of the window.
Definition: newgrf_widget.h:18
@ WID_NP_SETTING_DROPDOWN
Dynamically created dropdown for changing setting value.
Definition: newgrf_widget.h:31
@ WID_NP_BACKGROUND
Panel to draw the settings on.
Definition: newgrf_widget.h:24
@ WID_NP_ACCEPT
Accept button.
Definition: newgrf_widget.h:26
@ WID_NP_NUMPAR
Optional number of parameters.
Definition: newgrf_widget.h:22
@ WID_NP_SHOW_NUMPAR
NWID_SELECTION to optionally display WID_NP_NUMPAR.
Definition: newgrf_widget.h:19
@ WID_NP_SHOW_DESCRIPTION
NWID_SELECTION to optionally display parameter descriptions.
Definition: newgrf_widget.h:28
@ WID_NP_DESCRIPTION
Multi-line description of a parameter.
Definition: newgrf_widget.h:29
@ WID_SVP_SAVE
Button to save the preset.
Definition: newgrf_widget.h:71
@ WID_SVP_PRESET_LIST
List with available preset names.
Definition: newgrf_widget.h:67
@ WID_SVP_SCROLLBAR
Scrollbar for the list available preset names.
Definition: newgrf_widget.h:68
@ WID_SVP_CANCEL
Button to cancel saving the preset.
Definition: newgrf_widget.h:70
@ WID_SVP_EDITBOX
Edit box for changing the preset name.
Definition: newgrf_widget.h:69
bool RequestNewGRFScan(NewGRFScanCallback *callback)
Request a new NewGRF scan.
Definition: openttd.cpp:1331
static const uint8_t PC_GREY
Grey palette colour.
Definition: palette_func.h:69
static const uint8_t PC_DARK_GREY
Dark grey palette colour.
Definition: palette_func.h:68
static const uint8_t PC_DARK_BLUE
Dark blue palette colour.
Definition: palette_func.h:87
static const uint8_t PC_BLACK
Black palette colour.
Definition: palette_func.h:67
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
Definition: settings.cpp:1521
GRFConfig * LoadGRFPresetFromConfig(const char *config_name)
Load a NewGRF configuration by preset-name.
Definition: settings.cpp:1541
void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
Save a NewGRF configuration with a preset name.
Definition: settings.cpp:1558
void DeleteGRFPresetFromConfig(const char *config_name)
Delete a NewGRF configuration by preset name.
Definition: settings.cpp:1572
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
Functions related to setting/changing the settings.
void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
Draw [<][>] boxes.
void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable)
Draw a dropdown button.
void DrawBoolButton(int x, int y, bool state, bool clickable)
Draw a toggle button.
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
Types related to global configuration settings.
Base types for having sorted lists in GUIs.
This file contains all sprite-related enums and defines.
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition: sprites.h:1390
Definition of base types and functions in a cross-platform compatible way.
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition: string.cpp:81
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:589
bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:57
@ CS_NUMERAL
Only numeric ones.
Definition: string_type.h:26
std::vector< std::string > StringList
Type for a list of strings.
Definition: string_type.h:60
Searching and filtering using a stringterm.
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:127
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
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:319
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
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
void SetDParamMaxDigits(size_t n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:143
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
GUISettings gui
settings related to the GUI
Container for all important information about a piece of content.
uint32_t unique_id
Unique ID; either GRF ID or shortname.
MD5Hash md5sum
The MD5 checksum.
State state
Whether the content info is selected (for download)
std::string name
Name of the content.
@ DOES_NOT_EXIST
The content does not exist in the content system.
ContentType type
Type of content.
Dimensions (a width and height) of a rectangle in 2D.
Data structure describing what to show in the list (filter criteria).
Definition: sortlist_type.h:35
Information about GRF, used in the game and (part of it) in savegames.
MD5Hash original_md5sum
MD5 checksum of original file if only a 'compatible' file was loaded.
void SetParameterDefaults()
Set the default value for all parameters as specified by action14.
const char * GetURL() const
Get the grf url.
uint8_t palette
GRFPalette, bitset.
uint8_t flags
NOSAVE: GCF_Flags, bitset.
const char * GetDescription() const
Get the grf info.
std::vector< std::optional< GRFParameterInfo > > param_info
NOSAVE: extra information about the parameters.
uint32_t version
NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown.
uint8_t num_params
Number of used parameters.
struct GRFConfig * next
NOSAVE: Next item in the linked list.
GRFStatus status
NOSAVE: GRFStatus, enum.
std::optional< GRFError > error
NOSAVE: Error/Warning during GRF loading (Action 0x0B)
bool IsCompatible(uint32_t old_version) const
Return whether this NewGRF can replace an older version of the same NewGRF.
void CopyParams(const GRFConfig &src)
Copy the parameter information from the src config.
std::optional< std::string > GetTextfile(TextfileType type) const
Search a textfile file next to this NewGRF.
uint8_t num_valid_params
NOSAVE: Number of valid parameters (action 0x14)
std::string filename
Filename - either with or without full path.
GRFIdentifier ident
grfid and md5sum to uniquely identify newgrfs
const char * GetName() const
Get the name of this grf.
uint32_t min_loadable_version
NOSAVE: Minimum compatible version a NewGRF can define.
std::array< uint32_t, 0x80 > param
GRF parameters.
bool HasGrfIdentifier(uint32_t grfid, const MD5Hash *md5sum) const
Does the identification match the provided values?
Definition: newgrf_config.h:99
uint32_t grfid
GRF ID (defined by Action 0x08)
Definition: newgrf_config.h:83
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
Definition: newgrf_config.h:84
Information about one grf parameter.
bool complete_labels
True if all values have a label.
std::map< uint32_t, GRFTextList > value_names
Names for each value.
uint8_t param_nr
GRF parameter to store content in.
uint32_t min_value
The minimal value this parameter can have.
uint32_t max_value
The maximal value of this parameter.
uint32_t GetValue(struct GRFConfig *config) const
Get the value of this user-changeable parameter from the given config.
GRFParameterType type
The type of this parameter.
void SetValue(struct GRFConfig *config, uint32_t value)
Set the value of this user-changeable parameter in the given config.
GRFTextList name
The name of this parameter.
GRFTextList desc
The description of this parameter.
uint32_t last_newgrf_count
the numbers of NewGRFs we found during the last scan
bool newgrf_show_old_versions
whether to show old versions in the NewGRF list
bool scenario_developer
activate scenario developer: allow modifying NewGRFs in an existing game
bool newgrf_developer_tools
activate NewGRF developer tools and allow modifying NewGRFs in an existing game
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:30
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Window for setting the parameters of a NewGRF.
Definition: newgrf_gui.cpp:146
bool clicked_dropdown
Whether the dropdown is open.
Definition: newgrf_gui.cpp:151
static GRFParameterInfo & GetDummyParameterInfo(uint nr)
Get a dummy parameter-info object with default information.
Definition: newgrf_gui.cpp:186
void OnPaint() override
The window must be repainted.
Definition: newgrf_gui.cpp:325
bool editable
Allow editing parameters.
Definition: newgrf_gui.cpp:157
bool HasParameterInfo(uint nr) const
Test if GRF Parameter Info exists for a given parameter index.
Definition: newgrf_gui.cpp:197
static GRFParameterInfo dummy_parameter_info
Dummy info in case a newgrf didn't provide info about some parameter.
Definition: newgrf_gui.cpp:147
TimeoutTimer< TimerWindow > unclick_timeout
When reset, unclick the button after a small timeout.
Definition: newgrf_gui.cpp:503
bool action14present
True if action14 information is present.
Definition: newgrf_gui.cpp:156
int line_height
Height of a row in the matrix widget.
Definition: newgrf_gui.cpp:154
bool clicked_increase
True if the increase button was clicked, false for the decrease button.
Definition: newgrf_gui.cpp:150
int32_t clicked_row
The selected parameter, or INT_MAX when none is selected.
Definition: newgrf_gui.cpp:153
bool closing_dropdown
True, if the dropdown list is currently closing.
Definition: newgrf_gui.cpp:152
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: newgrf_gui.cpp:487
GRFConfig * grf_config
Set the parameters of this GRFConfig.
Definition: newgrf_gui.cpp:148
void OnDropdownClose(Point, WidgetID widget, int, bool) override
A dropdown window associated to this window has been closed.
Definition: newgrf_gui.cpp:465
int32_t clicked_button
The row in which a button was clicked or INT_MAX when none is selected.
Definition: newgrf_gui.cpp:149
GRFParameterInfo & GetParameterInfo(uint nr) const
Get GRF Parameter Info exists for a given parameter index.
Definition: newgrf_gui.cpp:208
void OnResize() override
Called after the window got resized.
Definition: newgrf_gui.cpp:477
Callback for NewGRF scanning.
Window for displaying the textfile of a NewGRF.
Definition: newgrf_gui.cpp:558
const GRFConfig * grf_config
View the textfile of this GRFConfig.
Definition: newgrf_gui.cpp:559
Window for showing NewGRF files.
Definition: newgrf_gui.cpp:605
bool editable
Is the window editable?
Definition: newgrf_gui.cpp:627
bool CanUpgradeCurrent()
Test whether the currently active set of NewGRFs can be upgraded with the available NewGRFs.
Definition: newgrf_gui.cpp:703
GRFConfig * active_sel
Selected active grf item.
Definition: newgrf_gui.cpp:624
bool show_params
Are the grf-parameters shown in the info-panel?
Definition: newgrf_gui.cpp:628
void UpgradeCurrent()
Upgrade the currently active set of NewGRFs.
Definition: newgrf_gui.cpp:716
void OnResize() override
Called after the window got resized.
Definition: newgrf_gui.cpp:797
bool AddGRFToActive(int ins_pos=-1)
Insert a GRF into the active list.
int avail_pos
Index of avail_sel if existing, else -1.
Definition: newgrf_gui.cpp:617
int active_over
Active GRF item over which another one is dragged, -1 if none.
Definition: newgrf_gui.cpp:631
bool modified
The list of active NewGRFs has been modified since the last time they got saved.
Definition: newgrf_gui.cpp:632
bool execute
On pressing 'apply changes' are grf changes applied immediately, or only list is updated.
Definition: newgrf_gui.cpp:629
int preset
Selected preset or -1 if none selected.
Definition: newgrf_gui.cpp:630
GRFConfig ** orig_list
List active grfs in the game. Used as initial value, may be updated by the window.
Definition: newgrf_gui.cpp:626
StringList grf_presets
List of known NewGRF presets.
Definition: newgrf_gui.cpp:621
const GRFConfig * avail_sel
Currently selected available grf. nullptr is none is selected.
Definition: newgrf_gui.cpp:616
void UpdateScrollBars()
Updates the scroll bars for the active and inactive NewGRF lists.
QueryString filter_editbox
Filter editbox;.
Definition: newgrf_gui.cpp:619
static bool TagNameFilter(const GRFConfig *const *a, StringFilter &filter)
Filter grfs by tags/name.
GRFConfig * actives
Temporary active grf list to which changes are made.
Definition: newgrf_gui.cpp:623
static Filtering last_filtering
Default filtering of #GUIGRFConfigList.
Definition: newgrf_gui.cpp:611
static const std::initializer_list< GUIGRFConfigList::SortFunction *const > sorter_funcs
Sort functions of the #GUIGRFConfigList.
Definition: newgrf_gui.cpp:612
static const std::initializer_list< GUIGRFConfigList::FilterFunction *const > filter_funcs
Filter functions of the #GUIGRFConfigList.
Definition: newgrf_gui.cpp:613
PaletteID GetPalette(const GRFConfig *c) const
Pick the palette for the sprite of the grf to display.
Definition: newgrf_gui.cpp:822
void OnNewGRFsScanned() override
Called whenever the NewGRF scan completed.
GUIGRFConfigList avails
Available (non-active) grfs.
Definition: newgrf_gui.cpp:615
StringFilter string_filter
Filter for available grf.
Definition: newgrf_gui.cpp:618
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
static Listing last_sorting
Default sorting of #GUIGRFConfigList.
Definition: newgrf_gui.cpp:610
static bool NameSorter(const GRFConfig *const &a, const GRFConfig *const &b)
Sort grfs by name.
Coordinates of a point in 2D.
Data stored about a string that can be modified in the GUI.
int ok_button
Widget button of parent window to simulate when pressing OK in OSK.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Class for the save preset window.
QueryString presetname_editbox
Edit box of the save preset.
void OnResize() override
Called after the window got resized.
SavePresetWindow(const char *initial_text)
Constructor of the save preset window.
int selected
Selected entry in the preset list, or -1 if none selected.
Scrollbar * vscroll
Pointer to the scrollbar widget.
StringList presets
Available presets.
Window for showing the progress of NewGRF scanning.
std::string last_name
The name of the last 'seen' NewGRF.
void UpdateNewGRFScanStatus(uint num, const char *name)
Update the NewGRF scan status.
int scanned
The number of NewGRFs that we have seen.
ScanProgressWindow()
Create the window.
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.
void Assign(StringID string)
Render a string into the textbuffer.
Definition: textbuf.cpp:431
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
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
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 OnQueryTextFinished([[maybe_unused]] std::optional< std::string > str)
The query window opened from this window has closed.
Definition: window_gui.h:779
int top
y position of top edge of the window
Definition: window_gui.h:310
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
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 width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:311
@ CONTENT_TYPE_NEWGRF
The content consists of a NewGRF.
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
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition: viewport.cpp:3498
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
Definition: viewport.cpp:3435
@ HT_DRAG
dragging items in the depot windows
Definition of Interval and OneShot timers.
Definition of the Window system.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:281
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
Definition: widget_type.h:482
uint ComputeMaxSize(uint base, uint max_space, uint step)
Return the biggest possible size of a nested widget.
Definition: widget_type.h:944
@ 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_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition: widget_type.h:51
@ NWID_CUSTOM
General Custom widget.
Definition: widget_type.h:85
@ 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
@ NWID_SPACER
Invisible widget that takes some space.
Definition: widget_type.h:79
@ WWT_EDITBOX
a textbox for typing
Definition: widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_MATRIX
Grid of rows and columns.
Definition: widget_type.h:59
@ 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
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
Definition: widget_type.h:119
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition: widget_type.h:40
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
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1098
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition: window.cpp:1113
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 SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
Window functions not directly related to making/drawing windows.
@ FR_BORDERONLY
Draw border only, no background.
Definition: window_gui.h:27
@ FR_LOWERED
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
Definition: window_gui.h:28
@ WDF_MODAL
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition: window_gui.h:204
@ WDP_CENTER
Center the window.
Definition: window_gui.h:148
int WidgetID
Widget ID.
Definition: window_type.h:18
@ WN_GAME_OPTIONS_NEWGRF_STATE
NewGRF settings.
Definition: window_type.h:25
EventState
State of handling an event.
Definition: window_type.h:743
@ ES_HANDLED
The passed event is handled.
Definition: window_type.h:744
@ ES_NOT_HANDLED
The passed event is not handled.
Definition: window_type.h:745
@ WC_BUILD_OBJECT
Build object; Window numbers:
Definition: window_type.h:376
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_SAVE_PRESET
Save preset; Window numbers:
Definition: window_type.h:698
@ 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
@ WC_MODAL_PROGRESS
Progress report of landscape generation; Window numbers:
Definition: window_type.h:469
@ GOID_NEWGRF_CURRENT_LOADED
The current list of active NewGRF has been loaded.
Definition: window_type.h:731
@ GOID_NEWGRF_RESCANNED
NewGRFs were just rescanned.
Definition: window_type.h:730
@ GOID_NEWGRF_CHANGES_APPLIED
The active NewGRF list changes have been applied.
Definition: window_type.h:734
@ GOID_NEWGRF_CHANGES_MADE
Changes have been made to a given NewGRF either through the palette or its parameters.
Definition: window_type.h:733
@ GOID_NEWGRF_LIST_EDITED
List of active NewGRFs is being edited.
Definition: window_type.h:732
Functions related to zooming.
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:117