OpenTTD Source 20241224-master-gf74b0cf984
picker_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 "core/backup_type.hpp"
12#include "gui.h"
13#include "hotkeys.h"
14#include "ini_type.h"
15#include "picker_gui.h"
16#include "querystring_gui.h"
17#include "settings_type.h"
18#include "sortlist_type.h"
19#include "sound_func.h"
20#include "sound_type.h"
21#include "string_func.h"
22#include "stringfilter_type.h"
23#include "strings_func.h"
24#include "widget_type.h"
25#include "window_func.h"
26#include "window_gui.h"
27#include "window_type.h"
28#include "zoom_func.h"
29
31
32#include "table/sprites.h"
33
34#include <charconv>
35
36#include "safeguards.h"
37
38static std::vector<PickerCallbacks *> &GetPickerCallbacks()
39{
40 static std::vector<PickerCallbacks *> callbacks;
41 return callbacks;
42}
43
44PickerCallbacks::PickerCallbacks(const std::string &ini_group) : ini_group(ini_group)
45{
46 GetPickerCallbacks().push_back(this);
47}
48
49PickerCallbacks::~PickerCallbacks()
50{
51 auto &callbacks = GetPickerCallbacks();
52 callbacks.erase(std::ranges::find(callbacks, this));
53}
54
60static void PickerLoadConfig(const IniFile &ini, PickerCallbacks &callbacks)
61{
62 const IniGroup *group = ini.GetGroup(callbacks.ini_group);
63 if (group == nullptr) return;
64
65 callbacks.saved.clear();
66 for (const IniItem &item : group->items) {
67 std::array<uint8_t, 4> grfid_buf;
68
69 std::string_view str = item.name;
70
71 /* Try reading "<grfid>|<localid>" */
72 auto grfid_pos = str.find('|');
73 if (grfid_pos == std::string_view::npos) continue;
74
75 std::string_view grfid_str = str.substr(0, grfid_pos);
76 if (!ConvertHexToBytes(grfid_str, grfid_buf)) continue;
77
78 str = str.substr(grfid_pos + 1);
79 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
80 uint16_t localid;
81 auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), localid);
82
83 if (err == std::errc{} && ptr == str.data() + str.size()) {
84 callbacks.saved.insert({grfid, localid, 0, 0});
85 }
86 }
87}
88
94static void PickerSaveConfig(IniFile &ini, const PickerCallbacks &callbacks)
95{
96 IniGroup &group = ini.GetOrCreateGroup(callbacks.ini_group);
97 group.Clear();
98
99 for (const PickerItem &item : callbacks.saved) {
100 std::string key = fmt::format("{:08X}|{}", BSWAP32(item.grfid), item.local_id);
101 group.CreateItem(key);
102 }
103}
104
109void PickerLoadConfig(const IniFile &ini)
110{
111 for (auto *cb : GetPickerCallbacks()) PickerLoadConfig(ini, *cb);
112}
113
119{
120 for (const auto *cb : GetPickerCallbacks()) PickerSaveConfig(ini, *cb);
121}
122
124static bool ClassIDSorter(int const &a, int const &b)
125{
126 return a < b;
127}
128
130static bool ClassTagNameFilter(int const *item, PickerFilterData &filter)
131{
132 filter.ResetState();
133 filter.AddLine(GetString(filter.callbacks->GetClassName(*item)));
134 return filter.GetState();
135}
136
138static bool TypeIDSorter(PickerItem const &a, PickerItem const &b)
139{
140 int r = a.class_index - b.class_index;
141 if (r == 0) r = a.index - b.index;
142 return r < 0;
143}
144
146static bool TypeTagNameFilter(PickerItem const *item, PickerFilterData &filter)
147{
148 filter.ResetState();
149 filter.AddLine(GetString(filter.callbacks->GetTypeName(item->class_index, item->index)));
150 return filter.GetState();
151}
152
153static const std::initializer_list<PickerClassList::SortFunction * const> _class_sorter_funcs = { &ClassIDSorter };
154static const std::initializer_list<PickerClassList::FilterFunction * const> _class_filter_funcs = { &ClassTagNameFilter };
155static const std::initializer_list<PickerTypeList::SortFunction * const> _type_sorter_funcs = { TypeIDSorter };
156static const std::initializer_list<PickerTypeList::FilterFunction * const> _type_filter_funcs = { TypeTagNameFilter };
157
158PickerWindow::PickerWindow(WindowDesc &desc, Window *parent, int window_number, PickerCallbacks &callbacks) : PickerWindowBase(desc, parent), callbacks(callbacks),
159 class_editbox(EDITBOX_MAX_SIZE * MAX_CHAR_LENGTH, EDITBOX_MAX_SIZE),
160 type_editbox(EDITBOX_MAX_SIZE * MAX_CHAR_LENGTH, EDITBOX_MAX_SIZE)
161{
162 this->window_number = window_number;
163
164 /* Init of nested tree is deferred.
165 * PickerWindow::ConstructWindow must be called by the inheriting window. */
166}
167
168void PickerWindow::ConstructWindow()
169{
170 this->CreateNestedTree();
171
172 /* Test if pickers should be active.*/
173 bool isActive = this->callbacks.IsActive();
174
175 /* Functionality depends on widgets being present, not window class. */
176 this->has_class_picker = isActive && this->GetWidget<NWidgetBase>(WID_PW_CLASS_LIST) != nullptr && this->callbacks.HasClassChoice();
177 this->has_type_picker = isActive && this->GetWidget<NWidgetBase>(WID_PW_TYPE_MATRIX) != nullptr;
178
179 if (this->has_class_picker) {
180 this->GetWidget<NWidgetCore>(WID_PW_CLASS_LIST)->tool_tip = this->callbacks.GetClassTooltip();
181
183 } else {
184 if (auto *nwid = this->GetWidget<NWidgetStacked>(WID_PW_CLASS_SEL); nwid != nullptr) {
185 /* Check the container orientation. MakeNWidgets adds an additional NWID_VERTICAL container so we check the grand-parent. */
186 bool is_vertical = (nwid->parent->parent->type == NWID_VERTICAL);
187 nwid->SetDisplayedPlane(is_vertical ? SZSP_HORIZONTAL : SZSP_VERTICAL);
188 }
189 }
190
192 this->class_string_filter.SetFilterTerm(this->class_editbox.text.buf);
193 this->class_string_filter.callbacks = &this->callbacks;
194
195 this->classes.SetListing(this->callbacks.class_last_sorting);
196 this->classes.SetFiltering(this->callbacks.class_last_filtering);
197 this->classes.SetSortFuncs(_class_sorter_funcs);
198 this->classes.SetFilterFuncs(_class_filter_funcs);
199
200 /* Update saved type information. */
201 this->callbacks.saved = this->callbacks.UpdateSavedItems(this->callbacks.saved);
202
203 /* Clear used type information. */
204 this->callbacks.used.clear();
205
206 if (this->has_type_picker) {
207 /* Populate used type information. */
208 this->callbacks.FillUsedItems(this->callbacks.used);
209
211
212 this->GetWidget<NWidgetCore>(WID_PW_TYPE_ITEM)->tool_tip = this->callbacks.GetTypeTooltip();
213
214 auto *matrix = this->GetWidget<NWidgetMatrix>(WID_PW_TYPE_MATRIX);
215 matrix->SetScrollbar(this->GetScrollbar(WID_PW_TYPE_SCROLL));
216
218 } else {
219 if (auto *nwid = this->GetWidget<NWidgetStacked>(WID_PW_TYPE_SEL); nwid != nullptr) {
220 /* Check the container orientation. MakeNWidgets adds an additional NWID_VERTICAL container so we check the grand-parent. */
221 bool is_vertical = (nwid->parent->parent->type == NWID_VERTICAL);
222 nwid->SetDisplayedPlane(is_vertical ? SZSP_HORIZONTAL : SZSP_VERTICAL);
223 }
224 }
225
227 this->type_string_filter.SetFilterTerm(this->type_editbox.text.buf);
228 this->type_string_filter.callbacks = &this->callbacks;
229
230 this->types.SetListing(this->callbacks.type_last_sorting);
231 this->types.SetFiltering(this->callbacks.type_last_filtering);
232 this->types.SetSortFuncs(_type_sorter_funcs);
233 this->types.SetFilterFuncs(_type_filter_funcs);
234
235 this->FinishInitNested(this->window_number);
236
238}
239
241{
242 this->callbacks.Close(data);
243 this->PickerWindowBase::Close(data);
244}
245
246void PickerWindow::UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize)
247{
248 switch (widget) {
249 /* Class picker */
251 resize.height = GetCharacterHeight(FS_NORMAL) + padding.height;
252 size.height = 5 * resize.height;
253 break;
254
255 /* Type picker */
257 /* At least two items wide. */
258 size.width += resize.width;
259 fill.width = resize.width;
260 fill.height = 1;
261
262 /* Resizing in X direction only at blob size, but at pixel level in Y. */
263 resize.height = 1;
264 break;
265
266 /* Type picker */
267 case WID_PW_TYPE_ITEM:
270 break;
271 }
272}
273
274void PickerWindow::DrawWidget(const Rect &r, WidgetID widget) const
275{
276 switch (widget) {
277 /* Class picker */
278 case WID_PW_CLASS_LIST: {
280 const int selected = this->callbacks.GetSelectedClass();
281 const auto vscroll = this->GetScrollbar(WID_PW_CLASS_SCROLL);
282 const int y_step = this->GetWidget<NWidgetResizeBase>(widget)->resize_y;
283 auto [first, last] = vscroll->GetVisibleRangeIterators(this->classes);
284 for (auto it = first; it != last; ++it) {
285 DrawString(ir, this->callbacks.GetClassName(*it), *it == selected ? TC_WHITE : TC_BLACK);
286 ir.top += y_step;
287 }
288 break;
289 }
290
291 /* Type picker */
292 case WID_PW_TYPE_ITEM: {
293 assert(this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement() < static_cast<int>(this->types.size()));
294 const auto &item = this->types[this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement()];
295
300 int x = (ir.Width() - ScaleSpriteTrad(PREVIEW_WIDTH)) / 2 + ScaleSpriteTrad(PREVIEW_LEFT);
302
303 this->callbacks.DrawType(x, y, item.class_index, item.index);
304 if (this->callbacks.saved.contains(item)) {
305 DrawSprite(SPR_BLOT, PALETTE_TO_YELLOW, 0, 0);
306 }
307 if (this->callbacks.used.contains(item)) {
308 DrawSprite(SPR_BLOT, PALETTE_TO_GREEN, ir.Width() - GetSpriteSize(SPR_BLOT).width, 0);
309 }
310 }
311
312 if (!this->callbacks.IsTypeAvailable(item.class_index, item.index)) {
313 GfxFillRect(ir, GetColourGradient(COLOUR_GREY, SHADE_DARKER), FILLRECT_CHECKER);
314 }
315 break;
316 }
317
318 case WID_PW_TYPE_NAME:
319 DrawString(r, this->callbacks.GetTypeName(this->callbacks.GetSelectedClass(), this->callbacks.GetSelectedType()), TC_ORANGE, SA_CENTER);
320 break;
321 }
322}
323
330
332{
333 switch (widget) {
334 /* Class Picker */
335 case WID_PW_CLASS_LIST: {
336 const auto vscroll = this->GetWidget<NWidgetScrollbar>(WID_PW_CLASS_SCROLL);
337 auto it = vscroll->GetScrolledItemFromWidget(this->classes, pt.y, this, WID_PW_CLASS_LIST);
338 if (it == this->classes.end()) return;
339
340 if (this->callbacks.GetSelectedClass() != *it || HasBit(this->callbacks.mode, PFM_ALL)) {
341 ClrBit(this->callbacks.mode, PFM_ALL); // Disable showing all.
342 this->callbacks.SetSelectedClass(*it);
344 }
347 break;
348 }
349
350 case WID_PW_MODE_ALL:
351 case WID_PW_MODE_USED:
353 ToggleBit(this->callbacks.mode, widget - WID_PW_MODE_ALL);
354 if (!this->IsWidgetDisabled(WID_PW_MODE_ALL) && HasBit(this->callbacks.mode, widget - WID_PW_MODE_ALL)) {
355 /* Enabling used or saved filters automatically enables all. */
356 SetBit(this->callbacks.mode, PFM_ALL);
357 }
359 break;
360
361 /* Type Picker */
362 case WID_PW_TYPE_ITEM: {
363 int sel = this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement();
364 assert(sel < (int)this->types.size());
365 const auto &item = this->types[sel];
366
367 if (_ctrl_pressed) {
368 auto it = this->callbacks.saved.find(item);
369 if (it == std::end(this->callbacks.saved)) {
370 this->callbacks.saved.insert(item);
371 } else {
372 this->callbacks.saved.erase(it);
373 }
375 break;
376 }
377
378 if (this->callbacks.IsTypeAvailable(item.class_index, item.index)) {
379 this->callbacks.SetSelectedClass(item.class_index);
380 this->callbacks.SetSelectedType(item.index);
382 }
385 break;
386 }
387 }
388}
389
390void PickerWindow::OnInvalidateData(int data, bool gui_scope)
391{
392 if (!gui_scope) return;
393
394 if ((data & PFI_CLASS) != 0) this->classes.ForceRebuild();
395 if ((data & PFI_TYPE) != 0) this->types.ForceRebuild();
396
397 this->BuildPickerClassList();
398 if ((data & PFI_VALIDATE) != 0) this->EnsureSelectedClassIsValid();
399 if ((data & PFI_POSITION) != 0) this->EnsureSelectedClassIsVisible();
400
401 this->BuildPickerTypeList();
402 if ((data & PFI_VALIDATE) != 0) this->EnsureSelectedTypeIsValid();
403 if ((data & PFI_POSITION) != 0) this->EnsureSelectedTypeIsVisible();
404
405 if (this->has_type_picker) {
409 }
410}
411
413{
414 switch (hotkey) {
416 /* Cycle between the two edit boxes. */
417 if (this->has_type_picker && (this->nested_focus == nullptr || this->nested_focus->index != WID_PW_TYPE_FILTER)) {
419 } else if (this->has_class_picker && (this->nested_focus == nullptr || this->nested_focus->index != WID_PW_CLASS_FILTER)) {
421 }
422 SetFocusedWindow(this);
423 return ES_HANDLED;
424
425 default:
426 return ES_NOT_HANDLED;
427 }
428}
429
431{
432 switch (wid) {
434 this->class_string_filter.SetFilterTerm(this->class_editbox.text.buf);
435 this->classes.SetFilterState(!class_string_filter.IsEmpty());
437 break;
438
440 this->type_string_filter.SetFilterTerm(this->type_editbox.text.buf);
441 this->types.SetFilterState(!type_string_filter.IsEmpty());
443 break;
444
445 default:
446 break;
447 }
448}
449
452{
453 if (!this->classes.NeedRebuild()) return;
454
455 int count = this->callbacks.GetClassCount();
456
457 this->classes.clear();
458 this->classes.reserve(count);
459
460 bool filter_used = HasBit(this->callbacks.mode, PFM_USED);
461 bool filter_saved = HasBit(this->callbacks.mode, PFM_SAVED);
462 for (int i = 0; i < count; i++) {
463 if (this->callbacks.GetClassName(i) == INVALID_STRING_ID) continue;
464 if (filter_used && std::none_of(std::begin(this->callbacks.used), std::end(this->callbacks.used), [i](const PickerItem &item) { return item.class_index == i; })) continue;
465 if (filter_saved && std::none_of(std::begin(this->callbacks.saved), std::end(this->callbacks.saved), [i](const PickerItem &item) { return item.class_index == i; })) continue;
466 this->classes.emplace_back(i);
467 }
468
469 this->classes.Filter(this->class_string_filter);
470 this->classes.RebuildDone();
471 this->classes.Sort();
472
473 if (!this->has_class_picker) return;
474 this->GetScrollbar(WID_PW_CLASS_SCROLL)->SetCount(this->classes.size());
475}
476
477void PickerWindow::EnsureSelectedClassIsValid()
478{
479 int class_index = this->callbacks.GetSelectedClass();
480 if (std::binary_search(std::begin(this->classes), std::end(this->classes), class_index)) return;
481
482 if (!this->classes.empty()) {
483 class_index = this->classes.front();
484 } else {
485 /* Classes can be empty if filters are enabled, find the first usable class. */
486 int count = this->callbacks.GetClassCount();
487 for (int i = 0; i < count; i++) {
488 if (this->callbacks.GetClassName(i) == INVALID_STRING_ID) continue;
489 class_index = i;
490 break;
491 }
492 }
493
494 this->callbacks.SetSelectedClass(class_index);
495 this->types.ForceRebuild();
496}
497
498void PickerWindow::EnsureSelectedClassIsVisible()
499{
500 if (!this->has_class_picker) return;
501 if (this->classes.empty()) return;
502
503 auto it = std::ranges::find(this->classes, this->callbacks.GetSelectedClass());
504 if (it == std::end(this->classes)) return;
505
506 int pos = static_cast<int>(std::distance(std::begin(this->classes), it));
508}
509
510void PickerWindow::RefreshUsedTypeList()
511{
512 if (!this->has_type_picker) return;
513
514 this->callbacks.used.clear();
515 this->callbacks.FillUsedItems(this->callbacks.used);
517}
518
521{
522 if (!this->types.NeedRebuild()) return;
523
524 this->types.clear();
525
526 bool show_all = HasBit(this->callbacks.mode, PFM_ALL);
527 bool filter_used = HasBit(this->callbacks.mode, PFM_USED);
528 bool filter_saved = HasBit(this->callbacks.mode, PFM_SAVED);
529 int cls_id = this->callbacks.GetSelectedClass();
530
531 if (filter_used) {
532 /* Showing used items. May also be filtered by saved items. */
533 this->types.reserve(this->callbacks.used.size());
534 for (const PickerItem &item : this->callbacks.used) {
535 if (!show_all && item.class_index != cls_id) continue;
536 if (this->callbacks.GetTypeName(item.class_index, item.index) == INVALID_STRING_ID) continue;
537 this->types.emplace_back(item);
538 }
539 } else if (filter_saved) {
540 /* Showing only saved items. */
541 this->types.reserve(this->callbacks.saved.size());
542 for (const PickerItem &item : this->callbacks.saved) {
543 /* The used list may contain items that aren't currently loaded, skip these. */
544 if (item.class_index == -1) continue;
545 if (!show_all && item.class_index != cls_id) continue;
546 if (this->callbacks.GetTypeName(item.class_index, item.index) == INVALID_STRING_ID) continue;
547 this->types.emplace_back(item);
548 }
549 } else if (show_all) {
550 /* Reserve enough space for everything. */
551 int total = 0;
552 for (int class_index : this->classes) total += this->callbacks.GetTypeCount(class_index);
553 this->types.reserve(total);
554 /* Add types in all classes. */
555 for (int class_index : this->classes) {
556 int count = this->callbacks.GetTypeCount(class_index);
557 for (int i = 0; i < count; i++) {
558 if (this->callbacks.GetTypeName(class_index, i) == INVALID_STRING_ID) continue;
559 this->types.emplace_back(this->callbacks.GetPickerItem(class_index, i));
560 }
561 }
562 } else {
563 /* Add types in only the selected class. */
564 if (cls_id >= 0 && cls_id < this->callbacks.GetClassCount()) {
565 int count = this->callbacks.GetTypeCount(cls_id);
566 this->types.reserve(count);
567 for (int i = 0; i < count; i++) {
568 if (this->callbacks.GetTypeName(cls_id, i) == INVALID_STRING_ID) continue;
569 this->types.emplace_back(this->callbacks.GetPickerItem(cls_id, i));
570 }
571 }
572 }
573
574 this->types.Filter(this->type_string_filter);
575 this->types.RebuildDone();
576 this->types.Sort();
577
578 if (!this->has_type_picker) return;
579 this->GetWidget<NWidgetMatrix>(WID_PW_TYPE_MATRIX)->SetCount(static_cast<int>(this->types.size()));
580}
581
582void PickerWindow::EnsureSelectedTypeIsValid()
583{
584 int class_index = this->callbacks.GetSelectedClass();
585 int index = this->callbacks.GetSelectedType();
586 if (std::any_of(std::begin(this->types), std::end(this->types), [class_index, index](const auto &item) { return item.class_index == class_index && item.index == index; })) return;
587
588 if (!this->types.empty()) {
589 class_index = this->types.front().class_index;
590 index = this->types.front().index;
591 } else {
592 /* Types can be empty if filters are enabled, find the first usable type. */
593 int count = this->callbacks.GetTypeCount(class_index);
594 for (int i = 0; i < count; i++) {
595 if (this->callbacks.GetTypeName(class_index, i) == INVALID_STRING_ID) continue;
596 index = i;
597 break;
598 }
599 }
600 this->callbacks.SetSelectedClass(class_index);
601 this->callbacks.SetSelectedType(index);
602}
603
604void PickerWindow::EnsureSelectedTypeIsVisible()
605{
606 if (!this->has_type_picker) return;
607 if (this->types.empty()) {
608 this->GetWidget<NWidgetMatrix>(WID_PW_TYPE_MATRIX)->SetClicked(-1);
609 return;
610 }
611
612 int class_index = this->callbacks.GetSelectedClass();
613 int index = this->callbacks.GetSelectedType();
614
615 auto it = std::ranges::find_if(this->types, [class_index, index](const auto &item) { return item.class_index == class_index && item.index == index; });
616 if (it == std::end(this->types)) return;
617
618 int pos = static_cast<int>(std::distance(std::begin(this->types), it));
619 this->GetWidget<NWidgetMatrix>(WID_PW_TYPE_MATRIX)->SetClicked(pos);
620}
621
623std::unique_ptr<NWidgetBase> MakePickerClassWidgets()
624{
625 static constexpr NWidgetPart picker_class_widgets[] = {
626 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_PW_CLASS_SEL),
628 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
629 NWidget(WWT_EDITBOX, COLOUR_DARK_GREEN, WID_PW_CLASS_FILTER), SetMinimalSize(144, 0), SetPadding(2), SetFill(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
630 EndContainer(),
632 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
635 EndContainer(),
636 NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_PW_CLASS_SCROLL),
637 EndContainer(),
638 EndContainer(),
639 EndContainer(),
640 };
641
642 return MakeNWidgets(picker_class_widgets, nullptr);
643}
644
646std::unique_ptr<NWidgetBase> MakePickerTypeWidgets()
647{
648 static constexpr NWidgetPart picker_type_widgets[] = {
649 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_PW_TYPE_SEL),
651 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
652 NWidget(WWT_EDITBOX, COLOUR_DARK_GREEN, WID_PW_TYPE_FILTER), SetPadding(2), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
653 EndContainer(),
655 NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_PW_MODE_ALL), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_PICKER_MODE_ALL, STR_PICKER_MODE_ALL_TOOLTIP),
656 NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_PW_MODE_USED), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_PICKER_MODE_USED, STR_PICKER_MODE_USED_TOOLTIP),
657 NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_PW_MODE_SAVED), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_PICKER_MODE_SAVED, STR_PICKER_MODE_SAVED_TOOLTIP),
658 EndContainer(),
660 NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_PW_TYPE_SCROLL),
663 EndContainer(),
664 EndContainer(),
665 EndContainer(),
666 NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_PW_TYPE_SCROLL),
667 EndContainer(),
669 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
671 EndContainer(),
672 NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN, WID_PW_TYPE_RESIZE),
673 EndContainer(),
674 EndContainer(),
675 EndContainer(),
676 };
677
678 return MakeNWidgets(picker_type_widgets, nullptr);
679}
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
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.
const WidgetID index
Index of the nested widget (-1 means 'not used').
Matrix container with implicitly equal sized (virtual) sub-widgets.
Class for PickerClassWindow to collect information and retain state.
Definition picker_gui.h:37
virtual int GetSelectedClass() const =0
Get the index of the selected class.
Filtering type_last_filtering
Default filtering of PickerTypeList.
Definition picker_gui.h:89
virtual PickerItem GetPickerItem(int cls_id, int id) const =0
Get data about an item.
const std::string ini_group
Ini Group for saving favourites.
Definition picker_gui.h:91
virtual void SetSelectedClass(int id) const =0
Set the selected class.
virtual bool IsActive() const =0
Should picker class/type selection be enabled?
virtual StringID GetTypeName(int cls_id, int id) const =0
Get the item of a type.
virtual bool IsTypeAvailable(int cls_id, int id) const =0
Test if an item is currently buildable.
virtual void FillUsedItems(std::set< PickerItem > &items)=0
Fill a set with all items that are used by the current player.
virtual StringID GetTypeTooltip() const =0
Get the tooltip string for the type grid.
virtual bool HasClassChoice() const =0
Are there multiple classes to chose from?
Listing type_last_sorting
Default sorting of PickerTypeList.
Definition picker_gui.h:88
std::set< PickerItem > used
Set of items used in the current game by the current company.
Definition picker_gui.h:94
virtual StringID GetClassTooltip() const =0
Get the tooltip string for the class list.
virtual int GetTypeCount(int cls_id) const =0
Get the number of types in a class.
virtual int GetClassCount() const =0
Get the number of classes.
virtual void SetSelectedType(int id) const =0
Set the selected type.
virtual StringID GetClassName(int id) const =0
Get the name of a class.
virtual std::set< PickerItem > UpdateSavedItems(const std::set< PickerItem > &src)=0
Update link between grfid/localidx and class_index/index in saved items.
virtual void DrawType(int x, int y, int cls_id, int id) const =0
Draw preview image of an item.
Filtering class_last_filtering
Default filtering of PickerClassList.
Definition picker_gui.h:86
virtual int GetSelectedType() const =0
Get the selected type.
uint8_t mode
Bitmask of PickerFilterModes.
Definition picker_gui.h:92
std::set< PickerItem > saved
Set of saved favourite items.
Definition picker_gui.h:95
Listing class_last_sorting
Default sorting of PickerClassList.
Definition picker_gui.h:85
Base class for windows opened from a toolbar.
Definition window_gui.h:986
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:3524
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
bool has_class_picker
Set if this window has a class picker 'component'.
Definition picker_gui.h:170
static const int PREVIEW_LEFT
Offset from left edge to draw preview.
Definition picker_gui.h:165
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
@ PFM_USED
Show used types.
Definition picker_gui.h:152
@ PFM_ALL
Show all classes.
Definition picker_gui.h:151
@ PFM_SAVED
Show saved types.
Definition picker_gui.h:153
PickerTypeList types
List of types.
Definition picker_gui.h:202
QueryString class_editbox
Filter editbox.
Definition picker_gui.h:196
bool has_type_picker
Set if this window has a type picker 'component'.
Definition picker_gui.h:171
void BuildPickerClassList()
Builds the filter list of classes.
@ PCWHK_FOCUS_FILTER_BOX
Focus the edit box for editing the filter string.
Definition picker_gui.h:185
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
void BuildPickerTypeList()
Builds the filter list of types.
void OnResize() override
Called after the window got resized.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
@ PFI_POSITION
Update scroll positions.
Definition picker_gui.h:159
@ PFI_VALIDATE
Validate selected item.
Definition picker_gui.h:160
@ PFI_CLASS
Refresh the class list.
Definition picker_gui.h:157
@ PFI_TYPE
Refresh the type list.
Definition picker_gui.h:158
static const int PREVIEW_WIDTH
Width of each preview button.
Definition picker_gui.h:163
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
QueryString type_editbox
Filter editbox.
Definition picker_gui.h:204
static const int PREVIEW_BOTTOM
Offset from bottom edge to draw preview.
Definition picker_gui.h:166
EventState OnHotkey(int hotkey) override
A hotkey has been pressed.
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.
PickerClassList classes
List of classes.
Definition picker_gui.h:194
static const int PREVIEW_HEIGHT
Height of each preview button.
Definition picker_gui.h:164
void SetCount(size_t num)
Sets the number of elements in the list.
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition widget.cpp:2451
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:28
RectPadding fullbevel
Always-scaled bevel thickness.
Definition window_gui.h:41
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:96
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:922
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
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
bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height)
Set up a clipping area for only drawing into a certain area.
Definition gfx.cpp:1548
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:353
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:209
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:299
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
std::unique_ptr< NWidgetBase > MakeNWidgets(std::span< const NWidgetPart > nwid_parts, std::unique_ptr< NWidgetBase > &&container)
Construct a nested widget tree from an array of parts.
Definition widget.cpp:3297
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
GUI functions that shouldn't be here.
Hotkey related functions.
Types related to reading/writing '*.ini' files.
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:314
static const std::initializer_list< PickerClassList::FilterFunction *const > _class_filter_funcs
Filter functions of the PickerClassList.
static bool TypeIDSorter(PickerItem const &a, PickerItem const &b)
Sort types by id.
static void PickerLoadConfig(const IniFile &ini, PickerCallbacks &callbacks)
Load favourites of a picker from config.
static const std::initializer_list< PickerTypeList::SortFunction *const > _type_sorter_funcs
Sort functions of the PickerTypeList.
static bool ClassIDSorter(int const &a, int const &b)
Sort classes by id.
static const std::initializer_list< PickerClassList::SortFunction *const > _class_sorter_funcs
Sort functions of the PickerClassList.
std::unique_ptr< NWidgetBase > MakePickerClassWidgets()
Create nested widgets for the class picker widgets.
static bool TypeTagNameFilter(PickerItem const *item, PickerFilterData &filter)
Filter types by class name.
static const std::initializer_list< PickerTypeList::FilterFunction *const > _type_filter_funcs
Filter functions of the PickerTypeList.
static void PickerSaveConfig(IniFile &ini, const PickerCallbacks &callbacks)
Save favourites of a picker to config.
std::unique_ptr< NWidgetBase > MakePickerTypeWidgets()
Create nested widgets for the type picker widgets.
static bool ClassTagNameFilter(int const *item, PickerFilterData &filter)
Filter classes by class name.
Functions/types etc.
Types related to the picker widgets.
@ WID_PW_MODE_SAVED
Toggle showing only saved types.
@ WID_PW_CLASS_FILTER
Editbox filter.
@ WID_PW_TYPE_SCROLL
Scrollbar for the matrix.
@ WID_PW_TYPE_ITEM
A single item.
@ WID_PW_CLASS_LIST
List of classes.
@ WID_PW_TYPE_FILTER
Text filter.
@ WID_PW_MODE_USED
Toggle showing only used types.
@ WID_PW_TYPE_MATRIX
Matrix with items.
@ WID_PW_CLASS_SEL
Stack to hide the class picker.
@ WID_PW_MODE_ALL
Toggle "Show all" filter mode.
@ WID_PW_CLASS_SCROLL
Scrollbar for list of classes.
@ WID_PW_TYPE_SEL
Stack to hide the type picker.
@ WID_PW_TYPE_NAME
Name of selected item.
@ WID_PW_TYPE_RESIZE
Type resize handle.
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Types related to global configuration settings.
Base types for having sorted lists in GUIs.
Functions related to sound.
Types related to sounds.
@ SND_15_BEEP
19 == 0x13 GUI button click
Definition sound_type.h:66
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
bool ConvertHexToBytes(std::string_view hex, std::span< uint8_t > bytes)
Convert a hex-string to a byte-array, while validating it was actually hex.
Definition string.cpp:734
Functions related to low-level strings.
Searching and filtering using a stringterm.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:333
Functions related to OTTD's strings.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
SoundSettings sound
sound effect settings
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
Definition gfx_type.h:157
Ini file that supports both loading and saving.
Definition ini_type.h:88
A group within an ini file.
Definition ini_type.h:34
void Clear()
Clear all items in the group.
Definition ini_load.cpp:98
IniItem & CreateItem(std::string_view name)
Create an item with the given name.
Definition ini_load.cpp:81
std::list< IniItem > items
all items in the group
Definition ini_type.h:35
A single "line" in an ini file.
Definition ini_type.h:23
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:119
IniGroup & GetOrCreateGroup(std::string_view name)
Get the group with the given name, and if it doesn't exist create a new group.
Definition ini_load.cpp:147
Partial widget specification to allow NWidgets to be written nested.
const PickerCallbacks * callbacks
Callbacks for filter functions to access to callbacks.
Definition picker_gui.h:142
Coordinates of a point in 2D.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
bool click_beep
Beep on a random selection of buttons.
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.
char *const buf
buffer in which text is saved
High level window description.
Definition window_gui.h:159
Data structure for an opened window.
Definition window_gui.h:273
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1733
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:320
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3159
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1723
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:486
bool IsWidgetDisabled(WidgetID widget_index) const
Gets the enabled/disabled status of a widget.
Definition window_gui.h:416
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:447
const NWidgetCore * nested_focus
Currently focused nested widget, or nullptr if no nested widget has focus.
Definition window_gui.h:319
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:977
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:387
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:35
Definitions about widgets.
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ SZSP_VERTICAL
Display plane with zero size horizontally, and filling and resizing vertically.
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:50
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:59
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:85
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:77
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:48
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:68
@ NWID_MATRIX
Matrix container.
Definition widget_type.h:78
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:80
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1140
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:422
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
Types related to windows.
int WidgetID
Widget ID.
Definition window_type.h:18
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_SELECT_STATION
Select station (when joining stations); Window numbers:
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107