OpenTTD Source 20241224-master-gf74b0cf984
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"
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
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
71static 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
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()) {
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->param.empty()) {
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())) {
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
155 Scrollbar *vscroll;
157 bool editable;
158
160 grf_config(c),
166 {
167 this->action14present = (c->num_valid_params != c->param.size() || !c->param_info.empty());
168
169 this->CreateNestedTree();
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
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
214 {
215 switch (widget) {
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, GRFConfig::MAX_NUM_PARAMS);
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
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
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;
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;
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++) {
287 uint32_t current_value = this->grf_config->GetValue(par_info);
288 bool selected = (i == this->clicked_row);
289
290 if (par_info.type == PTYPE_BOOL) {
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 }
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) {
306 SetDParamStr(3, label);
307 }
308 }
309 }
310
311 const char *name = GetGRFStringFromGRFText(par_info.name);
312 if (name != nullptr) {
314 SetDParamStr(1, name);
315 } else {
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) {
338 if (this->editable && !this->action14present && !this->grf_config->param.empty()) {
339 this->grf_config->param.pop_back();
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->param.size() < c->num_valid_params) {
348 this->grf_config->param.emplace_back(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
372
373 /* One of the arrows is clicked */
374 uint32_t old_val = this->grf_config->GetValue(par_info);
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)) {
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 this->grf_config->SetValue(par_info, 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);
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 this->grf_config->SetValue(par_info, value);
452 this->SetDirty();
453 }
454
455 void OnDropdownSelect(WidgetID widget, int index) override
456 {
457 if (widget != WID_NP_SETTING_DROPDOWN) return;
458 assert(this->clicked_dropdown);
459 GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
460 this->grf_config->SetValue(par_info, index);
461 this->SetDirty();
462 }
463
464 void OnDropdownClose(Point, WidgetID widget, int, bool) override
465 {
466 if (widget != WID_NP_SETTING_DROPDOWN) return;
467 /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
468 * the same dropdown button was clicked again, and then not open the dropdown again.
469 * So, we only remember that it was closed, and process it on the next OnPaint, which is
470 * after OnClick. */
471 assert(this->clicked_dropdown);
472 this->closing_dropdown = true;
473 this->SetDirty();
474 }
475
476 void OnResize() override
477 {
478 this->vscroll->SetCapacityFromWidget(this, WID_NP_BACKGROUND);
479 }
480
486 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
487 {
488 if (!gui_scope) return;
489 if (!this->action14present) {
490 this->SetWidgetDisabledState(WID_NP_NUMPAR_DEC, !this->editable || this->grf_config->param.empty());
491 this->SetWidgetDisabledState(WID_NP_NUMPAR_INC, !this->editable || std::size(this->grf_config->param) >= this->grf_config->num_valid_params);
492 }
493
494 this->vscroll->SetCount(this->action14present ? this->grf_config->num_valid_params : GRFConfig::MAX_NUM_PARAMS);
495 if (this->clicked_row != INT32_MAX && this->clicked_row >= this->vscroll->GetCount()) {
496 this->clicked_row = INT32_MAX;
498 }
499 }
500
502 TimeoutTimer<TimerWindow> unclick_timeout = {std::chrono::milliseconds(150), [this]() {
503 this->clicked_button = INT32_MAX;
504 this->SetDirty();
505 }};
506};
508
509
510static constexpr NWidgetPart _nested_newgrf_parameter_widgets[] = {
512 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
513 NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_NP_CAPTION),
514 NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
515 EndContainer(),
516 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_NUMPAR),
517 NWidget(WWT_PANEL, COLOUR_MAUVE), SetResize(1, 0), SetFill(1, 0), SetPIP(4, 0, 4),
518 NWidget(NWID_HORIZONTAL), SetPIP(4, 0, 4),
521 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),
522 EndContainer(),
523 EndContainer(),
524 EndContainer(),
526 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 EndContainer(),
530 NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NP_DESCRIPTION), SetResize(1, 0), SetFill(1, 0),
531 EndContainer(),
532 EndContainer(),
535 NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_CLOSE, STR_NULL),
536 NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_RESET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_RESET, STR_NEWGRF_PARAMETERS_RESET_TOOLTIP),
537 EndContainer(),
538 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
539 EndContainer(),
540};
541
544 WDP_CENTER, "settings_newgrf_config", 500, 208,
546 0,
547 _nested_newgrf_parameter_widgets
548);
549
550void OpenGRFParameterWindow(bool is_baseset, GRFConfig *c, bool editable)
551{
553 new NewGRFParametersWindow(_newgrf_parameters_desc, is_baseset, c, editable);
554}
555
559
561 {
562 this->ConstructWindow();
563
564 auto textfile = this->grf_config->GetTextfile(file_type);
565 this->LoadTextfile(textfile.value(), NEWGRF_DIR);
566 }
567
568 void SetStringParameters(WidgetID widget) const override
569 {
570 if (widget == WID_TF_CAPTION) {
572 SetDParamStr(1, this->grf_config->GetName());
573 }
574 }
575};
576
577void ShowNewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c)
578{
579 CloseWindowById(WC_TEXTFILE, file_type);
580 new NewGRFTextfileWindow(file_type, c);
581}
582
583typedef std::map<uint32_t, const GRFConfig *> GrfIdMap;
584
590static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map)
591{
592 while (c != nullptr) {
593 grfid_map->emplace(c->ident.grfid, c);
594 c = c->next;
595 }
596}
597
598static void NewGRFConfirmationCallback(Window *w, bool confirmed);
599static void ShowSavePresetWindow(const char *initial_text);
600
606
607 static const uint EDITBOX_MAX_SIZE = 50;
608
609 static Listing last_sorting;
611 static const std::initializer_list<GUIGRFConfigList::SortFunction * const> sorter_funcs;
612 static const std::initializer_list<GUIGRFConfigList::FilterFunction * const> filter_funcs;
613
619
621
624
626 bool editable;
628 bool execute;
629 int preset;
631 bool modified;
632
633 Scrollbar *vscroll;
634 Scrollbar *vscroll2;
635
636 NewGRFWindow(WindowDesc &desc, bool editable, bool show_params, bool execute, GRFConfig **orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE)
637 {
638 this->avail_sel = nullptr;
639 this->avail_pos = -1;
640 this->active_sel = nullptr;
641 this->actives = nullptr;
642 this->orig_list = orig_list;
643 this->editable = editable;
644 this->execute = execute;
645 this->show_params = show_params;
646 this->preset = -1;
647 this->active_over = -1;
648
649 CopyGRFConfigList(&this->actives, *orig_list, false);
650 this->grf_presets = GetGRFPresetList();
651
652 this->CreateNestedTree();
653 this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR);
654 this->vscroll2 = this->GetScrollbar(WID_NS_SCROLL2BAR);
655
656 this->GetWidget<NWidgetStacked>(WID_NS_SHOW_REMOVE)->SetDisplayedPlane(this->editable ? 0 : 1);
657 this->GetWidget<NWidgetStacked>(WID_NS_SHOW_APPLY)->SetDisplayedPlane(this->editable ? 0 : this->show_params ? 1 : SZSP_HORIZONTAL);
659
661 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
662 if (editable) {
664 } else {
666 }
667
668 this->avails.SetListing(this->last_sorting);
669 this->avails.SetFiltering(this->last_filtering);
670 this->avails.SetSortFuncs(this->sorter_funcs);
671 this->avails.SetFilterFuncs(this->filter_funcs);
672 this->avails.ForceRebuild();
673
675 }
676
677 void Close([[maybe_unused]] int data = 0) override
678 {
682
683 if (this->editable && this->modified && !this->execute && !_exit_game) {
684 CopyGRFConfigList(this->orig_list, this->actives, true);
685 ResetGRFConfig(false);
687 }
688
689 this->Window::Close();
690 }
691
693 {
694 /* Remove the temporary copy of grf-list used in window */
695 ClearGRFConfigList(&this->actives);
696 }
697
703 {
705 FillGrfidMap(this->actives, &grfid_map);
706
707 for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) {
708 GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid);
709 if (iter != grfid_map.end() && a->version > iter->second->version) return true;
710 }
711 return false;
712 }
713
716 {
718 FillGrfidMap(this->actives, &grfid_map);
719
720 for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) {
721 GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid);
722 if (iter == grfid_map.end() || iter->second->version >= a->version) continue;
723
724 GRFConfig **c = &this->actives;
725 while (*c != iter->second) c = &(*c)->next;
726 GRFConfig *d = new GRFConfig(*a);
727 d->next = (*c)->next;
728 if (d->IsCompatible((*c)->version)) {
729 d->CopyParams(**c);
730 } else {
731 d->SetParameterDefaults();
732 }
733 if (this->active_sel == *c) {
736 this->active_sel = nullptr;
737 }
738 delete *c;
739 *c = d;
740 iter->second = d;
741 }
742 }
743
745 {
746 switch (widget) {
747 case WID_NS_FILE_LIST:
748 {
749 Dimension d = maxdim(GetScaledSpriteSize(SPR_SQUARE), GetScaledSpriteSize(SPR_WARNING_SIGN));
750 resize.height = std::max<uint>(d.height + 2U, GetCharacterHeight(FS_NORMAL));
751 size.height = std::max(size.height, padding.height + 6 * resize.height);
752 break;
753 }
754
756 {
757 Dimension d = maxdim(GetScaledSpriteSize(SPR_SQUARE), GetScaledSpriteSize(SPR_WARNING_SIGN));
758 resize.height = std::max<uint>(d.height + 2U, GetCharacterHeight(FS_NORMAL));
759 size.height = std::max(size.height, padding.height + 8 * resize.height);
760 break;
761 }
762
765 size.height = std::max(size.height, dim.height + WidgetDimensions::scaled.frametext.Vertical());
766 size.width = std::max(size.width, dim.width + WidgetDimensions::scaled.frametext.Horizontal());
767 break;
768 }
769
771 size.height = std::max<uint>(size.height, WidgetDimensions::scaled.framerect.Vertical() + 10 * GetCharacterHeight(FS_NORMAL));
772 break;
773
774 case WID_NS_PRESET_LIST: {
776 for (const auto &i : this->grf_presets) {
777 SetDParamStr(0, i);
779 }
780 d.width += padding.width;
781 size = maxdim(d, size);
782 break;
783 }
784
789 size.width += padding.width;
790 size.height += padding.height;
791 break;
792 }
793 }
794 }
795
796 void OnResize() override
797 {
798 this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.Vertical());
799 this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.Vertical());
800 }
801
802 void SetStringParameters(WidgetID widget) const override
803 {
804 switch (widget) {
806 if (this->preset == -1) {
808 } else {
810 SetDParamStr(1, this->grf_presets[this->preset]);
811 }
812 break;
813 }
814 }
815
821 inline PaletteID GetPalette(const GRFConfig *c) const
822 {
823 PaletteID pal;
824
825 /* Pick a colour */
826 switch (c->status) {
827 case GCS_NOT_FOUND:
828 case GCS_DISABLED:
829 pal = PALETTE_TO_RED;
830 break;
831 case GCS_ACTIVATED:
832 pal = PALETTE_TO_GREEN;
833 break;
834 default:
835 pal = PALETTE_TO_BLUE;
836 break;
837 }
838
839 /* Do not show a "not-failure" colour when it actually failed to load */
840 if (pal != PALETTE_TO_RED) {
841 if (HasBit(c->flags, GCF_STATIC)) {
842 pal = PALETTE_TO_GREY;
843 } else if (HasBit(c->flags, GCF_COMPATIBLE)) {
844 pal = PALETTE_TO_ORANGE;
845 }
846 }
847
848 return pal;
849 }
850
851 void DrawWidget(const Rect &r, WidgetID widget) const override
852 {
853 switch (widget) {
854 case WID_NS_FILE_LIST: {
855 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
857
858 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
859 uint step_height = this->GetWidget<NWidgetBase>(WID_NS_FILE_LIST)->resize_y;
860 Dimension square = GetSpriteSize(SPR_SQUARE);
861 Dimension warning = GetSpriteSize(SPR_WARNING_SIGN);
862 int square_offset_y = (step_height - square.height) / 2;
863 int warning_offset_y = (step_height - warning.height) / 2;
864 int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
865
866 bool rtl = _current_text_dir == TD_RTL;
867 uint text_left = rtl ? tr.left : tr.left + square.width + 13;
868 uint text_right = rtl ? tr.right - square.width - 13 : tr.right;
869 uint square_left = rtl ? tr.right - square.width - 3 : tr.left + 3;
870 uint warning_left = rtl ? tr.right - square.width - warning.width - 8 : tr.left + square.width + 8;
871
872 int i = 0;
873 for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {
874 if (this->vscroll->IsVisible(i)) {
875 const char *text = c->GetName();
876 bool h = (this->active_sel == c);
877 PaletteID pal = this->GetPalette(c);
878
879 if (h) {
880 GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
881 } else if (i == this->active_over) {
882 /* Get index of current selection. */
883 int active_sel_pos = 0;
884 for (GRFConfig *c = this->actives; c != nullptr && c != this->active_sel; c = c->next, active_sel_pos++) {}
885 if (active_sel_pos != this->active_over) {
886 uint top = this->active_over < active_sel_pos ? tr.top + 1 : tr.top + step_height - 2;
887 GfxFillRect(tr.left, top - 1, tr.right, top + 1, PC_GREY);
888 }
889 }
890 DrawSprite(SPR_SQUARE, pal, square_left, tr.top + square_offset_y);
891 if (c->error.has_value()) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, tr.top + warning_offset_y);
892 uint txtoffset = !c->error.has_value() ? 0 : warning.width;
893 DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), tr.top + offset_y, text, h ? TC_WHITE : TC_ORANGE);
894 tr.top += step_height;
895 }
896 }
897 if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry.
898 GfxFillRect(tr.left, tr.top, tr.right, tr.top + 2, PC_GREY);
899 }
900 break;
901 }
902
903 case WID_NS_AVAIL_LIST: {
904 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
905 GfxFillRect(br, this->active_over == -2 ? PC_DARK_GREY : PC_BLACK);
906
907 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
908 uint step_height = this->GetWidget<NWidgetBase>(WID_NS_AVAIL_LIST)->resize_y;
909 int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
910
911 auto [first, last] = this->vscroll2->GetVisibleRangeIterators(this->avails);
912 for (auto it = first; it != last; ++it) {
913 const GRFConfig *c = *it;
914 bool h = (c == this->avail_sel);
915 const char *text = c->GetName();
916
917 if (h) GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
918 DrawString(tr.left, tr.right, tr.top + offset_y, text, h ? TC_WHITE : TC_SILVER);
919 tr.top += step_height;
920 }
921 break;
922 }
923
925 /* Create the nice grayish rectangle at the details top. */
927 DrawString(r.left, r.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
928 break;
929 }
930
931 case WID_NS_NEWGRF_INFO: {
932 const GRFConfig *selected = this->active_sel;
933 if (selected == nullptr) selected = this->avail_sel;
934 if (selected != nullptr) {
935 ShowNewGRFInfo(selected, r, this->show_params);
936 }
937 break;
938 }
939 }
940 }
941
942 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
943 {
944 if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_CONTENT_END) {
945 if (this->active_sel == nullptr && this->avail_sel == nullptr) return;
946
947 ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != nullptr ? this->active_sel : this->avail_sel);
948 return;
949 }
950
951 switch (widget) {
952 case WID_NS_PRESET_LIST: {
953 DropDownList list;
954
955 /* Add 'None' option for clearing list */
956 list.push_back(MakeDropDownListStringItem(STR_NONE, -1));
957
958 for (uint i = 0; i < this->grf_presets.size(); i++) {
959 list.push_back(MakeDropDownListStringItem(this->grf_presets[i], i));
960 }
961
962 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
963 ShowDropDownList(this, std::move(list), this->preset, WID_NS_PRESET_LIST);
964 break;
965 }
966
967 case WID_NS_OPEN_URL: {
968 const GRFConfig *c = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel;
969
970 OpenBrowser(c->GetURL());
971 break;
972 }
973
975 ShowSavePresetWindow((this->preset == -1) ? nullptr : this->grf_presets[this->preset].c_str());
976 break;
977
979 if (this->preset == -1) return;
980
981 DeleteGRFPresetFromConfig(this->grf_presets[this->preset].c_str());
982 this->grf_presets = GetGRFPresetList();
983 this->preset = -1;
984 this->InvalidateData();
985 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
986 break;
987
988 case WID_NS_MOVE_UP: { // Move GRF up
989 if (this->active_sel == nullptr || !this->editable) break;
990
991 int pos = 0;
992 for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) {
993 GRFConfig *c = *pc;
994 if (c->next == this->active_sel) {
995 c->next = this->active_sel->next;
996 this->active_sel->next = c;
997 *pc = this->active_sel;
998 break;
999 }
1000 }
1001 this->vscroll->ScrollTowards(pos);
1002 this->preset = -1;
1004 break;
1005 }
1006
1007 case WID_NS_MOVE_DOWN: { // Move GRF down
1008 if (this->active_sel == nullptr || !this->editable) break;
1009
1010 int pos = 1; // Start at 1 as we swap the selected newgrf with the next one
1011 for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) {
1012 GRFConfig *c = *pc;
1013 if (c == this->active_sel) {
1014 *pc = c->next;
1015 c->next = c->next->next;
1016 (*pc)->next = c;
1017 break;
1018 }
1019 }
1020 this->vscroll->ScrollTowards(pos);
1021 this->preset = -1;
1023 break;
1024 }
1025
1026 case WID_NS_FILE_LIST: { // Select an active GRF.
1028
1029 uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top);
1030
1031 GRFConfig *c;
1032 for (c = this->actives; c != nullptr && i > 0; c = c->next, i--) {}
1033
1034 if (this->active_sel != c) {
1037 }
1038 this->active_sel = c;
1039 this->avail_sel = nullptr;
1040 this->avail_pos = -1;
1041
1042 this->InvalidateData();
1043 if (click_count == 1) {
1044 if (this->editable && this->active_sel != nullptr) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1045 break;
1046 }
1047 /* With double click, continue */
1048 [[fallthrough]];
1049 }
1050
1051 case WID_NS_REMOVE: { // Remove GRF
1052 if (this->active_sel == nullptr || !this->editable) break;
1055
1056 /* Choose the next GRF file to be the selected file. */
1057 GRFConfig *newsel = this->active_sel->next;
1058 for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next) {
1059 GRFConfig *c = *pc;
1060 /* If the new selection is empty (i.e. we're deleting the last item
1061 * in the list, pick the file just before the selected file */
1062 if (newsel == nullptr && c->next == this->active_sel) newsel = c;
1063
1064 if (c == this->active_sel) {
1065 if (newsel == c) newsel = nullptr;
1066
1067 *pc = c->next;
1068 delete c;
1069 break;
1070 }
1071 }
1072
1073 this->active_sel = newsel;
1074 this->preset = -1;
1075 this->avail_pos = -1;
1076 this->avail_sel = nullptr;
1077 this->avails.ForceRebuild();
1079 break;
1080 }
1081
1082 case WID_NS_UPGRADE: { // Upgrade GRF.
1083 if (!this->editable || this->actives == nullptr) break;
1086 break;
1087 }
1088
1089 case WID_NS_AVAIL_LIST: { // Select a non-active GRF.
1091
1092 auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.top);
1093 this->active_sel = nullptr;
1095 if (it != this->avails.end()) {
1096 if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE);
1097 this->avail_sel = *it;
1098 this->avail_pos = it - this->avails.begin();
1099 }
1100 this->InvalidateData();
1101 if (click_count == 1) {
1102 if (this->editable && this->avail_sel != nullptr && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1103 break;
1104 }
1105 /* With double click, continue */
1106 [[fallthrough]];
1107 }
1108
1109 case WID_NS_ADD:
1110 if (this->avail_sel == nullptr || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break;
1111
1112 this->AddGRFToActive();
1113 break;
1114
1115 case WID_NS_APPLY_CHANGES: // Apply changes made to GRF list
1116 if (!this->editable) break;
1117 if (this->execute) {
1118 ShowQuery(
1121 this,
1123 );
1124 } else {
1125 CopyGRFConfigList(this->orig_list, this->actives, true);
1126 ResetGRFConfig(false);
1129 }
1130 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1131 break;
1132
1134 case WID_NS_SET_PARAMETERS: { // Edit parameters
1135 if (this->active_sel == nullptr || !this->show_params || this->active_sel->num_valid_params == 0) break;
1136
1137 OpenGRFParameterWindow(false, this->active_sel, this->editable);
1139 break;
1140 }
1141
1143 if (this->active_sel != nullptr && this->editable) {
1144 this->active_sel->palette ^= GRFP_USE_MASK;
1145 this->SetDirty();
1147 }
1148 break;
1149
1152 if (!_network_available) {
1154 } else {
1155 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1156
1157 ShowMissingContentWindow(this->actives);
1158 }
1159 break;
1160
1163 RequestNewGRFScan(this);
1164 break;
1165 }
1166 }
1167
1168 void OnNewGRFsScanned() override
1169 {
1170 if (this->active_sel == nullptr) CloseWindowByClass(WC_TEXTFILE);
1171 this->avail_sel = nullptr;
1172 this->avail_pos = -1;
1173 this->avails.ForceRebuild();
1174 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1175 }
1176
1177 void OnDropdownSelect(WidgetID widget, int index) override
1178 {
1179 if (widget != WID_NS_PRESET_LIST) return;
1180 if (!this->editable) return;
1181
1182 ClearGRFConfigList(&this->actives);
1183 this->preset = index;
1184
1185 if (index != -1) {
1186 this->actives = LoadGRFPresetFromConfig(this->grf_presets[index].c_str());
1187 }
1188 this->avails.ForceRebuild();
1189
1193 this->active_sel = nullptr;
1195 }
1196
1197 void OnQueryTextFinished(std::optional<std::string> str) override
1198 {
1199 if (!str.has_value()) return;
1200
1201 SaveGRFPresetToConfig(str->c_str(), this->actives);
1202 this->grf_presets = GetGRFPresetList();
1203
1204 /* Switch to this preset */
1205 for (uint i = 0; i < this->grf_presets.size(); i++) {
1206 if (this->grf_presets[i] == str) {
1207 this->preset = i;
1208 break;
1209 }
1210 }
1211
1212 this->InvalidateData();
1213 }
1214
1219 {
1220 /* Update scrollbars */
1221 int i = 0;
1222 for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {}
1223
1224 this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling.
1225
1226 if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos);
1227 }
1228
1234 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1235 {
1236 if (!gui_scope) return;
1237 switch (data) {
1238 default:
1239 /* Nothing important to do */
1240 break;
1241
1243 /* Search the list for items that are now found and mark them as such. */
1244 for (GRFConfig **l = &this->actives; *l != nullptr; l = &(*l)->next) {
1245 GRFConfig *c = *l;
1246 bool compatible = HasBit(c->flags, GCF_COMPATIBLE);
1247 if (c->status != GCS_NOT_FOUND && !compatible) continue;
1248
1249 const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum);
1250 if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue;
1251
1252 *l = new GRFConfig(*f);
1253 (*l)->next = c->next;
1254
1255 if (this->active_sel == c) this->active_sel = *l;
1256
1257 delete c;
1258 }
1259
1260 this->avails.ForceRebuild();
1261 [[fallthrough]];
1262
1264 this->modified = false;
1266 break;
1267
1269 this->preset = -1;
1270 [[fallthrough]];
1271
1274
1275 /* Changes have been made to the list of active NewGRFs */
1276 this->modified = true;
1277
1278 break;
1279
1281 /* No changes have been made to the list of active NewGRFs since the last time the changes got applied */
1282 this->modified = false;
1283 break;
1284 }
1285
1286 this->BuildAvailables();
1287
1288 this->SetWidgetDisabledState(WID_NS_APPLY_CHANGES, !((this->editable && this->modified) || _settings_client.gui.newgrf_developer_tools));
1289 this->SetWidgetsDisabledState(!this->editable,
1292 );
1293 this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == nullptr || HasBit(this->avail_sel->flags, GCF_INVALID));
1294 this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives == nullptr || !this->CanUpgradeCurrent());
1295
1296 bool disable_all = this->active_sel == nullptr || !this->editable;
1297 this->SetWidgetsDisabledState(disable_all,
1301 );
1302
1303 const GRFConfig *selected_config = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel;
1304 for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
1305 this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, selected_config == nullptr || !selected_config->GetTextfile(tft).has_value());
1306 }
1307 this->SetWidgetDisabledState(WID_NS_OPEN_URL, selected_config == nullptr || StrEmpty(selected_config->GetURL()));
1308
1309 this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0);
1310 this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0);
1311 this->SetWidgetDisabledState(WID_NS_TOGGLE_PALETTE, disable_all ||
1313
1314 if (!disable_all) {
1315 /* All widgets are now enabled, so disable widgets we can't use */
1316 if (this->active_sel == this->actives) this->DisableWidget(WID_NS_MOVE_UP);
1317 if (this->active_sel->next == nullptr) this->DisableWidget(WID_NS_MOVE_DOWN);
1318 }
1319
1320 this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1);
1321
1322 bool has_missing = false;
1323 bool has_compatible = false;
1324 for (const GRFConfig *c = this->actives; !has_missing && c != nullptr; c = c->next) {
1327 }
1328 uint32_t widget_data;
1329 StringID tool_tip;
1330 if (has_missing || has_compatible) {
1333 } else {
1334 widget_data = STR_INTRO_ONLINE_CONTENT;
1336 }
1337 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->widget_data = widget_data;
1338 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->tool_tip = tool_tip;
1339 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->widget_data = widget_data;
1340 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->tool_tip = tool_tip;
1341
1342 this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing);
1343 }
1344
1345 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
1346 {
1347 if (!this->editable) return ES_NOT_HANDLED;
1348
1349 if (this->vscroll2->UpdateListPositionOnKeyPress(this->avail_pos, keycode) == ES_NOT_HANDLED) return ES_NOT_HANDLED;
1350
1351 if (this->avail_pos >= 0) {
1352 this->active_sel = nullptr;
1354 if (this->avail_sel != this->avails[this->avail_pos]) CloseWindowByClass(WC_TEXTFILE);
1355 this->avail_sel = this->avails[this->avail_pos];
1356 this->vscroll2->ScrollTowards(this->avail_pos);
1357 this->InvalidateData(0);
1358 }
1359
1360 return ES_HANDLED;
1361 }
1362
1363 void OnEditboxChanged(WidgetID widget) override
1364 {
1365 if (!this->editable) return;
1366
1367 if (widget == WID_NS_FILTER) {
1368 string_filter.SetFilterTerm(this->filter_editbox.text.buf);
1369 this->avails.SetFilterState(!string_filter.IsEmpty());
1370 this->avails.ForceRebuild();
1371 this->InvalidateData(0);
1372 }
1373 }
1374
1375 void OnDragDrop(Point pt, WidgetID widget) override
1376 {
1377 if (!this->editable) return;
1378
1379 if (widget == WID_NS_FILE_LIST) {
1380 if (this->active_sel != nullptr) {
1381 /* Get pointer to the selected file in the active list. */
1382 int from_pos = 0;
1384 for (from_prev = &this->actives; *from_prev != this->active_sel; from_prev = &(*from_prev)->next, from_pos++) {}
1385
1386 /* Gets the drag-and-drop destination offset. Ignore the last dummy line. */
1387 int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 2);
1388 if (to_pos != from_pos) { // Don't move NewGRF file over itself.
1389 /* Get pointer to destination position. */
1390 GRFConfig **to_prev = &this->actives;
1391 for (int i = from_pos < to_pos ? -1 : 0; *to_prev != nullptr && i < to_pos; to_prev = &(*to_prev)->next, i++) {}
1392
1393 /* Detach NewGRF file from its original position. */
1394 *from_prev = this->active_sel->next;
1395
1396 /* Attach NewGRF file to its new position. */
1397 this->active_sel->next = *to_prev;
1398 *to_prev = this->active_sel;
1399
1400 this->vscroll->ScrollTowards(to_pos);
1401 this->preset = -1;
1402 this->InvalidateData();
1403 }
1404 } else if (this->avail_sel != nullptr) {
1405 int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 1);
1406 this->AddGRFToActive(to_pos);
1407 }
1408 } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) {
1409 /* Remove active NewGRF file by dragging it over available list. */
1410 Point dummy = {-1, -1};
1411 this->OnClick(dummy, WID_NS_REMOVE, 1);
1412 }
1413
1415
1416 if (this->active_over != -1) {
1417 /* End of drag-and-drop, hide dragged destination highlight. */
1418 this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
1419 this->active_over = -1;
1420 }
1421 }
1422
1423 void OnMouseDrag(Point pt, WidgetID widget) override
1424 {
1425 if (!this->editable) return;
1426
1427 if (widget == WID_NS_FILE_LIST && (this->active_sel != nullptr || this->avail_sel != nullptr)) {
1428 /* An NewGRF file is dragged over the active list. */
1430 /* Skip the last dummy line if the source is from the active list. */
1431 to_pos = std::min(to_pos, this->vscroll->GetCount() - (this->active_sel != nullptr ? 2 : 1));
1432
1433 if (to_pos != this->active_over) {
1434 this->active_over = to_pos;
1436 }
1437 } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) {
1438 this->active_over = -2;
1440 } else if (this->active_over != -1) {
1441 this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
1442 this->active_over = -1;
1443 }
1444 }
1445
1446private:
1448 static bool NameSorter(const GRFConfig * const &a, const GRFConfig * const &b)
1449 {
1450 int i = StrNaturalCompare(a->GetName(), b->GetName(), true); // Sort by name (natural sorting).
1451 if (i != 0) return i < 0;
1452
1453 i = a->version - b->version;
1454 if (i != 0) return i < 0;
1455
1456 return a->ident.md5sum < b->ident.md5sum;
1457 }
1458
1460 static bool TagNameFilter(const GRFConfig * const *a, StringFilter &filter)
1461 {
1462 filter.ResetState();
1463 filter.AddLine((*a)->GetName());
1464 filter.AddLine((*a)->filename);
1465 filter.AddLine((*a)->GetDescription());
1466 return filter.GetState();;
1467 }
1468
1469 void BuildAvailables()
1470 {
1471 if (!this->avails.NeedRebuild()) return;
1472
1473 this->avails.clear();
1474
1475 for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) {
1476 bool found = false;
1477 for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum);
1478 if (found) continue;
1479
1481 this->avails.push_back(c);
1482 } else {
1484 /* Never triggers; FindGRFConfig returns either c, or a newer version of c. */
1485 assert(best != nullptr);
1486
1487 /*
1488 * If the best version is 0, then all NewGRF with this GRF ID
1489 * have version 0, so for backward compatibility reasons we
1490 * want to show them all.
1491 * If we are the best version, then we definitely want to
1492 * show that NewGRF!.
1493 */
1494 if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) {
1495 this->avails.push_back(c);
1496 }
1497 }
1498 }
1499
1500 this->avails.Filter(this->string_filter);
1501 this->avails.RebuildDone();
1502 this->avails.Sort();
1503
1504 if (this->avail_sel != nullptr) {
1505 this->avail_pos = find_index(this->avails, this->avail_sel);
1506 if (this->avail_pos == -1) {
1507 this->avail_sel = nullptr;
1508 }
1509 }
1510
1511 this->vscroll2->SetCount(this->avails.size()); // Update the scrollbar
1512 }
1513
1520 {
1521 if (this->avail_sel == nullptr || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) return false;
1522
1524
1525 uint count = 0;
1526 GRFConfig **entry = nullptr;
1527 GRFConfig **list;
1528 /* Find last entry in the list, checking for duplicate grfid on the way */
1529 for (list = &this->actives; *list != nullptr; list = &(*list)->next, ins_pos--) {
1530 if (ins_pos == 0) entry = list; // Insert position? Save.
1531 if ((*list)->ident.grfid == this->avail_sel->ident.grfid) {
1533 return false;
1534 }
1535 if (!HasBit((*list)->flags, GCF_STATIC)) count++;
1536 }
1537 if (entry == nullptr) entry = list;
1538 if (count >= NETWORK_MAX_GRF_COUNT) {
1540 return false;
1541 }
1542
1543 GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list.
1545
1546 /* Insert GRF config to configuration list. */
1547 c->next = *entry;
1548 *entry = c;
1549
1550 /* Select next (or previous, if last one) item in the list. */
1551 int new_pos = this->avail_pos + 1;
1552 if (new_pos >= (int)this->avails.size()) new_pos = this->avail_pos - 1;
1553 this->avail_pos = new_pos;
1554 if (new_pos >= 0) this->avail_sel = this->avails[new_pos];
1555
1556 this->avails.ForceRebuild();
1558 return true;
1559 }
1560};
1561
1567{
1568 /* Only show the things in the current list, or everything when nothing's selected */
1569 ContentVector cv;
1570 for (const GRFConfig *c = list; c != nullptr; c = c->next) {
1571 if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue;
1572
1573 ContentInfo *ci = new ContentInfo();
1576 ci->name = c->GetName();
1577 ci->unique_id = BSWAP32(c->ident.grfid);
1579 cv.push_back(ci);
1580 }
1581 ShowNetworkContentListWindow(cv.empty() ? nullptr : &cv, CONTENT_TYPE_NEWGRF);
1582}
1583
1586
1587const std::initializer_list<NewGRFWindow::GUIGRFConfigList::SortFunction * const> NewGRFWindow::sorter_funcs = {
1588 &NameSorter,
1589};
1590
1591const std::initializer_list<NewGRFWindow::GUIGRFConfigList::FilterFunction * const> NewGRFWindow::filter_funcs = {
1592 &TagNameFilter,
1593};
1594
1602public:
1603 static const uint MAX_EXTRA_INFO_WIDTH;
1604 static const uint MIN_EXTRA_FOR_3_COLUMNS;
1605
1606 std::unique_ptr<NWidgetBase> avs;
1607 std::unique_ptr<NWidgetBase> acs;
1608 std::unique_ptr<NWidgetBase> inf;
1610
1611 NWidgetNewGRFDisplay(std::unique_ptr<NWidgetBase> &&avs, std::unique_ptr<NWidgetBase> &&acs, std::unique_ptr<NWidgetBase> &&inf) : NWidgetBase(NWID_CUSTOM)
1612 , avs(std::move(avs))
1613 , acs(std::move(acs))
1614 , inf(std::move(inf))
1615 , editable(true) // Temporary setting, 'real' value is set in SetupSmallestSize().
1616 {
1617 }
1618
1619 void SetupSmallestSize(Window *w) override
1620 {
1621 /* Copy state flag from the window. */
1622 assert(dynamic_cast<NewGRFWindow *>(w) != nullptr);
1623 NewGRFWindow *ngw = (NewGRFWindow *)w;
1624 this->editable = ngw->editable;
1625
1626 this->avs->SetupSmallestSize(w);
1627 this->acs->SetupSmallestSize(w);
1628 this->inf->SetupSmallestSize(w);
1629
1630 uint min_avs_width = this->avs->smallest_x + this->avs->padding.Horizontal();
1631 uint min_acs_width = this->acs->smallest_x + this->acs->padding.Horizontal();
1632 uint min_inf_width = this->inf->smallest_x + this->inf->padding.Horizontal();
1633
1634 uint min_avs_height = this->avs->smallest_y + this->avs->padding.Vertical();
1635 uint min_acs_height = this->acs->smallest_y + this->acs->padding.Vertical();
1636 uint min_inf_height = this->inf->smallest_y + this->inf->padding.Vertical();
1637
1638 /* Smallest window is in two column mode. */
1639 this->smallest_x = std::max(min_avs_width, min_acs_width) + WidgetDimensions::scaled.hsep_wide + min_inf_width;
1640 this->smallest_y = std::max(min_inf_height, min_acs_height + WidgetDimensions::scaled.vsep_wide + min_avs_height);
1641
1642 /* Filling. */
1643 this->fill_x = std::lcm(this->avs->fill_x, this->acs->fill_x);
1644 if (this->inf->fill_x > 0 && (this->fill_x == 0 || this->fill_x > this->inf->fill_x)) this->fill_x = this->inf->fill_x;
1645
1646 this->fill_y = this->avs->fill_y;
1647 if (this->acs->fill_y > 0 && (this->fill_y == 0 || this->fill_y > this->acs->fill_y)) this->fill_y = this->acs->fill_y;
1648 this->fill_y = std::lcm(this->fill_y, this->inf->fill_y);
1649
1650 /* Resizing. */
1651 this->resize_x = std::lcm(this->avs->resize_x, this->acs->resize_x);
1652 if (this->inf->resize_x > 0 && (this->resize_x == 0 || this->resize_x > this->inf->resize_x)) this->resize_x = this->inf->resize_x;
1653
1654 this->resize_y = this->avs->resize_y;
1655 if (this->acs->resize_y > 0 && (this->resize_y == 0 || this->resize_y > this->acs->resize_y)) this->resize_y = this->acs->resize_y;
1656 this->resize_y = std::lcm(this->resize_y, this->inf->resize_y);
1657
1658 /* Make sure the height suits the 3 column (resp. not-editable) format; the 2 column format can easily fill space between the lists */
1659 this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y);
1660 }
1661
1662 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
1663 {
1664 this->StoreSizePosition(sizing, x, y, given_width, given_height);
1665
1666 uint min_avs_width = this->avs->smallest_x + this->avs->padding.Horizontal();
1667 uint min_acs_width = this->acs->smallest_x + this->acs->padding.Horizontal();
1668 uint min_inf_width = this->inf->smallest_x + this->inf->padding.Horizontal();
1669
1670 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).
1671 uint avs_extra_width = min_list_width - min_avs_width; // Additional width needed for avs to reach min_list_width.
1672 uint acs_extra_width = min_list_width - min_acs_width; // Additional width needed for acs to reach min_list_width.
1673
1674 /* Use 2 or 3 columns? */
1675 uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * WidgetDimensions::scaled.hsep_wide;
1676 uint min_two_columns = min_list_width + min_inf_width + WidgetDimensions::scaled.hsep_wide;
1677 bool use_three_columns = this->editable && (min_three_columns + ScaleGUITrad(MIN_EXTRA_FOR_3_COLUMNS) <= given_width);
1678
1679 /* Info panel is a separate column in both modes. Compute its width first. */
1680 uint extra_width, inf_width;
1681 if (use_three_columns) {
1682 extra_width = given_width - min_three_columns;
1683 inf_width = std::min<uint>(ScaleGUITrad(MAX_EXTRA_INFO_WIDTH), extra_width / 2);
1684 } else {
1685 extra_width = given_width - min_two_columns;
1686 inf_width = std::min<uint>(ScaleGUITrad(MAX_EXTRA_INFO_WIDTH), extra_width / 2);
1687 }
1688 inf_width = ComputeMaxSize(this->inf->smallest_x, this->inf->smallest_x + inf_width, this->inf->GetHorizontalStepSize(sizing));
1689 extra_width -= inf_width - this->inf->smallest_x;
1690
1691 uint inf_height = ComputeMaxSize(this->inf->smallest_y, given_height, this->inf->GetVerticalStepSize(sizing));
1692
1693 if (use_three_columns) {
1694 /* Three column display, first make both lists equally wide, then divide whatever is left between both lists.
1695 * Only keep track of what avs gets, all other space goes to acs. */
1696 uint avs_width = std::min(avs_extra_width, extra_width);
1697 extra_width -= avs_width;
1698 extra_width -= std::min(acs_extra_width, extra_width);
1699 avs_width += extra_width / 2;
1700
1701 avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_width, this->avs->GetHorizontalStepSize(sizing));
1702
1703 uint acs_width = given_width - // Remaining space, including horizontal padding.
1704 inf_width - this->inf->padding.Horizontal() -
1705 avs_width - this->avs->padding.Horizontal() - 2 * WidgetDimensions::scaled.hsep_wide;
1706 acs_width = ComputeMaxSize(min_acs_width, acs_width, this->acs->GetHorizontalStepSize(sizing)) -
1707 this->acs->padding.Horizontal();
1708
1709 /* Never use fill_y on these; the minimal size is chosen, so that the 3 column view looks nice */
1710 uint avs_height = ComputeMaxSize(this->avs->smallest_y, given_height, this->avs->resize_y);
1711 uint acs_height = ComputeMaxSize(this->acs->smallest_y, given_height, this->acs->resize_y);
1712
1713 /* Assign size and position to the children. */
1714 if (rtl) {
1715 x += this->inf->padding.left;
1716 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1717 x += inf_width + this->inf->padding.right + WidgetDimensions::scaled.hsep_wide;
1718 } else {
1719 x += this->avs->padding.left;
1720 this->avs->AssignSizePosition(sizing, x, y + this->avs->padding.top, avs_width, avs_height, rtl);
1721 x += avs_width + this->avs->padding.right + WidgetDimensions::scaled.hsep_wide;
1722 }
1723
1724 x += this->acs->padding.left;
1725 this->acs->AssignSizePosition(sizing, x, y + this->acs->padding.top, acs_width, acs_height, rtl);
1726 x += acs_width + this->acs->padding.right + WidgetDimensions::scaled.hsep_wide;
1727
1728 if (rtl) {
1729 x += this->avs->padding.left;
1730 this->avs->AssignSizePosition(sizing, x, y + this->avs->padding.top, avs_width, avs_height, rtl);
1731 } else {
1732 x += this->inf->padding.left;
1733 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1734 }
1735 } else {
1736 /* Two columns, all space in extra_width goes to both lists. Since the lists are underneath each other,
1737 * the column is min_list_width wide at least. */
1738 uint avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_extra_width + extra_width,
1739 this->avs->GetHorizontalStepSize(sizing));
1740 uint acs_width = ComputeMaxSize(this->acs->smallest_x, this->acs->smallest_x + acs_extra_width + extra_width,
1741 this->acs->GetHorizontalStepSize(sizing));
1742
1743 uint min_avs_height = (!this->editable) ? 0 : this->avs->smallest_y + this->avs->padding.Vertical() + WidgetDimensions::scaled.vsep_wide;
1744 uint min_acs_height = this->acs->smallest_y + this->acs->padding.Vertical();
1745 uint extra_height = given_height - min_acs_height - min_avs_height;
1746
1747 /* Never use fill_y on these; instead use WidgetDimensions::scaled.vsep_wide as filler */
1748 uint avs_height = ComputeMaxSize(this->avs->smallest_y, this->avs->smallest_y + extra_height / 2, this->avs->resize_y);
1749 if (this->editable) extra_height -= avs_height - this->avs->smallest_y;
1750 uint acs_height = ComputeMaxSize(this->acs->smallest_y, this->acs->smallest_y + extra_height, this->acs->resize_y);
1751
1752 /* Assign size and position to the children. */
1753 if (rtl) {
1754 x += this->inf->padding.left;
1755 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1756 x += inf_width + this->inf->padding.right + WidgetDimensions::scaled.hsep_wide;
1757
1758 this->acs->AssignSizePosition(sizing, x + this->acs->padding.left, y + this->acs->padding.top, acs_width, acs_height, rtl);
1759 if (this->editable) {
1760 this->avs->AssignSizePosition(sizing, x + this->avs->padding.left, y + given_height - avs_height - this->avs->padding.bottom, avs_width, avs_height, rtl);
1761 } else {
1762 this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
1763 }
1764 } else {
1765 this->acs->AssignSizePosition(sizing, x + this->acs->padding.left, y + this->acs->padding.top, acs_width, acs_height, rtl);
1766 if (this->editable) {
1767 this->avs->AssignSizePosition(sizing, x + this->avs->padding.left, y + given_height - avs_height - this->avs->padding.bottom, avs_width, avs_height, rtl);
1768 } else {
1769 this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
1770 }
1771 uint dx = this->acs->current_x + this->acs->padding.Horizontal();
1772 if (this->editable) {
1773 dx = std::max(dx, this->avs->current_x + this->avs->padding.Horizontal());
1774 }
1775 x += dx + WidgetDimensions::scaled.hsep_wide + this->inf->padding.left;
1776 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1777 }
1778 }
1779 }
1780
1781 void FillWidgetLookup(WidgetLookup &widget_lookup) override
1782 {
1783 this->avs->FillWidgetLookup(widget_lookup);
1784 this->acs->FillWidgetLookup(widget_lookup);
1785 this->inf->FillWidgetLookup(widget_lookup);
1786 }
1787
1788 NWidgetCore *GetWidgetFromPos(int x, int y) override
1789 {
1790 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
1791
1792 NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : nullptr;
1793 if (nw == nullptr) nw = this->acs->GetWidgetFromPos(x, y);
1794 if (nw == nullptr) nw = this->inf->GetWidgetFromPos(x, y);
1795 return nw;
1796 }
1797
1798 void Draw(const Window *w) override
1799 {
1800 if (this->editable) this->avs->Draw(w);
1801 this->acs->Draw(w);
1802 this->inf->Draw(w);
1803 }
1804};
1805
1808
1809static constexpr NWidgetPart _nested_newgrf_actives_widgets[] = {
1811 /* Left side, presets. */
1814 NWidget(WWT_TEXT, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_SELECT_PRESET, STR_NULL),
1815 SetPadding(0, WidgetDimensions::unscaled.hsep_wide, 0, 0),
1816 NWidget(WWT_DROPDOWN, COLOUR_YELLOW, WID_NS_PRESET_LIST), SetFill(1, 0), SetResize(1, 0),
1817 SetDataTip(STR_JUST_STRING1, STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP),
1818 EndContainer(),
1820 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_SAVE), SetFill(1, 0), SetResize(1, 0),
1821 SetDataTip(STR_NEWGRF_SETTINGS_PRESET_SAVE, STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP),
1822 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_DELETE), SetFill(1, 0), SetResize(1, 0),
1823 SetDataTip(STR_NEWGRF_SETTINGS_PRESET_DELETE, STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP),
1824 EndContainer(),
1825 EndContainer(),
1826
1827 NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_ACTIVE_LIST, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1828 /* Left side, active grfs. */
1830 NWidget(WWT_PANEL, COLOUR_MAUVE),
1831 NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_FILE_LIST), SetMinimalSize(100, 1), SetPadding(2),
1832 SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLLBAR), SetDataTip(STR_NULL, STR_NEWGRF_SETTINGS_FILE_TOOLTIP),
1833 EndContainer(),
1834 EndContainer(),
1836 EndContainer(),
1837
1838 /* Buttons. */
1839 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_REMOVE),
1841 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_REMOVE), SetFill(1, 0), SetResize(1, 0),
1842 SetDataTip(STR_NEWGRF_SETTINGS_REMOVE, STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP),
1844 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_UP), SetFill(1, 0), SetResize(1, 0),
1845 SetDataTip(STR_NEWGRF_SETTINGS_MOVEUP, STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP),
1846 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_DOWN), SetFill(1, 0), SetResize(1, 0),
1847 SetDataTip(STR_NEWGRF_SETTINGS_MOVEDOWN, STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP),
1848 EndContainer(),
1849 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_UPGRADE), SetFill(1, 0), SetResize(1, 0),
1850 SetDataTip(STR_NEWGRF_SETTINGS_UPGRADE, STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP),
1851 EndContainer(),
1852
1854 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES2), SetFill(1, 0), SetResize(1, 0),
1855 SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
1856 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD2), SetFill(1, 0), SetResize(1, 0),
1857 SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
1858 EndContainer(),
1859 EndContainer(),
1860 EndContainer(),
1861 EndContainer(),
1862};
1863
1864static constexpr NWidgetPart _nested_newgrf_availables_widgets[] = {
1865 NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_INACTIVE_LIST, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1866 /* Left side, available grfs, filter edit box. */
1868 NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_NEWGRF_FILTER_TITLE, STR_NULL),
1869 NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_NS_FILTER), SetFill(1, 0), SetResize(1, 0),
1870 SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
1871 EndContainer(),
1872
1873 /* Left side, available grfs. */
1875 NWidget(WWT_PANEL, COLOUR_MAUVE),
1876 NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_AVAIL_LIST), SetMinimalSize(100, 1), SetPadding(2),
1878 EndContainer(),
1879 EndContainer(),
1881 EndContainer(),
1882
1883 /* Left side, available grfs, buttons. */
1885 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_ADD), SetFill(1, 0), SetResize(1, 0),
1886 SetDataTip(STR_NEWGRF_SETTINGS_ADD, STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP),
1888 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES), SetFill(1, 0), SetResize(1, 0),
1889 SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
1890 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD), SetFill(1, 0), SetResize(1, 0),
1891 SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
1892 EndContainer(),
1893 EndContainer(),
1894 EndContainer(),
1895};
1896
1897static constexpr NWidgetPart _nested_newgrf_infopanel_widgets[] = {
1899 /* Right side, info panel. */
1900 NWidget(WWT_PANEL, COLOUR_MAUVE),
1901 NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0),
1902 NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(150, 100),
1903 EndContainer(),
1904
1905 /* Right side, info buttons. */
1908 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_OPEN_URL), SetFill(1, 0), SetResize(1, 0),
1909 SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1911 SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1912 EndContainer(),
1915 SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1917 SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1918 EndContainer(),
1919 EndContainer(),
1920
1921 /* Right side, config buttons. */
1922 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_APPLY),
1925 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
1926 SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL),
1927 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0),
1928 SetDataTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP),
1929 EndContainer(),
1930 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0),
1931 SetDataTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES, STR_NULL),
1932 EndContainer(),
1933 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_VIEW_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
1934 SetDataTip(STR_NEWGRF_SETTINGS_SHOW_PARAMETERS, STR_NULL),
1935 EndContainer(),
1936 EndContainer(),
1937};
1938
1940std::unique_ptr<NWidgetBase> NewGRFDisplay()
1941{
1942 std::unique_ptr<NWidgetBase> avs = MakeNWidgets(_nested_newgrf_availables_widgets, nullptr);
1943 std::unique_ptr<NWidgetBase> acs = MakeNWidgets(_nested_newgrf_actives_widgets, nullptr);
1944 std::unique_ptr<NWidgetBase> inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, nullptr);
1945
1946 return std::make_unique<NWidgetNewGRFDisplay>(std::move(avs), std::move(acs), std::move(inf));
1947}
1948
1949/* Widget definition of the manage newgrfs window */
1950static constexpr NWidgetPart _nested_newgrf_widgets[] = {
1952 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
1953 NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1954 NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
1955 EndContainer(),
1956 NWidget(WWT_PANEL, COLOUR_MAUVE),
1958 /* Resize button. */
1960 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1961 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), SetDataTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1962 EndContainer(),
1963 EndContainer(),
1964};
1965
1966/* Window definition of the manage newgrfs window */
1967static WindowDesc _newgrf_desc(
1968 WDP_CENTER, "settings_newgrf", 300, 263,
1970 0,
1971 _nested_newgrf_widgets
1972);
1973
1979static void NewGRFConfirmationCallback(Window *w, bool confirmed)
1980{
1981 if (confirmed) {
1984 NewGRFWindow *nw = dynamic_cast<NewGRFWindow*>(w);
1985
1987 _gamelog.GRFUpdate(_grfconfig, nw->actives); // log GRF changes
1988 CopyGRFConfigList(nw->orig_list, nw->actives, false);
1991
1992 /* Show new, updated list */
1993 GRFConfig *c;
1994 int i = 0;
1995 for (c = nw->actives; c != nullptr && c != nw->active_sel; c = c->next, i++) {}
1996 CopyGRFConfigList(&nw->actives, *nw->orig_list, false);
1997 for (c = nw->actives; c != nullptr && i > 0; c = c->next, i--) {}
1998 nw->active_sel = c;
1999 nw->avails.ForceRebuild();
2000 nw->modified = false;
2001
2002 w->InvalidateData();
2003
2004 ReInitAllWindows(false);
2006 }
2007}
2008
2009
2010
2019void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
2020{
2022 new NewGRFWindow(_newgrf_desc, editable, show_params, exec_changes, config);
2023}
2024
2028 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2029 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_SAVE_PRESET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2030 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
2031 EndContainer(),
2032 NWidget(WWT_PANEL, COLOUR_GREY),
2034 NWidget(WWT_INSET, COLOUR_GREY, WID_SVP_PRESET_LIST), SetPadding(2, 1, 2, 2),
2035 SetDataTip(0x0, STR_SAVE_PRESET_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SVP_SCROLLBAR), EndContainer(),
2037 EndContainer(),
2038 EndContainer(),
2039 NWidget(WWT_PANEL, COLOUR_GREY),
2040 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SVP_EDITBOX), SetPadding(2, 2, 2, 2), SetFill(1, 0), SetResize(1, 0),
2041 SetDataTip(STR_SAVE_PRESET_TITLE, STR_SAVE_PRESET_EDITBOX_TOOLTIP),
2042 EndContainer(),
2044 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_CANCEL), SetDataTip(STR_SAVE_PRESET_CANCEL, STR_SAVE_PRESET_CANCEL_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2045 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_SAVE), SetDataTip(STR_SAVE_PRESET_SAVE, STR_SAVE_PRESET_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2046 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
2047 EndContainer(),
2048};
2049
2052 WDP_CENTER, "save_preset", 140, 110,
2054 WDF_MODAL,
2056);
2057
2059struct SavePresetWindow : public Window {
2064
2070 {
2071 this->presets = GetGRFPresetList();
2072 this->selected = -1;
2073 if (initial_text != nullptr) {
2074 for (uint i = 0; i < this->presets.size(); i++) {
2075 if (this->presets[i] == initial_text) {
2076 this->selected = i;
2077 break;
2078 }
2079 }
2080 }
2081
2083 this->presetname_editbox.ok_button = WID_SVP_SAVE;
2084 this->presetname_editbox.cancel_button = WID_SVP_CANCEL;
2085
2086 this->CreateNestedTree();
2087 this->vscroll = this->GetScrollbar(WID_SVP_SCROLLBAR);
2088 this->FinishInitNested(0);
2089
2090 this->vscroll->SetCount(this->presets.size());
2092 if (initial_text != nullptr) this->presetname_editbox.text.Assign(initial_text);
2093 }
2094
2096 {
2097 }
2098
2100 {
2101 switch (widget) {
2102 case WID_SVP_PRESET_LIST: {
2104 size.height = 0;
2105 for (uint i = 0; i < this->presets.size(); i++) {
2106 Dimension d = GetStringBoundingBox(this->presets[i]);
2107 size.width = std::max(size.width, d.width + padding.width);
2108 resize.height = std::max(resize.height, d.height);
2109 }
2110 size.height = ClampU((uint)this->presets.size(), 5, 20) * resize.height + padding.height;
2111 break;
2112 }
2113 }
2114 }
2115
2116 void DrawWidget(const Rect &r, WidgetID widget) const override
2117 {
2118 switch (widget) {
2119 case WID_SVP_PRESET_LIST: {
2120 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
2122
2123 uint step_height = this->GetWidget<NWidgetBase>(WID_SVP_PRESET_LIST)->resize_y;
2124 int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
2125 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2126
2127 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->presets);
2128 for (auto it = first; it != last; ++it) {
2129 int row = static_cast<int>(std::distance(std::begin(this->presets), it));
2130 if (row == this->selected) GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
2131
2132 DrawString(tr.left, tr.right, tr.top + offset_y, *it, (row == this->selected) ? TC_WHITE : TC_SILVER);
2133 tr.top += step_height;
2134 }
2135 break;
2136 }
2137 }
2138 }
2139
2140 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2141 {
2142 switch (widget) {
2143 case WID_SVP_PRESET_LIST: {
2144 auto it = this->vscroll->GetScrolledItemFromWidget(this->presets, pt.y, this, WID_SVP_PRESET_LIST);
2145 if (it != this->presets.end()) {
2146 this->selected = it - this->presets.begin();
2147 this->presetname_editbox.text.Assign(*it);
2150 }
2151 break;
2152 }
2153
2154 case WID_SVP_CANCEL:
2155 this->Close();
2156 break;
2157
2158 case WID_SVP_SAVE: {
2160 if (w != nullptr && !StrEmpty(this->presetname_editbox.text.buf)) w->OnQueryTextFinished(this->presetname_editbox.text.buf);
2161 this->Close();
2162 break;
2163 }
2164 }
2165 }
2166
2167 void OnResize() override
2168 {
2169 this->vscroll->SetCapacityFromWidget(this, WID_SVP_PRESET_LIST, WidgetDimensions::scaled.framerect.Vertical());
2170 }
2171};
2172
2177static void ShowSavePresetWindow(const char *initial_text)
2178{
2180 new SavePresetWindow(initial_text);
2181}
2182
2185 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NEWGRF_SCAN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2186 NWidget(WWT_PANEL, COLOUR_GREY),
2188 NWidget(WWT_LABEL, INVALID_COLOUR), SetDataTip(STR_NEWGRF_SCAN_MESSAGE, STR_NULL), SetFill(1, 0),
2189 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_BAR), SetFill(1, 0),
2190 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(400, 0),
2191 EndContainer(),
2192 EndContainer(),
2193};
2194
2197 WDP_CENTER, nullptr, 0, 0,
2199 0,
2201);
2202
2205 std::string last_name;
2207
2210 {
2211 this->InitNested(1);
2212 }
2213
2215 {
2216 switch (widget) {
2217 case WID_SP_PROGRESS_BAR: {
2218 SetDParamMaxValue(0, 100);
2220 /* We need some spacing for the 'border' */
2223 break;
2224 }
2225
2227 SetDParamMaxDigits(0, 4);
2228 SetDParamMaxDigits(1, 4);
2229 /* We really don't know the width. We could determine it by scanning the NewGRFs,
2230 * but this is the status window for scanning them... */
2231 size.width = std::max<uint>(size.width, GetStringBoundingBox(STR_NEWGRF_SCAN_STATUS).width + padding.width);
2233 break;
2234 }
2235 }
2236
2237 void DrawWidget(const Rect &r, WidgetID widget) const override
2238 {
2239 switch (widget) {
2240 case WID_SP_PROGRESS_BAR: {
2241 /* Draw the % complete with a bar and a text */
2242 DrawFrameRect(r, COLOUR_GREY, FR_BORDERONLY | FR_LOWERED);
2244 uint percent = scanned * 100 / std::max(1U, _settings_client.gui.last_newgrf_count);
2245 DrawFrameRect(ir.WithWidth(ir.Width() * percent / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, FR_NONE);
2246 SetDParam(0, percent);
2247 DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_GENERATION_PROGRESS, TC_FROMSTRING, SA_HOR_CENTER);
2248 break;
2249 }
2250
2252 SetDParam(0, this->scanned);
2254 DrawString(r.left, r.right, r.top, STR_NEWGRF_SCAN_STATUS, TC_FROMSTRING, SA_HOR_CENTER);
2255
2256 DrawString(r.left, r.right, r.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal, this->last_name, TC_BLACK, SA_HOR_CENTER);
2257 break;
2258 }
2259 }
2260
2266 void UpdateNewGRFScanStatus(uint num, const char *name)
2267 {
2268 if (name == nullptr) {
2269 this->last_name = GetString(STR_NEWGRF_SCAN_ARCHIVES);
2270 } else {
2271 this->last_name = name;
2272 }
2273 this->scanned = num;
2275
2276 this->SetDirty();
2277 }
2278};
2279
2285void UpdateNewGRFScanStatus(uint num, const char *name)
2286{
2288 if (w == nullptr) w = new ScanProgressWindow();
2289 w->UpdateNewGRFScanStatus(num, name);
2290}
debug_inline constexpr 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.
List template of 'things' T to sort in a GUI.
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.
void StoreSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height)
Store size and position.
uint resize_x
Horizontal resize step (0 means not resizable).
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
uint smallest_x
Smallest horizontal size of the widget in a filled window.
uint current_x
Current horizontal size (after resizing).
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint smallest_y
Smallest vertical size of the widget in a filled window.
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
uint resize_y
Vertical resize step (0 means not resizable).
uint current_y
Current vertical size (after resizing).
Base class for a 'real' widget.
NWidgetCore * GetWidgetFromPos(int x, int y) override
Retrieve a widget by its position.
Definition widget.cpp:1171
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.
NWidgetCore * GetWidgetFromPos(int x, int y) override
Retrieve a widget by its position.
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.
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.
bool IsVisible(size_type item) const
Checks whether given current item is visible in the list.
void SetCount(size_t num)
Sets the number of elements in the list.
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.
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:2377
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:2451
size_type GetCount() const
Gets the number of elements in the list.
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:2398
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
A timeout timer will fire once after the interval.
Definition timer.h:116
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:28
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:96
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.
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
@ 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.
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.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
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.
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
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:3297
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
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.
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
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...
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
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.
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.
GRFConfig ** CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only)
Copy a GRF Config list.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
void ResetGRFConfig(bool defaults)
Reset the current GRF Config to either blank or newgame settings.
@ GRFP_GRF_UNSET
The NewGRF provided no information.
@ GRFP_USE_WINDOWS
The palette state is set to use the Windows palette.
@ GRFP_BLT_32BPP
The NewGRF prefers a 32 bpp blitter.
@ GRFP_USE_MASK
Bitmask to get only the use palette use states.
@ GRFP_GRF_MASK
Bitmask to get only the NewGRF supplied information.
@ GCF_INVALID
GRF is unusable with this version of OpenTTD.
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
@ GCF_COMPATIBLE
GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches)
@ GCS_DISABLED
GRF file is disabled.
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ GCS_ACTIVATED
GRF file has been activated.
@ 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.
@ 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.
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.
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.
std::unique_ptr< NWidgetBase > NewGRFDisplay()
Construct nested container widget for managing the lists and the info panel of the NewGRF GUI.
void ShowNewGRFError()
Show the first NewGRF error we can find.
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
Setup 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.
@ WID_NS_APPLY_CHANGES
Apply changes to NewGRF config.
@ WID_NS_OPEN_URL
Open URL of NewGRF.
@ WID_NS_CONTENT_DOWNLOAD2
Open content download (active NewGRFs).
@ WID_NS_RESCAN_FILES
Rescan files (available NewGRFs).
@ WID_NS_CONTENT_DOWNLOAD
Open content download (available NewGRFs).
@ WID_NS_MOVE_UP
Move NewGRF up in active list.
@ WID_NS_SHOW_REMOVE
Select active list buttons (0 = normal, 1 = simple layout).
@ WID_NS_NEWGRF_INFO
Panel for Info on selected NewGRF.
@ WID_NS_NEWGRF_TEXTFILE
Open NewGRF readme, changelog (+1) or license (+2).
@ WID_NS_SET_PARAMETERS
Open Parameters Window for selected NewGRF for editing parameters.
@ WID_NS_ADD
Add NewGRF to active list.
@ WID_NS_MOVE_DOWN
Move NewGRF down in active list.
@ WID_NS_SCROLL2BAR
Scrollbar for available NewGRF list.
@ WID_NS_UPGRADE
Upgrade NewGRFs that have a newer version available.
@ WID_NS_PRESET_SAVE
Save list of active NewGRFs as presets.
@ WID_NS_FILTER
Filter list of available NewGRFs.
@ WID_NS_FILE_LIST
List window of active NewGRFs.
@ WID_NS_SHOW_APPLY
Select display of the buttons below the 'details'.
@ WID_NS_SCROLLBAR
Scrollbar for active NewGRF list.
@ WID_NS_PRESET_DELETE
Delete active preset.
@ WID_NS_TOGGLE_PALETTE
Toggle Palette of selected, active NewGRF.
@ WID_NS_RESCAN_FILES2
Rescan files (active NewGRFs).
@ WID_NS_NEWGRF_INFO_TITLE
Title for Info on selected NewGRF.
@ WID_NS_REMOVE
Remove NewGRF from active list.
@ WID_NS_PRESET_LIST
Active NewGRF preset.
@ WID_NS_AVAIL_LIST
List window of available NewGRFs.
@ WID_SP_PROGRESS_BAR
Simple progress bar.
@ WID_SP_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NP_NUMPAR_INC
Button to increase number of parameters.
@ WID_NP_RESET
Reset button.
@ WID_NP_NUMPAR_DEC
Button to decrease number of parameters.
@ WID_NP_SCROLLBAR
Scrollbar to scroll through all settings.
@ WID_NP_CAPTION
Caption of the window.
@ WID_NP_SETTING_DROPDOWN
Dynamically created dropdown for changing setting value.
@ WID_NP_BACKGROUND
Panel to draw the settings on.
@ WID_NP_ACCEPT
Accept button.
@ WID_NP_NUMPAR
Optional number of parameters.
@ WID_NP_SHOW_NUMPAR
NWID_SELECTION to optionally display WID_NP_NUMPAR.
@ WID_NP_SHOW_DESCRIPTION
NWID_SELECTION to optionally display parameter descriptions.
@ WID_NP_DESCRIPTION
Multi-line description of a parameter.
@ WID_SVP_SAVE
Button to save the preset.
@ WID_SVP_PRESET_LIST
List with available preset names.
@ WID_SVP_SCROLLBAR
Scrollbar for the list available preset names.
@ WID_SVP_CANCEL
Button to cancel saving the preset.
@ WID_SVP_EDITBOX
Edit box for changing the preset name.
bool RequestNewGRFScan(NewGRFScanCallback *callback)
Request a new NewGRF scan.
Definition openttd.cpp:1331
static const uint8_t PC_GREY
Grey palette colour.
static const uint8_t PC_DARK_GREY
Dark grey palette colour.
static const uint8_t PC_DARK_BLUE
Dark blue palette colour.
static const uint8_t PC_BLACK
Black palette colour.
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
GRFConfig * LoadGRFPresetFromConfig(const char *config_name)
Load a NewGRF configuration by preset-name.
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
Save a NewGRF configuration with a preset name.
void DeleteGRFPresetFromConfig(const char *config_name)
Delete a NewGRF configuration by preset name.
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.
#define SETTING_BUTTON_HEIGHT
Height of setting buttons.
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:333
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:371
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.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
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).
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.
std::vector< uint32_t > param
GRF parameters.
struct GRFConfig * next
NOSAVE: Next item in the linked list.
GRFStatus status
NOSAVE: GRFStatus, enum.
void SetValue(const GRFParameterInfo &info, uint32_t value)
Set the value of the given user-changeable parameter.
std::optional< GRFError > error
NOSAVE: Error/Warning during GRF loading (Action 0x0B)
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.
uint32_t GetValue(const GRFParameterInfo &info) const
Get the value of the given user-changeable parameter.
bool HasGrfIdentifier(uint32_t grfid, const MD5Hash *md5sum) const
Does the identification match the provided values?
uint32_t grfid
GRF ID (defined by Action 0x08)
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
Information about one grf parameter.
uint8_t param_nr
GRF parameter to store content in.
GRFParameterType type
The type 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).
Partial widget specification to allow NWidgets to be written nested.
Window for setting the parameters of a NewGRF.
bool clicked_dropdown
Whether the dropdown is open.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnPaint() override
The window must be repainted.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
bool editable
Allow editing parameters.
bool HasParameterInfo(uint nr) const
Test if GRF Parameter Info exists for a given parameter index.
static GRFParameterInfo dummy_parameter_info
Dummy info in case a newgrf didn't provide info about some parameter.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
TimeoutTimer< TimerWindow > unclick_timeout
When reset, unclick the button after a small timeout.
bool action14present
True if action14 information is present.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
int line_height
Height of a row in the matrix widget.
bool clicked_increase
True if the increase button was clicked, false for the decrease button.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
int32_t clicked_row
The selected parameter, or INT_MAX when none is selected.
bool closing_dropdown
True, if the dropdown list is currently closing.
GRFConfig * grf_config
Set the parameters of this GRFConfig.
void OnDropdownClose(Point, WidgetID widget, int, bool) override
A dropdown window associated to this window has been closed.
int32_t clicked_button
The row in which a button was clicked or INT_MAX when none is selected.
static GRFParameterInfo & GetDummyParameterInfo(uint nr)
Get a dummy parameter-info object with default information.
GRFParameterInfo & GetParameterInfo(uint nr) const
Get GRF Parameter Info exists for a given parameter index.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnResize() override
Called after the window got resized.
Callback for NewGRF scanning.
Window for displaying the textfile of a NewGRF.
const GRFConfig * grf_config
View the textfile of this GRFConfig.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
Window for showing NewGRF files.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
bool editable
Is the window editable?
void OnEditboxChanged(WidgetID widget) override
The text in an editbox has been edited.
bool CanUpgradeCurrent()
Test whether the currently active set of NewGRFs can be upgraded with the available NewGRFs.
GRFConfig * active_sel
Selected active grf item.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
bool show_params
Are the grf-parameters shown in the info-panel?
void UpgradeCurrent()
Upgrade the currently active set of NewGRFs.
void OnResize() override
Called after the window got resized.
bool AddGRFToActive(int ins_pos=-1)
Insert a GRF into the active list.
int avail_pos
Index of avail_sel if existing, else -1.
int active_over
Active GRF item over which another one is dragged, -1 if none.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnMouseDrag(Point pt, WidgetID widget) override
An 'object' is being dragged at the provided position, highlight the target if possible.
bool modified
The list of active NewGRFs has been modified since the last time they got saved.
bool execute
On pressing 'apply changes' are grf changes applied immediately, or only list is updated.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
EventState OnKeyPress(char32_t key, uint16_t keycode) override
A key has been pressed.
int preset
Selected preset or -1 if none selected.
GRFConfig ** orig_list
List active grfs in the game. Used as initial value, may be updated by the window.
StringList grf_presets
List of known NewGRF presets.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
const GRFConfig * avail_sel
Currently selected available grf. nullptr is none is selected.
void UpdateScrollBars()
Updates the scroll bars for the active and inactive NewGRF lists.
QueryString filter_editbox
Filter editbox;.
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.
void OnDragDrop(Point pt, WidgetID widget) override
A dragged 'object' has been released.
static Filtering last_filtering
Default filtering of GUIGRFConfigList.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
static const std::initializer_list< GUIGRFConfigList::SortFunction *const > sorter_funcs
Sort functions of the GUIGRFConfigList.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
static const std::initializer_list< GUIGRFConfigList::FilterFunction *const > filter_funcs
Filter functions of the GUIGRFConfigList.
PaletteID GetPalette(const GRFConfig *c) const
Pick the palette for the sprite of the grf to display.
void OnNewGRFsScanned() override
Called whenever the NewGRF scan completed.
GUIGRFConfigList avails
Available (non-active) grfs.
StringFilter string_filter
Filter for available grf.
static Listing last_sorting
Default sorting of GUIGRFConfigList.
static bool NameSorter(const GRFConfig *const &a, const GRFConfig *const &b)
Sort grfs by name.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
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.
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 UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
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.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
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.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in 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
Window for displaying a textfile.
TextfileType file_type
Type of textfile to view.
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:732
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3159
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
virtual void OnQueryTextFinished(std::optional< std::string > str)
The query window opened from this window has closed.
Definition window_gui.h:779
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:486
int top
y position of top edge of the window
Definition window_gui.h:310
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:977
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.
@ TFT_LICENSE
Content license.
@ TFT_README
Content readme.
@ TFT_CHANGELOG
Content changelog.
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
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...
@ 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:283
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:35
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
uint ComputeMaxSize(uint base, uint max_space, uint step)
Return the biggest possible size of a nested widget.
@ 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.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ 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:86
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
@ 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:85
@ 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.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
@ 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 * 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:3335
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1152
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1098
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3101
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.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_BUILD_OBJECT
Build object; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:45
@ WC_SAVE_PRESET
Save preset; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers:
@ WC_TEXTFILE
textfile; Window numbers:
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
@ WC_QUERY_STRING
Query string window; Window numbers:
@ WC_GRF_PARAMETERS
NewGRF parameters; Window numbers:
@ WC_MODAL_PROGRESS
Progress report of landscape generation; Window numbers:
@ GOID_NEWGRF_CURRENT_LOADED
The current list of active NewGRF has been loaded.
@ GOID_NEWGRF_RESCANNED
NewGRFs were just rescanned.
@ GOID_NEWGRF_CHANGES_APPLIED
The active NewGRF list changes have been applied.
@ GOID_NEWGRF_CHANGES_MADE
Changes have been made to a given NewGRF either through the palette or its parameters.
@ GOID_NEWGRF_LIST_EDITED
List of active NewGRFs is being edited.
Functions related to zooming.