OpenTTD Source  20241108-master-g80f628063a
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 
30 #include "widgets/picker_widget.h"
31 
32 #include "table/sprites.h"
33 
34 #include <charconv>
35 
36 #include "safeguards.h"
37 
38 static std::vector<PickerCallbacks *> &GetPickerCallbacks()
39 {
40  static std::vector<PickerCallbacks *> callbacks;
41  return callbacks;
42 }
43 
44 PickerCallbacks::PickerCallbacks(const std::string &ini_group) : ini_group(ini_group)
45 {
46  GetPickerCallbacks().push_back(this);
47 }
48 
49 PickerCallbacks::~PickerCallbacks()
50 {
51  auto &callbacks = GetPickerCallbacks();
52  callbacks.erase(std::find(callbacks.begin(), callbacks.end(), this));
53 }
54 
60 static 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 
94 static 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 
109 void 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 
124 static bool ClassIDSorter(int const &a, int const &b)
125 {
126  return a < b;
127 }
128 
130 static 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 
138 static 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 
146 static 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 
153 static const std::initializer_list<PickerClassList::SortFunction * const> _class_sorter_funcs = { &ClassIDSorter };
154 static const std::initializer_list<PickerClassList::FilterFunction * const> _class_filter_funcs = { &ClassTagNameFilter };
155 static const std::initializer_list<PickerTypeList::SortFunction * const> _type_sorter_funcs = { TypeIDSorter };
156 static const std::initializer_list<PickerTypeList::FilterFunction * const> _type_filter_funcs = { TypeTagNameFilter };
157 
158 PickerWindow::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 
168 void 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 
240 void PickerWindow::Close(int data)
241 {
242  this->callbacks.Close(data);
243  this->PickerWindowBase::Close(data);
244 }
245 
246 void PickerWindow::UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize)
247 {
248  switch (widget) {
249  /* Class picker */
250  case WID_PW_CLASS_LIST:
251  resize.height = GetCharacterHeight(FS_NORMAL) + padding.height;
252  size.height = 5 * resize.height;
253  break;
254 
255  /* Type picker */
256  case WID_PW_TYPE_MATRIX:
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 
274 void PickerWindow::DrawWidget(const Rect &r, WidgetID widget) const
275 {
276  switch (widget) {
277  /* Class picker */
278  case WID_PW_CLASS_LIST: {
279  Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
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 
296  DrawPixelInfo tmp_dpi;
297  Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
298  if (FillDrawPixelInfo(&tmp_dpi, ir)) {
299  AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
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 
325 {
326  if (this->has_class_picker) {
328  }
329 }
330 
331 void PickerWindow::OnClick(Point pt, WidgetID widget, int)
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:
352  case WID_PW_MODE_SAVED:
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  }
374  this->InvalidateData(PFI_TYPE);
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 
390 void 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 
430 void PickerWindow::OnEditboxChanged(WidgetID wid)
431 {
432  switch (wid) {
433  case WID_PW_CLASS_FILTER:
434  this->class_string_filter.SetFilterTerm(this->class_editbox.text.buf);
435  this->classes.SetFilterState(!class_string_filter.IsEmpty());
436  this->InvalidateData(PFI_CLASS);
437  break;
438 
439  case WID_PW_TYPE_FILTER:
440  this->type_string_filter.SetFilterTerm(this->type_editbox.text.buf);
441  this->types.SetFilterState(!type_string_filter.IsEmpty());
442  this->InvalidateData(PFI_TYPE);
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 
477 void 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 
498 void PickerWindow::EnsureSelectedClassIsVisible()
499 {
500  if (!this->has_class_picker) return;
501  if (this->classes.empty()) return;
502 
503  auto it = std::find(std::begin(this->classes), std::end(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 
510 void PickerWindow::RefreshUsedTypeList()
511 {
512  if (!this->has_type_picker) return;
513 
514  this->callbacks.used.clear();
515  this->callbacks.FillUsedItems(this->callbacks.used);
516  this->InvalidateData(PFI_TYPE);
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 
582 void 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 
604 void 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::find_if(std::begin(this->types), std::end(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 
623 std::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 
646 std::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),
661  NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_PW_TYPE_MATRIX), SetPIP(0, 2, 0), SetPadding(WidgetDimensions::unscaled.picker),
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.
constexpr debug_inline 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').
Definition: widget_type.h:392
Matrix container with implicitly equal sized (virtual) sub-widgets.
Definition: widget_type.h:597
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 std::set< PickerItem > UpdateSavedItems(const std::set< PickerItem > &src)=0
Update link between grfid/localidx and class_index/index in saved items.
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 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([[maybe_unused]] int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:3516
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition: picker_gui.cpp:240
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
@ 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.
Definition: picker_gui.cpp:451
@ PCWHK_FOCUS_FILTER_BOX
Focus the edit box for editing the filter string.
Definition: picker_gui.h:185
void BuildPickerTypeList()
Builds the filter list of types.
Definition: picker_gui.cpp:520
void OnResize() override
Called after the window got resized.
Definition: picker_gui.cpp:324
@ 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
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.
Definition: picker_gui.cpp:412
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.
Definition: widget_type.h:780
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition: widget.cpp:2394
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
Definition: widget_type.h:841
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
RectPadding fullbevel
Always-scaled bevel thickness.
Definition: window_gui.h:41
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
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.
Definition: widget_type.h:1181
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1260
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
Definition: widget_type.h:1228
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
std::unique_ptr< NWidgetBase > MakeNWidgets(std::span< const NWidgetPart > nwid_parts, std::unique_ptr< NWidgetBase > &&container)
Construct a nested widget tree from an array of parts.
Definition: widget.cpp:3239
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1214
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
Definition: widget_type.h:1149
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
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.
Definition: picker_gui.cpp:154
std::unique_ptr< NWidgetBase > MakePickerTypeWidgets()
Create nested widgets for the type picker widgets.
Definition: picker_gui.cpp:646
std::unique_ptr< NWidgetBase > MakePickerClassWidgets()
Create nested widgets for the class picker widgets.
Definition: picker_gui.cpp:623
static bool TypeIDSorter(PickerItem const &a, PickerItem const &b)
Sort types by id.
Definition: picker_gui.cpp:138
static void PickerLoadConfig(const IniFile &ini, PickerCallbacks &callbacks)
Load favourites of a picker from config.
Definition: picker_gui.cpp:60
static const std::initializer_list< PickerTypeList::SortFunction *const > _type_sorter_funcs
Sort functions of the PickerTypeList.
Definition: picker_gui.cpp:155
static bool ClassIDSorter(int const &a, int const &b)
Sort classes by id.
Definition: picker_gui.cpp:124
static const std::initializer_list< PickerClassList::SortFunction *const > _class_sorter_funcs
Sort functions of the PickerClassList.
Definition: picker_gui.cpp:153
static bool TypeTagNameFilter(PickerItem const *item, PickerFilterData &filter)
Filter types by class name.
Definition: picker_gui.cpp:146
static const std::initializer_list< PickerTypeList::FilterFunction *const > _type_filter_funcs
Filter functions of the PickerTypeList.
Definition: picker_gui.cpp:156
static void PickerSaveConfig(IniFile &ini, const PickerCallbacks &callbacks)
Save favourites of a picker to config.
Definition: picker_gui.cpp:94
static bool ClassTagNameFilter(int const *item, PickerFilterData &filter)
Filter classes by class name.
Definition: picker_gui.cpp:130
Functions/types etc.
Types related to the picker widgets.
@ WID_PW_MODE_SAVED
Toggle showing only saved types.
Definition: picker_widget.h:26
@ WID_PW_CLASS_FILTER
Editbox filter.
Definition: picker_widget.h:18
@ WID_PW_TYPE_SCROLL
Scrollbar for the matrix.
Definition: picker_widget.h:29
@ WID_PW_TYPE_ITEM
A single item.
Definition: picker_widget.h:28
@ WID_PW_CLASS_LIST
List of classes.
Definition: picker_widget.h:19
@ WID_PW_TYPE_FILTER
Text filter.
Definition: picker_widget.h:23
@ WID_PW_MODE_USED
Toggle showing only used types.
Definition: picker_widget.h:25
@ WID_PW_TYPE_MATRIX
Matrix with items.
Definition: picker_widget.h:27
@ WID_PW_CLASS_SEL
Stack to hide the class picker.
Definition: picker_widget.h:17
@ WID_PW_MODE_ALL
Toggle "Show all" filter mode.
Definition: picker_widget.h:24
@ WID_PW_CLASS_SCROLL
Scrollbar for list of classes.
Definition: picker_widget.h:20
@ WID_PW_TYPE_SEL
Stack to hide the type picker.
Definition: picker_widget.h:22
@ WID_PW_TYPE_NAME
Name of selected item.
Definition: picker_widget.h:30
@ WID_PW_TYPE_RESIZE
Type resize handle.
Definition: picker_widget.h:31
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:58
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:319
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)
Definition: strings_type.h:17
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
Definition: strings_type.h:18
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
std::string name
The name of this item.
Definition: ini_type.h:24
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.
Definition: widget_type.h:1075
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.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
int Height() const
Get height of Rect.
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
Definition: textbuf_type.h:32
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:3151
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 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
Definitions about widgets.
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
Definition: widget_type.h:482
@ SZSP_VERTICAL
Display plane with zero size horizontally, and filling and resizing vertically.
Definition: widget_type.h:481
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ 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:84
@ 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.
Definition: window_type.h:743
@ ES_HANDLED
The passed event is handled.
Definition: window_type.h:744
@ ES_NOT_HANDLED
The passed event is not handled.
Definition: window_type.h:745
@ WC_SELECT_STATION
Select station (when joining stations); Window numbers:
Definition: window_type.h:242
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition: zoom_func.h:107
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:117