OpenTTD Source  20241120-master-g6d3adc6169
network_content_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 "../strings_func.h"
12 #include "../gfx_func.h"
13 #include "../window_func.h"
14 #include "../error.h"
15 #include "../ai/ai.hpp"
16 #include "../game/game.hpp"
17 #include "../base_media_base.h"
18 #include "../openttd.h"
19 #include "../sortlist_type.h"
20 #include "../stringfilter_type.h"
21 #include "../querystring_gui.h"
22 #include "../core/geometry_func.hpp"
23 #include "../textfile_gui.h"
24 #include "../fios.h"
25 #include "network_content_gui.h"
26 
27 
28 #include "table/strings.h"
29 #include "../table/sprites.h"
30 
31 #include <bitset>
32 
33 #include "../safeguards.h"
34 
35 
37 static bool _accepted_external_search = false;
38 
39 
42  const ContentInfo *ci;
43 
45  {
46  this->ConstructWindow();
47 
48  auto textfile = this->ci->GetTextfile(file_type);
49  this->LoadTextfile(textfile.value(), GetContentInfoSubDir(this->ci->type));
50  }
51 
52  StringID GetTypeString() const
53  {
54  switch (this->ci->type) {
55  case CONTENT_TYPE_NEWGRF: return STR_CONTENT_TYPE_NEWGRF;
56  case CONTENT_TYPE_BASE_GRAPHICS: return STR_CONTENT_TYPE_BASE_GRAPHICS;
57  case CONTENT_TYPE_BASE_SOUNDS: return STR_CONTENT_TYPE_BASE_SOUNDS;
58  case CONTENT_TYPE_BASE_MUSIC: return STR_CONTENT_TYPE_BASE_MUSIC;
59  case CONTENT_TYPE_AI: return STR_CONTENT_TYPE_AI;
60  case CONTENT_TYPE_AI_LIBRARY: return STR_CONTENT_TYPE_AI_LIBRARY;
61  case CONTENT_TYPE_GAME: return STR_CONTENT_TYPE_GAME_SCRIPT;
62  case CONTENT_TYPE_GAME_LIBRARY: return STR_CONTENT_TYPE_GS_LIBRARY;
63  case CONTENT_TYPE_SCENARIO: return STR_CONTENT_TYPE_SCENARIO;
64  case CONTENT_TYPE_HEIGHTMAP: return STR_CONTENT_TYPE_HEIGHTMAP;
65  default: NOT_REACHED();
66  }
67  }
68 
69  void SetStringParameters(WidgetID widget) const override
70  {
71  if (widget == WID_TF_CAPTION) {
72  SetDParam(0, this->GetTypeString());
73  SetDParamStr(1, this->ci->name);
74  }
75  }
76 };
77 
78 void ShowContentTextfileWindow(TextfileType file_type, const ContentInfo *ci)
79 {
80  CloseWindowById(WC_TEXTFILE, file_type);
81  new ContentTextfileWindow(file_type, ci);
82 }
83 
86  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
87  NWidget(WWT_PANEL, COLOUR_GREY),
89  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_BAR), SetFill(1, 0),
90  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
91  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCDS_CANCELOK), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), SetFill(1, 0),
92  EndContainer(),
93  EndContainer(),
94 };
95 
98  WDP_CENTER, nullptr, 0, 0,
100  WDF_MODAL,
102 );
103 
105  Window(desc), downloaded_bytes(0), downloaded_files(0), cur_id(UINT32_MAX)
106 {
109 
111 }
112 
113 void BaseNetworkContentDownloadStatusWindow::Close([[maybe_unused]] int data)
114 {
116  this->Window::Close();
117 }
118 
119 void BaseNetworkContentDownloadStatusWindow::UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize)
120 {
121  switch (widget) {
123  SetDParamMaxDigits(0, 8);
124  SetDParamMaxDigits(1, 8);
125  SetDParamMaxDigits(2, 8);
126  size = GetStringBoundingBox(STR_CONTENT_DOWNLOAD_PROGRESS_SIZE);
127  /* We need some spacing for the 'border' */
130  break;
131 
134  break;
135  }
136 }
137 
138 void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, WidgetID widget) const
139 {
140  switch (widget) {
141  case WID_NCDS_PROGRESS_BAR: {
142  /* Draw the % complete with a bar and a text */
143  DrawFrameRect(r, COLOUR_GREY, FR_BORDERONLY | FR_LOWERED);
144  Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
145  DrawFrameRect(ir.WithWidth((uint64_t)ir.Width() * this->downloaded_bytes / this->total_bytes, _current_text_dir == TD_RTL), COLOUR_MAUVE, FR_NONE);
146  SetDParam(0, this->downloaded_bytes);
147  SetDParam(1, this->total_bytes);
148  SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes);
149  DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_HOR_CENTER);
150  break;
151  }
152 
153  case WID_NCDS_PROGRESS_TEXT: {
154  StringID str;
155  if (this->downloaded_bytes == this->total_bytes) {
156  str = STR_CONTENT_DOWNLOAD_COMPLETE;
157  } else if (!this->name.empty()) {
158  SetDParamStr(0, this->name);
159  SetDParam(1, this->downloaded_files);
160  SetDParam(2, this->total_files);
161  str = STR_CONTENT_DOWNLOAD_FILE;
162  } else {
163  str = STR_CONTENT_DOWNLOAD_INITIALISE;
164  }
165  DrawStringMultiLine(r, str, TC_FROMSTRING, SA_CENTER);
166  break;
167  }
168  }
169 }
170 
171 void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes)
172 {
173  if (ci->id != this->cur_id) {
174  this->name = ci->filename;
175  this->cur_id = ci->id;
176  this->downloaded_files++;
177  }
178 
179  /* A negative value means we are resetting; for example, when retrying or using a fallback. */
180  if (bytes < 0) {
181  this->downloaded_bytes = 0;
182  } else {
183  this->downloaded_bytes += bytes;
184  }
185 
186  this->SetDirty();
187 }
188 
189 
192 private:
193  std::vector<ContentType> receivedTypes;
194 
195 public:
201  {
203  }
204 
205  void Close([[maybe_unused]] int data = 0) override
206  {
208  for (auto ctype : this->receivedTypes) {
209  switch (ctype) {
210  case CONTENT_TYPE_AI:
212  /* AI::Rescan calls the scanner. */
213  break;
214  case CONTENT_TYPE_GAME:
216  /* Game::Rescan calls the scanner. */
217  break;
218 
222  mode |= TarScanner::BASESET;
223  break;
224 
225  case CONTENT_TYPE_NEWGRF:
226  /* ScanNewGRFFiles calls the scanner. */
227  break;
228 
231  mode |= TarScanner::SCENARIO;
232  break;
233 
234  default:
235  break;
236  }
237  }
238 
239  TarScanner::DoScan(mode);
240 
241  /* Tell all the backends about what we've downloaded */
242  for (auto ctype : this->receivedTypes) {
243  switch (ctype) {
244  case CONTENT_TYPE_AI:
246  AI::Rescan();
247  break;
248 
249  case CONTENT_TYPE_GAME:
251  Game::Rescan();
252  break;
253 
257  break;
258 
262  break;
263 
267  break;
268 
269  case CONTENT_TYPE_NEWGRF:
271  break;
272 
275  ScanScenarios();
277  break;
278 
279  default:
280  break;
281  }
282  }
283 
284  /* Always invalidate the download window; tell it we are going to be gone */
286 
287  this->BaseNetworkContentDownloadStatusWindow::Close();
288  }
289 
290  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
291  {
292  if (widget == WID_NCDS_CANCELOK) {
293  if (this->downloaded_bytes != this->total_bytes) {
295  this->Close();
296  } else {
297  /* If downloading succeeded, close the online content window. This will close
298  * the current window as well. */
300  }
301  }
302  }
303 
304  void OnDownloadProgress(const ContentInfo *ci, int bytes) override
305  {
306  BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ci, bytes);
307  include(this->receivedTypes, ci->type);
308 
309  /* When downloading is finished change cancel in ok */
310  if (this->downloaded_bytes == this->total_bytes) {
311  this->GetWidget<NWidgetCore>(WID_NCDS_CANCELOK)->widget_data = STR_BUTTON_OK;
312  }
313  }
314 };
315 
319  std::bitset<CONTENT_TYPE_END> types;
320 };
321 
326 };
327 
332 
333  static const uint EDITBOX_MAX_SIZE = 50;
334 
337  static const std::initializer_list<GUIContentList::SortFunction * const> sorter_funcs;
338  static const std::initializer_list<GUIContentList::FilterFunction * const> filter_funcs;
340  bool auto_select;
344 
346  int list_pos;
349 
350  static std::string content_type_strs[CONTENT_TYPE_END];
351 
354  {
355  std::string url;
356  url.reserve(1024);
357 
358  url += "https://grfsearch.openttd.org/?";
359 
360  if (this->auto_select) {
361  url += "do=searchgrfid&q=";
362 
363  bool first = true;
364  for (const ContentInfo *ci : this->content) {
365  if (ci->state != ContentInfo::DOES_NOT_EXIST) continue;
366 
367  if (!first) url.push_back(',');
368  first = false;
369 
370  fmt::format_to(std::back_inserter(url), "{:08X}:{}", ci->unique_id, FormatArrayAsHex(ci->md5sum));
371  }
372  } else {
373  url += "do=searchtext&q=";
374 
375  /* Escape search term */
376  for (const char *search = this->filter_editbox.text.buf; *search != '\0'; search++) {
377  /* Remove quotes */
378  if (*search == '\'' || *search == '"') continue;
379 
380  /* Escape special chars, such as &%,= */
381  if (*search < 0x30) {
382  fmt::format_to(std::back_inserter(url), "%{:02X}", *search);
383  } else {
384  url.push_back(*search);
385  }
386  }
387  }
388 
389  OpenBrowser(url);
390  }
391 
395  static void ExternalSearchDisclaimerCallback(Window *w, bool accepted)
396  {
397  if (accepted) {
399  ((NetworkContentListWindow*)w)->OpenExternalSearch();
400  }
401  }
402 
408  {
409  if (!this->content.NeedRebuild()) return;
410 
411  /* Create temporary array of games to use for listing */
412  this->content.clear();
413 
414  bool all_available = true;
415 
417  if ((*iter)->state == ContentInfo::DOES_NOT_EXIST) all_available = false;
418  this->content.push_back(*iter);
419  }
420 
421  this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select && all_available);
422 
423  this->FilterContentList();
424  this->content.RebuildDone();
425  this->SortContentList();
426 
427  this->vscroll->SetCount(this->content.size()); // Update the scrollbar
428  this->ScrollToSelected();
429  }
430 
432  static bool NameSorter(const ContentInfo * const &a, const ContentInfo * const &b)
433  {
434  return StrNaturalCompare(a->name, b->name, true) < 0; // Sort by name (natural sorting).
435  }
436 
438  static bool TypeSorter(const ContentInfo * const &a, const ContentInfo * const &b)
439  {
440  int r = 0;
441  if (a->type != b->type) {
443  }
444  if (r == 0) return NameSorter(a, b);
445  return r < 0;
446  }
447 
449  static bool StateSorter(const ContentInfo * const &a, const ContentInfo * const &b)
450  {
451  int r = a->state - b->state;
452  if (r == 0) return TypeSorter(a, b);
453  return r < 0;
454  }
455 
458  {
459  if (!this->content.Sort()) return;
460 
461  int idx = find_index(this->content, this->selected);
462  if (idx >= 0) this->list_pos = idx;
463  }
464 
466  static bool TagNameFilter(const ContentInfo * const *a, ContentListFilterData &filter)
467  {
468  if ((*a)->state == ContentInfo::SELECTED || (*a)->state == ContentInfo::AUTOSELECTED) return true;
469 
470  filter.string_filter.ResetState();
471  for (auto &tag : (*a)->tags) filter.string_filter.AddLine(tag);
472 
473  filter.string_filter.AddLine((*a)->name);
474  return filter.string_filter.GetState();
475  }
476 
478  static bool TypeOrSelectedFilter(const ContentInfo * const *a, ContentListFilterData &filter)
479  {
480  if (filter.types.none()) return true;
481  if (filter.types[(*a)->type]) return true;
482  return ((*a)->state == ContentInfo::SELECTED || (*a)->state == ContentInfo::AUTOSELECTED);
483  }
484 
487  {
488  /* Apply filters. */
489  bool changed = false;
490  if (!this->filter_data.string_filter.IsEmpty()) {
491  this->content.SetFilterType(CONTENT_FILTER_TEXT);
492  changed |= this->content.Filter(this->filter_data);
493  }
494  if (this->filter_data.types.any()) {
496  changed |= this->content.Filter(this->filter_data);
497  }
498  if (!changed) return;
499 
500  /* update list position */
501  int idx = find_index(this->content, this->selected);
502  if (idx >= 0) {
503  this->list_pos = idx;
504  return;
505  }
506 
507  /* previously selected item not in list anymore */
508  this->selected = nullptr;
509  this->list_pos = 0;
510  }
511 
517  {
518  Filtering old_params = this->content.GetFiltering();
519  bool new_state = !this->filter_data.string_filter.IsEmpty() || this->filter_data.types.any();
520  if (new_state != old_params.state) {
521  this->content.SetFilterState(new_state);
522  }
523  return new_state != old_params.state;
524  }
525 
528  {
529  if (this->selected == nullptr) return;
530 
531  this->vscroll->ScrollTowards(this->list_pos);
532  }
533 
535 public:
545  NetworkContentListWindow(WindowDesc &desc, bool select_all, const std::bitset<CONTENT_TYPE_END> &types) :
546  Window(desc),
547  auto_select(select_all),
549  selected(nullptr),
550  list_pos(0)
551  {
552  this->CreateNestedTree();
553  this->vscroll = this->GetScrollbar(WID_NCL_SCROLLBAR);
555 
556  this->GetWidget<NWidgetStacked>(WID_NCL_SEL_ALL_UPDATE)->SetDisplayedPlane(select_all);
557 
559  this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
561  this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select);
562  this->filter_data.types = types;
563 
565  this->content.SetListing(this->last_sorting);
566  this->content.SetFiltering(this->last_filtering);
567  this->content.SetSortFuncs(this->sorter_funcs);
568  this->content.SetFilterFuncs(this->filter_funcs);
569  this->UpdateFilterState();
570  this->content.ForceRebuild();
571  this->FilterContentList();
572  this->SortContentList();
573  this->InvalidateData();
574  }
575 
576  void Close([[maybe_unused]] int data = 0) override
577  {
579  this->Window::Close();
580  }
581 
582  void OnInit() override
583  {
584  this->checkbox_size = maxdim(maxdim(GetScaledSpriteSize(SPR_BOX_EMPTY), GetScaledSpriteSize(SPR_BOX_CHECKED)), GetScaledSpriteSize(SPR_BLOT));
585  }
586 
587  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
588  {
589  switch (widget) {
590  case WID_NCL_CHECKBOX:
591  size.width = this->checkbox_size.width + padding.width;
592  break;
593 
594  case WID_NCL_TYPE: {
595  Dimension d = size;
596  for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
597  d = maxdim(d, GetStringBoundingBox(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS));
598  }
599  size.width = d.width + padding.width;
600  break;
601  }
602 
603  case WID_NCL_MATRIX:
604  resize.height = std::max(this->checkbox_size.height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
605  size.height = 10 * resize.height;
606  break;
607  }
608  }
609 
610 
611  void DrawWidget(const Rect &r, WidgetID widget) const override
612  {
613  switch (widget) {
614  case WID_NCL_DETAILS:
615  this->DrawDetails(r);
616  break;
617 
618  case WID_NCL_MATRIX:
619  this->DrawMatrix(r);
620  break;
621  }
622  }
623 
624  void OnPaint() override
625  {
626  const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
627 
628  if (this->content.NeedRebuild()) {
629  this->BuildContentList();
630  }
631 
632  this->DrawWidgets();
633 
634  switch (this->content.SortType()) {
636  case WID_NCL_TYPE - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_TYPE, arrow); break;
637  case WID_NCL_NAME - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_NAME, arrow); break;
638  }
639  }
640 
645  void DrawMatrix(const Rect &r) const
646  {
647  const Rect checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX)->GetCurrentRect();
648  const Rect name = this->GetWidget<NWidgetBase>(WID_NCL_NAME)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
649  const Rect type = this->GetWidget<NWidgetBase>(WID_NCL_TYPE)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
650 
651  /* Fill the matrix with the information */
652  const uint step_height = this->GetWidget<NWidgetBase>(WID_NCL_MATRIX)->resize_y;
653  const int text_y_offset = WidgetDimensions::scaled.matrix.top + (step_height - WidgetDimensions::scaled.matrix.Vertical() - GetCharacterHeight(FS_NORMAL)) / 2;
654 
655  Rect mr = r.WithHeight(step_height);
656  auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->content);
657  for (auto iter = first; iter != last; iter++) {
658  const ContentInfo *ci = *iter;
659 
660  if (ci == this->selected) GfxFillRect(mr.Shrink(WidgetDimensions::scaled.bevel), PC_GREY);
661 
662  SpriteID sprite;
663  SpriteID pal = PAL_NONE;
664  switch (ci->state) {
665  case ContentInfo::UNSELECTED: sprite = SPR_BOX_EMPTY; break;
666  case ContentInfo::SELECTED: sprite = SPR_BOX_CHECKED; break;
667  case ContentInfo::AUTOSELECTED: sprite = SPR_BOX_CHECKED; break;
668  case ContentInfo::ALREADY_HERE: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
669  case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break;
670  default: NOT_REACHED();
671  }
672  DrawSpriteIgnorePadding(sprite, pal, {checkbox.left, mr.top, checkbox.right, mr.bottom}, SA_CENTER);
673 
674  StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
675  DrawString(type.left, type.right, mr.top + text_y_offset, str, TC_BLACK, SA_HOR_CENTER);
676 
677  DrawString(name.left, name.right, mr.top + text_y_offset, ci->name, TC_BLACK);
678  mr = mr.Translate(0, step_height);
679  }
680  }
681 
686  void DrawDetails(const Rect &r) const
687  {
688  /* Height for the title banner */
690 
691  Rect hr = r.WithHeight(HEADER_HEIGHT).Shrink(WidgetDimensions::scaled.frametext);
692  Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
693  tr.top += HEADER_HEIGHT;
694 
695  /* Create the nice grayish rectangle at the details top */
697  DrawString(hr.left, hr.right, hr.top, STR_CONTENT_DETAIL_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
698 
699  /* Draw the total download size */
700  SetDParam(0, this->filesize_sum);
701  DrawString(tr.left, tr.right, tr.bottom - GetCharacterHeight(FS_NORMAL) + 1, STR_CONTENT_TOTAL_DOWNLOAD_SIZE);
702 
703  if (this->selected == nullptr) return;
704 
705  /* And fill the rest of the details when there's information to place there */
706  DrawStringMultiLine(hr.left, hr.right, hr.top + GetCharacterHeight(FS_NORMAL), hr.bottom, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER);
707 
708  /* Also show the total download size, so keep some space from the bottom */
710 
711  if (this->selected->upgrade) {
712  SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
713  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_UPDATE);
715  }
716 
717  SetDParamStr(0, this->selected->name);
718  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_NAME);
719 
720  if (!this->selected->version.empty()) {
721  SetDParamStr(0, this->selected->version);
722  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_VERSION);
723  }
724 
725  if (!this->selected->description.empty()) {
726  SetDParamStr(0, this->selected->description);
727  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_DESCRIPTION);
728  }
729 
730  if (!this->selected->url.empty()) {
731  SetDParamStr(0, this->selected->url);
732  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_URL);
733  }
734 
735  SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
736  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_TYPE);
737 
739  SetDParam(0, this->selected->filesize);
740  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_FILESIZE);
741 
742  if (!this->selected->dependencies.empty()) {
743  /* List dependencies */
744  std::string buf;
745  for (auto &cid : this->selected->dependencies) {
746  /* Try to find the dependency */
748  for (; iter != _network_content_client.End(); iter++) {
749  const ContentInfo *ci = *iter;
750  if (ci->id != cid) continue;
751 
752  if (!buf.empty()) buf += ", ";
753  buf += (*iter)->name;
754  break;
755  }
756  }
757  SetDParamStr(0, buf);
758  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_DEPENDENCIES);
759  }
760 
761  if (!this->selected->tags.empty()) {
762  /* List all tags */
763  std::string buf;
764  for (auto &tag : this->selected->tags) {
765  if (!buf.empty()) buf += ", ";
766  buf += tag;
767  }
768  SetDParamStr(0, buf);
769  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_TAGS);
770  }
771 
772  if (this->selected->IsSelected()) {
773  /* When selected show all manually selected content that depends on this */
774  ConstContentVector tree;
776 
777  std::string buf;
778  for (const ContentInfo *ci : tree) {
779  if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
780 
781  if (!buf.empty()) buf += ", ";
782  buf += ci->name;
783  }
784  if (!buf.empty()) {
785  SetDParamStr(0, buf);
786  tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF);
787  }
788  }
789  }
790 
791  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
792  {
793  if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_CONTENT_END) {
794  if (this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE) return;
795 
796  ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
797  return;
798  }
799 
800  switch (widget) {
801  case WID_NCL_MATRIX: {
802  auto it = this->vscroll->GetScrolledItemFromWidget(this->content, pt.y, this, WID_NCL_MATRIX);
803  if (it == this->content.end()) return; // click out of bounds
804 
805  this->selected = *it;
806  this->list_pos = it - this->content.begin();
807 
808  const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
809  if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
811  this->content.ForceResort();
812  this->content.ForceRebuild();
813  }
814 
815  if (this->filter_data.types.any()) {
816  this->content.ForceRebuild();
817  }
818 
819  this->InvalidateData();
820  break;
821  }
822 
823  case WID_NCL_CHECKBOX:
824  case WID_NCL_TYPE:
825  case WID_NCL_NAME:
826  if (this->content.SortType() == widget - WID_NCL_CHECKBOX) {
827  this->content.ToggleSortOrder();
828  if (!this->content.empty()) this->list_pos = (int)this->content.size() - this->list_pos - 1;
829  } else {
830  this->content.SetSortType(widget - WID_NCL_CHECKBOX);
831  this->content.ForceResort();
832  this->SortContentList();
833  }
834  this->ScrollToSelected();
835  this->InvalidateData();
836  break;
837 
838  case WID_NCL_SELECT_ALL:
840  this->InvalidateData();
841  break;
842 
845  this->InvalidateData();
846  break;
847 
848  case WID_NCL_UNSELECT:
850  this->InvalidateData();
851  break;
852 
853  case WID_NCL_CANCEL:
854  this->Close();
855  break;
856 
857  case WID_NCL_OPEN_URL:
858  if (this->selected != nullptr) {
859  OpenBrowser(this->selected->url);
860  }
861  break;
862 
863  case WID_NCL_DOWNLOAD:
865  break;
866 
869  this->OpenExternalSearch();
870  } else {
871  ShowQuery(STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION, STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER, this, ExternalSearchDisclaimerCallback);
872  }
873  break;
874  }
875  }
876 
877  EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
878  {
879  if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_NOT_HANDLED) {
880  switch (keycode) {
881  case WKC_SPACE:
882  case WKC_RETURN:
883  if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) {
884  if (this->selected != nullptr) {
886  this->content.ForceResort();
887  this->InvalidateData();
888  }
889  if (this->filter_data.types.any()) {
890  this->content.ForceRebuild();
891  this->InvalidateData();
892  }
893  return ES_HANDLED;
894  }
895  /* space is pressed and filter is focused. */
896  [[fallthrough]];
897 
898  default:
899  return ES_NOT_HANDLED;
900  }
901  }
902 
903  if (this->content.empty()) {
904  if (this->UpdateFilterState()) {
905  this->content.ForceRebuild();
906  this->InvalidateData();
907  }
908  return ES_HANDLED;
909  }
910 
911  this->selected = this->content[this->list_pos];
912 
913  if (this->UpdateFilterState()) {
914  this->content.ForceRebuild();
915  } else {
916  /* Scroll to the new content if it is outside the current range. */
917  this->ScrollToSelected();
918  }
919 
920  /* redraw window */
921  this->InvalidateData();
922  return ES_HANDLED;
923  }
924 
925  void OnEditboxChanged(WidgetID wid) override
926  {
927  if (wid == WID_NCL_FILTER) {
928  this->filter_data.string_filter.SetFilterTerm(this->filter_editbox.text.buf);
929  this->UpdateFilterState();
930  this->content.ForceRebuild();
931  this->InvalidateData();
932  }
933  }
934 
935  void OnResize() override
936  {
937  this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX);
938  }
939 
940  void OnReceiveContentInfo(const ContentInfo *rci) override
941  {
942  if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci);
943  this->content.ForceRebuild();
944  this->InvalidateData(0, false);
945  }
946 
947  void OnDownloadComplete(ContentID) override
948  {
949  this->content.ForceResort();
950  this->InvalidateData();
951  }
952 
953  void OnConnect(bool success) override
954  {
955  if (!success) {
956  ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, WL_ERROR);
957  this->Close();
958  return;
959  }
960 
961  this->InvalidateData();
962  }
963 
969  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
970  {
971  if (!gui_scope) return;
972  if (this->content.NeedRebuild()) this->BuildContentList();
973 
974  /* To sum all the bytes we intend to download */
975  this->filesize_sum = 0;
976  bool show_select_all = false;
977  bool show_select_upgrade = false;
978  for (const ContentInfo *ci : this->content) {
979  switch (ci->state) {
982  this->filesize_sum += ci->filesize;
983  break;
984 
986  show_select_all = true;
987  show_select_upgrade |= ci->upgrade;
988  break;
989 
990  default:
991  break;
992  }
993  }
994 
995  /* If data == 2 then the status window caused this OnInvalidate */
997  this->SetWidgetDisabledState(WID_NCL_UNSELECT, this->filesize_sum == 0);
998  this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all);
999  this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade || !this->filter_data.string_filter.IsEmpty());
1000  this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == nullptr || this->selected->url.empty());
1001  for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
1002  this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE || !this->selected->GetTextfile(tft).has_value());
1003  }
1004 
1005  this->GetWidget<NWidgetCore>(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL;
1006  }
1007 };
1008 
1011 
1012 const std::initializer_list<NetworkContentListWindow::GUIContentList::SortFunction * const> NetworkContentListWindow::sorter_funcs = {
1013  &StateSorter,
1014  &TypeSorter,
1015  &NameSorter,
1016 };
1017 
1018 const std::initializer_list<NetworkContentListWindow::GUIContentList::FilterFunction * const> NetworkContentListWindow::filter_funcs = {
1019  &TagNameFilter,
1020  &TypeOrSelectedFilter,
1021 };
1022 
1024 
1029 {
1030  for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
1031  NetworkContentListWindow::content_type_strs[i] = GetString(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS);
1032  }
1033 }
1034 
1038  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1039  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_CONTENT_TITLE, STR_NULL),
1040  NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
1041  EndContainer(),
1042  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_BACKGROUND),
1044  /* Top */
1046  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_CONTENT_FILTER_TITLE, STR_NULL), SetAlignment(SA_RIGHT | SA_VERT_CENTER),
1047  NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0),
1048  SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
1049  EndContainer(),
1050  /* Lists and info. */
1052  /* Left side. */
1057  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CHECKBOX), SetDataTip(STR_EMPTY, STR_NULL),
1058  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TYPE),
1059  SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
1060  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_NAME), SetResize(1, 0), SetFill(1, 0),
1061  SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
1062  EndContainer(),
1063  NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NCL_MATRIX), SetResize(1, 1), SetFill(1, 1), SetScrollbar(WID_NCL_SCROLLBAR), SetMatrixDataTip(1, 0, STR_CONTENT_MATRIX_TOOLTIP),
1064  EndContainer(),
1065  NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR),
1066  EndContainer(),
1068  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE),
1069  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0),
1070  SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
1071  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0),
1072  SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
1073  EndContainer(),
1074  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0),
1075  SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
1076  EndContainer(),
1077  EndContainer(),
1078  /* Right side. */
1080  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1),
1081  EndContainer(),
1084  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1085  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1086  EndContainer(),
1088  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1089  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1090  EndContainer(),
1091  EndContainer(),
1092  EndContainer(),
1093  EndContainer(),
1094  /* Bottom. */
1096  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SEARCH_EXTERNAL), SetResize(1, 0), SetFill(1, 0),
1097  SetDataTip(STR_CONTENT_SEARCH_EXTERNAL, STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP),
1099  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CANCEL), SetResize(1, 0), SetFill(1, 0),
1100  SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
1101  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
1102  SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
1103  EndContainer(),
1104  EndContainer(),
1105  EndContainer(),
1106  /* Resize button. */
1108  NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1109  NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetDataTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1110  EndContainer(),
1111  EndContainer(),
1112 };
1113 
1116  WDP_CENTER, "list_content", 630, 460,
1118  0,
1120 );
1121 
1130 {
1131 #if defined(WITH_ZLIB)
1132  std::bitset<CONTENT_TYPE_END> types;
1134  if (cv == nullptr) {
1135  assert(type1 != CONTENT_TYPE_END || type2 == CONTENT_TYPE_END);
1136  assert(type1 == CONTENT_TYPE_END || type1 != type2);
1139 
1140  if (type1 != CONTENT_TYPE_END) types[type1] = true;
1141  if (type2 != CONTENT_TYPE_END) types[type2] = true;
1142  } else {
1144  }
1145 
1147  new NetworkContentListWindow(_network_content_list_desc, cv != nullptr, types);
1148 #else
1149  ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR);
1150  /* Connection failed... clean up the mess */
1151  if (cv != nullptr) {
1152  for (ContentInfo *ci : *cv) delete ci;
1153  }
1154 #endif /* WITH_ZLIB */
1155 }
static void Rescan()
Rescans all searchpaths for available AIs.
Definition: ai_core.cpp:326
static uint FindSets()
Do the scan for files.
Base window for showing the download status of content.
uint32_t cur_id
The current ID of the downloaded file.
BaseNetworkContentDownloadStatusWindow(WindowDesc &desc)
Create the window with the given description.
uint downloaded_bytes
Number of bytes downloaded.
uint total_files
Number of files to download.
std::string name
The current name of the downloaded file.
uint downloaded_files
Number of files downloaded.
uint total_bytes
Number of bytes to download.
ConstContentIterator Begin() const
Get the begin of the content inf iterator.
void SelectUpgrade()
Select everything that's an update for something we've got.
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
void ToggleSelectedState(const ContentInfo *ci)
Toggle the state of a content info and check its dependencies.
void RemoveCallback(ContentCallback *cb)
Remove a callback.
void UnselectAll()
Unselect everything that we've not downloaded so far.
void RequestContentList(ContentType type)
Request the content list for the given type.
void ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
Reverse lookup the dependencies of all parents over a given child.
void AddCallback(ContentCallback *cb)
Add a callback to this class.
void Clear()
Clear all downloaded content information.
ConstContentIterator End() const
Get the end of the content inf iterator.
void Cancel()
Cancel the current download.
void SelectAll()
Select everything we can select.
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.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
Filtering GetFiltering() const
Export current filter conditions.
bool NeedRebuild() const
Check if a rebuild is needed.
void SetFilterType(uint8_t n_type)
Set the filtertype of the list.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
Baseclass for nested widgets.
Definition: widget_type.h:144
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:243
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:248
Window that lists the content that's at the content server.
static bool NameSorter(const ContentInfo *const &a, const ContentInfo *const &b)
Sort content by name.
void DrawDetails(const Rect &r) const
Helper function to draw the details part of this window.
void OpenExternalSearch()
Search external websites for content.
void DrawMatrix(const Rect &r) const
Draw/fill the matrix with the list of content to download.
void OnResize() override
Called after the window got resized.
static std::string content_type_strs[CONTENT_TYPE_END]
Cached strings for all content types.
GUIContentList content
List with content.
uint filesize_sum
The sum of all selected file sizes.
bool auto_select
Automatically select all content when the meta-data becomes available.
ContentListFilterData filter_data
Filter for content list.
static Filtering last_filtering
The last filtering setting.
QueryString filter_editbox
Filter editbox;.
static const std::initializer_list< GUIContentList::SortFunction *const > sorter_funcs
Sorter functions.
static Listing last_sorting
The last sorting setting.
static bool TagNameFilter(const ContentInfo *const *a, ContentListFilterData &filter)
Filter content by tags/name.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
int list_pos
Our position in the list.
static bool TypeOrSelectedFilter(const ContentInfo *const *a, ContentListFilterData &filter)
Filter content by type, but still show content selected for download.
const ContentInfo * selected
The selected content info.
void OnInit() override
Notification that the nested widget tree gets initialized.
static const std::initializer_list< GUIContentList::FilterFunction *const > filter_funcs
Filter functions.
static bool TypeSorter(const ContentInfo *const &a, const ContentInfo *const &b)
Sort content by type.
void SortContentList()
Sort the content list.
static void ExternalSearchDisclaimerCallback(Window *w, bool accepted)
Callback function for disclaimer about entering external websites.
bool UpdateFilterState()
Update filter state based on current window state.
void OnPaint() override
The window must be repainted.
GUIList< const ContentInfo *, std::nullptr_t, ContentListFilterData & > GUIContentList
List with content infos.
static const uint EDITBOX_MAX_SIZE
Maximum size of the editbox in characters.
void BuildContentList()
(Re)build the network game list as its amount has changed because an item has been added or deleted f...
NetworkContentListWindow(WindowDesc &desc, bool select_all, const std::bitset< CONTENT_TYPE_END > &types)
Create the content list window.
Scrollbar * vscroll
Cache of the vertical scrollbar.
friend void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
void FilterContentList()
Filter the content list.
Dimension checkbox_size
Size of checkbox/"blot" sprite.
void ScrollToSelected()
Make sure that the currently selected content info is within the visible part of the matrix.
static bool StateSorter(const ContentInfo *const &a, const ContentInfo *const &b)
Sort content by state.
Scrollbar data structure.
Definition: widget_type.h:694
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
Definition: widget_type.h:879
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
EventState UpdateListPositionOnKeyPress(int &list_position, uint16_t keycode) const
Update the given list position as if it were on this scroll bar when the given keycode was pressed.
Definition: widget.cpp:2341
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
Definition: widget_type.h:841
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition: widget_type.h:860
uint DoScan(Subdirectory sd)
Perform the scanning of a particular subdirectory.
Definition: fileio.cpp:375
Mode
The mode of tar scanning.
Definition: fileio_func.h:63
@ BASESET
Scan for base sets.
Definition: fileio_func.h:65
@ NONE
Scan nothing.
Definition: fileio_func.h:64
@ SCENARIO
Scan for scenarios and heightmaps.
Definition: fileio_func.h:68
RectPadding frametext
Padding inside frame with text.
Definition: window_gui.h:43
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
int vsep_normal
Normal vertical spacing.
Definition: window_gui.h:60
int vsep_wide
Wide vertical spacing.
Definition: window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
RectPadding matrix
Padding of WWT_MATRIX items.
Definition: window_gui.h:44
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
int find_index(Container const &container, typename Container::const_reference item)
Helper function to get the index of an item Consider using std::set, std::unordered_set or std::flat_...
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_ERROR
Errors (eg. saving/loading failed)
Definition: error.h:26
void ScanScenarios()
Force a (re)scan of the scenarios.
Definition: fios.cpp:718
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
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
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
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
@ SA_RIGHT
Right align the text (must be a single bit).
Definition: gfx_type.h:345
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_type.h:344
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_type.h:353
@ SA_VERT_CENTER
Vertically center the text.
Definition: gfx_type.h:349
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
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
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 SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
Definition: widget_type.h:1170
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Definition: math_func.hpp:252
void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback, bool focus)
Show a confirmation window with standard 'yes' and 'no' buttons The window is aligned to the centre o...
Definition: misc_gui.cpp:1223
@ WID_TF_CAPTION
The caption of the window.
Definition: misc_widget.h:50
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
std::vector< const ContentInfo * > ConstContentVector
Vector with constant content info.
std::vector< ContentInfo * > ContentVector
Vector with content info.
const ContentInfo *const * ConstContentIterator
Iterator for the constant content vector.
static bool _accepted_external_search
Whether the user accepted to enter external websites during this session.
static constexpr NWidgetPart _nested_network_content_list_widgets[]
The widgets for the content list.
ContentListFilterCriteria
Filter criteria for NetworkContentListWindow.
@ CONTENT_FILTER_TYPE_OR_SELECTED
Filter by being of displayed type or selected for download.
@ CONTENT_FILTER_TEXT
Filter by query sting.
static constexpr NWidgetPart _nested_network_content_download_status_window_widgets[]
Nested widgets for the download window.
static WindowDesc _network_content_download_status_window_desc(WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_network_content_download_status_window_widgets)
Window description for the download window.
void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentType type2)
Show the content list window with a given set of content.
static WindowDesc _network_content_list_desc(WDP_CENTER, "list_content", 630, 460, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_content_list_widgets)
Window description of the content list.
void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
User interface for downloading files.
@ WID_NCL_CHECKBOX
Button above checkboxes.
@ WID_NCL_NAME
'Name' button.
@ WID_NCL_TYPE
'Type' button.
@ WID_NCL_SEARCH_EXTERNAL
Search external sites for missing NewGRF.
@ WID_NCL_CANCEL
'Cancel' button.
@ WID_NCL_DETAILS
Panel with content details.
@ WID_NCL_SEL_ALL_UPDATE
NWID_SELECTION widget for select all/update buttons..
@ WID_NCL_SELECT_ALL
'Select all' button.
@ WID_NCL_FILTER
Filter editbox.
@ WID_NCL_FILTER_CAPT
Caption for the filter editbox.
@ WID_NCL_DOWNLOAD
'Download' button.
@ WID_NCL_SCROLLBAR
Scrollbar of matrix.
@ WID_NCL_SELECT_UPDATE
'Select updates' button.
@ WID_NCL_TEXTFILE
Open readme, changelog (+1) or license (+2) of a file in the content window.
@ WID_NCL_MATRIX
Panel with list of content.
@ WID_NCL_BACKGROUND
Resize button.
@ WID_NCL_UNSELECT
'Unselect all' button.
@ WID_NCL_OPEN_URL
'Open url' button.
@ WID_NCDS_CANCELOK
(Optional) Cancel/OK button.
@ WID_NCDS_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NCDS_PROGRESS_BAR
Simple progress bar.
bool RequestNewGRFScan(NewGRFScanCallback *callback)
Request a new NewGRF scan.
Definition: openttd.cpp:1331
static const uint8_t PC_GREY
Grey palette colour.
Definition: palette_func.h:69
static const uint8_t PC_DARK_BLUE
Dark blue palette colour.
Definition: palette_func.h:87
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
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:319
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:357
void SetDParamMaxDigits(size_t n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:143
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Callbacks for notifying others about incoming data.
Container for all important information about a piece of content.
uint32_t unique_id
Unique ID; either GRF ID or shortname.
uint32_t filesize
Size of the file.
MD5Hash md5sum
The MD5 checksum.
std::string url
URL related to the content.
State state
Whether the content info is selected (for download)
std::string name
Name of the content.
std::string description
Description of the content.
std::optional< std::string > GetTextfile(TextfileType type) const
Search a textfile file next to this file in the content list.
Definition: tcp_content.cpp:54
std::string version
Version of the content.
ContentID id
Unique (server side) ID for the content.
@ DOES_NOT_EXIST
The content does not exist in the content system.
@ ALREADY_HERE
The content is already at the client side.
@ AUTOSELECTED
The content has been selected as dependency.
@ UNSELECTED
The content has not been selected.
@ SELECTED
The content has been manually selected.
std::string filename
Filename (for the .tar.gz; only valid on download)
bool IsSelected() const
Is the state either selected or autoselected?
Definition: tcp_content.cpp:27
ContentType type
Type of content.
std::vector< ContentID > dependencies
The dependencies (unique server side ids)
StringList tags
Tags associated with the content.
bool upgrade
This item is an upgrade.
Filter data for NetworkContentListWindow.
std::bitset< CONTENT_TYPE_END > types
Content types displayed.
StringFilter string_filter
Text filter of content list.
Window for displaying the textfile of an item in the content list.
const ContentInfo * ci
View the textfile of this ContentInfo.
Dimensions (a width and height) of a rectangle in 2D.
Data structure describing what to show in the list (filter criteria).
Definition: sortlist_type.h:35
bool state
Filter on/off.
Definition: sortlist_type.h:36
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:30
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Window for showing the download status of content.
std::vector< ContentType > receivedTypes
Types we received so we can update their cache.
NetworkContentDownloadStatusWindow()
Create a new download window based on a list of content information with flags whether to download th...
Coordinates of a point in 2D.
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
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.
char *const buf
buffer in which text is saved
Definition: textbuf_type.h:32
Window for displaying a textfile.
Definition: textfile_gui.h:21
TextfileType file_type
Type of textfile to view.
Definition: textfile_gui.h:22
virtual void LoadTextfile(const std::string &textfile, Subdirectory dir)
Loads the textfile text from file and setup lines.
High level window description.
Definition: window_gui.h:159
Data structure for an opened window.
Definition: window_gui.h:273
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:1047
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition: window_gui.h:320
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition: window.cpp:3151
Window * parent
Parent window.
Definition: window_gui.h:328
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition: widget.cpp:763
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
bool IsWidgetFocused(WidgetID widget_index) const
Check if given widget is focused within this window.
Definition: window_gui.h:426
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
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:387
Subdirectory GetContentInfoSubDir(ContentType type)
Helper to get the subdirectory a ContentInfo is located in.
ContentType
The values in the enum are important; they are used as database 'keys'.
@ CONTENT_TYPE_AI_LIBRARY
The content consists of an AI library.
@ CONTENT_TYPE_BASE_SOUNDS
The content consists of base sounds.
@ CONTENT_TYPE_GAME_LIBRARY
The content consists of a GS library.
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
@ CONTENT_TYPE_AI
The content consists of an AI.
@ CONTENT_TYPE_SCENARIO
The content consists of a scenario.
@ CONTENT_TYPE_NEWGRF
The content consists of a NewGRF.
@ CONTENT_TYPE_BEGIN
Helper to mark the begin of the types.
@ CONTENT_TYPE_BASE_MUSIC
The content consists of base music.
@ CONTENT_TYPE_GAME
The content consists of a game script.
@ CONTENT_TYPE_END
Helper to mark the end of the types.
@ CONTENT_TYPE_HEIGHTMAP
The content consists of a heightmap.
ContentID
Unique identifier for the content.
TextfileType
Additional text files accompanying Tar archives.
Definition: textfile_type.h:14
@ TFT_LICENSE
Content license.
Definition: textfile_type.h:19
@ TFT_README
Content readme.
Definition: textfile_type.h:17
@ TFT_CHANGELOG
Content changelog.
Definition: textfile_type.h:18
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:281
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:112
@ NWID_SPACER
Invisible widget that takes some space.
Definition: widget_type.h:79
@ WWT_EDITBOX
a textbox for typing
Definition: widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_MATRIX
Grid of rows and columns.
Definition: widget_type.h:59
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition: widget_type.h:48
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
@ WWT_TEXT
Pure simple text.
Definition: widget_type.h:58
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:80
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition: widget_type.h:40
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition: window.cpp:1223
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1098
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3211
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
SortButtonState
State of a sort direction button.
Definition: window_gui.h:218
@ SBS_DOWN
Sort ascending.
Definition: window_gui.h:220
@ SBS_UP
Sort descending.
Definition: window_gui.h:221
@ FR_BORDERONLY
Draw border only, no background.
Definition: window_gui.h:27
@ FR_LOWERED
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
Definition: window_gui.h:28
@ WDF_MODAL
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition: window_gui.h:204
@ WDP_CENTER
Center the window.
Definition: window_gui.h:148
int WidgetID
Widget ID.
Definition: window_type.h:18
@ WN_NETWORK_WINDOW_CONTENT_LIST
Network content list.
Definition: window_type.h:36
@ WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD
Network content download status.
Definition: window_type.h:40
@ WN_GAME_OPTIONS_GAME_OPTIONS
Game options.
Definition: window_type.h:26
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_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_GAME_OPTIONS
Game options window; Window numbers:
Definition: window_type.h:624
@ WC_NETWORK_WINDOW
Network window; Window numbers:
Definition: window_type.h:478
@ WC_TEXTFILE
textfile; Window numbers:
Definition: window_type.h:187
@ WC_SAVELOAD
Saveload window; Window numbers:
Definition: window_type.h:144
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
Definition: window_type.h:491