OpenTTD Source 20260731-master-g77ba2b244a
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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"
19#include "../base_media_music.h"
21#include "../openttd.h"
22#include "../sortlist_type.h"
24#include "../querystring_gui.h"
26#include "../textfile_gui.h"
27#include "../fios.h"
28#include "network_content_gui.h"
29
32
33#include "table/strings.h"
34#include "../table/sprites.h"
35
36#include "../safeguards.h"
37
38
40static bool _accepted_external_search = false;
41
48{
49 switch (type) {
50 case ContentType::NewGRF: return STR_CONTENT_TYPE_NEWGRF;
51 case ContentType::BaseGraphics: return STR_CONTENT_TYPE_BASE_GRAPHICS;
52 case ContentType::BaseSounds: return STR_CONTENT_TYPE_BASE_SOUNDS;
53 case ContentType::BaseMusic: return STR_CONTENT_TYPE_BASE_MUSIC;
54 case ContentType::Ai: return STR_CONTENT_TYPE_AI;
55 case ContentType::AiLibrary: return STR_CONTENT_TYPE_AI_LIBRARY;
56 case ContentType::Gs: return STR_CONTENT_TYPE_GAME_SCRIPT;
57 case ContentType::GsLibrary: return STR_CONTENT_TYPE_GS_LIBRARY;
58 case ContentType::Scenario: return STR_CONTENT_TYPE_SCENARIO;
59 case ContentType::Heightmap: return STR_CONTENT_TYPE_HEIGHTMAP;
60 default: NOT_REACHED();
61 }
62}
63
65struct ContentTextfileWindow : public TextfileWindow {
66 const ContentInfo *ci = nullptr;
67
75 {
76 this->ConstructWindow();
77
78 auto textfile = this->ci->GetTextfile(file_type);
79 this->LoadTextfile(textfile.value(), GetContentInfoSubDir(this->ci->type));
80 }
81
82 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
83 {
84 if (widget == WID_TF_CAPTION) {
85 return GetString(stringid, GetContentTypeString(this->ci->type), this->ci->name);
86 }
87
88 return this->Window::GetWidgetString(widget, stringid);
89 }
90};
91
98static void ShowContentTextfileWindow(Window *parent, TextfileType file_type, const ContentInfo *ci)
99{
100 parent->CloseChildWindowById(WindowClass::Textfile, file_type);
101 new ContentTextfileWindow(parent, file_type, ci);
102}
103
105static constexpr std::initializer_list<NWidgetPart> _nested_network_content_download_status_window_widgets = {
106 NWidget(WWT_CAPTION, Colours::Grey), SetStringTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
112 EndContainer(),
113 EndContainer(),
114};
115
118 WindowPosition::Center, {}, 0, 0,
119 WindowClass::NetworkStatus, WindowClass::None,
122);
123
131
133{
134 _network_content_client.RemoveCallback(this);
135 this->Window::Close();
136}
137
138void BaseNetworkContentDownloadStatusWindow::UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize)
139{
140 switch (widget) {
142 auto max_value = GetParamMaxDigits(8);
143 size = GetStringBoundingBox(GetString(STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, max_value, max_value, max_value));
144 /* We need some spacing for the 'border' */
145 size.height += WidgetDimensions::scaled.frametext.Horizontal();
146 size.width += WidgetDimensions::scaled.frametext.Vertical();
147 break;
148 }
149
151 size.height = GetCharacterHeight(FontSize::Normal) * 2 + WidgetDimensions::scaled.vsep_normal;
152 break;
153 }
154}
155
157{
158 switch (widget) {
160 /* Draw the % complete with a bar and a text */
163 DrawFrameRect(ir.WithWidth((uint64_t)ir.Width() * this->downloaded_bytes / this->total_bytes, _current_text_dir == TD_RTL), Colours::Mauve, {});
164 DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FontSize::Normal)),
165 GetString(STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, this->downloaded_bytes, this->total_bytes, this->downloaded_bytes * 100LL / this->total_bytes),
167 break;
168 }
169
171 if (this->downloaded_bytes == this->total_bytes) {
173 } else if (!this->name.empty()) {
175 GetString(STR_CONTENT_DOWNLOAD_FILE, this->name, this->downloaded_files, this->total_files),
177 } else {
179 }
180 break;
181 }
182}
183
185{
186 if (ci.id != this->cur_id) {
187 this->name = ci.filename;
188 this->cur_id = ci.id;
189 this->downloaded_files++;
190 }
191
192 /* A negative value means we are resetting; for example, when retrying or using a fallback. */
193 if (bytes < 0) {
194 this->downloaded_bytes = 0;
195 } else {
196 this->downloaded_bytes += bytes;
197 }
198
199 this->SetDirty();
200}
201
202
205private:
207
208public:
217
218 void Close([[maybe_unused]] int data = 0) override
219 {
220 TarScanner::Modes modes{};
221 for (auto ctype : this->received_types) {
222 switch (ctype) {
223 case ContentType::Ai:
225 /* AI::Rescan calls the scanner. */
226 break;
227 case ContentType::Gs:
229 /* Game::Rescan calls the scanner. */
230 break;
231
236 break;
237
239 /* ScanNewGRFFiles calls the scanner. */
240 break;
241
245 break;
246
247 default:
248 break;
249 }
250 }
251
252 TarScanner::DoScan(modes);
253
254 /* Tell all the backends about what we've downloaded */
255 for (auto ctype : this->received_types) {
256 switch (ctype) {
257 case ContentType::Ai:
259 AI::Rescan();
260 break;
261
262 case ContentType::Gs:
264 Game::Rescan();
265 break;
266
269 SetWindowDirty(WindowClass::GameOptions, GameOptionsWindowNumber::GameOptions);
270 break;
271
274 SetWindowDirty(WindowClass::GameOptions, GameOptionsWindowNumber::GameOptions);
275 break;
276
279 SetWindowDirty(WindowClass::GameOptions, GameOptionsWindowNumber::GameOptions);
280 break;
281
284 break;
285
289 InvalidateWindowData(WindowClass::SaveLoad, 0, 0);
290 break;
291
292 default:
293 break;
294 }
295 }
296
297 /* Always invalidate the download window; tell it we are going to be gone */
299
301 }
302
303 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
304 {
305 if (widget == WID_NCDS_CANCELOK) {
306 if (this->downloaded_bytes != this->total_bytes) {
308 this->Close();
309 } else {
310 /* If downloading succeeded, close the online content window. This will close
311 * the current window as well. */
313 }
314 }
315 }
316
317 void OnDownloadProgress(const ContentInfo &ci, int bytes) override
318 {
320 this->received_types.Set(ci.type);
321
322 /* When downloading is finished change cancel in ok */
323 if (this->downloaded_bytes == this->total_bytes) {
324 this->GetWidget<NWidgetCore>(WID_NCDS_CANCELOK)->SetString(STR_BUTTON_OK);
325 }
326 }
327};
328
334
340
345
346 static const uint EDITBOX_MAX_SIZE = 50;
347
348 static Listing last_sorting;
350 static const std::initializer_list<GUIContentList::SortFunction * const> sorter_funcs;
351 static const std::initializer_list<GUIContentList::FilterFunction * const> filter_funcs;
353 bool auto_select = false;
357
358 const ContentInfo *selected = nullptr;
359 int list_pos = 0;
360 uint filesize_sum = 0;
361 Scrollbar *vscroll = nullptr;
362
364
367 {
368 std::string url;
369 url.reserve(1024);
370
371 url += "https://grfsearch.openttd.org/?";
372
373 if (this->auto_select) {
374 url += "do=searchgrfid&q=";
375
376 bool first = true;
377 for (const ContentInfo *ci : this->content) {
378 if (ci->state != ContentInfo::State::DoesNotExist) continue;
379
380 if (!first) url.push_back(',');
381 first = false;
382
383 format_append(url, "{:08X}:{}", ci->unique_id, FormatArrayAsHex(ci->md5sum));
384 }
385 } else {
386 url += "do=searchtext&q=";
387
388 /* Escape search term */
389 for (char search : this->filter_editbox.text.GetText()) {
390 /* Remove quotes */
391 if (search == '\'' || search == '"') continue;
392
393 /* Escape special chars, such as &%,= */
394 if (static_cast<unsigned char>(search) < 0x30) {
395 format_append(url, "%{:02X}", search);
396 } else {
397 url.push_back(search);
398 }
399 }
400 }
401
402 OpenBrowser(url);
403 }
404
410 static void ExternalSearchDisclaimerCallback(Window *w, bool accepted)
411 {
412 if (accepted) {
414 ((NetworkContentListWindow*)w)->OpenExternalSearch();
415 }
416 }
417
423 {
424 if (!this->content.NeedRebuild()) return;
425
426 /* Create temporary array of games to use for listing */
427 this->content.clear();
428
429 bool all_available = true;
430
431 for (const ContentInfo &ci : _network_content_client.Info()) {
432 if (ci.state == ContentInfo::State::DoesNotExist) all_available = false;
433 this->content.push_back(&ci);
434 }
435
436 this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select && all_available);
437
438 this->FilterContentList();
439 this->content.RebuildDone();
440 this->SortContentList();
441
442 this->vscroll->SetCount(this->content.size()); // Update the scrollbar
443 this->ScrollToSelected();
444 }
445
447 static bool NameSorter(const ContentInfo * const &a, const ContentInfo * const &b)
448 {
449 int r = StrNaturalCompare(a->name, b->name, true); // Sort by name (natural sorting).
450 if (r == 0) r = StrNaturalCompare(a->version, b->version, true);
451 return r < 0;
452 }
453
455 static bool TypeSorter(const ContentInfo * const &a, const ContentInfo * const &b)
456 {
457 int r = 0;
458 if (a->type != b->type) {
460 }
461 if (r == 0) return NameSorter(a, b);
462 return r < 0;
463 }
464
466 static bool StateSorter(const ContentInfo * const &a, const ContentInfo * const &b)
467 {
468 int r = to_underlying(a->state) - to_underlying(b->state);
469 if (r == 0) return TypeSorter(a, b);
470 return r < 0;
471 }
472
475 {
476 if (!this->content.Sort()) return;
477
478 int idx = find_index(this->content, this->selected);
479 if (idx >= 0) this->list_pos = idx;
480 }
481
483 static bool TagNameFilter(const ContentInfo * const *item, ContentListFilterData &filter)
484 {
485 if ((*item)->state == ContentInfo::State::Selected || (*item)->state == ContentInfo::State::Autoselected) return true;
486
487 filter.string_filter.ResetState();
488 for (auto &tag : (*item)->tags) filter.string_filter.AddLine(tag);
489
490 filter.string_filter.AddLine((*item)->name);
491 return filter.string_filter.GetState();
492 }
493
495 static bool TypeOrSelectedFilter(const ContentInfo * const *item, ContentListFilterData &filter)
496 {
497 if (filter.types.None()) return true;
498 if (filter.types.Test((*item)->type)) return true;
499 return ((*item)->state == ContentInfo::State::Selected || (*item)->state == ContentInfo::State::Autoselected);
500 }
501
504 {
505 /* Apply filters. */
506 bool changed = false;
507 if (!this->filter_data.string_filter.IsEmpty()) {
508 this->content.SetFilterType(CONTENT_FILTER_TEXT);
509 changed |= this->content.Filter(this->filter_data);
510 }
511 if (this->filter_data.types.Any()) {
513 changed |= this->content.Filter(this->filter_data);
514 }
515 if (!changed) return;
516
517 /* update list position */
518 int idx = find_index(this->content, this->selected);
519 if (idx >= 0) {
520 this->list_pos = idx;
521 return;
522 }
523
524 /* previously selected item not in list anymore */
525 this->selected = nullptr;
526 this->list_pos = 0;
527 }
528
534 {
535 Filtering old_params = this->content.GetFiltering();
536 bool new_state = !this->filter_data.string_filter.IsEmpty() || this->filter_data.types.Any();
537 if (new_state != old_params.state) {
538 this->content.SetFilterState(new_state);
539 }
540 return new_state != old_params.state;
541 }
542
545 {
546 if (this->selected == nullptr) return;
547
548 this->vscroll->ScrollTowards(this->list_pos);
549 }
550
552public:
562 NetworkContentListWindow(WindowDesc &desc, bool select_all, ContentTypes types) :
563 Window(desc),
564 auto_select(select_all),
566 {
567 this->CreateNestedTree();
568 this->vscroll = this->GetScrollbar(WID_NCL_SCROLLBAR);
570
571 this->GetWidget<NWidgetStacked>(WID_NCL_SEL_ALL_UPDATE)->SetDisplayedPlane(select_all);
572
573 this->querystrings[WID_NCL_FILTER] = &this->filter_editbox;
574 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
576 this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select);
577 this->filter_data.types = types;
578
579 _network_content_client.AddCallback(this);
580 this->content.SetListing(this->last_sorting);
581 this->content.SetFiltering(this->last_filtering);
582 this->content.SetSortFuncs(this->sorter_funcs);
583 this->content.SetFilterFuncs(this->filter_funcs);
584 this->UpdateFilterState();
585 this->content.ForceRebuild();
586 this->FilterContentList();
587 this->SortContentList();
588 this->InvalidateData();
589 }
590
591 void Close([[maybe_unused]] int data = 0) override
592 {
593 _network_content_client.RemoveCallback(this);
594 this->Window::Close();
595 }
596
597 void OnInit() override
598 {
599 this->checkbox_size = maxdim(maxdim(GetScaledSpriteSize(SPR_BOX_EMPTY), GetScaledSpriteSize(SPR_BOX_CHECKED)), GetScaledSpriteSize(SPR_BLOT));
600 }
601
602 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
603 {
604 switch (widget) {
605 case WID_NCL_CHECKBOX:
606 size.width = std::max<uint>(this->checkbox_size.width, Window::SortButtonWidth()) + padding.width;
607 break;
608
609 case WID_NCL_TYPE: {
610 /* Width must be enough for header label and sort buttons.*/
611 size.width += Window::SortButtonWidth() * 2;
612 /* And also enough for the width of each type of content. */
613 Dimension d = size;
616 }
617 size.width = std::max(size.width, d.width + padding.width);
618 break;
619 }
620
621 case WID_NCL_NAME:
622 size.width += Window::SortButtonWidth() * 2;
623 break;
624
625 case WID_NCL_MATRIX:
626 fill.height = resize.height = std::max<uint>(std::max<uint>(this->checkbox_size.height, GetCharacterHeight(FontSize::Normal)), GetCharacterHeight(FontSize::Small)) + padding.height;
627 size.height = 10 * resize.height;
628 break;
629 }
630 }
631
632
633 void DrawWidget(const Rect &r, WidgetID widget) const override
634 {
635 switch (widget) {
636 case WID_NCL_DETAILS:
637 this->DrawDetails(r);
638 break;
639
640 case WID_NCL_MATRIX:
641 this->DrawMatrix(r);
642 break;
643 }
644 }
645
646 void OnPaint() override
647 {
648 if (this->content.NeedRebuild()) {
649 this->BuildContentList();
650 }
651
652 this->DrawWidgets();
653 this->DrawSortButton(this->content.SortType() + WID_NCL_CHECKBOX, this->content.IsDescSortOrder());
654 }
655
660 void DrawMatrix(const Rect &r) const
661 {
662 bool rtl = _current_text_dir == TD_RTL;
663 const Rect checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX)->GetCurrentRect();
664 const Rect name = this->GetWidget<NWidgetBase>(WID_NCL_NAME)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
665 const Rect type = this->GetWidget<NWidgetBase>(WID_NCL_TYPE)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
666
667 /* Fill the matrix with the information */
668 const uint step_height = this->GetWidget<NWidgetBase>(WID_NCL_MATRIX)->resize_y;
669 const int text_y_offset = WidgetDimensions::scaled.matrix.top + (step_height - WidgetDimensions::scaled.matrix.Vertical() - GetCharacterHeight(FontSize::Normal)) / 2;
670 const int version_y_offset = WidgetDimensions::scaled.matrix.top + (step_height - WidgetDimensions::scaled.matrix.Vertical() - GetCharacterHeight(FontSize::Small)) / 2;
671
672 Rect mr = r.WithHeight(step_height);
673 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->content);
674 for (auto iter = first; iter != last; iter++) {
675 const ContentInfo *ci = *iter;
676
677 if (ci == this->selected) GfxFillRect(mr.Shrink(WidgetDimensions::scaled.bevel), PC_GREY);
678
679 SpriteID sprite;
680 SpriteID pal = PAL_NONE;
681 switch (ci->state) {
682 case ContentInfo::State::Unselected: sprite = SPR_BOX_EMPTY; break;
683 case ContentInfo::State::Selected: sprite = SPR_BOX_CHECKED; break;
684 case ContentInfo::State::Autoselected: sprite = SPR_BOX_CHECKED; break;
685 case ContentInfo::State::AlreadyHere: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
686 case ContentInfo::State::DoesNotExist: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break;
687 default: NOT_REACHED();
688 }
689 DrawSpriteIgnorePadding(sprite, pal, checkbox.WithY(mr), {AlignmentH::Centre, AlignmentV::Middle});
690
692 DrawString(type.left, type.right, mr.top + text_y_offset, str, TextColour::Black, AlignmentH::Centre);
693
694 int x = DrawString(name.left, name.right, mr.top + version_y_offset, ci->version, TextColour::Black, AlignmentH::End, false, FontSize::Small);
695 x += rtl ? WidgetDimensions::scaled.hsep_wide : -WidgetDimensions::scaled.hsep_wide;
696
697 DrawString(rtl ? x : name.left, rtl ? name.right : x, mr.top + text_y_offset, ci->name, TextColour::Black);
698 mr = mr.Translate(0, step_height);
699 }
700 }
701
706 void DrawDetails(const Rect &r) const
707 {
708 /* Height for the title banner */
709 int HEADER_HEIGHT = 3 * GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.frametext.Vertical();
710
711 Rect hr = r.WithHeight(HEADER_HEIGHT).Shrink(WidgetDimensions::scaled.frametext);
712 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
713 tr.top += HEADER_HEIGHT;
714
715 /* Create the nice darker rectangle at the details top */
717 DrawString(hr.left, hr.right, hr.top, STR_CONTENT_DETAIL_TITLE, TextColour::FromString, AlignmentH::Centre);
718
719 /* Draw the total download size */
720 DrawString(tr.left, tr.right, tr.bottom - GetCharacterHeight(FontSize::Normal) + 1, GetString(STR_CONTENT_TOTAL_DOWNLOAD_SIZE, this->filesize_sum));
721
722 if (this->selected == nullptr) return;
723
724 /* And fill the rest of the details when there's information to place there */
725 DrawStringMultiLine(hr.left, hr.right, hr.top + GetCharacterHeight(FontSize::Normal), hr.bottom, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + to_underlying(this->selected->state), TextColour::FromString, {AlignmentH::Centre, AlignmentV::Middle});
726
727 /* Also show the total download size, so keep some space from the bottom */
729
730 if (this->selected->upgrade) {
731 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_UPDATE, GetContentTypeString(this->selected->type)));
732 tr.top += WidgetDimensions::scaled.vsep_wide;
733 }
734
735 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_NAME, this->selected->name));
736
737 if (!this->selected->version.empty()) {
738 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_VERSION, this->selected->version));
739 }
740
741 if (!this->selected->description.empty()) {
742 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_DESCRIPTION, this->selected->description));
743 }
744
745 if (!this->selected->url.empty()) {
746 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_URL, this->selected->url));
747 }
748
749 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_TYPE, GetContentTypeString(this->selected->type)));
750
751 tr.top += WidgetDimensions::scaled.vsep_wide;
752 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_FILESIZE, this->selected->filesize));
753
754 std::string_view list_separator = GetListSeparator();
755 if (!this->selected->dependencies.empty()) {
756 /* List dependencies */
757 std::string buf;
758 for (auto &cid : this->selected->dependencies) {
759 /* Try to find the dependency */
760 for (const ContentInfo &ci : _network_content_client.Info()) {
761 if (ci.id != cid) continue;
762
763 if (!buf.empty()) buf += list_separator;
764 buf += ci.name;
765 break;
766 }
767 }
768 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_DEPENDENCIES, std::move(buf)));
769 }
770
771 if (!this->selected->tags.empty()) {
772 /* List all tags */
773 std::string buf;
774 for (auto &tag : this->selected->tags) {
775 if (!buf.empty()) buf += list_separator;
776 buf += tag;
777 }
778 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_TAGS, std::move(buf)));
779 }
780
781 if (this->selected->IsSelected()) {
782 /* When selected show all manually selected content that depends on this */
784 _network_content_client.ReverseLookupTreeDependency(tree, this->selected);
785
786 std::string buf;
787 for (const ContentInfo *ci : tree) {
788 if (ci == this->selected || ci->state != ContentInfo::State::Selected) continue;
789
790 if (!buf.empty()) buf += list_separator;
791 buf += ci->name;
792 }
793 if (!buf.empty()) {
794 tr.top = DrawStringMultiLine(tr, GetString(STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF, std::move(buf)));
795 }
796 }
797 }
798
799 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
800 {
801 if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TextfileType::ContentEnd) {
802 if (this->selected == nullptr || this->selected->state != ContentInfo::State::AlreadyHere) return;
803
804 ShowContentTextfileWindow(this, (TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
805 return;
806 }
807
808 switch (widget) {
809 case WID_NCL_MATRIX: {
810 auto it = this->vscroll->GetScrolledItemFromWidget(this->content, pt.y, this, WID_NCL_MATRIX);
811 if (it == this->content.end()) return; // click out of bounds
812
813 const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
814 if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
815 _network_content_client.ToggleSelectedState(**it);
816 this->content.ForceResort();
817 this->content.ForceRebuild();
818 } else {
819 this->selected = *it;
820 this->list_pos = it - this->content.begin();
821 }
822
823 if (this->filter_data.types.Any()) {
824 this->content.ForceRebuild();
825 }
826
827 this->InvalidateData();
828 break;
829 }
830
831 case WID_NCL_CHECKBOX:
832 case WID_NCL_TYPE:
833 case WID_NCL_NAME:
834 if (this->content.SortType() == widget - WID_NCL_CHECKBOX) {
835 this->content.ToggleSortOrder();
836 if (!this->content.empty()) this->list_pos = (int)this->content.size() - this->list_pos - 1;
837 } else {
838 this->content.SetSortType(widget - WID_NCL_CHECKBOX);
839 this->content.ForceResort();
840 this->SortContentList();
841 }
842 this->ScrollToSelected();
843 this->InvalidateData();
844 break;
845
847 _network_content_client.SelectAll();
848 this->InvalidateData();
849 break;
850
852 _network_content_client.SelectUpgrade();
853 this->InvalidateData();
854 break;
855
856 case WID_NCL_UNSELECT:
857 _network_content_client.UnselectAll();
858 this->InvalidateData();
859 break;
860
861 case WID_NCL_OPEN_URL:
862 if (this->selected != nullptr) {
863 OpenBrowser(this->selected->url);
864 }
865 break;
866
867 case WID_NCL_DOWNLOAD:
869 break;
870
873 this->OpenExternalSearch();
874 } else {
875 ShowQuery(
876 GetEncodedString(STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION),
877 GetEncodedString(STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER),
879 }
880 break;
881 }
882 }
883
884 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
885 {
886 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == EventState::NotHandled) {
887 switch (keycode) {
888 case WKC_SPACE:
889 case WKC_RETURN:
890 if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) {
891 if (this->selected != nullptr) {
892 _network_content_client.ToggleSelectedState(*this->selected);
893 this->content.ForceResort();
894 this->InvalidateData();
895 }
896 if (this->filter_data.types.Any()) {
897 this->content.ForceRebuild();
898 this->InvalidateData();
899 }
900 return EventState::Handled;
901 }
902 /* space is pressed and filter is focused. */
903 [[fallthrough]];
904
905 default:
907 }
908 }
909
910 if (this->content.empty()) {
911 if (this->UpdateFilterState()) {
912 this->content.ForceRebuild();
913 this->InvalidateData();
914 }
915 return EventState::Handled;
916 }
917
918 this->selected = this->content[this->list_pos];
919
920 if (this->UpdateFilterState()) {
921 this->content.ForceRebuild();
922 } else {
923 /* Scroll to the new content if it is outside the current range. */
924 this->ScrollToSelected();
925 }
926
927 /* redraw window */
928 this->InvalidateData();
929 return EventState::Handled;
930 }
931
932 void OnEditboxChanged(WidgetID wid) override
933 {
934 if (wid == WID_NCL_FILTER) {
935 this->filter_data.string_filter.SetFilterTerm(this->filter_editbox.text.GetText());
936 this->UpdateFilterState();
937 this->content.ForceRebuild();
938 this->InvalidateData();
939 }
940 }
941
942 void OnResize() override
943 {
944 this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX);
945 }
946
947 void OnReceiveContentInfo(const ContentInfo &rci) override
948 {
949 if (this->auto_select && !rci.IsSelected()) _network_content_client.ToggleSelectedState(rci);
950 this->content.ForceRebuild();
951 this->InvalidateData(0, false);
952 }
953
955 {
956 this->content.ForceResort();
957 this->InvalidateData();
958 }
959
960 void OnConnect(bool success) override
961 {
962 if (!success) {
963 ShowErrorMessage(GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_CONNECT), {}, WarningLevel::Error);
964 this->Close();
965 return;
966 }
967
968 this->InvalidateData();
969 }
970
976 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
977 {
978 if (!gui_scope) return;
979 if (this->content.NeedRebuild()) this->BuildContentList();
980
981 /* To sum all the bytes we intend to download */
982 this->filesize_sum = 0;
983 bool show_select_all = false;
984 bool show_select_upgrade = false;
985 for (const ContentInfo *ci : this->content) {
986 switch (ci->state) {
989 this->filesize_sum += ci->filesize;
990 break;
991
993 show_select_all = true;
994 show_select_upgrade |= ci->upgrade;
995 break;
996
997 default:
998 break;
999 }
1000 }
1001
1002 /* If data == 2 then the status window caused this OnInvalidate */
1003 this->SetWidgetDisabledState(WID_NCL_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WindowClass::NetworkStatus, NetworkStatusWindowNumber::ContentDownload) != nullptr && data != 2));
1004 this->SetWidgetDisabledState(WID_NCL_UNSELECT, this->filesize_sum == 0);
1005 this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all);
1006 this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade || !this->filter_data.string_filter.IsEmpty());
1007 this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == nullptr || this->selected->url.empty());
1009 this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::State::AlreadyHere || !this->selected->GetTextfile(tft).has_value());
1010 }
1011 }
1012};
1013
1016
1017const std::initializer_list<NetworkContentListWindow::GUIContentList::SortFunction * const> NetworkContentListWindow::sorter_funcs = {
1018 &StateSorter,
1019 &TypeSorter,
1020 &NameSorter,
1021};
1022
1023const std::initializer_list<NetworkContentListWindow::GUIContentList::FilterFunction * const> NetworkContentListWindow::filter_funcs = {
1026};
1027
1029
1039
1041static constexpr std::initializer_list<NWidgetPart> _nested_network_content_list_widgets = {
1044 NWidget(WWT_CAPTION, Colours::LightBlue), SetStringTip(STR_CONTENT_TITLE),
1046 EndContainer(),
1049 /* Top */
1053 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
1054 EndContainer(),
1055 /* Lists and info. */
1057 /* Left side. */
1064 SetStringTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
1066 SetStringTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
1067 EndContainer(),
1069 EndContainer(),
1071 EndContainer(),
1075 SetStringTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
1077 SetStringTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
1078 EndContainer(),
1080 SetStringTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
1081 EndContainer(),
1082 EndContainer(),
1083 /* Right side. */
1086 EndContainer(),
1089 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
1090 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NCL_TEXTFILE + TextfileType::Readme), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
1091 EndContainer(),
1093 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NCL_TEXTFILE + TextfileType::Changelog), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
1094 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NCL_TEXTFILE + TextfileType::License), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
1095 EndContainer(),
1096 EndContainer(),
1097 EndContainer(),
1098 EndContainer(),
1099 /* Bottom. */
1102 SetStringTip(STR_CONTENT_SEARCH_EXTERNAL, STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP),
1104 SetStringTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
1105 EndContainer(),
1106 EndContainer(),
1107 /* Resize button. */
1109 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1111 EndContainer(),
1112 EndContainer(),
1113};
1114
1117 WindowPosition::Center, "list_content", 630, 460,
1118 WindowClass::Network, WindowClass::None,
1119 {},
1121);
1122
1131{
1132#if defined(WITH_ZLIB)
1133 ContentTypes types{};
1135 if (cv == nullptr) {
1136 assert(type1 != ContentType::End || type2 == ContentType::End);
1137 assert(type1 == ContentType::End || type1 != type2);
1138 _network_content_client.RequestContentList(type1);
1139 if (type2 != ContentType::End) _network_content_client.RequestContentList(type2);
1140
1141 if (type1 != ContentType::End) types.Set(type1);
1142 if (type2 != ContentType::End) types.Set(type2);
1143 } else {
1144 _network_content_client.RequestContentList(cv, true);
1145 }
1146
1148 new NetworkContentListWindow(_network_content_list_desc, cv != nullptr, types);
1149#else
1151 GetEncodedString(STR_CONTENT_NO_ZLIB),
1152 GetEncodedString(STR_CONTENT_NO_ZLIB_SUB),
1154#endif /* WITH_ZLIB */
1155}
Base functions for all AIs.
Generic functions for replacing base data (graphics, sounds).
Generic functions for replacing base graphics data.
Generic functions for replacing base music data.
Generic functions for replacing base sounds data.
static void Rescan()
Rescans all searchpaths for available AIs.
Definition ai_core.cpp:312
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool None() const
Test if none of the values are set.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
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.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnDownloadProgress(const ContentInfo &ci, int bytes) override
We have progress in the download of a file.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
std::string name
The current name of the downloaded file.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
uint downloaded_files
Number of files downloaded.
uint total_bytes
Number of bytes to download.
Iterate a range of enum values.
List template of 'things' T to sort in a GUI.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetFiltering(Filtering f)
Import filter conditions.
void SetListing(Listing l)
Import sort conditions.
void SetFilterState(bool state)
Enable or disable the filter.
void 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.
static void Rescan()
Rescans all searchpaths for available Game scripts.
Baseclass for nested widgets.
uint current_x
Current horizontal size (after resizing).
int pos_x
Horizontal position of top-left corner of the widget in the window.
Window that lists the content that's at the content server.
EventState OnKeyPress(char32_t key, uint16_t keycode) override
A key has been pressed.
static bool NameSorter(const ContentInfo *const &a, const ContentInfo *const &b)
Sort content by name.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
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.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
void OnReceiveContentInfo(const ContentInfo &rci) override
We received a content info.
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.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
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.
int list_pos
Our position in the list.
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.
static bool TypeOrSelectedFilter(const ContentInfo *const *item, ContentListFilterData &filter)
Filter content by type, but still show content selected for download.
bool UpdateFilterState()
Update filter state based on current window state.
void OnPaint() override
The window must be repainted.
NetworkContentListWindow(WindowDesc &desc, bool select_all, ContentTypes types)
Create the content list window.
static EnumIndexArray< std::string, ContentType, ContentType::End > content_type_strs
Cached strings for all content types.
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 OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
static bool TagNameFilter(const ContentInfo *const *item, ContentListFilterData &filter)
Filter content by tags/name.
void OnDownloadComplete(ContentID) override
We have finished downloading a file.
void BuildContentList()
(Re)build the network game list as its amount has changed because an item has been added or deleted f...
void OnConnect(bool success) override
Callback for when the connection has finished.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Scrollbar * vscroll
Cache of the vertical scrollbar.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
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.
void SetCount(size_t num)
Sets the number of elements in the list.
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
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:2548
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:2495
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
@ Scenario
Scan for scenarios and heightmaps.
Definition fileio_func.h:67
@ Baseset
Scan for base sets.
Definition fileio_func.h:64
uint DoScan(Subdirectory sd)
Perform the scanning of a particular subdirectory.
Definition fileio.cpp:383
EnumBitSet< Mode, uint8_t > Modes
Bitset of Mode elements.
Definition fileio_func.h:72
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:95
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_...
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Functions related to errors.
@ Error
Errors (eg. saving/loading failed).
Definition error.h:26
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
void ScanScenarios()
Force a (re)scan of the scenarios.
Definition fios.cpp:681
Declarations for savegames operations.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:88
Base functions for all Games.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
@ Centre
Align to the centre.
@ End
Align to the end, LTR/RTL aware.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
@ Middle
Align to the middle.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:899
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:116
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, ExtendedTextColour colour, Alignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:787
int DrawString(int left, int right, int top, std::string_view str, ExtendedTextColour colour, Alignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:668
Functions related to the gfx engine.
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:70
void DrawSpriteIgnorePadding(SpriteID img, PaletteID pal, const Rect &r, Alignment align)
Draw a sprite within a Rect, ignoring the sprite's padding.
Definition widget.cpp:350
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ Small
Index of the small font in the font tables.
Definition gfx_type.h:250
@ Normal
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ White
White.
Definition gfx_type.h:300
@ Mauve
Mauve.
Definition gfx_type.h:295
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ LightBlue
Light blue.
Definition gfx_type.h:290
@ Grey
Grey.
Definition gfx_type.h:299
@ FromString
Marker for telling to use the colour from the string.
Definition gfx_type.h:317
@ Black
Black colour.
Definition gfx_type.h:334
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetResizeWidgetTypeTip(ResizeWidgetType widget_type, StringID tip)
Widget part function for setting the resize widget type and tooltip.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetAlignment(Alignment align)
Widget part function for setting the alignment of text/images.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
Definition window.cpp:975
#define Point
Macro that prevents name conflicts between included headers.
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.
void ShowQuery(EncodedString &&caption, EncodedString &&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...
Types related to the misc widgets.
@ WID_TF_CAPTION
The caption of the window.
Definition misc_widget.h:53
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
std::vector< std::unique_ptr< ContentInfo > > ContentVector
Vector with content info.
std::vector< const ContentInfo * > ConstContentVector
Vector with constant content info.
static bool _accepted_external_search
Whether the user accepted to enter external websites during this session.
static void ShowContentTextfileWindow(Window *parent, TextfileType file_type, const ContentInfo *ci)
Open the window with one of the text files associated with content.
static constexpr std::initializer_list< NWidgetPart > _nested_network_content_list_widgets
The widgets for the content list.
static StringID GetContentTypeString(ContentType type)
Get the string associated with a ContentType.
static WindowDesc _network_content_list_desc(WindowPosition::Center, "list_content", 630, 460, WindowClass::Network, WindowClass::None, {}, _nested_network_content_list_widgets)
Window description of the content list.
void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentType type2)
Show the content list window with a given set of content.
static constexpr std::initializer_list< NWidgetPart > _nested_network_content_download_status_window_widgets
Nested widgets for the download window.
static WindowDesc _network_content_download_status_window_desc(WindowPosition::Center, {}, 0, 0, WindowClass::NetworkStatus, WindowClass::None, WindowDefaultFlag::Modal, _nested_network_content_download_status_window_widgets)
Window description for the download window.
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 string.
void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
User interface for downloading files.
Types related to the network content widgets.
@ 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_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:1323
Some generic types.
PixelColour GetColourGradient(Colours colour, Shade shade)
Get colour gradient palette index.
Definition palette.cpp:393
@ Normal
Normal colour shade.
static constexpr PixelColour PC_GREY
Grey palette colour.
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
Base types for having sorted lists in GUIs.
This file contains all sprite-related enums and defines.
static const PaletteID PALETTE_TO_GREEN
Definition sprites.h:1768
static const PaletteID PALETTE_TO_RED
Definition sprites.h:1766
static const SpriteID SPR_BLOT
Coloured circle (used for server compatibility and installed content).
Definition sprites.h:72
Definition of base types and functions in a cross-platform compatible way.
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:77
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:429
Searching and filtering using a stringterm.
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:299
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:218
Functions related to OTTD's strings.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Callbacks for notifying others about incoming data.
Container for all important information about a piece of content.
uint32_t filesize
Size of the file.
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.
std::string version
Version of the content.
ContentID id
Unique (server side) ID for the content.
std::string filename
Filename (for the .tar.gz; only valid on download).
bool IsSelected() const
Is the state either selected or autoselected?
ContentType type
Type of content.
std::vector< ContentID > dependencies
The dependencies (unique server side ids).
@ Unselected
The content has not been selected.
@ AlreadyHere
The content is already at the client side.
@ Selected
The content has been manually selected.
@ Autoselected
The content has been selected as dependency.
@ DoesNotExist
The content does not exist in the content system.
StringList tags
Tags associated with the content.
bool upgrade
This item is an upgrade.
Filter data for NetworkContentListWindow.
StringFilter string_filter
Text filter of content list.
ContentTypes types
Content types displayed.
Window for displaying the textfile of an item in the content list.
ContentTextfileWindow(Window *parent, TextfileType file_type, const ContentInfo *ci)
Create the window with one of the text files associated with content.
const ContentInfo * ci
View the textfile of this ContentInfo.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Dimensions (a width and height) of a rectangle in 2D.
Data structure describing what to show in the list (filter criteria).
bool state
Filter on/off.
Data structure describing how to show the list (what sort direction and criteria).
Window for showing the download status of content.
void OnDownloadProgress(const ContentInfo &ci, int bytes) override
We have progress in the download of a file.
ContentTypes received_types
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...
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
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.
Specification of a rectangle with absolute coordinates of all edges.
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 WithY(int new_top, int new_bottom) const
Create a new Rect, replacing the top and bottom coordinates.
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(std::string_view str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
bool GetState() const
Get the matching state of the current item.
std::string_view GetText() const
Get the current text.
Definition textbuf.cpp:284
TextfileType file_type
Type of textfile to view.
virtual void LoadTextfile(const std::string &textfile, Subdirectory dir)
Loads the textfile text from file and setup lines.
High level window description.
Definition window_gui.h:172
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:1112
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:839
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1817
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:792
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3258
Window * parent
Parent window.
Definition window_gui.h:328
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:513
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:420
void DrawSortButton(WidgetID widget, bool descending) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:824
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1807
void CloseChildWindowById(WindowClass wc, WindowNumber number) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1099
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:494
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1841
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:989
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1831
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:322
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:381
Subdirectory GetContentInfoSubDir(ContentType type)
Helper to get the subdirectory a ContentInfo is located in.
uint32_t ContentID
Unique identifier for the content.
ContentType
The values in the enum are important; they are received over the network from the content servers.
@ BaseSounds
The content consists of base sounds.
@ Begin
Helper to mark the begin of the types.
@ GsLibrary
The content consists of a GS library.
@ Scenario
The content consists of a scenario.
@ Heightmap
The content consists of a heightmap.
@ BaseGraphics
The content consists of base graphics.
@ Ai
The content consists of an AI.
@ End
Helper to mark the end of the types.
@ BaseMusic
The content consists of base music.
@ Gs
The content consists of a game script.
@ NewGRF
The content consists of a NewGRF.
@ AiLibrary
The content consists of an AI library.
EnumBitSet< ContentType, uint16_t, ContentType::End > ContentTypes
Bitset of chosen content types.
GUI functions related to textfiles.
TextfileType
Additional text files accompanying Tar archives.
@ Readme
Content readme.
@ ContentBegin
This marker is used to generate the below three buttons in sequence by various of places in the code.
@ ContentEnd
This marker is used to generate the above three buttons in sequence by various of places in the code.
@ License
Content license.
@ Changelog
Content changelog.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:308
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:62
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:49
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ EqualSize
Containers should keep all their (resizing) children equally large.
@ HideBevel
Bevel of resize box is hidden.
Definition widget_type.h:29
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:1204
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:3318
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1288
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1161
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3196
Window functions not directly related to making/drawing windows.
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition window_gui.h:156
@ BorderOnly
Draw border only, no background.
Definition window_gui.h:26
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed).
Definition window_gui.h:27
@ Center
Center the window.
Definition window_gui.h:147
int WidgetID
Widget ID.
Definition window_type.h:21
EventState
State of handling an event.
@ Handled
The passed event is handled.
@ NotHandled
The passed event is not handled.
@ GameOptions
Game options.
Definition window_type.h:32
@ ContentDownload
Network content download status.
Definition window_type.h:57
@ ContentList
Network content list.
Definition window_type.h:50