OpenTTD Source 20250205-master-gfd85ab1e2c
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 auto &c : _grfconfig) {
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}", std::byteswap(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 (c.flags.Test(GRFConfigFlag::Invalid)) tr.top = DrawStringMultiLine(tr, STR_NEWGRF_SETTINGS_INCOMPATIBLE);
132 if (c.flags.Test(GRFConfigFlag::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 = (this->grf_config.num_valid_params != this->grf_config.param.size() || !this->grf_config.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);
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 = std::ranges::lower_bound(par_info.value_names, current_value, std::less{}, &GRFParameterInfo::ValueName::first);
302 if (it != std::end(par_info.value_names) && it->first == current_value) {
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
346 if (this->editable && !this->action14present && this->grf_config.param.size() < this->grf_config.num_valid_params) {
347 this->grf_config.param.emplace_back(0);
348 this->InvalidateData();
350 }
351 break;
352
353 case WID_NP_BACKGROUND: {
354 if (!this->editable) break;
355 int32_t num = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NP_BACKGROUND);
356 if (num >= this->vscroll->GetCount()) break;
357
358 if (this->clicked_row != num) {
361 this->clicked_row = num;
362 this->clicked_dropdown = false;
363 }
364
365 Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
366 int x = pt.x - r.left;
367 if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x;
368
370
371 /* One of the arrows is clicked */
372 uint32_t old_val = this->grf_config.GetValue(par_info);
373 if (par_info.type != PTYPE_BOOL && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && par_info.complete_labels) {
374 if (this->clicked_dropdown) {
375 /* unclick the dropdown */
377 this->clicked_dropdown = false;
378 this->closing_dropdown = false;
379 } else {
380 int rel_y = (pt.y - r.top) % this->line_height;
381
382 Rect wi_rect;
383 wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x);;
384 wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1;
385 wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
386 wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1;
387
388 /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */
389 if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) {
390 this->clicked_dropdown = true;
391 this->closing_dropdown = false;
392
393 DropDownList list;
394 for (const auto &[value, name] : par_info.value_names) {
395 list.push_back(MakeDropDownListStringItem(GetGRFStringFromGRFText(name), value));
396 }
397
398 ShowDropDownListAt(this, std::move(list), old_val, WID_NP_SETTING_DROPDOWN, wi_rect, COLOUR_ORANGE);
399 }
400 }
401 } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) {
403 if (par_info.type == PTYPE_BOOL) {
404 val = !val;
405 } else {
406 if (x >= SETTING_BUTTON_WIDTH / 2) {
407 /* Increase button clicked */
408 if (val < par_info.max_value) val++;
409 this->clicked_increase = true;
410 } else {
411 /* Decrease button clicked */
412 if (val > par_info.min_value) val--;
413 this->clicked_increase = false;
414 }
415 }
416 if (val != old_val) {
417 this->grf_config.SetValue(par_info, val);
418
419 this->clicked_button = num;
420 this->unclick_timeout.Reset();
421 }
422 } else if (par_info.type == PTYPE_UINT_ENUM && !par_info.complete_labels && click_count >= 2) {
423 /* Display a query box so users can enter a custom value. */
424 SetDParam(0, old_val);
426 }
427 this->SetDirty();
428 break;
429 }
430
431 case WID_NP_RESET:
432 if (!this->editable) break;
433 this->grf_config.SetParameterDefaults();
434 this->InvalidateData();
436 break;
437
438 case WID_NP_ACCEPT:
439 this->Close();
440 break;
441 }
442 }
443
444 void OnQueryTextFinished(std::optional<std::string> str) override
445 {
446 if (!str.has_value() || str->empty()) return;
447 int32_t value = atoi(str->c_str());
448 GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
449 this->grf_config.SetValue(par_info, value);
450 this->SetDirty();
451 }
452
453 void OnDropdownSelect(WidgetID widget, int index) override
454 {
455 if (widget != WID_NP_SETTING_DROPDOWN) return;
456 assert(this->clicked_dropdown);
457 GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
458 this->grf_config.SetValue(par_info, index);
459 this->SetDirty();
460 }
461
462 void OnDropdownClose(Point, WidgetID widget, int, bool) override
463 {
464 if (widget != WID_NP_SETTING_DROPDOWN) return;
465 /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
466 * the same dropdown button was clicked again, and then not open the dropdown again.
467 * So, we only remember that it was closed, and process it on the next OnPaint, which is
468 * after OnClick. */
469 assert(this->clicked_dropdown);
470 this->closing_dropdown = true;
471 this->SetDirty();
472 }
473
474 void OnResize() override
475 {
476 this->vscroll->SetCapacityFromWidget(this, WID_NP_BACKGROUND);
477 }
478
484 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
485 {
486 if (!gui_scope) return;
487 if (!this->action14present) {
488 this->SetWidgetDisabledState(WID_NP_NUMPAR_DEC, !this->editable || this->grf_config.param.empty());
489 this->SetWidgetDisabledState(WID_NP_NUMPAR_INC, !this->editable || std::size(this->grf_config.param) >= this->grf_config.num_valid_params);
490 }
491
492 this->vscroll->SetCount(this->action14present ? this->grf_config.num_valid_params : GRFConfig::MAX_NUM_PARAMS);
493 if (this->clicked_row != INT32_MAX && this->clicked_row >= this->vscroll->GetCount()) {
494 this->clicked_row = INT32_MAX;
496 }
497 }
498
500 TimeoutTimer<TimerWindow> unclick_timeout = {std::chrono::milliseconds(150), [this]() {
501 this->clicked_button = INT32_MAX;
502 this->SetDirty();
503 }};
504};
506
507
508static constexpr NWidgetPart _nested_newgrf_parameter_widgets[] = {
510 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
511 NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_NP_CAPTION),
512 NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
513 EndContainer(),
514 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_NUMPAR),
515 NWidget(WWT_PANEL, COLOUR_MAUVE), SetResize(1, 0), SetFill(1, 0), SetPIP(4, 0, 4),
516 NWidget(NWID_HORIZONTAL), SetPIP(4, 0, 4),
519 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NP_NUMPAR), SetResize(1, 0), SetFill(1, 0), SetPadding(0, 0, 0, 4), SetStringTip(STR_NEWGRF_PARAMETERS_NUM_PARAM),
520 EndContainer(),
521 EndContainer(),
522 EndContainer(),
526 EndContainer(),
528 NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NP_DESCRIPTION), SetResize(1, 0), SetFill(1, 0),
529 EndContainer(),
530 EndContainer(),
533 NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NEWGRF_PARAMETERS_CLOSE),
534 NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_RESET), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NEWGRF_PARAMETERS_RESET, STR_NEWGRF_PARAMETERS_RESET_TOOLTIP),
535 EndContainer(),
536 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
537 EndContainer(),
538};
539
542 WDP_CENTER, "settings_newgrf_config", 500, 208,
544 {},
545 _nested_newgrf_parameter_widgets
546);
547
548void OpenGRFParameterWindow(bool is_baseset, GRFConfig &c, bool editable)
549{
551 new NewGRFParametersWindow(_newgrf_parameters_desc, is_baseset, c, editable);
552}
553
557
559 {
560 this->ConstructWindow();
561
562 auto textfile = this->grf_config->GetTextfile(file_type);
563 this->LoadTextfile(textfile.value(), NEWGRF_DIR);
564 }
565
566 void SetStringParameters(WidgetID widget) const override
567 {
568 if (widget == WID_TF_CAPTION) {
570 SetDParamStr(1, this->grf_config->GetName());
571 }
572 }
573};
574
575void ShowNewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c)
576{
577 CloseWindowById(WC_TEXTFILE, file_type);
578 new NewGRFTextfileWindow(file_type, c);
579}
580
581typedef std::map<uint32_t, const GRFConfig *> GrfIdMap;
582
588static void FillGrfidMap(const GRFConfigList &lst, GrfIdMap &grfid_map)
589{
590 for (const auto &c : lst) {
591 grfid_map.emplace(c->ident.grfid, c.get());
592 }
593}
594
595static void NewGRFConfirmationCallback(Window *w, bool confirmed);
596static void ShowSavePresetWindow(const char *initial_text);
597
603
604 static const uint EDITBOX_MAX_SIZE = 50;
605
606 static Listing last_sorting;
608 static const std::initializer_list<GUIGRFConfigList::SortFunction * const> sorter_funcs;
609 static const std::initializer_list<GUIGRFConfigList::FilterFunction * const> filter_funcs;
610
616
618
619 GRFConfigList actives;
621
622 GRFConfigList &orig_list;
623 bool editable;
625 bool execute;
626 int preset;
628 bool modified;
629
630 Scrollbar *vscroll;
631 Scrollbar *vscroll2;
632
633 NewGRFWindow(WindowDesc &desc, bool editable, bool show_params, bool execute, GRFConfigList &orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE), orig_list(orig_list)
634 {
635 this->avail_sel = nullptr;
636 this->avail_pos = -1;
637 this->active_sel = nullptr;
638 this->editable = editable;
639 this->execute = execute;
640 this->show_params = show_params;
641 this->preset = -1;
642 this->active_over = -1;
643
644 CopyGRFConfigList(this->actives, orig_list, false);
645 this->grf_presets = GetGRFPresetList();
646
647 this->CreateNestedTree();
648 this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR);
649 this->vscroll2 = this->GetScrollbar(WID_NS_SCROLL2BAR);
650
651 this->GetWidget<NWidgetStacked>(WID_NS_SHOW_REMOVE)->SetDisplayedPlane(this->editable ? 0 : 1);
652 this->GetWidget<NWidgetStacked>(WID_NS_SHOW_APPLY)->SetDisplayedPlane(this->editable ? 0 : this->show_params ? 1 : SZSP_HORIZONTAL);
654
656 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
657 if (editable) {
659 } else {
661 }
662
663 this->avails.SetListing(this->last_sorting);
664 this->avails.SetFiltering(this->last_filtering);
665 this->avails.SetSortFuncs(this->sorter_funcs);
666 this->avails.SetFilterFuncs(this->filter_funcs);
667 this->avails.ForceRebuild();
668
670 }
671
672 void Close([[maybe_unused]] int data = 0) override
673 {
677
678 if (this->editable && this->modified && !this->execute && !_exit_game) {
679 CopyGRFConfigList(this->orig_list, this->actives, true);
680 ResetGRFConfig(false);
682 }
683
684 this->Window::Close();
685 }
686
687 int GetCurrentActivePosition() const
688 {
689 if (this->active_sel != nullptr) {
690 auto it = std::ranges::find_if(this->actives, [this](const auto &c) { return c.get() == this->active_sel; });
691 if (it != std::end(this->actives)) return static_cast<int>(std::distance(std::begin(this->actives), it));
692 }
693 return -1;
694 }
695
701 {
703 FillGrfidMap(this->actives, grfid_map);
704
705 for (const auto &a : _all_grfs) {
706 GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid);
707 if (iter != grfid_map.end() && a->version > iter->second->version) return true;
708 }
709 return false;
710 }
711
714 {
716 FillGrfidMap(this->actives, grfid_map);
717
718 for (const auto &a : _all_grfs) {
719 GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid);
720 if (iter == grfid_map.end() || iter->second->version >= a->version) continue;
721
722 auto c = std::ranges::find_if(this->actives, [&iter](const auto &grfconfig) { return grfconfig.get() == iter->second; });
723 assert(c != std::end(this->actives));
724 auto d = std::make_unique<GRFConfig>(*iter->second);
725 if (d->IsCompatible((*c)->version)) {
726 d->CopyParams(**c);
727 } else {
728 d->SetParameterDefaults();
729 }
730 if (this->active_sel == c->get()) {
733 this->active_sel = nullptr;
734 }
735 *c = std::move(d);
736 iter->second = c->get();
737 }
738 }
739
741 {
742 switch (widget) {
743 case WID_NS_FILE_LIST:
744 {
745 Dimension d = maxdim(GetScaledSpriteSize(SPR_SQUARE), GetScaledSpriteSize(SPR_WARNING_SIGN));
746 resize.height = std::max<uint>(d.height + 2U, GetCharacterHeight(FS_NORMAL));
747 size.height = std::max(size.height, padding.height + 6 * resize.height);
748 break;
749 }
750
752 {
753 Dimension d = maxdim(GetScaledSpriteSize(SPR_SQUARE), GetScaledSpriteSize(SPR_WARNING_SIGN));
754 resize.height = std::max<uint>(d.height + 2U, GetCharacterHeight(FS_NORMAL));
755 size.height = std::max(size.height, padding.height + 8 * resize.height);
756 break;
757 }
758
761 size.height = std::max(size.height, dim.height + WidgetDimensions::scaled.frametext.Vertical());
762 size.width = std::max(size.width, dim.width + WidgetDimensions::scaled.frametext.Horizontal());
763 break;
764 }
765
767 size.height = std::max<uint>(size.height, WidgetDimensions::scaled.framerect.Vertical() + 10 * GetCharacterHeight(FS_NORMAL));
768 break;
769
770 case WID_NS_PRESET_LIST: {
772 for (const auto &i : this->grf_presets) {
773 SetDParamStr(0, i);
775 }
776 d.width += padding.width;
777 size = maxdim(d, size);
778 break;
779 }
780
785 size.width += padding.width;
786 size.height += padding.height;
787 break;
788 }
789 }
790 }
791
792 void OnResize() override
793 {
794 this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.Vertical());
795 this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.Vertical());
796 }
797
798 void SetStringParameters(WidgetID widget) const override
799 {
800 switch (widget) {
802 if (this->preset == -1) {
804 } else {
806 SetDParamStr(1, this->grf_presets[this->preset]);
807 }
808 break;
809 }
810 }
811
817 inline PaletteID GetPalette(const GRFConfig &c) const
818 {
819 PaletteID pal;
820
821 /* Pick a colour */
822 switch (c.status) {
823 case GCS_NOT_FOUND:
824 case GCS_DISABLED:
825 pal = PALETTE_TO_RED;
826 break;
827 case GCS_ACTIVATED:
828 pal = PALETTE_TO_GREEN;
829 break;
830 default:
831 pal = PALETTE_TO_BLUE;
832 break;
833 }
834
835 /* Do not show a "not-failure" colour when it actually failed to load */
836 if (pal != PALETTE_TO_RED) {
838 pal = PALETTE_TO_GREY;
839 } else if (c.flags.Test(GRFConfigFlag::Compatible)) {
840 pal = PALETTE_TO_ORANGE;
841 }
842 }
843
844 return pal;
845 }
846
847 void DrawWidget(const Rect &r, WidgetID widget) const override
848 {
849 switch (widget) {
850 case WID_NS_FILE_LIST: {
851 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
853
854 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
855 uint step_height = this->GetWidget<NWidgetBase>(WID_NS_FILE_LIST)->resize_y;
856 Dimension square = GetSpriteSize(SPR_SQUARE);
857 Dimension warning = GetSpriteSize(SPR_WARNING_SIGN);
858 int square_offset_y = (step_height - square.height) / 2;
859 int warning_offset_y = (step_height - warning.height) / 2;
860 int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
861
862 bool rtl = _current_text_dir == TD_RTL;
863 uint text_left = rtl ? tr.left : tr.left + square.width + 13;
864 uint text_right = rtl ? tr.right - square.width - 13 : tr.right;
865 uint square_left = rtl ? tr.right - square.width - 3 : tr.left + 3;
866 uint warning_left = rtl ? tr.right - square.width - warning.width - 8 : tr.left + square.width + 8;
867
868 int i = 0;
869 for (const auto &c : this->actives) {
870 if (this->vscroll->IsVisible(i)) {
871 const char *text = c->GetName();
872 bool h = (this->active_sel == c.get());
873 PaletteID pal = this->GetPalette(*c);
874
875 if (h) {
876 GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
877 } else if (i == this->active_over) {
878 /* Get index of current selection. */
879 int active_sel_pos = this->GetCurrentActivePosition();
880 if (active_sel_pos != this->active_over) {
881 uint top = this->active_over < active_sel_pos ? tr.top + 1 : tr.top + step_height - 2;
882 GfxFillRect(tr.left, top - 1, tr.right, top + 1, PC_GREY);
883 }
884 }
885 DrawSprite(SPR_SQUARE, pal, square_left, tr.top + square_offset_y);
886 if (c->error.has_value()) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, tr.top + warning_offset_y);
887 uint txtoffset = !c->error.has_value() ? 0 : warning.width;
888 DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), tr.top + offset_y, text, h ? TC_WHITE : TC_ORANGE);
889 tr.top += step_height;
890 }
891 i++;
892 }
893 if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry.
894 GfxFillRect(tr.left, tr.top, tr.right, tr.top + 2, PC_GREY);
895 }
896 break;
897 }
898
899 case WID_NS_AVAIL_LIST: {
900 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
901 GfxFillRect(br, this->active_over == -2 ? PC_DARK_GREY : PC_BLACK);
902
903 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
904 uint step_height = this->GetWidget<NWidgetBase>(WID_NS_AVAIL_LIST)->resize_y;
905 int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
906
907 auto [first, last] = this->vscroll2->GetVisibleRangeIterators(this->avails);
908 for (auto it = first; it != last; ++it) {
909 const GRFConfig *c = *it;
910 bool h = (c == this->avail_sel);
911 const char *text = c->GetName();
912
913 if (h) GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
914 DrawString(tr.left, tr.right, tr.top + offset_y, text, h ? TC_WHITE : TC_SILVER);
915 tr.top += step_height;
916 }
917 break;
918 }
919
921 /* Create the nice grayish rectangle at the details top. */
923 DrawString(r.left, r.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
924 break;
925 }
926
927 case WID_NS_NEWGRF_INFO: {
928 const GRFConfig *selected = this->active_sel;
929 if (selected == nullptr) selected = this->avail_sel;
930 if (selected != nullptr) {
931 ShowNewGRFInfo(*selected, r, this->show_params);
932 }
933 break;
934 }
935 }
936 }
937
938 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
939 {
940 if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_CONTENT_END) {
941 if (this->active_sel == nullptr && this->avail_sel == nullptr) return;
942
943 ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != nullptr ? this->active_sel : this->avail_sel);
944 return;
945 }
946
947 switch (widget) {
948 case WID_NS_PRESET_LIST: {
949 DropDownList list;
950
951 /* Add 'None' option for clearing list */
952 list.push_back(MakeDropDownListStringItem(STR_NONE, -1));
953
954 for (uint i = 0; i < this->grf_presets.size(); i++) {
955 list.push_back(MakeDropDownListStringItem(this->grf_presets[i], i));
956 }
957
958 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
959 ShowDropDownList(this, std::move(list), this->preset, WID_NS_PRESET_LIST);
960 break;
961 }
962
963 case WID_NS_OPEN_URL: {
964 const GRFConfig *c = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel;
965
966 OpenBrowser(c->GetURL());
967 break;
968 }
969
971 ShowSavePresetWindow((this->preset == -1) ? nullptr : this->grf_presets[this->preset].c_str());
972 break;
973
975 if (this->preset == -1) return;
976
977 DeleteGRFPresetFromConfig(this->grf_presets[this->preset].c_str());
978 this->grf_presets = GetGRFPresetList();
979 this->preset = -1;
980 this->InvalidateData();
981 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
982 break;
983
984 case WID_NS_MOVE_UP: { // Move GRF up
985 if (this->active_sel == nullptr || !this->editable) break;
986
987 int pos = this->GetCurrentActivePosition();
988 if (pos <= 0) break;
989
990 std::swap(this->actives[pos - 1], this->actives[pos]);
991
992 this->vscroll->ScrollTowards(pos - 1);
993 this->preset = -1;
995 break;
996 }
997
998 case WID_NS_MOVE_DOWN: { // Move GRF down
999 if (this->active_sel == nullptr || !this->editable) break;
1000
1001 int pos = this->GetCurrentActivePosition();
1002 if (pos == -1 || static_cast<size_t>(pos) >= this->actives.size() - 1) break;
1003
1004 std::swap(this->actives[pos], this->actives[pos + 1]);
1005
1006 this->vscroll->ScrollTowards(pos + 1);
1007 this->preset = -1;
1009 break;
1010 }
1011
1012 case WID_NS_FILE_LIST: { // Select an active GRF.
1014
1015 const GRFConfig *old_sel = this->active_sel;
1016 uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top);
1017 if (i < this->actives.size()) {
1018 this->active_sel = this->actives[i].get();
1019 } else {
1020 this->active_sel = nullptr;
1021 }
1022 if (this->active_sel != old_sel) {
1025 }
1026 this->avail_sel = nullptr;
1027 this->avail_pos = -1;
1028
1029 this->InvalidateData();
1030 if (click_count == 1) {
1031 if (this->editable && this->active_sel != nullptr) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1032 break;
1033 }
1034 /* With double click, continue */
1035 [[fallthrough]];
1036 }
1037
1038 case WID_NS_REMOVE: { // Remove GRF
1039 if (this->active_sel == nullptr || !this->editable) break;
1042
1043 /* Choose the next GRF file to be the selected file. */
1044 int pos = this->GetCurrentActivePosition();
1045 if (pos < 0) break;
1046
1047 auto it = std::next(std::begin(this->actives), pos);
1048 it = this->actives.erase(it);
1049 if (this->actives.empty()) {
1050 this->active_sel = nullptr;
1051 } else if (it == std::end(this->actives)) {
1052 this->active_sel = this->actives.back().get();
1053 } else {
1054 this->active_sel = it->get();
1055 }
1056 this->preset = -1;
1057 this->avail_pos = -1;
1058 this->avail_sel = nullptr;
1059 this->avails.ForceRebuild();
1061 break;
1062 }
1063
1064 case WID_NS_UPGRADE: { // Upgrade GRF.
1065 if (!this->editable || this->actives.empty()) break;
1068 break;
1069 }
1070
1071 case WID_NS_AVAIL_LIST: { // Select a non-active GRF.
1073
1074 auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.top);
1075 this->active_sel = nullptr;
1077 if (it != std::end(this->avails)) {
1078 if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE);
1079 this->avail_sel = *it;
1080 this->avail_pos = static_cast<int>(std::distance(std::begin(this->avails), it));
1081 }
1082 this->InvalidateData();
1083 if (click_count == 1) {
1084 if (this->editable && this->avail_sel != nullptr && !this->avail_sel->flags.Test(GRFConfigFlag::Invalid)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1085 break;
1086 }
1087 /* With double click, continue */
1088 [[fallthrough]];
1089 }
1090
1091 case WID_NS_ADD:
1092 if (this->avail_sel == nullptr || !this->editable || this->avail_sel->flags.Test(GRFConfigFlag::Invalid)) break;
1093
1094 this->AddGRFToActive();
1095 break;
1096
1097 case WID_NS_APPLY_CHANGES: // Apply changes made to GRF list
1098 if (!this->editable) break;
1099 if (this->execute) {
1100 ShowQuery(
1103 this,
1105 );
1106 } else {
1107 CopyGRFConfigList(this->orig_list, this->actives, true);
1108 ResetGRFConfig(false);
1111 }
1112 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1113 break;
1114
1116 case WID_NS_SET_PARAMETERS: { // Edit parameters
1117 if (this->active_sel == nullptr || !this->show_params || this->active_sel->num_valid_params == 0) break;
1118
1119 OpenGRFParameterWindow(false, *this->active_sel, this->editable);
1121 break;
1122 }
1123
1125 if (this->active_sel != nullptr && this->editable) {
1126 this->active_sel->palette ^= GRFP_USE_MASK;
1127 this->SetDirty();
1129 }
1130 break;
1131
1134 if (!_network_available) {
1136 } else {
1137 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1138
1139 ShowMissingContentWindow(this->actives);
1140 }
1141 break;
1142
1145 RequestNewGRFScan(this);
1146 break;
1147 }
1148 }
1149
1150 void OnNewGRFsScanned() override
1151 {
1152 if (this->active_sel == nullptr) CloseWindowByClass(WC_TEXTFILE);
1153 this->avail_sel = nullptr;
1154 this->avail_pos = -1;
1155 this->avails.ForceRebuild();
1156 this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
1157 }
1158
1159 void OnDropdownSelect(WidgetID widget, int index) override
1160 {
1161 if (widget != WID_NS_PRESET_LIST) return;
1162 if (!this->editable) return;
1163
1164 ClearGRFConfigList(this->actives);
1165 this->preset = index;
1166
1167 if (index != -1) {
1168 this->actives = LoadGRFPresetFromConfig(this->grf_presets[index].c_str());
1169 }
1170 this->avails.ForceRebuild();
1171
1175 this->active_sel = nullptr;
1177 }
1178
1179 void OnQueryTextFinished(std::optional<std::string> str) override
1180 {
1181 if (!str.has_value()) return;
1182
1183 SaveGRFPresetToConfig(str->c_str(), this->actives);
1184 this->grf_presets = GetGRFPresetList();
1185
1186 /* Switch to this preset */
1187 for (uint i = 0; i < this->grf_presets.size(); i++) {
1188 if (this->grf_presets[i] == str) {
1189 this->preset = i;
1190 break;
1191 }
1192 }
1193
1194 this->InvalidateData();
1195 }
1196
1201 {
1202 /* Update scrollbars */
1203 this->vscroll->SetCount(this->actives.size() + 1); // Reserve empty space for drag and drop handling.
1204
1205 if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos);
1206 }
1207
1213 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1214 {
1215 if (!gui_scope) return;
1216 switch (data) {
1217 default:
1218 /* Nothing important to do */
1219 break;
1220
1222 /* Search the list for items that are now found and mark them as such. */
1223 for (auto &c : this->actives) {
1224 bool compatible = c->flags.Test(GRFConfigFlag::Compatible);
1225 if (c->status != GCS_NOT_FOUND && !compatible) continue;
1226
1227 const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum);
1228 if (f == nullptr || f->flags.Test(GRFConfigFlag::Invalid)) continue;
1229
1230 c = std::make_unique<GRFConfig>(*f);
1231 }
1232
1233 this->avails.ForceRebuild();
1234 [[fallthrough]];
1235
1237 this->modified = false;
1239 break;
1240
1242 this->preset = -1;
1243 [[fallthrough]];
1244
1247
1248 /* Changes have been made to the list of active NewGRFs */
1249 this->modified = true;
1250
1251 break;
1252
1254 /* No changes have been made to the list of active NewGRFs since the last time the changes got applied */
1255 this->modified = false;
1256 break;
1257 }
1258
1259 this->BuildAvailables();
1260
1261 this->SetWidgetDisabledState(WID_NS_APPLY_CHANGES, !((this->editable && this->modified) || _settings_client.gui.newgrf_developer_tools));
1262 this->SetWidgetsDisabledState(!this->editable,
1265 );
1266 this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == nullptr || this->avail_sel->flags.Test(GRFConfigFlag::Invalid));
1267 this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives.empty() || !this->CanUpgradeCurrent());
1268
1269 bool disable_all = this->active_sel == nullptr || !this->editable;
1270 this->SetWidgetsDisabledState(disable_all,
1274 );
1275
1276 const GRFConfig *selected_config = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel;
1277 for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
1278 this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, selected_config == nullptr || !selected_config->GetTextfile(tft).has_value());
1279 }
1280 this->SetWidgetDisabledState(WID_NS_OPEN_URL, selected_config == nullptr || StrEmpty(selected_config->GetURL()));
1281
1282 this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0);
1283 this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0);
1284 this->SetWidgetDisabledState(WID_NS_TOGGLE_PALETTE, disable_all ||
1286
1287 if (!disable_all) {
1288 /* All widgets are now enabled, so disable widgets we can't use */
1289 if (this->active_sel == this->actives.front().get()) this->DisableWidget(WID_NS_MOVE_UP);
1290 if (this->active_sel == this->actives.back().get()) this->DisableWidget(WID_NS_MOVE_DOWN);
1291 }
1292
1293 this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1);
1294
1295 bool has_missing = false;
1296 bool has_compatible = false;
1297 for (const auto &c : this->actives) {
1298 has_missing |= c->status == GCS_NOT_FOUND;
1300 }
1301 StringID text;
1302 StringID tool_tip;
1303 if (has_missing || has_compatible) {
1306 } else {
1309 }
1310 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->SetStringTip(text, tool_tip);
1311 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->SetStringTip(text, tool_tip);
1312
1313 this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing);
1314 }
1315
1316 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
1317 {
1318 if (!this->editable) return ES_NOT_HANDLED;
1319
1320 if (this->vscroll2->UpdateListPositionOnKeyPress(this->avail_pos, keycode) == ES_NOT_HANDLED) return ES_NOT_HANDLED;
1321
1322 if (this->avail_pos >= 0) {
1323 this->active_sel = nullptr;
1325 if (this->avail_sel != this->avails[this->avail_pos]) CloseWindowByClass(WC_TEXTFILE);
1326 this->avail_sel = this->avails[this->avail_pos];
1327 this->vscroll2->ScrollTowards(this->avail_pos);
1328 this->InvalidateData(0);
1329 }
1330
1331 return ES_HANDLED;
1332 }
1333
1334 void OnEditboxChanged(WidgetID widget) override
1335 {
1336 if (!this->editable) return;
1337
1338 if (widget == WID_NS_FILTER) {
1339 string_filter.SetFilterTerm(this->filter_editbox.text.GetText());
1340 this->avails.SetFilterState(!string_filter.IsEmpty());
1341 this->avails.ForceRebuild();
1342 this->InvalidateData(0);
1343 }
1344 }
1345
1346 void OnDragDrop(Point pt, WidgetID widget) override
1347 {
1348 if (!this->editable) return;
1349
1350 if (widget == WID_NS_FILE_LIST) {
1351 if (this->active_sel != nullptr) {
1352 int from_pos = this->GetCurrentActivePosition();
1353
1354 /* Gets the drag-and-drop destination offset. Ignore the last dummy line. */
1355 int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 2);
1356 if (to_pos != from_pos) { // Don't move NewGRF file over itself.
1357 if (to_pos > from_pos) ++to_pos;
1358
1359 auto from = std::next(std::begin(this->actives), from_pos);
1360 auto to = std::next(std::begin(this->actives), to_pos);
1361 Slide(from, std::next(from), to);
1362
1363 this->vscroll->ScrollTowards(to_pos);
1364 this->preset = -1;
1365 this->InvalidateData();
1366 }
1367 } else if (this->avail_sel != nullptr) {
1368 int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 1);
1369 this->AddGRFToActive(to_pos);
1370 }
1371 } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) {
1372 /* Remove active NewGRF file by dragging it over available list. */
1373 Point dummy = {-1, -1};
1374 this->OnClick(dummy, WID_NS_REMOVE, 1);
1375 }
1376
1378
1379 if (this->active_over != -1) {
1380 /* End of drag-and-drop, hide dragged destination highlight. */
1381 this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
1382 this->active_over = -1;
1383 }
1384 }
1385
1386 void OnMouseDrag(Point pt, WidgetID widget) override
1387 {
1388 if (!this->editable) return;
1389
1390 if (widget == WID_NS_FILE_LIST && (this->active_sel != nullptr || this->avail_sel != nullptr)) {
1391 /* An NewGRF file is dragged over the active list. */
1393 /* Skip the last dummy line if the source is from the active list. */
1394 to_pos = std::min(to_pos, this->vscroll->GetCount() - (this->active_sel != nullptr ? 2 : 1));
1395
1396 if (to_pos != this->active_over) {
1397 this->active_over = to_pos;
1399 }
1400 } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) {
1401 this->active_over = -2;
1403 } else if (this->active_over != -1) {
1404 this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
1405 this->active_over = -1;
1406 }
1407 }
1408
1409private:
1411 static bool NameSorter(const GRFConfig * const &a, const GRFConfig * const &b)
1412 {
1413 std::string name_a = StrMakeValid(a->GetName(), SVS_NONE); // Make a copy without control codes.
1414 std::string name_b = StrMakeValid(b->GetName(), SVS_NONE); // Make a copy without control codes.
1415 int i = StrNaturalCompare(name_a, name_b, true); // Sort by name (natural sorting).
1416 if (i != 0) return i < 0;
1417
1418 i = a->version - b->version;
1419 if (i != 0) return i < 0;
1420
1421 return a->ident.md5sum < b->ident.md5sum;
1422 }
1423
1425 static bool TagNameFilter(const GRFConfig * const *a, StringFilter &filter)
1426 {
1427 filter.ResetState();
1428 filter.AddLine((*a)->GetName());
1429 filter.AddLine((*a)->filename);
1430 filter.AddLine((*a)->GetDescription());
1431 return filter.GetState();;
1432 }
1433
1434 void BuildAvailables()
1435 {
1436 if (!this->avails.NeedRebuild()) return;
1437
1438 this->avails.clear();
1439
1440 for (const auto &c : _all_grfs) {
1441 if (std::ranges::any_of(this->actives, [&c](const auto &gc) { return gc->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum); })) continue;
1442
1444 this->avails.push_back(c.get());
1445 } else {
1447 /* Never triggers; FindGRFConfig returns either c, or a newer version of c. */
1448 assert(best != nullptr);
1449
1450 /*
1451 * If the best version is 0, then all NewGRF with this GRF ID
1452 * have version 0, so for backward compatibility reasons we
1453 * want to show them all.
1454 * If we are the best version, then we definitely want to
1455 * show that NewGRF!.
1456 */
1457 if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) {
1458 this->avails.push_back(c.get());
1459 }
1460 }
1461 }
1462
1463 this->avails.Filter(this->string_filter);
1464 this->avails.RebuildDone();
1465 this->avails.Sort();
1466
1467 if (this->avail_sel != nullptr) {
1468 this->avail_pos = find_index(this->avails, this->avail_sel);
1469 if (this->avail_pos == -1) {
1470 this->avail_sel = nullptr;
1471 }
1472 }
1473
1474 this->vscroll2->SetCount(this->avails.size()); // Update the scrollbar
1475 }
1476
1483 {
1484 if (this->avail_sel == nullptr || !this->editable || this->avail_sel->flags.Test(GRFConfigFlag::Invalid)) return false;
1485
1487
1488 /* Get number of non-static NewGRFs. */
1489 size_t count = std::ranges::count_if(this->actives, [](const auto &gc) { return !gc->flags.Test(GRFConfigFlag::Static); });
1490 if (count >= NETWORK_MAX_GRF_COUNT) {
1492 return false;
1493 }
1494
1495 /* Check for duplicate GRF ID. */
1496 if (std::ranges::any_of(this->actives, [&grfid = this->avail_sel->ident.grfid](const auto &gc) { return gc->ident.grfid == grfid; })) {
1498 return false;
1499 }
1500
1501 auto entry = (ins_pos >= 0 && static_cast<size_t>(ins_pos) < std::size(this->actives))
1502 ? std::next(std::begin(this->actives), ins_pos)
1503 : std::end(this->actives);
1504
1505 /* Copy GRF details from scanned list. */
1506 entry = this->actives.insert(entry, std::make_unique<GRFConfig>(*this->avail_sel));
1507 (*entry)->SetParameterDefaults();
1508
1509 /* Select next (or previous, if last one) item in the list. */
1510 int new_pos = this->avail_pos + 1;
1511 if (new_pos >= (int)this->avails.size()) new_pos = this->avail_pos - 1;
1512 this->avail_pos = new_pos;
1513 if (new_pos >= 0) this->avail_sel = this->avails[new_pos];
1514
1515 this->avails.ForceRebuild();
1517 return true;
1518 }
1519};
1520
1525void ShowMissingContentWindow(const GRFConfigList &list)
1526{
1527 /* Only show the things in the current list, or everything when nothing's selected */
1528 ContentVector cv;
1529 for (const auto &c : list) {
1530 if (c->status != GCS_NOT_FOUND && !c->flags.Test(GRFConfigFlag::Compatible)) continue;
1531
1532 ContentInfo *ci = new ContentInfo();
1535 ci->name = c->GetName();
1536 ci->unique_id = std::byteswap(c->ident.grfid);
1538 cv.push_back(ci);
1539 }
1540 ShowNetworkContentListWindow(cv.empty() ? nullptr : &cv, CONTENT_TYPE_NEWGRF);
1541}
1542
1545
1546const std::initializer_list<NewGRFWindow::GUIGRFConfigList::SortFunction * const> NewGRFWindow::sorter_funcs = {
1547 &NameSorter,
1548};
1549
1550const std::initializer_list<NewGRFWindow::GUIGRFConfigList::FilterFunction * const> NewGRFWindow::filter_funcs = {
1551 &TagNameFilter,
1552};
1553
1561public:
1562 static const uint MAX_EXTRA_INFO_WIDTH;
1563 static const uint MIN_EXTRA_FOR_3_COLUMNS;
1564
1565 std::unique_ptr<NWidgetBase> avs;
1566 std::unique_ptr<NWidgetBase> acs;
1567 std::unique_ptr<NWidgetBase> inf;
1569
1570 NWidgetNewGRFDisplay(std::unique_ptr<NWidgetBase> &&avs, std::unique_ptr<NWidgetBase> &&acs, std::unique_ptr<NWidgetBase> &&inf) : NWidgetBase(NWID_CUSTOM)
1571 , avs(std::move(avs))
1572 , acs(std::move(acs))
1573 , inf(std::move(inf))
1574 , editable(true) // Temporary setting, 'real' value is set in SetupSmallestSize().
1575 {
1576 }
1577
1578 void SetupSmallestSize(Window *w) override
1579 {
1580 /* Copy state flag from the window. */
1581 assert(dynamic_cast<NewGRFWindow *>(w) != nullptr);
1582 NewGRFWindow *ngw = (NewGRFWindow *)w;
1583 this->editable = ngw->editable;
1584
1585 this->avs->SetupSmallestSize(w);
1586 this->acs->SetupSmallestSize(w);
1587 this->inf->SetupSmallestSize(w);
1588
1589 uint min_avs_width = this->avs->smallest_x + this->avs->padding.Horizontal();
1590 uint min_acs_width = this->acs->smallest_x + this->acs->padding.Horizontal();
1591 uint min_inf_width = this->inf->smallest_x + this->inf->padding.Horizontal();
1592
1593 uint min_avs_height = this->avs->smallest_y + this->avs->padding.Vertical();
1594 uint min_acs_height = this->acs->smallest_y + this->acs->padding.Vertical();
1595 uint min_inf_height = this->inf->smallest_y + this->inf->padding.Vertical();
1596
1597 /* Smallest window is in two column mode. */
1598 this->smallest_x = std::max(min_avs_width, min_acs_width) + WidgetDimensions::scaled.hsep_wide + min_inf_width;
1599 this->smallest_y = std::max(min_inf_height, min_acs_height + WidgetDimensions::scaled.vsep_wide + min_avs_height);
1600
1601 /* Filling. */
1602 this->fill_x = std::lcm(this->avs->fill_x, this->acs->fill_x);
1603 if (this->inf->fill_x > 0 && (this->fill_x == 0 || this->fill_x > this->inf->fill_x)) this->fill_x = this->inf->fill_x;
1604
1605 this->fill_y = this->avs->fill_y;
1606 if (this->acs->fill_y > 0 && (this->fill_y == 0 || this->fill_y > this->acs->fill_y)) this->fill_y = this->acs->fill_y;
1607 this->fill_y = std::lcm(this->fill_y, this->inf->fill_y);
1608
1609 /* Resizing. */
1610 this->resize_x = std::lcm(this->avs->resize_x, this->acs->resize_x);
1611 if (this->inf->resize_x > 0 && (this->resize_x == 0 || this->resize_x > this->inf->resize_x)) this->resize_x = this->inf->resize_x;
1612
1613 this->resize_y = this->avs->resize_y;
1614 if (this->acs->resize_y > 0 && (this->resize_y == 0 || this->resize_y > this->acs->resize_y)) this->resize_y = this->acs->resize_y;
1615 this->resize_y = std::lcm(this->resize_y, this->inf->resize_y);
1616
1617 /* Make sure the height suits the 3 column (resp. not-editable) format; the 2 column format can easily fill space between the lists */
1618 this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y);
1619 }
1620
1621 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
1622 {
1623 this->StoreSizePosition(sizing, x, y, given_width, given_height);
1624
1625 uint min_avs_width = this->avs->smallest_x + this->avs->padding.Horizontal();
1626 uint min_acs_width = this->acs->smallest_x + this->acs->padding.Horizontal();
1627 uint min_inf_width = this->inf->smallest_x + this->inf->padding.Horizontal();
1628
1629 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).
1630 uint avs_extra_width = min_list_width - min_avs_width; // Additional width needed for avs to reach min_list_width.
1631 uint acs_extra_width = min_list_width - min_acs_width; // Additional width needed for acs to reach min_list_width.
1632
1633 /* Use 2 or 3 columns? */
1634 uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * WidgetDimensions::scaled.hsep_wide;
1635 uint min_two_columns = min_list_width + min_inf_width + WidgetDimensions::scaled.hsep_wide;
1636 bool use_three_columns = this->editable && (min_three_columns + ScaleGUITrad(MIN_EXTRA_FOR_3_COLUMNS) <= given_width);
1637
1638 /* Info panel is a separate column in both modes. Compute its width first. */
1639 uint extra_width, inf_width;
1640 if (use_three_columns) {
1641 extra_width = given_width - min_three_columns;
1642 inf_width = std::min<uint>(ScaleGUITrad(MAX_EXTRA_INFO_WIDTH), extra_width / 2);
1643 } else {
1644 extra_width = given_width - min_two_columns;
1645 inf_width = std::min<uint>(ScaleGUITrad(MAX_EXTRA_INFO_WIDTH), extra_width / 2);
1646 }
1647 inf_width = ComputeMaxSize(this->inf->smallest_x, this->inf->smallest_x + inf_width, this->inf->GetHorizontalStepSize(sizing));
1648 extra_width -= inf_width - this->inf->smallest_x;
1649
1650 uint inf_height = ComputeMaxSize(this->inf->smallest_y, given_height, this->inf->GetVerticalStepSize(sizing));
1651
1652 if (use_three_columns) {
1653 /* Three column display, first make both lists equally wide, then divide whatever is left between both lists.
1654 * Only keep track of what avs gets, all other space goes to acs. */
1655 uint avs_width = std::min(avs_extra_width, extra_width);
1656 extra_width -= avs_width;
1657 extra_width -= std::min(acs_extra_width, extra_width);
1658 avs_width += extra_width / 2;
1659
1660 avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_width, this->avs->GetHorizontalStepSize(sizing));
1661
1662 uint acs_width = given_width - // Remaining space, including horizontal padding.
1663 inf_width - this->inf->padding.Horizontal() -
1664 avs_width - this->avs->padding.Horizontal() - 2 * WidgetDimensions::scaled.hsep_wide;
1665 acs_width = ComputeMaxSize(min_acs_width, acs_width, this->acs->GetHorizontalStepSize(sizing)) -
1666 this->acs->padding.Horizontal();
1667
1668 /* Never use fill_y on these; the minimal size is chosen, so that the 3 column view looks nice */
1669 uint avs_height = ComputeMaxSize(this->avs->smallest_y, given_height, this->avs->resize_y);
1670 uint acs_height = ComputeMaxSize(this->acs->smallest_y, given_height, this->acs->resize_y);
1671
1672 /* Assign size and position to the children. */
1673 if (rtl) {
1674 x += this->inf->padding.left;
1675 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1676 x += inf_width + this->inf->padding.right + WidgetDimensions::scaled.hsep_wide;
1677 } else {
1678 x += this->avs->padding.left;
1679 this->avs->AssignSizePosition(sizing, x, y + this->avs->padding.top, avs_width, avs_height, rtl);
1680 x += avs_width + this->avs->padding.right + WidgetDimensions::scaled.hsep_wide;
1681 }
1682
1683 x += this->acs->padding.left;
1684 this->acs->AssignSizePosition(sizing, x, y + this->acs->padding.top, acs_width, acs_height, rtl);
1685 x += acs_width + this->acs->padding.right + WidgetDimensions::scaled.hsep_wide;
1686
1687 if (rtl) {
1688 x += this->avs->padding.left;
1689 this->avs->AssignSizePosition(sizing, x, y + this->avs->padding.top, avs_width, avs_height, rtl);
1690 } else {
1691 x += this->inf->padding.left;
1692 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1693 }
1694 } else {
1695 /* Two columns, all space in extra_width goes to both lists. Since the lists are underneath each other,
1696 * the column is min_list_width wide at least. */
1697 uint avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_extra_width + extra_width,
1698 this->avs->GetHorizontalStepSize(sizing));
1699 uint acs_width = ComputeMaxSize(this->acs->smallest_x, this->acs->smallest_x + acs_extra_width + extra_width,
1700 this->acs->GetHorizontalStepSize(sizing));
1701
1702 uint min_avs_height = (!this->editable) ? 0 : this->avs->smallest_y + this->avs->padding.Vertical() + WidgetDimensions::scaled.vsep_wide;
1703 uint min_acs_height = this->acs->smallest_y + this->acs->padding.Vertical();
1704 uint extra_height = given_height - min_acs_height - min_avs_height;
1705
1706 /* Never use fill_y on these; instead use WidgetDimensions::scaled.vsep_wide as filler */
1707 uint avs_height = ComputeMaxSize(this->avs->smallest_y, this->avs->smallest_y + extra_height / 2, this->avs->resize_y);
1708 if (this->editable) extra_height -= avs_height - this->avs->smallest_y;
1709 uint acs_height = ComputeMaxSize(this->acs->smallest_y, this->acs->smallest_y + extra_height, this->acs->resize_y);
1710
1711 /* Assign size and position to the children. */
1712 if (rtl) {
1713 x += this->inf->padding.left;
1714 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1715 x += inf_width + this->inf->padding.right + WidgetDimensions::scaled.hsep_wide;
1716
1717 this->acs->AssignSizePosition(sizing, x + this->acs->padding.left, y + this->acs->padding.top, acs_width, acs_height, rtl);
1718 if (this->editable) {
1719 this->avs->AssignSizePosition(sizing, x + this->avs->padding.left, y + given_height - avs_height - this->avs->padding.bottom, avs_width, avs_height, rtl);
1720 } else {
1721 this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
1722 }
1723 } else {
1724 this->acs->AssignSizePosition(sizing, x + this->acs->padding.left, y + this->acs->padding.top, acs_width, acs_height, rtl);
1725 if (this->editable) {
1726 this->avs->AssignSizePosition(sizing, x + this->avs->padding.left, y + given_height - avs_height - this->avs->padding.bottom, avs_width, avs_height, rtl);
1727 } else {
1728 this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
1729 }
1730 uint dx = this->acs->current_x + this->acs->padding.Horizontal();
1731 if (this->editable) {
1732 dx = std::max(dx, this->avs->current_x + this->avs->padding.Horizontal());
1733 }
1734 x += dx + WidgetDimensions::scaled.hsep_wide + this->inf->padding.left;
1735 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding.top, inf_width, inf_height, rtl);
1736 }
1737 }
1738 }
1739
1740 void FillWidgetLookup(WidgetLookup &widget_lookup) override
1741 {
1742 this->avs->FillWidgetLookup(widget_lookup);
1743 this->acs->FillWidgetLookup(widget_lookup);
1744 this->inf->FillWidgetLookup(widget_lookup);
1745 }
1746
1747 NWidgetCore *GetWidgetFromPos(int x, int y) override
1748 {
1749 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
1750
1751 NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : nullptr;
1752 if (nw == nullptr) nw = this->acs->GetWidgetFromPos(x, y);
1753 if (nw == nullptr) nw = this->inf->GetWidgetFromPos(x, y);
1754 return nw;
1755 }
1756
1757 void Draw(const Window *w) override
1758 {
1759 if (this->editable) this->avs->Draw(w);
1760 this->acs->Draw(w);
1761 this->inf->Draw(w);
1762 }
1763};
1764
1767
1768static constexpr NWidgetPart _nested_newgrf_actives_widgets[] = {
1770 /* Left side, presets. */
1773 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NEWGRF_SETTINGS_SELECT_PRESET),
1774 SetPadding(0, WidgetDimensions::unscaled.hsep_wide, 0, 0),
1775 NWidget(WWT_DROPDOWN, COLOUR_YELLOW, WID_NS_PRESET_LIST), SetFill(1, 0), SetResize(1, 0),
1776 SetStringTip(STR_JUST_STRING1, STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP),
1777 EndContainer(),
1779 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_SAVE), SetFill(1, 0), SetResize(1, 0),
1780 SetStringTip(STR_NEWGRF_SETTINGS_PRESET_SAVE, STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP),
1781 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_DELETE), SetFill(1, 0), SetResize(1, 0),
1782 SetStringTip(STR_NEWGRF_SETTINGS_PRESET_DELETE, STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP),
1783 EndContainer(),
1784 EndContainer(),
1785
1786 NWidget(WWT_FRAME, COLOUR_MAUVE), SetStringTip(STR_NEWGRF_SETTINGS_ACTIVE_LIST), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1787 /* Left side, active grfs. */
1789 NWidget(WWT_PANEL, COLOUR_MAUVE),
1790 NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_FILE_LIST), SetMinimalSize(100, 1), SetPadding(2),
1791 SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLLBAR), SetToolTip(STR_NEWGRF_SETTINGS_FILE_TOOLTIP),
1792 EndContainer(),
1793 EndContainer(),
1795 EndContainer(),
1796
1797 /* Buttons. */
1798 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_REMOVE),
1800 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_REMOVE), SetFill(1, 0), SetResize(1, 0),
1801 SetStringTip(STR_NEWGRF_SETTINGS_REMOVE, STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP),
1803 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_UP), SetFill(1, 0), SetResize(1, 0),
1804 SetStringTip(STR_NEWGRF_SETTINGS_MOVEUP, STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP),
1805 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_DOWN), SetFill(1, 0), SetResize(1, 0),
1806 SetStringTip(STR_NEWGRF_SETTINGS_MOVEDOWN, STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP),
1807 EndContainer(),
1808 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_UPGRADE), SetFill(1, 0), SetResize(1, 0),
1809 SetStringTip(STR_NEWGRF_SETTINGS_UPGRADE, STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP),
1810 EndContainer(),
1811
1813 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES2), SetFill(1, 0), SetResize(1, 0),
1814 SetStringTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
1815 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD2), SetFill(1, 0), SetResize(1, 0),
1816 SetStringTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
1817 EndContainer(),
1818 EndContainer(),
1819 EndContainer(),
1820 EndContainer(),
1821};
1822
1823static constexpr NWidgetPart _nested_newgrf_availables_widgets[] = {
1824 NWidget(WWT_FRAME, COLOUR_MAUVE), SetStringTip(STR_NEWGRF_SETTINGS_INACTIVE_LIST), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0),
1825 /* Left side, available grfs, filter edit box. */
1827 NWidget(WWT_TEXT, INVALID_COLOUR), SetFill(0, 1), SetStringTip(STR_NEWGRF_FILTER_TITLE),
1828 NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_NS_FILTER), SetFill(1, 0), SetResize(1, 0),
1829 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
1830 EndContainer(),
1831
1832 /* Left side, available grfs. */
1834 NWidget(WWT_PANEL, COLOUR_MAUVE),
1835 NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_AVAIL_LIST), SetMinimalSize(100, 1), SetPadding(2),
1837 EndContainer(),
1838 EndContainer(),
1840 EndContainer(),
1841
1842 /* Left side, available grfs, buttons. */
1844 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_ADD), SetFill(1, 0), SetResize(1, 0),
1845 SetStringTip(STR_NEWGRF_SETTINGS_ADD, STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP),
1847 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES), SetFill(1, 0), SetResize(1, 0),
1848 SetStringTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
1849 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD), SetFill(1, 0), SetResize(1, 0),
1850 SetStringTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
1851 EndContainer(),
1852 EndContainer(),
1853 EndContainer(),
1854};
1855
1856static constexpr NWidgetPart _nested_newgrf_infopanel_widgets[] = {
1858 /* Right side, info panel. */
1859 NWidget(WWT_PANEL, COLOUR_MAUVE),
1860 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0),
1861 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(150, 100),
1862 EndContainer(),
1863
1864 /* Right side, info buttons. */
1867 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_OPEN_URL), SetFill(1, 0), SetResize(1, 0),
1868 SetStringTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1870 SetStringTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1871 EndContainer(),
1874 SetStringTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1876 SetStringTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1877 EndContainer(),
1878 EndContainer(),
1879
1880 /* Right side, config buttons. */
1881 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_APPLY),
1884 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
1885 SetStringTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS),
1886 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0),
1887 SetStringTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP),
1888 EndContainer(),
1889 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0),
1890 SetStringTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES),
1891 EndContainer(),
1892 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_VIEW_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
1893 SetStringTip(STR_NEWGRF_SETTINGS_SHOW_PARAMETERS),
1894 EndContainer(),
1895 EndContainer(),
1896};
1897
1899std::unique_ptr<NWidgetBase> NewGRFDisplay()
1900{
1901 std::unique_ptr<NWidgetBase> avs = MakeNWidgets(_nested_newgrf_availables_widgets, nullptr);
1902 std::unique_ptr<NWidgetBase> acs = MakeNWidgets(_nested_newgrf_actives_widgets, nullptr);
1903 std::unique_ptr<NWidgetBase> inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, nullptr);
1904
1905 return std::make_unique<NWidgetNewGRFDisplay>(std::move(avs), std::move(acs), std::move(inf));
1906}
1907
1908/* Widget definition of the manage newgrfs window */
1909static constexpr NWidgetPart _nested_newgrf_widgets[] = {
1911 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
1912 NWidget(WWT_CAPTION, COLOUR_MAUVE), SetStringTip(STR_NEWGRF_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1913 NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
1914 EndContainer(),
1915 NWidget(WWT_PANEL, COLOUR_MAUVE),
1917 /* Resize button. */
1919 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1920 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1921 EndContainer(),
1922 EndContainer(),
1923};
1924
1925/* Window definition of the manage newgrfs window */
1926static WindowDesc _newgrf_desc(
1927 WDP_CENTER, "settings_newgrf", 300, 263,
1929 {},
1930 _nested_newgrf_widgets
1931);
1932
1938static void NewGRFConfirmationCallback(Window *w, bool confirmed)
1939{
1940 if (confirmed) {
1943 NewGRFWindow *nw = dynamic_cast<NewGRFWindow*>(w);
1944
1946 _gamelog.GRFUpdate(_grfconfig, nw->actives); // log GRF changes
1947 CopyGRFConfigList(nw->orig_list, nw->actives, false);
1950
1951 /* Show new, updated list */
1952 int pos = nw->GetCurrentActivePosition();
1953
1954 CopyGRFConfigList(nw->actives, nw->orig_list, false);
1955
1956 if (nw->active_sel != nullptr) {
1957 /* Set current selection from position */
1958 if (static_cast<size_t>(pos) >= nw->actives.size()) {
1959 nw->active_sel = nw->actives.back().get();
1960 } else {
1961 auto it = std::next(std::begin(nw->actives), pos);
1962 nw->active_sel = it->get();
1963 }
1964 }
1965 nw->avails.ForceRebuild();
1966 nw->modified = false;
1967
1968 w->InvalidateData();
1969
1970 ReInitAllWindows(false);
1972 }
1973}
1974
1975
1976
1985void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config)
1986{
1988 new NewGRFWindow(_newgrf_desc, editable, show_params, exec_changes, config);
1989}
1990
1994 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1995 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_SAVE_PRESET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1996 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1997 EndContainer(),
1998 NWidget(WWT_PANEL, COLOUR_GREY),
2000 NWidget(WWT_INSET, COLOUR_GREY, WID_SVP_PRESET_LIST), SetPadding(2, 1, 2, 2),
2001 SetToolTip(STR_SAVE_PRESET_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SVP_SCROLLBAR), EndContainer(),
2003 EndContainer(),
2004 EndContainer(),
2005 NWidget(WWT_PANEL, COLOUR_GREY),
2006 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SVP_EDITBOX), SetPadding(2, 2, 2, 2), SetFill(1, 0), SetResize(1, 0),
2007 SetStringTip(STR_SAVE_PRESET_TITLE, STR_SAVE_PRESET_EDITBOX_TOOLTIP),
2008 EndContainer(),
2010 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_CANCEL), SetStringTip(STR_SAVE_PRESET_CANCEL, STR_SAVE_PRESET_CANCEL_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2011 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_SAVE), SetStringTip(STR_SAVE_PRESET_SAVE, STR_SAVE_PRESET_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2012 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
2013 EndContainer(),
2014};
2015
2018 WDP_CENTER, "save_preset", 140, 110,
2022);
2023
2025struct SavePresetWindow : public Window {
2030
2036 {
2037 this->presets = GetGRFPresetList();
2038 this->selected = -1;
2039 if (initial_text != nullptr) {
2040 for (uint i = 0; i < this->presets.size(); i++) {
2041 if (this->presets[i] == initial_text) {
2042 this->selected = i;
2043 break;
2044 }
2045 }
2046 }
2047
2049 this->presetname_editbox.ok_button = WID_SVP_SAVE;
2050 this->presetname_editbox.cancel_button = WID_SVP_CANCEL;
2051
2052 this->CreateNestedTree();
2053 this->vscroll = this->GetScrollbar(WID_SVP_SCROLLBAR);
2054 this->FinishInitNested(0);
2055
2056 this->vscroll->SetCount(this->presets.size());
2058 if (initial_text != nullptr) this->presetname_editbox.text.Assign(initial_text);
2059 }
2060
2062 {
2063 }
2064
2066 {
2067 switch (widget) {
2068 case WID_SVP_PRESET_LIST: {
2070 size.height = 0;
2071 for (uint i = 0; i < this->presets.size(); i++) {
2072 Dimension d = GetStringBoundingBox(this->presets[i]);
2073 size.width = std::max(size.width, d.width + padding.width);
2074 resize.height = std::max(resize.height, d.height);
2075 }
2076 size.height = ClampU((uint)this->presets.size(), 5, 20) * resize.height + padding.height;
2077 break;
2078 }
2079 }
2080 }
2081
2082 void DrawWidget(const Rect &r, WidgetID widget) const override
2083 {
2084 switch (widget) {
2085 case WID_SVP_PRESET_LIST: {
2086 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
2088
2089 uint step_height = this->GetWidget<NWidgetBase>(WID_SVP_PRESET_LIST)->resize_y;
2090 int offset_y = (step_height - GetCharacterHeight(FS_NORMAL)) / 2;
2091 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2092
2093 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->presets);
2094 for (auto it = first; it != last; ++it) {
2095 int row = static_cast<int>(std::distance(std::begin(this->presets), it));
2096 if (row == this->selected) GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
2097
2098 DrawString(tr.left, tr.right, tr.top + offset_y, *it, (row == this->selected) ? TC_WHITE : TC_SILVER);
2099 tr.top += step_height;
2100 }
2101 break;
2102 }
2103 }
2104 }
2105
2106 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2107 {
2108 switch (widget) {
2109 case WID_SVP_PRESET_LIST: {
2110 auto it = this->vscroll->GetScrolledItemFromWidget(this->presets, pt.y, this, WID_SVP_PRESET_LIST);
2111 if (it != this->presets.end()) {
2112 this->selected = it - this->presets.begin();
2113 this->presetname_editbox.text.Assign(*it);
2116 }
2117 break;
2118 }
2119
2120 case WID_SVP_CANCEL:
2121 this->Close();
2122 break;
2123
2124 case WID_SVP_SAVE: {
2126 if (w != nullptr && !StrEmpty(this->presetname_editbox.text.GetText())) w->OnQueryTextFinished(this->presetname_editbox.text.GetText());
2127 this->Close();
2128 break;
2129 }
2130 }
2131 }
2132
2133 void OnResize() override
2134 {
2135 this->vscroll->SetCapacityFromWidget(this, WID_SVP_PRESET_LIST, WidgetDimensions::scaled.framerect.Vertical());
2136 }
2137};
2138
2143static void ShowSavePresetWindow(const char *initial_text)
2144{
2146 new SavePresetWindow(initial_text);
2147}
2148
2151 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NEWGRF_SCAN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2152 NWidget(WWT_PANEL, COLOUR_GREY),
2154 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_NEWGRF_SCAN_MESSAGE), SetFill(1, 0),
2155 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_BAR), SetFill(1, 0),
2156 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(400, 0),
2157 EndContainer(),
2158 EndContainer(),
2159};
2160
2163 WDP_CENTER, nullptr, 0, 0,
2165 {},
2167);
2168
2171 std::string last_name;
2173
2176 {
2177 this->InitNested(1);
2178 }
2179
2181 {
2182 switch (widget) {
2183 case WID_SP_PROGRESS_BAR: {
2184 SetDParamMaxValue(0, 100);
2186 /* We need some spacing for the 'border' */
2189 break;
2190 }
2191
2193 SetDParamMaxDigits(0, 4);
2194 SetDParamMaxDigits(1, 4);
2195 /* We really don't know the width. We could determine it by scanning the NewGRFs,
2196 * but this is the status window for scanning them... */
2197 size.width = std::max<uint>(size.width, GetStringBoundingBox(STR_NEWGRF_SCAN_STATUS).width + padding.width);
2199 break;
2200 }
2201 }
2202
2203 void DrawWidget(const Rect &r, WidgetID widget) const override
2204 {
2205 switch (widget) {
2206 case WID_SP_PROGRESS_BAR: {
2207 /* Draw the % complete with a bar and a text */
2210 uint percent = scanned * 100 / std::max(1U, _settings_client.gui.last_newgrf_count);
2211 DrawFrameRect(ir.WithWidth(ir.Width() * percent / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {});
2212 SetDParam(0, percent);
2213 DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_GENERATION_PROGRESS, TC_FROMSTRING, SA_HOR_CENTER);
2214 break;
2215 }
2216
2218 SetDParam(0, this->scanned);
2220 DrawString(r.left, r.right, r.top, STR_NEWGRF_SCAN_STATUS, TC_FROMSTRING, SA_HOR_CENTER);
2221
2222 DrawString(r.left, r.right, r.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal, this->last_name, TC_BLACK, SA_HOR_CENTER);
2223 break;
2224 }
2225 }
2226
2232 void UpdateNewGRFScanStatus(uint num, const char *name)
2233 {
2234 if (name == nullptr) {
2235 this->last_name = GetString(STR_NEWGRF_SCAN_ARCHIVES);
2236 } else {
2237 this->last_name = name;
2238 }
2239 this->scanned = num;
2241
2242 this->SetDirty();
2243 }
2244};
2245
2251void UpdateNewGRFScanStatus(uint num, const char *name)
2252{
2254 if (w == nullptr) w = new ScanProgressWindow();
2255 w->UpdateNewGRFScanStatus(num, name);
2256}
constexpr bool Test(Tenum value) const
Test if the enum value is set.
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 StopAction()
Stops logging of any changes.
Definition gamelog.cpp:74
void GRFUpdate(const GRFConfigList &oldg, const GRFConfigList &newg)
Compares two NewGRF lists and logs any change.
Definition gamelog.cpp:606
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:1254
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:2459
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:2533
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:2480
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:40
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
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:58
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:60
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
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_...
auto Slide(TIter first, TIter last, TIter position) -> std::pair< TIter, TIter >
Move elements between first and last to a new position, rotating elements in between as necessary.
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.
@ 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
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
@ 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
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:376
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
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 SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetResizeWidgetTypeTip(ResizeWidgetValues widget_type, StringID tip)
Widget part function for setting the resize widget type and tooltip.
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:3381
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetArrowWidgetTypeTip(ArrowWidgetValues widget_type, StringID tip={})
Widget part function for setting the arrow widget type and tooltip.
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:937
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 bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between 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.
GRFConfigList _grfconfig
First item in list of current GRF set up.
void CopyGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only)
Copy a GRF Config list.
std::string GRFBuildParamList(const GRFConfig &c)
Build a string containing space separated parameter values, and terminate.
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.
GRFConfigList _all_grfs
First item in list of all scanned NewGRFs.
void ClearGRFConfigList(GRFConfigList &config)
Clear a GRF Config list, freeing all nodes.
@ 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.
@ Compatible
GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches)
@ Static
GRF file is used statically (can be used in any MP game)
@ Invalid
GRF is unusable with this version of OpenTTD.
@ 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 GRFConfigFlag::Invalid set.
@ FGCM_EXACT
Only find Grfs matching md5sum.
@ 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.
std::map< uint32_t, const GRFConfig * > GrfIdMap
Map of grfid to the grf config.
static WindowDesc _save_preset_desc(WDP_CENTER, "save_preset", 140, 110, WC_SAVE_PRESET, WC_GAME_OPTIONS, WindowDefaultFlag::Modal, _nested_save_preset_widgets)
Window description of the preset save window.
void UpdateNewGRFScanStatus(uint num, const char *name)
Update the NewGRF scan status.
static void NewGRFConfirmationCallback(Window *w, bool confirmed)
Callback function for the newgrf 'apply changes' confirmation window.
static WindowDesc _scan_progress_desc(WDP_CENTER, nullptr, 0, 0, WC_MODAL_PROGRESS, WC_NONE, {}, _nested_scan_progress_widgets)
Description of the widgets and other settings of the window.
static void ShowSavePresetWindow(const char *initial_text)
Open the window for saving a preset.
static void FillGrfidMap(const GRFConfigList &lst, GrfIdMap &grfid_map)
Add all grf configs from c into the map.
static constexpr NWidgetPart _nested_scan_progress_widgets[]
Widgets for the progress window.
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config)
Setup the NewGRF gui.
static constexpr NWidgetPart _nested_save_preset_widgets[]
Widget parts of the save preset window.
std::unique_ptr< NWidgetBase > NewGRFDisplay()
Construct nested container widget for managing the lists and the info panel of the NewGRF GUI.
static WindowDesc _newgrf_parameters_desc(WDP_CENTER, "settings_newgrf_config", 500, 208, WC_GRF_PARAMETERS, WC_NONE, {}, _nested_newgrf_parameter_widgets)
Window definition for the change grf parameters window.
void ShowNewGRFError()
Show the first NewGRF error we can find.
void ShowMissingContentWindow(const GRFConfigList &list)
Show the content list window with all missing grfs from the given list.
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:1332
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.
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
Save a NewGRF configuration with a preset name.
void DeleteGRFPresetFromConfig(const char *config_name)
Delete a NewGRF configuration by preset name.
GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
Load 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.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:107
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
@ SVS_NONE
Allow nothing and replace nothing.
Definition string_type.h:45
@ 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:332
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:370
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.
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)
@ TD_RTL
Text is written right-to-left by default.
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.
ContentType type
Type of content.
@ DOES_NOT_EXIST
The content does not exist in the content system.
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.
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.
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.
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
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.
void OnDropdownClose(Point, WidgetID widget, int, bool) override
A dropdown window associated to this window has been closed.
GRFConfig & grf_config
Set the parameters of this GRFConfig.
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.
GRFConfigList actives
Temporary active grf list to which changes are made.
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.
GRFConfigList & orig_list
List active grfs in the game. Used as initial value, may be updated by the window.
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.
PaletteID GetPalette(const GRFConfig &c) const
Pick the palette for the sprite of the grf to display.
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.
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.
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
const char * GetText() const
Get the current text.
Definition textbuf.cpp:290
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:168
Data structure for an opened window.
Definition window_gui.h:272
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1044
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1730
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:319
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3157
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:548
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1032
ResizeInfo resize
Resize information.
Definition window_gui.h:313
void DisableWidget(WidgetID widget_index)
Sets a widget to disabled.
Definition window_gui.h:390
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:514
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1720
virtual void OnQueryTextFinished(std::optional< std::string > str)
The query window opened from this window has closed.
Definition window_gui.h:772
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:483
int top
y position of top edge of the window
Definition window_gui.h:309
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:970
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1743
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:311
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:380
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:310
@ 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
@ 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:42
@ NWID_CUSTOM
General Custom widget.
Definition widget_type.h:77
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
@ WWT_LABEL
Centered label.
Definition widget_type.h:48
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:62
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:41
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:60
@ WWT_FRAME
Frame.
Definition widget_type.h:51
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:39
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:56
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:49
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
uint ComputeMaxSize(uint base, uint max_space, uint step)
Return the biggest possible size of a nested widget.
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition widget_type.h:22
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition widget_type.h:23
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
std::map< WidgetID, class NWidgetBase * > WidgetLookup
Lookup between widget IDs and NWidget objects.
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:31
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:1137
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1110
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
Definition window.cpp:3333
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1149
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1095
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3099
Window functions not directly related to making/drawing windows.
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
@ BorderOnly
Draw border only, no background.
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
@ WDP_CENTER
Center the window.
Definition window_gui.h:146
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_GAME_OPTIONS_NEWGRF_STATE
NewGRF settings.
Definition window_type.h:27
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ 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.
@ WC_BUILD_OBJECT
Build object; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ 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:
Functions related to zooming.