OpenTTD Source 20260531-master-g0e951f3528
news_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 "gui.h"
12#include "viewport_func.h"
13#include "strings_func.h"
14#include "window_func.h"
15#include "vehicle_base.h"
16#include "vehicle_func.h"
17#include "vehicle_gui.h"
18#include "roadveh.h"
19#include "station_base.h"
20#include "industry.h"
21#include "town.h"
22#include "sound_func.h"
23#include "string_func.h"
24#include "statusbar_gui.h"
26#include "company_func.h"
27#include "engine_base.h"
28#include "engine_gui.h"
30#include "command_func.h"
31#include "company_base.h"
32#include "settings_internal.h"
33#include "group_gui.h"
34#include "zoom_func.h"
35#include "news_cmd.h"
36#include "news_func.h"
37#include "timer/timer.h"
38#include "timer/timer_window.h"
40
41#include "widgets/news_widget.h"
42
43#include "table/strings.h"
44
45#include "safeguards.h"
46
47static const uint MIN_NEWS_AMOUNT = 30;
48static const uint MAX_NEWS_AMOUNT = 1U << 10;
49
51
58static NewsIterator _forced_news = std::end(_news);
59
61static NewsIterator _current_news = std::end(_news);
62
65
71{
72 return (_statusbar_news == std::end(_news)) ? nullptr : &*_statusbar_news;
73}
74
80{
81 return _news;
82}
83
90{
91 struct visitor {
92 TileIndex operator()(const std::monostate &) { return INVALID_TILE; }
93 TileIndex operator()(const TileIndex &t) { return t; }
94 TileIndex operator()(const VehicleID) { return INVALID_TILE; }
95 TileIndex operator()(const StationID s) { return Station::Get(s)->xy; }
96 TileIndex operator()(const IndustryID i) { return Industry::Get(i)->location.tile + TileDiffXY(1, 1); }
97 TileIndex operator()(const TownID t) { return Town::Get(t)->xy; }
98 TileIndex operator()(const EngineID) { return INVALID_TILE; }
99 };
100
101 return std::visit(visitor{}, reference);
102}
103
128
131 WindowPosition::Manual, {}, 0, 0,
132 WindowClass::News, WindowClass::None,
133 {},
135);
136
138static constexpr std::initializer_list<NWidgetPart> _nested_vehicle_news_widgets = {
142 /* Layer 1 */
146 EndContainer(),
147 EndContainer(),
148 /* Layer 2 */
150 SetFill(1, 1),
152 SetMinimalSize(400, 0),
154 SetStringTip(STR_EMPTY),
156 EndContainer(),
161 SetMinimalSize(350, 0),
163 SetFill(1, 0),
165 SetMinimalSize(350, 32),
166 SetFill(1, 0),
169 SetMinimalSize(350, 0),
171 SetFill(1, 0),
172 EndContainer(),
173 EndContainer(),
174 EndContainer(),
175 EndContainer(),
176};
177
180 WindowPosition::Manual, {}, 0, 0,
181 WindowClass::News, WindowClass::None,
182 {},
184);
185
187static constexpr std::initializer_list<NWidgetPart> _nested_company_news_widgets = {
191 /* Layer 1 */
195 EndContainer(),
196 EndContainer(),
197 /* Layer 2 */
199 SetFill(1, 1),
201 SetMinimalSize(400, 0),
204 EndContainer(),
208 SetFill(0, 0),
209 SetMinimalSize(93, 119),
211 SetFill(0, 1),
213 EndContainer(),
215 SetFill(1, 1),
217 SetMinimalSize(300, 0),
219 EndContainer(),
220 EndContainer(),
221 EndContainer(),
222};
223
226 WindowPosition::Manual, {}, 0, 0,
227 WindowClass::News, WindowClass::None,
228 {},
230);
231
258
261 WindowPosition::Manual, {}, 0, 0,
262 WindowClass::News, WindowClass::None,
263 {},
265);
266
268static constexpr std::initializer_list<NWidgetPart> _nested_small_news_widgets = {
269 /* Caption + close box. The caption is not WWT_CAPTION as the window shall not be moveable and so on. */
275 SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON),
276 SetResize(1, 0),
277 SetToolTip(STR_NEWS_SHOW_VEHICLE_GROUP_TOOLTIP),
278 EndContainer(),
279 EndContainer(),
280
281 /* Main part */
284 SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
285 SetPadding(2),
288 SetMinimalSize(274, 47),
289 EndContainer(),
292 SetMinimalSize(275, 0),
294 EndContainer(),
295 EndContainer(),
296};
297
300 WindowPosition::Manual, {}, 0, 0,
301 WindowClass::News, WindowClass::None,
302 {},
304);
305
310 &_thin_news_desc, // NewsStyle::Thin
311 &_small_news_desc, // NewsStyle::Small
312 &_normal_news_desc, // NewsStyle::Normal
313 &_vehicle_news_desc, // NewsStyle::Vehicle
314 &_company_news_desc, // NewsStyle::Company
315};
316
317static WindowDesc &GetNewsWindowLayout(NewsStyle style)
318{
319 uint layout = to_underlying(style);
320 assert(layout < lengthof(_news_window_layout));
321 return *_news_window_layout[layout];
322}
323
328 /* name, age, sound, */
329 NewsTypeData("news_display.arrival_player", 60, SND_1D_APPLAUSE ),
330 NewsTypeData("news_display.arrival_other", 60, SND_1D_APPLAUSE ),
331 NewsTypeData("news_display.accident", 90, SND_BEGIN ),
332 NewsTypeData("news_display.accident_other", 90, SND_BEGIN ),
333 NewsTypeData("news_display.company_info", 60, SND_BEGIN ),
334 NewsTypeData("news_display.open", 90, SND_BEGIN ),
335 NewsTypeData("news_display.close", 90, SND_BEGIN ),
336 NewsTypeData("news_display.economy", 30, SND_BEGIN ),
337 NewsTypeData("news_display.production_player", 30, SND_BEGIN ),
338 NewsTypeData("news_display.production_other", 30, SND_BEGIN ),
339 NewsTypeData("news_display.production_nobody", 30, SND_BEGIN ),
340 NewsTypeData("news_display.advice", 150, SND_BEGIN ),
341 NewsTypeData("news_display.new_vehicles", 30, SND_1E_NEW_ENGINE),
342 NewsTypeData("news_display.acceptance", 90, SND_BEGIN ),
343 NewsTypeData("news_display.subsidies", 180, SND_BEGIN ),
344 NewsTypeData("news_display.general", 60, SND_BEGIN ),
345};
346
352{
353 const SettingDesc *sd = GetSettingFromName(this->name);
354 assert(sd != nullptr && sd->IsIntSetting());
355 return static_cast<NewsDisplay>(sd->AsIntSetting()->Read(nullptr));
356}
357
359struct NewsWindow : Window {
360 uint16_t chat_height = 0;
361 uint16_t status_height = 0;
362 const NewsItem *ni = nullptr;
363 static int duration;
364
365 NewsWindow(WindowDesc &desc, const NewsItem *ni) : Window(desc), ni(ni)
366 {
367 NewsWindow::duration = 16650;
368 const Window *w = FindWindowByClass(WindowClass::NetworkChat);
369 this->chat_height = (w != nullptr) ? w->height : 0;
370 this->status_height = FindWindowById(WindowClass::Statusbar, 0)->height;
371
373
374 this->CreateNestedTree();
375
376 bool has_vehicle_id = std::holds_alternative<VehicleID>(ni->ref1);
378 if (nwid_sel != nullptr) nwid_sel->SetDisplayedPlane(has_vehicle_id ? 0 : SZSP_NONE);
379
381 if (has_vehicle_id && nwid != nullptr) {
382 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(ni->ref1));
383 switch (v->type) {
385 nwid->SetString(STR_TRAIN);
386 break;
388 nwid->SetString(RoadVehicle::From(v)->IsBus() ? STR_BUS : STR_LORRY);
389 break;
391 nwid->SetString(STR_SHIP);
392 break;
394 nwid->SetString(STR_PLANE);
395 break;
396 default:
397 break; // Do nothing
398 }
399 }
400
401 this->FinishInitNested(0);
402
403 /* Initialize viewport if it exists. */
405 if (nvp != nullptr) {
406 if (std::holds_alternative<VehicleID>(ni->ref1)) {
407 nvp->InitializeViewport(this, std::get<VehicleID>(ni->ref1), ScaleZoomGUI(ZoomLevel::News));
408 } else {
410 }
412 if (!this->ni->flags.Test(NewsFlag::InColour)) {
414 } else if (this->ni->flags.Test(NewsFlag::Shaded)) {
416 }
417 }
418
420 }
421
422 void DrawNewsBorder(const Rect &r) const
423 {
426
427 ir = ir.Expand(1);
428 GfxFillRect( r.left, r.top, ir.left, r.bottom, PC_BLACK);
429 GfxFillRect(ir.right, r.top, r.right, r.bottom, PC_BLACK);
430 GfxFillRect( r.left, r.top, r.right, ir.top, PC_BLACK);
431 GfxFillRect( r.left, ir.bottom, r.right, r.bottom, PC_BLACK);
432 }
433
434 Point OnInitialPosition([[maybe_unused]] int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
435 {
436 Point pt = { 0, _screen.height };
437 return pt;
438 }
439
440 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
441 {
442 FontSize fontsize = FontSize::Normal;
443 std::string str;
444 switch (widget) {
445 case WID_N_CAPTION: {
446 /* Caption is not a real caption (so that the window cannot be moved)
447 * thus it doesn't get the default sizing of a caption. */
448 Dimension d2 = GetStringBoundingBox(STR_NEWS_MESSAGE_CAPTION);
449 d2.height += WidgetDimensions::scaled.captiontext.Vertical();
450 size = maxdim(size, d2);
451 return;
452 }
453
454 case WID_N_MGR_FACE:
455 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
456 break;
457
458 case WID_N_MESSAGE:
460 fontsize = this->GetWidget<NWidgetLeaf>(widget)->GetFontSize();
461 str = this->ni->headline.GetDecodedString();
462 break;
463
464 case WID_N_VEH_NAME:
465 case WID_N_VEH_TITLE:
466 str = this->GetNewVehicleMessageString(widget);
467 break;
468
469 case WID_N_VEH_INFO: {
470 assert(std::holds_alternative<EngineID>(ni->ref1));
471 EngineID engine = std::get<EngineID>(this->ni->ref1);
472 str = GetEngineInfoString(engine);
473 break;
474 }
475
476 case WID_N_SHOW_GROUP:
477 if (std::holds_alternative<VehicleID>(ni->ref1)) {
479 d2.height += WidgetDimensions::scaled.captiontext.Vertical();
480 d2.width += WidgetDimensions::scaled.captiontext.Horizontal();
481 size = d2;
482 }
483 return;
484
485 default:
486 return; // Do nothing
487 }
488
489 /* Update minimal size with length of the multi-line string. */
490 Dimension d = size;
491 d.width = (d.width >= padding.width) ? d.width - padding.width : 0;
492 d.height = (d.height >= padding.height) ? d.height - padding.height : 0;
493 d = GetStringMultiLineBoundingBox(str, d, fontsize);
494 d.width += padding.width;
495 d.height += padding.height;
496 size = maxdim(size, d);
497 }
498
499 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
500 {
501 if (widget == WID_N_DATE) {
502 return GetString(STR_JUST_DATE_LONG, this->ni->date);
503 } else if (widget == WID_N_TITLE) {
504 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
505 return GetString(cni->title);
506 }
507
508 return this->Window::GetWidgetString(widget, stringid);
509
510 }
511
512 void DrawWidget(const Rect &r, WidgetID widget) const override
513 {
514 switch (widget) {
515 case WID_N_CAPTION:
517 break;
518
519 case WID_N_PANEL:
520 this->DrawNewsBorder(r);
521 break;
522
523 case WID_N_MESSAGE:
524 case WID_N_COMPANY_MSG: {
525 const NWidgetLeaf &nwid = *this->GetWidget<NWidgetLeaf>(widget);
526 DrawStringMultiLine(r, this->ni->headline.GetDecodedString(), nwid.GetTextColour(), SA_CENTER, false, nwid.GetFontSize());
527 break;
528 }
529
530 case WID_N_MGR_FACE: {
531 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
532 DrawCompanyManagerFace(cni->face, cni->colour, r);
534 break;
535 }
536 case WID_N_MGR_NAME: {
537 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
539 break;
540 }
541
542 case WID_N_VEH_BKGND:
544 break;
545
546 case WID_N_VEH_NAME:
547 case WID_N_VEH_TITLE:
548 DrawStringMultiLine(r, this->GetNewVehicleMessageString(widget), TextColour::FromString, SA_CENTER);
549 break;
550
551 case WID_N_VEH_SPR: {
552 assert(std::holds_alternative<EngineID>(ni->ref1));
553 EngineID engine = std::get<EngineID>(this->ni->ref1);
554 DrawVehicleEngine(r.left, r.right, CentreBounds(r.left, r.right, 0), CentreBounds(r.top, r.bottom, 0), engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW);
556 break;
557 }
558 case WID_N_VEH_INFO: {
559 assert(std::holds_alternative<EngineID>(ni->ref1));
560 EngineID engine = std::get<EngineID>(this->ni->ref1);
562 break;
563 }
564 }
565 }
566
567 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
568 {
569 switch (widget) {
570 case WID_N_CLOSEBOX:
572 this->Close();
573 _forced_news = std::end(_news);
574 break;
575
576 case WID_N_CAPTION:
577 if (std::holds_alternative<VehicleID>(ni->ref1)) {
578 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(this->ni->ref1));
580 }
581 break;
582
583 case WID_N_VIEWPORT:
584 break; // Ignore clicks
585
586 case WID_N_SHOW_GROUP:
587 if (std::holds_alternative<VehicleID>(ni->ref1)) {
588 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(this->ni->ref1));
590 }
591 break;
592 default:
593 if (std::holds_alternative<VehicleID>(ni->ref1)) {
594 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(this->ni->ref1))->GetMovingFront();
596 } else {
597 TileIndex tile1 = GetReferenceTile(this->ni->ref1);
598 TileIndex tile2 = GetReferenceTile(this->ni->ref2);
599 if (_ctrl_pressed) {
600 if (tile1 != INVALID_TILE) ShowExtraViewportWindow(tile1);
601 if (tile2 != INVALID_TILE) ShowExtraViewportWindow(tile2);
602 } else {
603 if ((tile1 == INVALID_TILE || !ScrollMainWindowToTile(tile1)) && tile2 != INVALID_TILE) {
605 }
606 }
607 }
608 break;
609 }
610 }
611
612 void OnResize() override
613 {
614 if (this->viewport != nullptr) {
616 nvp->UpdateViewportCoordinates(this);
617
618 if (!std::holds_alternative<VehicleID>(ni->ref1)) {
619 ScrollWindowToTile(GetReferenceTile(ni->ref1), this, true); // Re-center viewport.
620 }
621 }
622
624 if (wid != nullptr) {
625 int y = GetStringHeight(GetString(STR_JUST_RAW_STRING, static_cast<const CompanyNewsInformation *>(this->ni->data.get())->president_name), wid->current_x);
626 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
627 }
628 }
629
635 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
636 {
637 if (!gui_scope) return;
638 /* The chatbar has notified us that is was either created or closed */
639 int newtop = this->top + this->chat_height - data;
640 this->chat_height = data;
641 this->SetWindowTop(newtop);
642 }
643
644 void OnRealtimeTick([[maybe_unused]] uint delta_ms) override
645 {
646 /* Decrement the news timer. We don't need to action an elapsed event here,
647 * so no need to use TimerElapsed(). */
648 if (NewsWindow::duration > 0) NewsWindow::duration -= delta_ms;
649 }
650
656 const IntervalTimer<TimerWindow> scroll_interval = {std::chrono::milliseconds(210) / GetCharacterHeight(FontSize::Normal), [this](uint count) {
657 int newtop = std::max(this->top - 2 * static_cast<int>(count), _screen.height - this->height - this->status_height - this->chat_height);
658 this->SetWindowTop(newtop);
659 }};
660
661private:
666 void SetWindowTop(int newtop)
667 {
668 if (this->top == newtop) return;
669
670 int mintop = std::min(newtop, this->top);
671 int maxtop = std::max(newtop, this->top);
672 if (this->viewport != nullptr) this->viewport->top += newtop - this->top;
673 this->top = newtop;
674
675 AddDirtyBlock(this->left, mintop, this->left + this->width, maxtop + this->height);
676 }
677
678 std::string GetNewVehicleMessageString(WidgetID widget) const
679 {
680 assert(std::holds_alternative<EngineID>(ni->ref1));
681 EngineID engine = std::get<EngineID>(this->ni->ref1);
682
683 switch (widget) {
684 case WID_N_VEH_TITLE:
685 return GetString(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE, GetEngineCategoryName(engine));
686
687 case WID_N_VEH_NAME:
688 return GetString(STR_NEWS_NEW_VEHICLE_TYPE, PackEngineNameDParam(engine, EngineNameContext::PreviewNews));
689
690 default:
691 NOT_REACHED();
692 }
693 }
694};
695
696/* static */ int NewsWindow::duration = 0; // Instance creation.
697
702static void ShowNewspaper(const NewsItem *ni)
703{
704 SoundFx sound = _news_type_data[ni->type].sound;
705 if (sound != 0 && _settings_client.sound.news_full) SndPlayFx(sound);
706
707 new NewsWindow(GetNewsWindowLayout(ni->style), ni);
708}
709
715{
716 if (_settings_client.sound.news_ticker) SndPlayFx(SND_16_NEWS_TICKER);
717
718 _statusbar_news = ni;
719 InvalidateWindowData(WindowClass::Statusbar, 0, SBI_SHOW_TICKER);
720}
721
724{
725 _news.clear();
726 _forced_news = std::end(_news);
727 _current_news = std::end(_news);
728 _statusbar_news = std::end(_news);
730}
731
738{
739 const NewsItem *ni = GetStatusbarNews();
740 if (ni == nullptr) return true;
741
742 /* Ticker message
743 * Check if the status bar message is still being displayed? */
744 return !IsNewsTickerShown();
745}
746
753{
754 if (_forced_news == std::end(_news) && _current_news == std::end(_news)) return true;
755
756 /* neither newsticker nor newspaper are running */
757 return (NewsWindow::duration <= 0 || FindWindowById(WindowClass::News, 0) == nullptr);
758}
759
762{
763 /* There is no status bar, so no reason to show news;
764 * especially important with the end game screen when
765 * there is no status bar but possible news. */
766 if (FindWindowById(WindowClass::Statusbar, 0) == nullptr) return;
767
768 /* No news to move to. */
769 if (std::empty(_news)) return;
770
771 /* if we're not at the latest item, then move on */
772 while (_statusbar_news != std::begin(_news)) {
774 const NewsType type = _statusbar_news->type;
775
776 /* check the date, don't show too old items */
777 if (TimerGameEconomy::date - _news_type_data[type].age > _statusbar_news->economy_date) continue;
778
779 switch (_news_type_data[type].GetDisplay()) {
780 default: NOT_REACHED();
781 case NewsDisplay::Off: // Show nothing only a small reminder in the status bar.
782 InvalidateWindowData(WindowClass::Statusbar, 0, SBI_SHOW_REMINDER);
783 return;
784
785 case NewsDisplay::Summary: // Show ticker.
787 return;
788
789 case NewsDisplay::Full: // Show newspaper, skipped here.
790 break;;
791 }
792 }
793}
794
797{
798 /* There is no status bar, so no reason to show news;
799 * especially important with the end game screen when
800 * there is no status bar but possible news. */
801 if (FindWindowById(WindowClass::Statusbar, 0) == nullptr) return;
802
803 CloseWindowById(WindowClass::News, 0); // close the newspapers window if shown
804 _forced_news = std::end(_news);
805
806 /* No news to move to. */
807 if (std::empty(_news)) return;
808
809 /* if we're not at the latest item, then move on */
810 while (_current_news != std::begin(_news)) {
812 const NewsType type = _current_news->type;
813
814 /* check the date, don't show too old items */
815 if (TimerGameEconomy::date - _news_type_data[type].age > _current_news->economy_date) continue;
816
817 switch (_news_type_data[type].GetDisplay()) {
818 default: NOT_REACHED();
819 case NewsDisplay::Off: // Show nothing only a small reminder in the status bar, skipped here.
820 break;
821
822 case NewsDisplay::Summary: // Show ticker, skipped here.
823 break;
824
825 case NewsDisplay::Full: // Sshow newspaper.
827 return;
828 }
829 }
830}
831
837static std::list<NewsItem>::iterator DeleteNewsItem(std::list<NewsItem>::iterator ni)
838{
839 bool update_current_news = (_forced_news == ni || _current_news == ni);
840 bool update_statusbar_news = (_statusbar_news == ni);
841
842 if (update_current_news) {
843 /* When we're the current news, go to the next older item first;
844 * we just possibly made that the last news item. */
845 if (_current_news == ni) ++_current_news;
846 if (_forced_news == ni) _forced_news = std::end(_news);
847 }
848
849 if (update_statusbar_news) {
850 /* When we're the current news, go to the next older item first;
851 * we just possibly made that the last news item. */
853 }
854
855 /* Delete the news from the news queue. */
856 ni = _news.erase(ni);
857
858 if (update_current_news) {
859 /* About to remove the currently forced item (shown as newspapers) ||
860 * about to remove the currently displayed item (newspapers) */
862 }
863
864 if (update_statusbar_news) {
865 /* About to remove the currently displayed item (ticker, or just a reminder) */
866 InvalidateWindowData(WindowClass::Statusbar, 0, SBI_NEWS_DELETED); // invalidate the statusbar
868 }
869
870 return ni;
871}
872
888{
889 /* show this news message in colour? */
890 if (TimerGameCalendar::year >= _settings_client.gui.coloured_news_year) this->flags.Set(NewsFlag::InColour);
891}
892
893std::string NewsItem::GetStatusText() const
894{
895 if (this->data != nullptr) {
896 /* CompanyNewsInformation is the only type of additional data used. */
897 const CompanyNewsInformation &cni = *static_cast<const CompanyNewsInformation*>(this->data.get());
898 return GetString(STR_MESSAGE_NEWS_FORMAT, cni.title, this->headline.GetDecodedString());
899 }
900
901 return this->headline.GetDecodedString();
902}
903
917void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type)
918{
919 if (_game_mode == GameMode::Menu) return;
920
921 /* Create new news item node */
922 _news.emplace_front(std::move(headline), type, style, flags, ref1, ref2, std::move(data), advice_type);
923
924 /* Keep the number of stored news items to a manageable number */
925 if (std::size(_news) > MAX_NEWS_AMOUNT) {
926 DeleteNewsItem(std::prev(std::end(_news)));
927 }
928
929 InvalidateWindowData(WindowClass::MessageHistory, 0);
930}
931
937uint32_t SerialiseNewsReference(const NewsReference &reference)
938{
939 struct visitor {
940 uint32_t operator()(const std::monostate &) { return 0; }
941 uint32_t operator()(const TileIndex &t) { return t.base(); }
942 uint32_t operator()(const VehicleID v) { return v.base(); }
943 uint32_t operator()(const StationID s) { return s.base(); }
944 uint32_t operator()(const IndustryID i) { return i.base(); }
945 uint32_t operator()(const TownID t) { return t.base(); }
946 uint32_t operator()(const EngineID e) { return e.base(); }
947 };
948
949 return std::visit(visitor{}, reference);
950}
951
961CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const EncodedString &text)
962{
964
965 if (company != INVALID_OWNER && !Company::IsValidID(company)) return CMD_ERROR;
966 if (type >= NewsType::End) return CMD_ERROR;
967 if (text.empty()) return CMD_ERROR;
968
969 struct visitor {
970 bool operator()(const std::monostate &) { return true; }
971 bool operator()(const TileIndex t) { return IsValidTile(t); }
972 bool operator()(const VehicleID v) { return Vehicle::IsValidID(v); }
973 bool operator()(const StationID s) { return Station::IsValidID(s); }
974 bool operator()(const IndustryID i) { return Industry::IsValidID(i); }
975 bool operator()(const TownID t) { return Town::IsValidID(t); }
976 bool operator()(const EngineID e) { return Engine::IsValidID(e); }
977 };
978
979 if (!std::visit(visitor{}, reference)) return CMD_ERROR;
980
981 if (company != INVALID_OWNER && company != _local_company) return CommandCost();
982
983 if (flags.Test(DoCommandFlag::Execute)) {
984 AddNewsItem(EncodedString{text}, type, NewsStyle::Normal, {}, reference, {});
985 }
986
987 return CommandCost();
988}
989
996template <size_t Tmin = 0, class Tpredicate>
997void DeleteNews(Tpredicate predicate)
998{
999 bool dirty = false;
1000 for (auto it = std::rbegin(_news); it != std::rend(_news); /* nothing */) {
1001 if constexpr (Tmin > 0) {
1002 if (std::size(_news) <= Tmin) break;
1003 }
1004 if (predicate(*it)) {
1005 it = std::make_reverse_iterator(DeleteNewsItem(std::prev(it.base())));
1006 dirty = true;
1007 } else {
1008 ++it;
1009 }
1010 }
1011 if (dirty) InvalidateWindowData(WindowClass::MessageHistory, 0);
1012}
1013
1014template <typename T>
1015static bool IsReferenceObject(const NewsReference &reference, T id)
1016{
1017 return std::holds_alternative<T>(reference) && std::get<T>(reference) == id;
1018}
1019
1020template <typename T>
1021static bool HasReferenceObject(const NewsItem &ni, T id)
1022{
1023 return IsReferenceObject(ni.ref1, id) || IsReferenceObject(ni.ref2, id);
1024}
1025
1033{
1034 DeleteNews([&](const auto &ni) {
1035 return HasReferenceObject(ni, vid) && (advice_type == AdviceType::Invalid || ni.advice_type == advice_type);
1036 });
1037}
1038
1044void DeleteStationNews(StationID sid)
1045{
1046 DeleteNews([&](const auto &ni) {
1047 return HasReferenceObject(ni, sid);
1048 });
1049}
1050
1055void DeleteIndustryNews(IndustryID iid)
1056{
1057 DeleteNews([&](const auto &ni) {
1058 return HasReferenceObject(ni, iid);
1059 });
1060}
1061
1062bool IsInvalidEngineNews(const NewsReference &reference)
1063{
1064 if (!std::holds_alternative<EngineID>(reference)) return false;
1065
1066 EngineID eid = std::get<EngineID>(reference);
1067 return !Engine::IsValidID(eid) || !Engine::Get(eid)->IsEnabled();
1068}
1069
1074{
1075 DeleteNews([](const auto &ni) {
1076 return IsInvalidEngineNews(ni.ref1) || IsInvalidEngineNews(ni.ref2);
1077 });
1078}
1079
1080static void RemoveOldNewsItems()
1081{
1082 DeleteNews<MIN_NEWS_AMOUNT>([](const auto &ni) {
1083 return TimerGameEconomy::date - _news_type_data[ni.type].age * _settings_client.gui.news_message_timeout > ni.economy_date;
1084 });
1085}
1086
1087template <typename T>
1088static void ChangeObject(NewsReference reference, T from, T to)
1089{
1090 if (!std::holds_alternative<T>(reference)) return;
1091 if (std::get<T>(reference) == from) reference = to;
1092}
1093
1100void ChangeVehicleNews(VehicleID from_index, VehicleID to_index)
1101{
1102 for (auto &ni : _news) {
1103 ChangeObject(ni.ref1, from_index, to_index);
1104 ChangeObject(ni.ref2, from_index, to_index);
1105 if (ni.flags.Test(NewsFlag::VehicleParam0) && IsReferenceObject(ni.ref1, to_index)) ni.headline = ni.headline.ReplaceParam(0, to_index.base());
1106 }
1107}
1108
1109void NewsLoop()
1110{
1111 /* no news item yet */
1112 if (std::empty(_news)) return;
1113
1114 static TimerGameEconomy::Month _last_clean_month = 0;
1115
1116 if (_last_clean_month != TimerGameEconomy::month) {
1117 RemoveOldNewsItems();
1118 _last_clean_month = TimerGameEconomy::month;
1119 }
1120
1123}
1124
1130{
1131 assert(!std::empty(_news));
1132
1133 /* Delete the news window */
1134 CloseWindowById(WindowClass::News, 0);
1135
1136 /* setup forced news item */
1137 _forced_news = ni;
1138
1139 if (_forced_news != std::end(_news)) {
1140 CloseWindowById(WindowClass::News, 0);
1141 ShowNewspaper(&*ni);
1142 }
1143}
1144
1150{
1151 NewsWindow *w = dynamic_cast<NewsWindow *>(FindWindowById(WindowClass::News, 0));
1152 if (w == nullptr) return false;
1153 w->Close();
1154 return true;
1155}
1156
1159{
1160 if (std::empty(_news)) return;
1161
1162 NewsIterator ni;
1163 if (_forced_news == std::end(_news)) {
1164 /* Not forced any news yet, show the current one, unless a news window is
1165 * open (which can only be the current one), then show the previous item */
1166 if (_current_news == std::end(_news)) {
1167 /* No news were shown yet resp. the last shown one was already deleted.
1168 * Treat this as if _forced_news reached the oldest news; so, wrap around and start anew with the latest. */
1169 ni = std::begin(_news);
1170 } else {
1171 const Window *w = FindWindowById(WindowClass::News, 0);
1172 ni = (w == nullptr || (std::next(_current_news) == std::end(_news))) ? _current_news : std::next(_current_news);
1173 }
1174 } else if (std::next(_forced_news) == std::end(_news)) {
1175 /* We have reached the oldest news, start anew with the latest */
1176 ni = std::begin(_news);
1177 } else {
1178 /* 'Scrolling' through news history show each one in turn */
1179 ni = std::next(_forced_news);
1180 }
1181 bool wrap = false;
1182 for (;;) {
1183 if (_news_type_data[ni->type].GetDisplay() != NewsDisplay::Off) {
1184 ShowNewsMessage(ni);
1185 break;
1186 }
1187
1188 ++ni;
1189 if (ni == std::end(_news)) {
1190 if (wrap) break;
1191 /* We have reached the oldest news, start anew with the latest */
1192 ni = std::begin(_news);
1193 wrap = true;
1194 }
1195 }
1196}
1197
1198
1208static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem &ni)
1209{
1210 /* Get the string, replaces newlines with spaces and remove control codes from the string. */
1211 std::string message = StrMakeValid(ni.GetStatusText(), StringValidationSetting::ReplaceTabCrNlWithSpace);
1212
1213 /* Truncate and show string; postfixed by '...' if necessary */
1214 DrawString(left, right, y, message, colour);
1215}
1216
1217struct MessageHistoryWindow : Window {
1218 int line_height = 0;
1219 int date_width = 0;
1220
1221 Scrollbar *vscroll = nullptr;
1222
1223 MessageHistoryWindow(WindowDesc &desc) : Window(desc)
1224 {
1225 this->CreateNestedTree();
1226 this->vscroll = this->GetScrollbar(WID_MH_SCROLLBAR);
1227 this->FinishInitNested(); // Initializes 'this->line_height' and 'this->date_width'.
1228 this->OnInvalidateData(0);
1229 }
1230
1231 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1232 {
1233 if (widget == WID_MH_BACKGROUND) {
1234 this->line_height = GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_normal;
1235 fill.height = resize.height = this->line_height;
1236
1237 /* Months are off-by-one, so it's actually 8. Not using
1238 * month 12 because the 1 is usually less wide. */
1240
1241 size.height = 4 * resize.height + WidgetDimensions::scaled.framerect.Vertical(); // At least 4 lines are visible.
1242 size.width = std::max(200u, size.width); // At least 200 pixels wide.
1243 }
1244 }
1245
1246 void DrawWidget(const Rect &r, WidgetID widget) const override
1247 {
1248 if (widget != WID_MH_BACKGROUND || std::empty(_news)) return;
1249
1250 /* Fill the widget with news items. */
1251 bool rtl = _current_text_dir == TD_RTL;
1252 Rect news = r.Shrink(WidgetDimensions::scaled.framerect).Indent(this->date_width + WidgetDimensions::scaled.hsep_wide, rtl);
1253 Rect date = r.Shrink(WidgetDimensions::scaled.framerect).WithWidth(this->date_width, rtl);
1254 int y = news.top;
1255
1256 auto [first, last] = this->vscroll->GetVisibleRangeIterators(_news);
1257 for (auto ni = first; ni != last; ++ni) {
1258 DrawString(date.left, date.right, y, GetString(STR_JUST_DATE_TINY, ni->date), TextColour::White);
1259
1260 DrawNewsString(news.left, news.right, y, TextColour::White, *ni);
1261 y += this->line_height;
1262 }
1263 }
1264
1270 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1271 {
1272 if (!gui_scope) return;
1273 this->vscroll->SetCount(std::size(_news));
1274 }
1275
1276 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1277 {
1278 if (widget == WID_MH_BACKGROUND) {
1279 /* Scheduled window invalidations currently occur after the input loop, which means the scrollbar count
1280 * could be invalid, so ensure it's correct now. Potentially this means that item clicked on might be
1281 * different as well. */
1282 this->vscroll->SetCount(std::size(_news));
1283 auto ni = this->vscroll->GetScrolledItemFromWidget(_news, pt.y, this, widget, WidgetDimensions::scaled.framerect.top);
1284 if (ni == std::end(_news)) return;
1285
1286 ShowNewsMessage(ni);
1287 }
1288 }
1289
1290 void OnResize() override
1291 {
1292 this->vscroll->SetCapacityFromWidget(this, WID_MH_BACKGROUND, WidgetDimensions::scaled.framerect.Vertical());
1293 }
1294};
1295
1296static constexpr std::initializer_list<NWidgetPart> _nested_message_history = {
1299 NWidget(WWT_CAPTION, Colours::Brown), SetStringTip(STR_MESSAGE_HISTORY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1303 EndContainer(),
1304
1307 EndContainer(),
1311 EndContainer(),
1312 EndContainer(),
1313};
1314
1317 WindowPosition::Automatic, "list_news", 400, 140,
1318 WindowClass::MessageHistory, WindowClass::None,
1319 {},
1320 _nested_message_history
1321);
1322
1325{
1326 CloseWindowById(WindowClass::MessageHistory, 0);
1328}
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
Common return value for all commands.
Container for an encoded string, created by GetEncodedString.
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:207
EncodedString ReplaceParam(size_t param, StringParameter &&value) const
Replace a parameter of this EncodedString.
Definition strings.cpp:150
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
uint current_x
Current horizontal size (after resizing).
Base class for a 'real' widget.
NWidgetDisplayFlags disp_flags
Flags that affect display and interaction with the widget.
void SetString(StringID string)
Set string of the nested widget.
Definition widget.cpp:1185
Leaf widget.
Base class for a resizable nested widget.
bool UpdateVerticalSize(uint min_y)
Set absolute (post-scaling) minimal size of the widget.
Definition widget.cpp:1151
Stacked widgets, widgets all occupying the same space in the window.
bool SetDisplayedPlane(int plane)
Select which plane to show (for NWID_SELECTION only).
Definition widget.cpp:1453
Nested widget to display a viewport in a window.
void UpdateViewportCoordinates(Window *w)
Update the position and size of the viewport (after eg a resize).
Definition widget.cpp:2434
void InitializeViewport(Window *w, std::variant< TileIndex, VehicleID > focus, ZoomLevel zoom)
Initialize the viewport of the window.
Definition widget.cpp:2425
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:2531
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Timer that is increased every 27ms, and counts towards ticks / days / months / years.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static Year year
Current year, starting at 0.
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_MAX_YEAR
Timer that is increased every 27ms, and counts towards economy time units, expressed in days / months...
static Date date
Current date in days (day counter).
static Month month
Current month (0..11).
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:93
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
Draws the face of a company manager's face.
Functionality related to the company manager's face.
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
static constexpr Owner INVALID_OWNER
An invalid owner.
Base class for engines.
std::string GetEngineInfoString(EngineID engine)
Get a multi-line string with some technical data, describing the engine.
StringID GetEngineCategoryName(EngineID engine)
Return the category of an engine.
void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
Draw an engine.
Engine GUI functions, used by build_vehicle_gui and autoreplace_gui.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
uint64_t PackEngineNameDParam(EngineID engine_id, EngineNameContext context, uint32_t extra_data=0)
Combine an engine ID and a name context to an engine name StringParameter.
@ PreviewNews
Name is shown in exclusive preview or newspaper.
#define T
Climate temperate.
Definition engines.h:91
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.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:88
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:716
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:899
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, ExtendedTextColour colour, StringAlignment 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, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:668
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition gfx.cpp:752
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
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:70
FontSize
Available font sizes.
Definition gfx_type.h:248
@ Small
Index of the small font in the font tables.
Definition gfx_type.h:250
@ Large
Index of the large font in the font tables.
Definition gfx_type.h:251
@ Normal
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ SA_TOP
Top align the text.
Definition gfx_type.h:439
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:436
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:444
@ White
White.
Definition gfx_type.h:300
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ LightBlue
Light blue.
Definition gfx_type.h:290
@ Brown
Brown.
Definition gfx_type.h:298
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:315
@ White
White colour.
Definition gfx_type.h:330
@ FromString
Marker for telling to use the colour from the string.
Definition gfx_type.h:317
@ Black
Black colour.
Definition gfx_type.h:334
@ Recolour
Apply a recolour sprite to the screen content.
Definition gfx_type.h:393
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FontSize::Normal)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetTextStyle(TextColour colour, FontSize size=FontSize::Normal)
Widget part function for setting the text style.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetAlignment(StringAlignment 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.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
void AddDirtyBlock(int left, int top, int right, int bottom)
Extend the internal _invalid_rect rectangle to contain the rectangle defined by the given parameters.
Definition gfx.cpp:1520
void ShowCompanyGroupForVehicle(const Vehicle *v)
Show the group window for the given vehicle.
Functions/definitions that have something to do with groups.
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Base of all industries.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:392
Command definitions related to news messages.
Functions related to news.
static NewsContainer _news
List of news, with newest items at the start.
Definition news_gui.cpp:50
void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr< NewsAllocatedData > &&data, AdviceType advice_type)
Add a new newsitem to be shown.
Definition news_gui.cpp:917
static void MoveToNextNewsItem()
Move to the next news item.
Definition news_gui.cpp:796
static void ShowTicker(NewsIterator ni)
Show news item in the ticker.
Definition news_gui.cpp:714
static constexpr std::initializer_list< NWidgetPart > _nested_normal_news_widgets
Normal news items.
Definition news_gui.cpp:105
void DeleteNews(Tpredicate predicate)
Delete news items by predicate, and invalidate the message history if necessary.
Definition news_gui.cpp:997
static void ShowNewspaper(const NewsItem *ni)
Open up an own newspaper window for the news item.
Definition news_gui.cpp:702
static const uint MIN_NEWS_AMOUNT
preferred minimum amount of news messages.
Definition news_gui.cpp:47
CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const EncodedString &text)
Create a new custom news item.
Definition news_gui.cpp:961
static constexpr std::initializer_list< NWidgetPart > _nested_vehicle_news_widgets
New vehicles news items.
Definition news_gui.cpp:138
static WindowDesc _normal_news_desc(WindowPosition::Manual, {}, 0, 0, WindowClass::News, WindowClass::None, {}, _nested_normal_news_widgets)
Window definition for the normal news window.
static NewsIterator _forced_news
Forced news item.
Definition news_gui.cpp:58
void DeleteIndustryNews(IndustryID iid)
Remove news regarding given industry.
static WindowDesc _vehicle_news_desc(WindowPosition::Manual, {}, 0, 0, WindowClass::News, WindowClass::None, {}, _nested_vehicle_news_widgets)
Window definition for the vehicle news window.
void DeleteStationNews(StationID sid)
Remove news regarding given station so there are no 'unknown station now accepts Mail' or 'First trai...
static TileIndex GetReferenceTile(const NewsReference &reference)
Get the position a news-reference is referencing.
Definition news_gui.cpp:89
static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem &ni)
Draw an unformatted news message truncated to a maximum length.
void ShowLastNewsMessage()
Show previous news item.
static const uint MAX_NEWS_AMOUNT
Do not exceed this number of news messages.
Definition news_gui.cpp:48
static WindowDesc _message_history_desc(WindowPosition::Automatic, "list_news", 400, 140, WindowClass::MessageHistory, WindowClass::None, {}, _nested_message_history)
Window definition for the news message history window.
uint32_t SerialiseNewsReference(const NewsReference &reference)
Encode a NewsReference for serialisation, e.g.
Definition news_gui.cpp:937
void DeleteInvalidEngineNews()
Remove engine announcements for invalid engines.
static WindowDesc _thin_news_desc(WindowPosition::Manual, {}, 0, 0, WindowClass::News, WindowClass::None, {}, _nested_thin_news_widgets)
Window definition for the thin news window.
static bool ReadyForNextNewsItem()
Are we ready to show another news item?
Definition news_gui.cpp:752
static std::list< NewsItem >::iterator DeleteNewsItem(std::list< NewsItem >::iterator ni)
Delete a news item from the queue.
Definition news_gui.cpp:837
bool HideActiveNewsMessage()
Close active news message window.
void ShowMessageHistory()
Display window with news messages history.
void ChangeVehicleNews(VehicleID from_index, VehicleID to_index)
Report a change in vehicle IDs (due to autoreplace) to affected vehicle news.
static constexpr EnumIndexArray< NewsTypeData, NewsType, NewsType::End > _news_type_data
Per-NewsType data.
Definition news_gui.cpp:327
void InitNewsItemStructs()
Initialize the news-items data structures.
Definition news_gui.cpp:723
static void MoveToNextTickerItem()
Move to the next ticker item.
Definition news_gui.cpp:761
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type)
Delete news with a given advice type about a vehicle.
const NewsContainer & GetNews()
Get read-only reference to all news items.
Definition news_gui.cpp:79
static void ShowNewsMessage(NewsIterator ni)
Do a forced show of a specific message.
static WindowDesc _company_news_desc(WindowPosition::Manual, {}, 0, 0, WindowClass::News, WindowClass::None, {}, _nested_company_news_widgets)
Window definition for the company news window.
static constexpr std::initializer_list< NWidgetPart > _nested_thin_news_widgets
Thin news items.
Definition news_gui.cpp:233
static NewsIterator _current_news
Current news item (last item shown regularly).
Definition news_gui.cpp:61
const NewsItem * GetStatusbarNews()
Get pointer to the current status bar news item.
Definition news_gui.cpp:70
static WindowDesc _small_news_desc(WindowPosition::Manual, {}, 0, 0, WindowClass::News, WindowClass::None, {}, _nested_small_news_widgets)
Window definition for the small news window.
static constexpr std::initializer_list< NWidgetPart > _nested_company_news_widgets
Company news items.
Definition news_gui.cpp:187
static constexpr std::initializer_list< NWidgetPart > _nested_small_news_widgets
Small news items.
Definition news_gui.cpp:268
static bool ReadyForNextTickerItem()
Are we ready to show another ticker item?
Definition news_gui.cpp:737
static WindowDesc * _news_window_layout[]
Window layouts for news items.
Definition news_gui.cpp:309
static NewsIterator _statusbar_news
Current status bar news item.
Definition news_gui.cpp:64
NewsType
Type of news.
Definition news_type.h:29
@ End
end-of-array marker
Definition news_type.h:47
NewsContainer::const_iterator NewsIterator
Iterator type for news items.
Definition news_type.h:176
std::list< NewsItem > NewsContainer
Container type for storing news items.
Definition news_type.h:175
NewsStyle
News Window Styles.
Definition news_type.h:77
@ Normal
Normal news item. (Newspaper with text only).
Definition news_type.h:80
AdviceType
Sub type of the NewsType::Advice to be able to remove specific news items.
Definition news_type.h:51
@ Invalid
Invalid marker.
Definition news_type.h:62
std::variant< std::monostate, TileIndex, VehicleID, StationID, IndustryID, TownID, EngineID > NewsReference
References to objects in news.
Definition news_type.h:74
@ NoTransparency
News item disables transparency in the viewport.
Definition news_type.h:91
@ VehicleParam0
String param 0 contains a vehicle ID. (special autoreplace behaviour).
Definition news_type.h:93
@ Shaded
News item uses shaded colours.
Definition news_type.h:92
@ InColour
News item is shown in colour (otherwise it is shown in black & white).
Definition news_type.h:90
NewsDisplay
News display options.
Definition news_type.h:100
@ Summary
Show ticker.
Definition news_type.h:102
@ Full
Show newspaper.
Definition news_type.h:103
@ Off
Only show a reminder in the status bar.
Definition news_type.h:101
Types related to the news widgets.
@ WID_N_DATE
Date of the news item.
Definition news_widget.h:21
@ WID_N_PANEL
Panel of the window.
Definition news_widget.h:17
@ WID_N_CLOSEBOX
Close the window.
Definition news_widget.h:20
@ WID_N_SHOW_GROUP
Show vehicle's group.
Definition news_widget.h:34
@ WID_N_CAPTION
Title bar of the window. Only used in small news items.
Definition news_widget.h:22
@ WID_N_HEADLINE
The news headline.
Definition news_widget.h:19
@ WID_N_INSET
Inset around the viewport in the window. Only used in small news items.
Definition news_widget.h:23
@ WID_N_SHOW_GROUP_SEL
Selector for showing vehicle group, which can be hidden.
Definition news_widget.h:35
@ WID_N_VEH_TITLE
Vehicle new title.
Definition news_widget.h:29
@ WID_N_VEH_INFO
Some technical data of the new vehicle.
Definition news_widget.h:33
@ WID_N_TITLE
Title of the company news.
Definition news_widget.h:18
@ WID_N_VIEWPORT
Viewport in the window.
Definition news_widget.h:24
@ WID_N_MGR_FACE
Face of the manager.
Definition news_widget.h:27
@ WID_N_MESSAGE
Space for displaying the message. Only used in small news items.
Definition news_widget.h:26
@ WID_N_VEH_BKGND
Dark background of new vehicle news.
Definition news_widget.h:30
@ WID_N_VEH_SPR
Graphical display of the new vehicle.
Definition news_widget.h:32
@ WID_N_VEH_NAME
Name of the new vehicle.
Definition news_widget.h:31
@ WID_N_COMPANY_MSG
Message in company news items.
Definition news_widget.h:25
@ WID_N_MGR_NAME
Name of the manager.
Definition news_widget.h:28
@ WID_MH_SCROLLBAR
Scrollbar for the list.
Definition news_widget.h:42
@ WID_MH_BACKGROUND
Background of the window.
Definition news_widget.h:41
@ Menu
In the main menu.
Definition openttd.h:19
static constexpr PixelColour PC_GREY
Grey palette colour.
static constexpr PixelColour PC_BLACK
Black palette colour.
static constexpr PixelColour PC_WHITE
White palette colour.
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
static const SettingDesc * GetSettingFromName(std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Functions and types used internally for the settings configurations.
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:46
@ SND_1D_APPLAUSE
27 == 0x1B News: first vehicle at station
Definition sound_type.h:75
@ SND_16_NEWS_TICKER
20 == 0x14 News ticker
Definition sound_type.h:68
@ SND_1E_NEW_ENGINE
28 == 0x1C News: new engine available
Definition sound_type.h:76
static const PaletteID PALETTE_NEWSPAPER
Recolour sprite for newspaper-greying.
Definition sprites.h:1618
Base classes/functions for stations.
bool IsNewsTickerShown()
Checks whether the news ticker is currently being used.
Functions, definitions and such used only by the GUI.
@ SBI_SHOW_REMINDER
show a reminder (dot on the right side of the statusbar)
@ SBI_SHOW_TICKER
start scrolling news
@ SBI_NEWS_DELETED
abort current news display (active news were deleted)
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:119
Functions related to low-level strings.
@ ReplaceTabCrNlWithSpace
Replace tabs ('\t'), carriage returns ('\r') and newlines (' ') with spaces.
Definition string_type.h:53
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
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
TileIndex xy
Base tile of the station.
VehicleType type
Type of vehicle.
Data that needs to be stored for company news messages.
Definition news_type.h:163
CompanyManagerFace face
The face of the president.
Definition news_type.h:169
Colours colour
The colour related to the company.
Definition news_type.h:170
std::string president_name
The name of the president.
Definition news_type.h:165
Dimensions (a width and height) of a rectangle in 2D.
int date_width
Width needed for the date part.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
int line_height
Height of a single line in the news history window including spacing.
void OnResize() override
Called after the window got resized.
Scrollbar * vscroll
Cache of the vertical scrollbar.
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.
Information about a single item of news.
Definition news_type.h:138
TimerGameCalendar::Date date
Calendar date to show for the news.
Definition news_type.h:140
std::unique_ptr< NewsAllocatedData > data
Custom data for the news item that will be deallocated (deleted) when the news item has reached its e...
Definition news_type.h:150
NewsType type
Type of the news.
Definition news_type.h:142
EncodedString headline
Headline of news.
Definition news_type.h:139
AdviceType advice_type
The type of advice, to be able to remove specific advices later on.
Definition news_type.h:143
TimerGameEconomy::Date economy_date
Economy date of the news item, never shown but used to calculate age.
Definition news_type.h:141
NewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr< NewsAllocatedData > &&data, AdviceType advice_type)
Create a new newsitem to be shown.
Definition news_gui.cpp:886
NewsFlags flags
NewsFlags bits.
Definition news_type.h:145
NewsStyle style
Window style for the news.
Definition news_type.h:144
NewsReference ref2
Reference 2 to some object: Used for scrolling after clicking on the news, and for deleting the news ...
Definition news_type.h:148
NewsReference ref1
Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news,...
Definition news_type.h:147
Per-NewsType data.
Definition news_type.h:109
NewsDisplay GetDisplay() const
Return the news display option.
Definition news_gui.cpp:351
const std::string_view name
Name.
Definition news_type.h:110
Window class displaying a news item.
Definition news_gui.cpp:359
uint16_t chat_height
Height of the chat window.
Definition news_gui.cpp:360
void OnResize() override
Called after the window got resized.
Definition news_gui.cpp:612
static int duration
Remaining time for showing the current news message (may only be access while a news item is displaye...
Definition news_gui.cpp:363
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition news_gui.cpp:512
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.
Definition news_gui.cpp:440
Point OnInitialPosition(int16_t sm_width, int16_t sm_height, int window_number) override
Compute the initial position of the window.
Definition news_gui.cpp:434
void OnRealtimeTick(uint delta_ms) override
Called periodically.
Definition news_gui.cpp:644
uint16_t status_height
Height of the status bar window.
Definition news_gui.cpp:361
const NewsItem * ni
News item to display.
Definition news_gui.cpp:362
void SetWindowTop(int newtop)
Moves the window to a new top coordinate.
Definition news_gui.cpp:666
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition news_gui.cpp:499
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition news_gui.cpp:635
const IntervalTimer< TimerWindow > scroll_interval
Scroll the news message slowly up from the bottom.
Definition news_gui.cpp:656
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition news_gui.cpp:567
static Industry * Get(auto index)
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Expand(int s) const
Copy and expand Rect by s pixels.
Properties of config file settings.
virtual bool IsIntSetting() const
Check whether this setting is an integer type setting.
const struct IntSettingDesc * AsIntSetting() const
Get the setting description of this setting as an integer setting.
Definition settings.cpp:922
static Station * Get(auto index)
static RoadVehicle * From(Vehicle *v)
Vehicle data structure.
int32_t z_pos
z coordinate.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
High level window description.
Definition window_gui.h:168
Data structure for an opened window.
Definition window_gui.h:274
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:992
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1117
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1822
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:518
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1812
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
int left
x position of left edge of the window
Definition window_gui.h:310
int top
y position of top edge of the window
Definition window_gui.h:311
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1846
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
WindowFlags flags
Window flags.
Definition window_gui.h:301
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:327
int height
Height of the window (number of pixels down in y direction).
Definition window_gui.h:313
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the Window system.
Base of the town class.
PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2167
Base class for all vehicles.
Functions related to vehicles.
void ShowVehicleViewWindow(const Vehicle *v)
Shows the vehicle view window of the given vehicle.
Functions related to the vehicle's GUIs.
@ EIT_PREVIEW
Vehicle drawn in preview window, news, ...
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
@ Ship
Ship vehicle type.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Train
Train vehicle type.
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Functions related to (drawing on) viewports.
void DrawCaption(const Rect &r, Colours colour, Owner owner, TextColour text_colour, std::string_view str, StringAlignment align, FontSize fs)
Draw a caption bar.
Definition widget.cpp:738
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:40
@ WWT_LABEL
Centered label.
Definition widget_type.h:48
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX).
Definition widget_type.h:55
@ 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
@ NWID_VIEWPORT
Nested widget containing a viewport.
Definition widget_type.h:73
@ NWID_LAYER
Layered widgets, all visible together.
Definition widget_type.h:72
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ ShadeGrey
Shade viewport to grey-scale.
@ NoTransparency
Viewport is never transparent.
@ ShadeDimmed
Display dimmed colours in the viewport.
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
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:1209
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1181
int PositionNewsMessage(Window *w)
(Re)position news message window at the screen.
Definition window.cpp:3516
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:3322
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1166
Window functions not directly related to making/drawing windows.
@ DisableVpScroll
Window does not do autoscroll,.
Definition window_gui.h:234
@ Automatic
Find a place automatically.
Definition window_gui.h:144
@ Manual
Manually align the window (so no automatic location finding).
Definition window_gui.h:143
int WidgetID
Widget ID.
Definition window_type.h:21
Functions related to zooming.
ZoomLevel ScaleZoomGUI(ZoomLevel value)
Scale zoom level relative to GUI zoom.
Definition zoom_func.h:87
@ News
Default zoom level for the news messages.
Definition zoom_type.h:35