OpenTTD Source 20250312-master-gcdcc6b491d
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 <http://www.gnu.org/licenses/>.
6 */
7
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
104/* Normal news items. */
105static constexpr NWidgetPart _nested_normal_news_widgets[] = {
106 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
108 NWidget(NWID_LAYER, INVALID_COLOUR),
109 /* Layer 1 */
112 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
113 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_DATE),
114 SetTextStyle(TC_BLACK, FS_SMALL),
116 EndContainer(),
117 EndContainer(),
118 /* Layer 2 */
119 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MESSAGE),
121 SetMinimalSize(400, 0),
123 SetTextStyle(TC_BLACK, FS_LARGE),
124 EndContainer(),
125 EndContainer(),
126 EndContainer(),
127};
128
129static WindowDesc _normal_news_desc(
130 WDP_MANUAL, nullptr, 0, 0,
132 {},
133 _nested_normal_news_widgets
134);
135
136/* New vehicles news items. */
137static constexpr NWidgetPart _nested_vehicle_news_widgets[] = {
138 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
140 NWidget(NWID_LAYER, INVALID_COLOUR),
141 /* Layer 1 */
144 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
145 EndContainer(),
146 EndContainer(),
147 /* Layer 2 */
148 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_VEH_TITLE),
149 SetFill(1, 1),
151 SetMinimalSize(400, 0),
153 SetStringTip(STR_EMPTY),
154 SetTextStyle(TC_BLACK, FS_LARGE),
155 EndContainer(),
158 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_NAME),
160 SetMinimalSize(350, 0),
162 SetFill(1, 0),
163 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_SPR),
164 SetMinimalSize(350, 32),
165 SetFill(1, 0),
166 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_INFO),
168 SetMinimalSize(350, 0),
170 SetFill(1, 0),
171 EndContainer(),
172 EndContainer(),
173 EndContainer(),
174 EndContainer(),
175};
176
177static WindowDesc _vehicle_news_desc(
178 WDP_MANUAL, nullptr, 0, 0,
180 {},
181 _nested_vehicle_news_widgets
182);
183
184/* Company news items. */
185static constexpr NWidgetPart _nested_company_news_widgets[] = {
186 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
188 NWidget(NWID_LAYER, INVALID_COLOUR),
189 /* Layer 1 */
192 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
193 EndContainer(),
194 EndContainer(),
195 /* Layer 2 */
196 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_TITLE),
197 SetFill(1, 1),
199 SetMinimalSize(400, 0),
201 SetTextStyle(TC_BLACK, FS_LARGE),
202 EndContainer(),
205 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MGR_FACE),
206 SetFill(0, 0),
207 SetMinimalSize(93, 119),
208 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MGR_NAME),
209 SetFill(0, 1),
211 EndContainer(),
212 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_COMPANY_MSG),
213 SetFill(1, 1),
215 SetMinimalSize(300, 0),
216 SetTextStyle(TC_BLACK, FS_LARGE),
217 EndContainer(),
218 EndContainer(),
219 EndContainer(),
220};
221
222static WindowDesc _company_news_desc(
223 WDP_MANUAL, nullptr, 0, 0,
225 {},
226 _nested_company_news_widgets
227);
228
229/* Thin news items. */
230static constexpr NWidgetPart _nested_thin_news_widgets[] = {
231 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
233 NWidget(NWID_LAYER, INVALID_COLOUR),
234 /* Layer 1 */
237 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
238 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_DATE),
239 SetTextStyle(TC_BLACK, FS_SMALL),
241 EndContainer(),
242 EndContainer(),
243 /* Layer 2 */
244 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MESSAGE),
246 SetMinimalSize(400, 0),
248 SetTextStyle(TC_BLACK, FS_LARGE),
249 EndContainer(),
250 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetMinimalSize(426, 70),
252 EndContainer(),
253 EndContainer(),
254};
255
256static WindowDesc _thin_news_desc(
257 WDP_MANUAL, nullptr, 0, 0,
259 {},
260 _nested_thin_news_widgets
261);
262
263/* Small news items. */
264static constexpr NWidgetPart _nested_small_news_widgets[] = {
265 /* Caption + close box. The caption is not WWT_CAPTION as the window shall not be moveable and so on. */
267 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE, WID_N_CLOSEBOX),
268 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_CAPTION),
269 NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_N_SHOW_GROUP),
270 SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON),
271 SetResize(1, 0),
272 SetToolTip(STR_NEWS_SHOW_VEHICLE_GROUP_TOOLTIP),
273 EndContainer(),
274
275 /* Main part */
276 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_N_HEADLINE),
278 SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
279 SetPadding(2),
280 NWidget(WWT_INSET, COLOUR_LIGHT_BLUE, WID_N_INSET),
281 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT),
282 SetMinimalSize(274, 47),
283 EndContainer(),
284 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MESSAGE),
286 SetMinimalSize(275, 0),
287 SetTextStyle(TC_WHITE, FS_NORMAL),
288 EndContainer(),
289 EndContainer(),
290};
291
292static WindowDesc _small_news_desc(
293 WDP_MANUAL, nullptr, 0, 0,
295 {},
296 _nested_small_news_widgets
297);
298
303 &_thin_news_desc, // NewsStyle::Thin
304 &_small_news_desc, // NewsStyle::Small
305 &_normal_news_desc, // NewsStyle::Normal
306 &_vehicle_news_desc, // NewsStyle::Vehicle
307 &_company_news_desc, // NewsStyle::Company
308};
309
310static WindowDesc &GetNewsWindowLayout(NewsStyle style)
311{
312 uint layout = to_underlying(style);
313 assert(layout < lengthof(_news_window_layout));
314 return *_news_window_layout[layout];
315}
316
321 /* name, age, sound, */
322 NewsTypeData("news_display.arrival_player", 60, SND_1D_APPLAUSE ),
323 NewsTypeData("news_display.arrival_other", 60, SND_1D_APPLAUSE ),
324 NewsTypeData("news_display.accident", 90, SND_BEGIN ),
325 NewsTypeData("news_display.accident_other", 90, SND_BEGIN ),
326 NewsTypeData("news_display.company_info", 60, SND_BEGIN ),
327 NewsTypeData("news_display.open", 90, SND_BEGIN ),
328 NewsTypeData("news_display.close", 90, SND_BEGIN ),
329 NewsTypeData("news_display.economy", 30, SND_BEGIN ),
330 NewsTypeData("news_display.production_player", 30, SND_BEGIN ),
331 NewsTypeData("news_display.production_other", 30, SND_BEGIN ),
332 NewsTypeData("news_display.production_nobody", 30, SND_BEGIN ),
333 NewsTypeData("news_display.advice", 150, SND_BEGIN ),
334 NewsTypeData("news_display.new_vehicles", 30, SND_1E_NEW_ENGINE),
335 NewsTypeData("news_display.acceptance", 90, SND_BEGIN ),
336 NewsTypeData("news_display.subsidies", 180, SND_BEGIN ),
337 NewsTypeData("news_display.general", 60, SND_BEGIN ),
338};
339
340static_assert(std::size(_news_type_data) == to_underlying(NewsType::End));
341
347{
348 const SettingDesc *sd = GetSettingFromName(this->name);
349 assert(sd != nullptr && sd->IsIntSetting());
350 return static_cast<NewsDisplay>(sd->AsIntSetting()->Read(nullptr));
351}
352
357 const NewsItem *ni = nullptr;
358 static int duration;
359
360 NewsWindow(WindowDesc &desc, const NewsItem *ni) : Window(desc), ni(ni)
361 {
362 NewsWindow::duration = 16650;
364 this->chat_height = (w != nullptr) ? w->height : 0;
365 this->status_height = FindWindowById(WC_STATUS_BAR, 0)->height;
366
368
369 this->CreateNestedTree();
370
372 if (std::holds_alternative<VehicleID>(ni->ref1) && nwid != nullptr) {
373 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(ni->ref1));
374 switch (v->type) {
375 case VEH_TRAIN:
376 nwid->SetString(STR_TRAIN);
377 break;
378 case VEH_ROAD:
379 nwid->SetString(RoadVehicle::From(v)->IsBus() ? STR_BUS : STR_LORRY);
380 break;
381 case VEH_SHIP:
382 nwid->SetString(STR_SHIP);
383 break;
384 case VEH_AIRCRAFT:
385 nwid->SetString(STR_PLANE);
386 break;
387 default:
388 break; // Do nothing
389 }
390 }
391
392 this->FinishInitNested(0);
393
394 /* Initialize viewport if it exists. */
396 if (nvp != nullptr) {
397 if (std::holds_alternative<VehicleID>(ni->ref1)) {
398 nvp->InitializeViewport(this, std::get<VehicleID>(ni->ref1), ScaleZoomGUI(ZOOM_LVL_NEWS));
399 } else {
400 nvp->InitializeViewport(this, GetReferenceTile(ni->ref1), ScaleZoomGUI(ZOOM_LVL_NEWS));
401 }
403 if (!this->ni->flags.Test(NewsFlag::InColour)) {
404 nvp->disp_flags.Set(NWidgetDisplayFlag::ShadeGrey);
405 } else if (this->ni->flags.Test(NewsFlag::Shaded)) {
406 nvp->disp_flags.Set(NWidgetDisplayFlag::ShadeDimmed);
407 }
408 }
409
411 }
412
413 void DrawNewsBorder(const Rect &r) const
414 {
417
418 ir = ir.Expand(1);
419 GfxFillRect( r.left, r.top, ir.left, r.bottom, PC_BLACK);
420 GfxFillRect(ir.right, r.top, r.right, r.bottom, PC_BLACK);
421 GfxFillRect( r.left, r.top, r.right, ir.top, PC_BLACK);
422 GfxFillRect( r.left, ir.bottom, r.right, r.bottom, PC_BLACK);
423 }
424
426 {
427 Point pt = { 0, _screen.height };
428 return pt;
429 }
430
432 {
433 FontSize fontsize = FS_NORMAL;
434 std::string str;
435 switch (widget) {
436 case WID_N_CAPTION: {
437 /* Caption is not a real caption (so that the window cannot be moved)
438 * thus it doesn't get the default sizing of a caption. */
441 size = maxdim(size, d2);
442 return;
443 }
444
445 case WID_N_MGR_FACE:
446 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
447 break;
448
449 case WID_N_MESSAGE:
451 fontsize = this->GetWidget<NWidgetLeaf>(widget)->GetFontSize();
452 str = this->ni->headline.GetDecodedString();
453 break;
454
455 case WID_N_VEH_NAME:
456 case WID_N_VEH_TITLE:
457 str = this->GetNewVehicleMessageString(widget);
458 break;
459
460 case WID_N_VEH_INFO: {
461 assert(std::holds_alternative<EngineID>(ni->ref1));
462 EngineID engine = std::get<EngineID>(this->ni->ref1);
463 str = GetEngineInfoString(engine);
464 break;
465 }
466
467 case WID_N_SHOW_GROUP:
468 if (std::holds_alternative<VehicleID>(ni->ref1)) {
472 size = d2;
473 } else {
474 /* Hide 'Show group window' button if this news is not about a vehicle. */
475 size.width = 0;
476 size.height = 0;
477 resize.width = 0;
478 resize.height = 0;
479 fill.width = 0;
480 fill.height = 0;
481 }
482 return;
483
484 default:
485 return; // Do nothing
486 }
487
488 /* Update minimal size with length of the multi-line string. */
489 Dimension d = size;
490 d.width = (d.width >= padding.width) ? d.width - padding.width : 0;
491 d.height = (d.height >= padding.height) ? d.height - padding.height : 0;
492 d = GetStringMultiLineBoundingBox(str, d, fontsize);
493 d.width += padding.width;
494 d.height += padding.height;
495 size = maxdim(size, d);
496 }
497
498 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
499 {
500 if (widget == WID_N_DATE) {
501 return GetString(STR_JUST_DATE_LONG, this->ni->date);
502 } else if (widget == WID_N_TITLE) {
503 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
504 return GetString(cni->title);
505 }
506
507 return this->Window::GetWidgetString(widget, stringid);
508
509 }
510
511 void DrawWidget(const Rect &r, WidgetID widget) const override
512 {
513 switch (widget) {
514 case WID_N_CAPTION:
515 DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, TC_FROMSTRING, GetString(STR_NEWS_MESSAGE_CAPTION), SA_CENTER, FS_NORMAL);
516 break;
517
518 case WID_N_PANEL:
519 this->DrawNewsBorder(r);
520 break;
521
522 case WID_N_MESSAGE:
523 case WID_N_COMPANY_MSG: {
524 const NWidgetLeaf &nwid = *this->GetWidget<NWidgetLeaf>(widget);
525 DrawStringMultiLine(r, this->ni->headline.GetDecodedString(), nwid.GetTextColour(), SA_CENTER, false, nwid.GetFontSize());
526 break;
527 }
528
529 case WID_N_MGR_FACE: {
530 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
531 DrawCompanyManagerFace(cni->face, cni->colour, r);
533 break;
534 }
535 case WID_N_MGR_NAME: {
536 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
537 DrawStringMultiLine(r, GetString(STR_JUST_RAW_STRING, cni->president_name), TC_FROMSTRING, SA_CENTER);
538 break;
539 }
540
541 case WID_N_VEH_BKGND:
543 break;
544
545 case WID_N_VEH_NAME:
546 case WID_N_VEH_TITLE:
547 DrawStringMultiLine(r, this->GetNewVehicleMessageString(widget), TC_FROMSTRING, SA_CENTER);
548 break;
549
550 case WID_N_VEH_SPR: {
551 assert(std::holds_alternative<EngineID>(ni->ref1));
552 EngineID engine = std::get<EngineID>(this->ni->ref1);
553 DrawVehicleEngine(r.left, r.right, CenterBounds(r.left, r.right, 0), CenterBounds(r.top, r.bottom, 0), engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW);
555 break;
556 }
557 case WID_N_VEH_INFO: {
558 assert(std::holds_alternative<EngineID>(ni->ref1));
559 EngineID engine = std::get<EngineID>(this->ni->ref1);
561 break;
562 }
563 }
564 }
565
566 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
567 {
568 switch (widget) {
569 case WID_N_CLOSEBOX:
571 this->Close();
572 _forced_news = std::end(_news);
573 break;
574
575 case WID_N_CAPTION:
576 if (std::holds_alternative<VehicleID>(ni->ref1)) {
577 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(this->ni->ref1));
579 }
580 break;
581
582 case WID_N_VIEWPORT:
583 break; // Ignore clicks
584
585 case WID_N_SHOW_GROUP:
586 if (std::holds_alternative<VehicleID>(ni->ref1)) {
587 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(this->ni->ref1));
589 }
590 break;
591 default:
592 if (std::holds_alternative<VehicleID>(ni->ref1)) {
593 const Vehicle *v = Vehicle::Get(std::get<VehicleID>(this->ni->ref1));
595 } else {
598 if (_ctrl_pressed) {
601 } else {
604 }
605 }
606 }
607 break;
608 }
609 }
610
611 void OnResize() override
612 {
613 if (this->viewport != nullptr) {
615 nvp->UpdateViewportCoordinates(this);
616
617 if (!std::holds_alternative<VehicleID>(ni->ref1)) {
618 ScrollWindowToTile(GetReferenceTile(ni->ref1), this, true); // Re-center viewport.
619 }
620 }
621
623 if (wid != nullptr) {
624 int y = GetStringHeight(GetString(STR_JUST_RAW_STRING, static_cast<const CompanyNewsInformation *>(this->ni->data.get())->president_name), wid->current_x);
625 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
626 }
627 }
628
634 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
635 {
636 if (!gui_scope) return;
637 /* The chatbar has notified us that is was either created or closed */
638 int newtop = this->top + this->chat_height - data;
639 this->chat_height = data;
640 this->SetWindowTop(newtop);
641 }
642
643 void OnRealtimeTick([[maybe_unused]] uint delta_ms) override
644 {
645 /* Decrement the news timer. We don't need to action an elapsed event here,
646 * so no need to use TimerElapsed(). */
648 }
649
655 IntervalTimer<TimerWindow> scroll_interval = {std::chrono::milliseconds(210) / GetCharacterHeight(FS_NORMAL), [this](uint count) {
656 int newtop = std::max(this->top - 2 * static_cast<int>(count), _screen.height - this->height - this->status_height - this->chat_height);
657 this->SetWindowTop(newtop);
658 }};
659
660private:
666 {
667 if (this->top == newtop) return;
668
669 int mintop = std::min(newtop, this->top);
670 int maxtop = std::max(newtop, this->top);
671 if (this->viewport != nullptr) this->viewport->top += newtop - this->top;
672 this->top = newtop;
673
674 AddDirtyBlock(this->left, mintop, this->left + this->width, maxtop + this->height);
675 }
676
677 std::string GetNewVehicleMessageString(WidgetID widget) const
678 {
679 assert(std::holds_alternative<EngineID>(ni->ref1));
680 EngineID engine = std::get<EngineID>(this->ni->ref1);
681
682 switch (widget) {
683 case WID_N_VEH_TITLE:
685
686 case WID_N_VEH_NAME:
688
689 default:
690 NOT_REACHED();
691 }
692 }
693};
694
695/* static */ int NewsWindow::duration = 0; // Instance creation.
696
698static void ShowNewspaper(const NewsItem *ni)
699{
701 if (sound != 0 && _settings_client.sound.news_full) SndPlayFx(sound);
702
703 new NewsWindow(GetNewsWindowLayout(ni->style), ni);
704}
705
714
717{
718 _news.clear();
719 _forced_news = std::end(_news);
720 _current_news = std::end(_news);
721 _statusbar_news = std::end(_news);
723}
724
730{
731 const NewsItem *ni = GetStatusbarNews();
732 if (ni == nullptr) return true;
733
734 /* Ticker message
735 * Check if the status bar message is still being displayed? */
736 return !IsNewsTickerShown();
737}
738
744{
745 if (_forced_news == std::end(_news) && _current_news == std::end(_news)) return true;
746
747 /* neither newsticker nor newspaper are running */
748 return (NewsWindow::duration <= 0 || FindWindowById(WC_NEWS_WINDOW, 0) == nullptr);
749}
750
753{
754 /* There is no status bar, so no reason to show news;
755 * especially important with the end game screen when
756 * there is no status bar but possible news. */
757 if (FindWindowById(WC_STATUS_BAR, 0) == nullptr) return;
758
759 /* No news to move to. */
760 if (std::empty(_news)) return;
761
762 /* if we're not at the latest item, then move on */
763 while (_statusbar_news != std::begin(_news)) {
765 const NewsType type = _statusbar_news->type;
766
767 /* check the date, don't show too old items */
768 if (TimerGameEconomy::date - _news_type_data[to_underlying(type)].age > _statusbar_news->economy_date) continue;
769
770 switch (_news_type_data[to_underlying(type)].GetDisplay()) {
771 default: NOT_REACHED();
772 case NewsDisplay::Off: // Show nothing only a small reminder in the status bar.
774 return;
775
776 case NewsDisplay::Summary: // Show ticker.
778 return;
779
780 case NewsDisplay::Full: // Show newspaper, skipped here.
781 break;;
782 }
783 }
784}
785
788{
789 /* There is no status bar, so no reason to show news;
790 * especially important with the end game screen when
791 * there is no status bar but possible news. */
792 if (FindWindowById(WC_STATUS_BAR, 0) == nullptr) return;
793
794 CloseWindowById(WC_NEWS_WINDOW, 0); // close the newspapers window if shown
795 _forced_news = std::end(_news);
796
797 /* No news to move to. */
798 if (std::empty(_news)) return;
799
800 /* if we're not at the latest item, then move on */
801 while (_current_news != std::begin(_news)) {
803 const NewsType type = _current_news->type;
804
805 /* check the date, don't show too old items */
806 if (TimerGameEconomy::date - _news_type_data[to_underlying(type)].age > _current_news->economy_date) continue;
807
808 switch (_news_type_data[to_underlying(type)].GetDisplay()) {
809 default: NOT_REACHED();
810 case NewsDisplay::Off: // Show nothing only a small reminder in the status bar, skipped here.
811 break;
812
813 case NewsDisplay::Summary: // Show ticker, skipped here.
814 break;
815
816 case NewsDisplay::Full: // Sshow newspaper.
818 return;
819 }
820 }
821}
822
824static std::list<NewsItem>::iterator DeleteNewsItem(std::list<NewsItem>::iterator ni)
825{
826 bool updateCurrentNews = (_forced_news == ni || _current_news == ni);
827 bool updateStatusbarNews = (_statusbar_news == ni);
828
829 if (updateCurrentNews) {
830 /* When we're the current news, go to the next older item first;
831 * we just possibly made that the last news item. */
832 if (_current_news == ni) ++_current_news;
833 if (_forced_news == ni) _forced_news = std::end(_news);
834 }
835
836 if (updateStatusbarNews) {
837 /* When we're the current news, go to the next older item first;
838 * we just possibly made that the last news item. */
840 }
841
842 /* Delete the news from the news queue. */
843 ni = _news.erase(ni);
844
845 if (updateCurrentNews) {
846 /* About to remove the currently forced item (shown as newspapers) ||
847 * about to remove the currently displayed item (newspapers) */
849 }
850
851 if (updateStatusbarNews) {
852 /* About to remove the currently displayed item (ticker, or just a reminder) */
853 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); // invalidate the statusbar
855 }
856
857 return ni;
858}
859
872NewsItem::NewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type) :
873 headline(std::move(headline)), date(TimerGameCalendar::date), economy_date(TimerGameEconomy::date), type(type), advice_type(advice_type), style(style), flags(flags), ref1(ref1), ref2(ref2), data(std::move(data))
874{
875 /* show this news message in colour? */
877}
878
879std::string NewsItem::GetStatusText() const
880{
881 if (this->data != nullptr) {
882 /* CompanyNewsInformation is the only type of additional data used. */
883 const CompanyNewsInformation &cni = *static_cast<const CompanyNewsInformation*>(this->data.get());
884 return GetString(STR_MESSAGE_NEWS_FORMAT, cni.title, this->headline.GetDecodedString());
885 }
886
887 return this->headline.GetDecodedString();
888}
889
902void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type)
903{
904 if (_game_mode == GM_MENU) return;
905
906 /* Create new news item node */
907 _news.emplace_front(std::move(headline), type, style, flags, ref1, ref2, std::move(data), advice_type);
908
909 /* Keep the number of stored news items to a manageable number */
910 if (std::size(_news) > MAX_NEWS_AMOUNT) {
911 DeleteNewsItem(std::prev(std::end(_news)));
912 }
913
915}
916
922uint32_t SerialiseNewsReference(const NewsReference &reference)
923{
924 struct visitor {
925 uint32_t operator()(const std::monostate &) { return 0; }
926 uint32_t operator()(const TileIndex &t) { return t.base(); }
927 uint32_t operator()(const VehicleID v) { return v.base(); }
928 uint32_t operator()(const StationID s) { return s.base(); }
929 uint32_t operator()(const IndustryID i) { return i.base(); }
930 uint32_t operator()(const TownID t) { return t.base(); }
931 uint32_t operator()(const EngineID e) { return e.base(); }
932 };
933
934 return std::visit(visitor{}, reference);
935}
936
948{
950
951 if (company != INVALID_OWNER && !Company::IsValidID(company)) return CMD_ERROR;
952 if (type >= NewsType::End) return CMD_ERROR;
953 if (text.empty()) return CMD_ERROR;
954
955 struct visitor {
956 bool operator()(const std::monostate &) { return true; }
957 bool operator()(const TileIndex t) { return IsValidTile(t); }
958 bool operator()(const VehicleID v) { return Vehicle::IsValidID(v); }
959 bool operator()(const StationID s) { return Station::IsValidID(s); }
960 bool operator()(const IndustryID i) { return Industry::IsValidID(i); }
961 bool operator()(const TownID t) { return Town::IsValidID(t); }
962 bool operator()(const EngineID e) { return Engine::IsValidID(e); }
963 };
964
965 if (!std::visit(visitor{}, reference)) return CMD_ERROR;
966
967 if (company != INVALID_OWNER && company != _local_company) return CommandCost();
968
969 if (flags.Test(DoCommandFlag::Execute)) {
970 AddNewsItem(EncodedString{text}, type, NewsStyle::Normal, {}, reference, {});
971 }
972
973 return CommandCost();
974}
975
981template <size_t Tmin = 0, class Tpredicate>
982void DeleteNews(Tpredicate predicate)
983{
984 bool dirty = false;
985 for (auto it = std::rbegin(_news); it != std::rend(_news); /* nothing */) {
986 if constexpr (Tmin > 0) {
987 if (std::size(_news) <= Tmin) break;
988 }
989 if (predicate(*it)) {
990 it = std::make_reverse_iterator(DeleteNewsItem(std::prev(it.base())));
991 dirty = true;
992 } else {
993 ++it;
994 }
995 }
997}
998
999template <typename T>
1000static bool IsReferenceObject(const NewsReference &reference, T id)
1001{
1002 return std::holds_alternative<T>(reference) && std::get<T>(reference) == id;
1003}
1004
1005template <typename T>
1006static bool HasReferenceObject(const NewsItem &ni, T id)
1007{
1008 return IsReferenceObject(ni.ref1, id) || IsReferenceObject(ni.ref2, id);
1009}
1010
1018{
1019 DeleteNews([&](const auto &ni) {
1020 return HasReferenceObject(ni, vid) && (advice_type == AdviceType::Invalid || ni.advice_type == advice_type);
1021 });
1022}
1023
1030{
1031 DeleteNews([&](const auto &ni) {
1032 return HasReferenceObject(ni, sid);
1033 });
1034}
1035
1041{
1042 DeleteNews([&](const auto &ni) {
1043 return HasReferenceObject(ni, iid);
1044 });
1045}
1046
1047bool IsInvalidEngineNews(const NewsReference &reference)
1048{
1049 if (!std::holds_alternative<EngineID>(reference)) return false;
1050
1051 EngineID eid = std::get<EngineID>(reference);
1052 return !Engine::IsValidID(eid) || !Engine::Get(eid)->IsEnabled();
1053}
1054
1059{
1060 DeleteNews([](const auto &ni) {
1061 return IsInvalidEngineNews(ni.ref1) || IsInvalidEngineNews(ni.ref2);
1062 });
1063}
1064
1065static void RemoveOldNewsItems()
1066{
1067 DeleteNews<MIN_NEWS_AMOUNT>([](const auto &ni) {
1069 });
1070}
1071
1072template <typename T>
1073static void ChangeObject(NewsReference reference, T from, T to)
1074{
1075 if (!std::holds_alternative<T>(reference)) return;
1076 if (std::get<T>(reference) == from) reference = to;
1077}
1078
1085void ChangeVehicleNews(VehicleID from_index, VehicleID to_index)
1086{
1087 for (auto &ni : _news) {
1088 ChangeObject(ni.ref1, from_index, to_index);
1089 ChangeObject(ni.ref2, from_index, to_index);
1090 if (ni.flags.Test(NewsFlag::VehicleParam0) && IsReferenceObject(ni.ref1, to_index)) ni.headline = ni.headline.ReplaceParam(0, to_index.base());
1091 }
1092}
1093
1094void NewsLoop()
1095{
1096 /* no news item yet */
1097 if (std::empty(_news)) return;
1098
1099 static TimerGameEconomy::Month _last_clean_month = 0;
1100
1101 if (_last_clean_month != TimerGameEconomy::month) {
1102 RemoveOldNewsItems();
1103 _last_clean_month = TimerGameEconomy::month;
1104 }
1105
1108}
1109
1112{
1113 assert(!std::empty(_news));
1114
1115 /* Delete the news window */
1117
1118 /* setup forced news item */
1119 _forced_news = ni;
1120
1121 if (_forced_news != std::end(_news)) {
1123 ShowNewspaper(&*ni);
1124 }
1125}
1126
1132{
1133 NewsWindow *w = dynamic_cast<NewsWindow *>(FindWindowById(WC_NEWS_WINDOW, 0));
1134 if (w == nullptr) return false;
1135 w->Close();
1136 return true;
1137}
1138
1141{
1142 if (std::empty(_news)) return;
1143
1144 NewsIterator ni;
1145 if (_forced_news == std::end(_news)) {
1146 /* Not forced any news yet, show the current one, unless a news window is
1147 * open (which can only be the current one), then show the previous item */
1148 if (_current_news == std::end(_news)) {
1149 /* No news were shown yet resp. the last shown one was already deleted.
1150 * Treat this as if _forced_news reached the oldest news; so, wrap around and start anew with the latest. */
1151 ni = std::begin(_news);
1152 } else {
1153 const Window *w = FindWindowById(WC_NEWS_WINDOW, 0);
1154 ni = (w == nullptr || (std::next(_current_news) == std::end(_news))) ? _current_news : std::next(_current_news);
1155 }
1156 } else if (std::next(_forced_news) == std::end(_news)) {
1157 /* We have reached the oldest news, start anew with the latest */
1158 ni = std::begin(_news);
1159 } else {
1160 /* 'Scrolling' through news history show each one in turn */
1161 ni = std::next(_forced_news);
1162 }
1163 bool wrap = false;
1164 for (;;) {
1166 ShowNewsMessage(ni);
1167 break;
1168 }
1169
1170 ++ni;
1171 if (ni == std::end(_news)) {
1172 if (wrap) break;
1173 /* We have reached the oldest news, start anew with the latest */
1174 ni = std::begin(_news);
1175 wrap = true;
1176 }
1177 }
1178}
1179
1180
1190static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni)
1191{
1192 /* Get the string, replaces newlines with spaces and remove control codes from the string. */
1193 std::string message = StrMakeValid(ni->GetStatusText(), SVS_REPLACE_TAB_CR_NL_WITH_SPACE);
1194
1195 /* Truncate and show string; postfixed by '...' if necessary */
1196 DrawString(left, right, y, message, colour);
1197}
1198
1200 int line_height = 0;
1201 int date_width = 0;
1202
1203 Scrollbar *vscroll = nullptr;
1204
1206 {
1207 this->CreateNestedTree();
1208 this->vscroll = this->GetScrollbar(WID_MH_SCROLLBAR);
1209 this->FinishInitNested(); // Initializes 'this->line_height' and 'this->date_width'.
1210 this->OnInvalidateData(0);
1211 }
1212
1214 {
1215 if (widget == WID_MH_BACKGROUND) {
1217 resize.height = this->line_height;
1218
1219 /* Months are off-by-one, so it's actually 8. Not using
1220 * month 12 because the 1 is usually less wide. */
1222
1223 size.height = 4 * resize.height + WidgetDimensions::scaled.framerect.Vertical(); // At least 4 lines are visible.
1224 size.width = std::max(200u, size.width); // At least 200 pixels wide.
1225 }
1226 }
1227
1228 void DrawWidget(const Rect &r, WidgetID widget) const override
1229 {
1230 if (widget != WID_MH_BACKGROUND || std::empty(_news)) return;
1231
1232 /* Fill the widget with news items. */
1233 bool rtl = _current_text_dir == TD_RTL;
1234 Rect news = r.Shrink(WidgetDimensions::scaled.framerect).Indent(this->date_width + WidgetDimensions::scaled.hsep_wide, rtl);
1235 Rect date = r.Shrink(WidgetDimensions::scaled.framerect).WithWidth(this->date_width, rtl);
1236 int y = news.top;
1237
1238 auto [first, last] = this->vscroll->GetVisibleRangeIterators(_news);
1239 for (auto ni = first; ni != last; ++ni) {
1240 DrawString(date.left, date.right, y, GetString(STR_JUST_DATE_TINY, ni->date), TC_WHITE);
1241
1242 DrawNewsString(news.left, news.right, y, TC_WHITE, &*ni);
1243 y += this->line_height;
1244 }
1245 }
1246
1252 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1253 {
1254 if (!gui_scope) return;
1255 this->vscroll->SetCount(std::size(_news));
1256 }
1257
1258 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1259 {
1260 if (widget == WID_MH_BACKGROUND) {
1261 /* Scheduled window invalidations currently occur after the input loop, which means the scrollbar count
1262 * could be invalid, so ensure it's correct now. Potentially this means that item clicked on might be
1263 * different as well. */
1264 this->vscroll->SetCount(std::size(_news));
1265 auto ni = this->vscroll->GetScrolledItemFromWidget(_news, pt.y, this, widget, WidgetDimensions::scaled.framerect.top);
1266 if (ni == std::end(_news)) return;
1267
1268 ShowNewsMessage(ni);
1269 }
1270 }
1271
1272 void OnResize() override
1273 {
1274 this->vscroll->SetCapacityFromWidget(this, WID_MH_BACKGROUND, WidgetDimensions::scaled.framerect.Vertical());
1275 }
1276};
1277
1278static constexpr NWidgetPart _nested_message_history[] = {
1280 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
1281 NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_MESSAGE_HISTORY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1282 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
1283 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
1284 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
1285 EndContainer(),
1286
1288 NWidget(WWT_PANEL, COLOUR_BROWN, WID_MH_BACKGROUND), SetMinimalSize(200, 125), SetToolTip(STR_MESSAGE_HISTORY_TOOLTIP), SetResize(1, 12), SetScrollbar(WID_MH_SCROLLBAR),
1289 EndContainer(),
1292 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
1293 EndContainer(),
1294 EndContainer(),
1295};
1296
1297static WindowDesc _message_history_desc(
1298 WDP_AUTO, "list_news", 400, 140,
1300 {},
1301 _nested_message_history
1302);
1303
1306{
1308 new MessageHistoryWindow(_message_history_desc);
1309}
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:219
EncodedString ReplaceParam(size_t param, StringParameter &&value) const
Replace a parameter of this EncodedString.
Definition strings.cpp:153
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Base class for a 'real' widget.
Leaf widget.
Base class for a resizable nested widget.
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:2424
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:2521
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
The maximum year of the original TTD.
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).
uint8_t Month
Type for the month, note: 0 based, i.e.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
RectPadding captiontext
Padding for text within caption widget.
Definition window_gui.h:49
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
int vsep_normal
Normal vertical spacing.
Definition window_gui.h:58
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
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(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
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 dparam.
@ PreviewNews
Name is shown in exclusive preview or newspaper.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:705
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition gfx.cpp:741
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:775
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:67
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
FontSize
Available font sizes.
Definition gfx_type.h:242
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:244
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
@ FS_LARGE
Index of the large font in the font tables.
Definition gfx_type.h:245
@ SA_TOP
Top align the text.
Definition gfx_type.h:380
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:377
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:385
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:294
@ FILLRECT_RECOLOUR
Apply a recolour sprite to the screen content.
Definition gfx_type.h:334
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 SetTextStyle(TextColour colour, FontSize size=FS_NORMAL)
Widget part function for setting the text style.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
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 SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
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:1467
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.
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:388
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:902
static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni)
Draw an unformatted news message truncated to a maximum length.
static void MoveToNextNewsItem()
Move to the next news item.
Definition news_gui.cpp:787
static void ShowTicker(NewsIterator ni)
Show news item in the ticker.
Definition news_gui.cpp:707
void DeleteNews(Tpredicate predicate)
Delete news items by predicate, and invalidate the message history if necessary.
Definition news_gui.cpp:982
static void ShowNewspaper(const NewsItem *ni)
Open up an own newspaper window for the news item.
Definition news_gui.cpp:698
static const uint MIN_NEWS_AMOUNT
preferred minimum amount of news messages.
Definition news_gui.cpp:47
static NewsTypeData _news_type_data[]
Per-NewsType data.
Definition news_gui.cpp:320
CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const EncodedString &text)
Create a new custom news item.
Definition news_gui.cpp:947
static NewsIterator _forced_news
Forced news item.
Definition news_gui.cpp:58
void DeleteIndustryNews(IndustryID iid)
Remove news regarding given industry.
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
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
uint32_t SerialiseNewsReference(const NewsReference &reference)
Encode a NewsReference for serialisation, e.g.
Definition news_gui.cpp:922
void DeleteInvalidEngineNews()
Remove engine announcements for invalid engines.
static bool ReadyForNextNewsItem()
Are we ready to show another news item? Only if no newspaper is displayed.
Definition news_gui.cpp:743
static std::list< NewsItem >::iterator DeleteNewsItem(std::list< NewsItem >::iterator ni)
Delete a news item from the queue.
Definition news_gui.cpp:824
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.
void InitNewsItemStructs()
Initialize the news-items data structures.
Definition news_gui.cpp:716
static void MoveToNextTickerItem()
Move to the next ticker item.
Definition news_gui.cpp:752
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 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 bool ReadyForNextTickerItem()
Are we ready to show another ticker item? Only if nothing is in the newsticker is displayed.
Definition news_gui.cpp:729
static WindowDesc * _news_window_layout[]
Window layouts for news items.
Definition news_gui.cpp:302
static NewsIterator _statusbar_news
Current status bar news item.
Definition news_gui.cpp:64
NewsType
Type of news.
Definition news_type.h:28
@ End
end-of-array marker
NewsContainer::const_iterator NewsIterator
Iterator type for news items.
Definition news_type.h:174
std::list< NewsItem > NewsContainer
Container type for storing news items.
Definition news_type.h:173
NewsStyle
News Window Styles.
Definition news_type.h:76
@ Normal
Normal news item. (Newspaper with text only)
AdviceType
Sub type of the NewsType::Advice to be able to remove specific news items.
Definition news_type.h:50
std::variant< std::monostate, TileIndex, VehicleID, StationID, IndustryID, TownID, EngineID > NewsReference
References to objects in news.
Definition news_type.h:73
@ NoTransparency
News item disables transparency in the viewport.
@ VehicleParam0
String param 0 contains a vehicle ID. (special autoreplace behaviour)
@ Shaded
News item uses shaded colours.
@ InColour
News item is shown in colour (otherwise it is shown in black & white).
NewsDisplay
News display options.
Definition news_type.h:99
@ Summary
Show ticker.
@ Full
Show newspaper.
@ Off
Only show a reminder in the status bar.
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_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:41
@ WID_MH_BACKGROUND
Background of the window.
Definition news_widget.h:40
static const uint8_t PC_GREY
Grey palette colour.
static const uint8_t PC_WHITE
White palette colour.
static const uint8_t PC_BLACK
Black palette colour.
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
static const SettingDesc * GetSettingFromName(const 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:57
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:45
@ SND_1D_APPLAUSE
27 == 0x1B News: first vehicle at station
Definition sound_type.h:74
@ SND_16_NEWS_TICKER
20 == 0x14 News ticker
Definition sound_type.h:67
@ SND_1E_NEW_ENGINE
28 == 0x1C News: new engine available
Definition sound_type.h:75
static const PaletteID PALETTE_NEWSPAPER
Recolour sprite for newspaper-greying.
Definition sprites.h:1608
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:277
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:125
Functions related to low-level strings.
@ SVS_REPLACE_TAB_CR_NL_WITH_SPACE
Replace tabs ('\t'), carriage returns ('\r') and newlines (' ') with spaces.
Definition string_type.h:54
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:426
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.
SoundSettings sound
sound effect settings
GUISettings gui
settings related to the GUI
Data that needs to be stored for company news messages.
Definition news_type.h:161
std::string president_name
The name of the president.
Definition news_type.h:163
Dimensions (a width and height) of a rectangle in 2D.
uint8_t news_message_timeout
how much longer than the news message "age" should we keep the message in the history
TimerGameCalendar::Year coloured_news_year
when does newspaper become coloured?
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:579
int date_width
< Height of a single line in the news history window including spacing.
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.
void OnResize() override
Called after the window got resized.
Scrollbar * vscroll
< Width needed for the date part.
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.
Partial widget specification to allow NWidgets to be written nested.
Information about a single item of news.
Definition news_type.h:136
TimerGameCalendar::Date date
Calendar date to show for the news.
Definition news_type.h:138
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:148
NewsType type
Type of the news.
Definition news_type.h:140
EncodedString headline
Headline of news.
Definition news_type.h:137
AdviceType advice_type
The type of advice, to be able to remove specific advices later on.
Definition news_type.h:141
TimerGameEconomy::Date economy_date
Economy date of the news item, never shown but used to calculate age.
Definition news_type.h:139
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:872
NewsFlags flags
Window style for the news.
Definition news_type.h:143
NewsReference ref2
Reference 2 to some object: Used for scrolling after clicking on the news, and for deleting the news ...
Definition news_type.h:146
NewsReference ref1
Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news,...
Definition news_type.h:145
Per-NewsType data.
Definition news_type.h:108
NewsDisplay GetDisplay() const
Return the news display option.
Definition news_gui.cpp:346
const char *const name
Name.
Definition news_type.h:109
const SoundFx sound
Sound.
Definition news_type.h:111
const uint8_t age
Maximum age of news items (in days)
Definition news_type.h:110
Window class displaying a news item.
Definition news_gui.cpp:354
uint16_t chat_height
Height of the chat window.
Definition news_gui.cpp:355
void OnResize() override
Called after the window got resized.
Definition news_gui.cpp:611
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:358
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition news_gui.cpp:511
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:431
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:425
void OnRealtimeTick(uint delta_ms) override
Called periodically.
Definition news_gui.cpp:643
uint16_t status_height
Height of the status bar window.
Definition news_gui.cpp:356
const NewsItem * ni
News item to display.
Definition news_gui.cpp:357
void SetWindowTop(int newtop)
Moves the window to a new top coordinate.
Definition news_gui.cpp:665
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition news_gui.cpp:498
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition news_gui.cpp:634
IntervalTimer< TimerWindow > scroll_interval
Scroll the news message slowly up from the bottom.
Definition news_gui.cpp:655
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:566
Coordinates of a point in 2D.
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
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.
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:928
bool news_ticker
Play a ticker sound when a news item is published.
bool news_full
Play sound effects associated to certain news types.
static bool IsValidID(auto index)
Tests whether given index is a valid index for station of this type.
static Station * Get(auto index)
Gets station with given index.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Vehicle data structure.
int32_t z_pos
z coordinate.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
int top
Screen coordinate top edge of the viewport.
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:955
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1050
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:502
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:1726
ViewportData * viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
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
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
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:311
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
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
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:2133
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, ...
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_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:692
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:41
@ WWT_LABEL
Centered label.
Definition widget_type.h:47
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:65
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:45
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:54
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:67
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
@ NWID_VIEWPORT
Nested widget containing a viewport.
Definition widget_type.h:72
@ NWID_LAYER
Layered widgets, all visible together.
Definition widget_type.h:71
@ ShadeDimmed
Display dimmed colours in the viewport.
@ ShadeGrey
Shade viewport to grey-scale.
@ NoTransparency
Viewport is never transparent.
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:1143
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1116
int PositionNewsMessage(Window *w)
(Re)position news message window at the screen.
Definition window.cpp:3417
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:3224
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1101
Window functions not directly related to making/drawing windows.
@ DisableVpScroll
Window does not do autoscroll,.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:145
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_NEWS_WINDOW
News window; Window numbers:
@ WC_STATUS_BAR
Statusbar (at the bottom of your screen); Window numbers:
Definition window_type.h:66
@ WC_SEND_NETWORK_MSG
Chatbox; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_MESSAGE_HISTORY
News history list; Window numbers:
Functions related to zooming.
ZoomLevel ScaleZoomGUI(ZoomLevel value)
Scale zoom level relative to GUI zoom.
Definition zoom_func.h:87
@ ZOOM_LVL_NEWS
Default zoom level for the news messages.
Definition zoom_type.h:29