OpenTTD Source 20250205-master-gfd85ab1e2c
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
90static TileIndex GetReferenceTile(NewsReferenceType reftype, uint32_t ref)
91{
92 switch (reftype) {
93 case NR_TILE: return (TileIndex)ref;
94 case NR_STATION: return Station::Get((StationID)ref)->xy;
95 case NR_INDUSTRY: return Industry::Get((IndustryID)ref)->location.tile + TileDiffXY(1, 1);
96 case NR_TOWN: return Town::Get((TownID)ref)->xy;
97 default: return INVALID_TILE;
98 }
99}
100
101/* Normal news items. */
102static constexpr NWidgetPart _nested_normal_news_widgets[] = {
103 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
105 NWidget(NWID_LAYER, INVALID_COLOUR),
106 /* Layer 1 */
109 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
110 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_DATE),
111 SetStringTip(STR_JUST_DATE_LONG),
112 SetTextStyle(TC_BLACK, FS_SMALL),
114 EndContainer(),
115 EndContainer(),
116 /* Layer 2 */
117 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MESSAGE),
119 SetMinimalSize(400, 0),
121 EndContainer(),
122 EndContainer(),
123 EndContainer(),
124};
125
126static WindowDesc _normal_news_desc(
127 WDP_MANUAL, nullptr, 0, 0,
129 {},
130 _nested_normal_news_widgets
131);
132
133/* New vehicles news items. */
134static constexpr NWidgetPart _nested_vehicle_news_widgets[] = {
135 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
137 NWidget(NWID_LAYER, INVALID_COLOUR),
138 /* Layer 1 */
141 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
142 EndContainer(),
143 EndContainer(),
144 /* Layer 2 */
145 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_VEH_TITLE),
146 SetFill(1, 1),
148 SetMinimalSize(400, 0),
150 SetStringTip(STR_EMPTY),
151 EndContainer(),
154 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_NAME),
156 SetMinimalSize(350, 0),
158 SetFill(1, 0),
159 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_SPR),
160 SetMinimalSize(350, 32),
161 SetFill(1, 0),
162 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_INFO),
164 SetMinimalSize(350, 0),
166 SetFill(1, 0),
167 EndContainer(),
168 EndContainer(),
169 EndContainer(),
170 EndContainer(),
171};
172
173static WindowDesc _vehicle_news_desc(
174 WDP_MANUAL, nullptr, 0, 0,
176 {},
177 _nested_vehicle_news_widgets
178);
179
180/* Company news items. */
181static constexpr NWidgetPart _nested_company_news_widgets[] = {
182 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
184 NWidget(NWID_LAYER, INVALID_COLOUR),
185 /* Layer 1 */
188 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
189 EndContainer(),
190 EndContainer(),
191 /* Layer 2 */
192 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_TITLE),
193 SetFill(1, 1),
195 SetMinimalSize(400, 0),
197 SetStringTip(STR_EMPTY),
198 EndContainer(),
201 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MGR_FACE),
202 SetFill(0, 0),
203 SetMinimalSize(93, 119),
204 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MGR_NAME),
205 SetFill(0, 1),
207 EndContainer(),
208 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_COMPANY_MSG),
209 SetFill(1, 1),
211 SetMinimalSize(300, 0),
212 EndContainer(),
213 EndContainer(),
214 EndContainer(),
215};
216
217static WindowDesc _company_news_desc(
218 WDP_MANUAL, nullptr, 0, 0,
220 {},
221 _nested_company_news_widgets
222);
223
224/* Thin news items. */
225static constexpr NWidgetPart _nested_thin_news_widgets[] = {
226 NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL),
228 NWidget(NWID_LAYER, INVALID_COLOUR),
229 /* Layer 1 */
232 NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX),
233 NWidget(WWT_LABEL, INVALID_COLOUR, WID_N_DATE),
234 SetStringTip(STR_JUST_DATE_LONG),
235 SetTextStyle(TC_BLACK, FS_SMALL),
237 EndContainer(),
238 EndContainer(),
239 /* Layer 2 */
240 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MESSAGE),
242 SetMinimalSize(400, 0),
244 EndContainer(),
245 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetMinimalSize(426, 70),
247 EndContainer(),
248 EndContainer(),
249};
250
251static WindowDesc _thin_news_desc(
252 WDP_MANUAL, nullptr, 0, 0,
254 {},
255 _nested_thin_news_widgets
256);
257
258/* Small news items. */
259static constexpr NWidgetPart _nested_small_news_widgets[] = {
260 /* Caption + close box. The caption is not WWT_CAPTION as the window shall not be moveable and so on. */
262 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE, WID_N_CLOSEBOX),
263 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_CAPTION),
264 NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_N_SHOW_GROUP),
265 SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON),
266 SetResize(1, 0),
267 SetToolTip(STR_NEWS_SHOW_VEHICLE_GROUP_TOOLTIP),
268 EndContainer(),
269
270 /* Main part */
271 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_N_HEADLINE),
273 SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
274 SetPadding(2),
275 NWidget(WWT_INSET, COLOUR_LIGHT_BLUE, WID_N_INSET),
276 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT),
277 SetMinimalSize(274, 47),
278 EndContainer(),
279 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_MESSAGE),
281 SetMinimalSize(275, 0),
282 EndContainer(),
283 EndContainer(),
284};
285
286static WindowDesc _small_news_desc(
287 WDP_MANUAL, nullptr, 0, 0,
289 {},
290 _nested_small_news_widgets
291);
292
297 &_thin_news_desc,
298 &_small_news_desc,
299 &_normal_news_desc,
300 &_vehicle_news_desc,
301 &_company_news_desc,
302};
303
304WindowDesc &GetNewsWindowLayout(NewsFlag flags)
305{
306 uint layout = GB(flags, NFB_WINDOW_LAYOUT, NFB_WINDOW_LAYOUT_COUNT);
307 assert(layout < lengthof(_news_window_layout));
308 return *_news_window_layout[layout];
309}
310
315 /* name, age, sound, */
316 NewsTypeData("news_display.arrival_player", 60, SND_1D_APPLAUSE ),
317 NewsTypeData("news_display.arrival_other", 60, SND_1D_APPLAUSE ),
318 NewsTypeData("news_display.accident", 90, SND_BEGIN ),
319 NewsTypeData("news_display.accident_other", 90, SND_BEGIN ),
320 NewsTypeData("news_display.company_info", 60, SND_BEGIN ),
321 NewsTypeData("news_display.open", 90, SND_BEGIN ),
322 NewsTypeData("news_display.close", 90, SND_BEGIN ),
323 NewsTypeData("news_display.economy", 30, SND_BEGIN ),
324 NewsTypeData("news_display.production_player", 30, SND_BEGIN ),
325 NewsTypeData("news_display.production_other", 30, SND_BEGIN ),
326 NewsTypeData("news_display.production_nobody", 30, SND_BEGIN ),
327 NewsTypeData("news_display.advice", 150, SND_BEGIN ),
328 NewsTypeData("news_display.new_vehicles", 30, SND_1E_NEW_ENGINE),
329 NewsTypeData("news_display.acceptance", 90, SND_BEGIN ),
330 NewsTypeData("news_display.subsidies", 180, SND_BEGIN ),
331 NewsTypeData("news_display.general", 60, SND_BEGIN ),
332};
333
334static_assert(lengthof(_news_type_data) == NT_END);
335
341{
342 const SettingDesc *sd = GetSettingFromName(this->name);
343 assert(sd != nullptr && sd->IsIntSetting());
344 return (NewsDisplay)sd->AsIntSetting()->Read(nullptr);
345}
346
351 const NewsItem *ni;
352 static int duration;
353
354 NewsWindow(WindowDesc &desc, const NewsItem *ni) : Window(desc), ni(ni)
355 {
356 NewsWindow::duration = 16650;
358 this->chat_height = (w != nullptr) ? w->height : 0;
359 this->status_height = FindWindowById(WC_STATUS_BAR, 0)->height;
360
361 this->flags.Set(WindowFlag::DisableVpScroll);
362
363 this->CreateNestedTree();
364
365 /* For company news with a face we have a separate headline in param[0] */
366 if (&desc == &_company_news_desc) this->GetWidget<NWidgetCore>(WID_N_TITLE)->SetString(static_cast<StringID>(std::get<uint64_t>(this->ni->params[0])));
367
369 if (ni->reftype1 == NR_VEHICLE && nwid != nullptr) {
370 const Vehicle *v = Vehicle::Get(ni->ref1);
371 switch (v->type) {
372 case VEH_TRAIN:
373 nwid->SetString(STR_TRAIN);
374 break;
375 case VEH_ROAD:
376 nwid->SetString(RoadVehicle::From(v)->IsBus() ? STR_BUS : STR_LORRY);
377 break;
378 case VEH_SHIP:
379 nwid->SetString(STR_SHIP);
380 break;
381 case VEH_AIRCRAFT:
382 nwid->SetString(STR_PLANE);
383 break;
384 default:
385 break; // Do nothing
386 }
387 }
388
389 this->FinishInitNested(0);
390
391 /* Initialize viewport if it exists. */
393 if (nvp != nullptr) {
394 if (ni->reftype1 == NR_VEHICLE) {
395 nvp->InitializeViewport(this, static_cast<VehicleID>(ni->ref1), ScaleZoomGUI(ZOOM_LVL_NEWS));
396 } else {
397 nvp->InitializeViewport(this, GetReferenceTile(ni->reftype1, ni->ref1), ScaleZoomGUI(ZOOM_LVL_NEWS));
398 }
399 if (this->ni->flags & NF_NO_TRANSPARENT) nvp->disp_flags |= ND_NO_TRANSPARENCY;
400 if ((this->ni->flags & NF_INCOLOUR) == 0) {
401 nvp->disp_flags |= ND_SHADE_GREY;
402 } else if (this->ni->flags & NF_SHADE) {
403 nvp->disp_flags |= ND_SHADE_DIMMED;
404 }
405 }
406
408 }
409
410 void DrawNewsBorder(const Rect &r) const
411 {
414
415 ir = ir.Expand(1);
416 GfxFillRect( r.left, r.top, ir.left, r.bottom, PC_BLACK);
417 GfxFillRect(ir.right, r.top, r.right, r.bottom, PC_BLACK);
418 GfxFillRect( r.left, r.top, r.right, ir.top, PC_BLACK);
419 GfxFillRect( r.left, ir.bottom, r.right, r.bottom, PC_BLACK);
420 }
421
423 {
424 Point pt = { 0, _screen.height };
425 return pt;
426 }
427
429 {
430 StringID str = STR_NULL;
431 switch (widget) {
432 case WID_N_CAPTION: {
433 /* Caption is not a real caption (so that the window cannot be moved)
434 * thus it doesn't get the default sizing of a caption. */
437 size = maxdim(size, d2);
438 return;
439 }
440
441 case WID_N_MGR_FACE:
442 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
443 break;
444
445 case WID_N_MESSAGE:
446 CopyInDParam(this->ni->params);
447 str = this->ni->string_id;
448 break;
449
451 str = this->GetCompanyMessageString();
452 break;
453
454 case WID_N_VEH_NAME:
455 case WID_N_VEH_TITLE:
456 str = this->GetNewVehicleMessageString(widget);
457 break;
458
459 case WID_N_VEH_INFO: {
460 assert(this->ni->reftype1 == NR_ENGINE);
461 EngineID engine = this->ni->ref1;
462 str = GetEngineInfoString(engine);
463 break;
464 }
465
466 case WID_N_SHOW_GROUP:
467 if (this->ni->reftype1 == NR_VEHICLE) {
471 size = d2;
472 } else {
473 /* Hide 'Show group window' button if this news is not about a vehicle. */
474 size.width = 0;
475 size.height = 0;
476 resize.width = 0;
477 resize.height = 0;
478 fill.width = 0;
479 fill.height = 0;
480 }
481 return;
482
483 default:
484 return; // Do nothing
485 }
486
487 /* Update minimal size with length of the multi-line string. */
488 Dimension d = size;
489 d.width = (d.width >= padding.width) ? d.width - padding.width : 0;
490 d.height = (d.height >= padding.height) ? d.height - padding.height : 0;
492 d.width += padding.width;
493 d.height += padding.height;
494 size = maxdim(size, d);
495 }
496
497 void SetStringParameters(WidgetID widget) const override
498 {
499 if (widget == WID_N_DATE) SetDParam(0, this->ni->date);
500 }
501
502 void DrawWidget(const Rect &r, WidgetID widget) const override
503 {
504 switch (widget) {
505 case WID_N_CAPTION:
506 DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, TC_FROMSTRING, STR_NEWS_MESSAGE_CAPTION, SA_CENTER, FS_NORMAL);
507 break;
508
509 case WID_N_PANEL:
510 this->DrawNewsBorder(r);
511 break;
512
513 case WID_N_MESSAGE:
514 CopyInDParam(this->ni->params);
515 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->ni->string_id, TC_FROMSTRING, SA_CENTER);
516 break;
517
518 case WID_N_MGR_FACE: {
519 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
520 DrawCompanyManagerFace(cni->face, cni->colour, r);
521 GfxFillRect(r.left, r.top, r.right, r.bottom, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
522 break;
523 }
524 case WID_N_MGR_NAME: {
525 const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
526 SetDParamStr(0, cni->president_name);
527 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER);
528 break;
529 }
531 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetCompanyMessageString(), TC_FROMSTRING, SA_CENTER);
532 break;
533
534 case WID_N_VEH_BKGND:
535 GfxFillRect(r.left, r.top, r.right, r.bottom, PC_GREY);
536 break;
537
538 case WID_N_VEH_NAME:
539 case WID_N_VEH_TITLE:
540 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetNewVehicleMessageString(widget), TC_FROMSTRING, SA_CENTER);
541 break;
542
543 case WID_N_VEH_SPR: {
544 assert(this->ni->reftype1 == NR_ENGINE);
545 EngineID engine = this->ni->ref1;
546 DrawVehicleEngine(r.left, r.right, CenterBounds(r.left, r.right, 0), CenterBounds(r.top, r.bottom, 0), engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW);
547 GfxFillRect(r.left, r.top, r.right, r.bottom, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
548 break;
549 }
550 case WID_N_VEH_INFO: {
551 assert(this->ni->reftype1 == NR_ENGINE);
552 EngineID engine = this->ni->ref1;
553 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER);
554 break;
555 }
556 }
557 }
558
559 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
560 {
561 switch (widget) {
562 case WID_N_CLOSEBOX:
564 this->Close();
565 _forced_news = std::end(_news);
566 break;
567
568 case WID_N_CAPTION:
569 if (this->ni->reftype1 == NR_VEHICLE) {
570 const Vehicle *v = Vehicle::Get(this->ni->ref1);
572 }
573 break;
574
575 case WID_N_VIEWPORT:
576 break; // Ignore clicks
577
578 case WID_N_SHOW_GROUP:
579 if (this->ni->reftype1 == NR_VEHICLE) {
580 const Vehicle *v = Vehicle::Get(this->ni->ref1);
582 }
583 break;
584 default:
585 if (this->ni->reftype1 == NR_VEHICLE) {
586 const Vehicle *v = Vehicle::Get(this->ni->ref1);
588 } else {
589 TileIndex tile1 = GetReferenceTile(this->ni->reftype1, this->ni->ref1);
590 TileIndex tile2 = GetReferenceTile(this->ni->reftype2, this->ni->ref2);
591 if (_ctrl_pressed) {
594 } else {
597 }
598 }
599 }
600 break;
601 }
602 }
603
604 void OnResize() override
605 {
606 if (this->viewport != nullptr) {
608 nvp->UpdateViewportCoordinates(this);
609
610 if (ni->reftype1 != NR_VEHICLE) {
611 ScrollWindowToTile(GetReferenceTile(ni->reftype1, ni->ref1), this, true); // Re-center viewport.
612 }
613 }
614
616 if (wid != nullptr) {
617 SetDParamStr(0, static_cast<const CompanyNewsInformation *>(this->ni->data.get())->president_name);
618 int y = GetStringHeight(STR_JUST_RAW_STRING, wid->current_x);
619 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
620 }
621 }
622
628 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
629 {
630 if (!gui_scope) return;
631 /* The chatbar has notified us that is was either created or closed */
632 int newtop = this->top + this->chat_height - data;
633 this->chat_height = data;
634 this->SetWindowTop(newtop);
635 }
636
637 void OnRealtimeTick([[maybe_unused]] uint delta_ms) override
638 {
639 /* Decrement the news timer. We don't need to action an elapsed event here,
640 * so no need to use TimerElapsed(). */
642 }
643
649 IntervalTimer<TimerWindow> scroll_interval = {std::chrono::milliseconds(210) / GetCharacterHeight(FS_NORMAL), [this](uint count) {
650 int newtop = std::max(this->top - 2 * static_cast<int>(count), _screen.height - this->height - this->status_height - this->chat_height);
651 this->SetWindowTop(newtop);
652 }};
653
654private:
660 {
661 if (this->top == newtop) return;
662
663 int mintop = std::min(newtop, this->top);
664 int maxtop = std::max(newtop, this->top);
665 if (this->viewport != nullptr) this->viewport->top += newtop - this->top;
666 this->top = newtop;
667
668 AddDirtyBlock(this->left, mintop, this->left + this->width, maxtop + this->height);
669 }
670
671 StringID GetCompanyMessageString() const
672 {
673 /* Company news with a face have a separate headline, so the normal message is shifted by two params */
674 CopyInDParam(std::span(this->ni->params.data() + 2, this->ni->params.size() - 2));
675 return std::get<uint64_t>(this->ni->params[1]);
676 }
677
678 StringID GetNewVehicleMessageString(WidgetID widget) const
679 {
680 assert(this->ni->reftype1 == NR_ENGINE);
681 EngineID engine = this->ni->ref1;
682
683 switch (widget) {
684 case WID_N_VEH_TITLE:
687
688 case WID_N_VEH_NAME:
691
692 default:
693 NOT_REACHED();
694 }
695 }
696};
697
698/* static */ int NewsWindow::duration = 0; // Instance creation.
699
701static void ShowNewspaper(const NewsItem *ni)
702{
703 SoundFx sound = _news_type_data[ni->type].sound;
704 if (sound != 0 && _settings_client.sound.news_full) SndPlayFx(sound);
705
706 new NewsWindow(GetNewsWindowLayout(ni->flags), ni);
707}
708
717
720{
721 _news.clear();
722 _forced_news = std::end(_news);
723 _current_news = std::end(_news);
724 _statusbar_news = std::end(_news);
726}
727
733{
734 const NewsItem *ni = GetStatusbarNews();
735 if (ni == nullptr) return true;
736
737 /* Ticker message
738 * Check if the status bar message is still being displayed? */
739 return !IsNewsTickerShown();
740}
741
747{
748 if (_forced_news == std::end(_news) && _current_news == std::end(_news)) return true;
749
750 /* neither newsticker nor newspaper are running */
751 return (NewsWindow::duration <= 0 || FindWindowById(WC_NEWS_WINDOW, 0) == nullptr);
752}
753
756{
757 /* There is no status bar, so no reason to show news;
758 * especially important with the end game screen when
759 * there is no status bar but possible news. */
760 if (FindWindowById(WC_STATUS_BAR, 0) == nullptr) return;
761
762 /* No news to move to. */
763 if (std::empty(_news)) return;
764
765 /* if we're not at the latest item, then move on */
766 while (_statusbar_news != std::begin(_news)) {
768 const NewsType type = _statusbar_news->type;
769
770 /* check the date, don't show too old items */
771 if (TimerGameEconomy::date - _news_type_data[type].age > _statusbar_news->economy_date) continue;
772
773 switch (_news_type_data[type].GetDisplay()) {
774 default: NOT_REACHED();
775 case ND_OFF: // Off - show nothing only a small reminder in the status bar
777 return;
778
779 case ND_SUMMARY: // Summary - show ticker
781 return;
782
783 case ND_FULL: // Full - show newspaper, skipped here
784 break;;
785 }
786 }
787}
788
791{
792 /* There is no status bar, so no reason to show news;
793 * especially important with the end game screen when
794 * there is no status bar but possible news. */
795 if (FindWindowById(WC_STATUS_BAR, 0) == nullptr) return;
796
797 CloseWindowById(WC_NEWS_WINDOW, 0); // close the newspapers window if shown
798 _forced_news = std::end(_news);
799
800 /* No news to move to. */
801 if (std::empty(_news)) return;
802
803 /* if we're not at the latest item, then move on */
804 while (_current_news != std::begin(_news)) {
806 const NewsType type = _current_news->type;
807
808 /* check the date, don't show too old items */
809 if (TimerGameEconomy::date - _news_type_data[type].age > _current_news->economy_date) continue;
810
811 switch (_news_type_data[type].GetDisplay()) {
812 default: NOT_REACHED();
813 case ND_OFF: // Off - show nothing only a small reminder in the status bar, skipped here
814 break;
815
816 case ND_SUMMARY: // Summary - show ticker, skipped here
817 break;;
818
819 case ND_FULL: // Full - show newspaper
821 return;
822 }
823 }
824}
825
827static std::list<NewsItem>::iterator DeleteNewsItem(std::list<NewsItem>::iterator ni)
828{
829 bool updateCurrentNews = (_forced_news == ni || _current_news == ni);
830 bool updateStatusbarNews = (_statusbar_news == ni);
831
832 if (updateCurrentNews) {
833 /* When we're the current news, go to the next older item first;
834 * we just possibly made that the last news item. */
835 if (_current_news == ni) ++_current_news;
836 if (_forced_news == ni) _forced_news = std::end(_news);
837 }
838
839 if (updateStatusbarNews) {
840 /* When we're the current news, go to the next older item first;
841 * we just possibly made that the last news item. */
843 }
844
845 /* Delete the news from the news queue. */
846 ni = _news.erase(ni);
847
848 if (updateCurrentNews) {
849 /* About to remove the currently forced item (shown as newspapers) ||
850 * about to remove the currently displayed item (newspapers) */
852 }
853
854 if (updateStatusbarNews) {
855 /* About to remove the currently displayed item (ticker, or just a reminder) */
856 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); // invalidate the statusbar
858 }
859
860 return ni;
861}
862
877NewsItem::NewsItem(StringID string_id, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32_t ref1, NewsReferenceType reftype2, uint32_t ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type) :
878 string_id(string_id), date(TimerGameCalendar::date), economy_date(TimerGameEconomy::date), type(type), advice_type(advice_type), flags(flags), reftype1(reftype1), reftype2(reftype2), ref1(ref1), ref2(ref2), data(std::move(data))
879{
880 /* show this news message in colour? */
882 CopyOutDParam(this->params, 10);
883}
884
899void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32_t ref1, NewsReferenceType reftype2, uint32_t ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type)
900{
901 if (_game_mode == GM_MENU) return;
902
903 /* Create new news item node */
904 _news.emplace_front(string, type, flags, reftype1, ref1, reftype2, ref2, std::move(data), advice_type);
905
906 /* Keep the number of stored news items to a managable number */
907 if (std::size(_news) > MAX_NEWS_AMOUNT) {
908 DeleteNewsItem(std::prev(std::end(_news)));
909 }
910
912}
913
924CommandCost CmdCustomNewsItem(DoCommandFlag flags, NewsType type, NewsReferenceType reftype1, CompanyID company, uint32_t reference, const std::string &text)
925{
927
928 if (company != INVALID_OWNER && !Company::IsValidID(company)) return CMD_ERROR;
929 if (type >= NT_END) return CMD_ERROR;
930 if (text.empty()) return CMD_ERROR;
931
932 switch (reftype1) {
933 case NR_NONE: break;
934 case NR_TILE:
935 if (!IsValidTile(reference)) return CMD_ERROR;
936 break;
937
938 case NR_VEHICLE:
939 if (!Vehicle::IsValidID(reference)) return CMD_ERROR;
940 break;
941
942 case NR_STATION:
943 if (!Station::IsValidID(reference)) return CMD_ERROR;
944 break;
945
946 case NR_INDUSTRY:
947 if (!Industry::IsValidID(reference)) return CMD_ERROR;
948 break;
949
950 case NR_TOWN:
951 if (!Town::IsValidID(reference)) return CMD_ERROR;
952 break;
953
954 case NR_ENGINE:
955 if (!Engine::IsValidID(reference)) return CMD_ERROR;
956 break;
957
958 default: return CMD_ERROR;
959 }
960
961 if (company != INVALID_OWNER && company != _local_company) return CommandCost();
962
963 if (flags & DC_EXEC) {
964 SetDParamStr(0, text);
965 AddNewsItem(STR_NEWS_CUSTOM_ITEM, type, NF_NORMAL, reftype1, reference, NR_NONE, UINT32_MAX);
966 }
967
968 return CommandCost();
969}
970
976template <size_t Tmin = 0, class Tpredicate>
977void DeleteNews(Tpredicate predicate)
978{
979 bool dirty = false;
980 for (auto it = std::rbegin(_news); it != std::rend(_news); /* nothing */) {
981 if constexpr (Tmin > 0) {
982 if (std::size(_news) <= Tmin) break;
983 }
984 if (predicate(*it)) {
985 it = std::make_reverse_iterator(DeleteNewsItem(std::prev(it.base())));
986 dirty = true;
987 } else {
988 ++it;
989 }
990 }
992}
993
1001{
1002 DeleteNews([&](const auto &ni) {
1003 return ((ni.reftype1 == NR_VEHICLE && ni.ref1 == vid) || (ni.reftype2 == NR_VEHICLE && ni.ref2 == vid)) && (advice_type == AdviceType::Invalid || ni.advice_type == advice_type);
1004 });
1005}
1006
1012void DeleteStationNews(StationID sid)
1013{
1014 DeleteNews([&](const auto &ni) {
1015 return (ni.reftype1 == NR_STATION && ni.ref1 == sid) || (ni.reftype2 == NR_STATION && ni.ref2 == sid);
1016 });
1017}
1018
1023void DeleteIndustryNews(IndustryID iid)
1024{
1025 DeleteNews([&](const auto &ni) {
1026 return (ni.reftype1 == NR_INDUSTRY && ni.ref1 == iid) || (ni.reftype2 == NR_INDUSTRY && ni.ref2 == iid);
1027 });
1028}
1029
1034{
1035 DeleteNews([](const auto &ni) {
1036 return (ni.reftype1 == NR_ENGINE && (!Engine::IsValidID(ni.ref1) || !Engine::Get(ni.ref1)->IsEnabled())) ||
1037 (ni.reftype2 == NR_ENGINE && (!Engine::IsValidID(ni.ref2) || !Engine::Get(ni.ref2)->IsEnabled()));
1038 });
1039}
1040
1041static void RemoveOldNewsItems()
1042{
1043 DeleteNews<MIN_NEWS_AMOUNT>([](const auto &ni) {
1045 });
1046}
1047
1054void ChangeVehicleNews(VehicleID from_index, VehicleID to_index)
1055{
1056 for (auto &ni : _news) {
1057 if (ni.reftype1 == NR_VEHICLE && ni.ref1 == from_index) ni.ref1 = to_index;
1058 if (ni.reftype2 == NR_VEHICLE && ni.ref2 == from_index) ni.ref2 = to_index;
1059 if (ni.flags & NF_VEHICLE_PARAM0 && std::get<uint64_t>(ni.params[0]) == from_index) ni.params[0] = to_index;
1060 }
1061}
1062
1063void NewsLoop()
1064{
1065 /* no news item yet */
1066 if (std::empty(_news)) return;
1067
1068 static TimerGameEconomy::Month _last_clean_month = 0;
1069
1070 if (_last_clean_month != TimerGameEconomy::month) {
1071 RemoveOldNewsItems();
1072 _last_clean_month = TimerGameEconomy::month;
1073 }
1074
1077}
1078
1081{
1082 assert(!std::empty(_news));
1083
1084 /* Delete the news window */
1086
1087 /* setup forced news item */
1088 _forced_news = ni;
1089
1090 if (_forced_news != std::end(_news)) {
1092 ShowNewspaper(&*ni);
1093 }
1094}
1095
1101{
1102 NewsWindow *w = dynamic_cast<NewsWindow *>(FindWindowById(WC_NEWS_WINDOW, 0));
1103 if (w == nullptr) return false;
1104 w->Close();
1105 return true;
1106}
1107
1110{
1111 if (std::empty(_news)) return;
1112
1113 NewsIterator ni;
1114 if (_forced_news == std::end(_news)) {
1115 /* Not forced any news yet, show the current one, unless a news window is
1116 * open (which can only be the current one), then show the previous item */
1117 if (_current_news == std::end(_news)) {
1118 /* No news were shown yet resp. the last shown one was already deleted.
1119 * Treat this as if _forced_news reached the oldest news; so, wrap around and start anew with the latest. */
1120 ni = std::begin(_news);
1121 } else {
1122 const Window *w = FindWindowById(WC_NEWS_WINDOW, 0);
1123 ni = (w == nullptr || (std::next(_current_news) == std::end(_news))) ? _current_news : std::next(_current_news);
1124 }
1125 } else if (std::next(_forced_news) == std::end(_news)) {
1126 /* We have reached the oldest news, start anew with the latest */
1127 ni = std::begin(_news);
1128 } else {
1129 /* 'Scrolling' through news history show each one in turn */
1130 ni = std::next(_forced_news);
1131 }
1132 bool wrap = false;
1133 for (;;) {
1134 if (_news_type_data[ni->type].GetDisplay() != ND_OFF) {
1135 ShowNewsMessage(ni);
1136 break;
1137 }
1138
1139 ++ni;
1140 if (ni == std::end(_news)) {
1141 if (wrap) break;
1142 /* We have reached the oldest news, start anew with the latest */
1143 ni = std::begin(_news);
1144 wrap = true;
1145 }
1146 }
1147}
1148
1149
1159static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni)
1160{
1161 CopyInDParam(ni->params);
1162
1163 /* Get the string, replaces newlines with spaces and remove control codes from the string. */
1165
1166 /* Truncate and show string; postfixed by '...' if necessary */
1167 DrawString(left, right, y, message, colour);
1168}
1169
1171 int line_height;
1173
1175
1177 {
1178 this->CreateNestedTree();
1179 this->vscroll = this->GetScrollbar(WID_MH_SCROLLBAR);
1180 this->FinishInitNested(); // Initializes 'this->line_height' and 'this->date_width'.
1181 this->OnInvalidateData(0);
1182 }
1183
1185 {
1186 if (widget == WID_MH_BACKGROUND) {
1188 resize.height = this->line_height;
1189
1190 /* Months are off-by-one, so it's actually 8. Not using
1191 * month 12 because the 1 is usually less wide. */
1194
1195 size.height = 4 * resize.height + WidgetDimensions::scaled.framerect.Vertical(); // At least 4 lines are visible.
1196 size.width = std::max(200u, size.width); // At least 200 pixels wide.
1197 }
1198 }
1199
1200 void DrawWidget(const Rect &r, WidgetID widget) const override
1201 {
1202 if (widget != WID_MH_BACKGROUND || std::empty(_news)) return;
1203
1204 /* Fill the widget with news items. */
1205 bool rtl = _current_text_dir == TD_RTL;
1206 Rect news = r.Shrink(WidgetDimensions::scaled.framerect).Indent(this->date_width + WidgetDimensions::scaled.hsep_wide, rtl);
1207 Rect date = r.Shrink(WidgetDimensions::scaled.framerect).WithWidth(this->date_width, rtl);
1208 int y = news.top;
1209
1210 auto [first, last] = this->vscroll->GetVisibleRangeIterators(_news);
1211 for (auto ni = first; ni != last; ++ni) {
1212 SetDParam(0, ni->date);
1213 DrawString(date.left, date.right, y, STR_JUST_DATE_TINY, TC_WHITE);
1214
1215 DrawNewsString(news.left, news.right, y, TC_WHITE, &*ni);
1216 y += this->line_height;
1217 }
1218 }
1219
1225 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1226 {
1227 if (!gui_scope) return;
1228 this->vscroll->SetCount(std::size(_news));
1229 }
1230
1231 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1232 {
1233 if (widget == WID_MH_BACKGROUND) {
1234 /* Scheduled window invalidations currently occur after the input loop, which means the scrollbar count
1235 * could be invalid, so ensure it's correct now. Potentially this means that item clicked on might be
1236 * different as well. */
1237 this->vscroll->SetCount(std::size(_news));
1238 auto ni = this->vscroll->GetScrolledItemFromWidget(_news, pt.y, this, widget, WidgetDimensions::scaled.framerect.top);
1239 if (ni == std::end(_news)) return;
1240
1241 ShowNewsMessage(ni);
1242 }
1243 }
1244
1245 void OnResize() override
1246 {
1247 this->vscroll->SetCapacityFromWidget(this, WID_MH_BACKGROUND, WidgetDimensions::scaled.framerect.Vertical());
1248 }
1249};
1250
1251static constexpr NWidgetPart _nested_message_history[] = {
1253 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
1254 NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_MESSAGE_HISTORY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1255 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
1256 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
1257 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
1258 EndContainer(),
1259
1261 NWidget(WWT_PANEL, COLOUR_BROWN, WID_MH_BACKGROUND), SetMinimalSize(200, 125), SetToolTip(STR_MESSAGE_HISTORY_TOOLTIP), SetResize(1, 12), SetScrollbar(WID_MH_SCROLLBAR),
1262 EndContainer(),
1265 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
1266 EndContainer(),
1267 EndContainer(),
1268};
1269
1270static WindowDesc _message_history_desc(
1271 WDP_AUTO, "list_news", 400, 140,
1273 {},
1274 _nested_message_history
1275);
1276
1279{
1281 new MessageHistoryWindow(_message_history_desc);
1282}
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Common return value for all commands.
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.
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:2436
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:2533
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:28
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.
DoCommandFlag
List of flags for a command.
@ DC_EXEC
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.
Owner
Enum for all companies/owners.
@ INVALID_OWNER
An invalid owner.
@ OWNER_DEITY
The object is owned by a superuser / goal script.
Base class for engines.
StringID GetEngineCategoryName(EngineID engine)
Return the category of an engine.
StringID GetEngineInfoString(EngineID engine)
Get a multi-line string with some technical data, describing the 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
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:23
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.
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:704
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:851
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:114
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition gfx.cpp:740
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:774
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:54
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
@ 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:1486
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:389
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
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:790
static void ShowTicker(NewsIterator ni)
Show news item in the ticker.
Definition news_gui.cpp:710
void DeleteNews(Tpredicate predicate)
Delete news items by predicate, and invalidate the message history if necessary.
Definition news_gui.cpp:977
static void ShowNewspaper(const NewsItem *ni)
Open up an own newspaper window for the news item.
Definition news_gui.cpp:701
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:314
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...
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
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:746
static TileIndex GetReferenceTile(NewsReferenceType reftype, uint32_t ref)
Get the position a news-reference is referencing.
Definition news_gui.cpp:90
static std::list< NewsItem >::iterator DeleteNewsItem(std::list< NewsItem >::iterator ni)
Delete a news item from the queue.
Definition news_gui.cpp:827
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 AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32_t ref1, NewsReferenceType reftype2, uint32_t ref2, std::unique_ptr< NewsAllocatedData > &&data, AdviceType advice_type)
Add a new newsitem to be shown.
Definition news_gui.cpp:899
CommandCost CmdCustomNewsItem(DoCommandFlag flags, NewsType type, NewsReferenceType reftype1, CompanyID company, uint32_t reference, const std::string &text)
Create a new custom news item.
Definition news_gui.cpp:924
void InitNewsItemStructs()
Initialize the news-items data structures.
Definition news_gui.cpp:719
static void MoveToNextTickerItem()
Move to the next ticker item.
Definition news_gui.cpp:755
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:732
static WindowDesc * _news_window_layout[]
Window layouts for news items.
Definition news_gui.cpp:296
static NewsIterator _statusbar_news
Current status bar news item.
Definition news_gui.cpp:64
NewsType
Type of news.
Definition news_type.h:23
@ NT_END
end-of-array marker
Definition news_type.h:40
NewsReferenceType
References to objects in news.
Definition news_type.h:67
@ NR_TILE
Reference tile. Scroll to tile when clicking on the news.
Definition news_type.h:69
@ NR_STATION
Reference station. Scroll to station when clicking on the news. Delete news when station is deleted.
Definition news_type.h:71
@ NR_ENGINE
Reference engine.
Definition news_type.h:74
@ NR_TOWN
Reference town. Scroll to town when clicking on the news.
Definition news_type.h:73
@ NR_INDUSTRY
Reference industry. Scroll to industry when clicking on the news. Delete news when industry is delete...
Definition news_type.h:72
@ NR_NONE
Empty reference.
Definition news_type.h:68
@ NR_VEHICLE
Reference vehicle. Scroll to vehicle when clicking on the news. Delete news when vehicle is deleted.
Definition news_type.h:70
NewsContainer::const_iterator NewsIterator
Iterator type for news items.
Definition news_type.h:181
std::list< NewsItem > NewsContainer
Container type for storing news items.
Definition news_type.h:180
AdviceType
Sub type of the NT_ADVICE to be able to remove specific news items.
Definition news_type.h:44
NewsFlag
Various OR-able news-item flags.
Definition news_type.h:81
@ NF_NO_TRANSPARENT
Bit value for disabling transparency.
Definition news_type.h:90
@ NF_SHADE
Bit value for enabling shading.
Definition news_type.h:91
@ NF_VEHICLE_PARAM0
Bit value for specifying that string param 0 contains a vehicle ID. (special autoreplace behaviour)
Definition news_type.h:92
@ NFB_WINDOW_LAYOUT
First bit for window layout.
Definition news_type.h:85
@ NF_NORMAL
Normal news item. (Newspaper with text only)
Definition news_type.h:96
@ NF_INCOLOUR
Bit value for coloured news.
Definition news_type.h:89
@ NFB_WINDOW_LAYOUT_COUNT
Number of bits for window layout.
Definition news_type.h:86
NewsDisplay
News display options.
Definition news_type.h:106
@ ND_SUMMARY
Show ticker.
Definition news_type.h:108
@ ND_OFF
Only show a reminder in the status bar.
Definition news_type.h:107
@ ND_FULL
Show newspaper.
Definition news_type.h:109
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:56
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:1604
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:107
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
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:332
void CopyOutDParam(std::vector< StringParameterData > &backup, size_t num)
Copy num string parameters from the global string parameter array to the backup.
Definition strings.cpp:171
void CopyInDParam(const std::span< const StringParameterData > backup)
Copy the parameters from the backup into the global string parameter array.
Definition strings.cpp:159
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition strings.cpp:370
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:169
std::string president_name
The name of the president.
Definition news_type.h:171
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:581
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:143
TimerGameCalendar::Date date
Calendar date to show for the news.
Definition news_type.h:145
NewsItem(StringID string_id, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32_t ref1, NewsReferenceType reftype2, uint32_t ref2, std::unique_ptr< NewsAllocatedData > &&data, AdviceType advice_type)
Create a new newsitem to be shown.
Definition news_gui.cpp:877
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:156
std::vector< StringParameterData > params
Parameters for string resolving.
Definition news_type.h:158
NewsType type
Type of the news.
Definition news_type.h:147
uint32_t ref1
Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news,...
Definition news_type.h:153
NewsReferenceType reftype1
Type of ref1.
Definition news_type.h:151
AdviceType advice_type
The type of advice, to be able to remove specific advices later on.
Definition news_type.h:148
TimerGameEconomy::Date economy_date
Economy date of the news item, never shown but used to calculate age.
Definition news_type.h:146
uint32_t ref2
Reference 2 to some object: Used for scrolling after clicking on the news, and for deleting the news ...
Definition news_type.h:154
StringID string_id
Message text.
Definition news_type.h:144
NewsFlag flags
NewsFlags bits.
Definition news_type.h:149
NewsReferenceType reftype2
Type of ref2.
Definition news_type.h:152
Per-NewsType data.
Definition news_type.h:115
NewsDisplay GetDisplay() const
Return the news display option.
Definition news_gui.cpp:340
const char *const name
Name.
Definition news_type.h:116
const SoundFx sound
Sound.
Definition news_type.h:118
const uint8_t age
Maximum age of news items (in days)
Definition news_type.h:117
Window class displaying a news item.
Definition news_gui.cpp:348
uint16_t chat_height
Height of the chat window.
Definition news_gui.cpp:349
void OnResize() override
Called after the window got resized.
Definition news_gui.cpp:604
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:352
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition news_gui.cpp:502
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:428
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:422
void OnRealtimeTick(uint delta_ms) override
Called periodically.
Definition news_gui.cpp:637
uint16_t status_height
Height of the status bar window.
Definition news_gui.cpp:350
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
Definition news_gui.cpp:497
const NewsItem * ni
News item to display.
Definition news_gui.cpp:351
void SetWindowTop(int newtop)
Moves the window to a new top coordinate.
Definition news_gui.cpp:659
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition news_gui.cpp:628
IntervalTimer< TimerWindow > scroll_interval
Scroll the news message slowly up from the bottom.
Definition news_gui.cpp:649
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:559
Coordinates of a point in 2D.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * Get(size_t index)
Returns Titem with given index.
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:930
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 Station * Get(size_t index)
Gets station with given index.
static bool IsValidID(size_t index)
Tests whether given index is a valid index for station of this type.
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:272
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:949
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1044
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1730
ResizeInfo resize
Resize information.
Definition window_gui.h:313
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1720
ViewportData * viewport
Pointer to viewport data, if present.
Definition window_gui.h:317
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:315
int left
x position of left edge of the window
Definition window_gui.h:308
int top
y position of top edge of the window
Definition window_gui.h:309
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:970
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:311
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:310
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:301
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:2142
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.
uint32_t VehicleID
The type all our vehicle IDs have.
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, StringID str, StringAlignment align, FontSize fs)
Draw a caption bar.
Definition widget.cpp:679
@ ND_SHADE_GREY
Bit value of the 'shade to grey' flag.
@ ND_SHADE_DIMMED
Bit value of the 'dimmed colours' flag.
@ ND_NO_TRANSPARENCY
Bit value of the 'no transparency' flag.
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:42
@ 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:46
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:41
@ 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:39
@ 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
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:1137
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1110
int PositionNewsMessage(Window *w)
(Re)position news message window at the screen.
Definition window.cpp:3410
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:3217
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1095
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